rafters 0.0.81 → 0.0.83
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 +832 -231
- package/dist/registry/types.d.ts +122 -1
- package/dist/registry/types.js +43 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,13 +5,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var
|
|
9
|
-
get: (a2, b2) => (typeof require !== "undefined" ? require : a2)[b2]
|
|
10
|
-
}) : x)(function(x) {
|
|
11
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
12
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
13
|
-
});
|
|
14
|
-
var __commonJS = (cb, mod) => function __require2() {
|
|
8
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
15
9
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
16
10
|
};
|
|
17
11
|
var __export = (target, all) => {
|
|
@@ -316,6 +310,7 @@ function toDTCG(tokens, options = {}) {
|
|
|
316
310
|
}
|
|
317
311
|
|
|
318
312
|
// ../design-tokens/src/exporters/tailwind.ts
|
|
313
|
+
import * as csstree from "css-tree";
|
|
319
314
|
var SHADOW_PART_SUFFIX = /-(offset-x|offset-y|blur|spread|color)$/;
|
|
320
315
|
var MOTION_NAMESPACE_PROPERTY = {
|
|
321
316
|
duration: "transition-duration",
|
|
@@ -1259,19 +1254,18 @@ ${themeBody}`;
|
|
|
1259
1254
|
}
|
|
1260
1255
|
}
|
|
1261
1256
|
function postProcessDocSheet(css) {
|
|
1262
|
-
const
|
|
1263
|
-
const ast = csstree3.parse(css);
|
|
1257
|
+
const ast = csstree.parse(css);
|
|
1264
1258
|
const parts = [];
|
|
1265
1259
|
let hasHostContainer = false;
|
|
1266
1260
|
const atruleNames = /* @__PURE__ */ new Set(["layer", "property", "keyframes"]);
|
|
1267
|
-
|
|
1261
|
+
csstree.walk(ast, {
|
|
1268
1262
|
visit: "Atrule",
|
|
1269
1263
|
enter(node) {
|
|
1270
1264
|
if (!atruleNames.has(node.name)) return;
|
|
1271
1265
|
if (node.name === "layer") {
|
|
1272
|
-
const prelude = node.prelude ?
|
|
1266
|
+
const prelude = node.prelude ? csstree.generate(node.prelude) : "";
|
|
1273
1267
|
if (prelude === "theme" && node.block) {
|
|
1274
|
-
let content =
|
|
1268
|
+
let content = csstree.generate(node.block);
|
|
1275
1269
|
content = content.replace(/^\{/, "").replace(/\}$/, "");
|
|
1276
1270
|
content = rewriteRootToHost(content);
|
|
1277
1271
|
if (!hasHostContainer) {
|
|
@@ -1281,22 +1275,22 @@ function postProcessDocSheet(css) {
|
|
|
1281
1275
|
parts.push(content);
|
|
1282
1276
|
}
|
|
1283
1277
|
} else if (/^(base|components|utilities)/.test(prelude) && node.block) {
|
|
1284
|
-
parts.push(
|
|
1278
|
+
parts.push(csstree.generate(node));
|
|
1285
1279
|
} else if (prelude.startsWith("properties") && node.block) {
|
|
1286
|
-
let block =
|
|
1280
|
+
let block = csstree.generate(node);
|
|
1287
1281
|
block = rewritePropertiesSelector(block);
|
|
1288
1282
|
parts.push(block);
|
|
1289
1283
|
}
|
|
1290
1284
|
} else {
|
|
1291
|
-
parts.push(
|
|
1285
|
+
parts.push(csstree.generate(node));
|
|
1292
1286
|
}
|
|
1293
1287
|
}
|
|
1294
1288
|
});
|
|
1295
|
-
|
|
1289
|
+
csstree.walk(ast, {
|
|
1296
1290
|
visit: "Rule",
|
|
1297
1291
|
enter(node, _item, list) {
|
|
1298
1292
|
if (list !== ast.children) return;
|
|
1299
|
-
let block =
|
|
1293
|
+
let block = csstree.generate(node);
|
|
1300
1294
|
block = rewriteRootToHost(block);
|
|
1301
1295
|
parts.push(block);
|
|
1302
1296
|
}
|
|
@@ -2105,7 +2099,7 @@ function coerceCoords(space, format, name, coords) {
|
|
|
2105
2099
|
});
|
|
2106
2100
|
return types;
|
|
2107
2101
|
}
|
|
2108
|
-
function
|
|
2102
|
+
function parse2(str, { meta } = {}) {
|
|
2109
2103
|
let env = { "str": String(str)?.trim() };
|
|
2110
2104
|
hooks.run("parse-start", env);
|
|
2111
2105
|
if (env.color) {
|
|
@@ -2205,7 +2199,7 @@ function getColor(color) {
|
|
|
2205
2199
|
throw new TypeError("Empty color reference");
|
|
2206
2200
|
}
|
|
2207
2201
|
if (isString(color)) {
|
|
2208
|
-
color =
|
|
2202
|
+
color = parse2(color);
|
|
2209
2203
|
}
|
|
2210
2204
|
let space = color.space || color.spaceId;
|
|
2211
2205
|
if (!(space instanceof ColorSpace)) {
|
|
@@ -5700,7 +5694,7 @@ Object.assign(Color, {
|
|
|
5700
5694
|
WHITES,
|
|
5701
5695
|
Space: ColorSpace,
|
|
5702
5696
|
spaces: ColorSpace.registry,
|
|
5703
|
-
parse,
|
|
5697
|
+
parse: parse2,
|
|
5704
5698
|
// Global defaults one may want to configure
|
|
5705
5699
|
defaults
|
|
5706
5700
|
});
|
|
@@ -5950,7 +5944,7 @@ __export(external_exports, {
|
|
|
5950
5944
|
object: () => object,
|
|
5951
5945
|
optional: () => optional,
|
|
5952
5946
|
overwrite: () => _overwrite,
|
|
5953
|
-
parse: () =>
|
|
5947
|
+
parse: () => parse4,
|
|
5954
5948
|
parseAsync: () => parseAsync2,
|
|
5955
5949
|
partialRecord: () => partialRecord,
|
|
5956
5950
|
pipe: () => pipe,
|
|
@@ -6254,7 +6248,7 @@ __export(core_exports2, {
|
|
|
6254
6248
|
isValidBase64URL: () => isValidBase64URL,
|
|
6255
6249
|
isValidJWT: () => isValidJWT,
|
|
6256
6250
|
locales: () => locales_exports,
|
|
6257
|
-
parse: () =>
|
|
6251
|
+
parse: () => parse3,
|
|
6258
6252
|
parseAsync: () => parseAsync,
|
|
6259
6253
|
prettifyError: () => prettifyError,
|
|
6260
6254
|
regexes: () => regexes_exports,
|
|
@@ -7122,7 +7116,7 @@ var _parse = (_Err) => (schema, value, _ctx, _params) => {
|
|
|
7122
7116
|
}
|
|
7123
7117
|
return result.value;
|
|
7124
7118
|
};
|
|
7125
|
-
var
|
|
7119
|
+
var parse3 = /* @__PURE__ */ _parse($ZodRealError);
|
|
7126
7120
|
var _parseAsync = (_Err) => async (schema, value, _ctx, params) => {
|
|
7127
7121
|
const ctx = _ctx ? Object.assign(_ctx, { async: true }) : { async: true };
|
|
7128
7122
|
let result = schema._zod.run({ value, issues: [] }, ctx);
|
|
@@ -9658,10 +9652,10 @@ var $ZodFunction = /* @__PURE__ */ $constructor("$ZodFunction", (inst, def) => {
|
|
|
9658
9652
|
throw new Error("implement() must be called with a function");
|
|
9659
9653
|
}
|
|
9660
9654
|
return function(...args) {
|
|
9661
|
-
const parsedArgs = inst._def.input ?
|
|
9655
|
+
const parsedArgs = inst._def.input ? parse3(inst._def.input, args) : args;
|
|
9662
9656
|
const result = Reflect.apply(func, this, parsedArgs);
|
|
9663
9657
|
if (inst._def.output) {
|
|
9664
|
-
return
|
|
9658
|
+
return parse3(inst._def.output, result);
|
|
9665
9659
|
}
|
|
9666
9660
|
return result;
|
|
9667
9661
|
};
|
|
@@ -17283,7 +17277,7 @@ var ZodRealError = $constructor("ZodError", initializer2, {
|
|
|
17283
17277
|
});
|
|
17284
17278
|
|
|
17285
17279
|
// ../../node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/classic/parse.js
|
|
17286
|
-
var
|
|
17280
|
+
var parse4 = /* @__PURE__ */ _parse(ZodRealError);
|
|
17287
17281
|
var parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
|
|
17288
17282
|
var safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
|
|
17289
17283
|
var safeParseAsync2 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
|
|
@@ -17316,7 +17310,7 @@ var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
|
|
|
17316
17310
|
reg.add(inst, meta);
|
|
17317
17311
|
return inst;
|
|
17318
17312
|
});
|
|
17319
|
-
inst.parse = (data, params) =>
|
|
17313
|
+
inst.parse = (data, params) => parse4(inst, data, params, { callee: inst.parse });
|
|
17320
17314
|
inst.safeParse = (data, params) => safeParse2(inst, data, params);
|
|
17321
17315
|
inst.parseAsync = async (data, params) => parseAsync2(inst, data, params, { callee: inst.parseAsync });
|
|
17322
17316
|
inst.safeParseAsync = async (data, params) => safeParseAsync2(inst, data, params);
|
|
@@ -27313,8 +27307,8 @@ function generateBaseSystem(config2 = {}) {
|
|
|
27313
27307
|
const byNamespace = /* @__PURE__ */ new Map();
|
|
27314
27308
|
const allTokens = [];
|
|
27315
27309
|
const generators = createGeneratorDefs(mergedConfig.colorPaletteBases);
|
|
27316
|
-
for (const { generate:
|
|
27317
|
-
const result =
|
|
27310
|
+
for (const { generate: generate4 } of generators) {
|
|
27311
|
+
const result = generate4(resolvedConfig);
|
|
27318
27312
|
byNamespace.set(result.namespace, result.tokens);
|
|
27319
27313
|
allTokens.push(...result.tokens);
|
|
27320
27314
|
}
|
|
@@ -27349,22 +27343,22 @@ function getAvailableAdapters() {
|
|
|
27349
27343
|
}
|
|
27350
27344
|
|
|
27351
27345
|
// ../design-tokens/src/importers/shadcn.ts
|
|
27352
|
-
import * as
|
|
27346
|
+
import * as csstree2 from "css-tree";
|
|
27353
27347
|
function extractShadcnRoot(css) {
|
|
27354
|
-
const ast =
|
|
27348
|
+
const ast = csstree2.parse(css);
|
|
27355
27349
|
const out = [];
|
|
27356
|
-
|
|
27350
|
+
csstree2.walk(ast, {
|
|
27357
27351
|
visit: "Rule",
|
|
27358
27352
|
enter(rule) {
|
|
27359
|
-
const selectors =
|
|
27353
|
+
const selectors = csstree2.generate(rule.prelude).split(",").map((s) => s.trim());
|
|
27360
27354
|
if (!selectors.includes(":root")) return;
|
|
27361
|
-
|
|
27355
|
+
csstree2.walk(rule.block, {
|
|
27362
27356
|
visit: "Declaration",
|
|
27363
27357
|
enter(decl) {
|
|
27364
27358
|
if (!decl.property.startsWith("--")) return;
|
|
27365
27359
|
out.push({
|
|
27366
27360
|
name: decl.property.slice(2),
|
|
27367
|
-
value:
|
|
27361
|
+
value: csstree2.generate(decl.value).trim()
|
|
27368
27362
|
});
|
|
27369
27363
|
}
|
|
27370
27364
|
});
|
|
@@ -27393,13 +27387,13 @@ function extractThemeBlocks2(css) {
|
|
|
27393
27387
|
|
|
27394
27388
|
// ../design-tokens/src/importers/bases.ts
|
|
27395
27389
|
var LENGTH = /^(-?\d+(?:\.\d+)?)\s*(rem|px|em)$/;
|
|
27396
|
-
function detectBase(css, names,
|
|
27390
|
+
function detectBase(css, names, parse8) {
|
|
27397
27391
|
const decls = [...extractShadcnRoot(css), ...extractThemeBlocks2(css)];
|
|
27398
27392
|
let last2 = null;
|
|
27399
27393
|
for (const decl of decls) {
|
|
27400
27394
|
if (names.includes(decl.name)) last2 = decl.value.trim();
|
|
27401
27395
|
}
|
|
27402
|
-
return last2 === null ? null :
|
|
27396
|
+
return last2 === null ? null : parse8(last2);
|
|
27403
27397
|
}
|
|
27404
27398
|
function parseLength(raw) {
|
|
27405
27399
|
const match = raw.match(LENGTH);
|
|
@@ -27527,7 +27521,7 @@ function colorsFromClassification(classification) {
|
|
|
27527
27521
|
}
|
|
27528
27522
|
|
|
27529
27523
|
// ../design-tokens/src/importers/fonts.ts
|
|
27530
|
-
import * as
|
|
27524
|
+
import * as csstree3 from "css-tree";
|
|
27531
27525
|
var GENERIC_KEYWORDS = /* @__PURE__ */ new Set([
|
|
27532
27526
|
"sans-serif",
|
|
27533
27527
|
"serif",
|
|
@@ -27622,19 +27616,19 @@ function extractFontFaceFamilies(css) {
|
|
|
27622
27616
|
const out = [];
|
|
27623
27617
|
let ast;
|
|
27624
27618
|
try {
|
|
27625
|
-
ast =
|
|
27619
|
+
ast = csstree3.parse(css);
|
|
27626
27620
|
} catch {
|
|
27627
27621
|
return out;
|
|
27628
27622
|
}
|
|
27629
|
-
|
|
27623
|
+
csstree3.walk(ast, {
|
|
27630
27624
|
visit: "Atrule",
|
|
27631
27625
|
enter(atrule) {
|
|
27632
27626
|
if (atrule.name !== "font-face" || atrule.block === null) return;
|
|
27633
|
-
|
|
27627
|
+
csstree3.walk(atrule.block, {
|
|
27634
27628
|
visit: "Declaration",
|
|
27635
27629
|
enter(decl) {
|
|
27636
27630
|
if (decl.property.toLowerCase() !== "font-family") return;
|
|
27637
|
-
const raw =
|
|
27631
|
+
const raw = csstree3.generate(decl.value).trim();
|
|
27638
27632
|
const name = stripQuotes(raw);
|
|
27639
27633
|
if (name !== "") out.push(name);
|
|
27640
27634
|
}
|
|
@@ -28386,6 +28380,41 @@ var RegistryItemIntelligenceSchema = external_exports.object({
|
|
|
28386
28380
|
nevers: external_exports.array(external_exports.string()).default([])
|
|
28387
28381
|
}).optional()
|
|
28388
28382
|
});
|
|
28383
|
+
var ComponentTargetSchema = external_exports.enum(["react", "astro", "vue", "svelte", "wc"]);
|
|
28384
|
+
var PropFieldSchema = external_exports.discriminatedUnion("type", [
|
|
28385
|
+
external_exports.object({
|
|
28386
|
+
type: external_exports.literal("enum"),
|
|
28387
|
+
values: external_exports.array(external_exports.string()),
|
|
28388
|
+
// verbatim literal union members -- never "string"
|
|
28389
|
+
default: external_exports.string().optional(),
|
|
28390
|
+
required: external_exports.boolean().optional(),
|
|
28391
|
+
constraint: external_exports.object({
|
|
28392
|
+
when: external_exports.object({ prop: external_exports.string(), matches: external_exports.string() }),
|
|
28393
|
+
requires: external_exports.object({ prop: external_exports.string() })
|
|
28394
|
+
}).optional()
|
|
28395
|
+
}),
|
|
28396
|
+
external_exports.object({
|
|
28397
|
+
// Matches #2072's PropNode 'grammar' arm exactly, so graph.ts's
|
|
28398
|
+
// describe(<id>.props.<name>.vocab) drill has real shape data.
|
|
28399
|
+
type: external_exports.literal("grammar"),
|
|
28400
|
+
grammar: external_exports.array(external_exports.string()).min(1),
|
|
28401
|
+
// grammar shape tokens, e.g. ['word', 'word/alpha']
|
|
28402
|
+
vocab: external_exports.string(),
|
|
28403
|
+
// drillable addr, e.g. 'container.props.fill.vocab' -- never inlined
|
|
28404
|
+
onInvalid: external_exports.literal("silent-noop"),
|
|
28405
|
+
default: external_exports.string().optional()
|
|
28406
|
+
}),
|
|
28407
|
+
external_exports.object({
|
|
28408
|
+
type: external_exports.literal("deprecated"),
|
|
28409
|
+
deprecatedFor: external_exports.string()
|
|
28410
|
+
})
|
|
28411
|
+
]);
|
|
28412
|
+
var FacetSchema = external_exports.object({
|
|
28413
|
+
props: external_exports.record(external_exports.string(), PropFieldSchema),
|
|
28414
|
+
slots: external_exports.array(external_exports.string()).optional(),
|
|
28415
|
+
events: external_exports.array(external_exports.string()).optional(),
|
|
28416
|
+
snippet: external_exports.string()
|
|
28417
|
+
});
|
|
28389
28418
|
var RegistryItemSchema = external_exports.object({
|
|
28390
28419
|
name: external_exports.string(),
|
|
28391
28420
|
type: RegistryItemTypeSchema,
|
|
@@ -28394,7 +28423,11 @@ var RegistryItemSchema = external_exports.object({
|
|
|
28394
28423
|
files: external_exports.array(RegistryFileSchema),
|
|
28395
28424
|
rules: external_exports.array(external_exports.string()).default([]),
|
|
28396
28425
|
composites: external_exports.array(external_exports.string()).default([]),
|
|
28397
|
-
intelligence: RegistryItemIntelligenceSchema.optional()
|
|
28426
|
+
intelligence: RegistryItemIntelligenceSchema.optional(),
|
|
28427
|
+
// Per-target facets. zod v4's `z.record(enum, ...)` demands EVERY enum key be
|
|
28428
|
+
// present; a component built for only some targets must parse, so this is a
|
|
28429
|
+
// partial record (only the built targets appear).
|
|
28430
|
+
facets: external_exports.partialRecord(ComponentTargetSchema, FacetSchema).default({})
|
|
28398
28431
|
});
|
|
28399
28432
|
var RegistryIndexSchema = external_exports.object({
|
|
28400
28433
|
name: external_exports.string(),
|
|
@@ -28482,6 +28515,46 @@ var RegistryClient = class {
|
|
|
28482
28515
|
}
|
|
28483
28516
|
throw new Error(`"${name}" not found in registry (component, primitive, composite, or rule)`);
|
|
28484
28517
|
}
|
|
28518
|
+
/**
|
|
28519
|
+
* Fetch every registry item in one call, for the whole-catalog load the MCP
|
|
28520
|
+
* intel graph needs at startup.
|
|
28521
|
+
*
|
|
28522
|
+
* Prefers a single bulk round-trip against `/registry/items.json`. A registry
|
|
28523
|
+
* that does not serve that route -- an older deploy, or a third-party
|
|
28524
|
+
* `registryUrl` (which is user-configurable, see ConfigWiringSchema) -- returns
|
|
28525
|
+
* a non-2xx, and this falls back to looping `fetchItem` over `fetchIndex()`'s
|
|
28526
|
+
* name list, retaining today's per-item cost so no workspace's `describe` ever
|
|
28527
|
+
* hard-fails on a registry that predates the bulk endpoint.
|
|
28528
|
+
*/
|
|
28529
|
+
async fetchAllItems() {
|
|
28530
|
+
const response = await fetch(`${this.baseUrl}/registry/items.json`);
|
|
28531
|
+
if (response.ok) {
|
|
28532
|
+
return external_exports.array(RegistryItemSchema).parse(await response.json());
|
|
28533
|
+
}
|
|
28534
|
+
return this.fetchAllItemsByIndex();
|
|
28535
|
+
}
|
|
28536
|
+
/**
|
|
28537
|
+
* The fallback whole-catalog load: one `fetchItem` per name in the index,
|
|
28538
|
+
* across every describe-relevant kind. Deduped so a name appearing in more
|
|
28539
|
+
* than one index list is fetched once.
|
|
28540
|
+
*/
|
|
28541
|
+
async fetchAllItemsByIndex() {
|
|
28542
|
+
const index = await this.fetchIndex();
|
|
28543
|
+
const names = [
|
|
28544
|
+
...index.components,
|
|
28545
|
+
...index.primitives,
|
|
28546
|
+
...index.composites,
|
|
28547
|
+
...index.substrate
|
|
28548
|
+
];
|
|
28549
|
+
const seen = /* @__PURE__ */ new Set();
|
|
28550
|
+
const items = [];
|
|
28551
|
+
for (const name of names) {
|
|
28552
|
+
if (seen.has(name)) continue;
|
|
28553
|
+
seen.add(name);
|
|
28554
|
+
items.push(await this.fetchItem(name));
|
|
28555
|
+
}
|
|
28556
|
+
return items;
|
|
28557
|
+
}
|
|
28485
28558
|
/**
|
|
28486
28559
|
* List all available components.
|
|
28487
28560
|
*/
|
|
@@ -30880,8 +30953,8 @@ function readVersion() {
|
|
|
30880
30953
|
var VERSION = readVersion();
|
|
30881
30954
|
|
|
30882
30955
|
// src/mcp/tools.ts
|
|
30883
|
-
import { readFile as readFile6 } from "fs/promises";
|
|
30884
|
-
import { join as join12 } from "path";
|
|
30956
|
+
import { readFile as readFile6, writeFile as writeFile4 } from "fs/promises";
|
|
30957
|
+
import { isAbsolute as isAbsolute3, join as join12 } from "path";
|
|
30885
30958
|
|
|
30886
30959
|
// ../composites/src/built-in-rules/email.ts
|
|
30887
30960
|
var email3 = external_exports.string().email();
|
|
@@ -31031,9 +31104,6 @@ function register3(composite) {
|
|
|
31031
31104
|
}
|
|
31032
31105
|
composites.set(id, composite);
|
|
31033
31106
|
}
|
|
31034
|
-
function get2(id) {
|
|
31035
|
-
return composites.get(id);
|
|
31036
|
-
}
|
|
31037
31107
|
function getAll2() {
|
|
31038
31108
|
return Array.from(composites.values());
|
|
31039
31109
|
}
|
|
@@ -31244,7 +31314,323 @@ function resolveWorkspace(workspaces, defaultWorkspace, name) {
|
|
|
31244
31314
|
return defaultWorkspace;
|
|
31245
31315
|
}
|
|
31246
31316
|
|
|
31317
|
+
// src/mcp/graph.ts
|
|
31318
|
+
function assembleGraph(items) {
|
|
31319
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
31320
|
+
for (const item of items) {
|
|
31321
|
+
const kind = kindOf(item.type);
|
|
31322
|
+
if (kind === null) continue;
|
|
31323
|
+
const src = item.intelligence;
|
|
31324
|
+
const intel = {
|
|
31325
|
+
dos: src?.usagePatterns?.dos ?? [],
|
|
31326
|
+
nevers: src?.usagePatterns?.nevers ?? []
|
|
31327
|
+
};
|
|
31328
|
+
if (src?.cognitiveLoad !== void 0) intel.cognitiveLoad = src.cognitiveLoad;
|
|
31329
|
+
if (src?.semanticMeaning !== void 0) intel.semanticMeaning = src.semanticMeaning;
|
|
31330
|
+
if (src?.accessibility !== void 0) intel.accessibility = src.accessibility;
|
|
31331
|
+
if (src?.attentionEconomics !== void 0) intel.attentionEconomics = src.attentionEconomics;
|
|
31332
|
+
if (src?.trustBuilding !== void 0) intel.trustBuilding = src.trustBuilding;
|
|
31333
|
+
nodes.set(item.name, {
|
|
31334
|
+
id: item.name,
|
|
31335
|
+
kind,
|
|
31336
|
+
intel,
|
|
31337
|
+
facets: item.facets ?? {},
|
|
31338
|
+
composesWith: item.composites
|
|
31339
|
+
});
|
|
31340
|
+
}
|
|
31341
|
+
for (const node of nodes.values()) {
|
|
31342
|
+
for (const target of node.composesWith) {
|
|
31343
|
+
if (!nodes.has(target)) {
|
|
31344
|
+
throw new Error(`graph: node "${node.id}" composesWith unknown id "${target}"`);
|
|
31345
|
+
}
|
|
31346
|
+
}
|
|
31347
|
+
}
|
|
31348
|
+
return { nodes };
|
|
31349
|
+
}
|
|
31350
|
+
function kindOf(type2) {
|
|
31351
|
+
if (type2 === "composite") return "composite";
|
|
31352
|
+
if (type2 === "ui" || type2 === "primitive") return "component";
|
|
31353
|
+
return null;
|
|
31354
|
+
}
|
|
31355
|
+
function describe(addr, graph, target) {
|
|
31356
|
+
const parts = addr === "" ? [] : addr.split(".");
|
|
31357
|
+
if (parts.length === 0) {
|
|
31358
|
+
return {
|
|
31359
|
+
kinds: [
|
|
31360
|
+
{ addr: "components", type: "edge" },
|
|
31361
|
+
{ addr: "composites", type: "edge" }
|
|
31362
|
+
],
|
|
31363
|
+
nodeCount: graph.nodes.size
|
|
31364
|
+
};
|
|
31365
|
+
}
|
|
31366
|
+
const [head, ...rest] = parts;
|
|
31367
|
+
if (head === void 0) return { error: `cannot resolve: ${addr}` };
|
|
31368
|
+
if (head === "components" || head === "composites") {
|
|
31369
|
+
const kind = head === "components" ? "component" : "composite";
|
|
31370
|
+
const roster = [];
|
|
31371
|
+
for (const node2 of graph.nodes.values()) {
|
|
31372
|
+
if (node2.kind === kind) roster.push({ id: node2.id });
|
|
31373
|
+
}
|
|
31374
|
+
return roster;
|
|
31375
|
+
}
|
|
31376
|
+
const node = graph.nodes.get(head);
|
|
31377
|
+
if (!node) return { error: `unknown node: ${head}` };
|
|
31378
|
+
if (rest.length === 0) return layer0(node, target);
|
|
31379
|
+
if (rest.length === 1 && rest[0] === "composesWith") {
|
|
31380
|
+
return resolveEdges(node, graph, target);
|
|
31381
|
+
}
|
|
31382
|
+
if (rest[0] === "props") {
|
|
31383
|
+
const facet = target === void 0 ? void 0 : node.facets[target];
|
|
31384
|
+
const propName = rest[1];
|
|
31385
|
+
const prop = facet && propName !== void 0 ? facet.props[propName] : void 0;
|
|
31386
|
+
if (!prop) return { error: `cannot resolve: ${addr}` };
|
|
31387
|
+
if (rest.length === 2) return toAgentProp(prop);
|
|
31388
|
+
return { error: `cannot resolve: ${addr}` };
|
|
31389
|
+
}
|
|
31390
|
+
return { error: `cannot resolve: ${addr}` };
|
|
31391
|
+
}
|
|
31392
|
+
function toAgentProp(prop) {
|
|
31393
|
+
if (prop.type === "grammar") {
|
|
31394
|
+
const { vocab: _vocab, ...agentView } = prop;
|
|
31395
|
+
return agentView;
|
|
31396
|
+
}
|
|
31397
|
+
return prop;
|
|
31398
|
+
}
|
|
31399
|
+
function layer0(node, target) {
|
|
31400
|
+
const facet = target === void 0 ? void 0 : node.facets[target];
|
|
31401
|
+
const children = [];
|
|
31402
|
+
if (facet) {
|
|
31403
|
+
for (const [name, prop] of Object.entries(facet.props)) {
|
|
31404
|
+
const child = { addr: `${node.id}.props.${name}`, type: prop.type };
|
|
31405
|
+
if (prop.type === "deprecated") child.deprecatedFor = prop.deprecatedFor;
|
|
31406
|
+
children.push(child);
|
|
31407
|
+
}
|
|
31408
|
+
}
|
|
31409
|
+
if (node.composesWith.length > 0) {
|
|
31410
|
+
children.push({ addr: `${node.id}.composesWith`, type: "edge" });
|
|
31411
|
+
}
|
|
31412
|
+
const result = { id: node.id, kind: node.kind, intel: node.intel, children };
|
|
31413
|
+
if (facet) {
|
|
31414
|
+
result.snippet = facet.snippet;
|
|
31415
|
+
if (facet.slots !== void 0) result.slots = facet.slots;
|
|
31416
|
+
if (facet.events !== void 0) result.events = facet.events;
|
|
31417
|
+
}
|
|
31418
|
+
return result;
|
|
31419
|
+
}
|
|
31420
|
+
function resolveEdges(node, graph, target) {
|
|
31421
|
+
const seen = /* @__PURE__ */ new Set();
|
|
31422
|
+
const results = [];
|
|
31423
|
+
for (const edgeId of node.composesWith) {
|
|
31424
|
+
if (seen.has(edgeId)) continue;
|
|
31425
|
+
seen.add(edgeId);
|
|
31426
|
+
const edgeNode = graph.nodes.get(edgeId);
|
|
31427
|
+
if (edgeNode) results.push(layer0(edgeNode, target));
|
|
31428
|
+
}
|
|
31429
|
+
return results;
|
|
31430
|
+
}
|
|
31431
|
+
|
|
31432
|
+
// src/mcp/intent.ts
|
|
31433
|
+
var INTENT_TAGS = {
|
|
31434
|
+
modal: ["attention", "blocking", "above-all", "focus-trap"],
|
|
31435
|
+
alert: ["attention", "inline", "passive"],
|
|
31436
|
+
tooltip: ["hint", "passive", "inline", "hover"]
|
|
31437
|
+
};
|
|
31438
|
+
var INTENT_AXES = [
|
|
31439
|
+
{
|
|
31440
|
+
tag: "above-all",
|
|
31441
|
+
keywords: [
|
|
31442
|
+
"above everything",
|
|
31443
|
+
"above all",
|
|
31444
|
+
"on top of everything",
|
|
31445
|
+
"sits on top",
|
|
31446
|
+
"on top",
|
|
31447
|
+
"over everything",
|
|
31448
|
+
"over all",
|
|
31449
|
+
"topmost",
|
|
31450
|
+
"highest layer"
|
|
31451
|
+
]
|
|
31452
|
+
},
|
|
31453
|
+
{
|
|
31454
|
+
tag: "blocking",
|
|
31455
|
+
keywords: [
|
|
31456
|
+
"above everything",
|
|
31457
|
+
"on top of everything",
|
|
31458
|
+
"over everything",
|
|
31459
|
+
"block",
|
|
31460
|
+
"blocking",
|
|
31461
|
+
"must dismiss",
|
|
31462
|
+
"interrupt",
|
|
31463
|
+
"take over",
|
|
31464
|
+
"stops everything",
|
|
31465
|
+
"requires a response",
|
|
31466
|
+
"can't ignore",
|
|
31467
|
+
"cannot ignore"
|
|
31468
|
+
]
|
|
31469
|
+
},
|
|
31470
|
+
{
|
|
31471
|
+
tag: "inline",
|
|
31472
|
+
keywords: ["inline", "in place", "in the flow", "within the page", "non-blocking"]
|
|
31473
|
+
},
|
|
31474
|
+
{
|
|
31475
|
+
tag: "passive",
|
|
31476
|
+
keywords: ["passive", "non-intrusive", "subtle", "quietly", "in the background"]
|
|
31477
|
+
},
|
|
31478
|
+
{
|
|
31479
|
+
tag: "attention",
|
|
31480
|
+
keywords: ["attention", "notice", "get noticed", "important message"]
|
|
31481
|
+
},
|
|
31482
|
+
{
|
|
31483
|
+
tag: "hint",
|
|
31484
|
+
keywords: ["hint", "a tip", "explain", "extra info", "more info"]
|
|
31485
|
+
},
|
|
31486
|
+
{
|
|
31487
|
+
tag: "hover",
|
|
31488
|
+
keywords: ["hover", "on hover", "mouse over"]
|
|
31489
|
+
}
|
|
31490
|
+
];
|
|
31491
|
+
function isNaturalLanguageQuery(input) {
|
|
31492
|
+
return input.includes(" ");
|
|
31493
|
+
}
|
|
31494
|
+
function matchIntent(query, graph) {
|
|
31495
|
+
const normalized = query.toLowerCase();
|
|
31496
|
+
const matchedTags = collectMatchedTags(normalized);
|
|
31497
|
+
if (matchedTags.size === 0) return noMatch();
|
|
31498
|
+
const winner = selectUse(matchedTags, graph);
|
|
31499
|
+
if (winner === void 0) return noMatch();
|
|
31500
|
+
const winningTags = winner.tags.filter((tag) => matchedTags.has(tag));
|
|
31501
|
+
const decisive = new Set(winningTags);
|
|
31502
|
+
const nearMiss = selectNearMiss(winner, decisive, matchedTags, graph);
|
|
31503
|
+
if (nearMiss === void 0) return noMatch();
|
|
31504
|
+
const use = describeNode(winner.id, graph);
|
|
31505
|
+
const not = describeNode(nearMiss.id, graph);
|
|
31506
|
+
if (use === void 0 || not === void 0) return noMatch();
|
|
31507
|
+
const divergingTags = nearMiss.tags.filter((tag) => !winner.tags.includes(tag));
|
|
31508
|
+
const because = `${winner.id} is ${winningTags.join("/")}; ${nearMiss.id} is ${divergingTags.join("/")}`;
|
|
31509
|
+
return { use, not, because };
|
|
31510
|
+
}
|
|
31511
|
+
function collectMatchedTags(normalizedQuery) {
|
|
31512
|
+
const matched = /* @__PURE__ */ new Set();
|
|
31513
|
+
for (const axis of INTENT_AXES) {
|
|
31514
|
+
for (const keyword of axis.keywords) {
|
|
31515
|
+
if (normalizedQuery.includes(keyword)) {
|
|
31516
|
+
matched.add(axis.tag);
|
|
31517
|
+
break;
|
|
31518
|
+
}
|
|
31519
|
+
}
|
|
31520
|
+
}
|
|
31521
|
+
return matched;
|
|
31522
|
+
}
|
|
31523
|
+
function selectUse(matchedTags, graph) {
|
|
31524
|
+
let best;
|
|
31525
|
+
let bestScore = 0;
|
|
31526
|
+
for (const [id, tags] of Object.entries(INTENT_TAGS)) {
|
|
31527
|
+
if (!graph.nodes.has(id)) continue;
|
|
31528
|
+
const score = tags.reduce((sum, tag) => matchedTags.has(tag) ? sum + 1 : sum, 0);
|
|
31529
|
+
if (score > bestScore) {
|
|
31530
|
+
bestScore = score;
|
|
31531
|
+
best = { id, tags };
|
|
31532
|
+
}
|
|
31533
|
+
}
|
|
31534
|
+
return best;
|
|
31535
|
+
}
|
|
31536
|
+
function selectNearMiss(use, decisive, matchedTags, graph) {
|
|
31537
|
+
let best;
|
|
31538
|
+
let bestOverlap = 0;
|
|
31539
|
+
for (const [id, tags] of Object.entries(INTENT_TAGS)) {
|
|
31540
|
+
if (id === use.id || !graph.nodes.has(id)) continue;
|
|
31541
|
+
if (tags.some((tag) => decisive.has(tag))) continue;
|
|
31542
|
+
const overlap = tags.filter((tag) => use.tags.includes(tag));
|
|
31543
|
+
const sharesOutsideMatched = overlap.some((tag) => !matchedTags.has(tag));
|
|
31544
|
+
if (!sharesOutsideMatched) continue;
|
|
31545
|
+
if (overlap.length > bestOverlap) {
|
|
31546
|
+
bestOverlap = overlap.length;
|
|
31547
|
+
best = { id, tags };
|
|
31548
|
+
}
|
|
31549
|
+
}
|
|
31550
|
+
return best;
|
|
31551
|
+
}
|
|
31552
|
+
function describeNode(id, graph) {
|
|
31553
|
+
const result = describe(id, graph);
|
|
31554
|
+
if (!Array.isArray(result) && "children" in result) return result;
|
|
31555
|
+
return void 0;
|
|
31556
|
+
}
|
|
31557
|
+
function noMatch() {
|
|
31558
|
+
return { note: "no route matched; describe(components) or describe(composites) to browse" };
|
|
31559
|
+
}
|
|
31560
|
+
|
|
31561
|
+
// src/mcp/overlay.ts
|
|
31562
|
+
function buildInstalledSet(config2) {
|
|
31563
|
+
return {
|
|
31564
|
+
components: new Set(config2.installed?.components ?? []),
|
|
31565
|
+
composites: new Set(config2.installed?.composites ?? [])
|
|
31566
|
+
};
|
|
31567
|
+
}
|
|
31568
|
+
function describeWithOverlay(addr, graph, ctx) {
|
|
31569
|
+
const result = describe(addr, graph, ctx.target);
|
|
31570
|
+
if (addr === "components" || addr === "composites") {
|
|
31571
|
+
const set3 = addr === "components" ? ctx.installed.components : ctx.installed.composites;
|
|
31572
|
+
const roster = result;
|
|
31573
|
+
return roster.map((entry) => ({ id: entry.id, presence: presenceOf(set3, entry.id) }));
|
|
31574
|
+
}
|
|
31575
|
+
if (addr !== "" && !addr.includes(".") && isNodeResult(result)) {
|
|
31576
|
+
const set3 = result.kind === "component" ? ctx.installed.components : ctx.installed.composites;
|
|
31577
|
+
return {
|
|
31578
|
+
...result,
|
|
31579
|
+
presence: presenceOf(set3, result.id),
|
|
31580
|
+
target: ctx.target,
|
|
31581
|
+
rendersForTarget: ctx.target !== void 0 && graph.nodes.get(result.id)?.facets[ctx.target] !== void 0
|
|
31582
|
+
};
|
|
31583
|
+
}
|
|
31584
|
+
return result;
|
|
31585
|
+
}
|
|
31586
|
+
function presenceOf(set3, id) {
|
|
31587
|
+
return set3.has(id) ? "installed" : "available";
|
|
31588
|
+
}
|
|
31589
|
+
function isNodeResult(result) {
|
|
31590
|
+
return typeof result === "object" && result !== null && !Array.isArray(result) && "id" in result && "kind" in result && "children" in result;
|
|
31591
|
+
}
|
|
31592
|
+
|
|
31247
31593
|
// src/mcp/tools.ts
|
|
31594
|
+
function isSafeRelPath(p2) {
|
|
31595
|
+
if (isAbsolute3(p2)) return false;
|
|
31596
|
+
return !p2.split(/[/\\]/).includes("..");
|
|
31597
|
+
}
|
|
31598
|
+
var SafePathFieldSchema = PathFieldSchema.refine(
|
|
31599
|
+
(field) => {
|
|
31600
|
+
const entries = typeof field === "string" ? [field] : field;
|
|
31601
|
+
return entries.every((e) => isSafeRelPath(typeof e === "string" ? e : e.path));
|
|
31602
|
+
},
|
|
31603
|
+
{ message: "path must be relative and stay inside the workspace (no absolute or `..` paths)" }
|
|
31604
|
+
);
|
|
31605
|
+
var ConfigWiringSchema = external_exports.object({
|
|
31606
|
+
// Closed set -- excludes 'unknown', which is a detection sentinel, not a
|
|
31607
|
+
// valid target a caller may set.
|
|
31608
|
+
framework: external_exports.enum(["next", "vite", "remix", "react-router", "astro", "wc", "vanilla"]),
|
|
31609
|
+
// Must be a valid http(s) URL. (Blocking private/link-local/metadata hosts
|
|
31610
|
+
// is tracked as a follow-up -- see the registryUrl SSRF issue.)
|
|
31611
|
+
registryUrl: external_exports.string().url().refine((u) => /^https?:$/.test(new URL(u).protocol), {
|
|
31612
|
+
message: "registryUrl must be an http(s) URL"
|
|
31613
|
+
}),
|
|
31614
|
+
// Closed set derived from the framework (see ComponentTarget in detect.ts).
|
|
31615
|
+
componentTarget: external_exports.enum(["react", "astro", "vue", "svelte", "wc"]),
|
|
31616
|
+
source: external_exports.string().min(1),
|
|
31617
|
+
cssPath: external_exports.union([external_exports.string(), external_exports.null()]).refine((v) => v === null || isSafeRelPath(v), {
|
|
31618
|
+
message: "cssPath must be relative and stay inside the workspace"
|
|
31619
|
+
}),
|
|
31620
|
+
componentsPath: SafePathFieldSchema,
|
|
31621
|
+
primitivesPath: SafePathFieldSchema,
|
|
31622
|
+
compositesPath: SafePathFieldSchema,
|
|
31623
|
+
rulesPath: SafePathFieldSchema,
|
|
31624
|
+
exports: external_exports.object({
|
|
31625
|
+
tailwind: external_exports.boolean(),
|
|
31626
|
+
typescript: external_exports.boolean(),
|
|
31627
|
+
dtcg: external_exports.boolean(),
|
|
31628
|
+
compiled: external_exports.boolean(),
|
|
31629
|
+
documentation: external_exports.boolean()
|
|
31630
|
+
}).partial()
|
|
31631
|
+
}).partial().strict();
|
|
31632
|
+
var STUDIO_OWNED_KEYS = ["intent", "darkMode", "fonts"];
|
|
31633
|
+
var ADD_MANAGED_KEYS = ["installed"];
|
|
31248
31634
|
var WORKSPACE_PARAM = {
|
|
31249
31635
|
workspace: {
|
|
31250
31636
|
type: "string",
|
|
@@ -31254,16 +31640,76 @@ var WORKSPACE_PARAM = {
|
|
|
31254
31640
|
var TOOL_DEFINITIONS = [
|
|
31255
31641
|
{
|
|
31256
31642
|
name: "rafters_workspaces",
|
|
31257
|
-
description: "List rafters workspaces
|
|
31643
|
+
description: "List rafters workspaces, or update a workspace's WIRING config. Called with no arguments (or just `workspace`): returns each workspace name, path, and which is the default for unscoped tool calls -- call this first when the project might be a monorepo. Called with any wiring field: updates that workspace's .rafters/config.rafters.json -- framework, registryUrl, componentTarget, source, cssPath, and the path fields (componentsPath, primitivesPath, compositesPath, rulesPath) and exports; only fields you pass change. Cannot set designer decisions (intent, darkMode, fonts) -- those are set in Studio -- and cannot set installed -- that is managed by `rafters add`.",
|
|
31258
31644
|
inputSchema: {
|
|
31259
31645
|
type: "object",
|
|
31260
|
-
properties: {
|
|
31646
|
+
properties: {
|
|
31647
|
+
...WORKSPACE_PARAM,
|
|
31648
|
+
framework: { type: "string", description: 'Target framework (e.g., "react", "astro")' },
|
|
31649
|
+
registryUrl: {
|
|
31650
|
+
type: "string",
|
|
31651
|
+
description: "Registry to install from / query. Point at your own internal registry."
|
|
31652
|
+
},
|
|
31653
|
+
componentTarget: { type: "string", description: "Where installed components are written" },
|
|
31654
|
+
source: { type: "string", description: "Design system this project was imported from" },
|
|
31655
|
+
cssPath: { type: ["string", "null"], description: "Path to the main CSS file, or null" },
|
|
31656
|
+
componentsPath: {
|
|
31657
|
+
oneOf: [{ type: "string" }, { type: "array" }],
|
|
31658
|
+
description: "Folder(s) to read/write components. String or array of entries."
|
|
31659
|
+
},
|
|
31660
|
+
primitivesPath: {
|
|
31661
|
+
oneOf: [{ type: "string" }, { type: "array" }],
|
|
31662
|
+
description: "Folder(s) to read/write primitives. String or array of entries."
|
|
31663
|
+
},
|
|
31664
|
+
compositesPath: {
|
|
31665
|
+
oneOf: [{ type: "string" }, { type: "array" }],
|
|
31666
|
+
description: "Folder(s) to read/write composites. String or array of entries."
|
|
31667
|
+
},
|
|
31668
|
+
rulesPath: {
|
|
31669
|
+
oneOf: [{ type: "string" }, { type: "array" }],
|
|
31670
|
+
description: "Folder(s) to read/write rules. String or array of entries."
|
|
31671
|
+
},
|
|
31672
|
+
exports: {
|
|
31673
|
+
type: "object",
|
|
31674
|
+
description: "Which output formats to emit (tailwind, typescript, dtcg, compiled, documentation)."
|
|
31675
|
+
}
|
|
31676
|
+
},
|
|
31261
31677
|
required: []
|
|
31262
31678
|
}
|
|
31263
31679
|
},
|
|
31680
|
+
{
|
|
31681
|
+
name: "rafters_describe",
|
|
31682
|
+
description: 'Recursively introspect the component/composite intel graph. describe() returns the installed surface; describe(components)/describe(composites) list the kind roster; describe(button) returns a node -- intel plus type-marked, drillable children; describe(button.props.fill) drills into a prop; describe(button.props.fill.vocab) returns the real token values. A natural-language question (e.g. "what do I use when it needs to be above everything") routes to the best-matching node plus a near-miss counter-example instead of an address.',
|
|
31683
|
+
inputSchema: {
|
|
31684
|
+
type: "object",
|
|
31685
|
+
properties: {
|
|
31686
|
+
...WORKSPACE_PARAM,
|
|
31687
|
+
address: {
|
|
31688
|
+
type: "string",
|
|
31689
|
+
description: 'A dot-address ("button.props.variant") or a natural-language question.'
|
|
31690
|
+
}
|
|
31691
|
+
},
|
|
31692
|
+
required: ["address"]
|
|
31693
|
+
}
|
|
31694
|
+
},
|
|
31695
|
+
{
|
|
31696
|
+
name: "rafters_generate",
|
|
31697
|
+
description: "STUB (Issue E). Will produce a rafters-correct composition with visible placeholders for app-specific fields/actions/copy. Currently returns a structured not-implemented result.",
|
|
31698
|
+
inputSchema: {
|
|
31699
|
+
type: "object",
|
|
31700
|
+
properties: {
|
|
31701
|
+
...WORKSPACE_PARAM,
|
|
31702
|
+
intent: { type: "string", description: "What to generate" }
|
|
31703
|
+
},
|
|
31704
|
+
required: ["intent"]
|
|
31705
|
+
}
|
|
31706
|
+
},
|
|
31707
|
+
// Deprecated aliases -- kept for one minor release, then removed (tracked as a
|
|
31708
|
+
// follow-up). Input schemas unchanged; every response carries a `deprecated`
|
|
31709
|
+
// field pointing at rafters_describe.
|
|
31264
31710
|
{
|
|
31265
31711
|
name: "rafters_composite",
|
|
31266
|
-
description: "Query composites by ID, search term, or category. Returns designer intent (solves, appliesWhen, do/never), I/O rules for chaining, and block structure.",
|
|
31712
|
+
description: "[DEPRECATED -- use rafters_describe] Query composites by ID, search term, or category. Returns designer intent (solves, appliesWhen, do/never), I/O rules for chaining, and block structure.",
|
|
31267
31713
|
inputSchema: {
|
|
31268
31714
|
type: "object",
|
|
31269
31715
|
properties: {
|
|
@@ -31277,7 +31723,7 @@ var TOOL_DEFINITIONS = [
|
|
|
31277
31723
|
},
|
|
31278
31724
|
{
|
|
31279
31725
|
name: "rafters_pattern",
|
|
31280
|
-
description: 'Get design pattern guidance by querying composites. Search by what the pattern solves (e.g., "authentication", "data entry", "navigation") to get do/never rules, cognitive load, and designer intent.',
|
|
31726
|
+
description: '[DEPRECATED -- use rafters_describe] Get design pattern guidance by querying composites. Search by what the pattern solves (e.g., "authentication", "data entry", "navigation") to get do/never rules, cognitive load, and designer intent.',
|
|
31281
31727
|
inputSchema: {
|
|
31282
31728
|
type: "object",
|
|
31283
31729
|
properties: {
|
|
@@ -31296,7 +31742,7 @@ var TOOL_DEFINITIONS = [
|
|
|
31296
31742
|
},
|
|
31297
31743
|
{
|
|
31298
31744
|
name: "rafters_component",
|
|
31299
|
-
description: "Get component intelligence: cognitive load, accessibility, do/never guidance, variants, sizes.",
|
|
31745
|
+
description: "[DEPRECATED -- use rafters_describe] Get component intelligence: cognitive load, accessibility, do/never guidance, variants, sizes.",
|
|
31300
31746
|
inputSchema: {
|
|
31301
31747
|
type: "object",
|
|
31302
31748
|
properties: {
|
|
@@ -31310,6 +31756,7 @@ var TOOL_DEFINITIONS = [
|
|
|
31310
31756
|
}
|
|
31311
31757
|
}
|
|
31312
31758
|
];
|
|
31759
|
+
var DEPRECATED_MSG = "use rafters_describe instead";
|
|
31313
31760
|
var RaftersToolHandler = class {
|
|
31314
31761
|
workspaces;
|
|
31315
31762
|
defaultWorkspace;
|
|
@@ -31317,32 +31764,52 @@ var RaftersToolHandler = class {
|
|
|
31317
31764
|
compositesLoadedFor = /* @__PURE__ */ new Set();
|
|
31318
31765
|
/** Tracks built-in composite loading separately (loaded once globally). */
|
|
31319
31766
|
builtInCompositesLoaded = false;
|
|
31320
|
-
|
|
31767
|
+
/**
|
|
31768
|
+
* Registry clients keyed by base URL, so each workspace's `registryUrl` gets
|
|
31769
|
+
* its own fetch cache. Workspaces without a configured URL share the default
|
|
31770
|
+
* singleton (which points at the public registry).
|
|
31771
|
+
*/
|
|
31772
|
+
registryClients = /* @__PURE__ */ new Map();
|
|
31773
|
+
/**
|
|
31774
|
+
* Per-workspace-root cache: the intel graph, built once, lazily, on the first
|
|
31775
|
+
* describe/generate call that touches that root. The graph is universal and
|
|
31776
|
+
* target-free (a node carries all its per-target facets); the workspace's
|
|
31777
|
+
* target is applied per query by the overlay, not baked into the cache. Same
|
|
31778
|
+
* per-workspace caching shape as `compositesLoadedFor`/`registryClients`. A
|
|
31779
|
+
* failed build is never inserted, so the next call retries rather than
|
|
31780
|
+
* permanently wedging that workspace.
|
|
31781
|
+
*/
|
|
31782
|
+
graphsByWorkspace = /* @__PURE__ */ new Map();
|
|
31783
|
+
/**
|
|
31784
|
+
* The whole-catalog item source `ensureGraph` builds from. Defaults to the
|
|
31785
|
+
* workspace's registry client `fetchAllItems()` (bulk endpoint with per-item
|
|
31786
|
+
* fallback). Injectable so the dispatch can be unit-tested against a fixture
|
|
31787
|
+
* catalog without a network round-trip.
|
|
31788
|
+
*/
|
|
31789
|
+
itemsSource;
|
|
31790
|
+
constructor(workspaces, defaultWorkspace, itemsSource) {
|
|
31321
31791
|
this.workspaces = workspaces;
|
|
31322
31792
|
this.defaultWorkspace = defaultWorkspace;
|
|
31793
|
+
this.itemsSource = itemsSource ?? (async (ws) => (await this.registryClientFor(ws)).fetchAllItems());
|
|
31323
31794
|
}
|
|
31324
31795
|
async handleToolCall(name, args) {
|
|
31325
31796
|
switch (name) {
|
|
31326
31797
|
case "rafters_workspaces":
|
|
31327
|
-
return this.handleWorkspaces();
|
|
31798
|
+
return this.handleWorkspaces(args);
|
|
31799
|
+
case "rafters_describe":
|
|
31800
|
+
return this.handleDescribe(args.address, args.workspace);
|
|
31801
|
+
case "rafters_generate":
|
|
31802
|
+
return this.handleGenerate(args.intent, args.workspace);
|
|
31328
31803
|
case "rafters_composite":
|
|
31329
31804
|
return this.handleComposite(args);
|
|
31330
31805
|
case "rafters_pattern":
|
|
31331
31806
|
return this.handlePattern(args);
|
|
31332
31807
|
case "rafters_component":
|
|
31333
|
-
return this.handleComponent(args.name);
|
|
31808
|
+
return this.handleComponent(args.name, args.workspace);
|
|
31334
31809
|
default:
|
|
31335
|
-
return {
|
|
31336
|
-
|
|
31337
|
-
|
|
31338
|
-
type: "text",
|
|
31339
|
-
text: JSON.stringify({
|
|
31340
|
-
error: `Unknown tool: ${name}`,
|
|
31341
|
-
suggestion: "Available tools: rafters_workspaces, rafters_composite, rafters_pattern, rafters_component."
|
|
31342
|
-
})
|
|
31343
|
-
}
|
|
31344
|
-
]
|
|
31345
|
-
};
|
|
31810
|
+
return this.errorResult(`Unknown tool: ${name}`, {
|
|
31811
|
+
suggestion: "Available tools: rafters_workspaces, rafters_describe, rafters_generate. Deprecated: rafters_composite, rafters_pattern, rafters_component."
|
|
31812
|
+
});
|
|
31346
31813
|
}
|
|
31347
31814
|
}
|
|
31348
31815
|
/**
|
|
@@ -31359,42 +31826,84 @@ var RaftersToolHandler = class {
|
|
|
31359
31826
|
* Use this when a tool requires a workspace and the agent didn't pick one.
|
|
31360
31827
|
*/
|
|
31361
31828
|
workspaceRequiredError() {
|
|
31362
|
-
return {
|
|
31363
|
-
|
|
31364
|
-
|
|
31365
|
-
|
|
31366
|
-
text: JSON.stringify({
|
|
31367
|
-
error: "workspace parameter required",
|
|
31368
|
-
suggestion: "Multiple workspaces are available. Pass `workspace` with one of the names below.",
|
|
31369
|
-
workspaces: this.workspaces.map((w) => ({
|
|
31370
|
-
name: w.name,
|
|
31371
|
-
root: w.root
|
|
31372
|
-
}))
|
|
31373
|
-
})
|
|
31374
|
-
}
|
|
31375
|
-
]
|
|
31376
|
-
};
|
|
31829
|
+
return this.errorResult("workspace parameter required", {
|
|
31830
|
+
suggestion: "Multiple workspaces are available. Pass `workspace` with one of the names below.",
|
|
31831
|
+
workspaces: this.workspaces.map((w) => ({ name: w.name, root: w.root }))
|
|
31832
|
+
});
|
|
31377
31833
|
}
|
|
31378
|
-
|
|
31379
|
-
|
|
31380
|
-
|
|
31381
|
-
|
|
31382
|
-
|
|
31383
|
-
|
|
31384
|
-
|
|
31385
|
-
|
|
31386
|
-
|
|
31387
|
-
|
|
31388
|
-
|
|
31389
|
-
|
|
31390
|
-
|
|
31391
|
-
|
|
31392
|
-
|
|
31393
|
-
|
|
31394
|
-
|
|
31395
|
-
|
|
31396
|
-
|
|
31397
|
-
|
|
31834
|
+
/** Wrap a JSON-serialisable payload as a text tool result. */
|
|
31835
|
+
jsonResult(payload) {
|
|
31836
|
+
return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] };
|
|
31837
|
+
}
|
|
31838
|
+
/** Wrap an error string (with optional extra fields) as a tool result. */
|
|
31839
|
+
errorResult(error47, extra) {
|
|
31840
|
+
return this.jsonResult({ error: error47, ...extra });
|
|
31841
|
+
}
|
|
31842
|
+
/**
|
|
31843
|
+
* List workspaces, or -- when any wiring field is present -- update the
|
|
31844
|
+
* target workspace's config. `workspace` selects which; every other key is
|
|
31845
|
+
* treated as a wiring patch. No wiring keys means the list query.
|
|
31846
|
+
*/
|
|
31847
|
+
async handleWorkspaces(args) {
|
|
31848
|
+
const { workspace, ...patch } = args;
|
|
31849
|
+
if (Object.keys(patch).length === 0) {
|
|
31850
|
+
return this.jsonResult({
|
|
31851
|
+
workspaces: this.workspaces.map((w) => ({
|
|
31852
|
+
name: w.name,
|
|
31853
|
+
root: w.root,
|
|
31854
|
+
isDefault: w.name === this.defaultWorkspace?.name
|
|
31855
|
+
})),
|
|
31856
|
+
defaultWorkspace: this.defaultWorkspace?.name ?? null
|
|
31857
|
+
});
|
|
31858
|
+
}
|
|
31859
|
+
return this.updateWorkspaceConfig(workspace, patch);
|
|
31860
|
+
}
|
|
31861
|
+
/**
|
|
31862
|
+
* Write a WIRING patch to a workspace's config.rafters.json. Rejects the
|
|
31863
|
+
* designer-owned keys (intent, darkMode, fonts -> Studio) and add-managed
|
|
31864
|
+
* keys (installed -> `rafters add`) with a pointer to the right surface, so
|
|
31865
|
+
* this path structurally cannot remove designer choice. Only the fields in
|
|
31866
|
+
* the patch change; everything else in the config is preserved.
|
|
31867
|
+
*/
|
|
31868
|
+
async updateWorkspaceConfig(workspaceName, patch) {
|
|
31869
|
+
const resolved = this.resolve(workspaceName);
|
|
31870
|
+
if (!resolved) {
|
|
31871
|
+
return this.workspaceRequiredError();
|
|
31872
|
+
}
|
|
31873
|
+
const studioKeys = STUDIO_OWNED_KEYS.filter((k) => k in patch);
|
|
31874
|
+
if (studioKeys.length > 0) {
|
|
31875
|
+
return this.errorResult(
|
|
31876
|
+
`${studioKeys.join(", ")} ${studioKeys.length > 1 ? "are" : "is"} a designer decision owned by Rafters Studio, not the MCP. Set ${studioKeys.length > 1 ? "them" : "it"} in Studio.`
|
|
31877
|
+
);
|
|
31878
|
+
}
|
|
31879
|
+
const addKeys = ADD_MANAGED_KEYS.filter((k) => k in patch);
|
|
31880
|
+
if (addKeys.length > 0) {
|
|
31881
|
+
return this.errorResult(`${addKeys.join(", ")} is managed by \`rafters add\`, not the MCP.`);
|
|
31882
|
+
}
|
|
31883
|
+
const result = ConfigWiringSchema.safeParse(patch);
|
|
31884
|
+
if (!result.success) {
|
|
31885
|
+
return this.errorResult(`invalid wiring patch: ${result.error.message}`);
|
|
31886
|
+
}
|
|
31887
|
+
if (Object.keys(result.data).length === 0) {
|
|
31888
|
+
return this.errorResult("no writable wiring fields provided");
|
|
31889
|
+
}
|
|
31890
|
+
const config2 = await this.readConfig(resolved.root);
|
|
31891
|
+
if (!config2) {
|
|
31892
|
+
return this.errorResult(
|
|
31893
|
+
`no config at ${getRaftersPaths(resolved.root).config} -- run \`rafters init\` first`
|
|
31894
|
+
);
|
|
31895
|
+
}
|
|
31896
|
+
const updated = { ...config2, ...result.data };
|
|
31897
|
+
if (result.data.exports !== void 0) {
|
|
31898
|
+
updated.exports = { ...config2.exports, ...result.data.exports };
|
|
31899
|
+
}
|
|
31900
|
+
try {
|
|
31901
|
+
await this.writeConfig(resolved.root, updated);
|
|
31902
|
+
} catch (err) {
|
|
31903
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
31904
|
+
return this.errorResult(`failed to write config: ${message}`);
|
|
31905
|
+
}
|
|
31906
|
+
return this.jsonResult({ ok: true, workspace: resolved.name, updated: result.data });
|
|
31398
31907
|
}
|
|
31399
31908
|
/**
|
|
31400
31909
|
* Recursively discover composites under the given directories via the shared
|
|
@@ -31423,6 +31932,138 @@ var RaftersToolHandler = class {
|
|
|
31423
31932
|
this.compositesLoadedFor.add(workspace.root);
|
|
31424
31933
|
}
|
|
31425
31934
|
}
|
|
31935
|
+
/**
|
|
31936
|
+
* Read and migrate a workspace's `.rafters/config.rafters.json`. Returns null
|
|
31937
|
+
* when the file is absent or unparseable. The single config read the MCP
|
|
31938
|
+
* tools share -- composite paths and the registry URL both come through here.
|
|
31939
|
+
*/
|
|
31940
|
+
async readConfig(workspaceRoot) {
|
|
31941
|
+
const paths = getRaftersPaths(workspaceRoot);
|
|
31942
|
+
try {
|
|
31943
|
+
return migrateConfig(
|
|
31944
|
+
JSON.parse(await readFile6(paths.config, "utf-8"))
|
|
31945
|
+
);
|
|
31946
|
+
} catch {
|
|
31947
|
+
return null;
|
|
31948
|
+
}
|
|
31949
|
+
}
|
|
31950
|
+
/** Persist a workspace's config back to `.rafters/config.rafters.json`. */
|
|
31951
|
+
async writeConfig(workspaceRoot, config2) {
|
|
31952
|
+
const paths = getRaftersPaths(workspaceRoot);
|
|
31953
|
+
await writeFile4(paths.config, `${JSON.stringify(config2, null, 2)}
|
|
31954
|
+
`);
|
|
31955
|
+
}
|
|
31956
|
+
/**
|
|
31957
|
+
* Resolve the registry client for a workspace, honoring its configured
|
|
31958
|
+
* `registryUrl`. Workspaces with no config, or no `registryUrl`, share the
|
|
31959
|
+
* default singleton. Clients are cached per URL so each keeps its fetch cache.
|
|
31960
|
+
*/
|
|
31961
|
+
async registryClientFor(workspace) {
|
|
31962
|
+
if (!workspace) return registryClient;
|
|
31963
|
+
const url3 = (await this.readConfig(workspace.root))?.registryUrl;
|
|
31964
|
+
if (!url3) return registryClient;
|
|
31965
|
+
let client = this.registryClients.get(url3);
|
|
31966
|
+
if (!client) {
|
|
31967
|
+
client = new RegistryClient(url3);
|
|
31968
|
+
this.registryClients.set(url3, client);
|
|
31969
|
+
}
|
|
31970
|
+
return client;
|
|
31971
|
+
}
|
|
31972
|
+
/**
|
|
31973
|
+
* Build (once, lazily) and cache the intel graph for a workspace root.
|
|
31974
|
+
* `assembleGraph` (#2072/#2090) consumes the whole-catalog `RegistryItem[]` and
|
|
31975
|
+
* carries each node's complete intelligence and all per-target facets onto the
|
|
31976
|
+
* universal graph. Throws when the catalog can't be loaded (both the bulk
|
|
31977
|
+
* endpoint and the per-item fallback failed) or the graph is structurally
|
|
31978
|
+
* broken (a dangling `composesWith` edge -- #2072's deliberate fail-fast); the
|
|
31979
|
+
* caller converts that into a structured error result. A failed build is never
|
|
31980
|
+
* cached, so the next call retries.
|
|
31981
|
+
*/
|
|
31982
|
+
async ensureGraph(workspace) {
|
|
31983
|
+
const key = workspace?.root ?? "";
|
|
31984
|
+
const cached2 = this.graphsByWorkspace.get(key);
|
|
31985
|
+
if (cached2) return cached2;
|
|
31986
|
+
const graph = assembleGraph(await this.itemsSource(workspace));
|
|
31987
|
+
this.graphsByWorkspace.set(key, graph);
|
|
31988
|
+
return graph;
|
|
31989
|
+
}
|
|
31990
|
+
/**
|
|
31991
|
+
* Resolve a workspace's overlay context: the configured `componentTarget`
|
|
31992
|
+
* (echoed as-is, `undefined` in degraded mode) and its installed set. Per the
|
|
31993
|
+
* integration note on #2074, `installed.primitives` folds into the components
|
|
31994
|
+
* set -- a `primitive`-kind item maps to graph kind `component`, so without the
|
|
31995
|
+
* fold every installed primitive would misreport as `available`. Built here
|
|
31996
|
+
* rather than by mutating `buildInstalledSet`'s output, leaving overlay.ts
|
|
31997
|
+
* untouched.
|
|
31998
|
+
*
|
|
31999
|
+
* `componentTarget` comes off unvalidated on-disk config (`readConfig` is a raw
|
|
32000
|
+
* `JSON.parse`), so it is run through `ComponentTargetSchema` here rather than
|
|
32001
|
+
* trusted as a `ComponentTarget` -- a stale or typo'd value falls back to
|
|
32002
|
+
* degraded mode (`undefined` target) instead of silently forcing
|
|
32003
|
+
* `rendersForTarget` false for every node.
|
|
32004
|
+
*/
|
|
32005
|
+
async overlayContext(workspace) {
|
|
32006
|
+
const config2 = workspace ? await this.readConfig(workspace.root) : null;
|
|
32007
|
+
const base = buildInstalledSet(config2 ?? {});
|
|
32008
|
+
const components = /* @__PURE__ */ new Set([...base.components, ...config2?.installed?.primitives ?? []]);
|
|
32009
|
+
const parsedTarget = ComponentTargetSchema.safeParse(config2?.componentTarget);
|
|
32010
|
+
return {
|
|
32011
|
+
target: parsedTarget.success ? parsedTarget.data : void 0,
|
|
32012
|
+
installed: { components, composites: base.composites }
|
|
32013
|
+
};
|
|
32014
|
+
}
|
|
32015
|
+
/**
|
|
32016
|
+
* The `rafters_describe` dispatcher -- the one seam that composes #2072/#2074/
|
|
32017
|
+
* #2075. A natural-language question routes through the intent door
|
|
32018
|
+
* (`matchIntent`); a dot-address resolves through the workspace overlay
|
|
32019
|
+
* (`describeWithOverlay`, which delegates to #2072's `describe`).
|
|
32020
|
+
*/
|
|
32021
|
+
async handleDescribe(address, workspaceName) {
|
|
32022
|
+
const resolved = this.resolve(workspaceName);
|
|
32023
|
+
if (workspaceName && !resolved) {
|
|
32024
|
+
return this.workspaceRequiredError();
|
|
32025
|
+
}
|
|
32026
|
+
let graph;
|
|
32027
|
+
try {
|
|
32028
|
+
graph = await this.ensureGraph(resolved);
|
|
32029
|
+
} catch (err) {
|
|
32030
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
32031
|
+
return this.errorResult(`failed to build intel graph: ${message}`);
|
|
32032
|
+
}
|
|
32033
|
+
if (isNaturalLanguageQuery(address)) {
|
|
32034
|
+
return this.jsonResult(matchIntent(address, graph));
|
|
32035
|
+
}
|
|
32036
|
+
const ctx = await this.overlayContext(resolved);
|
|
32037
|
+
return this.jsonResult(describeWithOverlay(address, graph, ctx));
|
|
32038
|
+
}
|
|
32039
|
+
/**
|
|
32040
|
+
* The `rafters_generate` stub (Issue E). Registered now so the surface shape
|
|
32041
|
+
* (name, input schema) stabilizes before the generator lands; it never
|
|
32042
|
+
* attempts real composition. Deliberately does NOT build the graph: nothing
|
|
32043
|
+
* here reads it, and a build failure must not turn an honest stub into an
|
|
32044
|
+
* error result.
|
|
32045
|
+
*/
|
|
32046
|
+
async handleGenerate(intent, workspaceName) {
|
|
32047
|
+
const resolved = this.resolve(workspaceName);
|
|
32048
|
+
if (workspaceName && !resolved) {
|
|
32049
|
+
return this.workspaceRequiredError();
|
|
32050
|
+
}
|
|
32051
|
+
return this.jsonResult({
|
|
32052
|
+
implemented: false,
|
|
32053
|
+
note: `generate is a spike -- see issue E; not yet implemented (requested: ${intent})`
|
|
32054
|
+
});
|
|
32055
|
+
}
|
|
32056
|
+
/**
|
|
32057
|
+
* Stamp the deprecated marker as a top-level field. Objects gain a sibling
|
|
32058
|
+
* `deprecated` key; the rare array/leaf result is wrapped so the marker still
|
|
32059
|
+
* rides at top level.
|
|
32060
|
+
*/
|
|
32061
|
+
withDeprecated(payload) {
|
|
32062
|
+
if (typeof payload === "object" && payload !== null && !Array.isArray(payload)) {
|
|
32063
|
+
return { ...payload, deprecated: DEPRECATED_MSG };
|
|
32064
|
+
}
|
|
32065
|
+
return { result: payload, deprecated: DEPRECATED_MSG };
|
|
32066
|
+
}
|
|
31426
32067
|
/**
|
|
31427
32068
|
* Resolve the set of folders to scan for composite manifests in a workspace.
|
|
31428
32069
|
* Reads `.rafters/config.rafters.json` and applies the workspace's
|
|
@@ -31432,13 +32073,7 @@ var RaftersToolHandler = class {
|
|
|
31432
32073
|
*/
|
|
31433
32074
|
async compositeReadRoots(workspaceRoot) {
|
|
31434
32075
|
const paths = getRaftersPaths(workspaceRoot);
|
|
31435
|
-
|
|
31436
|
-
try {
|
|
31437
|
-
config2 = migrateConfig(
|
|
31438
|
-
JSON.parse(await readFile6(paths.config, "utf-8"))
|
|
31439
|
-
);
|
|
31440
|
-
} catch {
|
|
31441
|
-
}
|
|
32076
|
+
const config2 = await this.readConfig(workspaceRoot);
|
|
31442
32077
|
if (!config2?.compositesPath) {
|
|
31443
32078
|
return [join12(paths.root, "composites")];
|
|
31444
32079
|
}
|
|
@@ -31446,16 +32081,16 @@ var RaftersToolHandler = class {
|
|
|
31446
32081
|
}
|
|
31447
32082
|
async handleComposite(args) {
|
|
31448
32083
|
const { id, query, category, workspace } = args;
|
|
32084
|
+
if (id) {
|
|
32085
|
+
return this.describeById(id, workspace);
|
|
32086
|
+
}
|
|
31449
32087
|
const resolved = this.resolve(workspace);
|
|
31450
32088
|
if (workspace && !resolved) {
|
|
31451
32089
|
return this.workspaceRequiredError();
|
|
31452
32090
|
}
|
|
31453
32091
|
await this.ensureCompositesLoaded(resolved);
|
|
31454
32092
|
let composites2;
|
|
31455
|
-
if (
|
|
31456
|
-
const c4 = get2(id);
|
|
31457
|
-
composites2 = c4 ? [c4] : [];
|
|
31458
|
-
} else if (query) {
|
|
32093
|
+
if (query) {
|
|
31459
32094
|
composites2 = search(query);
|
|
31460
32095
|
} else if (category) {
|
|
31461
32096
|
composites2 = getByCategory(category);
|
|
@@ -31480,9 +32115,7 @@ var RaftersToolHandler = class {
|
|
|
31480
32115
|
// are listed -- the array is empty when nothing is constrained.
|
|
31481
32116
|
blockRules: c4.blocks.filter((b2) => b2.rules && b2.rules.length > 0).map((b2) => ({ id: b2.id, type: b2.type, rules: b2.rules }))
|
|
31482
32117
|
}));
|
|
31483
|
-
return {
|
|
31484
|
-
content: [{ type: "text", text: JSON.stringify({ composites: result }, null, 2) }]
|
|
31485
|
-
};
|
|
32118
|
+
return this.jsonResult({ composites: result, deprecated: DEPRECATED_MSG });
|
|
31486
32119
|
}
|
|
31487
32120
|
async handlePattern(args) {
|
|
31488
32121
|
const { solves, query, workspace } = args;
|
|
@@ -31509,17 +32142,10 @@ var RaftersToolHandler = class {
|
|
|
31509
32142
|
id: c4.manifest.id,
|
|
31510
32143
|
solves: c4.manifest.solves
|
|
31511
32144
|
}));
|
|
31512
|
-
return {
|
|
31513
|
-
|
|
31514
|
-
|
|
31515
|
-
|
|
31516
|
-
text: JSON.stringify({
|
|
31517
|
-
error: "No patterns found matching query",
|
|
31518
|
-
available
|
|
31519
|
-
})
|
|
31520
|
-
}
|
|
31521
|
-
]
|
|
31522
|
-
};
|
|
32145
|
+
return this.errorResult("No patterns found matching query", {
|
|
32146
|
+
available,
|
|
32147
|
+
deprecated: DEPRECATED_MSG
|
|
32148
|
+
});
|
|
31523
32149
|
}
|
|
31524
32150
|
const patterns = composites2.map((c4) => ({
|
|
31525
32151
|
id: c4.manifest.id,
|
|
@@ -31529,51 +32155,38 @@ var RaftersToolHandler = class {
|
|
|
31529
32155
|
cognitiveLoad: c4.manifest.cognitiveLoad,
|
|
31530
32156
|
usagePatterns: c4.manifest.usagePatterns
|
|
31531
32157
|
}));
|
|
31532
|
-
return {
|
|
31533
|
-
|
|
31534
|
-
|
|
32158
|
+
return this.jsonResult({ patterns, deprecated: DEPRECATED_MSG });
|
|
32159
|
+
}
|
|
32160
|
+
/**
|
|
32161
|
+
* DEPRECATED alias for `rafters_describe`. A component resolves by id through
|
|
32162
|
+
* the overlay exactly as `describe(<id>)` does (#2072's resolver has no
|
|
32163
|
+
* separate component/composite address form -- `describe(<id>)` resolves either
|
|
32164
|
+
* kind), so this is a direct, lossless forward with the deprecated marker added.
|
|
32165
|
+
*/
|
|
32166
|
+
async handleComponent(componentName, workspaceName) {
|
|
32167
|
+
return this.describeById(componentName, workspaceName);
|
|
31535
32168
|
}
|
|
31536
|
-
|
|
32169
|
+
/**
|
|
32170
|
+
* Shared by the deprecated `rafters_component` and `rafters_composite({id})`
|
|
32171
|
+
* paths: resolve one id through the overlay, stamp the deprecated marker.
|
|
32172
|
+
*/
|
|
32173
|
+
async describeById(id, workspaceName) {
|
|
32174
|
+
const resolved = this.resolve(workspaceName);
|
|
32175
|
+
if (workspaceName && !resolved) {
|
|
32176
|
+
return this.workspaceRequiredError();
|
|
32177
|
+
}
|
|
32178
|
+
let graph;
|
|
31537
32179
|
try {
|
|
31538
|
-
|
|
31539
|
-
return {
|
|
31540
|
-
content: [
|
|
31541
|
-
{
|
|
31542
|
-
type: "text",
|
|
31543
|
-
text: JSON.stringify(
|
|
31544
|
-
{
|
|
31545
|
-
name: item.name,
|
|
31546
|
-
type: item.type,
|
|
31547
|
-
description: item.description,
|
|
31548
|
-
primitives: item.primitives,
|
|
31549
|
-
rules: item.rules,
|
|
31550
|
-
composites: item.composites,
|
|
31551
|
-
files: item.files,
|
|
31552
|
-
// The intelligence field carries the WHY of the component:
|
|
31553
|
-
// cognitive load, accessibility, do/never, semantic meaning.
|
|
31554
|
-
// Extracted from JSDoc by the registry generator and present
|
|
31555
|
-
// on every component JSON. Previously stripped by the schema
|
|
31556
|
-
// (not declared) and not referenced by the handler -- the
|
|
31557
|
-
// tool's whole reason for existing went missing somewhere.
|
|
31558
|
-
intelligence: item.intelligence
|
|
31559
|
-
},
|
|
31560
|
-
null,
|
|
31561
|
-
2
|
|
31562
|
-
)
|
|
31563
|
-
}
|
|
31564
|
-
]
|
|
31565
|
-
};
|
|
32180
|
+
graph = await this.ensureGraph(resolved);
|
|
31566
32181
|
} catch (err) {
|
|
31567
32182
|
const message = err instanceof Error ? err.message : "Unknown error";
|
|
31568
|
-
return {
|
|
31569
|
-
|
|
31570
|
-
|
|
31571
|
-
type: "text",
|
|
31572
|
-
text: JSON.stringify({ error: message })
|
|
31573
|
-
}
|
|
31574
|
-
]
|
|
31575
|
-
};
|
|
32183
|
+
return this.errorResult(`failed to build intel graph: ${message}`, {
|
|
32184
|
+
deprecated: DEPRECATED_MSG
|
|
32185
|
+
});
|
|
31576
32186
|
}
|
|
32187
|
+
const ctx = await this.overlayContext(resolved);
|
|
32188
|
+
const out = describeWithOverlay(id, graph, ctx);
|
|
32189
|
+
return this.jsonResult(this.withDeprecated(out));
|
|
31577
32190
|
}
|
|
31578
32191
|
};
|
|
31579
32192
|
|
|
@@ -31650,8 +32263,8 @@ import { existsSync as existsSync8 } from "fs";
|
|
|
31650
32263
|
import { resolve as resolve6 } from "path";
|
|
31651
32264
|
|
|
31652
32265
|
// ../studio/src/api/vite-plugin.ts
|
|
31653
|
-
import { readFile as readFile7, writeFile as
|
|
31654
|
-
import { isAbsolute as
|
|
32266
|
+
import { readFile as readFile7, writeFile as writeFile5 } from "fs/promises";
|
|
32267
|
+
import { isAbsolute as isAbsolute4, join as join14 } from "path";
|
|
31655
32268
|
var REGISTRY_PLUGINS3 = [scalePlugin, contrastPlugin, statePlugin, invertPlugin];
|
|
31656
32269
|
var STUDIO_REASON_DEFAULT = "studio interactive edit";
|
|
31657
32270
|
var TokenResponseSchema = external_exports.object({
|
|
@@ -31712,7 +32325,7 @@ async function readRaftersConfig() {
|
|
|
31712
32325
|
}
|
|
31713
32326
|
function validateFontsPath(path) {
|
|
31714
32327
|
if (path === null || path === void 0) return null;
|
|
31715
|
-
if (
|
|
32328
|
+
if (isAbsolute4(path)) return "fonts path must be relative";
|
|
31716
32329
|
return null;
|
|
31717
32330
|
}
|
|
31718
32331
|
function validateIntent(intent) {
|
|
@@ -31731,6 +32344,17 @@ var SetTokenMessageSchema = external_exports.object({
|
|
|
31731
32344
|
persist: external_exports.boolean().optional(),
|
|
31732
32345
|
reason: external_exports.string().optional()
|
|
31733
32346
|
});
|
|
32347
|
+
var ConfigPatchSchema = external_exports.object({
|
|
32348
|
+
intent: external_exports.string().min(1).optional(),
|
|
32349
|
+
darkMode: external_exports.enum(["class", "media"]).optional(),
|
|
32350
|
+
fonts: FontsConfigSchema.optional()
|
|
32351
|
+
}).refine((patch) => Object.keys(patch).length > 0, {
|
|
32352
|
+
message: "patch must set at least one of: intent, darkMode, fonts"
|
|
32353
|
+
});
|
|
32354
|
+
function ridOf(rawData) {
|
|
32355
|
+
const rid = rawData?.__rid;
|
|
32356
|
+
return typeof rid === "string" ? rid : void 0;
|
|
32357
|
+
}
|
|
31734
32358
|
var TokenPatchSchema = TokenSchema.pick({
|
|
31735
32359
|
value: true,
|
|
31736
32360
|
trustLevel: true,
|
|
@@ -32241,83 +32865,60 @@ function studioApiPlugin() {
|
|
|
32241
32865
|
client.send("rafters:token-updated", { ok: false, error: String(error47) });
|
|
32242
32866
|
}
|
|
32243
32867
|
});
|
|
32244
|
-
server.ws.on("rafters:get-config", async (
|
|
32868
|
+
server.ws.on("rafters:get-config", async (rawData, client) => {
|
|
32869
|
+
const __rid = ridOf(rawData);
|
|
32870
|
+
const reply = (msg) => client.send("rafters:config", { ...msg, __rid });
|
|
32245
32871
|
const config2 = await readRaftersConfig();
|
|
32246
32872
|
if (!config2) {
|
|
32247
|
-
|
|
32248
|
-
ok: false,
|
|
32249
|
-
error: `config not found at ${configPath}`
|
|
32250
|
-
});
|
|
32873
|
+
reply({ ok: false, error: `config not found at ${configPath}` });
|
|
32251
32874
|
return;
|
|
32252
32875
|
}
|
|
32253
|
-
|
|
32876
|
+
reply({ ok: true, config: config2 });
|
|
32254
32877
|
});
|
|
32255
|
-
server.ws.on("rafters:set-
|
|
32256
|
-
const
|
|
32878
|
+
server.ws.on("rafters:set-config", async (rawData, client) => {
|
|
32879
|
+
const __rid = ridOf(rawData);
|
|
32880
|
+
const reply = (msg) => client.send("rafters:config", { ...msg, __rid });
|
|
32881
|
+
const parsed = ConfigPatchSchema.safeParse(rawData);
|
|
32257
32882
|
if (!parsed.success) {
|
|
32258
|
-
|
|
32259
|
-
ok: false,
|
|
32260
|
-
error: `Invalid message: ${parsed.error.message}`
|
|
32261
|
-
});
|
|
32883
|
+
reply({ ok: false, error: `Invalid patch: ${parsed.error.message}` });
|
|
32262
32884
|
return;
|
|
32263
32885
|
}
|
|
32264
|
-
const
|
|
32265
|
-
|
|
32266
|
-
|
|
32267
|
-
|
|
32268
|
-
|
|
32269
|
-
|
|
32270
|
-
|
|
32271
|
-
if (!config2) {
|
|
32272
|
-
client.send("rafters:intent-updated", {
|
|
32273
|
-
ok: false,
|
|
32274
|
-
error: `config not found at ${configPath}`
|
|
32275
|
-
});
|
|
32276
|
-
return;
|
|
32277
|
-
}
|
|
32278
|
-
const updated = { ...config2, intent };
|
|
32279
|
-
try {
|
|
32280
|
-
await writeFile4(configPath, JSON.stringify(updated, null, 2));
|
|
32281
|
-
client.send("rafters:intent-updated", { ok: true, intent });
|
|
32282
|
-
} catch (error47) {
|
|
32283
|
-
console.log(`[rafters] Intent update failed: ${error47}`);
|
|
32284
|
-
client.send("rafters:intent-updated", { ok: false, error: String(error47) });
|
|
32285
|
-
}
|
|
32286
|
-
});
|
|
32287
|
-
server.ws.on("rafters:set-fonts", async (rawData, client) => {
|
|
32288
|
-
const parsed = FontsConfigSchema.safeParse(rawData);
|
|
32289
|
-
if (!parsed.success) {
|
|
32290
|
-
client.send("rafters:fonts-updated", {
|
|
32291
|
-
ok: false,
|
|
32292
|
-
error: `Invalid message: ${parsed.error.message}`
|
|
32293
|
-
});
|
|
32294
|
-
return;
|
|
32886
|
+
const patch = parsed.data;
|
|
32887
|
+
if (patch.intent !== void 0) {
|
|
32888
|
+
const intentError = validateIntent(patch.intent);
|
|
32889
|
+
if (intentError) {
|
|
32890
|
+
reply({ ok: false, error: intentError });
|
|
32891
|
+
return;
|
|
32892
|
+
}
|
|
32295
32893
|
}
|
|
32296
|
-
|
|
32297
|
-
|
|
32298
|
-
|
|
32299
|
-
|
|
32300
|
-
|
|
32894
|
+
if (patch.fonts?.path !== void 0) {
|
|
32895
|
+
const pathError = validateFontsPath(patch.fonts.path);
|
|
32896
|
+
if (pathError) {
|
|
32897
|
+
reply({ ok: false, error: pathError });
|
|
32898
|
+
return;
|
|
32899
|
+
}
|
|
32301
32900
|
}
|
|
32302
32901
|
const config2 = await readRaftersConfig();
|
|
32303
32902
|
if (!config2) {
|
|
32304
|
-
|
|
32305
|
-
ok: false,
|
|
32306
|
-
error: `config not found at ${configPath}`
|
|
32307
|
-
});
|
|
32903
|
+
reply({ ok: false, error: `config not found at ${configPath}` });
|
|
32308
32904
|
return;
|
|
32309
32905
|
}
|
|
32310
|
-
const
|
|
32311
|
-
|
|
32312
|
-
if (
|
|
32313
|
-
if (
|
|
32314
|
-
|
|
32906
|
+
const updated = { ...config2 };
|
|
32907
|
+
if (patch.intent !== void 0) updated.intent = patch.intent;
|
|
32908
|
+
if (patch.darkMode !== void 0) updated.darkMode = patch.darkMode;
|
|
32909
|
+
if (patch.fonts !== void 0) {
|
|
32910
|
+
const merged = { ...config2.fonts };
|
|
32911
|
+
if (patch.fonts.path !== void 0) merged.path = patch.fonts.path;
|
|
32912
|
+
if (patch.fonts.imports !== void 0) merged.imports = patch.fonts.imports;
|
|
32913
|
+
updated.fonts = merged;
|
|
32914
|
+
}
|
|
32315
32915
|
try {
|
|
32316
|
-
await
|
|
32317
|
-
|
|
32916
|
+
await writeFile5(configPath, `${JSON.stringify(updated, null, 2)}
|
|
32917
|
+
`);
|
|
32918
|
+
reply({ ok: true, config: updated });
|
|
32318
32919
|
} catch (error47) {
|
|
32319
|
-
console.log(`[rafters]
|
|
32320
|
-
|
|
32920
|
+
console.log(`[rafters] Config update failed: ${error47}`);
|
|
32921
|
+
reply({ ok: false, error: String(error47) });
|
|
32321
32922
|
}
|
|
32322
32923
|
});
|
|
32323
32924
|
server.middlewares.use(async (req, res, next) => {
|