@dereekb/dbx-components-mcp 13.10.6 → 13.10.7
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/dbx-components-mcp.js +2091 -351
- package/generated/angular-material-m3.tokens.mcp.generated.json +1061 -0
- package/generated/angular-material-mdc.tokens.mcp.generated.json +298 -0
- package/generated/dereekb-dbx-web.tokens.mcp.generated.json +987 -0
- package/generated/dereekb-dbx-web.ui-components.mcp.generated.json +28 -0
- package/generated/rule-catalog.generated.json +3 -3
- package/package.json +1 -1
package/dbx-components-mcp.js
CHANGED
|
@@ -5,7 +5,7 @@ const require = __createRequire(import.meta.url);
|
|
|
5
5
|
// packages/dbx-components-mcp/package.json
|
|
6
6
|
var package_default = {
|
|
7
7
|
name: "@dereekb/dbx-components-mcp",
|
|
8
|
-
version: "13.10.
|
|
8
|
+
version: "13.10.7",
|
|
9
9
|
type: "module",
|
|
10
10
|
bin: {
|
|
11
11
|
"dbx-components-mcp": "dbx-components-mcp.js"
|
|
@@ -1987,13 +1987,13 @@ function parseDecoratorInput(property) {
|
|
|
1987
1987
|
}
|
|
1988
1988
|
}
|
|
1989
1989
|
const required = requiredFromDecorator ?? !property.hasQuestionToken();
|
|
1990
|
-
const
|
|
1990
|
+
const type68 = property.getTypeNode()?.getText() ?? "unknown";
|
|
1991
1991
|
const initializer = property.getInitializer();
|
|
1992
1992
|
const defaultValue = initializer === void 0 ? void 0 : initializer.getText();
|
|
1993
1993
|
return {
|
|
1994
1994
|
propertyName,
|
|
1995
1995
|
alias: alias ?? propertyName,
|
|
1996
|
-
type:
|
|
1996
|
+
type: type68,
|
|
1997
1997
|
required,
|
|
1998
1998
|
description: readPropertyDescription(property),
|
|
1999
1999
|
...defaultValue === void 0 ? {} : { defaultValue }
|
|
@@ -2059,22 +2059,22 @@ function parseDecoratorOutput(property) {
|
|
|
2059
2059
|
alias = decoratorArg.getLiteralText();
|
|
2060
2060
|
}
|
|
2061
2061
|
const initializer = property.getInitializer();
|
|
2062
|
-
let
|
|
2062
|
+
let type68 = "unknown";
|
|
2063
2063
|
if (initializer !== void 0 && Node4.isNewExpression(initializer)) {
|
|
2064
2064
|
const typeArgs = initializer.getTypeArguments();
|
|
2065
2065
|
if (typeArgs.length > 0) {
|
|
2066
|
-
|
|
2066
|
+
type68 = typeArgs[0].getText();
|
|
2067
2067
|
}
|
|
2068
2068
|
} else {
|
|
2069
2069
|
const explicit = property.getTypeNode()?.getText();
|
|
2070
2070
|
if (explicit !== void 0) {
|
|
2071
|
-
|
|
2071
|
+
type68 = explicit;
|
|
2072
2072
|
}
|
|
2073
2073
|
}
|
|
2074
2074
|
return {
|
|
2075
2075
|
propertyName,
|
|
2076
2076
|
name: alias ?? propertyName,
|
|
2077
|
-
type:
|
|
2077
|
+
type: type68,
|
|
2078
2078
|
description: readPropertyDescription(property)
|
|
2079
2079
|
};
|
|
2080
2080
|
}
|
|
@@ -2089,7 +2089,7 @@ function parseSignalOutput(property) {
|
|
|
2089
2089
|
}
|
|
2090
2090
|
const propertyName = property.getName();
|
|
2091
2091
|
const typeArgs = initializer.getTypeArguments();
|
|
2092
|
-
const
|
|
2092
|
+
const type68 = typeArgs.length > 0 ? typeArgs[0].getText() : "void";
|
|
2093
2093
|
const args = initializer.getArguments();
|
|
2094
2094
|
let alias;
|
|
2095
2095
|
if (args.length > 0 && Node4.isObjectLiteralExpression(args[0])) {
|
|
@@ -2098,7 +2098,7 @@ function parseSignalOutput(property) {
|
|
|
2098
2098
|
return {
|
|
2099
2099
|
propertyName,
|
|
2100
2100
|
name: alias ?? propertyName,
|
|
2101
|
-
type:
|
|
2101
|
+
type: type68,
|
|
2102
2102
|
description: readPropertyDescription(property)
|
|
2103
2103
|
};
|
|
2104
2104
|
}
|
|
@@ -2704,7 +2704,13 @@ var DbxMcpConfig = type13({
|
|
|
2704
2704
|
"forgeFields?": ClusterSection,
|
|
2705
2705
|
"pipes?": ClusterSection,
|
|
2706
2706
|
"actions?": ClusterSection,
|
|
2707
|
-
"filters?": ClusterSection
|
|
2707
|
+
"filters?": ClusterSection,
|
|
2708
|
+
"tokens?": ClusterSection,
|
|
2709
|
+
"uiSmellCheck?": {
|
|
2710
|
+
"projectConventions?": {
|
|
2711
|
+
"cardWrapperClasses?": "string[]"
|
|
2712
|
+
}
|
|
2713
|
+
}
|
|
2708
2714
|
});
|
|
2709
2715
|
|
|
2710
2716
|
// packages/dbx-components-mcp/src/config/load-config.ts
|
|
@@ -4140,11 +4146,241 @@ async function loadSemanticTypeRegistry(input) {
|
|
|
4140
4146
|
return result;
|
|
4141
4147
|
}
|
|
4142
4148
|
|
|
4143
|
-
// packages/dbx-components-mcp/src/manifest/load-
|
|
4149
|
+
// packages/dbx-components-mcp/src/manifest/load-tokens-registry.ts
|
|
4144
4150
|
import { existsSync as existsSync6 } from "node:fs";
|
|
4145
4151
|
import { dirname as dirname6, isAbsolute as isAbsolute6, resolve as resolve12 } from "node:path";
|
|
4146
4152
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
4147
4153
|
|
|
4154
|
+
// packages/dbx-components-mcp/src/registry/tokens-runtime.ts
|
|
4155
|
+
function createTokenRegistry(loaded) {
|
|
4156
|
+
const entries = Array.from(loaded.entries.values()).sort((a, b) => a.cssVariable.localeCompare(b.cssVariable));
|
|
4157
|
+
return createTokenRegistryFromEntries({ entries, loadedSources: loaded.loadedSources });
|
|
4158
|
+
}
|
|
4159
|
+
function createTokenRegistryFromEntries(input) {
|
|
4160
|
+
const all = [...input.entries].sort((a, b) => a.cssVariable.localeCompare(b.cssVariable));
|
|
4161
|
+
const bySource = /* @__PURE__ */ new Map();
|
|
4162
|
+
const byRole = /* @__PURE__ */ new Map();
|
|
4163
|
+
const byCssVariable = /* @__PURE__ */ new Map();
|
|
4164
|
+
const byScssVariable = /* @__PURE__ */ new Map();
|
|
4165
|
+
const byComponent = /* @__PURE__ */ new Map();
|
|
4166
|
+
for (const entry of all) {
|
|
4167
|
+
pushInto6(bySource, entry.source, entry);
|
|
4168
|
+
pushInto6(byRole, entry.role, entry);
|
|
4169
|
+
if (!byCssVariable.has(entry.cssVariable)) {
|
|
4170
|
+
byCssVariable.set(entry.cssVariable, entry);
|
|
4171
|
+
}
|
|
4172
|
+
if (entry.scssVariable !== void 0 && !byScssVariable.has(entry.scssVariable)) {
|
|
4173
|
+
byScssVariable.set(entry.scssVariable, entry);
|
|
4174
|
+
}
|
|
4175
|
+
if (entry.componentScope !== void 0) {
|
|
4176
|
+
pushInto6(byComponent, entry.componentScope, entry);
|
|
4177
|
+
}
|
|
4178
|
+
}
|
|
4179
|
+
const bySourceImmutable = freezeBuckets(bySource);
|
|
4180
|
+
const byRoleImmutable = freezeBuckets(byRole);
|
|
4181
|
+
const registry = {
|
|
4182
|
+
all,
|
|
4183
|
+
loadedSources: [...input.loadedSources],
|
|
4184
|
+
bySource: bySourceImmutable,
|
|
4185
|
+
byRole: byRoleImmutable,
|
|
4186
|
+
findByCssVariable(name) {
|
|
4187
|
+
return byCssVariable.get(name);
|
|
4188
|
+
},
|
|
4189
|
+
findByScssVariable(name) {
|
|
4190
|
+
return byScssVariable.get(name);
|
|
4191
|
+
},
|
|
4192
|
+
findByIntent(query, role) {
|
|
4193
|
+
const trimmed = query.trim().toLowerCase();
|
|
4194
|
+
let matches;
|
|
4195
|
+
if (trimmed.length === 0) {
|
|
4196
|
+
matches = [];
|
|
4197
|
+
} else {
|
|
4198
|
+
const candidates = role !== void 0 ? byRoleImmutable.get(role) ?? [] : all;
|
|
4199
|
+
matches = [];
|
|
4200
|
+
for (const entry of candidates) {
|
|
4201
|
+
let best = 0;
|
|
4202
|
+
for (const intent of entry.intents) {
|
|
4203
|
+
const lower = intent.toLowerCase();
|
|
4204
|
+
let score = 0;
|
|
4205
|
+
if (lower === trimmed) {
|
|
4206
|
+
score = 10;
|
|
4207
|
+
} else if (lower.includes(trimmed)) {
|
|
4208
|
+
score = 5;
|
|
4209
|
+
} else if (trimmed.includes(lower) && lower.length > 0) {
|
|
4210
|
+
score = 3;
|
|
4211
|
+
}
|
|
4212
|
+
if (score > best) {
|
|
4213
|
+
best = score;
|
|
4214
|
+
}
|
|
4215
|
+
}
|
|
4216
|
+
if (best > 0) {
|
|
4217
|
+
matches.push({ entry, score: best });
|
|
4218
|
+
}
|
|
4219
|
+
}
|
|
4220
|
+
matches.sort((a, b) => b.score - a.score);
|
|
4221
|
+
}
|
|
4222
|
+
return matches;
|
|
4223
|
+
},
|
|
4224
|
+
findByValue(value, role) {
|
|
4225
|
+
const trimmed = value.trim();
|
|
4226
|
+
let matches;
|
|
4227
|
+
if (trimmed.length === 0) {
|
|
4228
|
+
matches = [];
|
|
4229
|
+
} else {
|
|
4230
|
+
const candidates = role !== void 0 ? byRoleImmutable.get(role) ?? [] : all;
|
|
4231
|
+
matches = [];
|
|
4232
|
+
for (const entry of candidates) {
|
|
4233
|
+
let score = 0;
|
|
4234
|
+
if (entry.defaults.light !== void 0 && entry.defaults.light === trimmed) score = 10;
|
|
4235
|
+
if (entry.defaults.dark !== void 0 && entry.defaults.dark === trimmed && score < 10) score = 9;
|
|
4236
|
+
if (score === 0 && entry.defaults.light !== void 0 && entry.defaults.light.includes(trimmed)) score = 4;
|
|
4237
|
+
if (score === 0 && entry.defaults.dark !== void 0 && entry.defaults.dark.includes(trimmed)) score = 3;
|
|
4238
|
+
if (score > 0) {
|
|
4239
|
+
matches.push({ entry, score });
|
|
4240
|
+
}
|
|
4241
|
+
}
|
|
4242
|
+
matches.sort((a, b) => b.score - a.score);
|
|
4243
|
+
}
|
|
4244
|
+
return matches;
|
|
4245
|
+
},
|
|
4246
|
+
findByComponent(component) {
|
|
4247
|
+
return byComponent.get(component) ?? [];
|
|
4248
|
+
}
|
|
4249
|
+
};
|
|
4250
|
+
return registry;
|
|
4251
|
+
}
|
|
4252
|
+
var EMPTY_TOKEN_REGISTRY = createTokenRegistryFromEntries({ entries: [], loadedSources: [] });
|
|
4253
|
+
function pushInto6(map, key, entry) {
|
|
4254
|
+
const existing = map.get(key);
|
|
4255
|
+
if (existing === void 0) {
|
|
4256
|
+
map.set(key, [entry]);
|
|
4257
|
+
} else {
|
|
4258
|
+
existing.push(entry);
|
|
4259
|
+
}
|
|
4260
|
+
}
|
|
4261
|
+
function freezeBuckets(map) {
|
|
4262
|
+
const out = /* @__PURE__ */ new Map();
|
|
4263
|
+
for (const [key, list] of map) {
|
|
4264
|
+
out.set(key, [...list]);
|
|
4265
|
+
}
|
|
4266
|
+
return out;
|
|
4267
|
+
}
|
|
4268
|
+
|
|
4269
|
+
// packages/dbx-components-mcp/src/manifest/tokens-schema.ts
|
|
4270
|
+
import { type as type20 } from "arktype";
|
|
4271
|
+
var TOKEN_ROLES = ["color", "text-color", "surface", "spacing", "radius", "elevation", "shadow", "typography", "motion", "state-layer", "size", "breakpoint", "misc"];
|
|
4272
|
+
var TOKEN_SOURCES = ["dbx-web", "mat-sys", "mdc", "app"];
|
|
4273
|
+
var TokenDefaults = type20({
|
|
4274
|
+
"light?": "string",
|
|
4275
|
+
"dark?": "string"
|
|
4276
|
+
});
|
|
4277
|
+
var TokenSourceLocation = type20({
|
|
4278
|
+
file: "string",
|
|
4279
|
+
line: "number"
|
|
4280
|
+
});
|
|
4281
|
+
var TokenEntry = type20({
|
|
4282
|
+
cssVariable: "string",
|
|
4283
|
+
"scssVariable?": "string",
|
|
4284
|
+
source: '"dbx-web" | "mat-sys" | "mdc" | "app"',
|
|
4285
|
+
role: '"color" | "text-color" | "surface" | "spacing" | "radius" | "elevation" | "shadow" | "typography" | "motion" | "state-layer" | "size" | "breakpoint" | "misc"',
|
|
4286
|
+
intents: "string[]",
|
|
4287
|
+
description: "string",
|
|
4288
|
+
"antiUseNotes?": "string",
|
|
4289
|
+
defaults: TokenDefaults,
|
|
4290
|
+
"utilityClasses?": "string[]",
|
|
4291
|
+
"componentScope?": "string",
|
|
4292
|
+
"recommendedPrimitive?": "string",
|
|
4293
|
+
"seeAlso?": "string[]",
|
|
4294
|
+
"sourceLocation?": TokenSourceLocation
|
|
4295
|
+
});
|
|
4296
|
+
var TokenManifest = type20({
|
|
4297
|
+
version: "1",
|
|
4298
|
+
source: "string",
|
|
4299
|
+
module: "string",
|
|
4300
|
+
generatedAt: "string",
|
|
4301
|
+
generator: "string",
|
|
4302
|
+
entries: TokenEntry.array()
|
|
4303
|
+
});
|
|
4304
|
+
|
|
4305
|
+
// packages/dbx-components-mcp/src/manifest/tokens-loader.ts
|
|
4306
|
+
async function loadTokenManifests(input) {
|
|
4307
|
+
const { entries, indexMap, warnings, loadedSources } = await loadManifestsBase(input, {
|
|
4308
|
+
name: "loadTokenManifests",
|
|
4309
|
+
schema: TokenManifest,
|
|
4310
|
+
extractIndexValue: (entry) => entry.role,
|
|
4311
|
+
buildEntryKey: (_manifest, entry) => `${entry.source}::${entry.cssVariable}`
|
|
4312
|
+
});
|
|
4313
|
+
return { entries, roleIndex: indexMap, warnings, loadedSources };
|
|
4314
|
+
}
|
|
4315
|
+
|
|
4316
|
+
// packages/dbx-components-mcp/src/manifest/load-tokens-registry.ts
|
|
4317
|
+
var DEFAULT_BUNDLED_FILENAMES6 = ["dereekb-dbx-web.tokens.mcp.generated.json", "angular-material-m3.tokens.mcp.generated.json", "angular-material-mdc.tokens.mcp.generated.json"];
|
|
4318
|
+
function findPackageRoot6(startUrl) {
|
|
4319
|
+
const startPath = fileURLToPath6(startUrl);
|
|
4320
|
+
let dir = dirname6(startPath);
|
|
4321
|
+
let result;
|
|
4322
|
+
while (result === void 0) {
|
|
4323
|
+
if (existsSync6(resolve12(dir, "package.json"))) {
|
|
4324
|
+
result = dir;
|
|
4325
|
+
} else {
|
|
4326
|
+
const parent = dirname6(dir);
|
|
4327
|
+
if (parent === dir) {
|
|
4328
|
+
throw new Error(`findPackageRoot: no package.json found above ${startPath}`);
|
|
4329
|
+
}
|
|
4330
|
+
dir = parent;
|
|
4331
|
+
}
|
|
4332
|
+
}
|
|
4333
|
+
return result;
|
|
4334
|
+
}
|
|
4335
|
+
var DEFAULT_BUNDLED_PATHS6 = () => {
|
|
4336
|
+
const packageRoot = findPackageRoot6(import.meta.url);
|
|
4337
|
+
return DEFAULT_BUNDLED_FILENAMES6.map((name) => resolve12(packageRoot, "generated", name));
|
|
4338
|
+
};
|
|
4339
|
+
async function loadTokenRegistry(input) {
|
|
4340
|
+
const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS6, readFile: readFile20 } = input;
|
|
4341
|
+
const bundledSources = bundledManifestPaths().map((path) => ({ origin: "bundled", path }));
|
|
4342
|
+
const configResult = await findAndLoadConfig({ cwd, readFile: readFile20 });
|
|
4343
|
+
const externalSources = [];
|
|
4344
|
+
if (configResult.config !== null && configResult.configPath !== null) {
|
|
4345
|
+
const baseDir = dirname6(configResult.configPath);
|
|
4346
|
+
const tokensCluster = configResult.config.tokens;
|
|
4347
|
+
const declaredSources = tokensCluster?.sources ?? [];
|
|
4348
|
+
for (const source of declaredSources) {
|
|
4349
|
+
const absolute = isAbsolute6(source) ? source : resolve12(baseDir, source);
|
|
4350
|
+
externalSources.push({ origin: "external", path: absolute });
|
|
4351
|
+
}
|
|
4352
|
+
const declaredScans = tokensCluster?.scan ?? [];
|
|
4353
|
+
for (const scan of declaredScans) {
|
|
4354
|
+
const out = scan.out;
|
|
4355
|
+
if (typeof out === "string" && out.length > 0) {
|
|
4356
|
+
const absolute = isAbsolute6(out) ? out : resolve12(baseDir, out);
|
|
4357
|
+
externalSources.push({ origin: "external", path: absolute });
|
|
4358
|
+
}
|
|
4359
|
+
}
|
|
4360
|
+
}
|
|
4361
|
+
let registry = EMPTY_TOKEN_REGISTRY;
|
|
4362
|
+
let loaderWarnings = [];
|
|
4363
|
+
const sources = [...bundledSources, ...externalSources];
|
|
4364
|
+
if (sources.length > 0) {
|
|
4365
|
+
const loaded = await loadTokenManifests({ sources, readFile: readFile20 });
|
|
4366
|
+
registry = createTokenRegistry(loaded);
|
|
4367
|
+
loaderWarnings = loaded.warnings;
|
|
4368
|
+
}
|
|
4369
|
+
const result = {
|
|
4370
|
+
registry,
|
|
4371
|
+
configPath: configResult.configPath,
|
|
4372
|
+
configWarnings: configResult.warnings,
|
|
4373
|
+
loaderWarnings,
|
|
4374
|
+
externalSourceCount: externalSources.length
|
|
4375
|
+
};
|
|
4376
|
+
return result;
|
|
4377
|
+
}
|
|
4378
|
+
|
|
4379
|
+
// packages/dbx-components-mcp/src/manifest/load-ui-components-registry.ts
|
|
4380
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
4381
|
+
import { dirname as dirname7, isAbsolute as isAbsolute7, resolve as resolve13 } from "node:path";
|
|
4382
|
+
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
4383
|
+
|
|
4148
4384
|
// packages/dbx-components-mcp/src/registry/ui-components-runtime.ts
|
|
4149
4385
|
function createUiComponentRegistry(loaded) {
|
|
4150
4386
|
const entries = Array.from(loaded.entries.values()).sort((a, b) => a.slug.localeCompare(b.slug));
|
|
@@ -4159,10 +4395,10 @@ function createUiComponentRegistryFromEntries(input) {
|
|
|
4159
4395
|
const byClassName = /* @__PURE__ */ new Map();
|
|
4160
4396
|
const bySelectorToken = /* @__PURE__ */ new Map();
|
|
4161
4397
|
for (const entry of all) {
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4398
|
+
pushInto7(bySlug, entry.slug, entry);
|
|
4399
|
+
pushInto7(byCategory, entry.category, entry);
|
|
4400
|
+
pushInto7(byKind, entry.kind, entry);
|
|
4401
|
+
pushInto7(byModule, entry.module, entry);
|
|
4166
4402
|
byClassName.set(entry.className.toLowerCase(), entry);
|
|
4167
4403
|
for (const token of splitSelectorTokens(entry.selector)) {
|
|
4168
4404
|
if (!bySelectorToken.has(token)) {
|
|
@@ -4214,7 +4450,7 @@ ${entry.description}`.toLowerCase();
|
|
|
4214
4450
|
return registry;
|
|
4215
4451
|
}
|
|
4216
4452
|
var EMPTY_UI_COMPONENT_REGISTRY = createUiComponentRegistryFromEntries({ entries: [], loadedSources: [] });
|
|
4217
|
-
function
|
|
4453
|
+
function pushInto7(map, key, entry) {
|
|
4218
4454
|
const existing = map.get(key);
|
|
4219
4455
|
if (existing === void 0) {
|
|
4220
4456
|
map.set(key, [entry]);
|
|
@@ -4248,16 +4484,16 @@ async function loadUiComponentManifests(input) {
|
|
|
4248
4484
|
}
|
|
4249
4485
|
|
|
4250
4486
|
// packages/dbx-components-mcp/src/manifest/load-ui-components-registry.ts
|
|
4251
|
-
var
|
|
4252
|
-
function
|
|
4253
|
-
const startPath =
|
|
4254
|
-
let dir =
|
|
4487
|
+
var DEFAULT_BUNDLED_FILENAMES7 = ["dereekb-dbx-web.ui-components.mcp.generated.json"];
|
|
4488
|
+
function findPackageRoot7(startUrl) {
|
|
4489
|
+
const startPath = fileURLToPath7(startUrl);
|
|
4490
|
+
let dir = dirname7(startPath);
|
|
4255
4491
|
let result;
|
|
4256
4492
|
while (result === void 0) {
|
|
4257
|
-
if (
|
|
4493
|
+
if (existsSync7(resolve13(dir, "package.json"))) {
|
|
4258
4494
|
result = dir;
|
|
4259
4495
|
} else {
|
|
4260
|
-
const parent =
|
|
4496
|
+
const parent = dirname7(dir);
|
|
4261
4497
|
if (parent === dir) {
|
|
4262
4498
|
throw new Error(`findPackageRoot: no package.json found above ${startPath}`);
|
|
4263
4499
|
}
|
|
@@ -4266,20 +4502,20 @@ function findPackageRoot6(startUrl) {
|
|
|
4266
4502
|
}
|
|
4267
4503
|
return result;
|
|
4268
4504
|
}
|
|
4269
|
-
var
|
|
4270
|
-
const packageRoot =
|
|
4271
|
-
return
|
|
4505
|
+
var DEFAULT_BUNDLED_PATHS7 = () => {
|
|
4506
|
+
const packageRoot = findPackageRoot7(import.meta.url);
|
|
4507
|
+
return DEFAULT_BUNDLED_FILENAMES7.map((name) => resolve13(packageRoot, "generated", name));
|
|
4272
4508
|
};
|
|
4273
4509
|
async function loadUiComponentRegistry(input) {
|
|
4274
|
-
const { cwd, bundledManifestPaths =
|
|
4510
|
+
const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS7, readFile: readFile20 } = input;
|
|
4275
4511
|
const bundledSources = bundledManifestPaths().map((path) => ({ origin: "bundled", path }));
|
|
4276
4512
|
const configResult = await findAndLoadConfig({ cwd, readFile: readFile20 });
|
|
4277
4513
|
const externalSources = [];
|
|
4278
4514
|
if (configResult.config !== null && configResult.configPath !== null) {
|
|
4279
|
-
const baseDir =
|
|
4515
|
+
const baseDir = dirname7(configResult.configPath);
|
|
4280
4516
|
const declared = configResult.config.uiComponents?.sources ?? [];
|
|
4281
4517
|
for (const source of declared) {
|
|
4282
|
-
const absolute =
|
|
4518
|
+
const absolute = isAbsolute7(source) ? source : resolve13(baseDir, source);
|
|
4283
4519
|
externalSources.push({ origin: "external", path: absolute });
|
|
4284
4520
|
}
|
|
4285
4521
|
}
|
|
@@ -5294,11 +5530,11 @@ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
5294
5530
|
var FORM_TIER_ORDER = ["field-factory", "field-derivative", "composite-builder", "template-builder", "primitive"];
|
|
5295
5531
|
|
|
5296
5532
|
// packages/dbx-components-mcp/src/registry/downstream-models-runtime.ts
|
|
5297
|
-
import { resolve as
|
|
5533
|
+
import { resolve as resolve15 } from "node:path";
|
|
5298
5534
|
|
|
5299
5535
|
// packages/dbx-components-mcp/src/scan/discover-firebase-packages.ts
|
|
5300
5536
|
import { glob as fsGlob2, readFile, stat } from "node:fs/promises";
|
|
5301
|
-
import { basename, join, resolve as
|
|
5537
|
+
import { basename, join, resolve as resolve14, sep } from "node:path";
|
|
5302
5538
|
var COMPONENTS_GLOB = "components/*-firebase";
|
|
5303
5539
|
var MODEL_SUBPATH = "src/lib/model";
|
|
5304
5540
|
var PACKAGE_JSON = "package.json";
|
|
@@ -5309,7 +5545,7 @@ async function discoverDownstreamFirebasePackages(workspaceRoot) {
|
|
|
5309
5545
|
const componentDir = match.split(sep).join("/");
|
|
5310
5546
|
if (seen.has(componentDir)) continue;
|
|
5311
5547
|
seen.add(componentDir);
|
|
5312
|
-
const componentAbs =
|
|
5548
|
+
const componentAbs = resolve14(workspaceRoot, componentDir);
|
|
5313
5549
|
const pkg = await inspectPackage(componentAbs, componentDir);
|
|
5314
5550
|
if (pkg) out.push(pkg);
|
|
5315
5551
|
}
|
|
@@ -5323,7 +5559,7 @@ async function resolveExplicitFirebasePackages(workspaceRoot, componentDirs) {
|
|
|
5323
5559
|
const componentDir = raw.split(sep).join("/").replace(/\/+$/, "");
|
|
5324
5560
|
if (seen.has(componentDir) || componentDir.length === 0) continue;
|
|
5325
5561
|
seen.add(componentDir);
|
|
5326
|
-
const componentAbs =
|
|
5562
|
+
const componentAbs = resolve14(workspaceRoot, componentDir);
|
|
5327
5563
|
const pkg = await inspectPackage(componentAbs, componentDir);
|
|
5328
5564
|
if (pkg) out.push(pkg);
|
|
5329
5565
|
}
|
|
@@ -5956,13 +6192,13 @@ function getDownstreamCatalog(input) {
|
|
|
5956
6192
|
return pending;
|
|
5957
6193
|
}
|
|
5958
6194
|
function cacheKey(input) {
|
|
5959
|
-
const root =
|
|
6195
|
+
const root = resolve15(input.workspaceRoot);
|
|
5960
6196
|
const dirs = input.componentDirs;
|
|
5961
6197
|
const dirKey = dirs ? [...dirs].slice().sort((a, b) => a.localeCompare(b)).join(",") : "*";
|
|
5962
6198
|
return `${root}|${dirKey}`;
|
|
5963
6199
|
}
|
|
5964
6200
|
async function buildCatalog(input) {
|
|
5965
|
-
const workspaceRoot =
|
|
6201
|
+
const workspaceRoot = resolve15(input.workspaceRoot);
|
|
5966
6202
|
const discoveryUsed = input.componentDirs === void 0;
|
|
5967
6203
|
const packages = discoveryUsed ? await discoverDownstreamFirebasePackages(workspaceRoot) : await resolveExplicitFirebasePackages(workspaceRoot, input.componentDirs ?? []);
|
|
5968
6204
|
const errors = [];
|
|
@@ -5972,7 +6208,7 @@ async function buildCatalog(input) {
|
|
|
5972
6208
|
packages.map(async (pkg) => {
|
|
5973
6209
|
try {
|
|
5974
6210
|
const result = await extractModels({
|
|
5975
|
-
rootDir:
|
|
6211
|
+
rootDir: resolve15(workspaceRoot, pkg.modelDir),
|
|
5976
6212
|
sourcePackage: pkg.packageName,
|
|
5977
6213
|
workspaceRoot,
|
|
5978
6214
|
skipReservedFolders: RESERVED_FOLDER_NAMES
|
|
@@ -6942,6 +7178,141 @@ function registerSemanticTypesResource(server, config) {
|
|
|
6942
7178
|
);
|
|
6943
7179
|
}
|
|
6944
7180
|
|
|
7181
|
+
// packages/dbx-components-mcp/src/resources/tokens.resource.ts
|
|
7182
|
+
import { ResourceTemplate as ResourceTemplate8 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7183
|
+
var TOKENS_URI = "dbx://token/entries";
|
|
7184
|
+
var TOKENS_BY_SOURCE_TEMPLATE = "dbx://token/source/{source}";
|
|
7185
|
+
var TOKENS_BY_ROLE_TEMPLATE = "dbx://token/role/{role}";
|
|
7186
|
+
var TOKENS_BY_VAR_TEMPLATE = "dbx://token/css-var/{cssVariable}";
|
|
7187
|
+
function registerTokensResource(server, options) {
|
|
7188
|
+
const { registry } = options;
|
|
7189
|
+
server.registerResource(
|
|
7190
|
+
"dbx-components Tokens",
|
|
7191
|
+
TOKENS_URI,
|
|
7192
|
+
{
|
|
7193
|
+
title: "Design Tokens",
|
|
7194
|
+
description: "Catalog of dbx-web + Angular Material design tokens (system, MDC, dbx-web aliases).",
|
|
7195
|
+
mimeType: "application/json"
|
|
7196
|
+
},
|
|
7197
|
+
async () => {
|
|
7198
|
+
const payload = {
|
|
7199
|
+
description: "Every registered design token.",
|
|
7200
|
+
sourceOrder: TOKEN_SOURCES,
|
|
7201
|
+
roleOrder: TOKEN_ROLES,
|
|
7202
|
+
tokens: registry.all.map((t) => ({
|
|
7203
|
+
cssVariable: t.cssVariable,
|
|
7204
|
+
source: t.source,
|
|
7205
|
+
role: t.role,
|
|
7206
|
+
description: t.description
|
|
7207
|
+
}))
|
|
7208
|
+
};
|
|
7209
|
+
return {
|
|
7210
|
+
contents: [
|
|
7211
|
+
{
|
|
7212
|
+
uri: TOKENS_URI,
|
|
7213
|
+
mimeType: "application/json",
|
|
7214
|
+
text: JSON.stringify(payload, null, 2)
|
|
7215
|
+
}
|
|
7216
|
+
]
|
|
7217
|
+
};
|
|
7218
|
+
}
|
|
7219
|
+
);
|
|
7220
|
+
server.registerResource(
|
|
7221
|
+
"dbx-components Tokens by Source",
|
|
7222
|
+
new ResourceTemplate8(TOKENS_BY_SOURCE_TEMPLATE, { list: void 0 }),
|
|
7223
|
+
{
|
|
7224
|
+
title: "Tokens by Source",
|
|
7225
|
+
description: "Tokens filtered by origin: dbx-web, mat-sys, mdc, app.",
|
|
7226
|
+
mimeType: "application/json"
|
|
7227
|
+
},
|
|
7228
|
+
async (uri, variables) => {
|
|
7229
|
+
const rawSource = variables.source;
|
|
7230
|
+
const source = Array.isArray(rawSource) ? rawSource[0] : rawSource;
|
|
7231
|
+
const valid = source !== void 0 && TOKEN_SOURCES.includes(source);
|
|
7232
|
+
let text;
|
|
7233
|
+
if (valid && source !== void 0) {
|
|
7234
|
+
const tokens = registry.bySource.get(source) ?? [];
|
|
7235
|
+
text = JSON.stringify({ source, tokens }, null, 2);
|
|
7236
|
+
} else {
|
|
7237
|
+
text = `Invalid source. Valid values: ${TOKEN_SOURCES.join(", ")}`;
|
|
7238
|
+
}
|
|
7239
|
+
return {
|
|
7240
|
+
contents: [
|
|
7241
|
+
{
|
|
7242
|
+
uri: uri.href,
|
|
7243
|
+
mimeType: valid ? "application/json" : "text/plain",
|
|
7244
|
+
text
|
|
7245
|
+
}
|
|
7246
|
+
]
|
|
7247
|
+
};
|
|
7248
|
+
}
|
|
7249
|
+
);
|
|
7250
|
+
server.registerResource(
|
|
7251
|
+
"dbx-components Tokens by Role",
|
|
7252
|
+
new ResourceTemplate8(TOKENS_BY_ROLE_TEMPLATE, { list: void 0 }),
|
|
7253
|
+
{
|
|
7254
|
+
title: "Tokens by Role",
|
|
7255
|
+
description: "Tokens filtered by role (color, surface, spacing, radius, ...).",
|
|
7256
|
+
mimeType: "application/json"
|
|
7257
|
+
},
|
|
7258
|
+
async (uri, variables) => {
|
|
7259
|
+
const rawRole = variables.role;
|
|
7260
|
+
const role = Array.isArray(rawRole) ? rawRole[0] : rawRole;
|
|
7261
|
+
const valid = role !== void 0 && TOKEN_ROLES.includes(role);
|
|
7262
|
+
let text;
|
|
7263
|
+
if (valid && role !== void 0) {
|
|
7264
|
+
const tokens = registry.byRole.get(role) ?? [];
|
|
7265
|
+
text = JSON.stringify({ role, tokens }, null, 2);
|
|
7266
|
+
} else {
|
|
7267
|
+
text = `Invalid role. Valid values: ${TOKEN_ROLES.join(", ")}`;
|
|
7268
|
+
}
|
|
7269
|
+
return {
|
|
7270
|
+
contents: [
|
|
7271
|
+
{
|
|
7272
|
+
uri: uri.href,
|
|
7273
|
+
mimeType: valid ? "application/json" : "text/plain",
|
|
7274
|
+
text
|
|
7275
|
+
}
|
|
7276
|
+
]
|
|
7277
|
+
};
|
|
7278
|
+
}
|
|
7279
|
+
);
|
|
7280
|
+
server.registerResource(
|
|
7281
|
+
"dbx-components Token Details",
|
|
7282
|
+
new ResourceTemplate8(TOKENS_BY_VAR_TEMPLATE, { list: void 0 }),
|
|
7283
|
+
{
|
|
7284
|
+
title: "Token Details",
|
|
7285
|
+
description: "Full metadata for a single token by CSS variable name.",
|
|
7286
|
+
mimeType: "application/json"
|
|
7287
|
+
},
|
|
7288
|
+
async (uri, variables) => {
|
|
7289
|
+
const rawVar = variables.cssVariable;
|
|
7290
|
+
const cssVariable = Array.isArray(rawVar) ? rawVar[0] : rawVar;
|
|
7291
|
+
let text;
|
|
7292
|
+
let entry;
|
|
7293
|
+
if (cssVariable !== void 0) {
|
|
7294
|
+
entry = registry.findByCssVariable(cssVariable) ?? registry.findByScssVariable(cssVariable);
|
|
7295
|
+
}
|
|
7296
|
+
if (entry !== void 0) {
|
|
7297
|
+
text = JSON.stringify(entry, null, 2);
|
|
7298
|
+
} else if (cssVariable !== void 0) {
|
|
7299
|
+
text = `Token '${cssVariable}' not found.`;
|
|
7300
|
+
} else {
|
|
7301
|
+
text = "No cssVariable provided.";
|
|
7302
|
+
}
|
|
7303
|
+
return {
|
|
7304
|
+
contents: [
|
|
7305
|
+
{
|
|
7306
|
+
uri: uri.href,
|
|
7307
|
+
mimeType: entry !== void 0 ? "application/json" : "text/plain",
|
|
7308
|
+
text
|
|
7309
|
+
}
|
|
7310
|
+
]
|
|
7311
|
+
};
|
|
7312
|
+
}
|
|
7313
|
+
);
|
|
7314
|
+
}
|
|
7315
|
+
|
|
6945
7316
|
// packages/dbx-components-mcp/src/resources/index.ts
|
|
6946
7317
|
function registerResources(server, options = {}) {
|
|
6947
7318
|
if (options.forgeFieldRegistry !== void 0) {
|
|
@@ -6963,13 +7334,16 @@ function registerResources(server, options = {}) {
|
|
|
6963
7334
|
if (options.semanticTypeRegistry !== void 0) {
|
|
6964
7335
|
registerSemanticTypesResource(server, { registry: options.semanticTypeRegistry });
|
|
6965
7336
|
}
|
|
7337
|
+
if (options.tokenRegistry !== void 0) {
|
|
7338
|
+
registerTokensResource(server, { registry: options.tokenRegistry });
|
|
7339
|
+
}
|
|
6966
7340
|
}
|
|
6967
7341
|
|
|
6968
7342
|
// packages/dbx-components-mcp/src/tools/index.ts
|
|
6969
7343
|
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
6970
7344
|
|
|
6971
7345
|
// packages/dbx-components-mcp/src/tools/lookup-form.tool.ts
|
|
6972
|
-
import { type as
|
|
7346
|
+
import { type as type21 } from "arktype";
|
|
6973
7347
|
|
|
6974
7348
|
// packages/dbx-components-mcp/src/tools/form-alias-resolver.ts
|
|
6975
7349
|
var ALIASES = {
|
|
@@ -7206,13 +7580,13 @@ var DBX_FORM_LOOKUP_TOOL = {
|
|
|
7206
7580
|
required: ["topic"]
|
|
7207
7581
|
}
|
|
7208
7582
|
};
|
|
7209
|
-
var LookupFormArgsType =
|
|
7583
|
+
var LookupFormArgsType = type21({
|
|
7210
7584
|
topic: "string",
|
|
7211
7585
|
"depth?": "'brief' | 'full'"
|
|
7212
7586
|
});
|
|
7213
7587
|
function parseLookupFormArgs(raw) {
|
|
7214
7588
|
const parsed = LookupFormArgsType(raw);
|
|
7215
|
-
if (parsed instanceof
|
|
7589
|
+
if (parsed instanceof type21.errors) {
|
|
7216
7590
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
7217
7591
|
}
|
|
7218
7592
|
return {
|
|
@@ -7334,14 +7708,14 @@ function createLookupFormTool(config) {
|
|
|
7334
7708
|
}
|
|
7335
7709
|
|
|
7336
7710
|
// packages/dbx-components-mcp/src/tools/_search/score.ts
|
|
7337
|
-
import { type as
|
|
7338
|
-
var SEARCH_ARGS_TYPE =
|
|
7711
|
+
import { type as type22 } from "arktype";
|
|
7712
|
+
var SEARCH_ARGS_TYPE = type22({
|
|
7339
7713
|
query: "string",
|
|
7340
7714
|
"limit?": "number"
|
|
7341
7715
|
});
|
|
7342
7716
|
function parseSearchArgs(raw, config) {
|
|
7343
7717
|
const parsed = SEARCH_ARGS_TYPE(raw);
|
|
7344
|
-
if (parsed instanceof
|
|
7718
|
+
if (parsed instanceof type22.errors) {
|
|
7345
7719
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
7346
7720
|
}
|
|
7347
7721
|
const rawLimit = parsed.limit ?? config.defaultLimit;
|
|
@@ -7539,7 +7913,7 @@ function createSearchFormTool(config) {
|
|
|
7539
7913
|
}
|
|
7540
7914
|
|
|
7541
7915
|
// packages/dbx-components-mcp/src/tools/form-examples.tool.ts
|
|
7542
|
-
import { type as
|
|
7916
|
+
import { type as type23 } from "arktype";
|
|
7543
7917
|
|
|
7544
7918
|
// packages/dbx-components-mcp/src/tools/data/patterns/forms/form.address-form.pattern.ts
|
|
7545
7919
|
var FORM_PATTERN_ADDRESS_FORM = {
|
|
@@ -7828,13 +8202,13 @@ var DBX_FORM_EXAMPLES_TOOL = {
|
|
|
7828
8202
|
required: ["pattern"]
|
|
7829
8203
|
}
|
|
7830
8204
|
};
|
|
7831
|
-
var ExamplesArgsType =
|
|
8205
|
+
var ExamplesArgsType = type23({
|
|
7832
8206
|
pattern: "string",
|
|
7833
8207
|
"depth?": "'minimal' | 'brief' | 'full'"
|
|
7834
8208
|
});
|
|
7835
8209
|
function parseExamplesArgs(raw) {
|
|
7836
8210
|
const parsed = ExamplesArgsType(raw);
|
|
7837
|
-
if (parsed instanceof
|
|
8211
|
+
if (parsed instanceof type23.errors) {
|
|
7838
8212
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
7839
8213
|
}
|
|
7840
8214
|
const result = {
|
|
@@ -7895,7 +8269,7 @@ var formExamplesTool = {
|
|
|
7895
8269
|
};
|
|
7896
8270
|
|
|
7897
8271
|
// packages/dbx-components-mcp/src/tools/form-scaffold.tool.ts
|
|
7898
|
-
import { type as
|
|
8272
|
+
import { type as type24 } from "arktype";
|
|
7899
8273
|
var DEFAULT_VALUE_TYPE_NAME = "ScaffoldedFormValue";
|
|
7900
8274
|
var DBX_FORM_SCAFFOLD_TOOL = {
|
|
7901
8275
|
name: "dbx_form_scaffold",
|
|
@@ -7933,14 +8307,14 @@ var DBX_FORM_SCAFFOLD_TOOL = {
|
|
|
7933
8307
|
required: ["fields"]
|
|
7934
8308
|
}
|
|
7935
8309
|
};
|
|
7936
|
-
var ScaffoldArgsType =
|
|
8310
|
+
var ScaffoldArgsType = type24({
|
|
7937
8311
|
fields: "string[]>0",
|
|
7938
8312
|
"valueTypeName?": "string",
|
|
7939
8313
|
"wrapInSection?": "boolean"
|
|
7940
8314
|
});
|
|
7941
8315
|
function parseScaffoldArgs(raw) {
|
|
7942
8316
|
const parsed = ScaffoldArgsType(raw);
|
|
7943
|
-
if (parsed instanceof
|
|
8317
|
+
if (parsed instanceof type24.errors) {
|
|
7944
8318
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
7945
8319
|
}
|
|
7946
8320
|
const result = {
|
|
@@ -8096,7 +8470,7 @@ ${code11}
|
|
|
8096
8470
|
}
|
|
8097
8471
|
|
|
8098
8472
|
// packages/dbx-components-mcp/src/tools/lookup-ui.tool.ts
|
|
8099
|
-
import { type as
|
|
8473
|
+
import { type as type25 } from "arktype";
|
|
8100
8474
|
var DBX_UI_LOOKUP_TOOL = {
|
|
8101
8475
|
name: "dbx_ui_lookup",
|
|
8102
8476
|
description: [
|
|
@@ -8126,13 +8500,13 @@ var DBX_UI_LOOKUP_TOOL = {
|
|
|
8126
8500
|
required: ["topic"]
|
|
8127
8501
|
}
|
|
8128
8502
|
};
|
|
8129
|
-
var LookupUiArgsType =
|
|
8503
|
+
var LookupUiArgsType = type25({
|
|
8130
8504
|
topic: "string",
|
|
8131
8505
|
"depth?": "'brief' | 'full'"
|
|
8132
8506
|
});
|
|
8133
8507
|
function parseLookupUiArgs(raw) {
|
|
8134
8508
|
const parsed = LookupUiArgsType(raw);
|
|
8135
|
-
if (parsed instanceof
|
|
8509
|
+
if (parsed instanceof type25.errors) {
|
|
8136
8510
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
8137
8511
|
}
|
|
8138
8512
|
const result = {
|
|
@@ -8382,7 +8756,7 @@ function createLookupUiTool(input) {
|
|
|
8382
8756
|
}
|
|
8383
8757
|
|
|
8384
8758
|
// packages/dbx-components-mcp/src/tools/search-ui.tool.ts
|
|
8385
|
-
import { type as
|
|
8759
|
+
import { type as type26 } from "arktype";
|
|
8386
8760
|
var DEFAULT_LIMIT2 = 10;
|
|
8387
8761
|
var MAX_LIMIT2 = 25;
|
|
8388
8762
|
var DBX_UI_SEARCH_TOOL = {
|
|
@@ -8419,14 +8793,14 @@ var DBX_UI_SEARCH_TOOL = {
|
|
|
8419
8793
|
required: ["query"]
|
|
8420
8794
|
}
|
|
8421
8795
|
};
|
|
8422
|
-
var SearchUiArgsType =
|
|
8796
|
+
var SearchUiArgsType = type26({
|
|
8423
8797
|
query: "string",
|
|
8424
8798
|
"category?": "'layout' | 'list' | 'button' | 'card' | 'feedback' | 'overlay' | 'navigation' | 'text' | 'screen' | 'action' | 'router' | 'misc'",
|
|
8425
8799
|
"limit?": "number"
|
|
8426
8800
|
});
|
|
8427
8801
|
function parseSearchUiArgs(raw) {
|
|
8428
8802
|
const parsed = SearchUiArgsType(raw);
|
|
8429
|
-
if (parsed instanceof
|
|
8803
|
+
if (parsed instanceof type26.errors) {
|
|
8430
8804
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
8431
8805
|
}
|
|
8432
8806
|
const rawLimit = parsed.limit ?? DEFAULT_LIMIT2;
|
|
@@ -8579,7 +8953,7 @@ function createSearchUiTool(input) {
|
|
|
8579
8953
|
}
|
|
8580
8954
|
|
|
8581
8955
|
// packages/dbx-components-mcp/src/tools/ui-examples.tool.ts
|
|
8582
|
-
import { type as
|
|
8956
|
+
import { type as type27 } from "arktype";
|
|
8583
8957
|
|
|
8584
8958
|
// packages/dbx-components-mcp/src/tools/data/patterns/ui/ui.card-with-action.pattern.ts
|
|
8585
8959
|
var UI_PATTERN_CARD_WITH_ACTION = {
|
|
@@ -8985,13 +9359,13 @@ var DBX_UI_EXAMPLES_TOOL = {
|
|
|
8985
9359
|
required: ["pattern"]
|
|
8986
9360
|
}
|
|
8987
9361
|
};
|
|
8988
|
-
var UiExamplesArgsType =
|
|
9362
|
+
var UiExamplesArgsType = type27({
|
|
8989
9363
|
pattern: "string",
|
|
8990
9364
|
"depth?": "'minimal' | 'brief' | 'full'"
|
|
8991
9365
|
});
|
|
8992
9366
|
function parseUiExamplesArgs(raw) {
|
|
8993
9367
|
const parsed = UiExamplesArgsType(raw);
|
|
8994
|
-
if (parsed instanceof
|
|
9368
|
+
if (parsed instanceof type27.errors) {
|
|
8995
9369
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
8996
9370
|
}
|
|
8997
9371
|
const result = {
|
|
@@ -9052,7 +9426,7 @@ var uiExamplesTool = {
|
|
|
9052
9426
|
};
|
|
9053
9427
|
|
|
9054
9428
|
// packages/dbx-components-mcp/src/tools/lookup-model.tool.ts
|
|
9055
|
-
import { type as
|
|
9429
|
+
import { type as type28 } from "arktype";
|
|
9056
9430
|
|
|
9057
9431
|
// packages/dbx-components-mcp/src/tools/firebase-lookup.formatter.ts
|
|
9058
9432
|
function applyFieldsFilter(model, filter) {
|
|
@@ -9266,10 +9640,10 @@ function formatFirebaseStoreShapeTaxonomy() {
|
|
|
9266
9640
|
|
|
9267
9641
|
// packages/dbx-components-mcp/src/tools/validate-input.ts
|
|
9268
9642
|
import { glob as fsGlob3, readFile as readFile3, stat as stat3 } from "node:fs/promises";
|
|
9269
|
-
import { resolve as
|
|
9643
|
+
import { resolve as resolve16, sep as sep3 } from "node:path";
|
|
9270
9644
|
function ensurePathInsideCwd(relative17, cwd) {
|
|
9271
9645
|
const cwdPrefix = cwd.endsWith(sep3) ? cwd : cwd + sep3;
|
|
9272
|
-
const absolute =
|
|
9646
|
+
const absolute = resolve16(cwd, relative17);
|
|
9273
9647
|
if (!absolute.startsWith(cwdPrefix) && absolute !== cwd) {
|
|
9274
9648
|
throw new Error(`Path \`${relative17}\` resolves outside the server cwd and is not allowed.`);
|
|
9275
9649
|
}
|
|
@@ -9291,7 +9665,7 @@ async function resolveFolderPaths(config) {
|
|
|
9291
9665
|
}
|
|
9292
9666
|
if (glob) {
|
|
9293
9667
|
for await (const match of fsGlob3(glob, { cwd })) {
|
|
9294
|
-
const absolute =
|
|
9668
|
+
const absolute = resolve16(cwd, match);
|
|
9295
9669
|
try {
|
|
9296
9670
|
const stats = await stat3(absolute);
|
|
9297
9671
|
if (!stats.isDirectory()) continue;
|
|
@@ -9328,7 +9702,7 @@ async function resolveValidatorSources(config) {
|
|
|
9328
9702
|
for (const relative17 of pathList) {
|
|
9329
9703
|
if (seenNames.has(relative17)) continue;
|
|
9330
9704
|
ensurePathInsideCwd(relative17, cwd);
|
|
9331
|
-
const absolute =
|
|
9705
|
+
const absolute = resolve16(cwd, relative17);
|
|
9332
9706
|
const text = await readFile3(absolute, "utf8");
|
|
9333
9707
|
seenNames.add(relative17);
|
|
9334
9708
|
collected.push({ name: relative17, text });
|
|
@@ -9388,7 +9762,7 @@ var DBX_MODEL_LOOKUP_TOOL = {
|
|
|
9388
9762
|
required: ["topic"]
|
|
9389
9763
|
}
|
|
9390
9764
|
};
|
|
9391
|
-
var LookupModelArgsType =
|
|
9765
|
+
var LookupModelArgsType = type28({
|
|
9392
9766
|
topic: "string",
|
|
9393
9767
|
"depth?": "'brief' | 'full'",
|
|
9394
9768
|
"scope?": "'all' | 'upstream' | 'downstream'",
|
|
@@ -9415,7 +9789,7 @@ function normalizeFieldsFilter(raw) {
|
|
|
9415
9789
|
}
|
|
9416
9790
|
function parseLookupModelArgs(raw) {
|
|
9417
9791
|
const parsed = LookupModelArgsType(raw);
|
|
9418
|
-
if (parsed instanceof
|
|
9792
|
+
if (parsed instanceof type28.errors) {
|
|
9419
9793
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
9420
9794
|
}
|
|
9421
9795
|
return {
|
|
@@ -9532,10 +9906,10 @@ var lookupModelTool = {
|
|
|
9532
9906
|
};
|
|
9533
9907
|
|
|
9534
9908
|
// packages/dbx-components-mcp/src/tools/search-model.tool.ts
|
|
9535
|
-
import { type as
|
|
9909
|
+
import { type as type29 } from "arktype";
|
|
9536
9910
|
var DEFAULT_LIMIT3 = 10;
|
|
9537
9911
|
var MAX_LIMIT3 = 25;
|
|
9538
|
-
var SearchArgsType =
|
|
9912
|
+
var SearchArgsType = type29({
|
|
9539
9913
|
query: "string",
|
|
9540
9914
|
"limit?": "number",
|
|
9541
9915
|
"scope?": "'all' | 'upstream' | 'downstream'",
|
|
@@ -9679,7 +10053,7 @@ function formatSourceLine(scope, upstreamCount, downstreamPackages) {
|
|
|
9679
10053
|
}
|
|
9680
10054
|
function parseArgs2(rawArgs) {
|
|
9681
10055
|
const parsed = SearchArgsType(rawArgs);
|
|
9682
|
-
if (parsed instanceof
|
|
10056
|
+
if (parsed instanceof type29.errors) {
|
|
9683
10057
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
9684
10058
|
}
|
|
9685
10059
|
return {
|
|
@@ -9740,7 +10114,7 @@ var searchModelTool = {
|
|
|
9740
10114
|
};
|
|
9741
10115
|
|
|
9742
10116
|
// packages/dbx-components-mcp/src/tools/model-decode.tool.ts
|
|
9743
|
-
import { type as
|
|
10117
|
+
import { type as type30 } from "arktype";
|
|
9744
10118
|
|
|
9745
10119
|
// packages/dbx-components-mcp/src/tools/decode.formatter.ts
|
|
9746
10120
|
function formatDecode(context) {
|
|
@@ -9900,13 +10274,13 @@ var DBX_MODEL_DECODE_TOOL = {
|
|
|
9900
10274
|
required: ["data"]
|
|
9901
10275
|
}
|
|
9902
10276
|
};
|
|
9903
|
-
var DecodeArgsType =
|
|
10277
|
+
var DecodeArgsType = type30({
|
|
9904
10278
|
data: "string | object",
|
|
9905
10279
|
"model?": "string"
|
|
9906
10280
|
});
|
|
9907
10281
|
function parseDecodeArgs(raw) {
|
|
9908
10282
|
const parsed = DecodeArgsType(raw);
|
|
9909
|
-
if (parsed instanceof
|
|
10283
|
+
if (parsed instanceof type30.errors) {
|
|
9910
10284
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
9911
10285
|
}
|
|
9912
10286
|
const result = {
|
|
@@ -10046,9 +10420,9 @@ var modelDecodeTool = {
|
|
|
10046
10420
|
};
|
|
10047
10421
|
|
|
10048
10422
|
// packages/dbx-components-mcp/src/tools/validate-tool.ts
|
|
10049
|
-
import { resolve as
|
|
10050
|
-
import { type as
|
|
10051
|
-
var FolderValidateArgsType =
|
|
10423
|
+
import { resolve as resolve17 } from "node:path";
|
|
10424
|
+
import { type as type31 } from "arktype";
|
|
10425
|
+
var FolderValidateArgsType = type31({
|
|
10052
10426
|
"paths?": "string[]",
|
|
10053
10427
|
"glob?": "string"
|
|
10054
10428
|
});
|
|
@@ -10056,7 +10430,7 @@ function createFolderValidateTool(config) {
|
|
|
10056
10430
|
const { definition, inspectFolder: inspectFolder3, validate, format } = config;
|
|
10057
10431
|
async function run15(rawArgs) {
|
|
10058
10432
|
const parsed = FolderValidateArgsType(rawArgs);
|
|
10059
|
-
if (parsed instanceof
|
|
10433
|
+
if (parsed instanceof type31.errors) {
|
|
10060
10434
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
10061
10435
|
}
|
|
10062
10436
|
const hasAny = parsed.paths && parsed.paths.length > 0 || parsed.glob;
|
|
@@ -10077,7 +10451,7 @@ function createFolderValidateTool(config) {
|
|
|
10077
10451
|
const inspections = [];
|
|
10078
10452
|
try {
|
|
10079
10453
|
for (const relative17 of paths) {
|
|
10080
|
-
const absolute =
|
|
10454
|
+
const absolute = resolve17(cwd, relative17);
|
|
10081
10455
|
const inspection = await inspectFolder3(absolute);
|
|
10082
10456
|
const relativized = { ...inspection, path: relative17 };
|
|
10083
10457
|
inspections.push(relativized);
|
|
@@ -10097,8 +10471,8 @@ function createFolderValidateTool(config) {
|
|
|
10097
10471
|
const tool = { definition, run: run15 };
|
|
10098
10472
|
return tool;
|
|
10099
10473
|
}
|
|
10100
|
-
var SourceValidateArgsType =
|
|
10101
|
-
"sources?":
|
|
10474
|
+
var SourceValidateArgsType = type31({
|
|
10475
|
+
"sources?": type31({ name: "string", text: "string" }).array(),
|
|
10102
10476
|
"paths?": "string[]",
|
|
10103
10477
|
"glob?": "string"
|
|
10104
10478
|
});
|
|
@@ -10106,7 +10480,7 @@ function createSourceValidateTool(config) {
|
|
|
10106
10480
|
const { definition, validate, format } = config;
|
|
10107
10481
|
async function run15(rawArgs) {
|
|
10108
10482
|
const parsed = SourceValidateArgsType(rawArgs);
|
|
10109
|
-
if (parsed instanceof
|
|
10483
|
+
if (parsed instanceof type31.errors) {
|
|
10110
10484
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
10111
10485
|
}
|
|
10112
10486
|
const hasAny = parsed.sources && parsed.sources.length > 0 || parsed.paths && parsed.paths.length > 0 || parsed.glob;
|
|
@@ -10134,7 +10508,7 @@ function createSourceValidateTool(config) {
|
|
|
10134
10508
|
const tool = { definition, run: run15 };
|
|
10135
10509
|
return tool;
|
|
10136
10510
|
}
|
|
10137
|
-
var TwoSideValidateArgsType =
|
|
10511
|
+
var TwoSideValidateArgsType = type31({
|
|
10138
10512
|
componentDir: "string",
|
|
10139
10513
|
apiDir: "string"
|
|
10140
10514
|
});
|
|
@@ -10150,9 +10524,9 @@ function resolveTwoSideInput(parsed) {
|
|
|
10150
10524
|
return toolError(message);
|
|
10151
10525
|
}
|
|
10152
10526
|
return {
|
|
10153
|
-
componentAbs:
|
|
10527
|
+
componentAbs: resolve17(cwd, componentRel),
|
|
10154
10528
|
componentRel,
|
|
10155
|
-
apiAbs:
|
|
10529
|
+
apiAbs: resolve17(cwd, apiRel),
|
|
10156
10530
|
apiRel
|
|
10157
10531
|
};
|
|
10158
10532
|
}
|
|
@@ -10160,7 +10534,7 @@ function createTwoSideValidateTool(config) {
|
|
|
10160
10534
|
const { definition, inspectAndValidate, format } = config;
|
|
10161
10535
|
async function run15(rawArgs) {
|
|
10162
10536
|
const parsed = TwoSideValidateArgsType(rawArgs);
|
|
10163
|
-
if (parsed instanceof
|
|
10537
|
+
if (parsed instanceof type31.errors) {
|
|
10164
10538
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
10165
10539
|
}
|
|
10166
10540
|
const resolved = resolveTwoSideInput(parsed);
|
|
@@ -10178,7 +10552,7 @@ function createTwoSideValidateTool(config) {
|
|
|
10178
10552
|
const tool = { definition, run: run15 };
|
|
10179
10553
|
return tool;
|
|
10180
10554
|
}
|
|
10181
|
-
var ListAppArgsType =
|
|
10555
|
+
var ListAppArgsType = type31({
|
|
10182
10556
|
componentDir: "string",
|
|
10183
10557
|
apiDir: "string",
|
|
10184
10558
|
"format?": "'markdown' | 'json'"
|
|
@@ -10187,7 +10561,7 @@ function createListAppTool(config) {
|
|
|
10187
10561
|
const { definition, inspectAndList, formatMarkdown: formatMarkdown2, formatJson: formatJson2 } = config;
|
|
10188
10562
|
async function run15(rawArgs) {
|
|
10189
10563
|
const parsed = ListAppArgsType(rawArgs);
|
|
10190
|
-
if (parsed instanceof
|
|
10564
|
+
if (parsed instanceof type31.errors) {
|
|
10191
10565
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
10192
10566
|
}
|
|
10193
10567
|
const resolved = resolveTwoSideInput(parsed);
|
|
@@ -10684,9 +11058,9 @@ var RULE_CATALOG = [
|
|
|
10684
11058
|
severity: "error",
|
|
10685
11059
|
title: "A model is missing one of Fixture / Instance / Params / factory",
|
|
10686
11060
|
whatItFlags: "A model is missing one of Fixture / Instance / Params / factory\ncall / singleton \u2014 the five-anchor triplet definition is incomplete.",
|
|
10687
|
-
whenItApplies: "Every model that has at least one of the anchors.",
|
|
10688
|
-
whenItDoesNotApply: "
|
|
10689
|
-
canonicalFix: "Run `dbx_model_fixture_scaffold apiDir=<apiDir> model=<Model>` to generate the missing pieces
|
|
11061
|
+
whenItApplies: "Every Firestore-model fixture (`kind === 'firestore-model'`) that has at least one of the anchors.",
|
|
11062
|
+
whenItDoesNotApply: "Skipped for non-Firestore-model fixture pairs: AuthorizedUser-style fixtures (extending `AuthorizedUserTestContextFixture`/`Instance` or registered via `authorizedUserContextFactory`) and pairs tagged with `@dbxFixtureNotModel`.",
|
|
11063
|
+
canonicalFix: "Run `dbx_model_fixture_scaffold apiDir=<apiDir> model=<Model>` to generate the missing pieces; or, if the pair is intentionally not a Firestore model, ensure it extends a recognized framework base or carries `@dbxFixtureNotModel`.",
|
|
10690
11064
|
seeAlso: [
|
|
10691
11065
|
{
|
|
10692
11066
|
kind: "tool",
|
|
@@ -14722,8 +15096,8 @@ var modelValidateApiTool = createSourceValidateTool({
|
|
|
14722
15096
|
});
|
|
14723
15097
|
|
|
14724
15098
|
// packages/dbx-components-mcp/src/tools/model-api-list-app.tool.ts
|
|
14725
|
-
import { resolve as
|
|
14726
|
-
import { type as
|
|
15099
|
+
import { resolve as resolve18 } from "node:path";
|
|
15100
|
+
import { type as type32 } from "arktype";
|
|
14727
15101
|
|
|
14728
15102
|
// packages/dbx-components-mcp/src/tools/model-api-list-app/extract.ts
|
|
14729
15103
|
import { readdir as readdir2, readFile as readFile4, stat as stat4 } from "node:fs/promises";
|
|
@@ -15065,7 +15439,7 @@ async function listAppModelApi(componentAbs, options) {
|
|
|
15065
15439
|
}
|
|
15066
15440
|
|
|
15067
15441
|
// packages/dbx-components-mcp/src/tools/model-api-list-app.tool.ts
|
|
15068
|
-
var ListArgsType =
|
|
15442
|
+
var ListArgsType = type32({
|
|
15069
15443
|
componentDir: "string",
|
|
15070
15444
|
"model?": "string",
|
|
15071
15445
|
"identity?": "string",
|
|
@@ -15103,7 +15477,7 @@ var TOOL = {
|
|
|
15103
15477
|
};
|
|
15104
15478
|
async function run(rawArgs) {
|
|
15105
15479
|
const parsed = ListArgsType(rawArgs);
|
|
15106
|
-
if (parsed instanceof
|
|
15480
|
+
if (parsed instanceof type32.errors) {
|
|
15107
15481
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
15108
15482
|
}
|
|
15109
15483
|
const cwd = process.cwd();
|
|
@@ -15112,7 +15486,7 @@ async function run(rawArgs) {
|
|
|
15112
15486
|
} catch (err) {
|
|
15113
15487
|
return toolError(err instanceof Error ? err.message : String(err));
|
|
15114
15488
|
}
|
|
15115
|
-
const componentAbs =
|
|
15489
|
+
const componentAbs = resolve18(cwd, parsed.componentDir);
|
|
15116
15490
|
const modelFilter = parsed.model ?? (parsed.identity ? identityToModel(parsed.identity) : void 0);
|
|
15117
15491
|
let report;
|
|
15118
15492
|
try {
|
|
@@ -15132,8 +15506,8 @@ function identityToModel(identity) {
|
|
|
15132
15506
|
var modelApiListAppTool = { definition: TOOL, run };
|
|
15133
15507
|
|
|
15134
15508
|
// packages/dbx-components-mcp/src/tools/model-api-lookup.tool.ts
|
|
15135
|
-
import { resolve as
|
|
15136
|
-
import { type as
|
|
15509
|
+
import { resolve as resolve19 } from "node:path";
|
|
15510
|
+
import { type as type33 } from "arktype";
|
|
15137
15511
|
|
|
15138
15512
|
// packages/dbx-components-mcp/src/tools/model-api-lookup/extract.ts
|
|
15139
15513
|
import { readdir as readdir4, readFile as readFile6, stat as stat6 } from "node:fs/promises";
|
|
@@ -15555,7 +15929,7 @@ async function lookupModelApi(options) {
|
|
|
15555
15929
|
}
|
|
15556
15930
|
|
|
15557
15931
|
// packages/dbx-components-mcp/src/tools/model-api-lookup.tool.ts
|
|
15558
|
-
var LookupArgsType =
|
|
15932
|
+
var LookupArgsType = type33({
|
|
15559
15933
|
componentDir: "string",
|
|
15560
15934
|
"apiDir?": "string",
|
|
15561
15935
|
"model?": "string",
|
|
@@ -15593,7 +15967,7 @@ var TOOL2 = {
|
|
|
15593
15967
|
};
|
|
15594
15968
|
async function run2(rawArgs) {
|
|
15595
15969
|
const parsed = LookupArgsType(rawArgs);
|
|
15596
|
-
if (parsed instanceof
|
|
15970
|
+
if (parsed instanceof type33.errors) {
|
|
15597
15971
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
15598
15972
|
}
|
|
15599
15973
|
if (!parsed.model && !parsed.identity) {
|
|
@@ -15608,8 +15982,8 @@ async function run2(rawArgs) {
|
|
|
15608
15982
|
} catch (err) {
|
|
15609
15983
|
return toolError(err instanceof Error ? err.message : String(err));
|
|
15610
15984
|
}
|
|
15611
|
-
const componentAbs =
|
|
15612
|
-
const apiAbs = parsed.apiDir ?
|
|
15985
|
+
const componentAbs = resolve19(cwd, parsed.componentDir);
|
|
15986
|
+
const apiAbs = parsed.apiDir ? resolve19(cwd, parsed.apiDir) : void 0;
|
|
15613
15987
|
const modelFilter = parsed.model ?? identityToModel2(parsed.identity);
|
|
15614
15988
|
let report;
|
|
15615
15989
|
try {
|
|
@@ -15638,8 +16012,8 @@ function identityToModel2(identity) {
|
|
|
15638
16012
|
var modelApiLookupTool = { definition: TOOL2, run: run2 };
|
|
15639
16013
|
|
|
15640
16014
|
// packages/dbx-components-mcp/src/tools/model-api-validate-app.tool.ts
|
|
15641
|
-
import { resolve as
|
|
15642
|
-
import { type as
|
|
16015
|
+
import { resolve as resolve20 } from "node:path";
|
|
16016
|
+
import { type as type34 } from "arktype";
|
|
15643
16017
|
|
|
15644
16018
|
// packages/dbx-components-mcp/src/tools/model-api-validate-app/extract-declarations.ts
|
|
15645
16019
|
import { readdir as readdir5, readFile as readFile7, stat as stat7 } from "node:fs/promises";
|
|
@@ -15937,7 +16311,7 @@ async function validateAppModelApi(options) {
|
|
|
15937
16311
|
}
|
|
15938
16312
|
|
|
15939
16313
|
// packages/dbx-components-mcp/src/tools/model-api-validate-app.tool.ts
|
|
15940
|
-
var ValidateArgsType =
|
|
16314
|
+
var ValidateArgsType = type34({
|
|
15941
16315
|
componentDir: "string",
|
|
15942
16316
|
apiDir: "string",
|
|
15943
16317
|
"model?": "string",
|
|
@@ -15978,7 +16352,7 @@ var TOOL3 = {
|
|
|
15978
16352
|
};
|
|
15979
16353
|
async function run3(rawArgs) {
|
|
15980
16354
|
const parsed = ValidateArgsType(rawArgs);
|
|
15981
|
-
if (parsed instanceof
|
|
16355
|
+
if (parsed instanceof type34.errors) {
|
|
15982
16356
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
15983
16357
|
}
|
|
15984
16358
|
const cwd = process.cwd();
|
|
@@ -15988,8 +16362,8 @@ async function run3(rawArgs) {
|
|
|
15988
16362
|
} catch (err) {
|
|
15989
16363
|
return toolError(err instanceof Error ? err.message : String(err));
|
|
15990
16364
|
}
|
|
15991
|
-
const componentAbs =
|
|
15992
|
-
const apiAbs =
|
|
16365
|
+
const componentAbs = resolve20(cwd, parsed.componentDir);
|
|
16366
|
+
const apiAbs = resolve20(cwd, parsed.apiDir);
|
|
15993
16367
|
const modelFilter = parsed.model ?? (parsed.identity ? identityToModel3(parsed.identity) : void 0);
|
|
15994
16368
|
let report;
|
|
15995
16369
|
try {
|
|
@@ -16207,7 +16581,7 @@ var modelValidateFolderTool = createFolderValidateTool({
|
|
|
16207
16581
|
});
|
|
16208
16582
|
|
|
16209
16583
|
// packages/dbx-components-mcp/src/tools/model-store-scaffold.tool.ts
|
|
16210
|
-
import { type as
|
|
16584
|
+
import { type as type35 } from "arktype";
|
|
16211
16585
|
var STORE_SHAPES = ["root", "root-singleton", "sub-collection", "singleton-sub", "system-state"];
|
|
16212
16586
|
var SHAPE_PROFILES = {
|
|
16213
16587
|
root: { defaultSurfaces: ["document", "collection"], allowedSurfaces: ["document", "collection"], hasParent: false, emitsDirectives: true, requiresCollectionsClass: true, requiresSystemStateTypeConst: false },
|
|
@@ -16303,7 +16677,7 @@ var DBX_MODEL_STORE_SCAFFOLD_TOOL = {
|
|
|
16303
16677
|
required: ["model_name", "app_prefix", "firebase_package"]
|
|
16304
16678
|
}
|
|
16305
16679
|
};
|
|
16306
|
-
var ScaffoldArgsType2 =
|
|
16680
|
+
var ScaffoldArgsType2 = type35({
|
|
16307
16681
|
model_name: "string",
|
|
16308
16682
|
app_prefix: "string",
|
|
16309
16683
|
firebase_package: "string",
|
|
@@ -16323,7 +16697,7 @@ var ScaffoldArgsType2 = type34({
|
|
|
16323
16697
|
name: "string",
|
|
16324
16698
|
functions_path: "string"
|
|
16325
16699
|
},
|
|
16326
|
-
"crud_functions?":
|
|
16700
|
+
"crud_functions?": type35({
|
|
16327
16701
|
name: "string",
|
|
16328
16702
|
kind: "'create' | 'update' | 'crud'",
|
|
16329
16703
|
functions_path: "string"
|
|
@@ -16343,7 +16717,7 @@ function requireString(value, label) {
|
|
|
16343
16717
|
}
|
|
16344
16718
|
function parseArgs3(raw) {
|
|
16345
16719
|
const parsed = ScaffoldArgsType2(raw);
|
|
16346
|
-
if (parsed instanceof
|
|
16720
|
+
if (parsed instanceof type35.errors) {
|
|
16347
16721
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
16348
16722
|
}
|
|
16349
16723
|
const modelName = requireString(parsed.model_name, "model_name");
|
|
@@ -16735,8 +17109,8 @@ var modelStoreScaffoldTool = {
|
|
|
16735
17109
|
};
|
|
16736
17110
|
|
|
16737
17111
|
// packages/dbx-components-mcp/src/tools/model-fixture-list-app.tool.ts
|
|
16738
|
-
import { resolve as
|
|
16739
|
-
import { type as
|
|
17112
|
+
import { resolve as resolve21 } from "node:path";
|
|
17113
|
+
import { type as type36 } from "arktype";
|
|
16740
17114
|
|
|
16741
17115
|
// packages/dbx-components-mcp/src/tools/model-fixture-shared/archetype.ts
|
|
16742
17116
|
function classifyFixtureArchetype(input) {
|
|
@@ -16766,6 +17140,27 @@ function paramsHasFixtureDependencies(params) {
|
|
|
16766
17140
|
|
|
16767
17141
|
// packages/dbx-components-mcp/src/tools/model-fixture-shared/extract.ts
|
|
16768
17142
|
import { Node as Node13, Project as Project11, SyntaxKind as SyntaxKind7 } from "ts-morph";
|
|
17143
|
+
|
|
17144
|
+
// packages/dbx-components-mcp/src/tools/model-fixture-shared/framework-fixtures.ts
|
|
17145
|
+
var KNOWN_NON_MODEL_FIXTURE_FAMILIES = [
|
|
17146
|
+
{
|
|
17147
|
+
kind: "authorized-user",
|
|
17148
|
+
factoryName: "authorizedUserContextFactory",
|
|
17149
|
+
baseFixtureClass: "AuthorizedUserTestContextFixture",
|
|
17150
|
+
baseInstanceClass: "AuthorizedUserTestContextInstance",
|
|
17151
|
+
module: "@dereekb/firebase-server/test",
|
|
17152
|
+
description: "Authorized Firebase auth user (with custom claims). Not backed by a Firestore document."
|
|
17153
|
+
}
|
|
17154
|
+
];
|
|
17155
|
+
var NON_MODEL_JSDOC_TAG = "dbxFixtureNotModel";
|
|
17156
|
+
function findFamilyByFactoryName(factoryCallName) {
|
|
17157
|
+
return KNOWN_NON_MODEL_FIXTURE_FAMILIES.find((f) => f.factoryName === factoryCallName);
|
|
17158
|
+
}
|
|
17159
|
+
function findFamilyByBaseClass(baseClassName) {
|
|
17160
|
+
return KNOWN_NON_MODEL_FIXTURE_FAMILIES.find((f) => f.baseFixtureClass === baseClassName || f.baseInstanceClass === baseClassName);
|
|
17161
|
+
}
|
|
17162
|
+
|
|
17163
|
+
// packages/dbx-components-mcp/src/tools/model-fixture-shared/extract.ts
|
|
16769
17164
|
var FIXTURE_SUFFIX = "TestContextFixture";
|
|
16770
17165
|
var INSTANCE_SUFFIX = "TestContextInstance";
|
|
16771
17166
|
var PARAMS_SUFFIX = "TestContextParams";
|
|
@@ -16782,7 +17177,7 @@ function extractAppFixturesFromText(input) {
|
|
|
16782
17177
|
const unrecognized = [];
|
|
16783
17178
|
collectClasses(sourceFile, prefix, { fixtures: fixtureClasses, instances: instanceClasses, unrecognized });
|
|
16784
17179
|
const paramsTypes = collectParamsTypes(sourceFile, prefix);
|
|
16785
|
-
const factoriesByModel = collectFactories(sourceFile, prefix);
|
|
17180
|
+
const { factoriesByModel, nonModelFamiliesByModel } = collectFactories(sourceFile, prefix);
|
|
16786
17181
|
const singletonsByFactory = collectSingletonsByFactory(sourceFile);
|
|
16787
17182
|
const entries = [];
|
|
16788
17183
|
const seenModels = /* @__PURE__ */ new Set();
|
|
@@ -16806,10 +17201,13 @@ function extractAppFixturesFromText(input) {
|
|
|
16806
17201
|
const archetype = classifyFixtureArchetype({ factory, params });
|
|
16807
17202
|
const fixtureMethods = readClassMethods(fixtureClass);
|
|
16808
17203
|
const instanceMethods = readClassMethods(instanceClass);
|
|
17204
|
+
const { kind, nonModelFamily } = classifyFixtureKind({ fixtureClass, instanceClass, nonModelFamily: nonModelFamiliesByModel.get(model) });
|
|
16809
17205
|
const entry = {
|
|
16810
17206
|
model,
|
|
16811
17207
|
prefix: prefix ?? "",
|
|
16812
17208
|
archetype,
|
|
17209
|
+
kind,
|
|
17210
|
+
nonModelFamily,
|
|
16813
17211
|
fixtureClassName: fixtureClass.getName() ?? "",
|
|
16814
17212
|
instanceClassName: instanceClass.getName() ?? "",
|
|
16815
17213
|
paramsTypeName: params?.name ?? `${prefix ?? ""}${model}${PARAMS_SUFFIX}`,
|
|
@@ -16961,19 +17359,23 @@ function resolveFixtureFieldModel(typeText, prefix) {
|
|
|
16961
17359
|
return model.length > 0 ? model : void 0;
|
|
16962
17360
|
}
|
|
16963
17361
|
function collectFactories(sourceFile, prefix) {
|
|
16964
|
-
const
|
|
17362
|
+
const factoriesByModel = /* @__PURE__ */ new Map();
|
|
17363
|
+
const nonModelFamiliesByModel = /* @__PURE__ */ new Map();
|
|
16965
17364
|
for (const stmt of sourceFile.getVariableStatements()) {
|
|
16966
17365
|
for (const decl of stmt.getDeclarations()) {
|
|
16967
|
-
const
|
|
16968
|
-
if (!
|
|
16969
|
-
const model = factoryNameToModel(factory.factoryName, prefix);
|
|
17366
|
+
const parsed = readContextFactory(decl);
|
|
17367
|
+
if (!parsed) continue;
|
|
17368
|
+
const model = factoryNameToModel(parsed.factory.factoryName, prefix);
|
|
16970
17369
|
if (model === void 0) continue;
|
|
16971
|
-
|
|
17370
|
+
factoriesByModel.set(model, parsed.factory);
|
|
17371
|
+
if (parsed.family !== void 0) {
|
|
17372
|
+
nonModelFamiliesByModel.set(model, parsed.family);
|
|
17373
|
+
}
|
|
16972
17374
|
}
|
|
16973
17375
|
}
|
|
16974
|
-
return
|
|
17376
|
+
return { factoriesByModel, nonModelFamiliesByModel };
|
|
16975
17377
|
}
|
|
16976
|
-
function
|
|
17378
|
+
function readContextFactory(decl) {
|
|
16977
17379
|
const initializer = decl.getInitializer();
|
|
16978
17380
|
if (!initializer) return void 0;
|
|
16979
17381
|
let bodyExpr;
|
|
@@ -16984,7 +17386,13 @@ function readModelTestContextFactory(decl, _prefix) {
|
|
|
16984
17386
|
}
|
|
16985
17387
|
if (!bodyExpr || !Node13.isCallExpression(bodyExpr)) return void 0;
|
|
16986
17388
|
const callee = bodyExpr.getExpression();
|
|
16987
|
-
if (!Node13.isIdentifier(callee)
|
|
17389
|
+
if (!Node13.isIdentifier(callee)) return void 0;
|
|
17390
|
+
const calleeName = callee.getText();
|
|
17391
|
+
let family;
|
|
17392
|
+
if (calleeName !== MODEL_FACTORY_NAME) {
|
|
17393
|
+
family = findFamilyByFactoryName(calleeName);
|
|
17394
|
+
if (family === void 0) return void 0;
|
|
17395
|
+
}
|
|
16988
17396
|
const generics = bodyExpr.getTypeArguments().map((t) => t.getText());
|
|
16989
17397
|
const args = bodyExpr.getArguments();
|
|
16990
17398
|
let hasParamsGetCollection = false;
|
|
@@ -17011,7 +17419,7 @@ function readModelTestContextFactory(decl, _prefix) {
|
|
|
17011
17419
|
}
|
|
17012
17420
|
}
|
|
17013
17421
|
}
|
|
17014
|
-
const
|
|
17422
|
+
const factory = {
|
|
17015
17423
|
factoryName: decl.getName(),
|
|
17016
17424
|
genericArgs: generics,
|
|
17017
17425
|
hasParamsGetCollection,
|
|
@@ -17020,7 +17428,41 @@ function readModelTestContextFactory(decl, _prefix) {
|
|
|
17020
17428
|
parentFixtureFieldFromGetCollection,
|
|
17021
17429
|
line: decl.getStartLineNumber()
|
|
17022
17430
|
};
|
|
17023
|
-
return
|
|
17431
|
+
return { factory, family };
|
|
17432
|
+
}
|
|
17433
|
+
function classifyFixtureKind(input) {
|
|
17434
|
+
if (hasNonModelJsDoc(input.fixtureClass) || hasNonModelJsDoc(input.instanceClass)) {
|
|
17435
|
+
return { kind: "non-model", nonModelFamily: "jsdoc-tag" };
|
|
17436
|
+
}
|
|
17437
|
+
const familyFromInheritance = familyFromExtends(input.fixtureClass) ?? familyFromExtends(input.instanceClass);
|
|
17438
|
+
const family = familyFromInheritance ?? input.nonModelFamily;
|
|
17439
|
+
if (family !== void 0) {
|
|
17440
|
+
return { kind: family.kind, nonModelFamily: family.kind };
|
|
17441
|
+
}
|
|
17442
|
+
return { kind: "firestore-model" };
|
|
17443
|
+
}
|
|
17444
|
+
function hasNonModelJsDoc(cls) {
|
|
17445
|
+
for (const doc of cls.getJsDocs()) {
|
|
17446
|
+
for (const tag of doc.getTags()) {
|
|
17447
|
+
if (tag.getTagName() === NON_MODEL_JSDOC_TAG) return true;
|
|
17448
|
+
}
|
|
17449
|
+
}
|
|
17450
|
+
return false;
|
|
17451
|
+
}
|
|
17452
|
+
function familyFromExtends(cls) {
|
|
17453
|
+
const ext = cls.getExtends();
|
|
17454
|
+
if (!ext) return void 0;
|
|
17455
|
+
const expr = ext.getExpression();
|
|
17456
|
+
let baseName;
|
|
17457
|
+
if (Node13.isIdentifier(expr)) {
|
|
17458
|
+
baseName = expr.getText();
|
|
17459
|
+
} else {
|
|
17460
|
+
const text = ext.getText();
|
|
17461
|
+
const match = /^([A-Za-z_$][\w$]*)/.exec(text);
|
|
17462
|
+
baseName = match ? match[1] : void 0;
|
|
17463
|
+
}
|
|
17464
|
+
if (baseName === void 0) return void 0;
|
|
17465
|
+
return findFamilyByBaseClass(baseName);
|
|
17024
17466
|
}
|
|
17025
17467
|
function readSingleReturnExpression(fn) {
|
|
17026
17468
|
const body = fn.getBody();
|
|
@@ -17176,12 +17618,15 @@ async function inspectAppFixtures(apiAbs, apiRel) {
|
|
|
17176
17618
|
function validateAppFixtures(extraction, options = {}) {
|
|
17177
17619
|
const diagnostics = [];
|
|
17178
17620
|
for (const entry of extraction.entries) {
|
|
17179
|
-
|
|
17621
|
+
const isFirestoreModel = entry.kind === "firestore-model";
|
|
17622
|
+
if (isFirestoreModel) {
|
|
17623
|
+
pushTripletCompletenessDiagnostics(entry, diagnostics);
|
|
17624
|
+
pushArchetypeConsistencyDiagnostics(entry, diagnostics);
|
|
17625
|
+
pushParentFieldNamingDiagnostics(entry, options.registry, diagnostics);
|
|
17626
|
+
pushRegistryDiagnostics(entry, options.registry, diagnostics);
|
|
17627
|
+
}
|
|
17180
17628
|
pushForwardingDiagnostics(entry, diagnostics);
|
|
17181
|
-
pushGenericAlignmentDiagnostics(entry, diagnostics);
|
|
17182
|
-
pushArchetypeConsistencyDiagnostics(entry, diagnostics);
|
|
17183
|
-
pushParentFieldNamingDiagnostics(entry, options.registry, diagnostics);
|
|
17184
|
-
pushRegistryDiagnostics(entry, options.registry, diagnostics);
|
|
17629
|
+
pushGenericAlignmentDiagnostics(entry, diagnostics, { skipFactoryComparison: !isFirestoreModel });
|
|
17185
17630
|
}
|
|
17186
17631
|
pushOrphanFixtureDiagnostics(extraction, diagnostics);
|
|
17187
17632
|
pushModelsWithoutFixtureDiagnostics(extraction, options.registry, diagnostics);
|
|
@@ -17257,7 +17702,7 @@ function pushForwardingDiagnostics(entry, out) {
|
|
|
17257
17702
|
}
|
|
17258
17703
|
}
|
|
17259
17704
|
}
|
|
17260
|
-
function pushGenericAlignmentDiagnostics(entry, out) {
|
|
17705
|
+
function pushGenericAlignmentDiagnostics(entry, out, options = { skipFactoryComparison: false }) {
|
|
17261
17706
|
const fixGenerics = entry.fixtureExtendsGenerics;
|
|
17262
17707
|
const instGenerics = entry.instanceExtendsGenerics;
|
|
17263
17708
|
const factoryGenerics = entry.factory?.genericArgs ?? [];
|
|
@@ -17285,6 +17730,7 @@ function pushGenericAlignmentDiagnostics(entry, out) {
|
|
|
17285
17730
|
line: entry.fixtureLine
|
|
17286
17731
|
});
|
|
17287
17732
|
}
|
|
17733
|
+
if (options.skipFactoryComparison) return;
|
|
17288
17734
|
if (factoryModel !== void 0 && fixModel !== void 0 && factoryModel !== fixModel) {
|
|
17289
17735
|
out.push({
|
|
17290
17736
|
code: "generics-misaligned",
|
|
@@ -17419,6 +17865,8 @@ function summarizeEntry(entry, full = false) {
|
|
|
17419
17865
|
const summary = {
|
|
17420
17866
|
model: entry.model,
|
|
17421
17867
|
prefix: entry.prefix,
|
|
17868
|
+
kind: entry.kind,
|
|
17869
|
+
nonModelFamily: entry.nonModelFamily,
|
|
17422
17870
|
archetype: entry.archetype,
|
|
17423
17871
|
fixtureClassName: entry.fixtureClassName,
|
|
17424
17872
|
instanceClassName: entry.instanceClassName,
|
|
@@ -17452,9 +17900,16 @@ function formatListAsMarkdown(extraction) {
|
|
|
17452
17900
|
if (extraction.entries.length === 0) {
|
|
17453
17901
|
lines.push("", "_No model fixtures found._");
|
|
17454
17902
|
} else {
|
|
17455
|
-
lines.push("", "| Model | Archetype | Fixture | Instance | Params | Factory | Singleton | Methods (F/I) | Lines |", "
|
|
17903
|
+
lines.push("", "| Model | Kind | Archetype | Fixture | Instance | Params | Factory | Singleton | Methods (F/I) | Lines |", "|---|---|---|---|---|---|---|---|---|---|");
|
|
17456
17904
|
for (const e of extraction.entries) {
|
|
17457
|
-
lines.push("| " + [e.model, e.archetype, code3(e.fixtureClassName), code3(e.instanceClassName), code3(e.paramsTypeName), code3(e.factoryName ?? "\u2014"), code3(e.singletonName ?? "\u2014"), `${e.fixtureMethods.length}/${e.instanceMethods.length}`, `${e.fixtureLine}-${e.instanceEndLine}`].join(" | ") + " |");
|
|
17905
|
+
lines.push("| " + [e.model, e.kind, e.archetype, code3(e.fixtureClassName), code3(e.instanceClassName), code3(e.paramsTypeName), code3(e.factoryName ?? "\u2014"), code3(e.singletonName ?? "\u2014"), `${e.fixtureMethods.length}/${e.instanceMethods.length}`, `${e.fixtureLine}-${e.instanceEndLine}`].join(" | ") + " |");
|
|
17906
|
+
}
|
|
17907
|
+
const nonModelEntries = extraction.entries.filter((e) => e.kind !== "firestore-model");
|
|
17908
|
+
if (nonModelEntries.length > 0) {
|
|
17909
|
+
lines.push("", "### Non-model fixtures");
|
|
17910
|
+
for (const e of nonModelEntries) {
|
|
17911
|
+
lines.push("", `- **${e.model}** \u2014 ${nonModelDescription(e)}`);
|
|
17912
|
+
}
|
|
17458
17913
|
}
|
|
17459
17914
|
}
|
|
17460
17915
|
if (extraction.unrecognizedClassNames.length > 0) {
|
|
@@ -17481,7 +17936,21 @@ function formatLookupAsMarkdown2(extraction, entry) {
|
|
|
17481
17936
|
return lines.join("\n");
|
|
17482
17937
|
}
|
|
17483
17938
|
function appendLookupHeader(lines, extraction, entry) {
|
|
17484
|
-
lines.push(`# Fixture: \`${entry.prefix}${entry.model}\``, "", `Source: \`${extraction.fixturePath}\``, `Archetype: \`${entry.archetype}
|
|
17939
|
+
lines.push(`# Fixture: \`${entry.prefix}${entry.model}\``, "", `Source: \`${extraction.fixturePath}\``, `Kind: \`${entry.kind}\``, `Archetype: \`${entry.archetype}\``);
|
|
17940
|
+
if (entry.kind !== "firestore-model") {
|
|
17941
|
+
lines.push("", `> ${nonModelDescription(entry)}`);
|
|
17942
|
+
}
|
|
17943
|
+
lines.push("");
|
|
17944
|
+
}
|
|
17945
|
+
function nonModelDescription(entry) {
|
|
17946
|
+
if (entry.nonModelFamily === "jsdoc-tag") {
|
|
17947
|
+
return "Tagged `@dbxFixtureNotModel` \u2014 explicitly opted out of model validation.";
|
|
17948
|
+
}
|
|
17949
|
+
const family = KNOWN_NON_MODEL_FIXTURE_FAMILIES.find((f) => f.kind === entry.kind);
|
|
17950
|
+
if (family) {
|
|
17951
|
+
return `${family.description} Registered via \`${family.factoryName}\` (\`${family.module}\`).`;
|
|
17952
|
+
}
|
|
17953
|
+
return "Non-Firestore-model fixture.";
|
|
17485
17954
|
}
|
|
17486
17955
|
function appendLookupTriplet(lines, entry) {
|
|
17487
17956
|
lines.push("## Triplet", "", `- Fixture: \`${entry.fixtureClassName}\` (lines ${entry.fixtureLine}-${entry.fixtureEndLine})`, `- Instance: \`${entry.instanceClassName}\` (lines ${entry.instanceLine}-${entry.instanceEndLine})`, `- Params: \`${entry.paramsTypeName}\``, `- Factory: \`${entry.factoryName ?? "\u2014"}\``, `- Singleton: \`${entry.singletonName ?? "\u2014"}\``);
|
|
@@ -17845,7 +18314,7 @@ function topLevelColonIndex(text) {
|
|
|
17845
18314
|
}
|
|
17846
18315
|
|
|
17847
18316
|
// packages/dbx-components-mcp/src/tools/model-fixture-list-app.tool.ts
|
|
17848
|
-
var ListArgsType2 =
|
|
18317
|
+
var ListArgsType2 = type36({
|
|
17849
18318
|
apiDir: "string",
|
|
17850
18319
|
"format?": "'markdown' | 'json'"
|
|
17851
18320
|
});
|
|
@@ -17873,7 +18342,7 @@ var TOOL4 = {
|
|
|
17873
18342
|
};
|
|
17874
18343
|
async function run4(rawArgs) {
|
|
17875
18344
|
const parsed = ListArgsType2(rawArgs);
|
|
17876
|
-
if (parsed instanceof
|
|
18345
|
+
if (parsed instanceof type36.errors) {
|
|
17877
18346
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
17878
18347
|
}
|
|
17879
18348
|
const cwd = process.cwd();
|
|
@@ -17882,7 +18351,7 @@ async function run4(rawArgs) {
|
|
|
17882
18351
|
} catch (err) {
|
|
17883
18352
|
return toolError(err instanceof Error ? err.message : String(err));
|
|
17884
18353
|
}
|
|
17885
|
-
const apiAbs =
|
|
18354
|
+
const apiAbs = resolve21(cwd, parsed.apiDir);
|
|
17886
18355
|
let extraction;
|
|
17887
18356
|
try {
|
|
17888
18357
|
extraction = await inspectAppFixtures(apiAbs, parsed.apiDir);
|
|
@@ -17896,9 +18365,9 @@ async function run4(rawArgs) {
|
|
|
17896
18365
|
var modelFixtureListAppTool = { definition: TOOL4, run: run4 };
|
|
17897
18366
|
|
|
17898
18367
|
// packages/dbx-components-mcp/src/tools/model-fixture-lookup.tool.ts
|
|
17899
|
-
import { resolve as
|
|
17900
|
-
import { type as
|
|
17901
|
-
var LookupArgsType2 =
|
|
18368
|
+
import { resolve as resolve22 } from "node:path";
|
|
18369
|
+
import { type as type37 } from "arktype";
|
|
18370
|
+
var LookupArgsType2 = type37({
|
|
17902
18371
|
apiDir: "string",
|
|
17903
18372
|
"model?": "string",
|
|
17904
18373
|
"identity?": "string",
|
|
@@ -17930,7 +18399,7 @@ var TOOL5 = {
|
|
|
17930
18399
|
};
|
|
17931
18400
|
async function run5(rawArgs) {
|
|
17932
18401
|
const parsed = LookupArgsType2(rawArgs);
|
|
17933
|
-
if (parsed instanceof
|
|
18402
|
+
if (parsed instanceof type37.errors) {
|
|
17934
18403
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
17935
18404
|
}
|
|
17936
18405
|
if (!parsed.model && !parsed.identity) {
|
|
@@ -17942,7 +18411,7 @@ async function run5(rawArgs) {
|
|
|
17942
18411
|
} catch (err) {
|
|
17943
18412
|
return toolError(err instanceof Error ? err.message : String(err));
|
|
17944
18413
|
}
|
|
17945
|
-
const apiAbs =
|
|
18414
|
+
const apiAbs = resolve22(cwd, parsed.apiDir);
|
|
17946
18415
|
let extraction;
|
|
17947
18416
|
try {
|
|
17948
18417
|
extraction = await inspectAppFixtures(apiAbs, parsed.apiDir);
|
|
@@ -17968,9 +18437,9 @@ function identityToModel4(identity) {
|
|
|
17968
18437
|
var modelFixtureLookupTool = { definition: TOOL5, run: run5 };
|
|
17969
18438
|
|
|
17970
18439
|
// packages/dbx-components-mcp/src/tools/model-fixture-validate-app.tool.ts
|
|
17971
|
-
import { resolve as
|
|
17972
|
-
import { type as
|
|
17973
|
-
var ValidateArgsType2 =
|
|
18440
|
+
import { resolve as resolve23 } from "node:path";
|
|
18441
|
+
import { type as type38 } from "arktype";
|
|
18442
|
+
var ValidateArgsType2 = type38({
|
|
17974
18443
|
apiDir: "string",
|
|
17975
18444
|
"format?": "'markdown' | 'json'"
|
|
17976
18445
|
});
|
|
@@ -18003,7 +18472,7 @@ var TOOL6 = {
|
|
|
18003
18472
|
function createModelFixtureValidateAppTool(config = {}) {
|
|
18004
18473
|
async function run15(rawArgs) {
|
|
18005
18474
|
const parsed = ValidateArgsType2(rawArgs);
|
|
18006
|
-
if (parsed instanceof
|
|
18475
|
+
if (parsed instanceof type38.errors) {
|
|
18007
18476
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
18008
18477
|
}
|
|
18009
18478
|
const cwd = process.cwd();
|
|
@@ -18012,7 +18481,7 @@ function createModelFixtureValidateAppTool(config = {}) {
|
|
|
18012
18481
|
} catch (err) {
|
|
18013
18482
|
return toolError(err instanceof Error ? err.message : String(err));
|
|
18014
18483
|
}
|
|
18015
|
-
const apiAbs =
|
|
18484
|
+
const apiAbs = resolve23(cwd, parsed.apiDir);
|
|
18016
18485
|
let extraction;
|
|
18017
18486
|
try {
|
|
18018
18487
|
extraction = await inspectAppFixtures(apiAbs, parsed.apiDir);
|
|
@@ -18033,16 +18502,16 @@ function createModelFixtureValidateAppTool(config = {}) {
|
|
|
18033
18502
|
|
|
18034
18503
|
// packages/dbx-components-mcp/src/tools/model-fixture-scaffold.tool.ts
|
|
18035
18504
|
import { readFile as readFile11, writeFile } from "node:fs/promises";
|
|
18036
|
-
import { join as join10, resolve as
|
|
18037
|
-
import { type as
|
|
18038
|
-
var ScaffoldArgsType3 =
|
|
18505
|
+
import { join as join10, resolve as resolve24 } from "node:path";
|
|
18506
|
+
import { type as type39 } from "arktype";
|
|
18507
|
+
var ScaffoldArgsType3 = type39({
|
|
18039
18508
|
apiDir: "string",
|
|
18040
18509
|
model: "string",
|
|
18041
18510
|
archetype: "'top-level-simple' | 'top-level-with-deps' | 'sub-collection' | 'sub-collection-traversal'",
|
|
18042
18511
|
"prefix?": "string",
|
|
18043
18512
|
"parentFixture?": "string",
|
|
18044
18513
|
"parentFixtureField?": "string",
|
|
18045
|
-
"paramsDependsOn?":
|
|
18514
|
+
"paramsDependsOn?": type39({
|
|
18046
18515
|
field: "string",
|
|
18047
18516
|
fixtureModel: "string",
|
|
18048
18517
|
"optional?": "boolean",
|
|
@@ -18103,7 +18572,7 @@ var TOOL7 = {
|
|
|
18103
18572
|
};
|
|
18104
18573
|
async function run6(rawArgs) {
|
|
18105
18574
|
const parsed = ScaffoldArgsType3(rawArgs);
|
|
18106
|
-
if (parsed instanceof
|
|
18575
|
+
if (parsed instanceof type39.errors) {
|
|
18107
18576
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
18108
18577
|
}
|
|
18109
18578
|
const cwd = process.cwd();
|
|
@@ -18112,7 +18581,7 @@ async function run6(rawArgs) {
|
|
|
18112
18581
|
} catch (err) {
|
|
18113
18582
|
return toolError(err instanceof Error ? err.message : String(err));
|
|
18114
18583
|
}
|
|
18115
|
-
const apiAbs =
|
|
18584
|
+
const apiAbs = resolve24(cwd, parsed.apiDir);
|
|
18116
18585
|
let extraction;
|
|
18117
18586
|
try {
|
|
18118
18587
|
extraction = await inspectAppFixtures(apiAbs, parsed.apiDir);
|
|
@@ -18203,10 +18672,10 @@ function collectConflicts(extraction, rendered) {
|
|
|
18203
18672
|
var modelFixtureScaffoldTool = { definition: TOOL7, run: run6 };
|
|
18204
18673
|
|
|
18205
18674
|
// packages/dbx-components-mcp/src/tools/model-fixture-forward.tool.ts
|
|
18206
|
-
import { join as join11, resolve as
|
|
18207
|
-
import { type as
|
|
18675
|
+
import { join as join11, resolve as resolve25 } from "node:path";
|
|
18676
|
+
import { type as type40 } from "arktype";
|
|
18208
18677
|
import { Project as Project12 } from "ts-morph";
|
|
18209
|
-
var ForwardArgsType =
|
|
18678
|
+
var ForwardArgsType = type40({
|
|
18210
18679
|
apiDir: "string",
|
|
18211
18680
|
model: "string",
|
|
18212
18681
|
"methods?": "string[]"
|
|
@@ -18230,7 +18699,7 @@ var TOOL8 = {
|
|
|
18230
18699
|
};
|
|
18231
18700
|
async function run7(rawArgs) {
|
|
18232
18701
|
const parsed = ForwardArgsType(rawArgs);
|
|
18233
|
-
if (parsed instanceof
|
|
18702
|
+
if (parsed instanceof type40.errors) {
|
|
18234
18703
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
18235
18704
|
}
|
|
18236
18705
|
const cwd = process.cwd();
|
|
@@ -18239,7 +18708,7 @@ async function run7(rawArgs) {
|
|
|
18239
18708
|
} catch (err) {
|
|
18240
18709
|
return toolError(toErrorMessage(err));
|
|
18241
18710
|
}
|
|
18242
|
-
const apiAbs =
|
|
18711
|
+
const apiAbs = resolve25(cwd, parsed.apiDir);
|
|
18243
18712
|
let extraction;
|
|
18244
18713
|
try {
|
|
18245
18714
|
extraction = await inspectAppFixtures(apiAbs, parsed.apiDir);
|
|
@@ -18313,8 +18782,8 @@ function appendListSection(lines, heading, names) {
|
|
|
18313
18782
|
var modelFixtureForwardTool = { definition: TOOL8, run: run7 };
|
|
18314
18783
|
|
|
18315
18784
|
// packages/dbx-components-mcp/src/tools/model-test-tree.tool.ts
|
|
18316
|
-
import { resolve as
|
|
18317
|
-
import { type as
|
|
18785
|
+
import { resolve as resolve26 } from "node:path";
|
|
18786
|
+
import { type as type41 } from "arktype";
|
|
18318
18787
|
|
|
18319
18788
|
// packages/dbx-components-mcp/src/tools/model-test-shared/extract.ts
|
|
18320
18789
|
import { Node as Node14, Project as Project13, SyntaxKind as SyntaxKind8 } from "ts-morph";
|
|
@@ -19059,7 +19528,7 @@ function parseDescribePath2(value) {
|
|
|
19059
19528
|
}
|
|
19060
19529
|
|
|
19061
19530
|
// packages/dbx-components-mcp/src/tools/model-test-tree.tool.ts
|
|
19062
|
-
var TreeArgsType =
|
|
19531
|
+
var TreeArgsType = type41({
|
|
19063
19532
|
specFile: "string",
|
|
19064
19533
|
"apiDir?": "string",
|
|
19065
19534
|
"view?": "'all' | 'describes' | 'fixtures' | 'its' | 'helpers'",
|
|
@@ -19097,7 +19566,7 @@ var TOOL9 = {
|
|
|
19097
19566
|
};
|
|
19098
19567
|
async function run8(rawArgs) {
|
|
19099
19568
|
const parsed = TreeArgsType(rawArgs);
|
|
19100
|
-
if (parsed instanceof
|
|
19569
|
+
if (parsed instanceof type41.errors) {
|
|
19101
19570
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
19102
19571
|
}
|
|
19103
19572
|
const cwd = process.cwd();
|
|
@@ -19107,8 +19576,8 @@ async function run8(rawArgs) {
|
|
|
19107
19576
|
} catch (err) {
|
|
19108
19577
|
return toolError(err instanceof Error ? err.message : String(err));
|
|
19109
19578
|
}
|
|
19110
|
-
const specAbs =
|
|
19111
|
-
const apiAbs = parsed.apiDir !== void 0 ?
|
|
19579
|
+
const specAbs = resolve26(cwd, parsed.specFile);
|
|
19580
|
+
const apiAbs = parsed.apiDir !== void 0 ? resolve26(cwd, parsed.apiDir) : void 0;
|
|
19112
19581
|
let tree;
|
|
19113
19582
|
try {
|
|
19114
19583
|
tree = await inspectSpecFile({ specAbs, specRel: parsed.specFile, apiAbs, apiRel: parsed.apiDir });
|
|
@@ -19124,9 +19593,9 @@ async function run8(rawArgs) {
|
|
|
19124
19593
|
var modelTestTreeTool = { definition: TOOL9, run: run8 };
|
|
19125
19594
|
|
|
19126
19595
|
// packages/dbx-components-mcp/src/tools/model-test-search.tool.ts
|
|
19127
|
-
import { resolve as
|
|
19128
|
-
import { type as
|
|
19129
|
-
var SearchArgsType2 =
|
|
19596
|
+
import { resolve as resolve27 } from "node:path";
|
|
19597
|
+
import { type as type42 } from "arktype";
|
|
19598
|
+
var SearchArgsType2 = type42({
|
|
19130
19599
|
specFile: "string",
|
|
19131
19600
|
"apiDir?": "string",
|
|
19132
19601
|
"model?": "string",
|
|
@@ -19167,7 +19636,7 @@ var TOOL10 = {
|
|
|
19167
19636
|
};
|
|
19168
19637
|
async function run9(rawArgs) {
|
|
19169
19638
|
const parsed = SearchArgsType2(rawArgs);
|
|
19170
|
-
if (parsed instanceof
|
|
19639
|
+
if (parsed instanceof type42.errors) {
|
|
19171
19640
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
19172
19641
|
}
|
|
19173
19642
|
const queryFields = [
|
|
@@ -19190,8 +19659,8 @@ async function run9(rawArgs) {
|
|
|
19190
19659
|
} catch (err) {
|
|
19191
19660
|
return toolError(err instanceof Error ? err.message : String(err));
|
|
19192
19661
|
}
|
|
19193
|
-
const specAbs =
|
|
19194
|
-
const apiAbs = parsed.apiDir !== void 0 ?
|
|
19662
|
+
const specAbs = resolve27(cwd, parsed.specFile);
|
|
19663
|
+
const apiAbs = parsed.apiDir !== void 0 ? resolve27(cwd, parsed.apiDir) : void 0;
|
|
19195
19664
|
let tree;
|
|
19196
19665
|
try {
|
|
19197
19666
|
tree = await inspectSpecFile({ specAbs, specRel: parsed.specFile, apiAbs, apiRel: parsed.apiDir });
|
|
@@ -19618,8 +20087,8 @@ function getFunctionType(x) {
|
|
|
19618
20087
|
return typeof x === "function" ? x.prototype ? Object.getOwnPropertyDescriptor(x, "prototype")?.writable ? "function" : "class" : x.constructor.name === "AsyncFunction" ? "function" : "arrow" : null;
|
|
19619
20088
|
}
|
|
19620
20089
|
function isNonClassFunction(x) {
|
|
19621
|
-
const
|
|
19622
|
-
return
|
|
20090
|
+
const type68 = getFunctionType(x);
|
|
20091
|
+
return type68 != null && type68 !== "class";
|
|
19623
20092
|
}
|
|
19624
20093
|
|
|
19625
20094
|
// packages/util/src/lib/getter/getter.ts
|
|
@@ -19696,9 +20165,9 @@ function asNumber(input) {
|
|
|
19696
20165
|
}
|
|
19697
20166
|
|
|
19698
20167
|
// packages/util/src/lib/number/round.ts
|
|
19699
|
-
function roundingFunction(
|
|
20168
|
+
function roundingFunction(type68) {
|
|
19700
20169
|
let fn;
|
|
19701
|
-
switch (
|
|
20170
|
+
switch (type68) {
|
|
19702
20171
|
case "floor":
|
|
19703
20172
|
fn = Math.floor;
|
|
19704
20173
|
break;
|
|
@@ -19951,9 +20420,9 @@ function filterKeyValueTuplesInputToFilter(input) {
|
|
|
19951
20420
|
}
|
|
19952
20421
|
function filterKeyValueTupleFunction(inputFilter) {
|
|
19953
20422
|
const filter = filterKeyValueTuplesInputToFilter(inputFilter);
|
|
19954
|
-
const { valueFilter:
|
|
20423
|
+
const { valueFilter: type68 = 1 /* UNDEFINED */, invertFilter: inverseFilter = false, keysFilter } = filter;
|
|
19955
20424
|
let filterFn;
|
|
19956
|
-
switch (
|
|
20425
|
+
switch (type68) {
|
|
19957
20426
|
case 1 /* UNDEFINED */:
|
|
19958
20427
|
filterFn = ([, x]) => x !== void 0;
|
|
19959
20428
|
break;
|
|
@@ -20212,7 +20681,7 @@ var NUMBER_STRING_DENCODER_64_DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcd
|
|
|
20212
20681
|
var NUMBER_STRING_DENCODER_64_DEFAULT_NEGATIVE_PREFIX = "!";
|
|
20213
20682
|
function numberStringDencoder(config) {
|
|
20214
20683
|
const { negativePrefix, digits } = config;
|
|
20215
|
-
const
|
|
20684
|
+
const type68 = negativePrefix ? "integer" : "positive_integer";
|
|
20216
20685
|
const log2OfDigits = Math.min(6, Math.floor(Math.log2(digits.length)));
|
|
20217
20686
|
const bitDepth = Math.pow(2, log2OfDigits);
|
|
20218
20687
|
const bitMask = bitDepth - 1;
|
|
@@ -20249,7 +20718,7 @@ function numberStringDencoder(config) {
|
|
|
20249
20718
|
return result;
|
|
20250
20719
|
}
|
|
20251
20720
|
return {
|
|
20252
|
-
type:
|
|
20721
|
+
type: type68,
|
|
20253
20722
|
digits,
|
|
20254
20723
|
bitDepth,
|
|
20255
20724
|
negativePrefix,
|
|
@@ -20320,9 +20789,9 @@ function readableStreamToStringFunction(encoding) {
|
|
|
20320
20789
|
var readableStreamToBase64 = readableStreamToStringFunction("base64");
|
|
20321
20790
|
function readableStreamToBuffer(stream) {
|
|
20322
20791
|
const chunks = [];
|
|
20323
|
-
return new Promise((
|
|
20792
|
+
return new Promise((resolve41, reject) => {
|
|
20324
20793
|
stream.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
20325
|
-
stream.on("end", () =>
|
|
20794
|
+
stream.on("end", () => resolve41(Buffer.concat(chunks)));
|
|
20326
20795
|
stream.on("error", reject);
|
|
20327
20796
|
});
|
|
20328
20797
|
}
|
|
@@ -24106,7 +24575,7 @@ var systemMValidateFolderTool = createFolderValidateTool({
|
|
|
24106
24575
|
});
|
|
24107
24576
|
|
|
24108
24577
|
// packages/dbx-components-mcp/src/tools/lookup-action.tool.ts
|
|
24109
|
-
import { type as
|
|
24578
|
+
import { type as type43 } from "arktype";
|
|
24110
24579
|
var DBX_ACTION_LOOKUP_TOOL = {
|
|
24111
24580
|
name: "dbx_action_lookup",
|
|
24112
24581
|
description: [
|
|
@@ -24139,13 +24608,13 @@ var DBX_ACTION_LOOKUP_TOOL = {
|
|
|
24139
24608
|
required: ["topic"]
|
|
24140
24609
|
}
|
|
24141
24610
|
};
|
|
24142
|
-
var LookupActionArgsType =
|
|
24611
|
+
var LookupActionArgsType = type43({
|
|
24143
24612
|
topic: "string",
|
|
24144
24613
|
"depth?": "'brief' | 'full'"
|
|
24145
24614
|
});
|
|
24146
24615
|
function parseLookupActionArgs(raw) {
|
|
24147
24616
|
const parsed = LookupActionArgsType(raw);
|
|
24148
|
-
if (parsed instanceof
|
|
24617
|
+
if (parsed instanceof type43.errors) {
|
|
24149
24618
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
24150
24619
|
}
|
|
24151
24620
|
const result = {
|
|
@@ -24443,7 +24912,7 @@ function createLookupActionTool(input) {
|
|
|
24443
24912
|
}
|
|
24444
24913
|
|
|
24445
24914
|
// packages/dbx-components-mcp/src/tools/action-examples.tool.ts
|
|
24446
|
-
import { type as
|
|
24915
|
+
import { type as type44 } from "arktype";
|
|
24447
24916
|
|
|
24448
24917
|
// packages/dbx-components-mcp/src/tools/data/patterns/actions/action.auto-trigger-on-modify.pattern.ts
|
|
24449
24918
|
var ACTION_PATTERN_AUTO_TRIGGER_ON_MODIFY = {
|
|
@@ -24803,13 +25272,13 @@ var DBX_ACTION_EXAMPLES_TOOL = {
|
|
|
24803
25272
|
required: ["pattern"]
|
|
24804
25273
|
}
|
|
24805
25274
|
};
|
|
24806
|
-
var ActionExamplesArgsType =
|
|
25275
|
+
var ActionExamplesArgsType = type44({
|
|
24807
25276
|
pattern: "string",
|
|
24808
25277
|
"depth?": "'minimal' | 'brief' | 'full'"
|
|
24809
25278
|
});
|
|
24810
25279
|
function parseActionExamplesArgs(raw) {
|
|
24811
25280
|
const parsed = ActionExamplesArgsType(raw);
|
|
24812
|
-
if (parsed instanceof
|
|
25281
|
+
if (parsed instanceof type44.errors) {
|
|
24813
25282
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
24814
25283
|
}
|
|
24815
25284
|
const result = {
|
|
@@ -24871,7 +25340,7 @@ var actionExamplesTool = {
|
|
|
24871
25340
|
};
|
|
24872
25341
|
|
|
24873
25342
|
// packages/dbx-components-mcp/src/tools/action-scaffold.tool.ts
|
|
24874
|
-
import { type as
|
|
25343
|
+
import { type as type45 } from "arktype";
|
|
24875
25344
|
var TRIGGER_VALUES = ["button", "form", "auto-modify"];
|
|
24876
25345
|
var SUCCESS_FEEDBACK_VALUES = ["snackbar", "redirect", "none"];
|
|
24877
25346
|
var CONTEXT_PROVIDER_VALUES = ["inline", "parent", "host-component"];
|
|
@@ -24905,7 +25374,7 @@ var DBX_ACTION_SCAFFOLD_TOOL = {
|
|
|
24905
25374
|
required: ["use_case", "trigger", "value_type"]
|
|
24906
25375
|
}
|
|
24907
25376
|
};
|
|
24908
|
-
var ScaffoldArgsType4 =
|
|
25377
|
+
var ScaffoldArgsType4 = type45({
|
|
24909
25378
|
use_case: "string",
|
|
24910
25379
|
trigger: "'button' | 'form' | 'auto-modify'",
|
|
24911
25380
|
"confirm?": "boolean",
|
|
@@ -24916,7 +25385,7 @@ var ScaffoldArgsType4 = type44({
|
|
|
24916
25385
|
});
|
|
24917
25386
|
function parseScaffoldArgs2(raw) {
|
|
24918
25387
|
const parsed = ScaffoldArgsType4(raw);
|
|
24919
|
-
if (parsed instanceof
|
|
25388
|
+
if (parsed instanceof type45.errors) {
|
|
24920
25389
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
24921
25390
|
}
|
|
24922
25391
|
const useCase = parsed.use_case.trim();
|
|
@@ -25122,11 +25591,11 @@ var actionScaffoldTool = {
|
|
|
25122
25591
|
};
|
|
25123
25592
|
|
|
25124
25593
|
// packages/dbx-components-mcp/src/tools/route-tree.tool.ts
|
|
25125
|
-
import { type as
|
|
25594
|
+
import { type as type46 } from "arktype";
|
|
25126
25595
|
|
|
25127
25596
|
// packages/dbx-components-mcp/src/tools/route/load-sources.ts
|
|
25128
25597
|
import { glob as fsGlob4, readFile as readFile16, stat as stat12 } from "node:fs/promises";
|
|
25129
|
-
import { dirname as
|
|
25598
|
+
import { dirname as dirname8, isAbsolute as isAbsolute8, resolve as resolve28, sep as sep9 } from "node:path";
|
|
25130
25599
|
|
|
25131
25600
|
// packages/dbx-components-mcp/src/tools/route/extract.ts
|
|
25132
25601
|
import { Node as Node19, Project as Project16, SyntaxKind as SyntaxKind12 } from "ts-morph";
|
|
@@ -25441,7 +25910,7 @@ function computeRelativeSpecifiers(source) {
|
|
|
25441
25910
|
// packages/dbx-components-mcp/src/tools/route/load-sources.ts
|
|
25442
25911
|
var TRY_EXTENSIONS = [".ts", ".tsx", "/index.ts", "/index.tsx"];
|
|
25443
25912
|
async function loadRouteSources(args) {
|
|
25444
|
-
const cwdResolved = args.cwd ?
|
|
25913
|
+
const cwdResolved = args.cwd ? resolve28(process.cwd(), args.cwd) : process.cwd();
|
|
25445
25914
|
guardCwdInsideServer(args.cwd, cwdResolved);
|
|
25446
25915
|
const collected = /* @__PURE__ */ new Map();
|
|
25447
25916
|
if (args.sources) {
|
|
@@ -25513,7 +25982,7 @@ async function loadOne(relative17, cwd, into) {
|
|
|
25513
25982
|
if (into.has(relative17)) {
|
|
25514
25983
|
return;
|
|
25515
25984
|
}
|
|
25516
|
-
const absolute =
|
|
25985
|
+
const absolute = resolve28(cwd, relative17);
|
|
25517
25986
|
const cwdPrefix = cwd.endsWith(sep9) ? cwd : cwd + sep9;
|
|
25518
25987
|
if (!absolute.startsWith(cwdPrefix) && absolute !== cwd) {
|
|
25519
25988
|
throw new Error(`Path \`${relative17}\` resolves outside the server cwd and is not allowed.`);
|
|
@@ -25525,9 +25994,9 @@ async function resolveRelativeImport(fromFile, specifier, cwd) {
|
|
|
25525
25994
|
if (!specifier.startsWith(".")) {
|
|
25526
25995
|
return void 0;
|
|
25527
25996
|
}
|
|
25528
|
-
const fromAbsolute =
|
|
25529
|
-
const fromDir =
|
|
25530
|
-
const baseAbsolute =
|
|
25997
|
+
const fromAbsolute = isAbsolute8(fromFile) ? fromFile : resolve28(cwd, fromFile);
|
|
25998
|
+
const fromDir = dirname8(fromAbsolute);
|
|
25999
|
+
const baseAbsolute = resolve28(fromDir, specifier);
|
|
25531
26000
|
const cwdPrefix = cwd.endsWith(sep9) ? cwd : cwd + sep9;
|
|
25532
26001
|
for (const ext of TRY_EXTENSIONS) {
|
|
25533
26002
|
const candidateAbsolute = baseAbsolute + ext;
|
|
@@ -25906,8 +26375,8 @@ var DBX_ROUTE_TREE_TOOL = {
|
|
|
25906
26375
|
}
|
|
25907
26376
|
}
|
|
25908
26377
|
};
|
|
25909
|
-
var TreeArgsType2 =
|
|
25910
|
-
"sources?":
|
|
26378
|
+
var TreeArgsType2 = type46({
|
|
26379
|
+
"sources?": type46({ name: "string", text: "string" }).array(),
|
|
25911
26380
|
"paths?": "string[]",
|
|
25912
26381
|
"glob?": "string",
|
|
25913
26382
|
"format?": "'markdown' | 'json' | 'flat'",
|
|
@@ -25916,7 +26385,7 @@ var TreeArgsType2 = type45({
|
|
|
25916
26385
|
});
|
|
25917
26386
|
function parseArgs4(raw) {
|
|
25918
26387
|
const parsed = TreeArgsType2(raw);
|
|
25919
|
-
if (parsed instanceof
|
|
26388
|
+
if (parsed instanceof type46.errors) {
|
|
25920
26389
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
25921
26390
|
}
|
|
25922
26391
|
const result = {
|
|
@@ -25966,7 +26435,7 @@ var routeTreeTool = {
|
|
|
25966
26435
|
};
|
|
25967
26436
|
|
|
25968
26437
|
// packages/dbx-components-mcp/src/tools/route-lookup.tool.ts
|
|
25969
|
-
import { type as
|
|
26438
|
+
import { type as type47 } from "arktype";
|
|
25970
26439
|
var DBX_ROUTE_LOOKUP_TOOL = {
|
|
25971
26440
|
name: "dbx_route_lookup",
|
|
25972
26441
|
description: ["Look up a single UIRouter state by name, full URL, or component class name. Returns the state's URL, component, parent chain, params, resolves, siblings, and children.", "", "Provide at least one of `sources` / `paths` / `glob` to point the tool at the source set, plus a `topic`.", "", "Resolution order: exact state name \u2192 URL path \u2192 component class name \u2192 fuzzy substring (returns up to 5 candidates)."].join("\n"),
|
|
@@ -25991,9 +26460,9 @@ var DBX_ROUTE_LOOKUP_TOOL = {
|
|
|
25991
26460
|
required: ["topic"]
|
|
25992
26461
|
}
|
|
25993
26462
|
};
|
|
25994
|
-
var LookupArgsType3 =
|
|
26463
|
+
var LookupArgsType3 = type47({
|
|
25995
26464
|
topic: "string",
|
|
25996
|
-
"sources?":
|
|
26465
|
+
"sources?": type47({ name: "string", text: "string" }).array(),
|
|
25997
26466
|
"paths?": "string[]",
|
|
25998
26467
|
"glob?": "string",
|
|
25999
26468
|
"depth?": "'brief' | 'full'",
|
|
@@ -26001,7 +26470,7 @@ var LookupArgsType3 = type46({
|
|
|
26001
26470
|
});
|
|
26002
26471
|
function parseArgs5(raw) {
|
|
26003
26472
|
const parsed = LookupArgsType3(raw);
|
|
26004
|
-
if (parsed instanceof
|
|
26473
|
+
if (parsed instanceof type47.errors) {
|
|
26005
26474
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
26006
26475
|
}
|
|
26007
26476
|
const result = {
|
|
@@ -26194,7 +26663,7 @@ var routeLookupTool = {
|
|
|
26194
26663
|
};
|
|
26195
26664
|
|
|
26196
26665
|
// packages/dbx-components-mcp/src/tools/route-search.tool.ts
|
|
26197
|
-
import { type as
|
|
26666
|
+
import { type as type48 } from "arktype";
|
|
26198
26667
|
var DBX_ROUTE_SEARCH_TOOL = {
|
|
26199
26668
|
name: "dbx_route_search",
|
|
26200
26669
|
description: ["Search the UIRouter state tree of a dbx-components app. Matches against state names, full URLs, component class names, resolve keys, and source-file paths. Returns the top 10 results with state name, URL, component, and source location.", "", "Provide at least one of `sources` / `paths` / `glob` plus a `query`. `scope` narrows to a single axis (`name`, `url`, `component`, `resolve`)."].join("\n"),
|
|
@@ -26218,9 +26687,9 @@ var DBX_ROUTE_SEARCH_TOOL = {
|
|
|
26218
26687
|
required: ["query"]
|
|
26219
26688
|
}
|
|
26220
26689
|
};
|
|
26221
|
-
var SearchArgsType3 =
|
|
26690
|
+
var SearchArgsType3 = type48({
|
|
26222
26691
|
query: "string",
|
|
26223
|
-
"sources?":
|
|
26692
|
+
"sources?": type48({ name: "string", text: "string" }).array(),
|
|
26224
26693
|
"paths?": "string[]",
|
|
26225
26694
|
"glob?": "string",
|
|
26226
26695
|
"scope?": "'name' | 'url' | 'component' | 'resolve' | 'all'",
|
|
@@ -26228,7 +26697,7 @@ var SearchArgsType3 = type47({
|
|
|
26228
26697
|
});
|
|
26229
26698
|
function parseArgs6(raw) {
|
|
26230
26699
|
const parsed = SearchArgsType3(raw);
|
|
26231
|
-
if (parsed instanceof
|
|
26700
|
+
if (parsed instanceof type48.errors) {
|
|
26232
26701
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
26233
26702
|
}
|
|
26234
26703
|
const result = {
|
|
@@ -26321,14 +26790,14 @@ var routeSearchTool = {
|
|
|
26321
26790
|
};
|
|
26322
26791
|
|
|
26323
26792
|
// packages/dbx-components-mcp/src/tools/_lookup.factory.ts
|
|
26324
|
-
import { type as
|
|
26325
|
-
var LOOKUP_ARGS_TYPE =
|
|
26793
|
+
import { type as type49 } from "arktype";
|
|
26794
|
+
var LOOKUP_ARGS_TYPE = type49({
|
|
26326
26795
|
topic: "string",
|
|
26327
26796
|
"depth?": "'brief' | 'full'"
|
|
26328
26797
|
});
|
|
26329
26798
|
function parseLookupArgs(raw) {
|
|
26330
26799
|
const parsed = LOOKUP_ARGS_TYPE(raw);
|
|
26331
|
-
if (parsed instanceof
|
|
26800
|
+
if (parsed instanceof type49.errors) {
|
|
26332
26801
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
26333
26802
|
}
|
|
26334
26803
|
const result = {
|
|
@@ -26530,7 +26999,7 @@ function createLookupFilterTool(input) {
|
|
|
26530
26999
|
}
|
|
26531
27000
|
|
|
26532
27001
|
// packages/dbx-components-mcp/src/tools/filter-scaffold.tool.ts
|
|
26533
|
-
import { type as
|
|
27002
|
+
import { type as type50 } from "arktype";
|
|
26534
27003
|
var DBX_FILTER_SCAFFOLD_TOOL = {
|
|
26535
27004
|
name: "dbx_filter_scaffold",
|
|
26536
27005
|
description: [
|
|
@@ -26555,7 +27024,7 @@ var DBX_FILTER_SCAFFOLD_TOOL = {
|
|
|
26555
27024
|
required: ["model_name", "filter_type"]
|
|
26556
27025
|
}
|
|
26557
27026
|
};
|
|
26558
|
-
var ScaffoldArgsType5 =
|
|
27027
|
+
var ScaffoldArgsType5 = type50({
|
|
26559
27028
|
model_name: "string",
|
|
26560
27029
|
filter_type: "string",
|
|
26561
27030
|
"preset_keys?": "string[]",
|
|
@@ -26563,7 +27032,7 @@ var ScaffoldArgsType5 = type49({
|
|
|
26563
27032
|
});
|
|
26564
27033
|
function parseArgs7(raw) {
|
|
26565
27034
|
const parsed = ScaffoldArgsType5(raw);
|
|
26566
|
-
if (parsed instanceof
|
|
27035
|
+
if (parsed instanceof type50.errors) {
|
|
26567
27036
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
26568
27037
|
}
|
|
26569
27038
|
const modelName = parsed.model_name.trim();
|
|
@@ -26803,8 +27272,8 @@ function createLookupPipeTool(input) {
|
|
|
26803
27272
|
|
|
26804
27273
|
// packages/dbx-components-mcp/src/tools/artifact-scaffold.tool.ts
|
|
26805
27274
|
import { access } from "node:fs/promises";
|
|
26806
|
-
import { resolve as
|
|
26807
|
-
import { type as
|
|
27275
|
+
import { resolve as resolve29, sep as sep10 } from "node:path";
|
|
27276
|
+
import { type as type51 } from "arktype";
|
|
26808
27277
|
|
|
26809
27278
|
// packages/dbx-components-mcp/src/tools/artifact-scaffold/templates.ts
|
|
26810
27279
|
function splitWords(input) {
|
|
@@ -27352,7 +27821,7 @@ var DBX_ARTIFACT_SCAFFOLD_TOOL = {
|
|
|
27352
27821
|
required: ["artifact", "name", "componentDir", "apiDir"]
|
|
27353
27822
|
}
|
|
27354
27823
|
};
|
|
27355
|
-
var ScaffoldArtifactArgsType =
|
|
27824
|
+
var ScaffoldArtifactArgsType = type51({
|
|
27356
27825
|
artifact: ARTIFACT_KIND_LITERAL_UNION,
|
|
27357
27826
|
name: "string",
|
|
27358
27827
|
componentDir: "string",
|
|
@@ -27365,7 +27834,7 @@ var ScaffoldArtifactArgsType = type50({
|
|
|
27365
27834
|
});
|
|
27366
27835
|
function parseArgs8(raw) {
|
|
27367
27836
|
const parsed = ScaffoldArtifactArgsType(raw);
|
|
27368
|
-
if (parsed instanceof
|
|
27837
|
+
if (parsed instanceof type51.errors) {
|
|
27369
27838
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
27370
27839
|
}
|
|
27371
27840
|
const result = {
|
|
@@ -27378,7 +27847,7 @@ function parseArgs8(raw) {
|
|
|
27378
27847
|
return result;
|
|
27379
27848
|
}
|
|
27380
27849
|
function ensureInsideCwd(relativePath, cwd) {
|
|
27381
|
-
const absolute =
|
|
27850
|
+
const absolute = resolve29(cwd, relativePath);
|
|
27382
27851
|
const cwdPrefix = cwd.endsWith(sep10) ? cwd : cwd + sep10;
|
|
27383
27852
|
if (!absolute.startsWith(cwdPrefix) && absolute !== cwd) {
|
|
27384
27853
|
throw new Error(`Path \`${relativePath}\` resolves outside the server cwd and is not allowed.`);
|
|
@@ -27418,7 +27887,7 @@ async function runArtifactScaffold(rawArgs) {
|
|
|
27418
27887
|
const message = err instanceof Error ? err.message : String(err);
|
|
27419
27888
|
return toolError(`Scaffold failed: ${message}`);
|
|
27420
27889
|
}
|
|
27421
|
-
const checked = await applyIdempotency(raw, (relativePath) => fileExists2(
|
|
27890
|
+
const checked = await applyIdempotency(raw, (relativePath) => fileExists2(resolve29(cwd, relativePath)));
|
|
27422
27891
|
const text = formatResult9(checked);
|
|
27423
27892
|
const result = {
|
|
27424
27893
|
content: [{ type: "text", text }]
|
|
@@ -27431,7 +27900,7 @@ var artifactScaffoldTool = {
|
|
|
27431
27900
|
};
|
|
27432
27901
|
|
|
27433
27902
|
// packages/dbx-components-mcp/src/tools/artifact-file-convention.tool.ts
|
|
27434
|
-
import { type as
|
|
27903
|
+
import { type as type52 } from "arktype";
|
|
27435
27904
|
|
|
27436
27905
|
// packages/dbx-components-mcp/src/tools/artifact-file-convention/spec.ts
|
|
27437
27906
|
var FIRESTORE_MODEL = {
|
|
@@ -27867,7 +28336,7 @@ var DBX_ARTIFACT_FILE_CONVENTION_TOOL = {
|
|
|
27867
28336
|
required: ["artifact"]
|
|
27868
28337
|
}
|
|
27869
28338
|
};
|
|
27870
|
-
var FileConventionArgsType =
|
|
28339
|
+
var FileConventionArgsType = type52({
|
|
27871
28340
|
artifact: ARTIFACT_KIND_LITERAL_UNION2,
|
|
27872
28341
|
"componentDir?": "string",
|
|
27873
28342
|
"apiDir?": "string",
|
|
@@ -27875,7 +28344,7 @@ var FileConventionArgsType = type51({
|
|
|
27875
28344
|
});
|
|
27876
28345
|
function parseArgs9(raw) {
|
|
27877
28346
|
const parsed = FileConventionArgsType(raw);
|
|
27878
|
-
if (parsed instanceof
|
|
28347
|
+
if (parsed instanceof type52.errors) {
|
|
27879
28348
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
27880
28349
|
}
|
|
27881
28350
|
const result = {
|
|
@@ -27908,8 +28377,8 @@ var artifactFileConventionTool = {
|
|
|
27908
28377
|
};
|
|
27909
28378
|
|
|
27910
28379
|
// packages/dbx-components-mcp/src/tools/explain-rule.tool.ts
|
|
27911
|
-
import { type as
|
|
27912
|
-
var ExplainRuleArgsType =
|
|
28380
|
+
import { type as type53 } from "arktype";
|
|
28381
|
+
var ExplainRuleArgsType = type53({
|
|
27913
28382
|
code: "string",
|
|
27914
28383
|
"format?": "'markdown' | 'json'"
|
|
27915
28384
|
});
|
|
@@ -27938,7 +28407,7 @@ var TOOL11 = {
|
|
|
27938
28407
|
};
|
|
27939
28408
|
async function run10(rawArgs) {
|
|
27940
28409
|
const parsed = ExplainRuleArgsType(rawArgs);
|
|
27941
|
-
if (parsed instanceof
|
|
28410
|
+
if (parsed instanceof type53.errors) {
|
|
27942
28411
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
27943
28412
|
}
|
|
27944
28413
|
const exact = findRule(parsed.code);
|
|
@@ -27963,11 +28432,11 @@ async function run10(rawArgs) {
|
|
|
27963
28432
|
var explainRuleTool = { definition: TOOL11, run: run10 };
|
|
27964
28433
|
|
|
27965
28434
|
// packages/dbx-components-mcp/src/tools/app-validate.tool.ts
|
|
27966
|
-
import { resolve as
|
|
28435
|
+
import { resolve as resolve30, join as join15 } from "node:path";
|
|
27967
28436
|
import { readdir as readdir10, stat as stat13 } from "node:fs/promises";
|
|
27968
|
-
import { type as
|
|
28437
|
+
import { type as type54 } from "arktype";
|
|
27969
28438
|
var Cluster = "'storagefile_m' | 'notification_m' | 'model_folder' | 'system_m' | 'fixture'";
|
|
27970
|
-
var AppValidateArgsType =
|
|
28439
|
+
var AppValidateArgsType = type54({
|
|
27971
28440
|
componentDir: "string",
|
|
27972
28441
|
apiDir: "string",
|
|
27973
28442
|
"format?": "'markdown' | 'json'",
|
|
@@ -28007,7 +28476,7 @@ var TOOL12 = {
|
|
|
28007
28476
|
};
|
|
28008
28477
|
async function run11(rawArgs) {
|
|
28009
28478
|
const parsed = AppValidateArgsType(rawArgs);
|
|
28010
|
-
if (parsed instanceof
|
|
28479
|
+
if (parsed instanceof type54.errors) {
|
|
28011
28480
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
28012
28481
|
}
|
|
28013
28482
|
const cwd = process.cwd();
|
|
@@ -28017,8 +28486,8 @@ async function run11(rawArgs) {
|
|
|
28017
28486
|
} catch (err) {
|
|
28018
28487
|
return toolError(err instanceof Error ? err.message : String(err));
|
|
28019
28488
|
}
|
|
28020
|
-
const componentAbs =
|
|
28021
|
-
const apiAbs =
|
|
28489
|
+
const componentAbs = resolve30(cwd, parsed.componentDir);
|
|
28490
|
+
const apiAbs = resolve30(cwd, parsed.apiDir);
|
|
28022
28491
|
const skip = new Set(parsed.skip ?? []);
|
|
28023
28492
|
const findings = [];
|
|
28024
28493
|
const skipped = [];
|
|
@@ -28216,8 +28685,8 @@ function formatJson(report) {
|
|
|
28216
28685
|
var appValidateTool = { definition: TOOL12, run: run11 };
|
|
28217
28686
|
|
|
28218
28687
|
// packages/dbx-components-mcp/src/tools/model-list-component.tool.ts
|
|
28219
|
-
import { resolve as
|
|
28220
|
-
import { type as
|
|
28688
|
+
import { resolve as resolve31 } from "node:path";
|
|
28689
|
+
import { type as type55 } from "arktype";
|
|
28221
28690
|
|
|
28222
28691
|
// packages/dbx-components-mcp/src/tools/model-list-component/extract.ts
|
|
28223
28692
|
import { readdir as readdir11, readFile as readFile17, stat as stat14 } from "node:fs/promises";
|
|
@@ -28485,7 +28954,7 @@ function stripCoverage(model) {
|
|
|
28485
28954
|
}
|
|
28486
28955
|
|
|
28487
28956
|
// packages/dbx-components-mcp/src/tools/model-list-component.tool.ts
|
|
28488
|
-
var ListArgsType3 =
|
|
28957
|
+
var ListArgsType3 = type55({
|
|
28489
28958
|
componentDir: "string",
|
|
28490
28959
|
"apiDir?": "string",
|
|
28491
28960
|
"format?": "'markdown' | 'json'"
|
|
@@ -28516,7 +28985,7 @@ var TOOL13 = {
|
|
|
28516
28985
|
};
|
|
28517
28986
|
async function run12(rawArgs) {
|
|
28518
28987
|
const parsed = ListArgsType3(rawArgs);
|
|
28519
|
-
if (parsed instanceof
|
|
28988
|
+
if (parsed instanceof type55.errors) {
|
|
28520
28989
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
28521
28990
|
}
|
|
28522
28991
|
const cwd = process.cwd();
|
|
@@ -28526,8 +28995,8 @@ async function run12(rawArgs) {
|
|
|
28526
28995
|
} catch (err) {
|
|
28527
28996
|
return toolError(err instanceof Error ? err.message : String(err));
|
|
28528
28997
|
}
|
|
28529
|
-
const componentAbs =
|
|
28530
|
-
const apiAbs = parsed.apiDir ?
|
|
28998
|
+
const componentAbs = resolve31(cwd, parsed.componentDir);
|
|
28999
|
+
const apiAbs = parsed.apiDir ? resolve31(cwd, parsed.apiDir) : void 0;
|
|
28531
29000
|
let report;
|
|
28532
29001
|
try {
|
|
28533
29002
|
report = await listComponentModels(componentAbs, { componentDir: parsed.componentDir, apiDir: parsed.apiDir, apiAbs });
|
|
@@ -28541,12 +29010,12 @@ async function run12(rawArgs) {
|
|
|
28541
29010
|
var modelListComponentTool = { definition: TOOL13, run: run12 };
|
|
28542
29011
|
|
|
28543
29012
|
// packages/dbx-components-mcp/src/tools/server-actions-list-app.tool.ts
|
|
28544
|
-
import { resolve as
|
|
28545
|
-
import { type as
|
|
29013
|
+
import { resolve as resolve32 } from "node:path";
|
|
29014
|
+
import { type as type56 } from "arktype";
|
|
28546
29015
|
|
|
28547
29016
|
// packages/dbx-components-mcp/src/tools/server-actions-list-app/extract.ts
|
|
28548
29017
|
import { readdir as readdir12, readFile as readFile18, stat as stat15 } from "node:fs/promises";
|
|
28549
|
-
import { dirname as
|
|
29018
|
+
import { dirname as dirname9, join as join17, relative as relative11, sep as sep12 } from "node:path";
|
|
28550
29019
|
import { Node as Node21, Project as Project18 } from "ts-morph";
|
|
28551
29020
|
var ACTION_SERVER_SUFFIX2 = ".action.server.ts";
|
|
28552
29021
|
var COMMON_MODEL_SUBPATH2 = "src/app/common/model";
|
|
@@ -28654,7 +29123,7 @@ async function inspectSiblingModule(actionFilePath, className) {
|
|
|
28654
29123
|
return { modulePath: moduleCandidates[0], providedByModule: false, exportedByModule: false };
|
|
28655
29124
|
}
|
|
28656
29125
|
async function findModuleCandidates(actionFilePath) {
|
|
28657
|
-
const dir =
|
|
29126
|
+
const dir = dirname9(actionFilePath);
|
|
28658
29127
|
const out = [];
|
|
28659
29128
|
try {
|
|
28660
29129
|
const entries = await readdir12(dir, { withFileTypes: true });
|
|
@@ -28841,7 +29310,7 @@ async function listAppServerActions(apiAbs, options) {
|
|
|
28841
29310
|
}
|
|
28842
29311
|
|
|
28843
29312
|
// packages/dbx-components-mcp/src/tools/server-actions-list-app.tool.ts
|
|
28844
|
-
var ListArgsType4 =
|
|
29313
|
+
var ListArgsType4 = type56({
|
|
28845
29314
|
apiDir: "string",
|
|
28846
29315
|
"format?": "'markdown' | 'json'"
|
|
28847
29316
|
});
|
|
@@ -28870,7 +29339,7 @@ var TOOL14 = {
|
|
|
28870
29339
|
};
|
|
28871
29340
|
async function run13(rawArgs) {
|
|
28872
29341
|
const parsed = ListArgsType4(rawArgs);
|
|
28873
|
-
if (parsed instanceof
|
|
29342
|
+
if (parsed instanceof type56.errors) {
|
|
28874
29343
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
28875
29344
|
}
|
|
28876
29345
|
const cwd = process.cwd();
|
|
@@ -28879,7 +29348,7 @@ async function run13(rawArgs) {
|
|
|
28879
29348
|
} catch (err) {
|
|
28880
29349
|
return toolError(err instanceof Error ? err.message : String(err));
|
|
28881
29350
|
}
|
|
28882
|
-
const apiAbs =
|
|
29351
|
+
const apiAbs = resolve32(cwd, parsed.apiDir);
|
|
28883
29352
|
let report;
|
|
28884
29353
|
try {
|
|
28885
29354
|
report = await listAppServerActions(apiAbs, { apiDir: parsed.apiDir });
|
|
@@ -28893,16 +29362,16 @@ async function run13(rawArgs) {
|
|
|
28893
29362
|
var serverActionsListAppTool = { definition: TOOL14, run: run13 };
|
|
28894
29363
|
|
|
28895
29364
|
// packages/dbx-components-mcp/src/tools/mcp-config.tool.ts
|
|
28896
|
-
import { type as
|
|
28897
|
-
import { resolve as
|
|
29365
|
+
import { type as type63 } from "arktype";
|
|
29366
|
+
import { resolve as resolve39 } from "node:path";
|
|
28898
29367
|
|
|
28899
29368
|
// packages/dbx-components-mcp/src/tools/mcp-config/snapshot.ts
|
|
28900
|
-
import { dirname as
|
|
29369
|
+
import { dirname as dirname10, isAbsolute as isAbsolute9, relative as relative12, resolve as resolve34 } from "node:path";
|
|
28901
29370
|
import { stat as stat17 } from "node:fs/promises";
|
|
28902
29371
|
|
|
28903
29372
|
// packages/dbx-components-mcp/src/scan/discover-downstream-packages.ts
|
|
28904
29373
|
import { glob as fsGlob5, readFile as readFile19, stat as stat16 } from "node:fs/promises";
|
|
28905
|
-
import { basename as basename7, join as join18, resolve as
|
|
29374
|
+
import { basename as basename7, join as join18, resolve as resolve33, sep as sep13 } from "node:path";
|
|
28906
29375
|
var COMPONENT_GLOBS = ["components/*-firebase", "components/*-shared", "components/*-web", "components/*-core"];
|
|
28907
29376
|
var APPS_GLOB = "apps/*";
|
|
28908
29377
|
var SCAN_CONFIG_FILENAME2 = "dbx-mcp.scan.json";
|
|
@@ -28947,7 +29416,7 @@ function normaliseExplicitDirs(dirs) {
|
|
|
28947
29416
|
return result;
|
|
28948
29417
|
}
|
|
28949
29418
|
async function inspectPackage2(workspaceRoot, relDir) {
|
|
28950
|
-
const absDir =
|
|
29419
|
+
const absDir = resolve33(workspaceRoot, relDir);
|
|
28951
29420
|
const isDir = await isDirectory2(absDir);
|
|
28952
29421
|
if (!isDir) return void 0;
|
|
28953
29422
|
const packageName = await readPackageName2(absDir, relDir);
|
|
@@ -29053,7 +29522,7 @@ function mergeClusters(...lists) {
|
|
|
29053
29522
|
async function buildSnapshot(input) {
|
|
29054
29523
|
const { workspaceRoot, explicitDirs } = input;
|
|
29055
29524
|
const configResult = await findAndLoadConfig({ cwd: workspaceRoot });
|
|
29056
|
-
const configBaseDir = configResult.configPath !== null ?
|
|
29525
|
+
const configBaseDir = configResult.configPath !== null ? dirname10(configResult.configPath) : workspaceRoot;
|
|
29057
29526
|
const registeredSources = await collectRegisteredSources(configResult.config, configBaseDir, workspaceRoot);
|
|
29058
29527
|
const packages = await discoverDownstreamPackages({ workspaceRoot, explicitDirs });
|
|
29059
29528
|
const packageSnapshots = packages.map((pkg) => ({
|
|
@@ -29075,7 +29544,7 @@ async function collectRegisteredSources(config, configBaseDir, workspaceRoot) {
|
|
|
29075
29544
|
for (const cluster of DOWNSTREAM_CLUSTERS) {
|
|
29076
29545
|
const declared = config[cluster]?.sources ?? [];
|
|
29077
29546
|
for (const declaredPath of declared) {
|
|
29078
|
-
const absolutePath =
|
|
29547
|
+
const absolutePath = isAbsolute9(declaredPath) ? declaredPath : resolve34(configBaseDir, declaredPath);
|
|
29079
29548
|
const exists = await fileExists4(absolutePath);
|
|
29080
29549
|
const relativePath = relativeOrAbsolute(workspaceRoot, absolutePath);
|
|
29081
29550
|
out.push({ cluster, declaredPath, absolutePath, relativePath, exists });
|
|
@@ -29113,8 +29582,19 @@ function relativeOrAbsolute(from, target) {
|
|
|
29113
29582
|
|
|
29114
29583
|
// packages/dbx-components-mcp/src/tools/mcp-config/init.ts
|
|
29115
29584
|
import { writeFile as nodeWriteFile3, mkdir as nodeMkdir, readFile as nodeReadFile7 } from "node:fs/promises";
|
|
29116
|
-
import { dirname as
|
|
29585
|
+
import { dirname as dirname11, relative as relative13, resolve as resolve35 } from "node:path";
|
|
29117
29586
|
var HEURISTIC_CLUSTERS = ["uiComponents", "forgeFields", "pipes", "actions", "filters"];
|
|
29587
|
+
var CLUSTER_FILENAME_SEGMENT = {
|
|
29588
|
+
semanticTypes: "semantic",
|
|
29589
|
+
uiComponents: "ui",
|
|
29590
|
+
forgeFields: "forge",
|
|
29591
|
+
pipes: "pipes",
|
|
29592
|
+
actions: "actions",
|
|
29593
|
+
filters: "filters"
|
|
29594
|
+
};
|
|
29595
|
+
function clusterFilenameSegment(cluster) {
|
|
29596
|
+
return CLUSTER_FILENAME_SEGMENT[cluster];
|
|
29597
|
+
}
|
|
29118
29598
|
var DEFAULT_INCLUDE = ["src/**/*.ts"];
|
|
29119
29599
|
var DEFAULT_EXCLUDE = ["**/*.spec.ts", "**/*.test.ts", "**/*.stories.ts"];
|
|
29120
29600
|
async function buildInitPlan(input) {
|
|
@@ -29136,14 +29616,14 @@ async function applyInitPlan(plan, opts) {
|
|
|
29136
29616
|
const mkdir = opts?.mkdir ?? defaultMkdir;
|
|
29137
29617
|
for (const change of plan.changes) {
|
|
29138
29618
|
if (change.reason === "unchanged") continue;
|
|
29139
|
-
await mkdir(
|
|
29619
|
+
await mkdir(dirname11(change.absolutePath));
|
|
29140
29620
|
await writeFile2(change.absolutePath, change.after);
|
|
29141
29621
|
}
|
|
29142
29622
|
}
|
|
29143
29623
|
async function planPackageScanConfig(input) {
|
|
29144
29624
|
const { snapshot, packageSnapshot, readFile: readFile20 } = input;
|
|
29145
29625
|
const { pkg } = packageSnapshot;
|
|
29146
|
-
const scanConfigPath =
|
|
29626
|
+
const scanConfigPath = resolve35(pkg.absDir, "dbx-mcp.scan.json");
|
|
29147
29627
|
const before = await tryRead(scanConfigPath, readFile20);
|
|
29148
29628
|
const parsed = parseExisting(before);
|
|
29149
29629
|
const targetClusters = HEURISTIC_CLUSTERS.filter((c) => pkg.candidateClusters.includes(c));
|
|
@@ -29154,7 +29634,7 @@ async function planPackageScanConfig(input) {
|
|
|
29154
29634
|
if (next.version !== 1) next.version = 1;
|
|
29155
29635
|
const sourcesToRegister = [];
|
|
29156
29636
|
if (typeof next.topicNamespace === "string" && Array.isArray(next.include)) {
|
|
29157
|
-
const outValue = typeof next.out === "string" && next.out.length > 0 ? next.out : `${pkg.slug}.
|
|
29637
|
+
const outValue = typeof next.out === "string" && next.out.length > 0 ? next.out : `${pkg.slug}.${clusterFilenameSegment("semanticTypes")}.json`;
|
|
29158
29638
|
const declaredOut = resolveScanOut(scanConfigPath, outValue);
|
|
29159
29639
|
sourcesToRegister.push({ cluster: "semanticTypes", relPath: relativeFromConfig(snapshot, declaredOut) });
|
|
29160
29640
|
}
|
|
@@ -29187,7 +29667,7 @@ async function planPackageScanConfig(input) {
|
|
|
29187
29667
|
}
|
|
29188
29668
|
async function planRootConfig(input) {
|
|
29189
29669
|
const { snapshot, sourcesToRegister, readFile: readFile20 } = input;
|
|
29190
|
-
const configPath = snapshot.configPath ??
|
|
29670
|
+
const configPath = snapshot.configPath ?? resolve35(snapshot.workspaceRoot, "dbx-mcp.config.json");
|
|
29191
29671
|
const before = snapshot.configPath !== null ? await tryRead(configPath, readFile20) : null;
|
|
29192
29672
|
const baseConfig = snapshot.config !== null ? cloneConfig(snapshot.config) : { version: 1 };
|
|
29193
29673
|
if (baseConfig.version !== 1) baseConfig.version = 1;
|
|
@@ -29216,14 +29696,14 @@ async function planRootConfig(input) {
|
|
|
29216
29696
|
};
|
|
29217
29697
|
}
|
|
29218
29698
|
function defaultOutFor(input) {
|
|
29219
|
-
const targetAbs =
|
|
29220
|
-
return relative13(
|
|
29699
|
+
const targetAbs = resolve35(input.snapshot.workspaceRoot, ".tmp/dbx-mcp", `${input.slug}.${clusterFilenameSegment(input.cluster)}.json`);
|
|
29700
|
+
return relative13(dirname11(input.scanConfigPath), targetAbs).split("\\").join("/");
|
|
29221
29701
|
}
|
|
29222
29702
|
function resolveScanOut(scanConfigPath, out) {
|
|
29223
|
-
return
|
|
29703
|
+
return resolve35(dirname11(scanConfigPath), out);
|
|
29224
29704
|
}
|
|
29225
29705
|
function relativeFromConfig(snapshot, absolute) {
|
|
29226
|
-
const configDir = snapshot.configPath !== null ?
|
|
29706
|
+
const configDir = snapshot.configPath !== null ? dirname11(snapshot.configPath) : snapshot.workspaceRoot;
|
|
29227
29707
|
return relative13(configDir, absolute).split("\\").join("/");
|
|
29228
29708
|
}
|
|
29229
29709
|
function workspaceRel(workspaceRoot, absolute) {
|
|
@@ -29267,8 +29747,8 @@ var defaultMkdir = async (dir) => {
|
|
|
29267
29747
|
};
|
|
29268
29748
|
|
|
29269
29749
|
// packages/dbx-components-mcp/src/scan/actions-build-manifest.ts
|
|
29270
|
-
import { relative as relative14, resolve as
|
|
29271
|
-
import { type as
|
|
29750
|
+
import { relative as relative14, resolve as resolve36 } from "node:path";
|
|
29751
|
+
import { type as type58 } from "arktype";
|
|
29272
29752
|
import { Project as Project19 } from "ts-morph";
|
|
29273
29753
|
|
|
29274
29754
|
// packages/dbx-components-mcp/src/scan/actions-extract.ts
|
|
@@ -29571,15 +30051,15 @@ function readMethodDescription(method) {
|
|
|
29571
30051
|
}
|
|
29572
30052
|
|
|
29573
30053
|
// packages/dbx-components-mcp/src/scan/actions-scan-config-schema.ts
|
|
29574
|
-
import { type as
|
|
29575
|
-
var ActionsScanSection =
|
|
30054
|
+
import { type as type57 } from "arktype";
|
|
30055
|
+
var ActionsScanSection = type57({
|
|
29576
30056
|
"source?": "string",
|
|
29577
30057
|
"module?": "string",
|
|
29578
30058
|
include: "string[] >= 1",
|
|
29579
30059
|
"exclude?": "string[]",
|
|
29580
30060
|
"out?": "string"
|
|
29581
30061
|
});
|
|
29582
|
-
var ActionsScanConfig =
|
|
30062
|
+
var ActionsScanConfig = type57({
|
|
29583
30063
|
version: "1",
|
|
29584
30064
|
actions: ActionsScanSection
|
|
29585
30065
|
});
|
|
@@ -29591,8 +30071,8 @@ var DEFAULT_READ_FILE9 = defaultReadFile;
|
|
|
29591
30071
|
var DEFAULT_GLOBBER4 = defaultGlobber;
|
|
29592
30072
|
async function buildActionsManifest(input) {
|
|
29593
30073
|
const { projectRoot, generator, readFile: readFile20 = DEFAULT_READ_FILE9, globber = DEFAULT_GLOBBER4, now = () => /* @__PURE__ */ new Date() } = input;
|
|
29594
|
-
const configPath =
|
|
29595
|
-
const packagePath =
|
|
30074
|
+
const configPath = resolve36(projectRoot, ACTIONS_SCAN_CONFIG_FILENAME);
|
|
30075
|
+
const packagePath = resolve36(projectRoot, "package.json");
|
|
29596
30076
|
const configOutcome = await loadScanConfig4(configPath, readFile20);
|
|
29597
30077
|
if (configOutcome.kind !== "ok") return configOutcome.outcome;
|
|
29598
30078
|
const scanSection = configOutcome.section;
|
|
@@ -29602,7 +30082,7 @@ async function buildActionsManifest(input) {
|
|
|
29602
30082
|
const filePaths = await globber({ projectRoot, include: scanSection.include, exclude: scanSection.exclude ?? [] });
|
|
29603
30083
|
const project = new Project19({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
|
|
29604
30084
|
for (const relPath of filePaths) {
|
|
29605
|
-
const absolute =
|
|
30085
|
+
const absolute = resolve36(projectRoot, relPath);
|
|
29606
30086
|
const text = await readFile20(absolute);
|
|
29607
30087
|
project.createSourceFile(absolute, text, { overwrite: true });
|
|
29608
30088
|
}
|
|
@@ -29620,10 +30100,10 @@ async function buildActionsManifest(input) {
|
|
|
29620
30100
|
};
|
|
29621
30101
|
const validated = ActionManifest(manifest);
|
|
29622
30102
|
let outcome;
|
|
29623
|
-
if (validated instanceof
|
|
30103
|
+
if (validated instanceof type58.errors) {
|
|
29624
30104
|
outcome = { kind: "invalid-manifest", error: validated.summary };
|
|
29625
30105
|
} else {
|
|
29626
|
-
const outPath =
|
|
30106
|
+
const outPath = resolve36(projectRoot, scanSection.out ?? DEFAULT_ACTIONS_SCAN_OUT_PATH);
|
|
29627
30107
|
outcome = {
|
|
29628
30108
|
kind: "success",
|
|
29629
30109
|
manifest: validated,
|
|
@@ -29654,7 +30134,7 @@ async function loadScanConfig4(configPath, readFile20) {
|
|
|
29654
30134
|
}
|
|
29655
30135
|
if (parseError === null) {
|
|
29656
30136
|
const validated = ActionsScanConfig(parsed);
|
|
29657
|
-
if (validated instanceof
|
|
30137
|
+
if (validated instanceof type58.errors) {
|
|
29658
30138
|
result = { kind: "fail", outcome: { kind: "invalid-scan-config", configPath, error: validated.summary } };
|
|
29659
30139
|
} else {
|
|
29660
30140
|
result = { kind: "ok", section: validated.actions };
|
|
@@ -29785,8 +30265,8 @@ function formatExtractWarning3(warning) {
|
|
|
29785
30265
|
}
|
|
29786
30266
|
|
|
29787
30267
|
// packages/dbx-components-mcp/src/scan/filters-build-manifest.ts
|
|
29788
|
-
import { relative as relative15, resolve as
|
|
29789
|
-
import { type as
|
|
30268
|
+
import { relative as relative15, resolve as resolve37 } from "node:path";
|
|
30269
|
+
import { type as type60 } from "arktype";
|
|
29790
30270
|
import { Project as Project20 } from "ts-morph";
|
|
29791
30271
|
|
|
29792
30272
|
// packages/dbx-components-mcp/src/scan/filters-extract.ts
|
|
@@ -29979,15 +30459,15 @@ function extractOutputs3(decl) {
|
|
|
29979
30459
|
}
|
|
29980
30460
|
|
|
29981
30461
|
// packages/dbx-components-mcp/src/scan/filters-scan-config-schema.ts
|
|
29982
|
-
import { type as
|
|
29983
|
-
var FiltersScanSection =
|
|
30462
|
+
import { type as type59 } from "arktype";
|
|
30463
|
+
var FiltersScanSection = type59({
|
|
29984
30464
|
"source?": "string",
|
|
29985
30465
|
"module?": "string",
|
|
29986
30466
|
include: "string[] >= 1",
|
|
29987
30467
|
"exclude?": "string[]",
|
|
29988
30468
|
"out?": "string"
|
|
29989
30469
|
});
|
|
29990
|
-
var FiltersScanConfig =
|
|
30470
|
+
var FiltersScanConfig = type59({
|
|
29991
30471
|
version: "1",
|
|
29992
30472
|
filters: FiltersScanSection
|
|
29993
30473
|
});
|
|
@@ -29999,8 +30479,8 @@ var DEFAULT_READ_FILE10 = defaultReadFile;
|
|
|
29999
30479
|
var DEFAULT_GLOBBER5 = defaultGlobber;
|
|
30000
30480
|
async function buildFiltersManifest(input) {
|
|
30001
30481
|
const { projectRoot, generator, readFile: readFile20 = DEFAULT_READ_FILE10, globber = DEFAULT_GLOBBER5, now = () => /* @__PURE__ */ new Date() } = input;
|
|
30002
|
-
const configPath =
|
|
30003
|
-
const packagePath =
|
|
30482
|
+
const configPath = resolve37(projectRoot, FILTERS_SCAN_CONFIG_FILENAME);
|
|
30483
|
+
const packagePath = resolve37(projectRoot, "package.json");
|
|
30004
30484
|
const configOutcome = await loadScanConfig5(configPath, readFile20);
|
|
30005
30485
|
if (configOutcome.kind !== "ok") {
|
|
30006
30486
|
return configOutcome.outcome;
|
|
@@ -30018,7 +30498,7 @@ async function buildFiltersManifest(input) {
|
|
|
30018
30498
|
});
|
|
30019
30499
|
const project = new Project20({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
|
|
30020
30500
|
for (const relPath of filePaths) {
|
|
30021
|
-
const absolute =
|
|
30501
|
+
const absolute = resolve37(projectRoot, relPath);
|
|
30022
30502
|
const text = await readFile20(absolute);
|
|
30023
30503
|
project.createSourceFile(absolute, text, { overwrite: true });
|
|
30024
30504
|
}
|
|
@@ -30036,10 +30516,10 @@ async function buildFiltersManifest(input) {
|
|
|
30036
30516
|
};
|
|
30037
30517
|
const validated = FilterManifest(manifest);
|
|
30038
30518
|
let outcome;
|
|
30039
|
-
if (validated instanceof
|
|
30519
|
+
if (validated instanceof type60.errors) {
|
|
30040
30520
|
outcome = { kind: "invalid-manifest", error: validated.summary };
|
|
30041
30521
|
} else {
|
|
30042
|
-
const outPath =
|
|
30522
|
+
const outPath = resolve37(projectRoot, scanSection.out ?? DEFAULT_FILTERS_SCAN_OUT_PATH);
|
|
30043
30523
|
outcome = {
|
|
30044
30524
|
kind: "success",
|
|
30045
30525
|
manifest: validated,
|
|
@@ -30070,7 +30550,7 @@ async function loadScanConfig5(configPath, readFile20) {
|
|
|
30070
30550
|
}
|
|
30071
30551
|
if (parseError === null) {
|
|
30072
30552
|
const validated = FiltersScanConfig(parsed);
|
|
30073
|
-
if (validated instanceof
|
|
30553
|
+
if (validated instanceof type60.errors) {
|
|
30074
30554
|
result = { kind: "fail", outcome: { kind: "invalid-scan-config", configPath, error: validated.summary } };
|
|
30075
30555
|
} else {
|
|
30076
30556
|
result = { kind: "ok", section: validated.filters };
|
|
@@ -30163,8 +30643,8 @@ function formatExtractWarning4(warning) {
|
|
|
30163
30643
|
}
|
|
30164
30644
|
|
|
30165
30645
|
// packages/dbx-components-mcp/src/scan/pipes-build-manifest.ts
|
|
30166
|
-
import { relative as relative16, resolve as
|
|
30167
|
-
import { type as
|
|
30646
|
+
import { relative as relative16, resolve as resolve38 } from "node:path";
|
|
30647
|
+
import { type as type62 } from "arktype";
|
|
30168
30648
|
import { Project as Project21 } from "ts-morph";
|
|
30169
30649
|
|
|
30170
30650
|
// packages/dbx-components-mcp/src/scan/pipes-extract.ts
|
|
@@ -30400,10 +30880,10 @@ function readTransformSignature(method, fallbackParamDescriptions) {
|
|
|
30400
30880
|
for (let i = 1; i < params.length; i += 1) {
|
|
30401
30881
|
const param = params[i];
|
|
30402
30882
|
const name = param.getName();
|
|
30403
|
-
const
|
|
30883
|
+
const type68 = readParamType(param);
|
|
30404
30884
|
const description = methodParamDescriptions.get(name) ?? fallbackParamDescriptions.get(name) ?? "";
|
|
30405
30885
|
const required = !param.isOptional() && !param.hasInitializer();
|
|
30406
|
-
args.push({ name, type:
|
|
30886
|
+
args.push({ name, type: type68, description, required });
|
|
30407
30887
|
}
|
|
30408
30888
|
return { inputType, outputType, args };
|
|
30409
30889
|
}
|
|
@@ -30440,15 +30920,15 @@ function extractParamName(rawTag) {
|
|
|
30440
30920
|
}
|
|
30441
30921
|
|
|
30442
30922
|
// packages/dbx-components-mcp/src/scan/pipes-scan-config-schema.ts
|
|
30443
|
-
import { type as
|
|
30444
|
-
var PipesScanSection =
|
|
30923
|
+
import { type as type61 } from "arktype";
|
|
30924
|
+
var PipesScanSection = type61({
|
|
30445
30925
|
"source?": "string",
|
|
30446
30926
|
"module?": "string",
|
|
30447
30927
|
include: "string[] >= 1",
|
|
30448
30928
|
"exclude?": "string[]",
|
|
30449
30929
|
"out?": "string"
|
|
30450
30930
|
});
|
|
30451
|
-
var PipesScanConfig =
|
|
30931
|
+
var PipesScanConfig = type61({
|
|
30452
30932
|
version: "1",
|
|
30453
30933
|
pipes: PipesScanSection
|
|
30454
30934
|
});
|
|
@@ -30460,8 +30940,8 @@ var DEFAULT_READ_FILE11 = defaultReadFile;
|
|
|
30460
30940
|
var DEFAULT_GLOBBER6 = defaultGlobber;
|
|
30461
30941
|
async function buildPipesManifest(input) {
|
|
30462
30942
|
const { projectRoot, generator, readFile: readFile20 = DEFAULT_READ_FILE11, globber = DEFAULT_GLOBBER6, now = () => /* @__PURE__ */ new Date() } = input;
|
|
30463
|
-
const configPath =
|
|
30464
|
-
const packagePath =
|
|
30943
|
+
const configPath = resolve38(projectRoot, PIPES_SCAN_CONFIG_FILENAME);
|
|
30944
|
+
const packagePath = resolve38(projectRoot, "package.json");
|
|
30465
30945
|
const configOutcome = await loadScanConfig6(configPath, readFile20);
|
|
30466
30946
|
if (configOutcome.kind !== "ok") {
|
|
30467
30947
|
return configOutcome.outcome;
|
|
@@ -30479,7 +30959,7 @@ async function buildPipesManifest(input) {
|
|
|
30479
30959
|
});
|
|
30480
30960
|
const project = new Project21({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
|
|
30481
30961
|
for (const relPath of filePaths) {
|
|
30482
|
-
const absolute =
|
|
30962
|
+
const absolute = resolve38(projectRoot, relPath);
|
|
30483
30963
|
const text = await readFile20(absolute);
|
|
30484
30964
|
project.createSourceFile(absolute, text, { overwrite: true });
|
|
30485
30965
|
}
|
|
@@ -30497,10 +30977,10 @@ async function buildPipesManifest(input) {
|
|
|
30497
30977
|
};
|
|
30498
30978
|
const validated = PipeManifest(manifest);
|
|
30499
30979
|
let outcome;
|
|
30500
|
-
if (validated instanceof
|
|
30980
|
+
if (validated instanceof type62.errors) {
|
|
30501
30981
|
outcome = { kind: "invalid-manifest", error: validated.summary };
|
|
30502
30982
|
} else {
|
|
30503
|
-
const outPath =
|
|
30983
|
+
const outPath = resolve38(projectRoot, scanSection.out ?? DEFAULT_PIPES_SCAN_OUT_PATH);
|
|
30504
30984
|
outcome = {
|
|
30505
30985
|
kind: "success",
|
|
30506
30986
|
manifest: validated,
|
|
@@ -30531,7 +31011,7 @@ async function loadScanConfig6(configPath, readFile20) {
|
|
|
30531
31011
|
}
|
|
30532
31012
|
if (parseError === null) {
|
|
30533
31013
|
const validated = PipesScanConfig(parsed);
|
|
30534
|
-
if (validated instanceof
|
|
31014
|
+
if (validated instanceof type62.errors) {
|
|
30535
31015
|
result = { kind: "fail", outcome: { kind: "invalid-scan-config", configPath, error: validated.summary } };
|
|
30536
31016
|
} else {
|
|
30537
31017
|
result = { kind: "ok", section: validated.pipes };
|
|
@@ -30880,7 +31360,7 @@ var TOOL15 = {
|
|
|
30880
31360
|
required: ["op"]
|
|
30881
31361
|
}
|
|
30882
31362
|
};
|
|
30883
|
-
var McpConfigArgsType =
|
|
31363
|
+
var McpConfigArgsType = type63({
|
|
30884
31364
|
op: "'status' | 'validate' | 'init' | 'refresh'",
|
|
30885
31365
|
"cwd?": "string",
|
|
30886
31366
|
"dryRun?": "boolean",
|
|
@@ -30888,12 +31368,12 @@ var McpConfigArgsType = type62({
|
|
|
30888
31368
|
});
|
|
30889
31369
|
function parseArgs10(rawArgs, defaultCwd) {
|
|
30890
31370
|
const parsed = McpConfigArgsType(rawArgs);
|
|
30891
|
-
if (parsed instanceof
|
|
31371
|
+
if (parsed instanceof type63.errors) {
|
|
30892
31372
|
return `Invalid arguments: ${parsed.summary}`;
|
|
30893
31373
|
}
|
|
30894
31374
|
let workspaceRoot = defaultCwd;
|
|
30895
31375
|
if (parsed.cwd !== void 0 && parsed.cwd.length > 0) {
|
|
30896
|
-
workspaceRoot =
|
|
31376
|
+
workspaceRoot = resolve39(defaultCwd, parsed.cwd);
|
|
30897
31377
|
}
|
|
30898
31378
|
if (parsed.explicitDirs !== void 0) {
|
|
30899
31379
|
for (const dir of parsed.explicitDirs) {
|
|
@@ -30945,7 +31425,7 @@ var mcpConfigTool = {
|
|
|
30945
31425
|
};
|
|
30946
31426
|
|
|
30947
31427
|
// packages/dbx-components-mcp/src/tools/lookup-semantic-type.tool.ts
|
|
30948
|
-
import { type as
|
|
31428
|
+
import { type as type64 } from "arktype";
|
|
30949
31429
|
|
|
30950
31430
|
// packages/dbx-components-mcp/src/tools/semantic-type-lookup.formatter.ts
|
|
30951
31431
|
function formatSemanticTypeEntry(entry, depth) {
|
|
@@ -31126,13 +31606,13 @@ var DBX_SEMANTIC_TYPE_LOOKUP_TOOL = {
|
|
|
31126
31606
|
required: ["name"]
|
|
31127
31607
|
}
|
|
31128
31608
|
};
|
|
31129
|
-
var LookupSemanticTypeArgsType =
|
|
31609
|
+
var LookupSemanticTypeArgsType = type64({
|
|
31130
31610
|
name: "string",
|
|
31131
31611
|
"depth?": "'brief' | 'full'"
|
|
31132
31612
|
});
|
|
31133
31613
|
function parseLookupArgs2(raw) {
|
|
31134
31614
|
const parsed = LookupSemanticTypeArgsType(raw);
|
|
31135
|
-
if (parsed instanceof
|
|
31615
|
+
if (parsed instanceof type64.errors) {
|
|
31136
31616
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
31137
31617
|
}
|
|
31138
31618
|
const result = {
|
|
@@ -31194,7 +31674,7 @@ function formatNotFound11(name, registry) {
|
|
|
31194
31674
|
}
|
|
31195
31675
|
|
|
31196
31676
|
// packages/dbx-components-mcp/src/tools/search-semantic-type.tool.ts
|
|
31197
|
-
import { type as
|
|
31677
|
+
import { type as type65 } from "arktype";
|
|
31198
31678
|
var DEFAULT_LIMIT4 = 25;
|
|
31199
31679
|
var MAX_LIMIT4 = 100;
|
|
31200
31680
|
var DBX_SEMANTIC_TYPE_SEARCH_TOOL = {
|
|
@@ -31227,7 +31707,7 @@ var DBX_SEMANTIC_TYPE_SEARCH_TOOL = {
|
|
|
31227
31707
|
}
|
|
31228
31708
|
}
|
|
31229
31709
|
};
|
|
31230
|
-
var SearchSemanticTypeArgsType =
|
|
31710
|
+
var SearchSemanticTypeArgsType = type65({
|
|
31231
31711
|
"topic?": "string",
|
|
31232
31712
|
"baseType?": "string",
|
|
31233
31713
|
"package?": "string",
|
|
@@ -31236,7 +31716,7 @@ var SearchSemanticTypeArgsType = type64({
|
|
|
31236
31716
|
});
|
|
31237
31717
|
function parseSearchArgs2(raw) {
|
|
31238
31718
|
const parsed = SearchSemanticTypeArgsType(raw);
|
|
31239
|
-
if (parsed instanceof
|
|
31719
|
+
if (parsed instanceof type65.errors) {
|
|
31240
31720
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
31241
31721
|
}
|
|
31242
31722
|
const rawLimit = parsed.limit ?? DEFAULT_LIMIT4;
|
|
@@ -31347,56 +31827,1273 @@ function describeFilters(args) {
|
|
|
31347
31827
|
return parts.join(" \xB7 ");
|
|
31348
31828
|
}
|
|
31349
31829
|
|
|
31350
|
-
// packages/dbx-components-mcp/src/tools/
|
|
31351
|
-
|
|
31352
|
-
|
|
31353
|
-
|
|
31354
|
-
|
|
31355
|
-
|
|
31356
|
-
|
|
31357
|
-
|
|
31358
|
-
|
|
31359
|
-
|
|
31360
|
-
|
|
31361
|
-
|
|
31362
|
-
|
|
31363
|
-
|
|
31364
|
-
|
|
31365
|
-
|
|
31366
|
-
|
|
31367
|
-
|
|
31368
|
-
|
|
31369
|
-
|
|
31370
|
-
|
|
31371
|
-
|
|
31372
|
-
|
|
31373
|
-
|
|
31374
|
-
|
|
31375
|
-
|
|
31376
|
-
|
|
31377
|
-
|
|
31378
|
-
|
|
31379
|
-
|
|
31380
|
-
|
|
31381
|
-
|
|
31382
|
-
|
|
31383
|
-
|
|
31384
|
-
|
|
31385
|
-
|
|
31386
|
-
|
|
31387
|
-
|
|
31388
|
-
|
|
31389
|
-
|
|
31390
|
-
|
|
31391
|
-
|
|
31392
|
-
|
|
31393
|
-
|
|
31394
|
-
|
|
31395
|
-
|
|
31396
|
-
|
|
31397
|
-
|
|
31398
|
-
|
|
31399
|
-
|
|
31830
|
+
// packages/dbx-components-mcp/src/tools/css-token-lookup.tool.ts
|
|
31831
|
+
import { type as type66 } from "arktype";
|
|
31832
|
+
|
|
31833
|
+
// packages/dbx-components-mcp/src/tools/css-token-lookup/synonyms.ts
|
|
31834
|
+
var INTENT_SYNONYMS = /* @__PURE__ */ new Map([
|
|
31835
|
+
["subtitle", ["hint", "secondary text", "caption", "muted text"]],
|
|
31836
|
+
["hint", ["secondary text", "subtitle", "caption", "muted text"]],
|
|
31837
|
+
["caption", ["hint", "subtitle", "supporting text"]],
|
|
31838
|
+
["muted", ["hint", "secondary", "subtitle"]],
|
|
31839
|
+
["card", ["surface", "container", "content-box"]],
|
|
31840
|
+
["card surface", ["surface", "container", "card background"]],
|
|
31841
|
+
["card background", ["surface", "container"]],
|
|
31842
|
+
["section gap", ["default padding", "12px", "padding 3", "card padding"]],
|
|
31843
|
+
["gap", ["padding", "spacing"]],
|
|
31844
|
+
["margin", ["spacing"]],
|
|
31845
|
+
["radius", ["corner", "rounding"]],
|
|
31846
|
+
["corner", ["radius", "rounding"]],
|
|
31847
|
+
["shadow", ["elevation"]],
|
|
31848
|
+
["error", ["warn", "destructive", "danger"]],
|
|
31849
|
+
["warn", ["error", "destructive"]],
|
|
31850
|
+
["accent", ["tertiary", "highlight"]],
|
|
31851
|
+
["outline", ["border", "divider", "stroke"]],
|
|
31852
|
+
["border", ["outline", "divider"]],
|
|
31853
|
+
["divider", ["outline", "border"]]
|
|
31854
|
+
]);
|
|
31855
|
+
function expandIntentQuery(query) {
|
|
31856
|
+
const trimmed = query.trim().toLowerCase();
|
|
31857
|
+
let result;
|
|
31858
|
+
if (trimmed.length === 0) {
|
|
31859
|
+
result = [];
|
|
31860
|
+
} else {
|
|
31861
|
+
const set = /* @__PURE__ */ new Set([trimmed]);
|
|
31862
|
+
const direct = INTENT_SYNONYMS.get(trimmed);
|
|
31863
|
+
if (direct !== void 0) {
|
|
31864
|
+
for (const value of direct) {
|
|
31865
|
+
set.add(value.toLowerCase());
|
|
31866
|
+
}
|
|
31867
|
+
}
|
|
31868
|
+
for (const [key, synonyms] of INTENT_SYNONYMS) {
|
|
31869
|
+
if (trimmed.includes(key)) {
|
|
31870
|
+
for (const value of synonyms) {
|
|
31871
|
+
set.add(value.toLowerCase());
|
|
31872
|
+
}
|
|
31873
|
+
}
|
|
31874
|
+
}
|
|
31875
|
+
result = [...set];
|
|
31876
|
+
}
|
|
31877
|
+
return result;
|
|
31878
|
+
}
|
|
31879
|
+
|
|
31880
|
+
// packages/dbx-components-mcp/src/tools/css-token-lookup/resolve.ts
|
|
31881
|
+
var CONFIDENT_THRESHOLD = 7;
|
|
31882
|
+
var MAX_MATCHES = 3;
|
|
31883
|
+
var SOURCE_RANK = { "mat-sys": 4, mdc: 3, "dbx-web": 2, app: 1 };
|
|
31884
|
+
function resolveToken(registry, input) {
|
|
31885
|
+
let candidates = registry.all;
|
|
31886
|
+
if (input.category !== void 0 && input.category !== "list") {
|
|
31887
|
+
candidates = candidates.filter((c) => c.source === input.category);
|
|
31888
|
+
}
|
|
31889
|
+
if (input.role !== void 0) {
|
|
31890
|
+
candidates = candidates.filter((c) => c.role === input.role);
|
|
31891
|
+
}
|
|
31892
|
+
if (input.component !== void 0) {
|
|
31893
|
+
candidates = candidates.filter((c) => c.componentScope === input.component);
|
|
31894
|
+
}
|
|
31895
|
+
const scored = /* @__PURE__ */ new Map();
|
|
31896
|
+
function add(entry, score) {
|
|
31897
|
+
if (score <= 0) return;
|
|
31898
|
+
const key = `${entry.source}::${entry.cssVariable}`;
|
|
31899
|
+
const previous = scored.get(key);
|
|
31900
|
+
if (previous === void 0 || previous < score) {
|
|
31901
|
+
scored.set(key, score);
|
|
31902
|
+
}
|
|
31903
|
+
}
|
|
31904
|
+
if (input.intent !== void 0 && input.intent.trim().length > 0) {
|
|
31905
|
+
const expanded = expandIntentQuery(input.intent);
|
|
31906
|
+
for (const entry of candidates) {
|
|
31907
|
+
const score = scoreIntent(entry, expanded);
|
|
31908
|
+
if (score > 0) add(entry, score);
|
|
31909
|
+
}
|
|
31910
|
+
}
|
|
31911
|
+
if (input.value !== void 0 && input.value.trim().length > 0) {
|
|
31912
|
+
const trimmed = input.value.trim();
|
|
31913
|
+
const parsedColor = parseColor(trimmed);
|
|
31914
|
+
const parsedLength = parseLength(trimmed);
|
|
31915
|
+
const parsedShadow = parseShadow(trimmed);
|
|
31916
|
+
const legacyHint = isLegacyHintColor(parsedColor);
|
|
31917
|
+
for (const entry of candidates) {
|
|
31918
|
+
let score = 0;
|
|
31919
|
+
if (parsedColor !== null && (entry.role === "color" || entry.role === "text-color" || entry.role === "surface" || entry.role === "shadow")) {
|
|
31920
|
+
score = Math.max(score, scoreColor(entry, parsedColor));
|
|
31921
|
+
}
|
|
31922
|
+
if (parsedLength !== null && (entry.role === "spacing" || entry.role === "radius" || entry.role === "size")) {
|
|
31923
|
+
score = Math.max(score, scoreLength(entry, parsedLength));
|
|
31924
|
+
}
|
|
31925
|
+
if (parsedShadow !== null && (entry.role === "elevation" || entry.role === "shadow")) {
|
|
31926
|
+
score = Math.max(score, scoreShadow(entry, trimmed, parsedShadow));
|
|
31927
|
+
}
|
|
31928
|
+
if (legacyHint && entry.cssVariable === "--mat-sys-on-surface-variant") {
|
|
31929
|
+
score = Math.max(score, 9);
|
|
31930
|
+
}
|
|
31931
|
+
if (score === 0) {
|
|
31932
|
+
score = scoreValueLiteral(entry, trimmed);
|
|
31933
|
+
}
|
|
31934
|
+
if (score > 0) add(entry, score);
|
|
31935
|
+
}
|
|
31936
|
+
}
|
|
31937
|
+
if (input.component !== void 0 && input.intent === void 0 && input.value === void 0) {
|
|
31938
|
+
for (const entry of candidates) {
|
|
31939
|
+
add(entry, 5);
|
|
31940
|
+
}
|
|
31941
|
+
}
|
|
31942
|
+
if (input.category !== void 0 && scored.size === 0 && input.intent === void 0 && input.value === void 0) {
|
|
31943
|
+
for (const entry of candidates) {
|
|
31944
|
+
add(entry, 1);
|
|
31945
|
+
}
|
|
31946
|
+
}
|
|
31947
|
+
const matches = [];
|
|
31948
|
+
for (const [key, score] of scored) {
|
|
31949
|
+
const [source, cssVariable] = splitKey(key);
|
|
31950
|
+
const entry = registry.all.find((e) => e.source === source && e.cssVariable === cssVariable);
|
|
31951
|
+
if (entry !== void 0) {
|
|
31952
|
+
matches.push({ entry, score });
|
|
31953
|
+
}
|
|
31954
|
+
}
|
|
31955
|
+
matches.sort((a, b) => {
|
|
31956
|
+
if (b.score !== a.score) return b.score - a.score;
|
|
31957
|
+
const rankDiff = (SOURCE_RANK[b.entry.source] ?? 0) - (SOURCE_RANK[a.entry.source] ?? 0);
|
|
31958
|
+
if (rankDiff !== 0) return rankDiff;
|
|
31959
|
+
return a.entry.cssVariable.localeCompare(b.entry.cssVariable);
|
|
31960
|
+
});
|
|
31961
|
+
const truncated = matches.slice(0, MAX_MATCHES);
|
|
31962
|
+
const confident = truncated.length > 0 && truncated[0].score >= CONFIDENT_THRESHOLD;
|
|
31963
|
+
return { matches: truncated, confident, category: input.category };
|
|
31964
|
+
}
|
|
31965
|
+
function scoreIntent(entry, expanded) {
|
|
31966
|
+
let best = 0;
|
|
31967
|
+
for (const intent of entry.intents) {
|
|
31968
|
+
const lower = intent.toLowerCase();
|
|
31969
|
+
for (const term of expanded) {
|
|
31970
|
+
let score = 0;
|
|
31971
|
+
if (lower === term) {
|
|
31972
|
+
score = 12;
|
|
31973
|
+
} else if (lower.includes(term)) {
|
|
31974
|
+
score = 7;
|
|
31975
|
+
} else if (term.length >= 3 && term.includes(lower)) {
|
|
31976
|
+
score = 4;
|
|
31977
|
+
}
|
|
31978
|
+
if (score > best) best = score;
|
|
31979
|
+
}
|
|
31980
|
+
}
|
|
31981
|
+
return best;
|
|
31982
|
+
}
|
|
31983
|
+
var RGB_RE = /rgba?\(\s*([0-9.]+)\s*,?\s*([0-9.]+)\s*,?\s*([0-9.]+)(?:[\s,/]+([0-9.]+%?))?\s*\)/i;
|
|
31984
|
+
var RGB_NEW_RE = /rgba?\(\s*([0-9.]+)\s+([0-9.]+)\s+([0-9.]+)(?:\s*\/\s*([0-9.]+%?))?\s*\)/i;
|
|
31985
|
+
var HEX_RE = /^#([0-9a-f]{3,8})$/i;
|
|
31986
|
+
function parseColor(raw) {
|
|
31987
|
+
const trimmed = raw.trim();
|
|
31988
|
+
if (trimmed === "transparent") return { r: 0, g: 0, b: 0, a: 0 };
|
|
31989
|
+
if (trimmed.toLowerCase() === "white") return { r: 255, g: 255, b: 255, a: 1 };
|
|
31990
|
+
if (trimmed.toLowerCase() === "black") return { r: 0, g: 0, b: 0, a: 1 };
|
|
31991
|
+
let match = RGB_RE.exec(trimmed);
|
|
31992
|
+
let result = null;
|
|
31993
|
+
if (match !== null) {
|
|
31994
|
+
result = {
|
|
31995
|
+
r: clamp(parseFloat(match[1]), 0, 255),
|
|
31996
|
+
g: clamp(parseFloat(match[2]), 0, 255),
|
|
31997
|
+
b: clamp(parseFloat(match[3]), 0, 255),
|
|
31998
|
+
a: parseAlpha(match[4])
|
|
31999
|
+
};
|
|
32000
|
+
}
|
|
32001
|
+
if (result === null) {
|
|
32002
|
+
match = RGB_NEW_RE.exec(trimmed);
|
|
32003
|
+
if (match !== null) {
|
|
32004
|
+
result = {
|
|
32005
|
+
r: clamp(parseFloat(match[1]), 0, 255),
|
|
32006
|
+
g: clamp(parseFloat(match[2]), 0, 255),
|
|
32007
|
+
b: clamp(parseFloat(match[3]), 0, 255),
|
|
32008
|
+
a: parseAlpha(match[4])
|
|
32009
|
+
};
|
|
32010
|
+
}
|
|
32011
|
+
}
|
|
32012
|
+
if (result === null) {
|
|
32013
|
+
const hexMatch = HEX_RE.exec(trimmed);
|
|
32014
|
+
if (hexMatch !== null) {
|
|
32015
|
+
result = parseHex(hexMatch[1]);
|
|
32016
|
+
}
|
|
32017
|
+
}
|
|
32018
|
+
return result;
|
|
32019
|
+
}
|
|
32020
|
+
function parseAlpha(value) {
|
|
32021
|
+
let alpha = 1;
|
|
32022
|
+
if (value !== void 0) {
|
|
32023
|
+
if (value.endsWith("%")) {
|
|
32024
|
+
alpha = clamp(parseFloat(value.slice(0, -1)) / 100, 0, 1);
|
|
32025
|
+
} else {
|
|
32026
|
+
alpha = clamp(parseFloat(value), 0, 1);
|
|
32027
|
+
}
|
|
32028
|
+
}
|
|
32029
|
+
return alpha;
|
|
32030
|
+
}
|
|
32031
|
+
function parseHex(hex) {
|
|
32032
|
+
let r = 0;
|
|
32033
|
+
let g = 0;
|
|
32034
|
+
let b = 0;
|
|
32035
|
+
let a = 1;
|
|
32036
|
+
if (hex.length === 3) {
|
|
32037
|
+
r = parseInt(hex[0] + hex[0], 16);
|
|
32038
|
+
g = parseInt(hex[1] + hex[1], 16);
|
|
32039
|
+
b = parseInt(hex[2] + hex[2], 16);
|
|
32040
|
+
} else if (hex.length === 4) {
|
|
32041
|
+
r = parseInt(hex[0] + hex[0], 16);
|
|
32042
|
+
g = parseInt(hex[1] + hex[1], 16);
|
|
32043
|
+
b = parseInt(hex[2] + hex[2], 16);
|
|
32044
|
+
a = parseInt(hex[3] + hex[3], 16) / 255;
|
|
32045
|
+
} else if (hex.length === 6) {
|
|
32046
|
+
r = parseInt(hex.slice(0, 2), 16);
|
|
32047
|
+
g = parseInt(hex.slice(2, 4), 16);
|
|
32048
|
+
b = parseInt(hex.slice(4, 6), 16);
|
|
32049
|
+
} else if (hex.length === 8) {
|
|
32050
|
+
r = parseInt(hex.slice(0, 2), 16);
|
|
32051
|
+
g = parseInt(hex.slice(2, 4), 16);
|
|
32052
|
+
b = parseInt(hex.slice(4, 6), 16);
|
|
32053
|
+
a = parseInt(hex.slice(6, 8), 16) / 255;
|
|
32054
|
+
}
|
|
32055
|
+
return { r, g, b, a };
|
|
32056
|
+
}
|
|
32057
|
+
function clamp(value, min, max) {
|
|
32058
|
+
return Math.max(min, Math.min(max, value));
|
|
32059
|
+
}
|
|
32060
|
+
function srgbToLinear(channel) {
|
|
32061
|
+
const v = channel / 255;
|
|
32062
|
+
return v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
|
32063
|
+
}
|
|
32064
|
+
function rgbToOkLab(rgb) {
|
|
32065
|
+
const r = srgbToLinear(rgb.r);
|
|
32066
|
+
const g = srgbToLinear(rgb.g);
|
|
32067
|
+
const b = srgbToLinear(rgb.b);
|
|
32068
|
+
const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
|
|
32069
|
+
const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
|
|
32070
|
+
const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
|
|
32071
|
+
const lCbrt = Math.cbrt(l);
|
|
32072
|
+
const mCbrt = Math.cbrt(m);
|
|
32073
|
+
const sCbrt = Math.cbrt(s);
|
|
32074
|
+
return {
|
|
32075
|
+
L: 0.2104542553 * lCbrt + 0.793617785 * mCbrt - 0.0040720468 * sCbrt,
|
|
32076
|
+
a: 1.9779984951 * lCbrt - 2.428592205 * mCbrt + 0.4505937099 * sCbrt,
|
|
32077
|
+
b: 0.0259040371 * lCbrt + 0.7827717662 * mCbrt - 0.808675766 * sCbrt,
|
|
32078
|
+
alpha: rgb.a
|
|
32079
|
+
};
|
|
32080
|
+
}
|
|
32081
|
+
function colorDistance(a, b) {
|
|
32082
|
+
const lab1 = rgbToOkLab(a);
|
|
32083
|
+
const lab2 = rgbToOkLab(b);
|
|
32084
|
+
const dL = lab1.L - lab2.L;
|
|
32085
|
+
const dA = lab1.a - lab2.a;
|
|
32086
|
+
const dB = lab1.b - lab2.b;
|
|
32087
|
+
const dAlpha = (lab1.alpha - lab2.alpha) * 0.5;
|
|
32088
|
+
return Math.sqrt(dL * dL + dA * dA + dB * dB + dAlpha * dAlpha);
|
|
32089
|
+
}
|
|
32090
|
+
function scoreColor(entry, target) {
|
|
32091
|
+
let best = 0;
|
|
32092
|
+
const candidates = [entry.defaults.light, entry.defaults.dark].filter((v) => v !== void 0);
|
|
32093
|
+
for (const value of candidates) {
|
|
32094
|
+
const parsed = parseColor(value);
|
|
32095
|
+
if (parsed !== null) {
|
|
32096
|
+
const distance = colorDistance(target, parsed);
|
|
32097
|
+
let score = 0;
|
|
32098
|
+
if (distance <= 5e-3) score = 11;
|
|
32099
|
+
else if (distance <= 0.02) score = 9;
|
|
32100
|
+
else if (distance <= 0.04) score = 5;
|
|
32101
|
+
else if (distance <= 0.08) score = 3;
|
|
32102
|
+
if (score > best) best = score;
|
|
32103
|
+
}
|
|
32104
|
+
}
|
|
32105
|
+
return best;
|
|
32106
|
+
}
|
|
32107
|
+
function isLegacyHintColor(parsed) {
|
|
32108
|
+
let result = false;
|
|
32109
|
+
if (parsed !== null) {
|
|
32110
|
+
const isBlack = parsed.r < 5 && parsed.g < 5 && parsed.b < 5;
|
|
32111
|
+
const isWhite = parsed.r > 250 && parsed.g > 250 && parsed.b > 250;
|
|
32112
|
+
if (isBlack && parsed.a >= 0.5 && parsed.a <= 0.74 || isWhite && parsed.a >= 0.6 && parsed.a <= 0.85) {
|
|
32113
|
+
result = true;
|
|
32114
|
+
}
|
|
32115
|
+
}
|
|
32116
|
+
return result;
|
|
32117
|
+
}
|
|
32118
|
+
var LENGTH_RE = /^([0-9.]+)\s*(px|rem|em|%|vh|vw)?$/i;
|
|
32119
|
+
function parseLength(raw) {
|
|
32120
|
+
const match = LENGTH_RE.exec(raw.trim());
|
|
32121
|
+
let result = null;
|
|
32122
|
+
if (match !== null) {
|
|
32123
|
+
result = {
|
|
32124
|
+
value: parseFloat(match[1]),
|
|
32125
|
+
unit: (match[2] ?? "").toLowerCase()
|
|
32126
|
+
};
|
|
32127
|
+
}
|
|
32128
|
+
return result;
|
|
32129
|
+
}
|
|
32130
|
+
function scoreLength(entry, target) {
|
|
32131
|
+
let best = 0;
|
|
32132
|
+
const candidates = [entry.defaults.light, entry.defaults.dark].filter((v) => v !== void 0);
|
|
32133
|
+
for (const value of candidates) {
|
|
32134
|
+
const parsed = parseLength(value);
|
|
32135
|
+
if (parsed !== null && parsed.unit === target.unit) {
|
|
32136
|
+
const diff = Math.abs(parsed.value - target.value);
|
|
32137
|
+
let score = 0;
|
|
32138
|
+
if (diff < 0.01) score = 11;
|
|
32139
|
+
else if (diff <= 1 && (entry.role === "spacing" || entry.role === "radius")) score = 7;
|
|
32140
|
+
else if (diff <= 2 && entry.role === "spacing") score = 4;
|
|
32141
|
+
if (score > best) best = score;
|
|
32142
|
+
}
|
|
32143
|
+
}
|
|
32144
|
+
return best;
|
|
32145
|
+
}
|
|
32146
|
+
function parseShadow(raw) {
|
|
32147
|
+
const trimmed = raw.trim();
|
|
32148
|
+
if (!trimmed.includes("px") && !trimmed.startsWith("rgba(") && !trimmed.includes(" ")) return null;
|
|
32149
|
+
const layers = [];
|
|
32150
|
+
for (const layerRaw of splitShadowLayers(trimmed)) {
|
|
32151
|
+
const parsed = parseShadowLayer(layerRaw);
|
|
32152
|
+
if (parsed !== null) layers.push(parsed);
|
|
32153
|
+
}
|
|
32154
|
+
return layers.length > 0 ? layers : null;
|
|
32155
|
+
}
|
|
32156
|
+
function splitShadowLayers(raw) {
|
|
32157
|
+
const out = [];
|
|
32158
|
+
let depth = 0;
|
|
32159
|
+
let buf = "";
|
|
32160
|
+
for (const ch of raw) {
|
|
32161
|
+
if (ch === "(") depth += 1;
|
|
32162
|
+
else if (ch === ")") depth -= 1;
|
|
32163
|
+
if (ch === "," && depth === 0) {
|
|
32164
|
+
if (buf.trim().length > 0) out.push(buf.trim());
|
|
32165
|
+
buf = "";
|
|
32166
|
+
} else {
|
|
32167
|
+
buf += ch;
|
|
32168
|
+
}
|
|
32169
|
+
}
|
|
32170
|
+
if (buf.trim().length > 0) out.push(buf.trim());
|
|
32171
|
+
return out;
|
|
32172
|
+
}
|
|
32173
|
+
function parseShadowLayer(raw) {
|
|
32174
|
+
const colorMatch = /(rgba?\([^)]*\)|#[0-9a-f]+)/i.exec(raw);
|
|
32175
|
+
let color = null;
|
|
32176
|
+
let withoutColor = raw;
|
|
32177
|
+
if (colorMatch !== null) {
|
|
32178
|
+
color = parseColor(colorMatch[1]);
|
|
32179
|
+
withoutColor = (raw.slice(0, colorMatch.index) + raw.slice(colorMatch.index + colorMatch[0].length)).trim();
|
|
32180
|
+
}
|
|
32181
|
+
const parts = withoutColor.split(/\s+/).filter((p) => p.length > 0);
|
|
32182
|
+
let result = null;
|
|
32183
|
+
if (parts.length >= 2) {
|
|
32184
|
+
const ox = parseLength(parts[0]);
|
|
32185
|
+
const oy = parseLength(parts[1]);
|
|
32186
|
+
const blur = parts.length >= 3 ? parseLength(parts[2]) : { value: 0, unit: "px" };
|
|
32187
|
+
const spread = parts.length >= 4 ? parseLength(parts[3]) : { value: 0, unit: "px" };
|
|
32188
|
+
if (ox !== null && oy !== null && blur !== null && spread !== null) {
|
|
32189
|
+
result = {
|
|
32190
|
+
offsetX: ox.value,
|
|
32191
|
+
offsetY: oy.value,
|
|
32192
|
+
blur: blur.value,
|
|
32193
|
+
spread: spread.value,
|
|
32194
|
+
color
|
|
32195
|
+
};
|
|
32196
|
+
}
|
|
32197
|
+
}
|
|
32198
|
+
return result;
|
|
32199
|
+
}
|
|
32200
|
+
function scoreShadow(entry, raw, target) {
|
|
32201
|
+
let best = 0;
|
|
32202
|
+
for (const value of [entry.defaults.light, entry.defaults.dark].filter((v) => v !== void 0)) {
|
|
32203
|
+
const parsed = parseShadow(value);
|
|
32204
|
+
if (parsed !== null) {
|
|
32205
|
+
let layerHits = 0;
|
|
32206
|
+
for (const t of target) {
|
|
32207
|
+
const found = parsed.find((p) => Math.abs(p.offsetX - t.offsetX) <= 1 && Math.abs(p.offsetY - t.offsetY) <= 1 && Math.abs(p.blur - t.blur) <= 2);
|
|
32208
|
+
if (found !== void 0) layerHits += 1;
|
|
32209
|
+
}
|
|
32210
|
+
let score = 0;
|
|
32211
|
+
if (layerHits === target.length) score = 9;
|
|
32212
|
+
else if (layerHits > 0) score = 5;
|
|
32213
|
+
if (score > best) best = score;
|
|
32214
|
+
}
|
|
32215
|
+
if (value === raw) best = Math.max(best, 11);
|
|
32216
|
+
}
|
|
32217
|
+
return best;
|
|
32218
|
+
}
|
|
32219
|
+
function scoreValueLiteral(entry, raw) {
|
|
32220
|
+
let best = 0;
|
|
32221
|
+
for (const value of [entry.defaults.light, entry.defaults.dark].filter((v) => v !== void 0)) {
|
|
32222
|
+
if (value === raw) best = Math.max(best, 11);
|
|
32223
|
+
else if (value.includes(raw)) best = Math.max(best, 4);
|
|
32224
|
+
}
|
|
32225
|
+
return best;
|
|
32226
|
+
}
|
|
32227
|
+
function splitKey(key) {
|
|
32228
|
+
const idx = key.indexOf("::");
|
|
32229
|
+
let result;
|
|
32230
|
+
if (idx < 0) {
|
|
32231
|
+
result = ["", key];
|
|
32232
|
+
} else {
|
|
32233
|
+
result = [key.slice(0, idx), key.slice(idx + 2)];
|
|
32234
|
+
}
|
|
32235
|
+
return result;
|
|
32236
|
+
}
|
|
32237
|
+
|
|
32238
|
+
// packages/dbx-components-mcp/src/tools/css-token-lookup/format.ts
|
|
32239
|
+
function formatCssTokenLookup(registry, input, result) {
|
|
32240
|
+
let text;
|
|
32241
|
+
if (input.category !== void 0 && input.category !== "list" || input.intent === void 0 && input.value === void 0 && input.component === void 0 && input.role === void 0) {
|
|
32242
|
+
if (input.category !== void 0) {
|
|
32243
|
+
text = formatBrowse(registry, input.category, result.matches);
|
|
32244
|
+
} else if (input.role !== void 0) {
|
|
32245
|
+
text = formatBrowse(registry, void 0, result.matches);
|
|
32246
|
+
} else {
|
|
32247
|
+
text = formatNoQuery();
|
|
32248
|
+
}
|
|
32249
|
+
} else if (result.matches.length === 0) {
|
|
32250
|
+
text = formatNoMatch(input);
|
|
32251
|
+
} else if (!result.confident && result.matches.length > 1) {
|
|
32252
|
+
text = formatAmbiguous(input, result.matches);
|
|
32253
|
+
} else {
|
|
32254
|
+
text = formatSingle2(result.matches[0], input, result.matches.slice(1));
|
|
32255
|
+
}
|
|
32256
|
+
return text;
|
|
32257
|
+
}
|
|
32258
|
+
function formatSingle2(match, input, otherMatches) {
|
|
32259
|
+
const entry = match.entry;
|
|
32260
|
+
const lines = [`# \`${entry.cssVariable}\``, "", formatHeaderLine(entry), "", `**Use:** \`var(${entry.cssVariable})\``];
|
|
32261
|
+
if (entry.scssVariable !== void 0) {
|
|
32262
|
+
lines.push(`**SCSS:** \`${entry.scssVariable}\``);
|
|
32263
|
+
}
|
|
32264
|
+
lines.push("");
|
|
32265
|
+
lines.push(entry.description);
|
|
32266
|
+
if (entry.defaults.light !== void 0 || entry.defaults.dark !== void 0) {
|
|
32267
|
+
lines.push("", "## Default value");
|
|
32268
|
+
if (entry.defaults.light !== void 0) {
|
|
32269
|
+
lines.push(`- light: \`${entry.defaults.light}\``);
|
|
32270
|
+
}
|
|
32271
|
+
if (entry.defaults.dark !== void 0) {
|
|
32272
|
+
lines.push(`- dark: \`${entry.defaults.dark}\``);
|
|
32273
|
+
}
|
|
32274
|
+
}
|
|
32275
|
+
if (entry.antiUseNotes !== void 0 && entry.antiUseNotes.length > 0) {
|
|
32276
|
+
lines.push("", "## Don't use this when", "", entry.antiUseNotes);
|
|
32277
|
+
}
|
|
32278
|
+
if (entry.utilityClasses !== void 0 && entry.utilityClasses.length > 0) {
|
|
32279
|
+
const classes = entry.utilityClasses.map((c) => `\`${c}\``).join(", ");
|
|
32280
|
+
lines.push("", `## Utility classes`, "", classes);
|
|
32281
|
+
}
|
|
32282
|
+
if (entry.recommendedPrimitive !== void 0) {
|
|
32283
|
+
lines.push("", "## Recommended primitive", "", `Reach for \`${entry.recommendedPrimitive}\` when you'd otherwise hand-roll this token. See \`dbx_ui_lookup topic="${entry.recommendedPrimitive}"\`.`);
|
|
32284
|
+
}
|
|
32285
|
+
if (entry.seeAlso !== void 0 && entry.seeAlso.length > 0) {
|
|
32286
|
+
const seeAlso = entry.seeAlso.map((s) => `\`${s}\``).join(", ");
|
|
32287
|
+
lines.push("", "## See also", "", seeAlso);
|
|
32288
|
+
}
|
|
32289
|
+
if (otherMatches.length > 0) {
|
|
32290
|
+
lines.push("", "## Other candidates", "");
|
|
32291
|
+
for (const candidate of otherMatches) {
|
|
32292
|
+
lines.push(`- \`${candidate.entry.cssVariable}\` \xB7 ${candidate.entry.role} \xB7 score ${candidate.score}`);
|
|
32293
|
+
}
|
|
32294
|
+
}
|
|
32295
|
+
return lines.join("\n");
|
|
32296
|
+
}
|
|
32297
|
+
function formatHeaderLine(entry) {
|
|
32298
|
+
const parts = [`**source:** \`${entry.source}\``, `**role:** \`${entry.role}\``];
|
|
32299
|
+
if (entry.componentScope !== void 0) parts.push(`**component:** \`${entry.componentScope}\``);
|
|
32300
|
+
return parts.join(" \xB7 ");
|
|
32301
|
+
}
|
|
32302
|
+
function formatAmbiguous(input, matches) {
|
|
32303
|
+
const lines = [`# Top candidates`, "", `Multiple tokens look relevant for the supplied query (${describeQuery(input)}). The candidates are sorted by confidence:`, ""];
|
|
32304
|
+
for (const match of matches) {
|
|
32305
|
+
lines.push(`## \`${match.entry.cssVariable}\` \xB7 score ${match.score}`);
|
|
32306
|
+
lines.push("", `${match.entry.description}`, "");
|
|
32307
|
+
if (match.entry.defaults.light !== void 0) {
|
|
32308
|
+
lines.push(`- light default: \`${match.entry.defaults.light}\``);
|
|
32309
|
+
}
|
|
32310
|
+
if (match.entry.defaults.dark !== void 0) {
|
|
32311
|
+
lines.push(`- dark default: \`${match.entry.defaults.dark}\``);
|
|
32312
|
+
}
|
|
32313
|
+
if (match.entry.antiUseNotes !== void 0 && match.entry.antiUseNotes.length > 0) {
|
|
32314
|
+
lines.push("", match.entry.antiUseNotes);
|
|
32315
|
+
}
|
|
32316
|
+
lines.push("");
|
|
32317
|
+
}
|
|
32318
|
+
return lines.join("\n").trimEnd();
|
|
32319
|
+
}
|
|
32320
|
+
function formatBrowse(registry, category, matches) {
|
|
32321
|
+
const list = matches.length > 0 ? matches.map((m) => m.entry) : registry.all;
|
|
32322
|
+
const title = category !== void 0 ? `# Tokens \xB7 category \`${category}\`` : `# Tokens`;
|
|
32323
|
+
const lines = [title, ""];
|
|
32324
|
+
if (list.length === 0) {
|
|
32325
|
+
lines.push("_No tokens matched._");
|
|
32326
|
+
} else {
|
|
32327
|
+
lines.push("| CSS variable | Role | Source | Description |");
|
|
32328
|
+
lines.push("| --- | --- | --- | --- |");
|
|
32329
|
+
for (const entry of list) {
|
|
32330
|
+
const desc = entry.description.replaceAll("|", String.raw`\|`).split("\n")[0];
|
|
32331
|
+
lines.push(`| \`${entry.cssVariable}\` | ${entry.role} | ${entry.source} | ${desc} |`);
|
|
32332
|
+
}
|
|
32333
|
+
}
|
|
32334
|
+
return lines.join("\n");
|
|
32335
|
+
}
|
|
32336
|
+
function formatNoQuery() {
|
|
32337
|
+
return ["# `dbx_css_token_lookup`", "", 'Provide at least one of `intent`, `value`, `role`, `component`, or `category` (use `category="list"` to browse the full catalog).'].join("\n");
|
|
32338
|
+
}
|
|
32339
|
+
function formatNoMatch(input) {
|
|
32340
|
+
const lines = ["# No confident match", "", `No token confidently matched the query (${describeQuery(input)}).`, "", "If this looks like a project-specific brand chrome value, define a project-local SCSS variable in your app's `styles.scss` instead of reaching for a system token."];
|
|
32341
|
+
return lines.join("\n");
|
|
32342
|
+
}
|
|
32343
|
+
function describeQuery(input) {
|
|
32344
|
+
const parts = [];
|
|
32345
|
+
if (input.intent !== void 0) parts.push(`intent="${input.intent}"`);
|
|
32346
|
+
if (input.value !== void 0) parts.push(`value="${input.value}"`);
|
|
32347
|
+
if (input.role !== void 0) parts.push(`role="${input.role}"`);
|
|
32348
|
+
if (input.component !== void 0) parts.push(`component="${input.component}"`);
|
|
32349
|
+
if (input.category !== void 0) parts.push(`category="${input.category}"`);
|
|
32350
|
+
return parts.join(", ") || "(none)";
|
|
32351
|
+
}
|
|
32352
|
+
|
|
32353
|
+
// packages/dbx-components-mcp/src/tools/css-token-lookup.tool.ts
|
|
32354
|
+
var DBX_CSS_TOKEN_LOOKUP_TOOL = {
|
|
32355
|
+
name: "dbx_css_token_lookup",
|
|
32356
|
+
description: [
|
|
32357
|
+
"Forward-lookup over the dbx-web + Angular Material design-token catalog.",
|
|
32358
|
+
"",
|
|
32359
|
+
"Pass any combination of:",
|
|
32360
|
+
' \u2022 `intent` \u2014 plain English ("hint text color", "card radius", "section gap", "primary button color");',
|
|
32361
|
+
" \u2022 `value` \u2014 raw CSS value to reverse-lookup (`rgba(0,0,0,0.6)`, `12px`, `#26353f`, `0 1px 2px rgba(0,0,0,.06)`);",
|
|
32362
|
+
" \u2022 `role` \u2014 narrow the candidate pool (color, text-color, surface, spacing, radius, elevation, shadow, typography, motion, state-layer, size, breakpoint);",
|
|
32363
|
+
' \u2022 `component` \u2014 Angular Material component slug ("mat-progress-bar", "mat-button", ...) to surface the relevant MDC tokens;',
|
|
32364
|
+
' \u2022 `category` \u2014 `"list"` for the full catalog, or `"dbx-web"|"mat-sys"|"mdc"|"app"` to browse one source.',
|
|
32365
|
+
"",
|
|
32366
|
+
"Returns the recommended `var(--\u2026)` plus light/dark defaults, anti-use notes, the dbx-web utility class or primitive that wraps the underlying token, and any see-also references."
|
|
32367
|
+
].join("\n"),
|
|
32368
|
+
inputSchema: {
|
|
32369
|
+
type: "object",
|
|
32370
|
+
properties: {
|
|
32371
|
+
intent: { type: "string", description: "Plain-English intent \u2014 what the value is for." },
|
|
32372
|
+
value: { type: "string", description: "Raw CSS value to reverse-lookup." },
|
|
32373
|
+
role: { type: "string", enum: [...TOKEN_ROLES], description: "Token-role filter." },
|
|
32374
|
+
component: { type: "string", description: "Angular Material component slug \u2014 narrows the lookup to MDC tokens scoped to that component." },
|
|
32375
|
+
category: { type: "string", description: '"list" for the full catalog, or "dbx-web"|"mat-sys"|"mdc"|"app" to browse one source.' }
|
|
32376
|
+
}
|
|
32377
|
+
}
|
|
32378
|
+
};
|
|
32379
|
+
var CssTokenLookupArgs = type66({
|
|
32380
|
+
"intent?": "string",
|
|
32381
|
+
"value?": "string",
|
|
32382
|
+
"role?": "string",
|
|
32383
|
+
"component?": "string",
|
|
32384
|
+
"category?": "string"
|
|
32385
|
+
});
|
|
32386
|
+
function parseArgs11(raw) {
|
|
32387
|
+
const parsed = CssTokenLookupArgs(raw);
|
|
32388
|
+
if (parsed instanceof type66.errors) {
|
|
32389
|
+
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
32390
|
+
}
|
|
32391
|
+
const result = {
|
|
32392
|
+
intent: parsed.intent,
|
|
32393
|
+
value: parsed.value,
|
|
32394
|
+
role: parsed.role,
|
|
32395
|
+
component: parsed.component,
|
|
32396
|
+
category: parsed.category
|
|
32397
|
+
};
|
|
32398
|
+
return result;
|
|
32399
|
+
}
|
|
32400
|
+
function createCssTokenLookupTool(input) {
|
|
32401
|
+
const { registry } = input;
|
|
32402
|
+
const run15 = (rawArgs) => {
|
|
32403
|
+
let args;
|
|
32404
|
+
try {
|
|
32405
|
+
args = parseArgs11(rawArgs);
|
|
32406
|
+
} catch (error) {
|
|
32407
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
32408
|
+
return toolError(message);
|
|
32409
|
+
}
|
|
32410
|
+
const result = resolveToken(registry, args);
|
|
32411
|
+
const text = formatCssTokenLookup(registry, args, result);
|
|
32412
|
+
const tool = { content: [{ type: "text", text }] };
|
|
32413
|
+
return tool;
|
|
32414
|
+
};
|
|
32415
|
+
return { definition: DBX_CSS_TOKEN_LOOKUP_TOOL, run: run15 };
|
|
32416
|
+
}
|
|
32417
|
+
|
|
32418
|
+
// packages/dbx-components-mcp/src/tools/ui-smell-check.tool.ts
|
|
32419
|
+
import { readFile as nodeReadFile8 } from "node:fs/promises";
|
|
32420
|
+
import { isAbsolute as isAbsolute10, resolve as resolve40 } from "node:path";
|
|
32421
|
+
import { type as type67 } from "arktype";
|
|
32422
|
+
|
|
32423
|
+
// packages/dbx-components-mcp/src/tools/ui-smell-check/smells.ts
|
|
32424
|
+
function captureSnippet(haystack, index, length) {
|
|
32425
|
+
const start = Math.max(0, haystack.lastIndexOf("\n", index) + 1);
|
|
32426
|
+
const end = haystack.indexOf("\n", index + length);
|
|
32427
|
+
let stop;
|
|
32428
|
+
if (end < 0) {
|
|
32429
|
+
stop = Math.min(haystack.length, index + length + 80);
|
|
32430
|
+
} else {
|
|
32431
|
+
stop = end;
|
|
32432
|
+
}
|
|
32433
|
+
return haystack.slice(start, stop).trimEnd();
|
|
32434
|
+
}
|
|
32435
|
+
function isInsideScssVarDeclaration(scss, colonIndex) {
|
|
32436
|
+
const lineStart = scss.lastIndexOf("\n", colonIndex - 1) + 1;
|
|
32437
|
+
const prefix = scss.slice(lineStart, colonIndex);
|
|
32438
|
+
return /^\s*\$[\w-]+\s*$/.test(prefix);
|
|
32439
|
+
}
|
|
32440
|
+
function findCardSurface(scss) {
|
|
32441
|
+
let result = null;
|
|
32442
|
+
let depth = 0;
|
|
32443
|
+
let blockStart = -1;
|
|
32444
|
+
for (let i = 0; i < scss.length; i += 1) {
|
|
32445
|
+
const ch = scss[i];
|
|
32446
|
+
if (ch === "{") {
|
|
32447
|
+
if (depth === 0) blockStart = i + 1;
|
|
32448
|
+
depth += 1;
|
|
32449
|
+
} else if (ch === "}") {
|
|
32450
|
+
depth -= 1;
|
|
32451
|
+
if (depth === 0 && blockStart >= 0) {
|
|
32452
|
+
const block = scss.slice(blockStart, i);
|
|
32453
|
+
if (looksLikeCardSurface(block)) {
|
|
32454
|
+
result = { index: blockStart, length: block.length, snippet: block.trim() };
|
|
32455
|
+
break;
|
|
32456
|
+
}
|
|
32457
|
+
blockStart = -1;
|
|
32458
|
+
}
|
|
32459
|
+
}
|
|
32460
|
+
}
|
|
32461
|
+
return result;
|
|
32462
|
+
}
|
|
32463
|
+
function looksLikeCardSurface(block) {
|
|
32464
|
+
const hasPadding = /\bpadding\s*:\s*[0-9]/i.test(block);
|
|
32465
|
+
const hasWhiteBg = /background\s*:\s*(#fff|#ffffff|white|rgb\(\s*255\s*,\s*255\s*,\s*255\s*\))/i.test(block);
|
|
32466
|
+
const hasRadius = /\bborder-radius\s*:\s*[0-9]/i.test(block);
|
|
32467
|
+
return hasPadding && hasWhiteBg && hasRadius;
|
|
32468
|
+
}
|
|
32469
|
+
var cardSurfaceHandrolled = (input) => {
|
|
32470
|
+
const matches = [];
|
|
32471
|
+
const hit = findCardSurface(input.scss);
|
|
32472
|
+
if (hit !== null) {
|
|
32473
|
+
const wrapperHint = input.conventions.cardWrapperClasses && input.conventions.cardWrapperClasses.length > 0 ? ` Or wrap the projection in your project-local class: \`${input.conventions.cardWrapperClasses.join("`, `")}\`.` : "";
|
|
32474
|
+
matches.push({
|
|
32475
|
+
id: "card-surface-handrolled",
|
|
32476
|
+
severity: "warn",
|
|
32477
|
+
title: "Hand-rolled card surface",
|
|
32478
|
+
snippet: hit.snippet,
|
|
32479
|
+
fix: ['This block re-implements `<dbx-content-box>`. Replace the wrapper element with `<dbx-content-box>` (it provides padding, surface color, and corner radius automatically) and project the section content via `<dbx-section header="..." hint="...">` for the title/subtitle stack.' + wrapperHint, "", "Replacement HTML:", "```html", "<dbx-content-box>", ' <dbx-section header="\u2026" hint="\u2026">', " <!-- projected content -->", " </dbx-section>", "</dbx-content-box>", "```"].join("\n"),
|
|
32480
|
+
seeAlsoSlugs: ["content-box", "section"],
|
|
32481
|
+
seeAlsoTokens: ["--mat-sys-surface-container", "--dbx-padding-3"]
|
|
32482
|
+
});
|
|
32483
|
+
}
|
|
32484
|
+
return matches;
|
|
32485
|
+
};
|
|
32486
|
+
var HARDCODED_RADIUS_RE = /border-radius\s*:\s*([0-9]+(?:\.[0-9]+)?(?:px|rem|em))(?!\s*\))/gi;
|
|
32487
|
+
var hardcodedRadius = (input) => {
|
|
32488
|
+
const matches = [];
|
|
32489
|
+
for (const match of input.scss.matchAll(HARDCODED_RADIUS_RE)) {
|
|
32490
|
+
if (match.index === void 0) continue;
|
|
32491
|
+
const colonIndex = input.scss.indexOf(":", match.index);
|
|
32492
|
+
if (colonIndex !== -1 && isInsideScssVarDeclaration(input.scss, colonIndex)) continue;
|
|
32493
|
+
const raw = match[1];
|
|
32494
|
+
const candidates = input.tokenRegistry.findByValue(raw, "radius");
|
|
32495
|
+
const top = candidates[0];
|
|
32496
|
+
const fix = top !== void 0 ? `Replace \`border-radius: ${raw}\` with \`border-radius: var(${top.entry.cssVariable})\` (matches the design-system corner token).` : `Hardcoded radius \`${raw}\` doesn't match any known design-system token. Either wrap it in a project-local SCSS variable or align it with one of \`--mat-sys-corner-extra-small/-small/-medium/-large/-extra-large/-full\`.`;
|
|
32497
|
+
matches.push({
|
|
32498
|
+
id: "hardcoded-radius",
|
|
32499
|
+
severity: "warn",
|
|
32500
|
+
title: "Hardcoded border-radius",
|
|
32501
|
+
snippet: captureSnippet(input.scss, match.index, match[0].length),
|
|
32502
|
+
fix,
|
|
32503
|
+
seeAlsoSlugs: top?.entry.recommendedPrimitive !== void 0 ? [top.entry.recommendedPrimitive] : [],
|
|
32504
|
+
seeAlsoTokens: top !== void 0 ? [top.entry.cssVariable] : []
|
|
32505
|
+
});
|
|
32506
|
+
}
|
|
32507
|
+
return matches;
|
|
32508
|
+
};
|
|
32509
|
+
var HARDCODED_SHADOW_RE = /box-shadow\s*:\s*([^;]+);/gi;
|
|
32510
|
+
var hardcodedShadow = (input) => {
|
|
32511
|
+
const matches = [];
|
|
32512
|
+
for (const match of input.scss.matchAll(HARDCODED_SHADOW_RE)) {
|
|
32513
|
+
if (match.index === void 0) continue;
|
|
32514
|
+
const raw = match[1].trim();
|
|
32515
|
+
if (raw.startsWith("var(") || raw === "none") continue;
|
|
32516
|
+
const candidates = input.tokenRegistry.findByValue(raw, "elevation");
|
|
32517
|
+
const top = candidates[0];
|
|
32518
|
+
const fix = top !== void 0 ? `Replace this hardcoded shadow with \`box-shadow: var(${top.entry.cssVariable})\` or use \`<dbx-content-box [elevate]="true">\` to apply the elevation through the wrapper component.` : 'Hardcoded `box-shadow:` declarations should map to one of the `--mat-sys-level0..5` elevation tokens, or wrap the surface in `<dbx-content-box [elevate]="true">` so the shadow comes from the design system.';
|
|
32519
|
+
matches.push({
|
|
32520
|
+
id: "hardcoded-shadow",
|
|
32521
|
+
severity: "warn",
|
|
32522
|
+
title: "Hardcoded box-shadow",
|
|
32523
|
+
snippet: captureSnippet(input.scss, match.index, match[0].length),
|
|
32524
|
+
fix,
|
|
32525
|
+
seeAlsoSlugs: ["content-box", "content-elevate"],
|
|
32526
|
+
seeAlsoTokens: top !== void 0 ? [top.entry.cssVariable] : ["--mat-sys-level1"]
|
|
32527
|
+
});
|
|
32528
|
+
}
|
|
32529
|
+
return matches;
|
|
32530
|
+
};
|
|
32531
|
+
var HARDCODED_HINT_COLOR_RE = /color\s*:\s*(rgba?\(\s*0\s*,\s*0\s*,\s*0\s*[,/\s]\s*0\.[5-7][0-9]?\s*\)|rgba?\(\s*255\s*,\s*255\s*,\s*255\s*[,/\s]\s*0\.[6-8][0-9]?\s*\))/gi;
|
|
32532
|
+
var hardcodedHintColor = (input) => {
|
|
32533
|
+
const matches = [];
|
|
32534
|
+
for (const match of input.scss.matchAll(HARDCODED_HINT_COLOR_RE)) {
|
|
32535
|
+
if (match.index === void 0) continue;
|
|
32536
|
+
matches.push({
|
|
32537
|
+
id: "hardcoded-hint-color",
|
|
32538
|
+
severity: "warn",
|
|
32539
|
+
title: "Hardcoded hint text color",
|
|
32540
|
+
snippet: captureSnippet(input.scss, match.index, match[0].length),
|
|
32541
|
+
fix: ["Replace this hardcoded hint color with `color: var(--mat-sys-on-surface-variant)` so it adapts to dark mode and matches Material guidance.", "", 'If this `color:` is on text inside a card, prefer `<dbx-section [header]="\u2026" [hint]="\u2026">`, which already styles the hint slot with the right token.'].join("\n"),
|
|
32542
|
+
seeAlsoSlugs: ["section"],
|
|
32543
|
+
seeAlsoTokens: ["--mat-sys-on-surface-variant"]
|
|
32544
|
+
});
|
|
32545
|
+
}
|
|
32546
|
+
return matches;
|
|
32547
|
+
};
|
|
32548
|
+
var HARDCODED_PADDING_RE = /(?:padding|margin)\s*(?:-(?:top|right|bottom|left))?\s*:\s*([0-9]+(?:\.[0-9]+)?px)(?!\s*\))/gi;
|
|
32549
|
+
var hardcodedPadding = (input) => {
|
|
32550
|
+
const matches = [];
|
|
32551
|
+
for (const match of input.scss.matchAll(HARDCODED_PADDING_RE)) {
|
|
32552
|
+
if (match.index === void 0) continue;
|
|
32553
|
+
const raw = match[1];
|
|
32554
|
+
const candidates = input.tokenRegistry.findByValue(raw, "spacing");
|
|
32555
|
+
const top = candidates[0];
|
|
32556
|
+
if (top !== void 0) {
|
|
32557
|
+
const utility = top.entry.utilityClasses?.[0];
|
|
32558
|
+
const fix = ["Replace `" + match[0].trim() + "` with `var(" + top.entry.cssVariable + ")`" + (utility !== void 0 ? ` (or use the \`${utility}\` utility class on the host element)` : "") + "."].join("\n");
|
|
32559
|
+
matches.push({
|
|
32560
|
+
id: "hardcoded-padding",
|
|
32561
|
+
severity: "warn",
|
|
32562
|
+
title: "Hardcoded padding/margin",
|
|
32563
|
+
snippet: captureSnippet(input.scss, match.index, match[0].length),
|
|
32564
|
+
fix,
|
|
32565
|
+
seeAlsoSlugs: [],
|
|
32566
|
+
seeAlsoTokens: [top.entry.cssVariable]
|
|
32567
|
+
});
|
|
32568
|
+
}
|
|
32569
|
+
}
|
|
32570
|
+
return matches;
|
|
32571
|
+
};
|
|
32572
|
+
var HARDCODED_TYPOGRAPHY_RE = /font-size\s*:\s*([0-9]+(?:\.[0-9]+)?)(rem|px)/gi;
|
|
32573
|
+
var hardcodedTypography = (input) => {
|
|
32574
|
+
const matches = [];
|
|
32575
|
+
for (const match of input.scss.matchAll(HARDCODED_TYPOGRAPHY_RE)) {
|
|
32576
|
+
if (match.index === void 0) continue;
|
|
32577
|
+
const value = parseFloat(match[1]);
|
|
32578
|
+
const unit = match[2];
|
|
32579
|
+
const tooBig = unit === "rem" && value > 1 || unit === "px" && value >= 18;
|
|
32580
|
+
if (tooBig) {
|
|
32581
|
+
matches.push({
|
|
32582
|
+
id: "hardcoded-typography",
|
|
32583
|
+
severity: "info",
|
|
32584
|
+
title: "Hardcoded large font-size",
|
|
32585
|
+
snippet: captureSnippet(input.scss, match.index, match[0].length),
|
|
32586
|
+
fix: "Use the `<dbx-section [header]>` (or `<dbx-section-page>` for page-level headers) primitive \u2014 it carries Material `headline` typography automatically. If you must inline a font-size, reach for one of `--mat-sys-headline-{small|medium|large}` or `--mat-sys-title-large`.",
|
|
32587
|
+
seeAlsoSlugs: ["section", "section-page"],
|
|
32588
|
+
seeAlsoTokens: ["--mat-sys-headline-medium", "--mat-sys-title-large"]
|
|
32589
|
+
});
|
|
32590
|
+
}
|
|
32591
|
+
}
|
|
32592
|
+
return matches;
|
|
32593
|
+
};
|
|
32594
|
+
var PIT_BACKGROUND_RE = /background\s*:\s*(rgba?\(\s*0\s*,\s*0\s*,\s*0\s*[,/\s]\s*0\.0[2-8]\s*\))/gi;
|
|
32595
|
+
var pitInsteadOfTintedBg = (input) => {
|
|
32596
|
+
const matches = [];
|
|
32597
|
+
for (const match of input.scss.matchAll(PIT_BACKGROUND_RE)) {
|
|
32598
|
+
if (match.index === void 0) continue;
|
|
32599
|
+
matches.push({
|
|
32600
|
+
id: "pit-instead-of-tinted-bg",
|
|
32601
|
+
severity: "warn",
|
|
32602
|
+
title: 'Hand-rolled tinted "pit" background',
|
|
32603
|
+
snippet: captureSnippet(input.scss, match.index, match[0].length),
|
|
32604
|
+
fix: "Apply `[dbxContentPit]` to the host element. The directive paints the right tinted surface color and supports the rounded variant via `[dbxContentPitRounded]`.",
|
|
32605
|
+
seeAlsoSlugs: ["content-pit"],
|
|
32606
|
+
seeAlsoTokens: ["--mat-sys-surface-container-low"]
|
|
32607
|
+
});
|
|
32608
|
+
}
|
|
32609
|
+
return matches;
|
|
32610
|
+
};
|
|
32611
|
+
var FLEX_COLUMN_GAP_RE = /display\s*:\s*flex\s*;\s*flex-direction\s*:\s*column\s*;\s*gap\s*:\s*[0-9]+(?:\.[0-9]+)?px\s*;/gi;
|
|
32612
|
+
var flexColumnWithGap = (input) => {
|
|
32613
|
+
const matches = [];
|
|
32614
|
+
for (const match of input.scss.matchAll(FLEX_COLUMN_GAP_RE)) {
|
|
32615
|
+
if (match.index === void 0) continue;
|
|
32616
|
+
matches.push({
|
|
32617
|
+
id: "flex-column-with-gap-as-card-stack",
|
|
32618
|
+
severity: "info",
|
|
32619
|
+
title: "Flex column + gap on a card stack",
|
|
32620
|
+
snippet: captureSnippet(input.scss, match.index, match[0].length),
|
|
32621
|
+
fix: "For stacking dbx-web cards/content-boxes, prefer `[dbxFlexGroup]` with `[breakToColumn]` (it handles wrapping, gaps, and responsive flow) or rely on the default sibling margins emitted by `<dbx-content-box>` siblings.",
|
|
32622
|
+
seeAlsoSlugs: ["flex-group"],
|
|
32623
|
+
seeAlsoTokens: ["--dbx-padding-3"]
|
|
32624
|
+
});
|
|
32625
|
+
}
|
|
32626
|
+
return matches;
|
|
32627
|
+
};
|
|
32628
|
+
var MDC_OVERRIDE_RE = /(--mdc-[a-z0-9-]+)\s*:/gi;
|
|
32629
|
+
var mdcTokenOverride = (input) => {
|
|
32630
|
+
const matches = [];
|
|
32631
|
+
const seen = /* @__PURE__ */ new Set();
|
|
32632
|
+
for (const match of input.scss.matchAll(MDC_OVERRIDE_RE)) {
|
|
32633
|
+
if (match.index === void 0) continue;
|
|
32634
|
+
const tokenName = match[1];
|
|
32635
|
+
if (seen.has(tokenName)) continue;
|
|
32636
|
+
seen.add(tokenName);
|
|
32637
|
+
const tokenEntry = input.tokenRegistry.findByCssVariable(tokenName);
|
|
32638
|
+
const componentScope = tokenEntry?.componentScope;
|
|
32639
|
+
const fix = componentScope !== void 0 ? `Don't override \`${tokenName}\` directly. Set \`color="primary|accent|warn"\` on the host \`<${componentScope}>\` (or wrap in a thin styled component) so the token resolution flows through Material's theme.` : `Don't override \`${tokenName}\` directly. Material component tokens should be set via the host component's \`color\` attribute or by a parent theme \u2014 direct overrides break dark mode and theme switching.`;
|
|
32640
|
+
matches.push({
|
|
32641
|
+
id: "mdc-token-override-instead-of-wrapper",
|
|
32642
|
+
severity: "warn",
|
|
32643
|
+
title: "Direct MDC token override",
|
|
32644
|
+
snippet: captureSnippet(input.scss, match.index, match[0].length),
|
|
32645
|
+
fix,
|
|
32646
|
+
seeAlsoSlugs: componentScope === "mat-button" ? ["button"] : [],
|
|
32647
|
+
seeAlsoTokens: [tokenName]
|
|
32648
|
+
});
|
|
32649
|
+
}
|
|
32650
|
+
return matches;
|
|
32651
|
+
};
|
|
32652
|
+
var HARDCODED_HEX_RE = /:\s*(#[0-9a-fA-F]{3,8})\b(?!\s*(?:px|rem|em))/g;
|
|
32653
|
+
var hardcodedHexBrand = (input) => {
|
|
32654
|
+
const matches = [];
|
|
32655
|
+
const seen = /* @__PURE__ */ new Set();
|
|
32656
|
+
for (const match of input.scss.matchAll(HARDCODED_HEX_RE)) {
|
|
32657
|
+
if (match.index === void 0) continue;
|
|
32658
|
+
if (isInsideScssVarDeclaration(input.scss, match.index)) continue;
|
|
32659
|
+
const hex = match[1];
|
|
32660
|
+
if (seen.has(hex)) continue;
|
|
32661
|
+
seen.add(hex);
|
|
32662
|
+
const candidates = input.tokenRegistry.findByValue(hex);
|
|
32663
|
+
if (candidates.length === 0 || candidates[0].score < 6) {
|
|
32664
|
+
matches.push({
|
|
32665
|
+
id: "hardcoded-hex-brand-color",
|
|
32666
|
+
severity: "info",
|
|
32667
|
+
title: "Hardcoded hex with no matching token",
|
|
32668
|
+
snippet: captureSnippet(input.scss, match.index, match[0].length),
|
|
32669
|
+
fix: `\`${hex}\` doesn't map to a known design-system token. If this is project-local brand chrome, define a project-local SCSS variable in your app's \`styles.scss\` (e.g. \`$myapp-onboarding-bg: ${hex};\`) so the value has one source of truth.`,
|
|
32670
|
+
seeAlsoSlugs: [],
|
|
32671
|
+
seeAlsoTokens: []
|
|
32672
|
+
});
|
|
32673
|
+
}
|
|
32674
|
+
}
|
|
32675
|
+
return matches;
|
|
32676
|
+
};
|
|
32677
|
+
var EMPTY_RULESET_RE = /([^{}\n;]+?)\s*\{\s*\}/g;
|
|
32678
|
+
var emptyRuleset = (input) => {
|
|
32679
|
+
const matches = [];
|
|
32680
|
+
for (const match of input.scss.matchAll(EMPTY_RULESET_RE)) {
|
|
32681
|
+
if (match.index === void 0) continue;
|
|
32682
|
+
const selector = match[1].trim();
|
|
32683
|
+
if (selector.length === 0) continue;
|
|
32684
|
+
if (!/^[.#&*:@\w]/.test(selector)) continue;
|
|
32685
|
+
matches.push({
|
|
32686
|
+
id: "empty-ruleset",
|
|
32687
|
+
severity: "info",
|
|
32688
|
+
title: "Empty rule block",
|
|
32689
|
+
snippet: captureSnippet(input.scss, match.index, match[0].length),
|
|
32690
|
+
fix: "Empty rule blocks add noise. Either add styles, remove the block, or replace it with a `// TODO:` comment if you want to mark a placeholder.",
|
|
32691
|
+
seeAlsoSlugs: [],
|
|
32692
|
+
seeAlsoTokens: []
|
|
32693
|
+
});
|
|
32694
|
+
}
|
|
32695
|
+
return matches;
|
|
32696
|
+
};
|
|
32697
|
+
var SCSS_USE_AS_RE = /@use\s+['"][^'"]+['"]\s+as\s+([\w-]+)\s*;/g;
|
|
32698
|
+
var unusedScssUse = (input) => {
|
|
32699
|
+
const matches = [];
|
|
32700
|
+
for (const match of input.scss.matchAll(SCSS_USE_AS_RE)) {
|
|
32701
|
+
if (match.index === void 0) continue;
|
|
32702
|
+
const ns = match[1];
|
|
32703
|
+
const usagePattern = new RegExp(`(?:^|[^\\w-])${ns}\\.`, "g");
|
|
32704
|
+
let used = false;
|
|
32705
|
+
for (const usageMatch of input.scss.matchAll(usagePattern)) {
|
|
32706
|
+
if (usageMatch.index === void 0) continue;
|
|
32707
|
+
const lineStart = input.scss.lastIndexOf("\n", usageMatch.index) + 1;
|
|
32708
|
+
const lineEndRaw = input.scss.indexOf("\n", usageMatch.index);
|
|
32709
|
+
const lineEnd = lineEndRaw === -1 ? input.scss.length : lineEndRaw;
|
|
32710
|
+
const line = input.scss.slice(lineStart, lineEnd);
|
|
32711
|
+
if (/^\s*@use\b/.test(line)) continue;
|
|
32712
|
+
used = true;
|
|
32713
|
+
break;
|
|
32714
|
+
}
|
|
32715
|
+
if (!used) {
|
|
32716
|
+
matches.push({
|
|
32717
|
+
id: "unused-scss-use",
|
|
32718
|
+
severity: "info",
|
|
32719
|
+
title: `Unused @use namespace \`${ns}\``,
|
|
32720
|
+
snippet: captureSnippet(input.scss, match.index, match[0].length),
|
|
32721
|
+
fix: `\`@use\` declares namespace \`${ns}\` but no \`${ns}.\` reference appears in this file. Remove the import to keep the file lean, or use it.`,
|
|
32722
|
+
seeAlsoSlugs: [],
|
|
32723
|
+
seeAlsoTokens: []
|
|
32724
|
+
});
|
|
32725
|
+
}
|
|
32726
|
+
}
|
|
32727
|
+
return matches;
|
|
32728
|
+
};
|
|
32729
|
+
var RAW_MAT_BUTTON_RE = /<button\b([^>]*?)\b(mat-stroked-button|mat-flat-button|mat-raised-button|mat-button)\b/gi;
|
|
32730
|
+
var rawMatButton = (input) => {
|
|
32731
|
+
const matches = [];
|
|
32732
|
+
for (const match of input.html.matchAll(RAW_MAT_BUTTON_RE)) {
|
|
32733
|
+
if (match.index === void 0) continue;
|
|
32734
|
+
const variant = match[2];
|
|
32735
|
+
const variantAttr = variant === "mat-stroked-button" ? "stroked" : variant === "mat-flat-button" ? "flat" : variant === "mat-raised-button" ? "raised" : "basic";
|
|
32736
|
+
matches.push({
|
|
32737
|
+
id: "raw-mat-button",
|
|
32738
|
+
severity: "warn",
|
|
32739
|
+
title: `Raw ${variant}`,
|
|
32740
|
+
snippet: captureSnippet(input.html, match.index, match[0].length),
|
|
32741
|
+
fix: `Use \`<dbx-button ${variantAttr}>\` instead of raw \`${variant}\`. \`<dbx-button>\` plugs into the action stack, accepts \`text\` / \`icon\` inputs, and inherits dbx-web theming.`,
|
|
32742
|
+
seeAlsoSlugs: ["button"],
|
|
32743
|
+
seeAlsoTokens: []
|
|
32744
|
+
});
|
|
32745
|
+
}
|
|
32746
|
+
return matches;
|
|
32747
|
+
};
|
|
32748
|
+
var HEADER_THEN_HINT_RE = /<(h[1-3])\b[^>]*>([\s\S]*?)<\/\1>\s*<(?:p|span)\b[^>]*>([\s\S]{1,200}?)<\/(?:p|span)>/gi;
|
|
32749
|
+
var customSectionHeader = (input) => {
|
|
32750
|
+
const matches = [];
|
|
32751
|
+
for (const match of input.html.matchAll(HEADER_THEN_HINT_RE)) {
|
|
32752
|
+
if (match.index === void 0) continue;
|
|
32753
|
+
const headerTag = match[1].toLowerCase();
|
|
32754
|
+
const isPageLevel = headerTag === "h1";
|
|
32755
|
+
matches.push({
|
|
32756
|
+
id: "custom-section-header",
|
|
32757
|
+
severity: "info",
|
|
32758
|
+
title: `Custom ${headerTag} + sibling hint text`,
|
|
32759
|
+
snippet: captureSnippet(input.html, match.index, match[0].length),
|
|
32760
|
+
fix: `Replace this header+hint pair with \`<${isPageLevel ? "dbx-section-page" : "dbx-section"} header="\u2026" hint="\u2026">\` \u2014 projected content lives inside, the typography and hint color come from dbx-web.`,
|
|
32761
|
+
seeAlsoSlugs: [isPageLevel ? "section-page" : "section"],
|
|
32762
|
+
seeAlsoTokens: ["--mat-sys-on-surface-variant"]
|
|
32763
|
+
});
|
|
32764
|
+
}
|
|
32765
|
+
return matches;
|
|
32766
|
+
};
|
|
32767
|
+
var TWO_COLUMN_GRID_RE = /grid-template-columns\s*:\s*(?:1fr\s+1fr|repeat\(\s*2\s*,)/gi;
|
|
32768
|
+
var customGridLayout = (input) => {
|
|
32769
|
+
const matches = [];
|
|
32770
|
+
for (const match of input.scss.matchAll(TWO_COLUMN_GRID_RE)) {
|
|
32771
|
+
if (match.index === void 0) continue;
|
|
32772
|
+
matches.push({
|
|
32773
|
+
id: "custom-grid-layout",
|
|
32774
|
+
severity: "info",
|
|
32775
|
+
title: "Custom two-column grid",
|
|
32776
|
+
snippet: captureSnippet(input.scss, match.index, match[0].length),
|
|
32777
|
+
fix: "For two-column layouts that should collapse on narrow viewports, prefer `[dbxFlexGroup] [breakToColumn]` on the parent and `[dbxFlexSize]` on each child. The directives handle responsive wrapping consistently across the app.",
|
|
32778
|
+
seeAlsoSlugs: ["flex-group", "flex-size"],
|
|
32779
|
+
seeAlsoTokens: []
|
|
32780
|
+
});
|
|
32781
|
+
}
|
|
32782
|
+
return matches;
|
|
32783
|
+
};
|
|
32784
|
+
var EYEBROW_TEXT_RE = /<span\b[^>]*?(?:class|style)=[^>]*?(?:text-transform\s*:\s*uppercase|uppercase)/gi;
|
|
32785
|
+
var eyebrowText = (input) => {
|
|
32786
|
+
const matches = [];
|
|
32787
|
+
for (const match of input.html.matchAll(EYEBROW_TEXT_RE)) {
|
|
32788
|
+
if (match.index === void 0) continue;
|
|
32789
|
+
matches.push({
|
|
32790
|
+
id: "eyebrow-text",
|
|
32791
|
+
severity: "info",
|
|
32792
|
+
title: "Eyebrow text (uppercase span above a heading)",
|
|
32793
|
+
snippet: captureSnippet(input.html, match.index, match[0].length),
|
|
32794
|
+
fix: 'No current dbx-web primitive wraps the "eyebrow" pattern (small uppercase label above a heading). Either keep it inline with `<dbx-label-block>` for now, or propose a `dbx-eyebrow` primitive in dbx-web.',
|
|
32795
|
+
seeAlsoSlugs: ["label-block"],
|
|
32796
|
+
seeAlsoTokens: ["--mat-sys-label-medium"]
|
|
32797
|
+
});
|
|
32798
|
+
}
|
|
32799
|
+
return matches;
|
|
32800
|
+
};
|
|
32801
|
+
var UI_SMELLS = [
|
|
32802
|
+
{ id: "card-surface-handrolled", detect: cardSurfaceHandrolled },
|
|
32803
|
+
{ id: "hardcoded-radius", detect: hardcodedRadius },
|
|
32804
|
+
{ id: "hardcoded-shadow", detect: hardcodedShadow },
|
|
32805
|
+
{ id: "hardcoded-hint-color", detect: hardcodedHintColor },
|
|
32806
|
+
{ id: "hardcoded-padding", detect: hardcodedPadding },
|
|
32807
|
+
{ id: "hardcoded-typography", detect: hardcodedTypography },
|
|
32808
|
+
{ id: "pit-instead-of-tinted-bg", detect: pitInsteadOfTintedBg },
|
|
32809
|
+
{ id: "flex-column-with-gap-as-card-stack", detect: flexColumnWithGap },
|
|
32810
|
+
{ id: "mdc-token-override-instead-of-wrapper", detect: mdcTokenOverride },
|
|
32811
|
+
{ id: "hardcoded-hex-brand-color", detect: hardcodedHexBrand },
|
|
32812
|
+
{ id: "empty-ruleset", detect: emptyRuleset },
|
|
32813
|
+
{ id: "unused-scss-use", detect: unusedScssUse },
|
|
32814
|
+
{ id: "raw-mat-button", detect: rawMatButton },
|
|
32815
|
+
{ id: "custom-section-header", detect: customSectionHeader },
|
|
32816
|
+
{ id: "custom-grid-layout", detect: customGridLayout },
|
|
32817
|
+
{ id: "eyebrow-text", detect: eyebrowText }
|
|
32818
|
+
];
|
|
32819
|
+
function detectSmells(input) {
|
|
32820
|
+
const matches = [];
|
|
32821
|
+
for (const smell of UI_SMELLS) {
|
|
32822
|
+
const found = smell.detect(input);
|
|
32823
|
+
for (const match of found) matches.push(match);
|
|
32824
|
+
}
|
|
32825
|
+
return matches;
|
|
32826
|
+
}
|
|
32827
|
+
|
|
32828
|
+
// packages/dbx-components-mcp/src/tools/ui-smell-check/format.ts
|
|
32829
|
+
function formatSmellResult(input, matches, tokenRegistry) {
|
|
32830
|
+
const sections = [];
|
|
32831
|
+
const title = "# UI smell check";
|
|
32832
|
+
sections.push(title);
|
|
32833
|
+
if (input.context !== void 0 && input.context.length > 0) {
|
|
32834
|
+
sections.push(`_Context:_ ${input.context}`);
|
|
32835
|
+
}
|
|
32836
|
+
if (matches.length === 0) {
|
|
32837
|
+
const goodSignals = formatGoodSignals(input.html, input.scss);
|
|
32838
|
+
if (goodSignals !== null) {
|
|
32839
|
+
sections.push("", "No smells detected.", "", goodSignals, "", "For a token recommendation, call `dbx_css_token_lookup` with an `intent` or `value`.");
|
|
32840
|
+
} else {
|
|
32841
|
+
sections.push("", "No smells detected against the v1 catalog. If you still want a token recommendation, call `dbx_css_token_lookup` with an `intent` or `value`.");
|
|
32842
|
+
}
|
|
32843
|
+
} else {
|
|
32844
|
+
sections.push("", "## Detected smells", "");
|
|
32845
|
+
for (const match of matches) {
|
|
32846
|
+
sections.push(formatMatch(match));
|
|
32847
|
+
}
|
|
32848
|
+
const tokenTable = formatTokenTable(matches, tokenRegistry);
|
|
32849
|
+
if (tokenTable !== null) {
|
|
32850
|
+
sections.push("", "## Tokens to use", "", tokenTable);
|
|
32851
|
+
}
|
|
32852
|
+
const infoOnly = matches.filter((m) => m.severity === "info");
|
|
32853
|
+
if (infoOnly.length > 0) {
|
|
32854
|
+
sections.push("", "## No-match notes", "");
|
|
32855
|
+
for (const match of infoOnly) {
|
|
32856
|
+
sections.push(`- **${match.id}** \u2014 ${match.title}`);
|
|
32857
|
+
}
|
|
32858
|
+
}
|
|
32859
|
+
}
|
|
32860
|
+
return sections.join("\n");
|
|
32861
|
+
}
|
|
32862
|
+
function formatMatch(match) {
|
|
32863
|
+
const lines = [`### ${match.id} \xB7 ${match.severity}`, "", match.title, "", "```", match.snippet, "```", "", match.fix];
|
|
32864
|
+
if (match.seeAlsoSlugs.length > 0 || match.seeAlsoTokens.length > 0) {
|
|
32865
|
+
const refs = [];
|
|
32866
|
+
for (const slug of match.seeAlsoSlugs) {
|
|
32867
|
+
refs.push(`\`dbx_ui_lookup topic="${slug}"\``);
|
|
32868
|
+
}
|
|
32869
|
+
for (const token of match.seeAlsoTokens) {
|
|
32870
|
+
refs.push(`\`dbx_css_token_lookup value="${token}"\``);
|
|
32871
|
+
}
|
|
32872
|
+
lines.push("", `See also: ${refs.join(", ")}`);
|
|
32873
|
+
}
|
|
32874
|
+
lines.push("");
|
|
32875
|
+
return lines.join("\n");
|
|
32876
|
+
}
|
|
32877
|
+
function formatGoodSignals(html, scss) {
|
|
32878
|
+
let result = null;
|
|
32879
|
+
if (html.length > 0 || scss.length > 0) {
|
|
32880
|
+
const lines = [];
|
|
32881
|
+
if (html.length > 0) {
|
|
32882
|
+
const elements = /* @__PURE__ */ new Map();
|
|
32883
|
+
for (const match of html.matchAll(/<(dbx-[\w-]+)\b/g)) {
|
|
32884
|
+
const tag = match[1].toLowerCase();
|
|
32885
|
+
elements.set(tag, (elements.get(tag) ?? 0) + 1);
|
|
32886
|
+
}
|
|
32887
|
+
if (elements.size > 0) {
|
|
32888
|
+
const summary = Array.from(elements.entries()).sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([tag, n]) => `${tag} \xD7${n}`).join(", ");
|
|
32889
|
+
lines.push(`- HTML uses: ${summary}`);
|
|
32890
|
+
} else {
|
|
32891
|
+
lines.push("- HTML uses: no `dbx-*` elements");
|
|
32892
|
+
}
|
|
32893
|
+
}
|
|
32894
|
+
if (scss.length > 0) {
|
|
32895
|
+
let dbx = 0;
|
|
32896
|
+
let matSys = 0;
|
|
32897
|
+
for (const match of scss.matchAll(/var\(\s*(--[\w-]+)/g)) {
|
|
32898
|
+
const name = match[1];
|
|
32899
|
+
if (name.startsWith("--dbx-")) dbx += 1;
|
|
32900
|
+
else if (name.startsWith("--mat-sys-")) matSys += 1;
|
|
32901
|
+
}
|
|
32902
|
+
lines.push(`- SCSS uses: ${dbx} \`--dbx-*\` reference${dbx === 1 ? "" : "s"}, ${matSys} \`--mat-sys-*\` reference${matSys === 1 ? "" : "s"}`);
|
|
32903
|
+
}
|
|
32904
|
+
if (lines.length > 0) {
|
|
32905
|
+
result = `Good signals:
|
|
32906
|
+
${lines.join("\n")}`;
|
|
32907
|
+
}
|
|
32908
|
+
}
|
|
32909
|
+
return result;
|
|
32910
|
+
}
|
|
32911
|
+
function formatTokenTable(matches, _tokenRegistry) {
|
|
32912
|
+
const rows = [];
|
|
32913
|
+
const seen = /* @__PURE__ */ new Set();
|
|
32914
|
+
for (const match of matches) {
|
|
32915
|
+
for (const token of match.seeAlsoTokens) {
|
|
32916
|
+
if (seen.has(token)) continue;
|
|
32917
|
+
seen.add(token);
|
|
32918
|
+
rows.push(`| ${match.id} | \`var(${token})\` |`);
|
|
32919
|
+
}
|
|
32920
|
+
}
|
|
32921
|
+
let result;
|
|
32922
|
+
if (rows.length === 0) {
|
|
32923
|
+
result = null;
|
|
32924
|
+
} else {
|
|
32925
|
+
result = ["| Smell | Recommended var |", "| --- | --- |", ...rows].join("\n");
|
|
32926
|
+
}
|
|
32927
|
+
return result;
|
|
32928
|
+
}
|
|
32929
|
+
|
|
32930
|
+
// packages/dbx-components-mcp/src/tools/ui-smell-check.tool.ts
|
|
32931
|
+
var DBX_UI_SMELL_CHECK_TOOL = {
|
|
32932
|
+
name: "dbx_ui_smell_check",
|
|
32933
|
+
description: [
|
|
32934
|
+
"Reverse-lookup: paste component HTML and/or SCSS and get back the dbx-web smells you triggered, plus the canonical fix.",
|
|
32935
|
+
"",
|
|
32936
|
+
"Run this after writing component SCSS \u2014 it flags hand-rolled card surfaces, raw `mat-button` usages, hardcoded paddings/radii/shadows/colors that map to existing tokens, MDC token overrides that should be a host attribute or wrapper, and other patterns that already have a dbx-web primitive.",
|
|
32937
|
+
"",
|
|
32938
|
+
"Pass either `html` / `scss` (inline strings) or `htmlPath` / `scssPath` (read from disk, relative to cwd or absolute). Prefer paths for files larger than ~1KB to keep the tool input small. Optional `context` is a one-liner about what the component is for (informational \u2014 does not change detection).",
|
|
32939
|
+
"",
|
|
32940
|
+
"Project-local conventions (e.g. wrapper class names) can be supplied via `projectConventions` or read from `dbx-mcp.config.json` `uiSmellCheck.projectConventions`."
|
|
32941
|
+
].join("\n"),
|
|
32942
|
+
inputSchema: {
|
|
32943
|
+
type: "object",
|
|
32944
|
+
properties: {
|
|
32945
|
+
html: { type: "string", description: "Component HTML (optional). Mutually exclusive with `htmlPath`." },
|
|
32946
|
+
scss: { type: "string", description: "Component SCSS (optional). Mutually exclusive with `scssPath`." },
|
|
32947
|
+
htmlPath: { type: "string", description: "Path to a component HTML file. Resolved relative to the MCP cwd, or used as-is when absolute. Mutually exclusive with `html`." },
|
|
32948
|
+
scssPath: { type: "string", description: "Path to a component SCSS/CSS file. Resolved relative to the MCP cwd, or used as-is when absolute. Mutually exclusive with `scss`." },
|
|
32949
|
+
context: { type: "string", description: "Optional one-liner about what the component is for." },
|
|
32950
|
+
projectConventions: {
|
|
32951
|
+
type: "object",
|
|
32952
|
+
description: "Optional project-local convention overrides \u2014 wins over the config-file defaults.",
|
|
32953
|
+
properties: {
|
|
32954
|
+
cardWrapperClasses: { type: "array", items: { type: "string" } }
|
|
32955
|
+
}
|
|
32956
|
+
}
|
|
32957
|
+
}
|
|
32958
|
+
}
|
|
32959
|
+
};
|
|
32960
|
+
var SmellCheckArgs = type67({
|
|
32961
|
+
"html?": "string",
|
|
32962
|
+
"scss?": "string",
|
|
32963
|
+
"htmlPath?": "string",
|
|
32964
|
+
"scssPath?": "string",
|
|
32965
|
+
"context?": "string",
|
|
32966
|
+
"projectConventions?": type67({ "cardWrapperClasses?": "string[]" })
|
|
32967
|
+
});
|
|
32968
|
+
function parseArgs12(raw, defaults) {
|
|
32969
|
+
const parsed = SmellCheckArgs(raw);
|
|
32970
|
+
if (parsed instanceof type67.errors) {
|
|
32971
|
+
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
32972
|
+
}
|
|
32973
|
+
const html = parsed.html ?? "";
|
|
32974
|
+
const scss = parsed.scss ?? "";
|
|
32975
|
+
const merged = {
|
|
32976
|
+
cardWrapperClasses: parsed.projectConventions?.cardWrapperClasses ?? defaults.cardWrapperClasses
|
|
32977
|
+
};
|
|
32978
|
+
return { html, scss, htmlPath: parsed.htmlPath, scssPath: parsed.scssPath, context: parsed.context, conventions: merged };
|
|
32979
|
+
}
|
|
32980
|
+
var DEFAULT_READ_FILE12 = (path) => nodeReadFile8(path, "utf-8");
|
|
32981
|
+
async function readPathInput(path, cwd, readFile20) {
|
|
32982
|
+
const absolute = isAbsolute10(path) ? path : resolve40(cwd, path);
|
|
32983
|
+
return readFile20(absolute);
|
|
32984
|
+
}
|
|
32985
|
+
function createUiSmellCheckTool(input) {
|
|
32986
|
+
const { tokenRegistry, uiComponentRegistry, cwd, readFile: readFile20 } = input;
|
|
32987
|
+
const run15 = async (rawArgs) => {
|
|
32988
|
+
let conventionsFromConfig = {};
|
|
32989
|
+
try {
|
|
32990
|
+
const configResult = await findAndLoadConfig({ cwd: cwd ?? process.cwd(), readFile: readFile20 });
|
|
32991
|
+
const block = configResult.config?.uiSmellCheck?.projectConventions;
|
|
32992
|
+
if (block !== void 0) {
|
|
32993
|
+
conventionsFromConfig = block;
|
|
32994
|
+
}
|
|
32995
|
+
} catch {
|
|
32996
|
+
conventionsFromConfig = {};
|
|
32997
|
+
}
|
|
32998
|
+
let args;
|
|
32999
|
+
try {
|
|
33000
|
+
args = parseArgs12(rawArgs, conventionsFromConfig);
|
|
33001
|
+
} catch (error) {
|
|
33002
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
33003
|
+
return toolError(message);
|
|
33004
|
+
}
|
|
33005
|
+
if (args.html.length > 0 && args.htmlPath !== void 0) {
|
|
33006
|
+
return toolError("dbx_ui_smell_check: provide either `html` or `htmlPath`, not both.");
|
|
33007
|
+
}
|
|
33008
|
+
if (args.scss.length > 0 && args.scssPath !== void 0) {
|
|
33009
|
+
return toolError("dbx_ui_smell_check: provide either `scss` or `scssPath`, not both.");
|
|
33010
|
+
}
|
|
33011
|
+
const resolvedCwd = cwd ?? process.cwd();
|
|
33012
|
+
const reader = readFile20 ?? DEFAULT_READ_FILE12;
|
|
33013
|
+
let html = args.html;
|
|
33014
|
+
let scss = args.scss;
|
|
33015
|
+
if (args.htmlPath !== void 0) {
|
|
33016
|
+
try {
|
|
33017
|
+
html = await readPathInput(args.htmlPath, resolvedCwd, reader);
|
|
33018
|
+
} catch (error) {
|
|
33019
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
33020
|
+
return toolError(`dbx_ui_smell_check: failed to read htmlPath \`${args.htmlPath}\`: ${message}`);
|
|
33021
|
+
}
|
|
33022
|
+
}
|
|
33023
|
+
if (args.scssPath !== void 0) {
|
|
33024
|
+
try {
|
|
33025
|
+
scss = await readPathInput(args.scssPath, resolvedCwd, reader);
|
|
33026
|
+
} catch (error) {
|
|
33027
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
33028
|
+
return toolError(`dbx_ui_smell_check: failed to read scssPath \`${args.scssPath}\`: ${message}`);
|
|
33029
|
+
}
|
|
33030
|
+
}
|
|
33031
|
+
if (html.length === 0 && scss.length === 0) {
|
|
33032
|
+
return toolError("dbx_ui_smell_check: provide at least one of `html`, `scss`, `htmlPath`, or `scssPath`.");
|
|
33033
|
+
}
|
|
33034
|
+
const matches = detectSmells({
|
|
33035
|
+
html,
|
|
33036
|
+
scss,
|
|
33037
|
+
conventions: args.conventions,
|
|
33038
|
+
tokenRegistry,
|
|
33039
|
+
uiComponentRegistry
|
|
33040
|
+
});
|
|
33041
|
+
const text = formatSmellResult({ html, scss, context: args.context }, matches, tokenRegistry);
|
|
33042
|
+
return { content: [{ type: "text", text }] };
|
|
33043
|
+
};
|
|
33044
|
+
return { definition: DBX_UI_SMELL_CHECK_TOOL, run: run15 };
|
|
33045
|
+
}
|
|
33046
|
+
|
|
33047
|
+
// packages/dbx-components-mcp/src/tools/index.ts
|
|
33048
|
+
var DBX_TOOLS = [
|
|
33049
|
+
// form
|
|
33050
|
+
formExamplesTool,
|
|
33051
|
+
// ui
|
|
33052
|
+
uiExamplesTool,
|
|
33053
|
+
// model
|
|
33054
|
+
lookupModelTool,
|
|
33055
|
+
searchModelTool,
|
|
33056
|
+
modelDecodeTool,
|
|
33057
|
+
modelValidateApiTool,
|
|
33058
|
+
modelApiListAppTool,
|
|
33059
|
+
modelApiLookupTool,
|
|
33060
|
+
modelApiValidateAppTool,
|
|
33061
|
+
modelValidateFolderTool,
|
|
33062
|
+
modelStoreScaffoldTool,
|
|
33063
|
+
modelFixtureListAppTool,
|
|
33064
|
+
modelFixtureLookupTool,
|
|
33065
|
+
modelFixtureScaffoldTool,
|
|
33066
|
+
modelFixtureForwardTool,
|
|
33067
|
+
modelTestTreeTool,
|
|
33068
|
+
modelTestSearchTool,
|
|
33069
|
+
// storagefile_m (model extension)
|
|
33070
|
+
storageFileMValidateAppTool,
|
|
33071
|
+
storageFileMListAppTool,
|
|
33072
|
+
storageFileMValidateFolderTool,
|
|
33073
|
+
// notification_m (model extension)
|
|
33074
|
+
notificationMValidateAppTool,
|
|
33075
|
+
notificationMListAppTool,
|
|
33076
|
+
notificationMValidateFolderTool,
|
|
33077
|
+
// system_m (model extension)
|
|
33078
|
+
systemMValidateFolderTool,
|
|
33079
|
+
// action
|
|
33080
|
+
actionExamplesTool,
|
|
33081
|
+
actionScaffoldTool,
|
|
33082
|
+
// route
|
|
33083
|
+
routeTreeTool,
|
|
33084
|
+
routeLookupTool,
|
|
33085
|
+
routeSearchTool,
|
|
33086
|
+
// filter
|
|
33087
|
+
filterScaffoldTool,
|
|
33088
|
+
// artifact (cross-domain dispatchers)
|
|
33089
|
+
artifactScaffoldTool,
|
|
33090
|
+
artifactFileConventionTool,
|
|
33091
|
+
// rule catalog (cross-domain reference)
|
|
33092
|
+
explainRuleTool,
|
|
33093
|
+
// aggregate orchestrator
|
|
33094
|
+
appValidateTool,
|
|
33095
|
+
// downstream component introspection
|
|
33096
|
+
modelListComponentTool,
|
|
31400
33097
|
serverActionsListAppTool,
|
|
31401
33098
|
// workspace config audit / setup
|
|
31402
33099
|
mcpConfigTool
|
|
@@ -31424,6 +33121,12 @@ function registerTools(server, options = {}) {
|
|
|
31424
33121
|
if (options.filterRegistry !== void 0) {
|
|
31425
33122
|
tools.push(createLookupFilterTool({ registry: options.filterRegistry }));
|
|
31426
33123
|
}
|
|
33124
|
+
if (options.tokenRegistry !== void 0) {
|
|
33125
|
+
tools.push(createCssTokenLookupTool({ registry: options.tokenRegistry }));
|
|
33126
|
+
if (options.uiComponentRegistry !== void 0) {
|
|
33127
|
+
tools.push(createUiSmellCheckTool({ tokenRegistry: options.tokenRegistry, uiComponentRegistry: options.uiComponentRegistry, cwd: options.cwd }));
|
|
33128
|
+
}
|
|
33129
|
+
}
|
|
31427
33130
|
underlyingServer.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
31428
33131
|
return { tools: tools.map((t) => t.definition) };
|
|
31429
33132
|
});
|
|
@@ -31464,6 +33167,11 @@ Resource URIs are namespaced by domain:
|
|
|
31464
33167
|
- dbx://ui/components[/{slug}|/category/{category}|/kind/{kind}]
|
|
31465
33168
|
- dbx://pipe/entries[/{slug}|/category/{category}]
|
|
31466
33169
|
- dbx://filter/entries[/{slug}|/kind/{kind}]
|
|
33170
|
+
- dbx://token/entries[/{cssVariable}|/source/{source}|/role/{role}]
|
|
33171
|
+
|
|
33172
|
+
UI styling reverse/forward lookup:
|
|
33173
|
+
- dbx_css_token_lookup \u2014 forward: intent/value/role/component \u2192 recommended \`var(--\u2026)\` + utility class + dbx-web primitive.
|
|
33174
|
+
- dbx_ui_smell_check \u2014 reverse: paste component HTML/SCSS, get smells + canonical fix. **Run this after writing component SCSS** so hardcoded paddings/radii/shadows/colors get caught before they ship.
|
|
31467
33175
|
|
|
31468
33176
|
Fall back to dbx-components prose skills only for content this server doesn't carry: Firestore security rules, multi-file orchestration walkthroughs, model design phase, naming/tier checklists, and decision/why content beyond catalog lookup.`;
|
|
31469
33177
|
async function createServer(options = {}) {
|
|
@@ -31592,12 +33300,30 @@ async function createServer(options = {}) {
|
|
|
31592
33300
|
filterRegistry = void 0;
|
|
31593
33301
|
}
|
|
31594
33302
|
}
|
|
33303
|
+
let tokenRegistry = options.tokenRegistry;
|
|
33304
|
+
if (tokenRegistry === void 0) {
|
|
33305
|
+
const cwd = options.cwd ?? process.cwd();
|
|
33306
|
+
try {
|
|
33307
|
+
const tokenLoaderResult = await loadTokenRegistry({ cwd });
|
|
33308
|
+
if (options.onTokenLoaderResult === void 0) {
|
|
33309
|
+
reportTokenLoaderResult(tokenLoaderResult);
|
|
33310
|
+
} else {
|
|
33311
|
+
options.onTokenLoaderResult(tokenLoaderResult);
|
|
33312
|
+
}
|
|
33313
|
+
tokenRegistry = tokenLoaderResult.registry;
|
|
33314
|
+
} catch (error) {
|
|
33315
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
33316
|
+
process.stderr.write(`[dbx-components-mcp] tokens registry unavailable: ${message}
|
|
33317
|
+
`);
|
|
33318
|
+
tokenRegistry = void 0;
|
|
33319
|
+
}
|
|
33320
|
+
}
|
|
31595
33321
|
const fixtureModelRegistry = {
|
|
31596
33322
|
entries: FIREBASE_MODELS.map((m) => ({ name: m.name, modelType: m.modelType, collectionPrefix: m.collectionPrefix }))
|
|
31597
33323
|
};
|
|
31598
33324
|
await emitDownstreamHints({ cwd: options.cwd ?? process.cwd(), externalCounts, onDownstreamHints: options.onDownstreamHints });
|
|
31599
|
-
registerResources(server, { semanticTypeRegistry: registry, forgeFieldRegistry: forgeRegistry, pipeRegistry, uiComponentRegistry: uiRegistry, actionRegistry, filterRegistry });
|
|
31600
|
-
registerTools(server, { semanticTypeRegistry: registry, forgeFieldRegistry: forgeRegistry, pipeRegistry, uiComponentRegistry: uiRegistry, actionRegistry, filterRegistry, fixtureModelRegistry, modelValidateRuleOptions });
|
|
33325
|
+
registerResources(server, { semanticTypeRegistry: registry, forgeFieldRegistry: forgeRegistry, pipeRegistry, uiComponentRegistry: uiRegistry, actionRegistry, filterRegistry, tokenRegistry });
|
|
33326
|
+
registerTools(server, { semanticTypeRegistry: registry, forgeFieldRegistry: forgeRegistry, pipeRegistry, uiComponentRegistry: uiRegistry, actionRegistry, filterRegistry, tokenRegistry, fixtureModelRegistry, modelValidateRuleOptions, cwd: options.cwd ?? process.cwd() });
|
|
31601
33327
|
return server;
|
|
31602
33328
|
}
|
|
31603
33329
|
function resolveModelValidateRuleOptions(config) {
|
|
@@ -31701,6 +33427,20 @@ function reportFilterLoaderResult(result) {
|
|
|
31701
33427
|
`);
|
|
31702
33428
|
}
|
|
31703
33429
|
}
|
|
33430
|
+
function reportTokenLoaderResult(result) {
|
|
33431
|
+
const { registry, configPath, configWarnings, loaderWarnings, externalSourceCount } = result;
|
|
33432
|
+
const summary = [`[dbx-components-mcp] tokens registry loaded`, ` sources: ${registry.loadedSources.join(", ") || "(none)"}`, ` external: ${externalSourceCount}`, ` config: ${configPath ?? "(none)"}`, ` entries: ${registry.all.length}`, ` warnings: ${configWarnings.length + loaderWarnings.length}`].join("\n");
|
|
33433
|
+
process.stderr.write(`${summary}
|
|
33434
|
+
`);
|
|
33435
|
+
for (const warning of configWarnings) {
|
|
33436
|
+
process.stderr.write(`[dbx-components-mcp] tokens-config-warning: ${warning.kind} ${warning.path}
|
|
33437
|
+
`);
|
|
33438
|
+
}
|
|
33439
|
+
for (const warning of loaderWarnings) {
|
|
33440
|
+
process.stderr.write(`[dbx-components-mcp] tokens-loader-warning: ${warning.kind}
|
|
33441
|
+
`);
|
|
33442
|
+
}
|
|
33443
|
+
}
|
|
31704
33444
|
var HINT_CLUSTER_LABEL = {
|
|
31705
33445
|
semanticTypes: "semantic-types",
|
|
31706
33446
|
uiComponents: "ui-components",
|