@dereekb/dbx-components-mcp 13.10.0 → 13.10.2

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.
@@ -5,10 +5,10 @@ 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.0",
8
+ version: "13.10.2",
9
9
  type: "module",
10
10
  bin: {
11
- "dbx-components-mcp": "./dbx-components-mcp.js"
11
+ "dbx-components-mcp": "dbx-components-mcp.js"
12
12
  },
13
13
  dependencies: {
14
14
  "@modelcontextprotocol/sdk": "^1.0.0",
@@ -799,10 +799,10 @@ var defaultGlobber = async (input) => {
799
799
  }
800
800
  return matches;
801
801
  };
802
- async function loadPackageName(packagePath, readFile6) {
802
+ async function loadPackageName(packagePath, readFile8) {
803
803
  let raw = null;
804
804
  try {
805
- raw = await readFile6(packagePath);
805
+ raw = await readFile8(packagePath);
806
806
  } catch {
807
807
  raw = null;
808
808
  }
@@ -862,15 +862,15 @@ function globToRegex(pattern) {
862
862
  var DEFAULT_READ_FILE = defaultReadFile;
863
863
  var DEFAULT_GLOBBER = defaultGlobber;
864
864
  async function buildForgeFieldsManifest(input) {
865
- const { projectRoot, generator, readFile: readFile6 = DEFAULT_READ_FILE, globber = DEFAULT_GLOBBER, now = () => /* @__PURE__ */ new Date() } = input;
865
+ const { projectRoot, generator, readFile: readFile8 = DEFAULT_READ_FILE, globber = DEFAULT_GLOBBER, now = () => /* @__PURE__ */ new Date() } = input;
866
866
  const configPath = resolve(projectRoot, FORGE_FIELDS_SCAN_CONFIG_FILENAME);
867
867
  const packagePath = resolve(projectRoot, "package.json");
868
- const configOutcome = await loadScanConfig(configPath, readFile6);
868
+ const configOutcome = await loadScanConfig(configPath, readFile8);
869
869
  if (configOutcome.kind !== "ok") {
870
870
  return configOutcome.outcome;
871
871
  }
872
872
  const scanSection = configOutcome.section;
873
- const packageOutcome = await loadPackageName(packagePath, readFile6);
873
+ const packageOutcome = await loadPackageName(packagePath, readFile8);
874
874
  if (packageOutcome.kind !== "ok") {
875
875
  return packageOutcome.outcome;
876
876
  }
@@ -883,7 +883,7 @@ async function buildForgeFieldsManifest(input) {
883
883
  const project = new Project({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
884
884
  for (const relPath of filePaths) {
885
885
  const absolute = resolve(projectRoot, relPath);
886
- const text = await readFile6(absolute);
886
+ const text = await readFile8(absolute);
887
887
  project.createSourceFile(absolute, text, { overwrite: true });
888
888
  }
889
889
  const extractResult = extractForgeFieldEntries({ project });
@@ -914,10 +914,10 @@ async function buildForgeFieldsManifest(input) {
914
914
  }
915
915
  return outcome;
916
916
  }
917
- async function loadScanConfig(configPath, readFile6) {
917
+ async function loadScanConfig(configPath, readFile8) {
918
918
  let raw = null;
919
919
  try {
920
- raw = await readFile6(configPath);
920
+ raw = await readFile8(configPath);
921
921
  } catch {
922
922
  raw = null;
923
923
  }
@@ -983,7 +983,7 @@ import { resolve as resolve2 } from "node:path";
983
983
  var DEFAULT_READ_FILE2 = (path) => nodeReadFile2(path, "utf-8");
984
984
  var DEFAULT_WRITE_FILE = (path, data) => nodeWriteFile(path, data, "utf-8");
985
985
  async function runScanCliBase(input, config) {
986
- const { argv, cwd, generator, readFile: readFile6 = DEFAULT_READ_FILE2, writeFile = DEFAULT_WRITE_FILE, globber, now, log = console.log, errorLog = console.error } = input;
986
+ const { argv, cwd, generator, readFile: readFile8 = DEFAULT_READ_FILE2, writeFile: writeFile2 = DEFAULT_WRITE_FILE, globber, now, log = console.log, errorLog = console.error } = input;
987
987
  let result;
988
988
  const args = parseScanArgs(argv);
989
989
  if (args.kind === "parse-error") {
@@ -999,8 +999,8 @@ async function runScanCliBase(input, config) {
999
999
  result = { exitCode: 2 };
1000
1000
  } else {
1001
1001
  const projectRoot = resolve2(cwd, args.project);
1002
- const outcome = await config.buildManifest({ projectRoot, generator, readFile: readFile6, globber, now });
1003
- result = await handleOutcome({ outcome, args, projectArg: args.project, readFile: readFile6, writeFile, log, errorLog, config });
1002
+ const outcome = await config.buildManifest({ projectRoot, generator, readFile: readFile8, globber, now });
1003
+ result = await handleOutcome({ outcome, args, projectArg: args.project, readFile: readFile8, writeFile: writeFile2, log, errorLog, config });
1004
1004
  }
1005
1005
  return result;
1006
1006
  }
@@ -1054,7 +1054,7 @@ function parseScanArgs(argv) {
1054
1054
  return result;
1055
1055
  }
1056
1056
  async function handleOutcome(input) {
1057
- const { outcome, args, projectArg, readFile: readFile6, writeFile, log, errorLog, config } = input;
1057
+ const { outcome, args, projectArg, readFile: readFile8, writeFile: writeFile2, log, errorLog, config } = input;
1058
1058
  let result;
1059
1059
  if (outcome.kind === "success") {
1060
1060
  const finalOutPath = args.out === void 0 ? outcome.outPath : resolve2(outcome.outPath, "..", args.out);
@@ -1062,7 +1062,7 @@ async function handleOutcome(input) {
1062
1062
  if (args.check) {
1063
1063
  let existing = null;
1064
1064
  try {
1065
- existing = await readFile6(finalOutPath);
1065
+ existing = await readFile8(finalOutPath);
1066
1066
  } catch {
1067
1067
  existing = null;
1068
1068
  }
@@ -1076,7 +1076,7 @@ async function handleOutcome(input) {
1076
1076
  result = { exitCode: 1 };
1077
1077
  }
1078
1078
  } else {
1079
- await writeFile(finalOutPath, serialized);
1079
+ await writeFile2(finalOutPath, serialized);
1080
1080
  log(`Wrote manifest: ${finalOutPath} (${outcome.manifest.entries.length} entries, ${outcome.scannedFileCount} files scanned)`);
1081
1081
  for (const warning of outcome.extractWarnings) {
1082
1082
  errorLog(`extract-warning: ${config.formatExtractWarning(warning)}`);
@@ -1334,8 +1334,8 @@ function parseExampleTag(text) {
1334
1334
  let result;
1335
1335
  if (fenceMatch) {
1336
1336
  const caption = fenceMatch[1].trim();
1337
- const code10 = fenceMatch[2];
1338
- result = caption.length > 0 ? { caption, code: code10 } : { code: code10 };
1337
+ const code11 = fenceMatch[2];
1338
+ result = caption.length > 0 ? { caption, code: code11 } : { code: code11 };
1339
1339
  } else {
1340
1340
  const standaloneFence = /^```[a-zA-Z]*\n([\s\S]*?)\n```\s*$/.exec(trimmed);
1341
1341
  if (standaloneFence) {
@@ -1542,15 +1542,15 @@ var SCAN_CONFIG_FILENAME = "dbx-mcp.scan.json";
1542
1542
  var DEFAULT_READ_FILE3 = defaultReadFile;
1543
1543
  var DEFAULT_GLOBBER2 = defaultGlobber;
1544
1544
  async function buildManifest(input) {
1545
- const { projectRoot, generator, readFile: readFile6 = DEFAULT_READ_FILE3, globber = DEFAULT_GLOBBER2, now = () => /* @__PURE__ */ new Date() } = input;
1545
+ const { projectRoot, generator, readFile: readFile8 = DEFAULT_READ_FILE3, globber = DEFAULT_GLOBBER2, now = () => /* @__PURE__ */ new Date() } = input;
1546
1546
  const configPath = resolve3(projectRoot, SCAN_CONFIG_FILENAME);
1547
1547
  const packagePath = resolve3(projectRoot, "package.json");
1548
- const configOutcome = await loadScanConfig2(configPath, readFile6);
1548
+ const configOutcome = await loadScanConfig2(configPath, readFile8);
1549
1549
  if (configOutcome.kind !== "ok") {
1550
1550
  return configOutcome.outcome;
1551
1551
  }
1552
1552
  const scanConfig = configOutcome.config;
1553
- const packageOutcome = await loadPackageName(packagePath, readFile6);
1553
+ const packageOutcome = await loadPackageName(packagePath, readFile8);
1554
1554
  if (packageOutcome.kind !== "ok") {
1555
1555
  return packageOutcome.outcome;
1556
1556
  }
@@ -1563,7 +1563,7 @@ async function buildManifest(input) {
1563
1563
  const project = new Project2({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
1564
1564
  for (const relPath of filePaths) {
1565
1565
  const absolute = resolve3(projectRoot, relPath);
1566
- const text = await readFile6(absolute);
1566
+ const text = await readFile8(absolute);
1567
1567
  project.createSourceFile(absolute, text, { overwrite: true });
1568
1568
  }
1569
1569
  const extracted = extractEntries({ project });
@@ -1592,10 +1592,10 @@ async function buildManifest(input) {
1592
1592
  }
1593
1593
  return outcome;
1594
1594
  }
1595
- async function loadScanConfig2(configPath, readFile6) {
1595
+ async function loadScanConfig2(configPath, readFile8) {
1596
1596
  let raw = null;
1597
1597
  try {
1598
- raw = await readFile6(configPath);
1598
+ raw = await readFile8(configPath);
1599
1599
  } catch {
1600
1600
  raw = null;
1601
1601
  }
@@ -1667,7 +1667,7 @@ var USAGE2 = [
1667
1667
  var DEFAULT_READ_FILE4 = (path) => nodeReadFile3(path, "utf-8");
1668
1668
  var DEFAULT_WRITE_FILE2 = (path, data) => nodeWriteFile2(path, data, "utf-8");
1669
1669
  async function runScanCli(input) {
1670
- const { argv, cwd, generator, readFile: readFile6 = DEFAULT_READ_FILE4, writeFile = DEFAULT_WRITE_FILE2, globber, now, log = console.log, errorLog = console.error } = input;
1670
+ const { argv, cwd, generator, readFile: readFile8 = DEFAULT_READ_FILE4, writeFile: writeFile2 = DEFAULT_WRITE_FILE2, globber, now, log = console.log, errorLog = console.error } = input;
1671
1671
  let result;
1672
1672
  const args = parseArgs(argv);
1673
1673
  if (args.kind === "parse-error") {
@@ -1683,8 +1683,8 @@ async function runScanCli(input) {
1683
1683
  result = { exitCode: 2 };
1684
1684
  } else {
1685
1685
  const projectRoot = resolve4(cwd, args.project);
1686
- const outcome = await buildManifest({ projectRoot, generator, readFile: readFile6, globber, now });
1687
- result = await handleOutcome2({ outcome, args, projectArg: args.project, readFile: readFile6, writeFile, log, errorLog });
1686
+ const outcome = await buildManifest({ projectRoot, generator, readFile: readFile8, globber, now });
1687
+ result = await handleOutcome2({ outcome, args, projectArg: args.project, readFile: readFile8, writeFile: writeFile2, log, errorLog });
1688
1688
  }
1689
1689
  return result;
1690
1690
  }
@@ -1738,24 +1738,24 @@ function parseArgs(argv) {
1738
1738
  return result;
1739
1739
  }
1740
1740
  async function handleSuccessOutcome(input) {
1741
- const { outcome, args, projectArg, readFile: readFile6, writeFile, log, errorLog } = input;
1741
+ const { outcome, args, projectArg, readFile: readFile8, writeFile: writeFile2, log, errorLog } = input;
1742
1742
  const finalOutPath = args.out === void 0 ? outcome.outPath : resolve4(outcome.outPath, "..", args.out);
1743
1743
  const serialized = serializeManifest(outcome.manifest);
1744
1744
  let result;
1745
1745
  if (args.check) {
1746
- result = await checkManifest({ finalOutPath, serialized, outcome, projectArg, readFile: readFile6, log, errorLog });
1746
+ result = await checkManifest({ finalOutPath, serialized, outcome, projectArg, readFile: readFile8, log, errorLog });
1747
1747
  } else {
1748
- await writeFile(finalOutPath, serialized);
1748
+ await writeFile2(finalOutPath, serialized);
1749
1749
  log(`Wrote manifest: ${finalOutPath} (${outcome.manifest.entries.length} entries, ${outcome.scannedFileCount} files scanned)`);
1750
1750
  result = { exitCode: 0 };
1751
1751
  }
1752
1752
  return result;
1753
1753
  }
1754
1754
  async function checkManifest(input) {
1755
- const { finalOutPath, serialized, outcome, projectArg, readFile: readFile6, log, errorLog } = input;
1755
+ const { finalOutPath, serialized, outcome, projectArg, readFile: readFile8, log, errorLog } = input;
1756
1756
  let existing;
1757
1757
  try {
1758
- existing = await readFile6(finalOutPath);
1758
+ existing = await readFile8(finalOutPath);
1759
1759
  } catch {
1760
1760
  existing = null;
1761
1761
  }
@@ -1950,13 +1950,13 @@ function parseDecoratorInput(property) {
1950
1950
  }
1951
1951
  }
1952
1952
  const required = requiredFromDecorator ?? !property.hasQuestionToken();
1953
- const type43 = property.getTypeNode()?.getText() ?? "unknown";
1953
+ const type48 = property.getTypeNode()?.getText() ?? "unknown";
1954
1954
  const initializer = property.getInitializer();
1955
1955
  const defaultValue = initializer === void 0 ? void 0 : initializer.getText();
1956
1956
  return {
1957
1957
  propertyName,
1958
1958
  alias: alias ?? propertyName,
1959
- type: type43,
1959
+ type: type48,
1960
1960
  required,
1961
1961
  description: readPropertyDescription(property),
1962
1962
  ...defaultValue === void 0 ? {} : { defaultValue }
@@ -2022,22 +2022,22 @@ function parseDecoratorOutput(property) {
2022
2022
  alias = decoratorArg.getLiteralText();
2023
2023
  }
2024
2024
  const initializer = property.getInitializer();
2025
- let type43 = "unknown";
2025
+ let type48 = "unknown";
2026
2026
  if (initializer !== void 0 && Node4.isNewExpression(initializer)) {
2027
2027
  const typeArgs = initializer.getTypeArguments();
2028
2028
  if (typeArgs.length > 0) {
2029
- type43 = typeArgs[0].getText();
2029
+ type48 = typeArgs[0].getText();
2030
2030
  }
2031
2031
  } else {
2032
2032
  const explicit = property.getTypeNode()?.getText();
2033
2033
  if (explicit !== void 0) {
2034
- type43 = explicit;
2034
+ type48 = explicit;
2035
2035
  }
2036
2036
  }
2037
2037
  return {
2038
2038
  propertyName,
2039
2039
  name: alias ?? propertyName,
2040
- type: type43,
2040
+ type: type48,
2041
2041
  description: readPropertyDescription(property)
2042
2042
  };
2043
2043
  }
@@ -2052,7 +2052,7 @@ function parseSignalOutput(property) {
2052
2052
  }
2053
2053
  const propertyName = property.getName();
2054
2054
  const typeArgs = initializer.getTypeArguments();
2055
- const type43 = typeArgs.length > 0 ? typeArgs[0].getText() : "void";
2055
+ const type48 = typeArgs.length > 0 ? typeArgs[0].getText() : "void";
2056
2056
  const args = initializer.getArguments();
2057
2057
  let alias;
2058
2058
  if (args.length > 0 && Node4.isObjectLiteralExpression(args[0])) {
@@ -2061,7 +2061,7 @@ function parseSignalOutput(property) {
2061
2061
  return {
2062
2062
  propertyName,
2063
2063
  name: alias ?? propertyName,
2064
- type: type43,
2064
+ type: type48,
2065
2065
  description: readPropertyDescription(property)
2066
2066
  };
2067
2067
  }
@@ -2448,15 +2448,15 @@ var UI_COMPONENTS_SCAN_CONFIG_FILENAME = "dbx-mcp.scan.json";
2448
2448
  var DEFAULT_READ_FILE5 = defaultReadFile;
2449
2449
  var DEFAULT_GLOBBER3 = defaultGlobber;
2450
2450
  async function buildUiComponentsManifest(input) {
2451
- const { projectRoot, generator, readFile: readFile6 = DEFAULT_READ_FILE5, globber = DEFAULT_GLOBBER3, now = () => /* @__PURE__ */ new Date() } = input;
2451
+ const { projectRoot, generator, readFile: readFile8 = DEFAULT_READ_FILE5, globber = DEFAULT_GLOBBER3, now = () => /* @__PURE__ */ new Date() } = input;
2452
2452
  const configPath = resolve5(projectRoot, UI_COMPONENTS_SCAN_CONFIG_FILENAME);
2453
2453
  const packagePath = resolve5(projectRoot, "package.json");
2454
- const configOutcome = await loadScanConfig3(configPath, readFile6);
2454
+ const configOutcome = await loadScanConfig3(configPath, readFile8);
2455
2455
  if (configOutcome.kind !== "ok") {
2456
2456
  return configOutcome.outcome;
2457
2457
  }
2458
2458
  const scanSection = configOutcome.section;
2459
- const packageOutcome = await loadPackageName(packagePath, readFile6);
2459
+ const packageOutcome = await loadPackageName(packagePath, readFile8);
2460
2460
  if (packageOutcome.kind !== "ok") {
2461
2461
  return packageOutcome.outcome;
2462
2462
  }
@@ -2469,7 +2469,7 @@ async function buildUiComponentsManifest(input) {
2469
2469
  const project = new Project3({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
2470
2470
  for (const relPath of filePaths) {
2471
2471
  const absolute = resolve5(projectRoot, relPath);
2472
- const text = await readFile6(absolute);
2472
+ const text = await readFile8(absolute);
2473
2473
  project.createSourceFile(absolute, text, { overwrite: true });
2474
2474
  }
2475
2475
  const extractResult = extractUiEntries({ project });
@@ -2500,10 +2500,10 @@ async function buildUiComponentsManifest(input) {
2500
2500
  }
2501
2501
  return outcome;
2502
2502
  }
2503
- async function loadScanConfig3(configPath, readFile6) {
2503
+ async function loadScanConfig3(configPath, readFile8) {
2504
2504
  let raw = null;
2505
2505
  try {
2506
- raw = await readFile6(configPath);
2506
+ raw = await readFile8(configPath);
2507
2507
  } catch {
2508
2508
  raw = null;
2509
2509
  }
@@ -2642,11 +2642,11 @@ var DbxMcpConfig = type13({
2642
2642
  var CONFIG_FILENAME = "dbx-mcp.config.json";
2643
2643
  var DEFAULT_READ_FILE6 = (path) => nodeReadFile4(path, "utf-8");
2644
2644
  async function findAndLoadConfig(input) {
2645
- const { cwd, readFile: readFile6 = DEFAULT_READ_FILE6 } = input;
2645
+ const { cwd, readFile: readFile8 = DEFAULT_READ_FILE6 } = input;
2646
2646
  const configPath = resolve6(cwd, CONFIG_FILENAME);
2647
2647
  let raw = null;
2648
2648
  try {
2649
- raw = await readFile6(configPath);
2649
+ raw = await readFile8(configPath);
2650
2650
  } catch {
2651
2651
  raw = null;
2652
2652
  }
@@ -2911,10 +2911,10 @@ import { readFile as nodeReadFile5 } from "node:fs/promises";
2911
2911
  import { type as type16 } from "arktype";
2912
2912
  var DEFAULT_READ_FILE7 = (path) => nodeReadFile5(path, "utf-8");
2913
2913
  var SUPPORTED_VERSION = 1;
2914
- async function loadFromSource(source, readFile6, schema) {
2914
+ async function loadFromSource(source, readFile8, schema) {
2915
2915
  let raw = null;
2916
2916
  try {
2917
- raw = await readFile6(source.path);
2917
+ raw = await readFile8(source.path);
2918
2918
  } catch {
2919
2919
  raw = null;
2920
2920
  }
@@ -2971,12 +2971,12 @@ function warningSortKey(warning) {
2971
2971
  return key;
2972
2972
  }
2973
2973
  async function loadManifestsBase(input, config) {
2974
- const { sources, readFile: readFile6 = DEFAULT_READ_FILE7 } = input;
2974
+ const { sources, readFile: readFile8 = DEFAULT_READ_FILE7 } = input;
2975
2975
  const { name, schema, extractIndexValue, buildEntryKey } = config;
2976
2976
  const successes = [];
2977
2977
  const warnings = [];
2978
2978
  for (const source of sources) {
2979
- const outcome = await loadFromSource(source, readFile6, schema);
2979
+ const outcome = await loadFromSource(source, readFile8, schema);
2980
2980
  if (outcome.kind === "success") {
2981
2981
  successes.push({ source, manifest: outcome.manifest });
2982
2982
  } else if (isStrictSource(source)) {
@@ -3080,9 +3080,9 @@ var DEFAULT_BUNDLED_PATHS = () => {
3080
3080
  return DEFAULT_BUNDLED_FILENAMES.map((name) => resolve7(packageRoot, "generated", name));
3081
3081
  };
3082
3082
  async function loadActionRegistry(input) {
3083
- const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS, readFile: readFile6 } = input;
3083
+ const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS, readFile: readFile8 } = input;
3084
3084
  const bundledSources = bundledManifestPaths().map((path) => ({ origin: "bundled", path }));
3085
- const configResult = await findAndLoadConfig({ cwd, readFile: readFile6 });
3085
+ const configResult = await findAndLoadConfig({ cwd, readFile: readFile8 });
3086
3086
  const externalSources = [];
3087
3087
  if (configResult.config !== null && configResult.configPath !== null) {
3088
3088
  const baseDir = dirname(configResult.configPath);
@@ -3096,7 +3096,7 @@ async function loadActionRegistry(input) {
3096
3096
  let loaderWarnings = [];
3097
3097
  const sources = [...bundledSources, ...externalSources];
3098
3098
  if (sources.length > 0) {
3099
- const loaded = await loadActionManifests({ sources, readFile: readFile6 });
3099
+ const loaded = await loadActionManifests({ sources, readFile: readFile8 });
3100
3100
  registry = createActionRegistry(loaded);
3101
3101
  loaderWarnings = loaded.warnings;
3102
3102
  }
@@ -3296,9 +3296,9 @@ var DEFAULT_BUNDLED_PATHS2 = () => {
3296
3296
  return DEFAULT_BUNDLED_FILENAMES2.map((name) => resolve8(packageRoot, "generated", name));
3297
3297
  };
3298
3298
  async function loadFilterRegistry(input) {
3299
- const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS2, readFile: readFile6 } = input;
3299
+ const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS2, readFile: readFile8 } = input;
3300
3300
  const bundledSources = bundledManifestPaths().map((path) => ({ origin: "bundled", path }));
3301
- const configResult = await findAndLoadConfig({ cwd, readFile: readFile6 });
3301
+ const configResult = await findAndLoadConfig({ cwd, readFile: readFile8 });
3302
3302
  const externalSources = [];
3303
3303
  if (configResult.config !== null && configResult.configPath !== null) {
3304
3304
  const baseDir = dirname2(configResult.configPath);
@@ -3312,7 +3312,7 @@ async function loadFilterRegistry(input) {
3312
3312
  let loaderWarnings = [];
3313
3313
  const sources = [...bundledSources, ...externalSources];
3314
3314
  if (sources.length > 0) {
3315
- const loaded = await loadFilterManifests({ sources, readFile: readFile6 });
3315
+ const loaded = await loadFilterManifests({ sources, readFile: readFile8 });
3316
3316
  registry = createFilterRegistry(loaded);
3317
3317
  loaderWarnings = loaded.warnings;
3318
3318
  }
@@ -3543,9 +3543,9 @@ var DEFAULT_BUNDLED_PATHS3 = () => {
3543
3543
  return DEFAULT_BUNDLED_FILENAMES3.map((name) => resolve9(packageRoot, "generated", name));
3544
3544
  };
3545
3545
  async function loadForgeFieldRegistry(input) {
3546
- const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS3, readFile: readFile6 } = input;
3546
+ const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS3, readFile: readFile8 } = input;
3547
3547
  const bundledSources = bundledManifestPaths().map((path) => ({ origin: "bundled", path }));
3548
- const configResult = await findAndLoadConfig({ cwd, readFile: readFile6 });
3548
+ const configResult = await findAndLoadConfig({ cwd, readFile: readFile8 });
3549
3549
  const externalSources = [];
3550
3550
  if (configResult.config !== null && configResult.configPath !== null) {
3551
3551
  const baseDir = dirname3(configResult.configPath);
@@ -3559,7 +3559,7 @@ async function loadForgeFieldRegistry(input) {
3559
3559
  let loaderWarnings = [];
3560
3560
  const sources = [...bundledSources, ...externalSources];
3561
3561
  if (sources.length > 0) {
3562
- const loaded = await loadForgeFieldManifests({ sources, readFile: readFile6 });
3562
+ const loaded = await loadForgeFieldManifests({ sources, readFile: readFile8 });
3563
3563
  registry = createForgeFieldRegistry(loaded);
3564
3564
  loaderWarnings = loaded.warnings;
3565
3565
  }
@@ -3725,9 +3725,9 @@ var DEFAULT_BUNDLED_PATHS4 = () => {
3725
3725
  return DEFAULT_BUNDLED_FILENAMES4.map((name) => resolve10(packageRoot, "generated", name));
3726
3726
  };
3727
3727
  async function loadPipeRegistry(input) {
3728
- const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS4, readFile: readFile6 } = input;
3728
+ const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS4, readFile: readFile8 } = input;
3729
3729
  const bundledSources = bundledManifestPaths().map((path) => ({ origin: "bundled", path }));
3730
- const configResult = await findAndLoadConfig({ cwd, readFile: readFile6 });
3730
+ const configResult = await findAndLoadConfig({ cwd, readFile: readFile8 });
3731
3731
  const externalSources = [];
3732
3732
  if (configResult.config !== null && configResult.configPath !== null) {
3733
3733
  const baseDir = dirname4(configResult.configPath);
@@ -3741,7 +3741,7 @@ async function loadPipeRegistry(input) {
3741
3741
  let loaderWarnings = [];
3742
3742
  const sources = [...bundledSources, ...externalSources];
3743
3743
  if (sources.length > 0) {
3744
- const loaded = await loadPipeManifests({ sources, readFile: readFile6 });
3744
+ const loaded = await loadPipeManifests({ sources, readFile: readFile8 });
3745
3745
  registry = createPipeRegistry(loaded);
3746
3746
  loaderWarnings = loaded.warnings;
3747
3747
  }
@@ -3845,10 +3845,10 @@ function isCoreTopic(topic) {
3845
3845
  // packages/dbx-components-mcp/src/manifest/loader.ts
3846
3846
  var DEFAULT_READ_FILE8 = (path) => nodeReadFile6(path, "utf-8");
3847
3847
  var SUPPORTED_VERSION2 = 1;
3848
- async function loadFromSource2(source, readFile6) {
3848
+ async function loadFromSource2(source, readFile8) {
3849
3849
  let raw = null;
3850
3850
  try {
3851
- raw = await readFile6(source.path);
3851
+ raw = await readFile8(source.path);
3852
3852
  } catch {
3853
3853
  }
3854
3854
  let result;
@@ -3935,11 +3935,11 @@ function warningSortKey2(warning) {
3935
3935
  return key;
3936
3936
  }
3937
3937
  async function loadSemanticTypeManifests(input) {
3938
- const { sources, readFile: readFile6 = DEFAULT_READ_FILE8 } = input;
3938
+ const { sources, readFile: readFile8 = DEFAULT_READ_FILE8 } = input;
3939
3939
  const successes = [];
3940
3940
  const warnings = [];
3941
3941
  for (const source of sources) {
3942
- const outcome = await loadFromSource2(source, readFile6);
3942
+ const outcome = await loadFromSource2(source, readFile8);
3943
3943
  if (outcome.kind === "success") {
3944
3944
  successes.push({ source, manifest: outcome.manifest });
3945
3945
  } else if (isStrictSource2(source)) {
@@ -4036,9 +4036,9 @@ var DEFAULT_BUNDLED_PATHS5 = () => {
4036
4036
  return DEFAULT_BUNDLED_FILENAMES5.map((name) => resolve11(packageRoot, "generated", name));
4037
4037
  };
4038
4038
  async function loadSemanticTypeRegistry(input) {
4039
- const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS5, readFile: readFile6 } = input;
4039
+ const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS5, readFile: readFile8 } = input;
4040
4040
  const bundledSources = bundledManifestPaths().map((path) => ({ origin: "bundled", path }));
4041
- const configResult = await findAndLoadConfig({ cwd, readFile: readFile6 });
4041
+ const configResult = await findAndLoadConfig({ cwd, readFile: readFile8 });
4042
4042
  const externalSources = [];
4043
4043
  if (configResult.config !== null && configResult.configPath !== null) {
4044
4044
  const baseDir = dirname5(configResult.configPath);
@@ -4052,7 +4052,7 @@ async function loadSemanticTypeRegistry(input) {
4052
4052
  let loaderWarnings = [];
4053
4053
  const sources = [...bundledSources, ...externalSources];
4054
4054
  if (sources.length > 0) {
4055
- const loaded = await loadSemanticTypeManifests({ sources, readFile: readFile6 });
4055
+ const loaded = await loadSemanticTypeManifests({ sources, readFile: readFile8 });
4056
4056
  registry = createSemanticTypeRegistry(loaded);
4057
4057
  loaderWarnings = loaded.warnings;
4058
4058
  }
@@ -4197,9 +4197,9 @@ var DEFAULT_BUNDLED_PATHS6 = () => {
4197
4197
  return DEFAULT_BUNDLED_FILENAMES6.map((name) => resolve12(packageRoot, "generated", name));
4198
4198
  };
4199
4199
  async function loadUiComponentRegistry(input) {
4200
- const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS6, readFile: readFile6 } = input;
4200
+ const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS6, readFile: readFile8 } = input;
4201
4201
  const bundledSources = bundledManifestPaths().map((path) => ({ origin: "bundled", path }));
4202
- const configResult = await findAndLoadConfig({ cwd, readFile: readFile6 });
4202
+ const configResult = await findAndLoadConfig({ cwd, readFile: readFile8 });
4203
4203
  const externalSources = [];
4204
4204
  if (configResult.config !== null && configResult.configPath !== null) {
4205
4205
  const baseDir = dirname6(configResult.configPath);
@@ -4213,7 +4213,7 @@ async function loadUiComponentRegistry(input) {
4213
4213
  let loaderWarnings = [];
4214
4214
  const sources = [...bundledSources, ...externalSources];
4215
4215
  if (sources.length > 0) {
4216
- const loaded = await loadUiComponentManifests({ sources, readFile: readFile6 });
4216
+ const loaded = await loadUiComponentManifests({ sources, readFile: readFile8 });
4217
4217
  registry = createUiComponentRegistry(loaded);
4218
4218
  loaderWarnings = loaded.warnings;
4219
4219
  }
@@ -4227,12 +4227,6 @@ async function loadUiComponentRegistry(input) {
4227
4227
  return result;
4228
4228
  }
4229
4229
 
4230
- // packages/dbx-components-mcp/src/resources/form-fields.resource.ts
4231
- import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
4232
-
4233
- // packages/dbx-components-mcp/src/registry/form-fields.ts
4234
- var FORM_TIER_ORDER = ["field-factory", "field-derivative", "composite-builder", "template-builder", "primitive"];
4235
-
4236
4230
  // packages/dbx-components-mcp/generated/firebase-models.generated.ts
4237
4231
  var FIREBASE_MODELS = [
4238
4232
  {
@@ -4301,7 +4295,8 @@ var FIREBASE_MODELS = [
4301
4295
  ],
4302
4296
  enums: [],
4303
4297
  detectionHints: ["m", "r", "w"],
4304
- modelGroup: "Notification"
4298
+ modelGroup: "Notification",
4299
+ collectionKind: "root"
4305
4300
  },
4306
4301
  {
4307
4302
  name: "NotificationSummary",
@@ -4377,7 +4372,8 @@ var FIREBASE_MODELS = [
4377
4372
  ],
4378
4373
  enums: [],
4379
4374
  detectionHints: ["m", "n", "lat", "rat"],
4380
- modelGroup: "Notification"
4375
+ modelGroup: "Notification",
4376
+ collectionKind: "root"
4381
4377
  },
4382
4378
  {
4383
4379
  name: "NotificationUser",
@@ -4443,7 +4439,8 @@ var FIREBASE_MODELS = [
4443
4439
  ],
4444
4440
  enums: [],
4445
4441
  detectionHints: ["b", "x", "dc", "gc", "bc", "ns"],
4446
- modelGroup: "Notification"
4442
+ modelGroup: "Notification",
4443
+ collectionKind: "root"
4447
4444
  },
4448
4445
  {
4449
4446
  name: "OidcEntry",
@@ -4519,7 +4516,8 @@ var FIREBASE_MODELS = [
4519
4516
  ],
4520
4517
  enums: [],
4521
4518
  detectionHints: ["type", "payload", "grantId", "userCode", "consumed", "expiresAt"],
4522
- modelGroup: "OidcModel"
4519
+ modelGroup: "OidcModel",
4520
+ collectionKind: "root"
4523
4521
  },
4524
4522
  {
4525
4523
  name: "StorageFile",
@@ -4776,7 +4774,8 @@ var FIREBASE_MODELS = [
4776
4774
  }
4777
4775
  ],
4778
4776
  detectionHints: ["bucketId", "pathString", "n", "ct", "fs", "ps", "pn", "pat", "pcat", "uby", "p", "pg", "sdat", "g", "gs"],
4779
- modelGroup: "StorageFile"
4777
+ modelGroup: "StorageFile",
4778
+ collectionKind: "root"
4780
4779
  },
4781
4780
  {
4782
4781
  name: "StorageFileGroup",
@@ -4868,7 +4867,8 @@ var FIREBASE_MODELS = [
4868
4867
  ],
4869
4868
  enums: [],
4870
4869
  detectionHints: ["f", "z", "zsf", "zat", "re", "c"],
4871
- modelGroup: "StorageFile"
4870
+ modelGroup: "StorageFile",
4871
+ collectionKind: "root"
4872
4872
  },
4873
4873
  {
4874
4874
  name: "SystemState",
@@ -4888,7 +4888,8 @@ var FIREBASE_MODELS = [
4888
4888
  ],
4889
4889
  enums: [],
4890
4890
  detectionHints: ["data"],
4891
- modelGroup: "SystemState"
4891
+ modelGroup: "SystemState",
4892
+ collectionKind: "root"
4892
4893
  },
4893
4894
  {
4894
4895
  name: "Notification",
@@ -5168,7 +5169,8 @@ var FIREBASE_MODELS = [
5168
5169
  ],
5169
5170
  detectionHints: ["st", "rf", "ts", "es", "ps", "ns", "n", "r", "ois", "ots", "sat", "a", "at", "tsr", "esr", "tpr", "ut"],
5170
5171
  parentIdentityConst: "notificationBoxIdentity",
5171
- modelGroup: "Notification"
5172
+ modelGroup: "Notification",
5173
+ collectionKind: "sub-collection"
5172
5174
  },
5173
5175
  {
5174
5176
  name: "NotificationWeek",
@@ -5197,10 +5199,17 @@ var FIREBASE_MODELS = [
5197
5199
  enums: [],
5198
5200
  detectionHints: ["w", "n"],
5199
5201
  parentIdentityConst: "notificationBoxIdentity",
5200
- modelGroup: "Notification"
5202
+ modelGroup: "Notification",
5203
+ collectionKind: "sub-collection"
5201
5204
  }
5202
5205
  ];
5203
5206
 
5207
+ // packages/dbx-components-mcp/src/resources/form-fields.resource.ts
5208
+ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
5209
+
5210
+ // packages/dbx-components-mcp/src/registry/form-fields.ts
5211
+ var FORM_TIER_ORDER = ["field-factory", "field-derivative", "composite-builder", "template-builder", "primitive"];
5212
+
5204
5213
  // packages/dbx-components-mcp/src/registry/index.ts
5205
5214
  function getFirebaseModels() {
5206
5215
  return FIREBASE_MODELS;
@@ -6317,7 +6326,11 @@ function formatConfigTable(field) {
6317
6326
  const rows = keys.map((key) => {
6318
6327
  const prop = field.config[key];
6319
6328
  const required = prop.required ? "\u2713" : "";
6320
- const defaultCell = prop.default === void 0 ? "" : `\`${typeof prop.default === "string" ? prop.default : JSON.stringify(prop.default)}\``;
6329
+ let defaultCell = "";
6330
+ if (prop.default !== void 0) {
6331
+ const defaultText = typeof prop.default === "string" ? prop.default : JSON.stringify(prop.default);
6332
+ defaultCell = `\`${defaultText}\``;
6333
+ }
6321
6334
  const desc = prop.description.replaceAll("|", String.raw`\|`);
6322
6335
  const escapedType = prop.type.replaceAll("|", String.raw`\|`);
6323
6336
  return `| \`${prop.name}\` | \`${escapedType}\` | ${required} | ${defaultCell} | ${desc} |`;
@@ -6487,7 +6500,7 @@ function createLookupFormTool(config) {
6487
6500
  }
6488
6501
  return lines.join("\n").trimEnd();
6489
6502
  }
6490
- function run(rawArgs) {
6503
+ function run5(rawArgs) {
6491
6504
  let args;
6492
6505
  try {
6493
6506
  args = parseLookupFormArgs(rawArgs);
@@ -6516,7 +6529,7 @@ function createLookupFormTool(config) {
6516
6529
  }
6517
6530
  const tool = {
6518
6531
  definition: DBX_FORM_LOOKUP_TOOL,
6519
- run
6532
+ run: run5
6520
6533
  };
6521
6534
  return tool;
6522
6535
  }
@@ -6705,7 +6718,7 @@ function formatSearchResults(input) {
6705
6718
  }
6706
6719
  function createSearchFormTool(config) {
6707
6720
  const { registry } = config;
6708
- function run(rawArgs) {
6721
+ function run5(rawArgs) {
6709
6722
  return runSearchTool(
6710
6723
  {
6711
6724
  entries: registry.all,
@@ -6721,7 +6734,7 @@ function createSearchFormTool(config) {
6721
6734
  }
6722
6735
  const tool = {
6723
6736
  definition: DBX_FORM_SEARCH_TOOL,
6724
- run
6737
+ run: run5
6725
6738
  };
6726
6739
  return tool;
6727
6740
  }
@@ -7244,7 +7257,7 @@ function renderScaffold(specs, valueTypeName, wrapInSection) {
7244
7257
  }
7245
7258
  function createFormScaffoldTool(config) {
7246
7259
  const { registry } = config;
7247
- function run(rawArgs) {
7260
+ function run5(rawArgs) {
7248
7261
  let args;
7249
7262
  try {
7250
7263
  args = parseScaffoldArgs(rawArgs);
@@ -7263,7 +7276,7 @@ function createFormScaffoldTool(config) {
7263
7276
  return toolError(lines.join("\n"));
7264
7277
  }
7265
7278
  const specs = parsed;
7266
- const code10 = renderScaffold(specs, args.valueTypeName, args.wrapInSection);
7279
+ const code11 = renderScaffold(specs, args.valueTypeName, args.wrapInSection);
7267
7280
  const slugList = specs.map((s) => s.slug).join(", ");
7268
7281
  const preamble = `# Scaffold
7269
7282
 
@@ -7271,14 +7284,14 @@ Generated from \`${slugList}\` (${specs.length} field${specs.length === 1 ? "" :
7271
7284
  const text = `${preamble}
7272
7285
 
7273
7286
  \`\`\`ts
7274
- ${code10}
7287
+ ${code11}
7275
7288
  \`\`\``;
7276
7289
  const result = { content: [{ type: "text", text }] };
7277
7290
  return result;
7278
7291
  }
7279
7292
  const tool = {
7280
7293
  definition: DBX_FORM_SCAFFOLD_TOOL,
7281
- run
7294
+ run: run5
7282
7295
  };
7283
7296
  return tool;
7284
7297
  }
@@ -7539,7 +7552,7 @@ function formatNotFound3(normalized, candidates) {
7539
7552
  }
7540
7553
  function createLookupUiTool(input) {
7541
7554
  const { registry } = input;
7542
- const run = (rawArgs) => {
7555
+ const run5 = (rawArgs) => {
7543
7556
  let args;
7544
7557
  try {
7545
7558
  args = parseLookupUiArgs(rawArgs);
@@ -7566,7 +7579,7 @@ function createLookupUiTool(input) {
7566
7579
  const result = { content: [{ type: "text", text }] };
7567
7580
  return result;
7568
7581
  };
7569
- return { definition: DBX_UI_LOOKUP_TOOL, run };
7582
+ return { definition: DBX_UI_LOOKUP_TOOL, run: run5 };
7570
7583
  }
7571
7584
 
7572
7585
  // packages/dbx-components-mcp/src/tools/search-ui.tool.ts
@@ -7748,7 +7761,7 @@ function formatSearchResults2(options) {
7748
7761
  }
7749
7762
  function createSearchUiTool(input) {
7750
7763
  const { registry } = input;
7751
- const run = (rawArgs) => {
7764
+ const run5 = (rawArgs) => {
7752
7765
  let args;
7753
7766
  try {
7754
7767
  args = parseSearchUiArgs(rawArgs);
@@ -7763,7 +7776,7 @@ function createSearchUiTool(input) {
7763
7776
  const result = { content: [{ type: "text", text }] };
7764
7777
  return result;
7765
7778
  };
7766
- return { definition: DBX_UI_SEARCH_TOOL, run };
7779
+ return { definition: DBX_UI_SEARCH_TOOL, run: run5 };
7767
7780
  }
7768
7781
 
7769
7782
  // packages/dbx-components-mcp/src/tools/ui-examples.tool.ts
@@ -8952,7 +8965,7 @@ var FolderValidateArgsType = type29({
8952
8965
  });
8953
8966
  function createFolderValidateTool(config) {
8954
8967
  const { definition, inspectFolder: inspectFolder3, validate, format } = config;
8955
- async function run(rawArgs) {
8968
+ async function run5(rawArgs) {
8956
8969
  const parsed = FolderValidateArgsType(rawArgs);
8957
8970
  if (parsed instanceof type29.errors) {
8958
8971
  return toolError(`Invalid arguments: ${parsed.summary}`);
@@ -8992,7 +9005,7 @@ function createFolderValidateTool(config) {
8992
9005
  };
8993
9006
  return toolResult;
8994
9007
  }
8995
- const tool = { definition, run };
9008
+ const tool = { definition, run: run5 };
8996
9009
  return tool;
8997
9010
  }
8998
9011
  var SourceValidateArgsType = type29({
@@ -9002,7 +9015,7 @@ var SourceValidateArgsType = type29({
9002
9015
  });
9003
9016
  function createSourceValidateTool(config) {
9004
9017
  const { definition, validate, format } = config;
9005
- async function run(rawArgs) {
9018
+ async function run5(rawArgs) {
9006
9019
  const parsed = SourceValidateArgsType(rawArgs);
9007
9020
  if (parsed instanceof type29.errors) {
9008
9021
  return toolError(`Invalid arguments: ${parsed.summary}`);
@@ -9029,7 +9042,7 @@ function createSourceValidateTool(config) {
9029
9042
  };
9030
9043
  return toolResult;
9031
9044
  }
9032
- const tool = { definition, run };
9045
+ const tool = { definition, run: run5 };
9033
9046
  return tool;
9034
9047
  }
9035
9048
  var TwoSideValidateArgsType = type29({
@@ -9056,7 +9069,7 @@ function resolveTwoSideInput(parsed) {
9056
9069
  }
9057
9070
  function createTwoSideValidateTool(config) {
9058
9071
  const { definition, inspectAndValidate, format } = config;
9059
- async function run(rawArgs) {
9072
+ async function run5(rawArgs) {
9060
9073
  const parsed = TwoSideValidateArgsType(rawArgs);
9061
9074
  if (parsed instanceof type29.errors) {
9062
9075
  return toolError(`Invalid arguments: ${parsed.summary}`);
@@ -9073,7 +9086,7 @@ function createTwoSideValidateTool(config) {
9073
9086
  };
9074
9087
  return toolResult;
9075
9088
  }
9076
- const tool = { definition, run };
9089
+ const tool = { definition, run: run5 };
9077
9090
  return tool;
9078
9091
  }
9079
9092
  var ListAppArgsType = type29({
@@ -9083,7 +9096,7 @@ var ListAppArgsType = type29({
9083
9096
  });
9084
9097
  function createListAppTool(config) {
9085
9098
  const { definition, inspectAndList, formatMarkdown, formatJson } = config;
9086
- async function run(rawArgs) {
9099
+ async function run5(rawArgs) {
9087
9100
  const parsed = ListAppArgsType(rawArgs);
9088
9101
  if (parsed instanceof type29.errors) {
9089
9102
  return toolError(`Invalid arguments: ${parsed.summary}`);
@@ -9097,7 +9110,7 @@ function createListAppTool(config) {
9097
9110
  const toolResult = { content: [{ type: "text", text }] };
9098
9111
  return toolResult;
9099
9112
  }
9100
- const tool = { definition, run };
9113
+ const tool = { definition, run: run5 };
9101
9114
  return tool;
9102
9115
  }
9103
9116
 
@@ -9290,6 +9303,7 @@ function extractModel(sourceFile, identity) {
9290
9303
  const collectionFnName = variant === "root" ? `${camelName}FirestoreCollection` : `${camelName}FirestoreCollectionFactory`;
9291
9304
  const collectionFn = findFunction(sourceFile, collectionFnName);
9292
9305
  const collectionGroupFn = variant === "subcollection" ? findFunction(sourceFile, `${camelName}FirestoreCollectionGroup`) : void 0;
9306
+ const factoryCallKind = detectFactoryCallKind(sourceFile, collectionFnName);
9293
9307
  const extractedIdentity = {
9294
9308
  constName: identity.constName,
9295
9309
  exported: identity.exported,
@@ -9314,10 +9328,38 @@ function extractModel(sourceFile, identity) {
9314
9328
  collectionFactoryType,
9315
9329
  collectionGroupType,
9316
9330
  collectionFn,
9317
- collectionGroupFn
9331
+ collectionGroupFn,
9332
+ factoryCallKind
9318
9333
  };
9319
9334
  return result;
9320
9335
  }
9336
+ function detectFactoryCallKind(sourceFile, factoryFnName) {
9337
+ const fn = sourceFile.getFunction(factoryFnName);
9338
+ if (!fn) {
9339
+ return void 0;
9340
+ }
9341
+ const calls = fn.getDescendantsOfKind(SyntaxKind3.CallExpression);
9342
+ for (const call of calls) {
9343
+ const expr = call.getExpression();
9344
+ if (!Node6.isPropertyAccessExpression(expr)) {
9345
+ continue;
9346
+ }
9347
+ const name = expr.getName();
9348
+ if (name === "firestoreCollection") {
9349
+ return "root";
9350
+ }
9351
+ if (name === "rootSingleItemFirestoreCollection") {
9352
+ return "root-singleton";
9353
+ }
9354
+ if (name === "firestoreCollectionWithParent") {
9355
+ return "sub-collection";
9356
+ }
9357
+ if (name === "singleItemFirestoreCollection") {
9358
+ return "singleton-sub";
9359
+ }
9360
+ }
9361
+ return void 0;
9362
+ }
9321
9363
  function deriveCamelName(constName) {
9322
9364
  const suffix = "Identity";
9323
9365
  return constName.endsWith(suffix) ? constName.slice(0, -suffix.length) : constName;
@@ -9784,21 +9826,37 @@ function checkCollectionType(file, model, violations) {
9784
9826
  return;
9785
9827
  }
9786
9828
  const typeText = model.collectionType.typeText ?? "";
9787
- if (model.variant === "root") {
9788
- const expected2 = `FirestoreCollection<${model.name}, ${model.name}Document>`;
9789
- if (typeText.replaceAll(/\s+/g, "") !== expected2.replaceAll(/\s+/g, "")) {
9790
- pushViolation(violations, {
9791
- code: "MODEL_COLLECTION_TYPE_WRONG_GENERIC",
9792
- message: `Type alias \`${model.name}FirestoreCollection\` must equal \`${expected2}\` (found \`${typeText || "<none>"}\`).`,
9793
- file: file.name,
9794
- line: model.collectionType.line,
9795
- model: model.name
9796
- });
9797
- }
9829
+ const allowedKinds = model.variant === "root" ? ["root", "root-singleton"] : ["sub-collection", "singleton-sub"];
9830
+ const aliasKind = detectAliasKind(typeText);
9831
+ const factoryKind = model.factoryCallKind;
9832
+ if (aliasKind && factoryKind && aliasKind !== factoryKind) {
9833
+ pushViolation(violations, {
9834
+ code: "MODEL_COLLECTION_FACTORY_TYPE_MISMATCH",
9835
+ message: `Type alias \`${model.name}FirestoreCollection\` is \`${COLLECTION_TYPE_NAME[aliasKind]}\` but factory \`${expectedCollectionFnName(model)}\` calls \`firestoreContext.${COLLECTION_FACTORY_FN_NAME[factoryKind]}({...})\`. Type alias and factory body must declare the same collection kind (\`${aliasKind}\` vs \`${factoryKind}\`).`,
9836
+ file: file.name,
9837
+ line: model.collectionType.line,
9838
+ model: model.name
9839
+ });
9798
9840
  return;
9799
9841
  }
9800
- const parentPascal = pascalCase2(deriveCamelName2(model.identity.parentIdentityRef ?? ""));
9801
- const expected = `SingleItemFirestoreCollection<${model.name}, ${parentPascal}, ${model.name}Document, ${parentPascal}Document>`;
9842
+ const isAllowed = (k) => k === void 0 || allowedKinds.includes(k);
9843
+ if (!isAllowed(aliasKind) || !isAllowed(factoryKind)) {
9844
+ const offender = !isAllowed(aliasKind) ? aliasKind : factoryKind;
9845
+ const offenderSite = !isAllowed(aliasKind) ? "type alias" : "factory body";
9846
+ const variantLabel = model.variant === "root" ? "root (no parent identity)" : "subcollection (parent identity declared)";
9847
+ const allowedList = allowedKinds.map((k) => `\`${k}\``).join(", ");
9848
+ pushViolation(violations, {
9849
+ code: "MODEL_COLLECTION_FACTORY_TYPE_MISMATCH",
9850
+ message: `Model \`${model.name}\` is a ${variantLabel} but its collection ${offenderSite} is \`${offender}\`. Allowed kinds for this variant: ${allowedList}.`,
9851
+ file: file.name,
9852
+ line: model.collectionType.line,
9853
+ model: model.name
9854
+ });
9855
+ return;
9856
+ }
9857
+ const defaultKind = model.variant === "root" ? "root" : "singleton-sub";
9858
+ const expectedKind = aliasKind ?? factoryKind ?? defaultKind;
9859
+ const expected = expectedCollectionTypeText(expectedKind, model);
9802
9860
  if (typeText.replaceAll(/\s+/g, "") !== expected.replaceAll(/\s+/g, "")) {
9803
9861
  pushViolation(violations, {
9804
9862
  code: "MODEL_COLLECTION_TYPE_WRONG_GENERIC",
@@ -9809,6 +9867,45 @@ function checkCollectionType(file, model, violations) {
9809
9867
  });
9810
9868
  }
9811
9869
  }
9870
+ var COLLECTION_TYPE_NAME = {
9871
+ root: "FirestoreCollection",
9872
+ "root-singleton": "RootSingleItemFirestoreCollection",
9873
+ "sub-collection": "FirestoreCollectionWithParent",
9874
+ "singleton-sub": "SingleItemFirestoreCollection"
9875
+ };
9876
+ var COLLECTION_FACTORY_FN_NAME = {
9877
+ root: "firestoreCollection",
9878
+ "root-singleton": "rootSingleItemFirestoreCollection",
9879
+ "sub-collection": "firestoreCollectionWithParent",
9880
+ "singleton-sub": "singleItemFirestoreCollection"
9881
+ };
9882
+ function detectAliasKind(typeText) {
9883
+ const normalized = typeText.replaceAll(/\s+/g, "");
9884
+ if (normalized.startsWith("RootSingleItemFirestoreCollection<")) {
9885
+ return "root-singleton";
9886
+ }
9887
+ if (normalized.startsWith("SingleItemFirestoreCollection<")) {
9888
+ return "singleton-sub";
9889
+ }
9890
+ if (normalized.startsWith("FirestoreCollectionWithParent<")) {
9891
+ return "sub-collection";
9892
+ }
9893
+ if (normalized.startsWith("FirestoreCollection<")) {
9894
+ return "root";
9895
+ }
9896
+ return void 0;
9897
+ }
9898
+ function expectedCollectionTypeText(kind, model) {
9899
+ const ctor = COLLECTION_TYPE_NAME[kind];
9900
+ if (kind === "root" || kind === "root-singleton") {
9901
+ return `${ctor}<${model.name}, ${model.name}Document>`;
9902
+ }
9903
+ const parentPascal = pascalCase2(deriveCamelName2(model.identity.parentIdentityRef ?? ""));
9904
+ return `${ctor}<${model.name}, ${parentPascal}, ${model.name}Document, ${parentPascal}Document>`;
9905
+ }
9906
+ function expectedCollectionFnName(model) {
9907
+ return model.variant === "root" ? `${model.camelName}FirestoreCollection` : `${model.camelName}FirestoreCollectionFactory`;
9908
+ }
9812
9909
  function checkCollectionFn(file, model, violations) {
9813
9910
  if (model.collectionFn) {
9814
9911
  return;
@@ -11011,11 +11108,11 @@ function checkReadonlyFields(file, violations) {
11011
11108
  }
11012
11109
  }
11013
11110
  function checkInterfaceReadonly(options) {
11014
- const { file, decl, code: code10, violations } = options;
11111
+ const { file, decl, code: code11, violations } = options;
11015
11112
  for (const field of decl.fields) {
11016
11113
  if (field.readonly) continue;
11017
11114
  pushViolation2(violations, {
11018
- code: code10,
11115
+ code: code11,
11019
11116
  severity: "warning",
11020
11117
  message: `Field \`${field.name}\` on \`${decl.name}\` should be declared \`readonly\`.`,
11021
11118
  file: file.name,
@@ -11347,8 +11444,8 @@ async function inspectFolder(path) {
11347
11444
  status = "not-directory";
11348
11445
  }
11349
11446
  } catch (err) {
11350
- const code10 = err.code;
11351
- if (code10 === "ENOENT" || code10 === "ENOTDIR") {
11447
+ const code11 = err.code;
11448
+ if (code11 === "ENOENT" || code11 === "ENOTDIR") {
11352
11449
  status = "not-found";
11353
11450
  } else {
11354
11451
  throw err;
@@ -11915,140 +12012,1700 @@ function systemStateAccessorBody(args) {
11915
12012
  if (args.functionsClass !== void 0) {
11916
12013
  lines.push(` readonly ${functionsFieldName(args.functionsClass)} = inject(${args.functionsClass});`, "");
11917
12014
  }
11918
- lines.push(` constructor() {`, ` super(${typeConst});`, ` }`);
11919
- const crudLines = renderCrudLines(args, "this.systemStateDocumentStore");
11920
- if (crudLines.length > 0) {
11921
- lines.push("", ...crudLines);
12015
+ lines.push(` constructor() {`, ` super(${typeConst});`, ` }`);
12016
+ const crudLines = renderCrudLines(args, "this.systemStateDocumentStore");
12017
+ if (crudLines.length > 0) {
12018
+ lines.push("", ...crudLines);
12019
+ }
12020
+ lines.push(`}`);
12021
+ return { path: `${args.fileBaseName}.store.accessor.ts`, body: lines.join("\n") };
12022
+ }
12023
+ function documentDirectiveBody(args) {
12024
+ const docType = `${args.modelName}Document`;
12025
+ const storeClass = `${args.modelName}DocumentStore`;
12026
+ const directiveClass = `${args.appPrefixPascal}${args.modelName}DocumentStoreDirective`;
12027
+ const selector = `[${args.appPrefixCamel}${args.modelName}Document]`;
12028
+ const lines = [
12029
+ `import { Directive, inject } from '@angular/core';`,
12030
+ `import { DbxFirebaseDocumentStoreDirective, provideDbxFirebaseDocumentStoreDirective } from '@dereekb/dbx-firebase';`,
12031
+ `import { type ${args.modelName}, type ${docType} } from '${args.firebasePackage}';`,
12032
+ `import { ${storeClass} } from './${args.fileBaseName}.document.store';`,
12033
+ "",
12034
+ `@Directive({`,
12035
+ ` selector: '${selector}',`,
12036
+ ` providers: provideDbxFirebaseDocumentStoreDirective(${directiveClass}, ${storeClass}),`,
12037
+ ` standalone: true`,
12038
+ `})`,
12039
+ `export class ${directiveClass} extends DbxFirebaseDocumentStoreDirective<${args.modelName}, ${docType}, ${storeClass}> {`,
12040
+ ` constructor() {`,
12041
+ ` super(inject(${storeClass}));`,
12042
+ ` }`,
12043
+ `}`
12044
+ ];
12045
+ return { path: `${args.fileBaseName}.document.store.directive.ts`, body: lines.join("\n") };
12046
+ }
12047
+ function collectionDirectiveBody(args) {
12048
+ const docType = `${args.modelName}Document`;
12049
+ const storeClass = `${args.modelName}CollectionStore`;
12050
+ const directiveClass = `${args.appPrefixPascal}${args.modelName}CollectionStoreDirective`;
12051
+ const selector = `[${args.appPrefixCamel}${args.modelName}Collection]`;
12052
+ const lines = [
12053
+ `import { Directive, inject } from '@angular/core';`,
12054
+ `import { DbxFirebaseCollectionStoreDirective, provideDbxFirebaseCollectionStoreDirective } from '@dereekb/dbx-firebase';`,
12055
+ `import { type ${args.modelName}, type ${docType} } from '${args.firebasePackage}';`,
12056
+ `import { ${storeClass} } from './${args.fileBaseName}.collection.store';`,
12057
+ "",
12058
+ `@Directive({`,
12059
+ ` selector: '${selector}',`,
12060
+ ` providers: provideDbxFirebaseCollectionStoreDirective(${directiveClass}, ${storeClass}),`,
12061
+ ` standalone: true`,
12062
+ `})`,
12063
+ `export class ${directiveClass} extends DbxFirebaseCollectionStoreDirective<${args.modelName}, ${docType}, ${storeClass}> {`,
12064
+ ` constructor() {`,
12065
+ ` super(inject(${storeClass}));`,
12066
+ ` }`,
12067
+ `}`
12068
+ ];
12069
+ return { path: `${args.fileBaseName}.collection.store.directive.ts`, body: lines.join("\n") };
12070
+ }
12071
+ function buildBlocks(args) {
12072
+ const blocks = [];
12073
+ if (args.shape === "system-state") {
12074
+ blocks.push(systemStateAccessorBody(args));
12075
+ } else {
12076
+ for (const surface of args.surfaces) {
12077
+ if (surface === "document") {
12078
+ if (args.shape === "sub-collection" || args.shape === "singleton-sub") {
12079
+ blocks.push(subDocumentStoreBody(args));
12080
+ } else {
12081
+ blocks.push(rootDocumentStoreBody(args));
12082
+ }
12083
+ if (args.profile.emitsDirectives) {
12084
+ blocks.push(documentDirectiveBody(args));
12085
+ }
12086
+ } else {
12087
+ if (args.shape === "sub-collection") {
12088
+ blocks.push(subCollectionStoreBody(args));
12089
+ } else {
12090
+ blocks.push(rootCollectionStoreBody(args));
12091
+ }
12092
+ if (args.profile.emitsDirectives) {
12093
+ blocks.push(collectionDirectiveBody(args));
12094
+ }
12095
+ }
12096
+ }
12097
+ }
12098
+ return blocks;
12099
+ }
12100
+ function formatScaffold(args) {
12101
+ const blocks = buildBlocks(args);
12102
+ const surfaceLabel = args.shape === "system-state" ? "accessor" : args.surfaces.join(" + ");
12103
+ const functionsLabel = args.functionsClass ?? "none";
12104
+ const crudLabel = args.crudFunctions.length > 0 ? args.crudFunctions.map((c) => `${c.name} (${c.kind})`).join(", ") : "none";
12105
+ const parentLabel = args.parentModel === void 0 ? "n/a" : args.parentModel.name;
12106
+ const lines = [`# ${args.modelName} store scaffold`, "", `Shape: \`${args.shape}\` \xB7 Surfaces: ${surfaceLabel} \xB7 Parent: ${parentLabel} \xB7 Functions: ${functionsLabel} \xB7 Crud: ${crudLabel}`, "", `Drop into \`<app>/src/lib/modules/${args.fileBaseName.replaceAll(".", "/")}/store/\`.`, ""];
12107
+ for (const block of blocks) {
12108
+ lines.push(`## \`${block.path}\``, "", "```ts", block.body, "```", "");
12109
+ }
12110
+ lines.push("## Notes", "", "- Each store is `@Injectable()` with no `providedIn` \u2014 wire it in the consuming feature module / route providers, alongside its directive (when present).");
12111
+ if (args.shape === "sub-collection" || args.shape === "singleton-sub") {
12112
+ lines.push(`- The \`${args.parentModel?.name}DocumentStore\` parent is injected with \`{ optional: true }\` so the store works both as a standalone and as a child of a parent's document directive.`);
12113
+ }
12114
+ if (args.shape === "system-state") {
12115
+ lines.push(`- The accessor wraps a shared \`SystemStateDocumentStore\` keyed by \`${args.systemStateTypeConst}\`. CRUD function helpers reference \`this.systemStateDocumentStore\` (not \`this\`).`);
12116
+ }
12117
+ if (args.crudFunctions.length > 0) {
12118
+ lines.push(`- ${args.crudFunctions.length} CRUD helper line${args.crudFunctions.length === 1 ? "" : "s"} wired through \`firebaseDocumentStore{Create,Update,Crud}Function\`.`);
12119
+ }
12120
+ lines.push('- \u2192 See `dbx_model_lookup topic="shapes"` for the full store-shape taxonomy.', "- \u2192 Skill: `dbx__guide__angular-stores`.");
12121
+ return lines.join("\n");
12122
+ }
12123
+ function runModelStoreScaffold(rawArgs) {
12124
+ let args;
12125
+ try {
12126
+ args = parseArgs2(rawArgs);
12127
+ } catch (err) {
12128
+ const message = err instanceof Error ? err.message : String(err);
12129
+ return toolError(message);
12130
+ }
12131
+ const text = formatScaffold(args);
12132
+ const result = { content: [{ type: "text", text }] };
12133
+ return result;
12134
+ }
12135
+ var modelStoreScaffoldTool = {
12136
+ definition: DBX_MODEL_STORE_SCAFFOLD_TOOL,
12137
+ run: runModelStoreScaffold
12138
+ };
12139
+
12140
+ // packages/dbx-components-mcp/src/tools/model-fixture-list-app.tool.ts
12141
+ import { resolve as resolve15 } from "node:path";
12142
+ import { type as type31 } from "arktype";
12143
+
12144
+ // packages/dbx-components-mcp/src/tools/model-fixture-shared/archetype.ts
12145
+ function classifyFixtureArchetype(input) {
12146
+ const { factory, params } = input;
12147
+ const subCollection = isSubCollection(factory);
12148
+ let archetype;
12149
+ if (subCollection) {
12150
+ archetype = factory?.hasCollectionForDocument ? "sub-collection-traversal" : "sub-collection";
12151
+ } else if (paramsHasFixtureDependencies(params)) {
12152
+ archetype = "top-level-with-deps";
12153
+ } else {
12154
+ archetype = "top-level-simple";
12155
+ }
12156
+ return archetype;
12157
+ }
12158
+ function isSubCollection(factory) {
12159
+ if (factory === void 0) return false;
12160
+ return factory.hasParamsGetCollection || factory.hasCollectionForDocument;
12161
+ }
12162
+ function paramsHasFixtureDependencies(params) {
12163
+ if (params === void 0) return false;
12164
+ for (const field of params.fields) {
12165
+ if (field.fixtureModel !== void 0) return true;
12166
+ }
12167
+ return false;
12168
+ }
12169
+
12170
+ // packages/dbx-components-mcp/src/tools/model-fixture-shared/extract.ts
12171
+ import { Node as Node8, Project as Project6, SyntaxKind as SyntaxKind5 } from "ts-morph";
12172
+ var FIXTURE_SUFFIX = "TestContextFixture";
12173
+ var INSTANCE_SUFFIX = "TestContextInstance";
12174
+ var PARAMS_SUFFIX = "TestContextParams";
12175
+ var FIXTURE_FILE_VIRTUAL_PATH = "__fixture__/fixture.ts";
12176
+ var BASE_CONTEXT_FIXTURE_BASE = "FirebaseAdminNestTestContextFixture";
12177
+ var MODEL_FACTORY_NAME = "modelTestContextFactory";
12178
+ function extractAppFixturesFromText(input) {
12179
+ const { text, fixturePath } = input;
12180
+ const project = new Project6({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
12181
+ const sourceFile = project.createSourceFile(FIXTURE_FILE_VIRTUAL_PATH, text, { overwrite: true });
12182
+ const prefix = detectPrefix(sourceFile);
12183
+ const fixtureClasses = /* @__PURE__ */ new Map();
12184
+ const instanceClasses = /* @__PURE__ */ new Map();
12185
+ const unrecognized = [];
12186
+ collectClasses(sourceFile, prefix, { fixtures: fixtureClasses, instances: instanceClasses, unrecognized });
12187
+ const paramsTypes = collectParamsTypes(sourceFile, prefix);
12188
+ const factoriesByModel = collectFactories(sourceFile, prefix);
12189
+ const singletonsByFactory = collectSingletonsByFactory(sourceFile);
12190
+ const entries = [];
12191
+ const seenModels = /* @__PURE__ */ new Set();
12192
+ const sortedModels = collectAllModels(fixtureClasses, instanceClasses);
12193
+ for (const model of sortedModels) {
12194
+ if (seenModels.has(model)) continue;
12195
+ seenModels.add(model);
12196
+ const fixtureClass = fixtureClasses.get(model);
12197
+ const instanceClass = instanceClasses.get(model);
12198
+ if (fixtureClass === void 0 || instanceClass === void 0) {
12199
+ continue;
12200
+ }
12201
+ const params = paramsTypes.get(model);
12202
+ const factory = factoriesByModel.get(model);
12203
+ if (factory?.factoryName) {
12204
+ const singleton = singletonsByFactory.get(factory.factoryName);
12205
+ if (singleton !== void 0) {
12206
+ Object.assign(factory, { singletonName: singleton });
12207
+ }
12208
+ }
12209
+ const archetype = classifyFixtureArchetype({ factory, params });
12210
+ const fixtureMethods = readClassMethods(fixtureClass);
12211
+ const instanceMethods = readClassMethods(instanceClass);
12212
+ const entry = {
12213
+ model,
12214
+ prefix: prefix ?? "",
12215
+ archetype,
12216
+ fixtureClassName: fixtureClass.getName() ?? "",
12217
+ instanceClassName: instanceClass.getName() ?? "",
12218
+ paramsTypeName: params?.name ?? `${prefix ?? ""}${model}${PARAMS_SUFFIX}`,
12219
+ factoryName: factory?.factoryName,
12220
+ singletonName: factory?.singletonName,
12221
+ fixtureExtendsGenerics: readExtendsGenerics(fixtureClass),
12222
+ instanceExtendsGenerics: readExtendsGenerics(instanceClass),
12223
+ fixtureMethods,
12224
+ instanceMethods,
12225
+ params,
12226
+ factory,
12227
+ fixtureLine: fixtureClass.getStartLineNumber(),
12228
+ fixtureEndLine: fixtureClass.getEndLineNumber(),
12229
+ instanceLine: instanceClass.getStartLineNumber(),
12230
+ instanceEndLine: instanceClass.getEndLineNumber()
12231
+ };
12232
+ entries.push(entry);
12233
+ }
12234
+ const identityImports = collectIdentityImports(sourceFile);
12235
+ const result = {
12236
+ fixturePath,
12237
+ prefix,
12238
+ entries,
12239
+ unrecognizedClassNames: unrecognized,
12240
+ identityImports
12241
+ };
12242
+ return result;
12243
+ }
12244
+ function detectPrefix(sourceFile) {
12245
+ for (const cls of sourceFile.getClasses()) {
12246
+ const name = cls.getName();
12247
+ if (!name) continue;
12248
+ if (!name.endsWith("ContextFixture")) continue;
12249
+ if (name.endsWith(FIXTURE_SUFFIX)) continue;
12250
+ if (!extendsByName(cls, BASE_CONTEXT_FIXTURE_BASE)) continue;
12251
+ return name.slice(0, name.length - "ContextFixture".length);
12252
+ }
12253
+ return void 0;
12254
+ }
12255
+ function extendsByName(cls, baseName) {
12256
+ const extendsClause = cls.getExtends();
12257
+ if (!extendsClause) return false;
12258
+ const expr = extendsClause.getExpression();
12259
+ if (Node8.isIdentifier(expr)) {
12260
+ return expr.getText() === baseName;
12261
+ }
12262
+ return extendsClause.getText().startsWith(baseName);
12263
+ }
12264
+ function collectClasses(sourceFile, prefix, buckets) {
12265
+ for (const cls of sourceFile.getClasses()) {
12266
+ const name = cls.getName();
12267
+ if (!name) continue;
12268
+ const fixtureModel = bareModel(name, FIXTURE_SUFFIX, prefix);
12269
+ if (fixtureModel !== void 0) {
12270
+ buckets.fixtures.set(fixtureModel, cls);
12271
+ continue;
12272
+ }
12273
+ const instanceModel = bareModel(name, INSTANCE_SUFFIX, prefix);
12274
+ if (instanceModel !== void 0) {
12275
+ buckets.instances.set(instanceModel, cls);
12276
+ continue;
12277
+ }
12278
+ if (name.endsWith(FIXTURE_SUFFIX) || name.endsWith(INSTANCE_SUFFIX)) {
12279
+ buckets.unrecognized.push(name);
12280
+ }
12281
+ }
12282
+ }
12283
+ function bareModel(className, suffix, prefix) {
12284
+ if (!className.endsWith(suffix)) return void 0;
12285
+ const trimmed = className.slice(0, className.length - suffix.length);
12286
+ if (prefix === void 0 || prefix === "") {
12287
+ return trimmed.length > 0 ? trimmed : void 0;
12288
+ }
12289
+ if (!trimmed.startsWith(prefix)) return void 0;
12290
+ const model = trimmed.slice(prefix.length);
12291
+ return model.length > 0 ? model : void 0;
12292
+ }
12293
+ function collectParamsTypes(sourceFile, prefix) {
12294
+ const out = /* @__PURE__ */ new Map();
12295
+ for (const i of sourceFile.getInterfaces()) {
12296
+ const name = i.getName();
12297
+ const model = bareModel(name, PARAMS_SUFFIX, prefix);
12298
+ if (model === void 0) continue;
12299
+ out.set(model, readParamsInterface(i, model, prefix));
12300
+ }
12301
+ for (const a of sourceFile.getTypeAliases()) {
12302
+ const name = a.getName();
12303
+ const model = bareModel(name, PARAMS_SUFFIX, prefix);
12304
+ if (model === void 0) continue;
12305
+ out.set(model, readParamsAlias(a, model));
12306
+ }
12307
+ return out;
12308
+ }
12309
+ function readParamsInterface(i, _model, prefix) {
12310
+ const extendsClauses = i.getExtends().map((e) => e.getText());
12311
+ const partialExtends = extendsClauses.find((t) => t.startsWith("Partial<"));
12312
+ const extendsPartial = partialExtends !== void 0;
12313
+ const modelName = partialExtends ? partialExtends.slice("Partial<".length, -1).trim() : void 0;
12314
+ const fields = [];
12315
+ for (const prop of i.getProperties()) {
12316
+ const propName = prop.getName();
12317
+ const typeNode = prop.getTypeNode();
12318
+ const typeText = typeNode ? typeNode.getText() : "";
12319
+ const optional = prop.hasQuestionToken();
12320
+ const fixtureModel = resolveFixtureFieldModel(typeText, prefix);
12321
+ const isArray = /\bArrayOrValue\b|\[\]\s*$|\bArray</.test(typeText);
12322
+ const field = {
12323
+ name: propName,
12324
+ typeText,
12325
+ optional,
12326
+ fixtureModel,
12327
+ array: isArray
12328
+ };
12329
+ fields.push(field);
12330
+ }
12331
+ const result = {
12332
+ name: i.getName(),
12333
+ kind: "interface",
12334
+ extendsPartial,
12335
+ aliasOfPartial: false,
12336
+ modelName,
12337
+ fields,
12338
+ line: i.getStartLineNumber()
12339
+ };
12340
+ return result;
12341
+ }
12342
+ function readParamsAlias(a, _model) {
12343
+ const typeText = a.getTypeNode()?.getText() ?? "";
12344
+ const aliasOfPartial = typeText.startsWith("Partial<");
12345
+ const modelName = aliasOfPartial ? typeText.slice("Partial<".length, -1).trim() : void 0;
12346
+ const result = {
12347
+ name: a.getName(),
12348
+ kind: "alias",
12349
+ extendsPartial: false,
12350
+ aliasOfPartial,
12351
+ modelName,
12352
+ fields: [],
12353
+ line: a.getStartLineNumber()
12354
+ };
12355
+ return result;
12356
+ }
12357
+ function resolveFixtureFieldModel(typeText, prefix) {
12358
+ const match = typeText.match(/([A-Z]\w*)TestContextFixture/);
12359
+ if (!match) return void 0;
12360
+ const before = match[1];
12361
+ if (prefix === void 0 || prefix === "") return before;
12362
+ if (!before.startsWith(prefix)) return void 0;
12363
+ const model = before.slice(prefix.length);
12364
+ return model.length > 0 ? model : void 0;
12365
+ }
12366
+ function collectFactories(sourceFile, prefix) {
12367
+ const out = /* @__PURE__ */ new Map();
12368
+ for (const stmt of sourceFile.getVariableStatements()) {
12369
+ for (const decl of stmt.getDeclarations()) {
12370
+ const factory = readModelTestContextFactory(decl, prefix);
12371
+ if (!factory) continue;
12372
+ const model = factoryNameToModel(factory.factoryName, prefix);
12373
+ if (model === void 0) continue;
12374
+ out.set(model, factory);
12375
+ }
12376
+ }
12377
+ return out;
12378
+ }
12379
+ function readModelTestContextFactory(decl, _prefix) {
12380
+ const initializer = decl.getInitializer();
12381
+ if (!initializer) return void 0;
12382
+ let bodyExpr;
12383
+ if (Node8.isArrowFunction(initializer) || Node8.isFunctionExpression(initializer)) {
12384
+ bodyExpr = readSingleReturnExpression(initializer);
12385
+ } else {
12386
+ bodyExpr = initializer;
12387
+ }
12388
+ if (!bodyExpr || !Node8.isCallExpression(bodyExpr)) return void 0;
12389
+ const callee = bodyExpr.getExpression();
12390
+ if (!Node8.isIdentifier(callee) || callee.getText() !== MODEL_FACTORY_NAME) return void 0;
12391
+ const generics = bodyExpr.getTypeArguments().map((t) => t.getText());
12392
+ const args = bodyExpr.getArguments();
12393
+ let hasParamsGetCollection = false;
12394
+ let hasCollectionForDocument = false;
12395
+ let hasInitDocument = false;
12396
+ let parentFixtureFieldFromGetCollection;
12397
+ if (args.length > 0) {
12398
+ const first = args[0];
12399
+ if (Node8.isObjectLiteralExpression(first)) {
12400
+ const getCollection = first.getProperty("getCollection");
12401
+ if (getCollection && Node8.isPropertyAssignment(getCollection)) {
12402
+ const fnInit = getCollection.getInitializer();
12403
+ const arity = readArrowParameterCount(fnInit);
12404
+ if (arity >= 2) {
12405
+ hasParamsGetCollection = true;
12406
+ parentFixtureFieldFromGetCollection = readParamsAccessFieldName(fnInit);
12407
+ }
12408
+ }
12409
+ if (first.getProperty("collectionForDocument") !== void 0) {
12410
+ hasCollectionForDocument = true;
12411
+ }
12412
+ if (first.getProperty("initDocument") !== void 0) {
12413
+ hasInitDocument = true;
12414
+ }
12415
+ }
12416
+ }
12417
+ const result = {
12418
+ factoryName: decl.getName(),
12419
+ genericArgs: generics,
12420
+ hasParamsGetCollection,
12421
+ hasCollectionForDocument,
12422
+ hasInitDocument,
12423
+ parentFixtureFieldFromGetCollection,
12424
+ line: decl.getStartLineNumber()
12425
+ };
12426
+ return result;
12427
+ }
12428
+ function readSingleReturnExpression(fn) {
12429
+ const body = fn.getBody();
12430
+ if (!body) return void 0;
12431
+ if (Node8.isBlock(body)) {
12432
+ for (const stmt of body.getStatements()) {
12433
+ if (Node8.isReturnStatement(stmt)) {
12434
+ return stmt.getExpression();
12435
+ }
12436
+ }
12437
+ return void 0;
12438
+ }
12439
+ return body;
12440
+ }
12441
+ function readArrowParameterCount(fn) {
12442
+ if (!fn) return 0;
12443
+ if (Node8.isArrowFunction(fn) || Node8.isFunctionExpression(fn) || Node8.isFunctionDeclaration(fn) || Node8.isMethodDeclaration(fn)) {
12444
+ return fn.getParameters().length;
12445
+ }
12446
+ return 0;
12447
+ }
12448
+ function readParamsAccessFieldName(fn) {
12449
+ if (!fn) return void 0;
12450
+ if (!Node8.isArrowFunction(fn) && !Node8.isFunctionExpression(fn)) return void 0;
12451
+ const body = fn.getBody();
12452
+ if (!body) return void 0;
12453
+ for (const access2 of body.getDescendantsOfKind(SyntaxKind5.PropertyAccessExpression)) {
12454
+ const expr = access2.getExpression();
12455
+ if (Node8.isIdentifier(expr) && expr.getText() === "params") {
12456
+ return access2.getName();
12457
+ }
12458
+ }
12459
+ return void 0;
12460
+ }
12461
+ function factoryNameToModel(factoryName, prefix) {
12462
+ const suffix = "ContextFactory";
12463
+ if (!factoryName.endsWith(suffix)) return void 0;
12464
+ const head = factoryName.slice(0, factoryName.length - suffix.length);
12465
+ if (prefix === void 0 || prefix === "") {
12466
+ if (head.length === 0) return void 0;
12467
+ return head.charAt(0).toUpperCase() + head.slice(1);
12468
+ }
12469
+ const factoryPrefixCandidates = factoryPrefixesFromWorkspacePrefix(prefix);
12470
+ for (const factoryPrefix of factoryPrefixCandidates) {
12471
+ if (head.startsWith(factoryPrefix)) {
12472
+ const remainder = head.slice(factoryPrefix.length);
12473
+ if (remainder.length === 0) continue;
12474
+ return remainder.charAt(0).toUpperCase() + remainder.slice(1);
12475
+ }
12476
+ }
12477
+ return void 0;
12478
+ }
12479
+ function factoryPrefixesFromWorkspacePrefix(prefix) {
12480
+ const lower = prefix.charAt(0).toLowerCase() + prefix.slice(1);
12481
+ const apiSuffix = "Api";
12482
+ if (prefix.endsWith(apiSuffix)) {
12483
+ const trimmed = prefix.slice(0, prefix.length - apiSuffix.length);
12484
+ if (trimmed.length > 0) {
12485
+ const lowerTrimmed = trimmed.charAt(0).toLowerCase() + trimmed.slice(1);
12486
+ return [lower, lowerTrimmed];
12487
+ }
12488
+ }
12489
+ return [lower];
12490
+ }
12491
+ function collectSingletonsByFactory(sourceFile) {
12492
+ const out = /* @__PURE__ */ new Map();
12493
+ for (const stmt of sourceFile.getVariableStatements()) {
12494
+ for (const decl of stmt.getDeclarations()) {
12495
+ const init = decl.getInitializer();
12496
+ if (!init || !Node8.isCallExpression(init)) continue;
12497
+ const callee = init.getExpression();
12498
+ if (!Node8.isIdentifier(callee)) continue;
12499
+ out.set(callee.getText(), decl.getName());
12500
+ }
12501
+ }
12502
+ return out;
12503
+ }
12504
+ function collectAllModels(fixtures, instances) {
12505
+ const all = /* @__PURE__ */ new Set();
12506
+ for (const k of fixtures.keys()) all.add(k);
12507
+ for (const k of instances.keys()) all.add(k);
12508
+ const list = [...all];
12509
+ list.sort((a, b) => {
12510
+ const aLine = (fixtures.get(a) ?? instances.get(a))?.getStartLineNumber() ?? 0;
12511
+ const bLine = (fixtures.get(b) ?? instances.get(b))?.getStartLineNumber() ?? 0;
12512
+ return aLine - bLine;
12513
+ });
12514
+ return list;
12515
+ }
12516
+ function readClassMethods(cls) {
12517
+ const out = [];
12518
+ for (const m of cls.getMethods()) {
12519
+ out.push(readMethod(m));
12520
+ }
12521
+ return out;
12522
+ }
12523
+ function readMethod(m) {
12524
+ const visibility = readVisibility(m);
12525
+ const isAsync = m.isAsync();
12526
+ const isStatic = m.isStatic();
12527
+ const params = m.getParameters().map((p) => p.getText()).join(", ");
12528
+ const returnTypeNode = m.getReturnTypeNode();
12529
+ const returnTypeText = returnTypeNode ? returnTypeNode.getText() : void 0;
12530
+ const result = {
12531
+ name: m.getName(),
12532
+ isStatic,
12533
+ isAsync,
12534
+ visibility,
12535
+ parameterText: params,
12536
+ returnTypeText,
12537
+ line: m.getStartLineNumber(),
12538
+ endLine: m.getEndLineNumber()
12539
+ };
12540
+ return result;
12541
+ }
12542
+ function readVisibility(m) {
12543
+ if (m.hasModifier(SyntaxKind5.PrivateKeyword)) return "private";
12544
+ if (m.hasModifier(SyntaxKind5.ProtectedKeyword)) return "protected";
12545
+ return "public";
12546
+ }
12547
+ function readExtendsGenerics(cls) {
12548
+ const ext = cls.getExtends();
12549
+ if (!ext) return [];
12550
+ return ext.getTypeArguments().map((t) => t.getText());
12551
+ }
12552
+ function collectIdentityImports(sourceFile) {
12553
+ const out = /* @__PURE__ */ new Set();
12554
+ for (const imp of sourceFile.getImportDeclarations()) {
12555
+ for (const named of imp.getNamedImports()) {
12556
+ const name = named.getNameNode().getText();
12557
+ if (name.endsWith("Identity")) {
12558
+ out.add(name);
12559
+ }
12560
+ }
12561
+ }
12562
+ const list = [...out];
12563
+ list.sort();
12564
+ return list;
12565
+ }
12566
+
12567
+ // packages/dbx-components-mcp/src/tools/model-fixture-shared/inspect.ts
12568
+ import { readFile as readFile2 } from "node:fs/promises";
12569
+ import { join } from "node:path";
12570
+ var FIXTURE_RELATIVE_PATH = "src/test/fixture.ts";
12571
+ async function inspectAppFixtures(apiAbs, apiRel) {
12572
+ const absolutePath = join(apiAbs, FIXTURE_RELATIVE_PATH);
12573
+ const relativePath = `${apiRel}/${FIXTURE_RELATIVE_PATH}`;
12574
+ const text = await readFile2(absolutePath, "utf8");
12575
+ return extractAppFixturesFromText({ text, fixturePath: relativePath });
12576
+ }
12577
+
12578
+ // packages/dbx-components-mcp/src/tools/model-fixture-shared/validate.ts
12579
+ function validateAppFixtures(extraction, options = {}) {
12580
+ const diagnostics = [];
12581
+ for (const entry of extraction.entries) {
12582
+ pushTripletCompletenessDiagnostics(entry, diagnostics);
12583
+ pushForwardingDiagnostics(entry, diagnostics);
12584
+ pushGenericAlignmentDiagnostics(entry, diagnostics);
12585
+ pushArchetypeConsistencyDiagnostics(entry, diagnostics);
12586
+ pushParentFieldNamingDiagnostics(entry, options.registry, diagnostics);
12587
+ pushRegistryDiagnostics(entry, options.registry, diagnostics);
12588
+ }
12589
+ pushOrphanFixtureDiagnostics(extraction, diagnostics);
12590
+ pushModelsWithoutFixtureDiagnostics(extraction, options.registry, diagnostics);
12591
+ let errorCount = 0;
12592
+ let warningCount = 0;
12593
+ for (const d of diagnostics) {
12594
+ if (d.severity === "error") errorCount += 1;
12595
+ else warningCount += 1;
12596
+ }
12597
+ return {
12598
+ fixturePath: extraction.fixturePath,
12599
+ diagnostics,
12600
+ errorCount,
12601
+ warningCount
12602
+ };
12603
+ }
12604
+ function pushTripletCompletenessDiagnostics(entry, out) {
12605
+ if (!entry.factoryName) {
12606
+ out.push({
12607
+ code: "triplet-incomplete",
12608
+ severity: "error",
12609
+ model: entry.model,
12610
+ message: `Model \`${entry.model}\` has Fixture/Instance classes but no \`modelTestContextFactory\` registration.`,
12611
+ line: entry.fixtureLine
12612
+ });
12613
+ }
12614
+ if (entry.factoryName && !entry.singletonName) {
12615
+ out.push({
12616
+ code: "triplet-incomplete",
12617
+ severity: "warning",
12618
+ model: entry.model,
12619
+ message: `Factory \`${entry.factoryName}\` has no exported singleton (e.g. \`export const ${decapitalize(entry.prefix)}${entry.model}Context = ${entry.factoryName}();\`).`,
12620
+ line: entry.factory?.line
12621
+ });
12622
+ }
12623
+ if (!entry.params) {
12624
+ out.push({
12625
+ code: "triplet-incomplete",
12626
+ severity: "warning",
12627
+ model: entry.model,
12628
+ message: `Model \`${entry.model}\` has no \`${entry.prefix}${entry.model}TestContextParams\` interface or alias.`,
12629
+ line: entry.fixtureLine
12630
+ });
12631
+ }
12632
+ }
12633
+ function pushForwardingDiagnostics(entry, out) {
12634
+ const fixtureByName = new Map(entry.fixtureMethods.map((m) => [m.name, m]));
12635
+ for (const instanceMethod of entry.instanceMethods) {
12636
+ if (instanceMethod.visibility !== "public") continue;
12637
+ const fixtureMethod = fixtureByName.get(instanceMethod.name);
12638
+ if (!fixtureMethod) {
12639
+ out.push({
12640
+ code: "forwarder-missing",
12641
+ severity: "warning",
12642
+ model: entry.model,
12643
+ message: `Fixture \`${entry.fixtureClassName}\` is missing a forwarder for instance method \`${instanceMethod.name}\`.`,
12644
+ line: instanceMethod.line
12645
+ });
12646
+ continue;
12647
+ }
12648
+ if (!signaturesMatch(fixtureMethod, instanceMethod)) {
12649
+ out.push({
12650
+ code: "forwarder-divergent",
12651
+ severity: "warning",
12652
+ model: entry.model,
12653
+ message: `Fixture forwarder \`${fixtureMethod.name}\` signature differs from the instance method.`,
12654
+ line: fixtureMethod.line
12655
+ });
12656
+ }
12657
+ }
12658
+ }
12659
+ function pushGenericAlignmentDiagnostics(entry, out) {
12660
+ const fixGenerics = entry.fixtureExtendsGenerics;
12661
+ const instGenerics = entry.instanceExtendsGenerics;
12662
+ const factoryGenerics = entry.factory?.genericArgs ?? [];
12663
+ const fixModel = fixGenerics[0];
12664
+ const fixDoc = fixGenerics[1];
12665
+ const instModel = instGenerics[0];
12666
+ const instDoc = instGenerics[1];
12667
+ const factoryModel = factoryGenerics[0];
12668
+ const factoryDoc = factoryGenerics[1];
12669
+ if (fixModel !== void 0 && instModel !== void 0 && fixModel !== instModel) {
12670
+ out.push({
12671
+ code: "generics-misaligned",
12672
+ severity: "error",
12673
+ model: entry.model,
12674
+ message: `Model generic differs between Fixture (\`${fixModel}\`) and Instance (\`${instModel}\`).`,
12675
+ line: entry.fixtureLine
12676
+ });
12677
+ }
12678
+ if (fixDoc !== void 0 && instDoc !== void 0 && fixDoc !== instDoc) {
12679
+ out.push({
12680
+ code: "generics-misaligned",
12681
+ severity: "error",
12682
+ model: entry.model,
12683
+ message: `Document generic differs between Fixture (\`${fixDoc}\`) and Instance (\`${instDoc}\`).`,
12684
+ line: entry.fixtureLine
12685
+ });
12686
+ }
12687
+ if (factoryModel !== void 0 && fixModel !== void 0 && factoryModel !== fixModel) {
12688
+ out.push({
12689
+ code: "generics-misaligned",
12690
+ severity: "error",
12691
+ model: entry.model,
12692
+ message: `Model generic differs between factory (\`${factoryModel}\`) and Fixture (\`${fixModel}\`).`,
12693
+ line: entry.factory?.line
12694
+ });
12695
+ }
12696
+ if (factoryDoc !== void 0 && fixDoc !== void 0 && factoryDoc !== fixDoc) {
12697
+ out.push({
12698
+ code: "generics-misaligned",
12699
+ severity: "error",
12700
+ model: entry.model,
12701
+ message: `Document generic differs between factory (\`${factoryDoc}\`) and Fixture (\`${fixDoc}\`).`,
12702
+ line: entry.factory?.line
12703
+ });
12704
+ }
12705
+ }
12706
+ function pushArchetypeConsistencyDiagnostics(entry, out) {
12707
+ if (!entry.factory) return;
12708
+ const archetype = entry.archetype;
12709
+ if (archetype === "sub-collection" || archetype === "sub-collection-traversal") {
12710
+ const accessedField = entry.factory.parentFixtureFieldFromGetCollection;
12711
+ if (accessedField !== void 0) {
12712
+ const present = entry.params?.fields.some((f) => f.name === accessedField && f.fixtureModel !== void 0);
12713
+ if (!present) {
12714
+ out.push({
12715
+ code: "archetype-inconsistent",
12716
+ severity: "error",
12717
+ model: entry.model,
12718
+ message: `\`getCollection\` reads \`params.${accessedField}\` but the Params interface has no fixture-typed \`${accessedField}\` field.`,
12719
+ line: entry.factory.line
12720
+ });
12721
+ }
12722
+ }
12723
+ }
12724
+ }
12725
+ function pushParentFieldNamingDiagnostics(entry, registry, out) {
12726
+ if (!registry) return;
12727
+ if (!entry.params) return;
12728
+ for (const field of entry.params.fields) {
12729
+ if (field.fixtureModel === void 0) continue;
12730
+ const expected = lookupCollectionPrefix(registry, field.fixtureModel);
12731
+ if (expected === void 0) continue;
12732
+ if (field.name !== expected) {
12733
+ out.push({
12734
+ code: "params-field-naming",
12735
+ severity: "warning",
12736
+ model: entry.model,
12737
+ message: `Params field \`${field.name}: ${field.typeText}\` should be named \`${expected}\` to match \`${field.fixtureModel}\`'s firestoreModelIdentity short alias.`,
12738
+ line: entry.params.line
12739
+ });
12740
+ }
12741
+ }
12742
+ }
12743
+ function pushRegistryDiagnostics(entry, registry, out) {
12744
+ if (!registry) return;
12745
+ const known = registry.entries.find((m) => m.name === entry.model);
12746
+ if (!known) {
12747
+ out.push({
12748
+ code: "model-not-in-registry",
12749
+ severity: "warning",
12750
+ model: entry.model,
12751
+ message: `Model \`${entry.model}\` has a fixture but isn't in the supplied model registry.`,
12752
+ line: entry.fixtureLine
12753
+ });
12754
+ }
12755
+ }
12756
+ function pushOrphanFixtureDiagnostics(extraction, out) {
12757
+ for (const name of extraction.unrecognizedClassNames) {
12758
+ out.push({
12759
+ code: "triplet-incomplete",
12760
+ severity: "warning",
12761
+ message: `Class \`${name}\` ends in TestContextFixture/Instance but doesn't fit the \`<Prefix><Model><Suffix>\` convention.`
12762
+ });
12763
+ }
12764
+ }
12765
+ function pushModelsWithoutFixtureDiagnostics(extraction, registry, out) {
12766
+ if (!registry) return;
12767
+ const have = new Set(extraction.entries.map((e) => e.model));
12768
+ for (const m of registry.entries) {
12769
+ if (have.has(m.name)) continue;
12770
+ out.push({
12771
+ code: "model-without-fixture",
12772
+ severity: "warning",
12773
+ model: m.name,
12774
+ message: `Model \`${m.name}\` is in the registry but \`${extraction.fixturePath}\` doesn't declare a fixture for it.`
12775
+ });
12776
+ }
12777
+ }
12778
+ function signaturesMatch(a, b) {
12779
+ if (a.parameterText.replace(/\s+/g, "") !== b.parameterText.replace(/\s+/g, "")) return false;
12780
+ if (a.isAsync !== b.isAsync) return false;
12781
+ return true;
12782
+ }
12783
+ function decapitalize(s) {
12784
+ if (s.length === 0) return s;
12785
+ return s.charAt(0).toLowerCase() + s.slice(1);
12786
+ }
12787
+ function lookupCollectionPrefix(registry, modelName) {
12788
+ const entry = registry.entries.find((m) => m.name === modelName);
12789
+ return entry?.collectionPrefix;
12790
+ }
12791
+
12792
+ // packages/dbx-components-mcp/src/tools/model-fixture-shared/format.json.ts
12793
+ function formatListAsJson(extraction) {
12794
+ return stringify({
12795
+ fixturePath: extraction.fixturePath,
12796
+ prefix: extraction.prefix,
12797
+ identityImports: extraction.identityImports,
12798
+ unrecognizedClassNames: extraction.unrecognizedClassNames,
12799
+ entries: extraction.entries.map((e) => summarizeEntry(e))
12800
+ });
12801
+ }
12802
+ function formatLookupAsJson(extraction, entry) {
12803
+ return stringify({
12804
+ fixturePath: extraction.fixturePath,
12805
+ prefix: extraction.prefix,
12806
+ entry: summarizeEntry(entry, true)
12807
+ });
12808
+ }
12809
+ function formatValidationAsJson(result) {
12810
+ return stringify({
12811
+ fixturePath: result.fixturePath,
12812
+ errorCount: result.errorCount,
12813
+ warningCount: result.warningCount,
12814
+ diagnostics: result.diagnostics
12815
+ });
12816
+ }
12817
+ function summarizeEntry(entry, full = false) {
12818
+ const summary = {
12819
+ model: entry.model,
12820
+ prefix: entry.prefix,
12821
+ archetype: entry.archetype,
12822
+ fixtureClassName: entry.fixtureClassName,
12823
+ instanceClassName: entry.instanceClassName,
12824
+ paramsTypeName: entry.paramsTypeName,
12825
+ factoryName: entry.factoryName,
12826
+ singletonName: entry.singletonName,
12827
+ fixtureLine: entry.fixtureLine,
12828
+ fixtureEndLine: entry.fixtureEndLine,
12829
+ instanceLine: entry.instanceLine,
12830
+ instanceEndLine: entry.instanceEndLine,
12831
+ fixtureMethodNames: entry.fixtureMethods.map((m) => m.name),
12832
+ instanceMethodNames: entry.instanceMethods.map((m) => m.name)
12833
+ };
12834
+ if (full) {
12835
+ summary.fixtureExtendsGenerics = entry.fixtureExtendsGenerics;
12836
+ summary.instanceExtendsGenerics = entry.instanceExtendsGenerics;
12837
+ summary.factory = entry.factory;
12838
+ summary.params = entry.params;
12839
+ summary.fixtureMethods = entry.fixtureMethods;
12840
+ summary.instanceMethods = entry.instanceMethods;
12841
+ }
12842
+ return summary;
12843
+ }
12844
+ function stringify(value) {
12845
+ return JSON.stringify(value, null, 2);
12846
+ }
12847
+
12848
+ // packages/dbx-components-mcp/src/tools/model-fixture-shared/format.markdown.ts
12849
+ function formatListAsMarkdown(extraction) {
12850
+ const lines = [];
12851
+ lines.push(`# App fixtures \u2014 ${extraction.fixturePath}`);
12852
+ lines.push("");
12853
+ lines.push(`Detected workspace prefix: \`${extraction.prefix ?? "(none)"}\``);
12854
+ lines.push(`Identity imports: ${extraction.identityImports.length === 0 ? "_None._" : extraction.identityImports.map((s) => "`" + s + "`").join(", ")}`);
12855
+ lines.push("");
12856
+ lines.push(`## Fixtures (${extraction.entries.length})`);
12857
+ if (extraction.entries.length === 0) {
12858
+ lines.push("", "_No model fixtures found._");
12859
+ } else {
12860
+ lines.push("");
12861
+ lines.push("| Model | Archetype | Fixture | Instance | Params | Factory | Singleton | Methods (F/I) | Lines |");
12862
+ lines.push("|---|---|---|---|---|---|---|---|---|");
12863
+ for (const e of extraction.entries) {
12864
+ 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(" | ") + " |");
12865
+ }
12866
+ }
12867
+ if (extraction.unrecognizedClassNames.length > 0) {
12868
+ lines.push("", `## Unrecognized classes (${extraction.unrecognizedClassNames.length})`);
12869
+ for (const name of extraction.unrecognizedClassNames) {
12870
+ lines.push("", `- \`${name}\``);
12871
+ }
12872
+ }
12873
+ return lines.join("\n");
12874
+ }
12875
+ function formatLookupAsMarkdown(extraction, entry) {
12876
+ const lines = [];
12877
+ appendLookupHeader(lines, extraction, entry);
12878
+ appendLookupTriplet(lines, entry);
12879
+ appendLookupGenerics(lines, entry);
12880
+ appendLookupFactoryCallbacks(lines, entry);
12881
+ appendLookupParams(lines, entry);
12882
+ lines.push("", `## Methods \u2014 Fixture (${entry.fixtureMethods.length})`);
12883
+ appendMethodTable(lines, entry.fixtureMethods);
12884
+ lines.push("", `## Methods \u2014 Instance (${entry.instanceMethods.length})`);
12885
+ appendMethodTable(lines, entry.instanceMethods);
12886
+ lines.push("", "## Forwarding");
12887
+ appendForwardingTable(lines, entry);
12888
+ return lines.join("\n");
12889
+ }
12890
+ function appendLookupHeader(lines, extraction, entry) {
12891
+ lines.push(`# Fixture: \`${entry.prefix}${entry.model}\``, "", `Source: \`${extraction.fixturePath}\``, `Archetype: \`${entry.archetype}\``, "");
12892
+ }
12893
+ function appendLookupTriplet(lines, entry) {
12894
+ 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"}\``);
12895
+ }
12896
+ function appendLookupGenerics(lines, entry) {
12897
+ if (entry.fixtureExtendsGenerics.length > 0) {
12898
+ lines.push("", `Fixture generics: \`${entry.fixtureExtendsGenerics.join(", ")}\``);
12899
+ }
12900
+ if (entry.instanceExtendsGenerics.length > 0) {
12901
+ lines.push(`Instance generics: \`${entry.instanceExtendsGenerics.join(", ")}\``);
12902
+ }
12903
+ if (entry.factory && entry.factory.genericArgs.length > 0) {
12904
+ lines.push(`Factory generics: \`${entry.factory.genericArgs.join(", ")}\``);
12905
+ }
12906
+ }
12907
+ function appendLookupFactoryCallbacks(lines, entry) {
12908
+ if (!entry.factory) return;
12909
+ const flags = [];
12910
+ flags.push(`getCollection: ${entry.factory.hasParamsGetCollection ? "`(fi, params) => \u2026`" : "`(fi) => \u2026`"}`);
12911
+ if (entry.factory.hasCollectionForDocument) flags.push("`collectionForDocument` present");
12912
+ if (entry.factory.hasInitDocument) flags.push("`initDocument` present");
12913
+ lines.push(`Factory callbacks: ${flags.join(", ")}`);
12914
+ if (entry.factory.parentFixtureFieldFromGetCollection) {
12915
+ lines.push(`Parent fixture field used in \`getCollection\`: \`params.${entry.factory.parentFixtureFieldFromGetCollection}\``);
12916
+ }
12917
+ }
12918
+ function appendLookupParams(lines, entry) {
12919
+ if (!entry.params) return;
12920
+ lines.push("", "## Params", "", `- Kind: ${entry.params.kind}`);
12921
+ if (entry.params.extendsPartial) lines.push(`- Extends \`Partial<${entry.params.modelName ?? "?"}>\``);
12922
+ if (entry.params.aliasOfPartial) lines.push(`- Alias of \`Partial<${entry.params.modelName ?? "?"}>\``);
12923
+ if (entry.params.fields.length === 0) return;
12924
+ lines.push("", "| Field | Type | Optional | Fixture dependency |", "|---|---|---|---|");
12925
+ for (const field of entry.params.fields) {
12926
+ lines.push("| " + [code3(field.name), code3(field.typeText), field.optional ? "yes" : "no", field.fixtureModel ? code3(field.fixtureModel) : "\u2014"].join(" | ") + " |");
12927
+ }
12928
+ }
12929
+ function formatValidationAsMarkdown(result) {
12930
+ const lines = [];
12931
+ lines.push(`# Fixture validation \u2014 ${result.fixturePath}`);
12932
+ lines.push("");
12933
+ lines.push(`Errors: ${result.errorCount}`);
12934
+ lines.push(`Warnings: ${result.warningCount}`);
12935
+ if (result.diagnostics.length === 0) {
12936
+ lines.push("", "_No diagnostics._");
12937
+ return lines.join("\n");
12938
+ }
12939
+ lines.push("", "## Diagnostics");
12940
+ for (const d of result.diagnostics) {
12941
+ const linePart = d.line !== void 0 ? ` (line ${d.line})` : "";
12942
+ const modelPart = d.model !== void 0 ? ` [${d.model}]` : "";
12943
+ lines.push("", `- **${d.severity.toUpperCase()}** \`${d.code}\`${modelPart}${linePart}: ${d.message}`);
12944
+ }
12945
+ return lines.join("\n");
12946
+ }
12947
+ function appendMethodTable(lines, methods) {
12948
+ if (methods.length === 0) {
12949
+ lines.push("", "_None._");
12950
+ return;
12951
+ }
12952
+ lines.push("", "| Method | Async | Returns | Line |");
12953
+ lines.push("|---|---|---|---|");
12954
+ for (const m of methods) {
12955
+ lines.push("| " + [code3(m.name + "(" + m.parameterText + ")"), m.isAsync ? "yes" : "no", code3(m.returnTypeText ?? "\u2014"), String(m.line)].join(" | ") + " |");
12956
+ }
12957
+ }
12958
+ function appendForwardingTable(lines, entry) {
12959
+ if (entry.instanceMethods.length === 0) {
12960
+ lines.push("", "_No instance methods to forward._");
12961
+ return;
12962
+ }
12963
+ const fixtureByName = new Map(entry.fixtureMethods.map((m) => [m.name, m]));
12964
+ lines.push("", "| Instance method | Forwarded? |");
12965
+ lines.push("|---|---|");
12966
+ for (const m of entry.instanceMethods) {
12967
+ const fixtureMethod = fixtureByName.get(m.name);
12968
+ let status;
12969
+ if (!fixtureMethod) {
12970
+ status = "missing";
12971
+ } else if (fixtureMethod.parameterText.replace(/\s+/g, "") !== m.parameterText.replace(/\s+/g, "")) {
12972
+ status = "forwarded \u2014 signature drifts";
12973
+ } else {
12974
+ status = "forwarded";
12975
+ }
12976
+ lines.push("| " + [code3(m.name), status].join(" | ") + " |");
12977
+ }
12978
+ }
12979
+ function code3(s) {
12980
+ return "`" + s + "`";
12981
+ }
12982
+
12983
+ // packages/dbx-components-mcp/src/tools/model-fixture-shared/scaffold.ts
12984
+ function renderFixtureScaffold(extraction, input) {
12985
+ const prefix = input.prefix;
12986
+ const factoryPrefix = input.factoryNamePrefix ?? defaultFactoryPrefix(prefix);
12987
+ const paramsTypeName = `${prefix}${input.model}TestContextParams`;
12988
+ const fixtureClassName = `${prefix}${input.model}TestContextFixture`;
12989
+ const instanceClassName = `${prefix}${input.model}TestContextInstance`;
12990
+ const factoryName = `${factoryPrefix}${input.model}ContextFactory`;
12991
+ const singletonName = `${factoryPrefix}${input.model}Context`;
12992
+ const modelDocumentTypeName = input.modelDocumentTypeName ?? `${input.model}Document`;
12993
+ const collectionGenericArg = input.collectionGenericArg;
12994
+ const todos = [];
12995
+ const paramsLines = renderParamsBlock(input, paramsTypeName, todos);
12996
+ const instanceBlock = renderInstanceBlock({ prefix, instanceClassName, modelDocumentTypeName, model: input.model, todos });
12997
+ const fixtureBlock = renderFixtureBlock({ prefix, fixtureClassName, instanceClassName, modelDocumentTypeName, model: input.model, todos });
12998
+ const factoryBlock = renderFactoryBlock({
12999
+ prefix,
13000
+ factoryName,
13001
+ fixtureClassName,
13002
+ instanceClassName,
13003
+ paramsTypeName,
13004
+ archetype: input.archetype,
13005
+ model: input.model,
13006
+ modelDocumentTypeName,
13007
+ collectionGenericArg,
13008
+ parentFixture: input.parentFixture,
13009
+ parentFixtureField: input.parentFixtureField,
13010
+ withInitDocument: input.withInitDocument === true,
13011
+ todos
13012
+ });
13013
+ const singletonBlock = `export const ${singletonName} = ${factoryName}();`;
13014
+ const snippet = [`// MARK: ${input.model}`, paramsLines.join("\n"), "", instanceBlock, "", fixtureBlock, "", factoryBlock, "", singletonBlock, ""].join("\n");
13015
+ const inserted = [
13016
+ { kind: "params", name: paramsTypeName },
13017
+ { kind: "instance", name: instanceClassName },
13018
+ { kind: "fixture", name: fixtureClassName },
13019
+ { kind: "factory", name: factoryName },
13020
+ { kind: "singleton", name: singletonName }
13021
+ ];
13022
+ if (!extraction.fixturePath) {
13023
+ todos.push("Confirm fixture path was parsed.");
13024
+ }
13025
+ todos.push(`Add named imports for \`${input.model}\` and \`${modelDocumentTypeName}\` if not already present.`);
13026
+ if (collectionGenericArg) {
13027
+ todos.push(`Add named import for \`${collectionGenericArg}\`.`);
13028
+ }
13029
+ if (input.archetype === "sub-collection" || input.archetype === "sub-collection-traversal") {
13030
+ todos.push("Wire `getCollection` to the correct collection factory accessor on `<prefix>FirestoreCollections`.");
13031
+ }
13032
+ todos.push("Replace TODOs in `makeRef` and instance methods with real logic.");
13033
+ return {
13034
+ snippet,
13035
+ todos,
13036
+ inserted,
13037
+ paramsTypeName,
13038
+ fixtureClassName,
13039
+ instanceClassName,
13040
+ factoryName,
13041
+ singletonName
13042
+ };
13043
+ }
13044
+ function defaultFactoryPrefix(prefix) {
13045
+ if (prefix.length === 0) return "app";
13046
+ const apiSuffix = "Api";
13047
+ if (prefix.endsWith(apiSuffix)) {
13048
+ const trimmed = prefix.slice(0, prefix.length - apiSuffix.length);
13049
+ if (trimmed.length === 0) return "app";
13050
+ return trimmed.charAt(0).toLowerCase() + trimmed.slice(1);
13051
+ }
13052
+ return prefix.charAt(0).toLowerCase() + prefix.slice(1);
13053
+ }
13054
+ function renderParamsBlock(input, paramsTypeName, todos) {
13055
+ const lines = [];
13056
+ const isSimplePartial = input.archetype === "top-level-simple" && (!input.paramsDependsOn || input.paramsDependsOn.length === 0);
13057
+ if (isSimplePartial) {
13058
+ lines.push(`export type ${paramsTypeName} = Partial<${input.model}>;`);
13059
+ return lines;
13060
+ }
13061
+ const extendsClause = input.archetype === "top-level-simple" || input.archetype === "top-level-with-deps" ? ` extends Partial<${input.model}>` : "";
13062
+ lines.push(`export interface ${paramsTypeName}${extendsClause} {`);
13063
+ if (input.archetype === "sub-collection" || input.archetype === "sub-collection-traversal") {
13064
+ if (input.parentFixture) {
13065
+ const field = input.parentFixtureField ?? defaultParentFieldName(input.parentFixture);
13066
+ lines.push(` readonly ${field}: ${input.prefix}${input.parentFixture}TestContextFixture;`);
13067
+ } else {
13068
+ todos.push("Add the required parent fixture field on the Params interface.");
13069
+ }
13070
+ }
13071
+ for (const dep of input.paramsDependsOn ?? []) {
13072
+ const optional = dep.optional ? "?" : "";
13073
+ const baseType = `${input.prefix}${dep.fixtureModel}TestContextFixture`;
13074
+ const typeText = dep.array ? `Maybe<ArrayOrValue<${baseType}>>` : baseType;
13075
+ lines.push(` readonly ${dep.field}${optional}: ${typeText};`);
13076
+ }
13077
+ lines.push("}");
13078
+ return lines;
13079
+ }
13080
+ function renderInstanceBlock(input) {
13081
+ input.todos.push(`Add instance methods to \`${input.instanceClassName}\`.`);
13082
+ return [`export class ${input.instanceClassName}<F extends FirebaseAdminFunctionTestContextInstance = FirebaseAdminFunctionTestContextInstance> extends ModelTestContextInstance<${input.model}, ${input.modelDocumentTypeName}, ${input.prefix}FunctionContextFixtureInstance<F>> {`, " // TODO: implement instance-side methods (these own the real logic).", "}"].join("\n");
13083
+ }
13084
+ function renderFixtureBlock(input) {
13085
+ input.todos.push(`Add forwarder methods to \`${input.fixtureClassName}\` after defining instance methods.`);
13086
+ return [`export class ${input.fixtureClassName}<F extends FirebaseAdminFunctionTestContextInstance = FirebaseAdminFunctionTestContextInstance> extends ModelTestContextFixture<${input.model}, ${input.modelDocumentTypeName}, ${input.prefix}FunctionContextFixtureInstance<F>, ${input.prefix}FunctionContextFixture<F>, ${input.instanceClassName}<F>> {`, " // TODO: forward instance methods. Run `dbx_model_fixture_forward` after adding instance methods.", "}"].join("\n");
13087
+ }
13088
+ function renderFactoryBlock(input) {
13089
+ const generics = renderFactoryGenerics(input);
13090
+ const callbacks = renderFactoryCallbacks(input);
13091
+ const lines = [];
13092
+ lines.push(`export const ${input.factoryName} = () =>`);
13093
+ lines.push(` modelTestContextFactory<`);
13094
+ for (let i = 0; i < generics.length; i += 1) {
13095
+ const isLast = i === generics.length - 1;
13096
+ lines.push(` ${generics[i]}${isLast ? "" : ","}`);
13097
+ }
13098
+ lines.push(" >({");
13099
+ for (let i = 0; i < callbacks.length; i += 1) {
13100
+ const isLast = i === callbacks.length - 1;
13101
+ lines.push(` ${callbacks[i]}${isLast ? "" : ","}`);
13102
+ }
13103
+ lines.push(" });");
13104
+ return lines.join("\n");
13105
+ }
13106
+ function renderFactoryGenerics(input) {
13107
+ const baseGenerics = [input.model, input.modelDocumentTypeName, input.paramsTypeName, `${input.prefix}FunctionContextFixtureInstance<FirebaseAdminFunctionTestContextInstance>`, `${input.prefix}FunctionContextFixture<FirebaseAdminFunctionTestContextInstance>`, `${input.instanceClassName}<FirebaseAdminFunctionTestContextInstance>`, `${input.fixtureClassName}<FirebaseAdminFunctionTestContextInstance>`];
13108
+ if (input.collectionGenericArg) {
13109
+ return [...baseGenerics, input.collectionGenericArg];
13110
+ }
13111
+ if (input.archetype === "sub-collection" || input.archetype === "sub-collection-traversal") {
13112
+ return [...baseGenerics, `${input.model}FirestoreCollection`];
13113
+ }
13114
+ return baseGenerics;
13115
+ }
13116
+ function renderFactoryCallbacks(input) {
13117
+ const callbacks = [];
13118
+ callbacks.push(`makeFixture: (f) => new ${input.fixtureClassName}(f)`);
13119
+ if (input.archetype === "sub-collection" || input.archetype === "sub-collection-traversal") {
13120
+ const field = input.parentFixtureField ?? (input.parentFixture ? defaultParentFieldName(input.parentFixture) : "parent");
13121
+ callbacks.push(`getCollection: (fi, params) => fi.${defaultCollectionsAccessor(input.prefix)}.${camelInitial(input.model)}CollectionFactory(params.${field}.document)`);
13122
+ if (input.archetype === "sub-collection-traversal") {
13123
+ callbacks.push(`collectionForDocument: (fi, doc) => fi.${defaultCollectionsAccessor(input.prefix)}.${camelInitial(input.model)}Collection`);
13124
+ input.todos.push("Verify `collectionForDocument` resolves to the correct collection accessor.");
13125
+ }
13126
+ } else {
13127
+ callbacks.push(`getCollection: (fi) => fi.${defaultCollectionsAccessor(input.prefix)}.${camelInitial(input.model)}Collection`);
13128
+ }
13129
+ callbacks.push(`makeInstance: (delegate, ref, testInstance) => new ${input.instanceClassName}(delegate, ref, testInstance)`);
13130
+ callbacks.push(`makeRef: async (collection, params, _p) => {
13131
+ // TODO: choose the correct ref strategy (auto id vs deterministic id).
13132
+ return collection.documentAccessor().newDocument().documentRef;
13133
+ }`);
13134
+ if (input.withInitDocument) {
13135
+ callbacks.push(`initDocument: async (instance, params) => {
13136
+ // TODO: seed the new document with sensible defaults from \`params\`.
13137
+ }`);
13138
+ }
13139
+ return callbacks;
13140
+ }
13141
+ function defaultCollectionsAccessor(prefix) {
13142
+ const base = prefix.length > 0 ? prefix.charAt(0).toLowerCase() + prefix.slice(1) : "app";
13143
+ if (base.endsWith("Api")) {
13144
+ return `${base.slice(0, -3)}FirestoreCollections`;
13145
+ }
13146
+ return `${base}FirestoreCollections`;
13147
+ }
13148
+ function camelInitial(name) {
13149
+ if (name.length === 0) return name;
13150
+ return name.charAt(0).toLowerCase() + name.slice(1);
13151
+ }
13152
+ function defaultParentFieldName(parentModel) {
13153
+ const acronym = parentModel.match(/[A-Z]/g);
13154
+ if (!acronym || acronym.length === 0) return parentModel.toLowerCase();
13155
+ return acronym.join("").toLowerCase();
13156
+ }
13157
+
13158
+ // packages/dbx-components-mcp/src/tools/model-fixture-shared/forward.ts
13159
+ function renderForwarders(input) {
13160
+ const { entry, methods } = input;
13161
+ const fixtureNames = new Set(entry.fixtureMethods.map((m) => m.name));
13162
+ const wanted = methods ? new Set(methods) : void 0;
13163
+ const added = [];
13164
+ const skipped = [];
13165
+ const missing = [];
13166
+ const instanceByName = new Map(entry.instanceMethods.map((m) => [m.name, m]));
13167
+ if (wanted) {
13168
+ for (const name of wanted) {
13169
+ if (!instanceByName.has(name)) {
13170
+ missing.push(name);
13171
+ }
13172
+ }
13173
+ }
13174
+ for (const m of entry.instanceMethods) {
13175
+ if (m.visibility !== "public") continue;
13176
+ if (wanted && !wanted.has(m.name)) continue;
13177
+ if (fixtureNames.has(m.name)) {
13178
+ skipped.push(m.name);
13179
+ continue;
13180
+ }
13181
+ added.push(renderOne(m));
13182
+ }
13183
+ return {
13184
+ added,
13185
+ skippedAlreadyForwarded: skipped,
13186
+ missingFromInstance: missing
13187
+ };
13188
+ }
13189
+ function renderOne(m) {
13190
+ const asyncKw = m.isAsync ? "async " : "";
13191
+ const returnType = m.returnTypeText ? `: ${m.returnTypeText}` : "";
13192
+ const args = parameterCallText(m.parameterText);
13193
+ const body = `return this.instance.${m.name}(${args});`;
13194
+ const source = ` ${asyncKw}${m.name}(${m.parameterText})${returnType} {
13195
+ ${body}
13196
+ }`;
13197
+ return { method: m.name, source };
13198
+ }
13199
+ function parameterCallText(parameterText) {
13200
+ if (parameterText.trim().length === 0) return "";
13201
+ const params = splitParameters(parameterText);
13202
+ const out = [];
13203
+ for (const raw of params) {
13204
+ const trimmed = raw.trim();
13205
+ if (trimmed.length === 0) continue;
13206
+ const isRest = trimmed.startsWith("...");
13207
+ const stripped = isRest ? trimmed.slice(3) : trimmed;
13208
+ const equalsIdx = stripped.indexOf("=");
13209
+ const beforeEq = equalsIdx === -1 ? stripped : stripped.slice(0, equalsIdx);
13210
+ const colonIdx = topLevelColonIndex(beforeEq);
13211
+ const head = colonIdx === -1 ? beforeEq : beforeEq.slice(0, colonIdx);
13212
+ const cleaned = head.replace(/\?$/, "").trim();
13213
+ const name = cleaned.replace(/^public\s+|^private\s+|^protected\s+|^readonly\s+/, "").trim();
13214
+ if (name.length === 0) continue;
13215
+ out.push(isRest ? `...${name}` : name);
13216
+ }
13217
+ return out.join(", ");
13218
+ }
13219
+ function splitParameters(text) {
13220
+ const out = [];
13221
+ let depth = 0;
13222
+ let start = 0;
13223
+ for (let i = 0; i < text.length; i += 1) {
13224
+ const ch = text[i];
13225
+ if (ch === "<" || ch === "(" || ch === "[" || ch === "{") depth += 1;
13226
+ else if (ch === ">" || ch === ")" || ch === "]" || ch === "}") depth -= 1;
13227
+ else if (ch === "," && depth === 0) {
13228
+ out.push(text.slice(start, i));
13229
+ start = i + 1;
13230
+ }
13231
+ }
13232
+ out.push(text.slice(start));
13233
+ return out;
13234
+ }
13235
+ function topLevelColonIndex(text) {
13236
+ let depth = 0;
13237
+ let index = 0;
13238
+ for (const ch of text) {
13239
+ if (ch === "<" || ch === "(" || ch === "[" || ch === "{") depth += 1;
13240
+ else if (ch === ">" || ch === ")" || ch === "]" || ch === "}") depth -= 1;
13241
+ else if (ch === ":" && depth === 0) return index;
13242
+ index += 1;
13243
+ }
13244
+ return -1;
13245
+ }
13246
+
13247
+ // packages/dbx-components-mcp/src/tools/model-fixture-list-app.tool.ts
13248
+ var ListArgsType = type31({
13249
+ apiDir: "string",
13250
+ "format?": "'markdown' | 'json'"
13251
+ });
13252
+ var TOOL = {
13253
+ name: "dbx_model_fixture_list_app",
13254
+ description: [
13255
+ "List every `<Prefix><Model>TestContext{Fixture,Instance,Params}` triplet declared in a downstream API app's `src/test/fixture.ts`.",
13256
+ "",
13257
+ "Each row reports the model name, archetype (`top-level-simple` / `top-level-with-deps` / `sub-collection` / `sub-collection-traversal`), Fixture and Instance class names, Params type, factory + singleton, fixture/instance method counts, and start/end lines.",
13258
+ "",
13259
+ "Provide:",
13260
+ "- `apiDir`: relative path to the API app (e.g. `apps/demo-api`).",
13261
+ "- `format` (optional): `markdown` (default) or `json`.",
13262
+ "",
13263
+ "Paths escaping the server cwd are rejected."
13264
+ ].join("\n"),
13265
+ inputSchema: {
13266
+ type: "object",
13267
+ properties: {
13268
+ apiDir: { type: "string", description: "Relative path to the API app (e.g. `apps/demo-api`)." },
13269
+ format: { type: "string", enum: ["markdown", "json"], description: "Output format. Defaults to markdown." }
13270
+ },
13271
+ required: ["apiDir"]
13272
+ }
13273
+ };
13274
+ async function run(rawArgs) {
13275
+ const parsed = ListArgsType(rawArgs);
13276
+ if (parsed instanceof type31.errors) {
13277
+ return toolError(`Invalid arguments: ${parsed.summary}`);
13278
+ }
13279
+ const cwd = process.cwd();
13280
+ try {
13281
+ ensurePathInsideCwd(parsed.apiDir, cwd);
13282
+ } catch (err) {
13283
+ return toolError(err instanceof Error ? err.message : String(err));
13284
+ }
13285
+ const apiAbs = resolve15(cwd, parsed.apiDir);
13286
+ let extraction;
13287
+ try {
13288
+ extraction = await inspectAppFixtures(apiAbs, parsed.apiDir);
13289
+ } catch (err) {
13290
+ return toolError(`Failed to read fixture file: ${err instanceof Error ? err.message : String(err)}`);
13291
+ }
13292
+ const text = parsed.format === "json" ? formatListAsJson(extraction) : formatListAsMarkdown(extraction);
13293
+ const result = { content: [{ type: "text", text }] };
13294
+ return result;
13295
+ }
13296
+ var modelFixtureListAppTool = { definition: TOOL, run };
13297
+
13298
+ // packages/dbx-components-mcp/src/tools/model-fixture-lookup.tool.ts
13299
+ import { resolve as resolve16 } from "node:path";
13300
+ import { type as type32 } from "arktype";
13301
+ var LookupArgsType = type32({
13302
+ apiDir: "string",
13303
+ model: "string",
13304
+ "format?": "'markdown' | 'json'"
13305
+ });
13306
+ var TOOL2 = {
13307
+ name: "dbx_model_fixture_lookup",
13308
+ description: [
13309
+ "Look up one fixture/instance triplet declared in `<apiDir>/src/test/fixture.ts`. Returns the archetype, generic args, Params shape with dependency edges, factory + singleton names, and full method tables for both Fixture and Instance with forwarding status.",
13310
+ "",
13311
+ "Provide:",
13312
+ "- `apiDir`: relative path to the API app (e.g. `apps/demo-api`).",
13313
+ "- `model`: bare model name with the workspace prefix stripped (e.g. `StorageFile`, `Profile`).",
13314
+ "- `format` (optional): `markdown` (default) or `json`."
13315
+ ].join("\n"),
13316
+ inputSchema: {
13317
+ type: "object",
13318
+ properties: {
13319
+ apiDir: { type: "string", description: "Relative path to the API app." },
13320
+ model: { type: "string", description: "Bare model name (e.g. `StorageFile`)." },
13321
+ format: { type: "string", enum: ["markdown", "json"], description: "Output format. Defaults to markdown." }
13322
+ },
13323
+ required: ["apiDir", "model"]
13324
+ }
13325
+ };
13326
+ async function run2(rawArgs) {
13327
+ const parsed = LookupArgsType(rawArgs);
13328
+ if (parsed instanceof type32.errors) {
13329
+ return toolError(`Invalid arguments: ${parsed.summary}`);
13330
+ }
13331
+ const cwd = process.cwd();
13332
+ try {
13333
+ ensurePathInsideCwd(parsed.apiDir, cwd);
13334
+ } catch (err) {
13335
+ return toolError(err instanceof Error ? err.message : String(err));
13336
+ }
13337
+ const apiAbs = resolve16(cwd, parsed.apiDir);
13338
+ let extraction;
13339
+ try {
13340
+ extraction = await inspectAppFixtures(apiAbs, parsed.apiDir);
13341
+ } catch (err) {
13342
+ return toolError(`Failed to read fixture file: ${err instanceof Error ? err.message : String(err)}`);
13343
+ }
13344
+ const entry = extraction.entries.find((e) => e.model === parsed.model);
13345
+ if (!entry) {
13346
+ const known = extraction.entries.map((e) => e.model).join(", ") || "(none)";
13347
+ return toolError(`Model \`${parsed.model}\` not found in \`${extraction.fixturePath}\`. Known: ${known}.`);
13348
+ }
13349
+ const text = parsed.format === "json" ? formatLookupAsJson(extraction, entry) : formatLookupAsMarkdown(extraction, entry);
13350
+ const result = { content: [{ type: "text", text }] };
13351
+ return result;
13352
+ }
13353
+ var modelFixtureLookupTool = { definition: TOOL2, run: run2 };
13354
+
13355
+ // packages/dbx-components-mcp/src/tools/model-fixture-validate-app.tool.ts
13356
+ import { resolve as resolve17 } from "node:path";
13357
+ import { type as type33 } from "arktype";
13358
+ var ValidateArgsType = type33({
13359
+ apiDir: "string",
13360
+ "format?": "'markdown' | 'json'"
13361
+ });
13362
+ var TOOL3 = {
13363
+ name: "dbx_model_fixture_validate_app",
13364
+ description: [
13365
+ "Validate every `<Prefix><Model>TestContext{Fixture,Instance,Params}` triplet in a downstream API app's `src/test/fixture.ts`.",
13366
+ "",
13367
+ "Diagnostics emitted:",
13368
+ "- `forwarder-missing` / `forwarder-divergent`: every public Instance method must have a Fixture forwarder with a matching signature.",
13369
+ "- `triplet-incomplete`: Fixture, Instance, Params, factory, and singleton must all be present per model.",
13370
+ "- `generics-misaligned`: Model and Document generics must agree across Fixture, Instance, and factory call.",
13371
+ "- `archetype-inconsistent`: sub-collection wiring requires a matching parent fixture field on the Params type.",
13372
+ "- `params-field-naming`: parent fixture field names must equal the parent model's firestoreModelIdentity short alias (when a model registry is configured).",
13373
+ "- `model-not-in-registry` / `model-without-fixture`: registry cross-reference (when a model registry is configured).",
13374
+ "",
13375
+ "Provide:",
13376
+ "- `apiDir`: relative path to the API app.",
13377
+ "- `format` (optional): `markdown` (default) or `json`."
13378
+ ].join("\n"),
13379
+ inputSchema: {
13380
+ type: "object",
13381
+ properties: {
13382
+ apiDir: { type: "string", description: "Relative path to the API app." },
13383
+ format: { type: "string", enum: ["markdown", "json"], description: "Output format. Defaults to markdown." }
13384
+ },
13385
+ required: ["apiDir"]
13386
+ }
13387
+ };
13388
+ function createModelFixtureValidateAppTool(config = {}) {
13389
+ async function run5(rawArgs) {
13390
+ const parsed = ValidateArgsType(rawArgs);
13391
+ if (parsed instanceof type33.errors) {
13392
+ return toolError(`Invalid arguments: ${parsed.summary}`);
13393
+ }
13394
+ const cwd = process.cwd();
13395
+ try {
13396
+ ensurePathInsideCwd(parsed.apiDir, cwd);
13397
+ } catch (err) {
13398
+ return toolError(err instanceof Error ? err.message : String(err));
13399
+ }
13400
+ const apiAbs = resolve17(cwd, parsed.apiDir);
13401
+ let extraction;
13402
+ try {
13403
+ extraction = await inspectAppFixtures(apiAbs, parsed.apiDir);
13404
+ } catch (err) {
13405
+ return toolError(`Failed to read fixture file: ${err instanceof Error ? err.message : String(err)}`);
13406
+ }
13407
+ const registry = config.getRegistry ? config.getRegistry() : void 0;
13408
+ const result = validateAppFixtures(extraction, { registry });
13409
+ const text = parsed.format === "json" ? formatValidationAsJson(result) : formatValidationAsMarkdown(result);
13410
+ const toolResult = {
13411
+ content: [{ type: "text", text }],
13412
+ isError: result.errorCount > 0
13413
+ };
13414
+ return toolResult;
13415
+ }
13416
+ return { definition: TOOL3, run: run5 };
13417
+ }
13418
+
13419
+ // packages/dbx-components-mcp/src/tools/model-fixture-scaffold.tool.ts
13420
+ import { readFile as readFile3, writeFile } from "node:fs/promises";
13421
+ import { join as join2, resolve as resolve18 } from "node:path";
13422
+ import { type as type34 } from "arktype";
13423
+ var ScaffoldArgsType3 = type34({
13424
+ apiDir: "string",
13425
+ model: "string",
13426
+ archetype: "'top-level-simple' | 'top-level-with-deps' | 'sub-collection' | 'sub-collection-traversal'",
13427
+ "prefix?": "string",
13428
+ "parentFixture?": "string",
13429
+ "parentFixtureField?": "string",
13430
+ "paramsDependsOn?": type34({
13431
+ field: "string",
13432
+ fixtureModel: "string",
13433
+ "optional?": "boolean",
13434
+ "array?": "boolean"
13435
+ }).array(),
13436
+ "withInitDocument?": "boolean",
13437
+ "collectionGenericArg?": "string",
13438
+ "modelDocumentTypeName?": "string",
13439
+ "factoryNamePrefix?": "string"
13440
+ });
13441
+ var TOOL4 = {
13442
+ name: "dbx_model_fixture_scaffold",
13443
+ description: [
13444
+ "Scaffold a new fixture/instance triplet directly into `<apiDir>/src/test/fixture.ts`. The tool appends a single block containing the Params interface (or `Partial<Model>` alias), Instance class, Fixture class, `modelTestContextFactory(...)` registration, and exported singleton. Every customizable callback body is left as a `TODO`.",
13445
+ "",
13446
+ "Refuses to mutate when any of the named entities already exist \u2014 review the conflict list and either rename or delete the existing entries before retrying.",
13447
+ "",
13448
+ "Use the four archetypes to control the factory dialect:",
13449
+ "- `top-level-simple`: 7 generics, single-arg `getCollection`, `Partial<Model>` Params alias.",
13450
+ "- `top-level-with-deps`: same shape but Params extends `Partial<Model>` and adds the listed fixture dependencies.",
13451
+ "- `sub-collection`: 8 generics, two-arg `getCollection(fi, params)` reading the parent fixture's document. Pass `parentFixture` to drive the parent ref.",
13452
+ "- `sub-collection-traversal`: same as `sub-collection` plus a `collectionForDocument` skeleton.",
13453
+ "",
13454
+ "When `parentFixture` is supplied without `parentFixtureField`, the field name defaults to lowercased initials of the parent model name (`SchoolGroup` \u2192 `sg`). Pass `parentFixtureField` to override.",
13455
+ "",
13456
+ "Returns a structured summary of the inserted entities and a TODO checklist for follow-up edits."
13457
+ ].join("\n"),
13458
+ inputSchema: {
13459
+ type: "object",
13460
+ properties: {
13461
+ apiDir: { type: "string", description: "Relative path to the API app." },
13462
+ model: { type: "string", description: "Bare model name (e.g. `Widget`)." },
13463
+ archetype: { type: "string", enum: ["top-level-simple", "top-level-with-deps", "sub-collection", "sub-collection-traversal"], description: "Archetype that drives the factory shape." },
13464
+ prefix: { type: "string", description: "Workspace prefix override (e.g. `DemoApi`). Defaults to the prefix detected in the fixture file." },
13465
+ parentFixture: { type: "string", description: "Bare model name of the parent fixture for sub-collection archetypes." },
13466
+ parentFixtureField: { type: "string", description: "Override for the Params field that holds the parent fixture (defaults to lowercased initials of `parentFixture`, e.g. `sg`)." },
13467
+ paramsDependsOn: {
13468
+ type: "array",
13469
+ description: "Additional fixture refs to add to the Params interface.",
13470
+ items: {
13471
+ type: "object",
13472
+ properties: {
13473
+ field: { type: "string", description: "Params field name (e.g. `u`)." },
13474
+ fixtureModel: { type: "string", description: "Bare fixture model name (e.g. `AuthorizedUser`)." },
13475
+ optional: { type: "boolean", description: "When true the field is optional." },
13476
+ array: { type: "boolean", description: "When true the field type is wrapped in `Maybe<ArrayOrValue<...>>`." }
13477
+ },
13478
+ required: ["field", "fixtureModel"]
13479
+ }
13480
+ },
13481
+ withInitDocument: { type: "boolean", description: "When true an `initDocument` callback skeleton is emitted." },
13482
+ collectionGenericArg: { type: "string", description: "Explicit collection generic for 8-generic factories (e.g. `WidgetFirestoreCollection`)." },
13483
+ modelDocumentTypeName: { type: "string", description: "Override for the Document type name (defaults to `<Model>Document`)." },
13484
+ factoryNamePrefix: { type: "string", description: "Override for the factory name prefix (defaults to lowerCamel of the workspace prefix sans `Api` suffix)." }
13485
+ },
13486
+ required: ["apiDir", "model", "archetype"]
13487
+ }
13488
+ };
13489
+ async function run3(rawArgs) {
13490
+ const parsed = ScaffoldArgsType3(rawArgs);
13491
+ if (parsed instanceof type34.errors) {
13492
+ return toolError(`Invalid arguments: ${parsed.summary}`);
13493
+ }
13494
+ const cwd = process.cwd();
13495
+ try {
13496
+ ensurePathInsideCwd(parsed.apiDir, cwd);
13497
+ } catch (err) {
13498
+ return toolError(err instanceof Error ? err.message : String(err));
13499
+ }
13500
+ const apiAbs = resolve18(cwd, parsed.apiDir);
13501
+ let extraction;
13502
+ try {
13503
+ extraction = await inspectAppFixtures(apiAbs, parsed.apiDir);
13504
+ } catch (err) {
13505
+ return toolError(`Failed to read fixture file: ${err instanceof Error ? err.message : String(err)}`);
13506
+ }
13507
+ const prefix = parsed.prefix ?? extraction.prefix;
13508
+ if (!prefix) {
13509
+ return toolError("Could not detect a workspace prefix from the fixture file. Pass `prefix` explicitly (e.g. `DemoApi`).");
13510
+ }
13511
+ if ((parsed.archetype === "sub-collection" || parsed.archetype === "sub-collection-traversal") && !parsed.parentFixture) {
13512
+ return toolError(`Archetype \`${parsed.archetype}\` requires \`parentFixture\` (the bare parent model name).`);
13513
+ }
13514
+ const paramsDependsOn = (parsed.paramsDependsOn ?? []).map((d) => {
13515
+ const dependency = {
13516
+ field: d.field,
13517
+ fixtureModel: d.fixtureModel,
13518
+ optional: d.optional,
13519
+ array: d.array
13520
+ };
13521
+ return dependency;
13522
+ });
13523
+ const rendered = renderFixtureScaffold(extraction, {
13524
+ model: parsed.model,
13525
+ prefix,
13526
+ archetype: parsed.archetype,
13527
+ parentFixture: parsed.parentFixture,
13528
+ parentFixtureField: parsed.parentFixtureField,
13529
+ paramsDependsOn,
13530
+ withInitDocument: parsed.withInitDocument,
13531
+ collectionGenericArg: parsed.collectionGenericArg,
13532
+ modelDocumentTypeName: parsed.modelDocumentTypeName,
13533
+ factoryNamePrefix: parsed.factoryNamePrefix
13534
+ });
13535
+ const conflicts = collectConflicts(extraction, rendered);
13536
+ if (conflicts.length > 0) {
13537
+ return toolError(["Refusing to scaffold \u2014 the following names already exist in `" + extraction.fixturePath + "`:", "", ...conflicts.map((c) => "- `" + c + "`"), "", "Rename, delete, or pick a different model name and retry."].join("\n"));
13538
+ }
13539
+ const absolutePath = join2(apiAbs, FIXTURE_RELATIVE_PATH);
13540
+ let original;
13541
+ try {
13542
+ original = await readFile3(absolutePath, "utf8");
13543
+ } catch (err) {
13544
+ return toolError(`Failed to read fixture file: ${err instanceof Error ? err.message : String(err)}`);
13545
+ }
13546
+ const newline = original.endsWith("\n") ? "" : "\n";
13547
+ const updated = `${original}${newline}
13548
+ ${rendered.snippet}`;
13549
+ try {
13550
+ await writeFile(absolutePath, updated, "utf8");
13551
+ } catch (err) {
13552
+ return toolError(`Failed to write fixture file: ${err instanceof Error ? err.message : String(err)}`);
13553
+ }
13554
+ const reExtraction = extractAppFixturesFromText({ text: updated, fixturePath: extraction.fixturePath });
13555
+ const newEntry = reExtraction.entries.find((e) => e.fixtureClassName === rendered.fixtureClassName);
13556
+ const lines = [];
13557
+ lines.push(`# Scaffolded \`${rendered.fixtureClassName}\``);
13558
+ lines.push("");
13559
+ lines.push(`File: \`${extraction.fixturePath}\``);
13560
+ lines.push(`Archetype: \`${parsed.archetype}\``);
13561
+ lines.push("");
13562
+ lines.push("## Inserted");
13563
+ for (const ins of rendered.inserted) {
13564
+ lines.push(`- ${ins.kind}: \`${ins.name}\``);
13565
+ }
13566
+ if (newEntry) {
13567
+ lines.push("", `Fixture lines: ${newEntry.fixtureLine}-${newEntry.fixtureEndLine}`);
13568
+ lines.push(`Instance lines: ${newEntry.instanceLine}-${newEntry.instanceEndLine}`);
11922
13569
  }
11923
- lines.push(`}`);
11924
- return { path: `${args.fileBaseName}.store.accessor.ts`, body: lines.join("\n") };
11925
- }
11926
- function documentDirectiveBody(args) {
11927
- const docType = `${args.modelName}Document`;
11928
- const storeClass = `${args.modelName}DocumentStore`;
11929
- const directiveClass = `${args.appPrefixPascal}${args.modelName}DocumentStoreDirective`;
11930
- const selector = `[${args.appPrefixCamel}${args.modelName}Document]`;
11931
- const lines = [
11932
- `import { Directive, inject } from '@angular/core';`,
11933
- `import { DbxFirebaseDocumentStoreDirective, provideDbxFirebaseDocumentStoreDirective } from '@dereekb/dbx-firebase';`,
11934
- `import { type ${args.modelName}, type ${docType} } from '${args.firebasePackage}';`,
11935
- `import { ${storeClass} } from './${args.fileBaseName}.document.store';`,
11936
- "",
11937
- `@Directive({`,
11938
- ` selector: '${selector}',`,
11939
- ` providers: provideDbxFirebaseDocumentStoreDirective(${directiveClass}, ${storeClass}),`,
11940
- ` standalone: true`,
11941
- `})`,
11942
- `export class ${directiveClass} extends DbxFirebaseDocumentStoreDirective<${args.modelName}, ${docType}, ${storeClass}> {`,
11943
- ` constructor() {`,
11944
- ` super(inject(${storeClass}));`,
11945
- ` }`,
11946
- `}`
11947
- ];
11948
- return { path: `${args.fileBaseName}.document.store.directive.ts`, body: lines.join("\n") };
13570
+ lines.push("", "## Follow-up TODOs");
13571
+ for (const todo of rendered.todos) {
13572
+ lines.push(`- [ ] ${todo}`);
13573
+ }
13574
+ const result = { content: [{ type: "text", text: lines.join("\n") }] };
13575
+ return result;
11949
13576
  }
11950
- function collectionDirectiveBody(args) {
11951
- const docType = `${args.modelName}Document`;
11952
- const storeClass = `${args.modelName}CollectionStore`;
11953
- const directiveClass = `${args.appPrefixPascal}${args.modelName}CollectionStoreDirective`;
11954
- const selector = `[${args.appPrefixCamel}${args.modelName}Collection]`;
11955
- const lines = [
11956
- `import { Directive, inject } from '@angular/core';`,
11957
- `import { DbxFirebaseCollectionStoreDirective, provideDbxFirebaseCollectionStoreDirective } from '@dereekb/dbx-firebase';`,
11958
- `import { type ${args.modelName}, type ${docType} } from '${args.firebasePackage}';`,
11959
- `import { ${storeClass} } from './${args.fileBaseName}.collection.store';`,
11960
- "",
11961
- `@Directive({`,
11962
- ` selector: '${selector}',`,
11963
- ` providers: provideDbxFirebaseCollectionStoreDirective(${directiveClass}, ${storeClass}),`,
11964
- ` standalone: true`,
11965
- `})`,
11966
- `export class ${directiveClass} extends DbxFirebaseCollectionStoreDirective<${args.modelName}, ${docType}, ${storeClass}> {`,
11967
- ` constructor() {`,
11968
- ` super(inject(${storeClass}));`,
11969
- ` }`,
11970
- `}`
11971
- ];
11972
- return { path: `${args.fileBaseName}.collection.store.directive.ts`, body: lines.join("\n") };
13577
+ function collectConflicts(extraction, rendered) {
13578
+ const out = [];
13579
+ for (const e of extraction.entries) {
13580
+ if (e.fixtureClassName === rendered.fixtureClassName) out.push(rendered.fixtureClassName);
13581
+ if (e.instanceClassName === rendered.instanceClassName) out.push(rendered.instanceClassName);
13582
+ if (e.paramsTypeName === rendered.paramsTypeName) out.push(rendered.paramsTypeName);
13583
+ if (e.factoryName === rendered.factoryName) out.push(rendered.factoryName);
13584
+ if (e.singletonName === rendered.singletonName) out.push(rendered.singletonName);
13585
+ }
13586
+ return [...new Set(out)];
11973
13587
  }
11974
- function buildBlocks(args) {
11975
- const blocks = [];
11976
- if (args.shape === "system-state") {
11977
- blocks.push(systemStateAccessorBody(args));
11978
- } else {
11979
- for (const surface of args.surfaces) {
11980
- if (surface === "document") {
11981
- if (args.shape === "sub-collection" || args.shape === "singleton-sub") {
11982
- blocks.push(subDocumentStoreBody(args));
11983
- } else {
11984
- blocks.push(rootDocumentStoreBody(args));
11985
- }
11986
- if (args.profile.emitsDirectives) {
11987
- blocks.push(documentDirectiveBody(args));
11988
- }
11989
- } else {
11990
- if (args.shape === "sub-collection") {
11991
- blocks.push(subCollectionStoreBody(args));
11992
- } else {
11993
- blocks.push(rootCollectionStoreBody(args));
11994
- }
11995
- if (args.profile.emitsDirectives) {
11996
- blocks.push(collectionDirectiveBody(args));
11997
- }
13588
+ var modelFixtureScaffoldTool = { definition: TOOL4, run: run3 };
13589
+
13590
+ // packages/dbx-components-mcp/src/tools/model-fixture-forward.tool.ts
13591
+ import { join as join3, resolve as resolve19 } from "node:path";
13592
+ import { type as type35 } from "arktype";
13593
+ import { Project as Project7 } from "ts-morph";
13594
+ var ForwardArgsType = type35({
13595
+ apiDir: "string",
13596
+ model: "string",
13597
+ "methods?": "string[]"
13598
+ });
13599
+ var TOOL5 = {
13600
+ name: "dbx_model_fixture_forward",
13601
+ description: ["Insert the missing Fixture forwarder methods for one model in `<apiDir>/src/test/fixture.ts`. Every public Instance method that lacks a Fixture method gains a thin wrapper:", "", "```ts", "async <name>(<paramText>): <returnType> {", " return this.instance.<name>(<args>);", "}", "```", "", "Existing forwarders are left untouched (idempotent). Pass `methods` to limit the run to specific method names; omit to forward everything that's missing."].join("\n"),
13602
+ inputSchema: {
13603
+ type: "object",
13604
+ properties: {
13605
+ apiDir: { type: "string", description: "Relative path to the API app." },
13606
+ model: { type: "string", description: "Bare model name (e.g. `StorageFile`)." },
13607
+ methods: {
13608
+ type: "array",
13609
+ items: { type: "string" },
13610
+ description: "Optional whitelist of instance method names to forward."
11998
13611
  }
11999
- }
13612
+ },
13613
+ required: ["apiDir", "model"]
12000
13614
  }
12001
- return blocks;
12002
- }
12003
- function formatScaffold(args) {
12004
- const blocks = buildBlocks(args);
12005
- const surfaceLabel = args.shape === "system-state" ? "accessor" : args.surfaces.join(" + ");
12006
- const functionsLabel = args.functionsClass ?? "none";
12007
- const crudLabel = args.crudFunctions.length > 0 ? args.crudFunctions.map((c) => `${c.name} (${c.kind})`).join(", ") : "none";
12008
- const parentLabel = args.parentModel === void 0 ? "n/a" : args.parentModel.name;
12009
- const lines = [`# ${args.modelName} store scaffold`, "", `Shape: \`${args.shape}\` \xB7 Surfaces: ${surfaceLabel} \xB7 Parent: ${parentLabel} \xB7 Functions: ${functionsLabel} \xB7 Crud: ${crudLabel}`, "", `Drop into \`<app>/src/lib/modules/${args.fileBaseName.replaceAll(".", "/")}/store/\`.`, ""];
12010
- for (const block of blocks) {
12011
- lines.push(`## \`${block.path}\``, "", "```ts", block.body, "```", "");
13615
+ };
13616
+ async function run4(rawArgs) {
13617
+ const parsed = ForwardArgsType(rawArgs);
13618
+ if (parsed instanceof type35.errors) {
13619
+ return toolError(`Invalid arguments: ${parsed.summary}`);
12012
13620
  }
12013
- lines.push("## Notes", "", "- Each store is `@Injectable()` with no `providedIn` \u2014 wire it in the consuming feature module / route providers, alongside its directive (when present).");
12014
- if (args.shape === "sub-collection" || args.shape === "singleton-sub") {
12015
- lines.push(`- The \`${args.parentModel?.name}DocumentStore\` parent is injected with \`{ optional: true }\` so the store works both as a standalone and as a child of a parent's document directive.`);
13621
+ const cwd = process.cwd();
13622
+ try {
13623
+ ensurePathInsideCwd(parsed.apiDir, cwd);
13624
+ } catch (err) {
13625
+ return toolError(toErrorMessage(err));
12016
13626
  }
12017
- if (args.shape === "system-state") {
12018
- lines.push(`- The accessor wraps a shared \`SystemStateDocumentStore\` keyed by \`${args.systemStateTypeConst}\`. CRUD function helpers reference \`this.systemStateDocumentStore\` (not \`this\`).`);
13627
+ const apiAbs = resolve19(cwd, parsed.apiDir);
13628
+ let extraction;
13629
+ try {
13630
+ extraction = await inspectAppFixtures(apiAbs, parsed.apiDir);
13631
+ } catch (err) {
13632
+ return toolError(`Failed to read fixture file: ${toErrorMessage(err)}`);
12019
13633
  }
12020
- if (args.crudFunctions.length > 0) {
12021
- lines.push(`- ${args.crudFunctions.length} CRUD helper line${args.crudFunctions.length === 1 ? "" : "s"} wired through \`firebaseDocumentStore{Create,Update,Crud}Function\`.`);
13634
+ const entry = extraction.entries.find((e) => e.model === parsed.model);
13635
+ if (!entry) {
13636
+ const known = extraction.entries.map((e) => e.model).join(", ") || "(none)";
13637
+ return toolError(`Model \`${parsed.model}\` not found in \`${extraction.fixturePath}\`. Known: ${known}.`);
12022
13638
  }
12023
- lines.push('- \u2192 See `dbx_model_lookup topic="shapes"` for the full store-shape taxonomy.', "- \u2192 Skill: `dbx__guide__angular-stores`.");
12024
- return lines.join("\n");
13639
+ const rendered = renderForwarders({ entry, methods: parsed.methods });
13640
+ if (rendered.added.length === 0) {
13641
+ return { content: [{ type: "text", text: renderNoOpReport(extraction.fixturePath, entry.fixtureClassName, rendered) }] };
13642
+ }
13643
+ const absolutePath = join3(apiAbs, FIXTURE_RELATIVE_PATH);
13644
+ const writeError = await applyForwardersToFile(absolutePath, entry.fixtureClassName, rendered);
13645
+ if (writeError) {
13646
+ return toolError(writeError);
13647
+ }
13648
+ return { content: [{ type: "text", text: renderSuccessReport(extraction.fixturePath, entry.fixtureClassName, rendered) }] };
12025
13649
  }
12026
- function runModelStoreScaffold(rawArgs) {
12027
- let args;
13650
+ function toErrorMessage(err) {
13651
+ return err instanceof Error ? err.message : String(err);
13652
+ }
13653
+ async function applyForwardersToFile(absolutePath, fixtureClassName, rendered) {
13654
+ const project = new Project7({ skipAddingFilesFromTsConfig: true });
13655
+ let sourceFile;
12028
13656
  try {
12029
- args = parseArgs2(rawArgs);
13657
+ sourceFile = project.addSourceFileAtPath(absolutePath);
12030
13658
  } catch (err) {
12031
- const message = err instanceof Error ? err.message : String(err);
12032
- return toolError(message);
13659
+ return `Failed to load fixture file: ${toErrorMessage(err)}`;
12033
13660
  }
12034
- const text = formatScaffold(args);
12035
- const result = { content: [{ type: "text", text }] };
12036
- return result;
13661
+ const fixtureClass = sourceFile.getClass(fixtureClassName);
13662
+ if (!fixtureClass) {
13663
+ return `Could not locate class \`${fixtureClassName}\` for in-place edit. The fixture file may have been modified since parsing.`;
13664
+ }
13665
+ for (const forwarder of rendered.added) {
13666
+ fixtureClass.insertText(fixtureClass.getEnd() - 1, "\n" + forwarder.source + "\n");
13667
+ }
13668
+ sourceFile.formatText({ ensureNewLineAtEndOfFile: true });
13669
+ try {
13670
+ await sourceFile.save();
13671
+ } catch (err) {
13672
+ return `Failed to write fixture file: ${toErrorMessage(err)}`;
13673
+ }
13674
+ return void 0;
12037
13675
  }
12038
- var modelStoreScaffoldTool = {
12039
- definition: DBX_MODEL_STORE_SCAFFOLD_TOOL,
12040
- run: runModelStoreScaffold
12041
- };
13676
+ function renderNoOpReport(fixturePath, fixtureClassName, rendered) {
13677
+ const lines = [`# No forwarders to add for \`${fixtureClassName}\``, "", `File: \`${fixturePath}\``];
13678
+ appendListSection(lines, "## Already forwarded", rendered.skippedAlreadyForwarded);
13679
+ appendListSection(lines, "## Whitelisted methods missing from Instance", rendered.missingFromInstance);
13680
+ return lines.join("\n");
13681
+ }
13682
+ function renderSuccessReport(fixturePath, fixtureClassName, rendered) {
13683
+ const lines = [`# Forwarded ${rendered.added.length} method${rendered.added.length === 1 ? "" : "s"} to \`${fixtureClassName}\``, "", `File: \`${fixturePath}\``, "", "## Added"];
13684
+ for (const f of rendered.added) {
13685
+ lines.push(`- \`${f.method}\``);
13686
+ }
13687
+ appendListSection(lines, "## Skipped (already forwarded)", rendered.skippedAlreadyForwarded);
13688
+ appendListSection(lines, "## Whitelisted methods missing from Instance", rendered.missingFromInstance);
13689
+ return lines.join("\n");
13690
+ }
13691
+ function appendListSection(lines, heading, names) {
13692
+ if (names.length === 0) return;
13693
+ lines.push("", heading);
13694
+ for (const name of names) {
13695
+ lines.push(`- \`${name}\``);
13696
+ }
13697
+ }
13698
+ var modelFixtureForwardTool = { definition: TOOL5, run: run4 };
12042
13699
 
12043
13700
  // packages/dbx-components-mcp/src/tools/storagefile-m-validate-app/extract.ts
12044
- import { Node as Node9, SyntaxKind as SyntaxKind6 } from "ts-morph";
13701
+ import { Node as Node10, SyntaxKind as SyntaxKind7 } from "ts-morph";
12045
13702
 
12046
13703
  // packages/dbx-components-mcp/src/tools/_validate/ast.ts
12047
- import { Node as Node8, Project as Project6, SyntaxKind as SyntaxKind5 } from "ts-morph";
13704
+ import { Node as Node9, Project as Project8, SyntaxKind as SyntaxKind6 } from "ts-morph";
12048
13705
  var COMPONENT_VIRTUAL_PREFIX = "__component__/";
12049
13706
  var API_VIRTUAL_PREFIX = "__api__/";
12050
13707
  function buildInMemoryProject(input) {
12051
- const project = new Project6({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
13708
+ const project = new Project8({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
12052
13709
  const componentSources = [];
12053
13710
  const apiSources = [];
12054
13711
  for (const file of input.component.files) {
@@ -12068,28 +13725,28 @@ function componentRelPath(sourceFile) {
12068
13725
  }
12069
13726
  function unwrapAsExpressions(node) {
12070
13727
  let current = node;
12071
- while (current && Node8.isAsExpression(current)) {
13728
+ while (current && Node9.isAsExpression(current)) {
12072
13729
  current = current.getExpression();
12073
13730
  }
12074
13731
  return current;
12075
13732
  }
12076
13733
  function asObjectLiteral(node) {
12077
13734
  const inner = unwrapAsExpressions(node);
12078
- if (inner && Node8.isObjectLiteralExpression(inner)) {
13735
+ if (inner && Node9.isObjectLiteralExpression(inner)) {
12079
13736
  return inner;
12080
13737
  }
12081
13738
  return void 0;
12082
13739
  }
12083
13740
  function asArrayLiteral(node) {
12084
13741
  const inner = unwrapAsExpressions(node);
12085
- if (inner && Node8.isArrayLiteralExpression(inner)) {
13742
+ if (inner && Node9.isArrayLiteralExpression(inner)) {
12086
13743
  return inner;
12087
13744
  }
12088
13745
  return void 0;
12089
13746
  }
12090
13747
  function readStringLiteralInitializer(decl) {
12091
13748
  const initializer = unwrapAsExpressions(decl.getInitializer());
12092
- if (initializer && Node8.isStringLiteral(initializer)) {
13749
+ if (initializer && Node9.isStringLiteral(initializer)) {
12093
13750
  return initializer.getLiteralText();
12094
13751
  }
12095
13752
  return void 0;
@@ -12101,37 +13758,37 @@ function typeAnnotationText(node) {
12101
13758
  function getPropertyInitializer(obj, name) {
12102
13759
  const prop = obj.getProperty(name);
12103
13760
  if (!prop) return void 0;
12104
- if (Node8.isPropertyAssignment(prop)) {
13761
+ if (Node9.isPropertyAssignment(prop)) {
12105
13762
  return prop.getInitializer();
12106
13763
  }
12107
- if (Node8.isShorthandPropertyAssignment(prop)) {
13764
+ if (Node9.isShorthandPropertyAssignment(prop)) {
12108
13765
  return prop.getNameNode();
12109
13766
  }
12110
13767
  return void 0;
12111
13768
  }
12112
13769
  function readStringProperty2(obj, name) {
12113
13770
  const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
12114
- if (init && Node8.isStringLiteral(init)) {
13771
+ if (init && Node9.isStringLiteral(init)) {
12115
13772
  return init.getLiteralText();
12116
13773
  }
12117
13774
  return void 0;
12118
13775
  }
12119
13776
  function readIdentifierProperty(obj, name) {
12120
13777
  const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
12121
- if (init && Node8.isIdentifier(init)) {
13778
+ if (init && Node9.isIdentifier(init)) {
12122
13779
  return init.getText();
12123
13780
  }
12124
13781
  return void 0;
12125
13782
  }
12126
13783
  function findReturnExpression(fn) {
12127
- if (!Node8.isArrowFunction(fn) && !Node8.isFunctionDeclaration(fn) && !Node8.isFunctionExpression(fn)) {
13784
+ if (!Node9.isArrowFunction(fn) && !Node9.isFunctionDeclaration(fn) && !Node9.isFunctionExpression(fn)) {
12128
13785
  return void 0;
12129
13786
  }
12130
13787
  const body = fn.getBody();
12131
13788
  if (!body) return void 0;
12132
- if (Node8.isBlock(body)) {
13789
+ if (Node9.isBlock(body)) {
12133
13790
  for (const stmt of body.getStatements()) {
12134
- if (Node8.isReturnStatement(stmt)) {
13791
+ if (Node9.isReturnStatement(stmt)) {
12135
13792
  return stmt.getExpression();
12136
13793
  }
12137
13794
  }
@@ -12145,17 +13802,17 @@ function findLocalVariable(sf, name) {
12145
13802
  if (decl.getName() === name) return decl;
12146
13803
  }
12147
13804
  }
12148
- for (const decl of sf.getDescendantsOfKind(SyntaxKind5.VariableDeclaration)) {
13805
+ for (const decl of sf.getDescendantsOfKind(SyntaxKind6.VariableDeclaration)) {
12149
13806
  if (decl.getName() === name) return decl;
12150
13807
  }
12151
13808
  return void 0;
12152
13809
  }
12153
13810
  function collectTypeofReferences(node, out) {
12154
- if (Node8.isTypeQuery(node)) {
13811
+ if (Node9.isTypeQuery(node)) {
12155
13812
  out.push(node.getExprName().getText());
12156
13813
  return;
12157
13814
  }
12158
- for (const tq of node.getDescendantsOfKind(SyntaxKind5.TypeQuery)) {
13815
+ for (const tq of node.getDescendantsOfKind(SyntaxKind6.TypeQuery)) {
12159
13816
  out.push(tq.getExprName().getText());
12160
13817
  }
12161
13818
  }
@@ -12308,7 +13965,7 @@ function filterMaybeArrayFunction(filterFn) {
12308
13965
  return ((values) => {
12309
13966
  let result;
12310
13967
  if (values != null) {
12311
- result = values.filter(filterFn);
13968
+ result = values.filter((v, i, arr) => filterFn(v, i, arr));
12312
13969
  } else {
12313
13970
  result = [];
12314
13971
  }
@@ -12419,7 +14076,7 @@ function booleanKeyArrayUtility(readKey) {
12419
14076
  removeByKey
12420
14077
  };
12421
14078
  }
12422
- var BooleanStringKeyArrayUtility = booleanKeyArrayUtility((x) => x ? x : void 0);
14079
+ var BooleanStringKeyArrayUtility = booleanKeyArrayUtility((x) => x || void 0);
12423
14080
 
12424
14081
  // packages/util/src/lib/set/set.selection.ts
12425
14082
  function isSelectedDecisionFunctionFactory(config) {
@@ -12453,8 +14110,8 @@ function getFunctionType(x) {
12453
14110
  return typeof x === "function" ? x.prototype ? Object.getOwnPropertyDescriptor(x, "prototype")?.writable ? "function" : "class" : x.constructor.name === "AsyncFunction" ? "function" : "arrow" : null;
12454
14111
  }
12455
14112
  function isNonClassFunction(x) {
12456
- const type43 = getFunctionType(x);
12457
- return type43 != null && type43 !== "class";
14113
+ const type48 = getFunctionType(x);
14114
+ return type48 != null && type48 !== "class";
12458
14115
  }
12459
14116
 
12460
14117
  // packages/util/src/lib/getter/getter.ts
@@ -12531,9 +14188,9 @@ function asNumber(input) {
12531
14188
  }
12532
14189
 
12533
14190
  // packages/util/src/lib/number/round.ts
12534
- function roundingFunction(type43) {
14191
+ function roundingFunction(type48) {
12535
14192
  let fn;
12536
- switch (type43) {
14193
+ switch (type48) {
12537
14194
  case "floor":
12538
14195
  fn = Math.floor;
12539
14196
  break;
@@ -12771,7 +14428,7 @@ function filterKeyValueTuplesFunction(filter) {
12771
14428
  if (filter != null) {
12772
14429
  const filterFn = filterKeyValueTupleFunction(filter);
12773
14430
  result = (obj) => {
12774
- return allKeyValueTuples(obj).filter(filterFn);
14431
+ return allKeyValueTuples(obj).filter((kv, i) => filterFn(kv, i));
12775
14432
  };
12776
14433
  } else {
12777
14434
  result = allKeyValueTuples;
@@ -12786,9 +14443,9 @@ function filterKeyValueTuplesInputToFilter(input) {
12786
14443
  }
12787
14444
  function filterKeyValueTupleFunction(inputFilter) {
12788
14445
  const filter = filterKeyValueTuplesInputToFilter(inputFilter);
12789
- const { valueFilter: type43 = 1 /* UNDEFINED */, invertFilter: inverseFilter = false, keysFilter } = filter;
14446
+ const { valueFilter: type48 = 1 /* UNDEFINED */, invertFilter: inverseFilter = false, keysFilter } = filter;
12790
14447
  let filterFn;
12791
- switch (type43) {
14448
+ switch (type48) {
12792
14449
  case 1 /* UNDEFINED */:
12793
14450
  filterFn = ([, x]) => x !== void 0;
12794
14451
  break;
@@ -13047,7 +14704,7 @@ var NUMBER_STRING_DENCODER_64_DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcd
13047
14704
  var NUMBER_STRING_DENCODER_64_DEFAULT_NEGATIVE_PREFIX = "!";
13048
14705
  function numberStringDencoder(config) {
13049
14706
  const { negativePrefix, digits } = config;
13050
- const type43 = negativePrefix ? "integer" : "positive_integer";
14707
+ const type48 = negativePrefix ? "integer" : "positive_integer";
13051
14708
  const log2OfDigits = Math.min(6, Math.floor(Math.log2(digits.length)));
13052
14709
  const bitDepth = Math.pow(2, log2OfDigits);
13053
14710
  const bitMask = bitDepth - 1;
@@ -13084,7 +14741,7 @@ function numberStringDencoder(config) {
13084
14741
  return result;
13085
14742
  }
13086
14743
  return {
13087
- type: type43,
14744
+ type: type48,
13088
14745
  digits,
13089
14746
  bitDepth,
13090
14747
  negativePrefix,
@@ -13155,9 +14812,9 @@ function readableStreamToStringFunction(encoding) {
13155
14812
  var readableStreamToBase64 = readableStreamToStringFunction("base64");
13156
14813
  function readableStreamToBuffer(stream) {
13157
14814
  const chunks = [];
13158
- return new Promise((resolve17, reject) => {
14815
+ return new Promise((resolve22, reject) => {
13159
14816
  stream.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
13160
- stream.on("end", () => resolve17(Buffer.concat(chunks)));
14817
+ stream.on("end", () => resolve22(Buffer.concat(chunks)));
13161
14818
  stream.on("error", reject);
13162
14819
  });
13163
14820
  }
@@ -13580,7 +15237,7 @@ function extractUploadInitializerEntries(sources) {
13580
15237
  const out = [];
13581
15238
  for (const sf of sources) {
13582
15239
  const rel = apiRelPath(sf);
13583
- for (const decl of sf.getDescendantsOfKind(SyntaxKind6.VariableDeclaration)) {
15240
+ for (const decl of sf.getDescendantsOfKind(SyntaxKind7.VariableDeclaration)) {
13584
15241
  const typeText = typeAnnotationText(decl);
13585
15242
  if (typeText !== UPLOAD_SERVICE_INITIALIZER_TYPE) continue;
13586
15243
  const obj = asObjectLiteral(decl.getInitializer());
@@ -13610,7 +15267,7 @@ function buildApiFunctionIndex(sources) {
13610
15267
  for (const decl of stmt.getDeclarations()) {
13611
15268
  const initializer = unwrapAsExpressions(decl.getInitializer());
13612
15269
  if (!initializer) continue;
13613
- if (Node9.isArrowFunction(initializer) || Node9.isFunctionExpression(initializer)) {
15270
+ if (Node10.isArrowFunction(initializer) || Node10.isFunctionExpression(initializer)) {
13614
15271
  map.set(decl.getName(), { node: initializer, sourceFile: sf });
13615
15272
  }
13616
15273
  }
@@ -13623,34 +15280,34 @@ function collectInitializerBindingsFromValue(options) {
13623
15280
  const { node, sf, index, resolved, unresolved, visited } = options;
13624
15281
  const inner = unwrapAsExpressions(node);
13625
15282
  if (!inner) return false;
13626
- if (Node9.isArrayLiteralExpression(inner)) {
15283
+ if (Node10.isArrayLiteralExpression(inner)) {
13627
15284
  for (const el of inner.getElements()) {
13628
- if (Node9.isSpreadElement(el)) {
15285
+ if (Node10.isSpreadElement(el)) {
13629
15286
  const spreadInner = el.getExpression();
13630
- if (Node9.isIdentifier(spreadInner)) {
15287
+ if (Node10.isIdentifier(spreadInner)) {
13631
15288
  collectInitializerBindingsFromIdentifier({ name: spreadInner.getText(), sf, index, resolved, unresolved, visited });
13632
- } else if (Node9.isCallExpression(spreadInner)) {
15289
+ } else if (Node10.isCallExpression(spreadInner)) {
13633
15290
  const callee = spreadInner.getExpression();
13634
- if (Node9.isIdentifier(callee)) {
15291
+ if (Node10.isIdentifier(callee)) {
13635
15292
  collectInitializerBindingsFromIdentifier({ name: callee.getText(), sf, index, resolved, unresolved, visited });
13636
15293
  }
13637
15294
  }
13638
15295
  continue;
13639
15296
  }
13640
15297
  const elementInner = unwrapAsExpressions(el);
13641
- if (elementInner && Node9.isIdentifier(elementInner)) {
15298
+ if (elementInner && Node10.isIdentifier(elementInner)) {
13642
15299
  resolved.push(elementInner.getText());
13643
15300
  }
13644
15301
  }
13645
15302
  return true;
13646
15303
  }
13647
- if (Node9.isCallExpression(inner)) {
15304
+ if (Node10.isCallExpression(inner)) {
13648
15305
  const callee = inner.getExpression();
13649
- if (Node9.isIdentifier(callee)) {
15306
+ if (Node10.isIdentifier(callee)) {
13650
15307
  return collectInitializerBindingsFromIdentifier({ name: callee.getText(), sf, index, resolved, unresolved, visited });
13651
15308
  }
13652
15309
  }
13653
- if (Node9.isIdentifier(inner)) {
15310
+ if (Node10.isIdentifier(inner)) {
13654
15311
  return collectInitializerBindingsFromIdentifier({ name: inner.getText(), sf, index, resolved, unresolved, visited });
13655
15312
  }
13656
15313
  return false;
@@ -13689,15 +15346,15 @@ function collectUploadInitializerArray(options) {
13689
15346
  const { initializerArr, sf, index, direct, spreads, resolved, unresolved } = options;
13690
15347
  const visited = /* @__PURE__ */ new Set();
13691
15348
  for (const el of initializerArr.getElements()) {
13692
- if (Node9.isSpreadElement(el)) {
15349
+ if (Node10.isSpreadElement(el)) {
13693
15350
  const inner2 = el.getExpression();
13694
- if (Node9.isIdentifier(inner2)) {
15351
+ if (Node10.isIdentifier(inner2)) {
13695
15352
  const name = inner2.getText();
13696
15353
  spreads.push(name);
13697
15354
  collectInitializerBindingsFromIdentifier({ name, sf, index, resolved, unresolved, visited });
13698
- } else if (Node9.isCallExpression(inner2)) {
15355
+ } else if (Node10.isCallExpression(inner2)) {
13699
15356
  const callee = inner2.getExpression();
13700
- if (Node9.isIdentifier(callee)) {
15357
+ if (Node10.isIdentifier(callee)) {
13701
15358
  const name = callee.getText();
13702
15359
  spreads.push(name);
13703
15360
  collectInitializerBindingsFromIdentifier({ name, sf, index, resolved, unresolved, visited });
@@ -13706,7 +15363,7 @@ function collectUploadInitializerArray(options) {
13706
15363
  continue;
13707
15364
  }
13708
15365
  const inner = unwrapAsExpressions(el);
13709
- if (inner && Node9.isIdentifier(inner)) {
15366
+ if (inner && Node10.isIdentifier(inner)) {
13710
15367
  const name = inner.getText();
13711
15368
  direct.push(name);
13712
15369
  resolved.push(name);
@@ -13717,9 +15374,9 @@ function extractUploadServiceCalls(sources, index) {
13717
15374
  const out = [];
13718
15375
  for (const sf of sources) {
13719
15376
  const rel = apiRelPath(sf);
13720
- for (const call of sf.getDescendantsOfKind(SyntaxKind6.CallExpression)) {
15377
+ for (const call of sf.getDescendantsOfKind(SyntaxKind7.CallExpression)) {
13721
15378
  const expr = call.getExpression();
13722
- if (!Node9.isIdentifier(expr) || expr.getText() !== UPLOAD_SERVICE_FACTORY) continue;
15379
+ if (!Node10.isIdentifier(expr) || expr.getText() !== UPLOAD_SERVICE_FACTORY) continue;
13723
15380
  const args = call.getArguments();
13724
15381
  const first = args[0] ? resolveObjectArg(args[0], sf) : void 0;
13725
15382
  if (!first) continue;
@@ -13747,12 +15404,12 @@ function extractUploadServiceCalls(sources, index) {
13747
15404
  function resolveObjectArg(node, sf) {
13748
15405
  const inner = unwrapAsExpressions(node);
13749
15406
  if (!inner) return void 0;
13750
- if (Node9.isObjectLiteralExpression(inner)) return inner;
13751
- if (Node9.isIdentifier(inner)) {
15407
+ if (Node10.isObjectLiteralExpression(inner)) return inner;
15408
+ if (Node10.isIdentifier(inner)) {
13752
15409
  const declNode = findLocalVariable(sf, inner.getText());
13753
15410
  if (declNode) {
13754
15411
  const declInit = unwrapAsExpressions(declNode.getInitializer());
13755
- if (declInit && Node9.isObjectLiteralExpression(declInit)) {
15412
+ if (declInit && Node10.isObjectLiteralExpression(declInit)) {
13756
15413
  return declInit;
13757
15414
  }
13758
15415
  }
@@ -13762,12 +15419,12 @@ function resolveObjectArg(node, sf) {
13762
15419
  function resolveArrayFromProperty(obj, name, sf) {
13763
15420
  const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
13764
15421
  if (!init) return void 0;
13765
- if (Node9.isArrayLiteralExpression(init)) return init;
13766
- if (Node9.isIdentifier(init)) {
15422
+ if (Node10.isArrayLiteralExpression(init)) return init;
15423
+ if (Node10.isIdentifier(init)) {
13767
15424
  const declNode = findLocalVariable(sf, init.getText());
13768
15425
  if (declNode) {
13769
15426
  const declInit = unwrapAsExpressions(declNode.getInitializer());
13770
- if (declInit && Node9.isArrayLiteralExpression(declInit)) {
15427
+ if (declInit && Node10.isArrayLiteralExpression(declInit)) {
13771
15428
  return declInit;
13772
15429
  }
13773
15430
  }
@@ -13778,11 +15435,11 @@ function enclosingFactoryName(node) {
13778
15435
  let current = node.getParent();
13779
15436
  let result;
13780
15437
  while (current) {
13781
- if (Node9.isFunctionDeclaration(current)) {
15438
+ if (Node10.isFunctionDeclaration(current)) {
13782
15439
  result = current.getName() ?? void 0;
13783
15440
  break;
13784
15441
  }
13785
- if (Node9.isVariableDeclaration(current)) {
15442
+ if (Node10.isVariableDeclaration(current)) {
13786
15443
  result = current.getName();
13787
15444
  break;
13788
15445
  }
@@ -13794,7 +15451,7 @@ function extractUploadServiceWirings(sources) {
13794
15451
  const out = [];
13795
15452
  for (const sf of sources) {
13796
15453
  const rel = apiRelPath(sf);
13797
- for (const obj of sf.getDescendantsOfKind(SyntaxKind6.ObjectLiteralExpression)) {
15454
+ for (const obj of sf.getDescendantsOfKind(SyntaxKind7.ObjectLiteralExpression)) {
13798
15455
  const provideIdent = readIdentifierProperty(obj, "provide");
13799
15456
  if (provideIdent !== UPLOAD_SERVICE_PROVIDE_TOKEN) continue;
13800
15457
  const useFactory = readIdentifierProperty(obj, "useFactory");
@@ -13807,7 +15464,7 @@ function extractProcessingConfigs(sources) {
13807
15464
  const out = [];
13808
15465
  for (const sf of sources) {
13809
15466
  const rel = apiRelPath(sf);
13810
- for (const decl of sf.getDescendantsOfKind(SyntaxKind6.VariableDeclaration)) {
15467
+ for (const decl of sf.getDescendantsOfKind(SyntaxKind7.VariableDeclaration)) {
13811
15468
  const config = extractProcessingConfigFromDecl(decl, rel);
13812
15469
  if (config) {
13813
15470
  out.push(config);
@@ -13836,10 +15493,10 @@ function extractProcessingConfigFromDecl(decl, rel) {
13836
15493
  function readFlowSubtasks(obj) {
13837
15494
  const flowInit = unwrapAsExpressions(getPropertyInitializer(obj, "flow"));
13838
15495
  const subtasks = [];
13839
- if (flowInit && Node9.isArrayLiteralExpression(flowInit)) {
15496
+ if (flowInit && Node10.isArrayLiteralExpression(flowInit)) {
13840
15497
  for (const el of flowInit.getElements()) {
13841
15498
  const inner = unwrapAsExpressions(el);
13842
- if (inner && Node9.isObjectLiteralExpression(inner)) {
15499
+ if (inner && Node10.isObjectLiteralExpression(inner)) {
13843
15500
  const subtask = readIdentifierProperty(inner, "subtask");
13844
15501
  if (subtask) subtasks.push(subtask);
13845
15502
  }
@@ -13851,9 +15508,9 @@ function extractProcessingHandlerCalls(sources) {
13851
15508
  const out = [];
13852
15509
  for (const sf of sources) {
13853
15510
  const rel = apiRelPath(sf);
13854
- for (const call of sf.getDescendantsOfKind(SyntaxKind6.CallExpression)) {
15511
+ for (const call of sf.getDescendantsOfKind(SyntaxKind7.CallExpression)) {
13855
15512
  const expr = call.getExpression();
13856
- if (!Node9.isIdentifier(expr) || expr.getText() !== PROCESSING_HANDLER_FACTORY) continue;
15513
+ if (!Node10.isIdentifier(expr) || expr.getText() !== PROCESSING_HANDLER_FACTORY) continue;
13857
15514
  const args = call.getArguments();
13858
15515
  const first = args[0] ? resolveObjectArg(args[0], sf) : void 0;
13859
15516
  if (!first) continue;
@@ -13874,7 +15531,7 @@ function extractProcessingHandlerCalls(sources) {
13874
15531
  }
13875
15532
  function collectProcessorArrayElements(processorsArr, direct, spreads) {
13876
15533
  for (const el of processorsArr.getElements()) {
13877
- if (Node9.isSpreadElement(el)) {
15534
+ if (Node10.isSpreadElement(el)) {
13878
15535
  addProcessorIdentifierName(el.getExpression(), spreads);
13879
15536
  continue;
13880
15537
  }
@@ -13886,13 +15543,13 @@ function collectProcessorArrayElements(processorsArr, direct, spreads) {
13886
15543
  }
13887
15544
  function addProcessorIdentifierName(node, bucket) {
13888
15545
  if (!node) return;
13889
- if (Node9.isIdentifier(node)) {
15546
+ if (Node10.isIdentifier(node)) {
13890
15547
  bucket.push(node.getText());
13891
15548
  return;
13892
15549
  }
13893
- if (Node9.isCallExpression(node)) {
15550
+ if (Node10.isCallExpression(node)) {
13894
15551
  const callee = node.getExpression();
13895
- if (Node9.isIdentifier(callee)) {
15552
+ if (Node10.isIdentifier(callee)) {
13896
15553
  bucket.push(callee.getText());
13897
15554
  }
13898
15555
  }
@@ -13934,7 +15591,7 @@ function runRules4(inspection, extracted) {
13934
15591
  violations,
13935
15592
  codes: IO_VIOLATION_CODES,
13936
15593
  messages: IO_VIOLATION_MESSAGES,
13937
- build: (code10, message, side) => buildIoViolation(code10, message, side)
15594
+ build: (code11, message, side) => buildIoViolation(code11, message, side)
13938
15595
  });
13939
15596
  if (!proceed) {
13940
15597
  return violations;
@@ -14166,18 +15823,18 @@ function checkDuplicates(extracted, violations) {
14166
15823
  flagDuplicates({ entries: extracted.fileTypeIdentifierConstants.map(toCodeRef), code: "STORAGEFILE_FILE_TYPE_IDENTIFIER_DUPLICATE", label: "`UploadedFileTypeIdentifier`", violations });
14167
15824
  }
14168
15825
  function toCodeRef(entry) {
14169
- const code10 = "purposeCode" in entry ? entry.purposeCode : entry.typeCode;
14170
- return { symbolName: entry.symbolName, code: code10, sourceFile: entry.sourceFile };
15826
+ const code11 = "purposeCode" in entry ? entry.purposeCode : entry.typeCode;
15827
+ return { symbolName: entry.symbolName, code: code11, sourceFile: entry.sourceFile };
14171
15828
  }
14172
15829
  function flagDuplicates(options) {
14173
- const { entries, code: code10, label, violations } = options;
15830
+ const { entries, code: code11, label, violations } = options;
14174
15831
  const seen = /* @__PURE__ */ new Map();
14175
15832
  for (const entry of entries) {
14176
15833
  if (!entry.code) continue;
14177
15834
  const previous = seen.get(entry.code);
14178
15835
  if (previous) {
14179
15836
  pushViolation4(violations, {
14180
- code: code10,
15837
+ code: code11,
14181
15838
  severity: "warning",
14182
15839
  message: `${label} value \`'${entry.code}'\` is shared by \`${previous}\` and \`${entry.symbolName}\`. Choose unique string literals.`,
14183
15840
  side: "component",
@@ -14227,9 +15884,9 @@ function pushViolation4(buffer, violation) {
14227
15884
  };
14228
15885
  buffer.push(filled);
14229
15886
  }
14230
- function buildIoViolation(code10, message, side) {
15887
+ function buildIoViolation(code11, message, side) {
14231
15888
  const result = {
14232
- code: code10,
15889
+ code: code11,
14233
15890
  severity: "error",
14234
15891
  message,
14235
15892
  side,
@@ -14245,8 +15902,8 @@ function formatResult4(result) {
14245
15902
  }
14246
15903
 
14247
15904
  // packages/dbx-components-mcp/src/tools/_validate/inspect.ts
14248
- import { readdir as readdir2, readFile as readFile2, stat as stat3 } from "node:fs/promises";
14249
- import { join, relative as relative4, sep as sep2 } from "node:path";
15905
+ import { readdir as readdir2, readFile as readFile4, stat as stat3 } from "node:fs/promises";
15906
+ import { join as join4, relative as relative4, sep as sep2 } from "node:path";
14250
15907
  async function inspectSide(rootDir, subpaths) {
14251
15908
  const rootStatus = await readRootStatus(rootDir);
14252
15909
  if (rootStatus !== void 0) {
@@ -14256,7 +15913,7 @@ async function inspectSide(rootDir, subpaths) {
14256
15913
  const presentFolders = [];
14257
15914
  const collectedFiles = [];
14258
15915
  for (const sub of subpaths) {
14259
- const absFolder = join(rootDir, sub);
15916
+ const absFolder = join4(rootDir, sub);
14260
15917
  const folderPresent = await isDirectory(absFolder);
14261
15918
  if (!folderPresent) continue;
14262
15919
  presentFolders.push(sub);
@@ -14275,8 +15932,8 @@ async function readRootStatus(rootDir) {
14275
15932
  const stats = await stat3(rootDir);
14276
15933
  return stats.isDirectory() ? void 0 : "dir-not-found";
14277
15934
  } catch (err) {
14278
- const code10 = err.code;
14279
- if (code10 === "ENOENT" || code10 === "ENOTDIR") {
15935
+ const code11 = err.code;
15936
+ if (code11 === "ENOENT" || code11 === "ENOTDIR") {
14280
15937
  return "dir-not-found";
14281
15938
  }
14282
15939
  throw err;
@@ -14302,7 +15959,7 @@ async function collectTsFiles(absFolder, rootDir) {
14302
15959
  continue;
14303
15960
  }
14304
15961
  for (const entry of entries) {
14305
- const full = join(current, entry.name);
15962
+ const full = join4(current, entry.name);
14306
15963
  if (entry.isDirectory()) {
14307
15964
  stack.push(full);
14308
15965
  continue;
@@ -14311,7 +15968,7 @@ async function collectTsFiles(absFolder, rootDir) {
14311
15968
  if (!entry.name.endsWith(".ts")) continue;
14312
15969
  if (entry.name.endsWith(".spec.ts")) continue;
14313
15970
  if (entry.name.endsWith(".d.ts")) continue;
14314
- const text = await readFile2(full, "utf8");
15971
+ const text = await readFile4(full, "utf8");
14315
15972
  const rel = relative4(rootDir, full).split(sep2).join("/");
14316
15973
  out.push({ relPath: rel, text });
14317
15974
  }
@@ -14483,7 +16140,7 @@ function formatReportAsJson(report) {
14483
16140
  // packages/dbx-components-mcp/src/tools/storagefile-m-list-app/format.markdown.ts
14484
16141
  function formatReportAsMarkdown(report) {
14485
16142
  const basename4 = report.componentDir.split("/").pop() ?? report.componentDir;
14486
- const uploadServiceFactoryText = report.uploadServiceFactoryName ? code3(report.uploadServiceFactoryName) : "_Not defined._";
16143
+ const uploadServiceFactoryText = report.uploadServiceFactoryName ? code4(report.uploadServiceFactoryName) : "_Not defined._";
14487
16144
  const lines = [`# App storagefiles \u2014 ${basename4}`, "", `Component: \`${report.componentDir}\``, `API: \`${report.apiDir}\``, "", `Upload service factory: ${uploadServiceFactoryText}`, `Wired via \`StorageFileInitializeFromUploadService\` provider: ${formatBool(report.uploadServiceWiredInApi)}`, `Processing handler call present: ${formatBool(report.processingHandlerWiredInApi)}`, "", `## Purposes (${report.purposes.length})`];
14488
16145
  if (report.purposes.length === 0) {
14489
16146
  lines.push("", "_None found._");
@@ -14499,15 +16156,15 @@ function formatPurposeBlock(p) {
14499
16156
  const heading = p.purposeCode ? `### ${p.purposeCode} \u2014 \`${p.purposeSymbolName}\`` : `### \`${p.purposeSymbolName}\``;
14500
16157
  parts.push(heading);
14501
16158
  if (p.fileTypeIdentifierCode) {
14502
- const codePart = p.fileTypeIdentifier ? ` (` + code3(`'${p.fileTypeIdentifier}'`) + `)` : "";
16159
+ const codePart = p.fileTypeIdentifier ? ` (` + code4(`'${p.fileTypeIdentifier}'`) + `)` : "";
14503
16160
  parts.push(`- Uploaded file type identifier: \`${p.fileTypeIdentifierCode}\`${codePart}`);
14504
16161
  } else {
14505
16162
  parts.push(`- Uploaded file type identifier: _Missing._`);
14506
16163
  }
14507
- const groupIdsText = p.fileGroupIdsFunctionName ? code3(p.fileGroupIdsFunctionName) : "_Missing._";
16164
+ const groupIdsText = p.fileGroupIdsFunctionName ? code4(p.fileGroupIdsFunctionName) : "_Missing._";
14508
16165
  parts.push(`- Group-ids helper: ${groupIdsText}`);
14509
16166
  if (p.subtasks.length > 0) {
14510
- const subtasksText = p.subtasks.map((s) => code3(s)).join(", ");
16167
+ const subtasksText = p.subtasks.map((s) => code4(s)).join(", ");
14511
16168
  parts.push(`- Processing subtasks: ${subtasksText}`);
14512
16169
  }
14513
16170
  const uploadInitSuffix = p.uploadInitializerSourceFile ? ` _(${p.uploadInitializerSourceFile})_` : "";
@@ -14518,7 +16175,7 @@ function formatPurposeBlock(p) {
14518
16175
  function formatBool(value) {
14519
16176
  return value ? "yes" : "no";
14520
16177
  }
14521
- function code3(value) {
16178
+ function code4(value) {
14522
16179
  return "`" + value + "`";
14523
16180
  }
14524
16181
 
@@ -14564,8 +16221,8 @@ var storageFileMListAppTool = createListAppTool({
14564
16221
  });
14565
16222
 
14566
16223
  // packages/dbx-components-mcp/src/tools/validate-two-side-folder.ts
14567
- import { readdir as readdir3, readFile as readFile3, stat as stat4 } from "node:fs/promises";
14568
- import { join as join2 } from "node:path";
16224
+ import { readdir as readdir3, readFile as readFile5, stat as stat4 } from "node:fs/promises";
16225
+ import { join as join5 } from "node:path";
14569
16226
  var REEXPORT_PATTERN = /^\s*export\s+\*\s+from\s+['"]\.\/([^'"\n]+)['"]\s*;?\s*$/gm;
14570
16227
  function createTwoSideFolderValidator(config) {
14571
16228
  async function inspect(input) {
@@ -14609,7 +16266,7 @@ async function inspectSide2(input) {
14609
16266
  let indexSource;
14610
16267
  const rootStatOk = await isExistingDirectory(rootDir);
14611
16268
  if (rootStatOk) {
14612
- const absFolder = join2(rootDir, subPath);
16269
+ const absFolder = join5(rootDir, subPath);
14613
16270
  const folderStatOk = await isExistingDirectory(absFolder);
14614
16271
  if (folderStatOk) {
14615
16272
  const folder = await readFolder(absFolder, indexFile);
@@ -14638,8 +16295,8 @@ async function isExistingDirectory(path) {
14638
16295
  const stats = await stat4(path);
14639
16296
  return stats.isDirectory();
14640
16297
  } catch (err) {
14641
- const code10 = err.code;
14642
- if (code10 !== "ENOENT" && code10 !== "ENOTDIR") {
16298
+ const code11 = err.code;
16299
+ if (code11 !== "ENOENT" && code11 !== "ENOTDIR") {
14643
16300
  throw err;
14644
16301
  }
14645
16302
  return false;
@@ -14661,7 +16318,7 @@ async function readFolder(absFolder, indexFile) {
14661
16318
  let indexSource;
14662
16319
  if (collectedFiles.includes(indexFile)) {
14663
16320
  try {
14664
- indexSource = await readFile3(join2(absFolder, indexFile), "utf8");
16321
+ indexSource = await readFile5(join5(absFolder, indexFile), "utf8");
14665
16322
  } catch {
14666
16323
  indexSource = void 0;
14667
16324
  }
@@ -14880,7 +16537,7 @@ var storageFileMValidateFolderTool = createTwoSideValidateTool({
14880
16537
  });
14881
16538
 
14882
16539
  // packages/dbx-components-mcp/src/tools/notification-m-validate-app/extract.ts
14883
- import { Node as Node10, SyntaxKind as SyntaxKind7 } from "ts-morph";
16540
+ import { Node as Node11, SyntaxKind as SyntaxKind8 } from "ts-morph";
14884
16541
  var NOTIF_TEMPLATE_TYPE = "NotificationTemplateType";
14885
16542
  var NOTIF_TEMPLATE_TYPE_INFO = "NotificationTemplateTypeInfo";
14886
16543
  var NOTIF_TEMPLATE_TYPE_INFO_ARRAY = "NotificationTemplateTypeInfo[]";
@@ -15001,7 +16658,7 @@ function extractTemplateInfoAggregates(sources) {
15001
16658
  const ids = [];
15002
16659
  for (const el of arr.getElements()) {
15003
16660
  const inner = unwrapAsExpressions(el);
15004
- if (inner && Node10.isIdentifier(inner)) {
16661
+ if (inner && Node11.isIdentifier(inner)) {
15005
16662
  ids.push(inner.getText());
15006
16663
  }
15007
16664
  }
@@ -15047,7 +16704,7 @@ function extractTaskAllTypesAggregates(sources) {
15047
16704
  const ids = [];
15048
16705
  for (const el of arr.getElements()) {
15049
16706
  const inner = unwrapAsExpressions(el);
15050
- if (inner && Node10.isIdentifier(inner)) {
16707
+ if (inner && Node11.isIdentifier(inner)) {
15051
16708
  ids.push(inner.getText());
15052
16709
  }
15053
16710
  }
@@ -15075,14 +16732,14 @@ function extractTaskCheckpointAliases(sources) {
15075
16732
  return out;
15076
16733
  }
15077
16734
  function collectStringLiterals(node, out) {
15078
- if (Node10.isLiteralTypeNode(node)) {
16735
+ if (Node11.isLiteralTypeNode(node)) {
15079
16736
  const lit = node.getLiteral();
15080
- if (Node10.isStringLiteral(lit)) {
16737
+ if (Node11.isStringLiteral(lit)) {
15081
16738
  out.push(lit.getLiteralText());
15082
16739
  }
15083
16740
  return;
15084
16741
  }
15085
- if (Node10.isUnionTypeNode(node)) {
16742
+ if (Node11.isUnionTypeNode(node)) {
15086
16743
  for (const child of node.getTypeNodes()) {
15087
16744
  collectStringLiterals(child, out);
15088
16745
  }
@@ -15136,7 +16793,7 @@ function extractTemplateInfoRecord(sources, index) {
15136
16793
  }
15137
16794
  function tryReadTemplateInfoRecord(decl, rel, index) {
15138
16795
  const initializer = unwrapAsExpressions(decl.getInitializer());
15139
- if (!initializer || !Node10.isCallExpression(initializer)) return void 0;
16796
+ if (!initializer || !Node11.isCallExpression(initializer)) return void 0;
15140
16797
  if (initializer.getExpression().getText() !== TEMPLATE_INFO_RECORD_FACTORY) return void 0;
15141
16798
  const args = initializer.getArguments();
15142
16799
  const arr = args[0] ? asArrayLiteral(args[0]) : void 0;
@@ -15157,15 +16814,15 @@ function tryReadTemplateInfoRecord(decl, rel, index) {
15157
16814
  }
15158
16815
  function classifyInfoRecordArrayElements(arr, direct, spreads) {
15159
16816
  for (const el of arr.getElements()) {
15160
- if (Node10.isSpreadElement(el)) {
16817
+ if (Node11.isSpreadElement(el)) {
15161
16818
  const inner2 = el.getExpression();
15162
- if (Node10.isIdentifier(inner2)) {
16819
+ if (Node11.isIdentifier(inner2)) {
15163
16820
  spreads.push(inner2.getText());
15164
16821
  }
15165
16822
  continue;
15166
16823
  }
15167
16824
  const inner = unwrapAsExpressions(el);
15168
- if (inner && Node10.isIdentifier(inner)) {
16825
+ if (inner && Node11.isIdentifier(inner)) {
15169
16826
  direct.push(inner.getText());
15170
16827
  }
15171
16828
  }
@@ -15186,13 +16843,13 @@ function resolveTemplateInfoSpreads(direct, spreads, index) {
15186
16843
  function extractTemplateInfoRecordWiring(sources) {
15187
16844
  for (const sf of sources) {
15188
16845
  const rel = apiRelPath(sf);
15189
- for (const call of sf.getDescendantsOfKind(SyntaxKind7.CallExpression)) {
16846
+ for (const call of sf.getDescendantsOfKind(SyntaxKind8.CallExpression)) {
15190
16847
  if (call.getExpression().getText() !== TEMPLATE_INFO_RECORD_SERVICE) continue;
15191
16848
  const args = call.getArguments();
15192
16849
  const first = args[0];
15193
16850
  if (!first) continue;
15194
16851
  const inner = unwrapAsExpressions(first);
15195
- if (!inner || !Node10.isIdentifier(inner)) continue;
16852
+ if (!inner || !Node11.isIdentifier(inner)) continue;
15196
16853
  const result = {
15197
16854
  recordIdentifier: inner.getText(),
15198
16855
  sourceFile: rel
@@ -15205,7 +16862,7 @@ function extractTemplateInfoRecordWiring(sources) {
15205
16862
  function extractTemplateConfigsArrayWiring(sources) {
15206
16863
  for (const sf of sources) {
15207
16864
  const rel = apiRelPath(sf);
15208
- for (const obj of sf.getDescendantsOfKind(SyntaxKind7.ObjectLiteralExpression)) {
16865
+ for (const obj of sf.getDescendantsOfKind(SyntaxKind8.ObjectLiteralExpression)) {
15209
16866
  const provideIdent = readIdentifierProperty(obj, "provide");
15210
16867
  if (provideIdent !== TEMPLATE_CONFIGS_ARRAY_TOKEN) continue;
15211
16868
  const useFactoryIdent = readIdentifierProperty(obj, "useFactory");
@@ -15230,7 +16887,7 @@ function buildApiFunctionIndex2(sources) {
15230
16887
  for (const decl of stmt.getDeclarations()) {
15231
16888
  const initializer = unwrapAsExpressions(decl.getInitializer());
15232
16889
  if (!initializer) continue;
15233
- if (Node10.isArrowFunction(initializer) || Node10.isFunctionExpression(initializer)) {
16890
+ if (Node11.isArrowFunction(initializer) || Node11.isFunctionExpression(initializer)) {
15234
16891
  map.set(decl.getName(), { node: initializer, sourceFile: sf, relPath: rel });
15235
16892
  }
15236
16893
  }
@@ -15266,11 +16923,11 @@ function extractTemplateConfigsArrayFactory(sources, index) {
15266
16923
  const arr = returnExpr ? asArrayLiteral(returnExpr) : void 0;
15267
16924
  if (arr) {
15268
16925
  for (const el of arr.getElements()) {
15269
- if (Node10.isSpreadElement(el)) {
16926
+ if (Node11.isSpreadElement(el)) {
15270
16927
  const inner2 = el.getExpression();
15271
- if (Node10.isCallExpression(inner2)) {
16928
+ if (Node11.isCallExpression(inner2)) {
15272
16929
  const callee = inner2.getExpression();
15273
- if (Node10.isIdentifier(callee)) {
16930
+ if (Node11.isIdentifier(callee)) {
15274
16931
  const callName = callee.getText();
15275
16932
  spreadCalls.push(callName);
15276
16933
  if (!index.functionsByName.has(callName)) {
@@ -15281,9 +16938,9 @@ function extractTemplateConfigsArrayFactory(sources, index) {
15281
16938
  continue;
15282
16939
  }
15283
16940
  const inner = unwrapAsExpressions(el);
15284
- if (inner && Node10.isCallExpression(inner)) {
16941
+ if (inner && Node11.isCallExpression(inner)) {
15285
16942
  const callee = inner.getExpression();
15286
- if (Node10.isIdentifier(callee)) {
16943
+ if (Node11.isIdentifier(callee)) {
15287
16944
  directCalls.push(callee.getText());
15288
16945
  }
15289
16946
  }
@@ -15332,11 +16989,11 @@ function collectFromArrayEntryFactory(name, out, index) {
15332
16989
  const arr = asArrayLiteral(returnExpr);
15333
16990
  if (!arr) return;
15334
16991
  for (const el of arr.getElements()) {
15335
- if (Node10.isSpreadElement(el)) {
16992
+ if (Node11.isSpreadElement(el)) {
15336
16993
  const inner2 = el.getExpression();
15337
- if (Node10.isCallExpression(inner2)) {
16994
+ if (Node11.isCallExpression(inner2)) {
15338
16995
  const callee = inner2.getExpression();
15339
- if (Node10.isIdentifier(callee)) {
16996
+ if (Node11.isIdentifier(callee)) {
15340
16997
  collectFromArrayEntryFactory(callee.getText(), out, index);
15341
16998
  }
15342
16999
  }
@@ -15344,9 +17001,9 @@ function collectFromArrayEntryFactory(name, out, index) {
15344
17001
  }
15345
17002
  const inner = unwrapAsExpressions(el);
15346
17003
  if (!inner) continue;
15347
- if (Node10.isCallExpression(inner)) {
17004
+ if (Node11.isCallExpression(inner)) {
15348
17005
  const callee = inner.getExpression();
15349
- if (Node10.isIdentifier(callee)) {
17006
+ if (Node11.isIdentifier(callee)) {
15350
17007
  collectFromSingleEntryFactory(callee.getText(), out, index);
15351
17008
  }
15352
17009
  continue;
@@ -15364,9 +17021,9 @@ function extractTaskServiceCalls(sources, index, trustedExternal) {
15364
17021
  const out = [];
15365
17022
  for (const sf of sources) {
15366
17023
  const rel = apiRelPath(sf);
15367
- for (const call of sf.getDescendantsOfKind(SyntaxKind7.CallExpression)) {
17024
+ for (const call of sf.getDescendantsOfKind(SyntaxKind8.CallExpression)) {
15368
17025
  const expr = call.getExpression();
15369
- if (!Node10.isIdentifier(expr) || expr.getText() !== TASK_SERVICE_FACTORY) continue;
17026
+ if (!Node11.isIdentifier(expr) || expr.getText() !== TASK_SERVICE_FACTORY) continue;
15370
17027
  const args = call.getArguments();
15371
17028
  const first = args[0] ? asObjectLiteral(args[0]) : void 0;
15372
17029
  if (!first) continue;
@@ -15392,13 +17049,13 @@ function collectValidateArrayElements(validateArr) {
15392
17049
  const spreads = [];
15393
17050
  if (!validateArr) return { ids, spreads };
15394
17051
  for (const el of validateArr.getElements()) {
15395
- if (Node10.isSpreadElement(el)) {
17052
+ if (Node11.isSpreadElement(el)) {
15396
17053
  const inner2 = el.getExpression();
15397
- if (Node10.isIdentifier(inner2)) spreads.push(inner2.getText());
17054
+ if (Node11.isIdentifier(inner2)) spreads.push(inner2.getText());
15398
17055
  continue;
15399
17056
  }
15400
17057
  const inner = unwrapAsExpressions(el);
15401
- if (inner && Node10.isIdentifier(inner)) ids.push(inner.getText());
17058
+ if (inner && Node11.isIdentifier(inner)) ids.push(inner.getText());
15402
17059
  }
15403
17060
  return { ids, spreads };
15404
17061
  }
@@ -15411,17 +17068,17 @@ function collectHandlersArrayElements(options) {
15411
17068
  if (!handlersArr) return { handlerTypes, unresolvedSpreads, resolvedBindings, unresolvedBindings };
15412
17069
  const visited = /* @__PURE__ */ new Set();
15413
17070
  for (const el of handlersArr.getElements()) {
15414
- if (Node10.isSpreadElement(el)) {
17071
+ if (Node11.isSpreadElement(el)) {
15415
17072
  consumeHandlersSpreadElement({ inner: el.getExpression(), sf, index, trustedExternal, unresolvedSpreads, resolvedBindings, unresolvedBindings, visited });
15416
17073
  continue;
15417
17074
  }
15418
17075
  const inner = unwrapAsExpressions(el);
15419
17076
  if (!inner) continue;
15420
- if (Node10.isIdentifier(inner)) {
17077
+ if (Node11.isIdentifier(inner)) {
15421
17078
  collectHandlerBindingsFromIdentifier({ name: inner.getText(), sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
15422
- } else if (Node10.isCallExpression(inner)) {
17079
+ } else if (Node11.isCallExpression(inner)) {
15423
17080
  const callee = inner.getExpression();
15424
- if (Node10.isIdentifier(callee)) {
17081
+ if (Node11.isIdentifier(callee)) {
15425
17082
  collectHandlerBindingsFromIdentifier({ name: callee.getText(), sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
15426
17083
  }
15427
17084
  }
@@ -15430,16 +17087,16 @@ function collectHandlersArrayElements(options) {
15430
17087
  }
15431
17088
  function consumeHandlersSpreadElement(options) {
15432
17089
  const { inner, sf, index, trustedExternal, unresolvedSpreads, resolvedBindings, unresolvedBindings, visited } = options;
15433
- if (Node10.isCallExpression(inner)) {
17090
+ if (Node11.isCallExpression(inner)) {
15434
17091
  const callee = inner.getExpression();
15435
- if (Node10.isIdentifier(callee)) {
17092
+ if (Node11.isIdentifier(callee)) {
15436
17093
  const name = callee.getText();
15437
17094
  unresolvedSpreads.push(name);
15438
17095
  collectHandlerBindingsFromIdentifier({ name, sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
15439
17096
  }
15440
17097
  return;
15441
17098
  }
15442
- if (Node10.isIdentifier(inner)) {
17099
+ if (Node11.isIdentifier(inner)) {
15443
17100
  const name = inner.getText();
15444
17101
  unresolvedSpreads.push(name);
15445
17102
  collectHandlerBindingsFromIdentifier({ name, sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
@@ -15449,13 +17106,13 @@ function collectHandlerBindingsFromValue(options) {
15449
17106
  const { node, sf, index, trustedExternal, resolved, unresolved, visited } = options;
15450
17107
  const inner = unwrapAsExpressions(node);
15451
17108
  if (!inner) return false;
15452
- if (Node10.isCallExpression(inner)) {
17109
+ if (Node11.isCallExpression(inner)) {
15453
17110
  const callee = inner.getExpression();
15454
- if (Node10.isIdentifier(callee)) {
17111
+ if (Node11.isIdentifier(callee)) {
15455
17112
  return collectHandlerBindingsFromIdentifier({ name: callee.getText(), sf, index, trustedExternal, resolved, unresolved, visited });
15456
17113
  }
15457
17114
  }
15458
- if (Node10.isIdentifier(inner)) {
17115
+ if (Node11.isIdentifier(inner)) {
15459
17116
  return collectHandlerBindingsFromIdentifier({ name: inner.getText(), sf, index, trustedExternal, resolved, unresolved, visited });
15460
17117
  }
15461
17118
  return false;
@@ -15472,7 +17129,7 @@ function collectHandlerBindingsFromIdentifier(options) {
15472
17129
  const typeText = typeNode ? typeNode.getText() : void 0;
15473
17130
  const isHandlerConfigTyped = typeText !== void 0 && (typeText === NOTIF_TASK_SERVICE_HANDLER_CONFIG || typeText.startsWith(`${NOTIF_TASK_SERVICE_HANDLER_CONFIG}<`));
15474
17131
  const declInit = unwrapAsExpressions(localDecl.getInitializer());
15475
- const isObjectLit = declInit !== void 0 && Node10.isObjectLiteralExpression(declInit);
17132
+ const isObjectLit = declInit !== void 0 && Node11.isObjectLiteralExpression(declInit);
15476
17133
  if (isHandlerConfigTyped && isObjectLit) {
15477
17134
  resolved.push(localDecl.getName());
15478
17135
  resolvedAny = true;
@@ -15503,12 +17160,12 @@ function collectHandlerBindingsFromIdentifier(options) {
15503
17160
  function resolveArrayFromProperty2(obj, name, sf) {
15504
17161
  const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
15505
17162
  if (!init) return void 0;
15506
- if (Node10.isArrayLiteralExpression(init)) return init;
15507
- if (Node10.isIdentifier(init)) {
17163
+ if (Node11.isArrayLiteralExpression(init)) return init;
17164
+ if (Node11.isIdentifier(init)) {
15508
17165
  const declNode = findLocalVariable(sf, init.getText());
15509
17166
  if (declNode) {
15510
17167
  const declInit = unwrapAsExpressions(declNode.getInitializer());
15511
- if (declInit && Node10.isArrayLiteralExpression(declInit)) {
17168
+ if (declInit && Node11.isArrayLiteralExpression(declInit)) {
15512
17169
  return declInit;
15513
17170
  }
15514
17171
  }
@@ -15529,12 +17186,12 @@ function extractTaskHandlerEntries(sources) {
15529
17186
  if (!typeIdent) return;
15530
17187
  const flowInit = unwrapAsExpressions(getPropertyInitializer(obj, "flow"));
15531
17188
  let flowCount;
15532
- if (flowInit && Node10.isArrayLiteralExpression(flowInit)) {
17189
+ if (flowInit && Node11.isArrayLiteralExpression(flowInit)) {
15533
17190
  flowCount = flowInit.getElements().length;
15534
17191
  }
15535
17192
  let dataArg;
15536
17193
  let checkpointArg;
15537
- if (Node10.isTypeReference(typeNode)) {
17194
+ if (Node11.isTypeReference(typeNode)) {
15538
17195
  const tArgs = typeNode.getTypeArguments();
15539
17196
  if (tArgs.length >= 1) dataArg = tArgs[0].getText();
15540
17197
  if (tArgs.length >= 2) checkpointArg = tArgs[1].getText();
@@ -15554,7 +17211,7 @@ function extractTaskHandlerEntries(sources) {
15554
17211
  };
15555
17212
  for (const sf of sources) {
15556
17213
  const rel = apiRelPath(sf);
15557
- for (const decl of sf.getDescendantsOfKind(SyntaxKind7.VariableDeclaration)) {
17214
+ for (const decl of sf.getDescendantsOfKind(SyntaxKind8.VariableDeclaration)) {
15558
17215
  collectFromVariable(decl, rel);
15559
17216
  }
15560
17217
  }
@@ -15579,7 +17236,7 @@ function runRules6(inspection, extracted) {
15579
17236
  violations,
15580
17237
  codes: IO_VIOLATION_CODES2,
15581
17238
  messages: IO_VIOLATION_MESSAGES2,
15582
- build: (code10, message, side) => buildIoViolation2(code10, message, side)
17239
+ build: (code11, message, side) => buildIoViolation2(code11, message, side)
15583
17240
  });
15584
17241
  if (!proceed) {
15585
17242
  return violations;
@@ -15932,14 +17589,14 @@ function flagUnusedInfoAggregates(extracted, violations) {
15932
17589
  }
15933
17590
  }
15934
17591
  }
15935
- function flagDuplicates2(entries, code10, violations) {
17592
+ function flagDuplicates2(entries, code11, violations) {
15936
17593
  const seen = /* @__PURE__ */ new Map();
15937
17594
  for (const entry of entries) {
15938
17595
  if (!entry.typeCode) continue;
15939
17596
  const previous = seen.get(entry.typeCode);
15940
17597
  if (previous) {
15941
17598
  pushViolation6(violations, {
15942
- code: code10,
17599
+ code: code11,
15943
17600
  severity: "warning",
15944
17601
  message: `Type code \`'${entry.typeCode}'\` is shared by \`${previous}\` and \`${entry.symbolName}\`. Runtime aggregators reject duplicates \u2014 change one of the string literals.`,
15945
17602
  side: "component",
@@ -15973,9 +17630,9 @@ function pushViolation6(buffer, violation) {
15973
17630
  };
15974
17631
  buffer.push(filled);
15975
17632
  }
15976
- function buildIoViolation2(code10, message, side) {
17633
+ function buildIoViolation2(code11, message, side) {
15977
17634
  const result = {
15978
- code: code10,
17635
+ code: code11,
15979
17636
  severity: "error",
15980
17637
  message,
15981
17638
  side,
@@ -16175,8 +17832,8 @@ function formatReportAsJson2(report) {
16175
17832
  // packages/dbx-components-mcp/src/tools/notification-m-list-app/format.markdown.ts
16176
17833
  function formatReportAsMarkdown2(report) {
16177
17834
  const basename4 = report.componentDir.split("/").pop() ?? report.componentDir;
16178
- const aggregatorRecordText = report.aggregatorRecordName ? code4(report.aggregatorRecordName) : "_Not defined._";
16179
- const templateConfigsFactoryText = report.templateConfigsArrayFactoryName ? code4(report.templateConfigsArrayFactoryName) : "_Not defined._";
17835
+ const aggregatorRecordText = report.aggregatorRecordName ? code5(report.aggregatorRecordName) : "_Not defined._";
17836
+ const templateConfigsFactoryText = report.templateConfigsArrayFactoryName ? code5(report.templateConfigsArrayFactoryName) : "_Not defined._";
16180
17837
  const lines = [
16181
17838
  `# App notifications \u2014 ${basename4}`,
16182
17839
  "",
@@ -16216,8 +17873,8 @@ function formatTemplateBlock(t) {
16216
17873
  if (t.description) parts.push(`- Description: ${t.description}`);
16217
17874
  if (t.notificationMIdentity) parts.push(`- Notification model: \`${t.notificationMIdentity}\``);
16218
17875
  if (t.targetModelIdentity) parts.push(`- Target model: \`${t.targetModelIdentity}\``);
16219
- const infoText = t.infoSymbolName ? code4(t.infoSymbolName) : "_Missing._";
16220
- const factorySuffix = t.factoryFunctionName ? ` (${code4(t.factoryFunctionName)})` : "";
17876
+ const infoText = t.infoSymbolName ? code5(t.infoSymbolName) : "_Missing._";
17877
+ const factorySuffix = t.factoryFunctionName ? ` (${code5(t.factoryFunctionName)})` : "";
16221
17878
  parts.push(`- Info object: ${infoText}`, `- In info record: ${formatBool2(t.inInfoRecord)}`, `- Has factory: ${formatBool2(t.hasFactory)}${factorySuffix}`, `- Source: \`${t.sourceFile}\``);
16222
17879
  return parts.join("\n");
16223
17880
  }
@@ -16227,7 +17884,7 @@ function formatTaskBlock(t) {
16227
17884
  parts.push(heading);
16228
17885
  if (t.dataInterfaceName) parts.push(`- Data interface: \`${t.dataInterfaceName}\``);
16229
17886
  if (t.checkpoints.length > 0) {
16230
- const checkpointsText = t.checkpoints.map((c) => code4(c)).join(", ");
17887
+ const checkpointsText = t.checkpoints.map((c) => code5(c)).join(", ");
16231
17888
  parts.push(`- Checkpoints: ${checkpointsText}`);
16232
17889
  }
16233
17890
  let handlerSuffix = "";
@@ -16241,7 +17898,7 @@ function formatTaskBlock(t) {
16241
17898
  function formatBool2(value) {
16242
17899
  return value ? "yes" : "no";
16243
17900
  }
16244
- function code4(value) {
17901
+ function code5(value) {
16245
17902
  return "`" + value + "`";
16246
17903
  }
16247
17904
 
@@ -16383,8 +18040,8 @@ function formatResult8(result) {
16383
18040
  }
16384
18041
 
16385
18042
  // packages/dbx-components-mcp/src/tools/system-m-validate-folder/inspect.ts
16386
- import { readdir as readdir4, readFile as readFile4, stat as stat5 } from "node:fs/promises";
16387
- import { basename as basename3, join as join3 } from "node:path";
18043
+ import { readdir as readdir4, readFile as readFile6, stat as stat5 } from "node:fs/promises";
18044
+ import { basename as basename3, join as join6 } from "node:path";
16388
18045
  async function inspectFolder2(path) {
16389
18046
  const name = basename3(path);
16390
18047
  let status;
@@ -16404,7 +18061,7 @@ async function inspectFolder2(path) {
16404
18061
  files = collected;
16405
18062
  if (collected.includes("system.ts")) {
16406
18063
  try {
16407
- systemSource = await readFile4(join3(path, "system.ts"), "utf8");
18064
+ systemSource = await readFile6(join6(path, "system.ts"), "utf8");
16408
18065
  } catch {
16409
18066
  systemSource = void 0;
16410
18067
  }
@@ -16413,8 +18070,8 @@ async function inspectFolder2(path) {
16413
18070
  status = "not-directory";
16414
18071
  }
16415
18072
  } catch (err) {
16416
- const code10 = err.code;
16417
- if (code10 === "ENOENT" || code10 === "ENOTDIR") {
18073
+ const code11 = err.code;
18074
+ if (code11 === "ENOENT" || code11 === "ENOTDIR") {
16418
18075
  status = "not-found";
16419
18076
  } else {
16420
18077
  throw err;
@@ -16425,14 +18082,14 @@ async function inspectFolder2(path) {
16425
18082
  }
16426
18083
 
16427
18084
  // packages/dbx-components-mcp/src/tools/system-m-validate-folder/extract.ts
16428
- import { Node as Node11, Project as Project7 } from "ts-morph";
18085
+ import { Node as Node12, Project as Project9 } from "ts-morph";
16429
18086
  var TYPE_CONSTANT_SUFFIX = "_SYSTEM_STATE_TYPE";
16430
18087
  var DATA_INTERFACE_SUFFIX = "SystemData";
16431
18088
  var CONVERTER_CONFIG_TYPE = "SystemStateStoredDataFieldConverterConfig";
16432
18089
  var CONVERTER_MAP_TYPE = "SystemStateStoredDataConverterMap";
16433
18090
  var SYSTEM_STATE_STORED_DATA = "SystemStateStoredData";
16434
18091
  function extractSystemFile(name, text) {
16435
- const project = new Project7({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
18092
+ const project = new Project9({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
16436
18093
  const sourceFile = project.createSourceFile(name, text, { overwrite: true });
16437
18094
  const typeConstants = findTypeConstants(sourceFile);
16438
18095
  const dataInterfaces = findDataInterfaces2(sourceFile);
@@ -16489,7 +18146,7 @@ function findDataInterfaces2(sourceFile) {
16489
18146
  return out;
16490
18147
  }
16491
18148
  function extendsSystemStateStoredData(iface) {
16492
- if (!Node11.isInterfaceDeclaration(iface)) return false;
18149
+ if (!Node12.isInterfaceDeclaration(iface)) return false;
16493
18150
  for (const clause of iface.getExtends()) {
16494
18151
  const text = clause.getText();
16495
18152
  if (text === SYSTEM_STATE_STORED_DATA || text.startsWith(`${SYSTEM_STATE_STORED_DATA}<`) || text === `${SYSTEM_STATE_STORED_DATA}, ${SYSTEM_STATE_STORED_DATA}`) {
@@ -16509,14 +18166,14 @@ function findConverters(sourceFile) {
16509
18166
  for (const decl of stmt.getDeclarations()) {
16510
18167
  const typeNode = decl.getTypeNode();
16511
18168
  if (!typeNode) continue;
16512
- if (!Node11.isTypeReference(typeNode)) continue;
18169
+ if (!Node12.isTypeReference(typeNode)) continue;
16513
18170
  const typeName = typeNode.getTypeName().getText();
16514
18171
  if (typeName !== CONVERTER_CONFIG_TYPE) continue;
16515
18172
  const typeArgs = typeNode.getTypeArguments();
16516
18173
  let dataTypeArgument;
16517
18174
  if (typeArgs.length >= 1) {
16518
18175
  const arg = typeArgs[0];
16519
- if (Node11.isTypeReference(arg)) {
18176
+ if (Node12.isTypeReference(arg)) {
16520
18177
  dataTypeArgument = arg.getTypeName().getText();
16521
18178
  } else {
16522
18179
  dataTypeArgument = arg.getText();
@@ -16563,19 +18220,19 @@ function collectConverterMapKeys(decl) {
16563
18220
  if (!obj) return [];
16564
18221
  const out = [];
16565
18222
  for (const prop of obj.getProperties()) {
16566
- if (!Node11.isPropertyAssignment(prop)) continue;
18223
+ if (!Node12.isPropertyAssignment(prop)) continue;
16567
18224
  const nameNode = prop.getNameNode();
16568
18225
  const line = prop.getStartLineNumber();
16569
- if (Node11.isComputedPropertyName(nameNode)) {
18226
+ if (Node12.isComputedPropertyName(nameNode)) {
16570
18227
  const inner = nameNode.getExpression();
16571
18228
  out.push({ raw: inner.getText(), kind: "identifier", line });
16572
18229
  continue;
16573
18230
  }
16574
- if (Node11.isStringLiteral(nameNode)) {
18231
+ if (Node12.isStringLiteral(nameNode)) {
16575
18232
  out.push({ raw: nameNode.getLiteralText(), kind: "string", line });
16576
18233
  continue;
16577
18234
  }
16578
- if (Node11.isIdentifier(nameNode)) {
18235
+ if (Node12.isIdentifier(nameNode)) {
16579
18236
  out.push({ raw: nameNode.getText(), kind: "string", line });
16580
18237
  continue;
16581
18238
  }
@@ -16585,10 +18242,10 @@ function collectConverterMapKeys(decl) {
16585
18242
  }
16586
18243
  function unwrapObjectLiteral(node) {
16587
18244
  let current = node;
16588
- while (current && Node11.isAsExpression(current)) {
18245
+ while (current && Node12.isAsExpression(current)) {
16589
18246
  current = current.getExpression();
16590
18247
  }
16591
- if (current && Node11.isObjectLiteralExpression(current)) {
18248
+ if (current && Node12.isObjectLiteralExpression(current)) {
16592
18249
  return current;
16593
18250
  }
16594
18251
  return void 0;
@@ -16622,10 +18279,10 @@ function findLastTopLevelExportLine(sourceFile) {
16622
18279
  return last;
16623
18280
  }
16624
18281
  function isExportedTopLevel(stmt) {
16625
- if (Node11.isVariableStatement(stmt) || Node11.isFunctionDeclaration(stmt) || Node11.isClassDeclaration(stmt) || Node11.isInterfaceDeclaration(stmt) || Node11.isTypeAliasDeclaration(stmt) || Node11.isEnumDeclaration(stmt)) {
18282
+ if (Node12.isVariableStatement(stmt) || Node12.isFunctionDeclaration(stmt) || Node12.isClassDeclaration(stmt) || Node12.isInterfaceDeclaration(stmt) || Node12.isTypeAliasDeclaration(stmt) || Node12.isEnumDeclaration(stmt)) {
16626
18283
  return stmt.isExported();
16627
18284
  }
16628
- if (Node11.isExportDeclaration(stmt) || Node11.isExportAssignment(stmt)) {
18285
+ if (Node12.isExportDeclaration(stmt) || Node12.isExportAssignment(stmt)) {
16629
18286
  return true;
16630
18287
  }
16631
18288
  return false;
@@ -16935,7 +18592,7 @@ var systemMValidateFolderTool = createFolderValidateTool({
16935
18592
  });
16936
18593
 
16937
18594
  // packages/dbx-components-mcp/src/tools/lookup-action.tool.ts
16938
- import { type as type31 } from "arktype";
18595
+ import { type as type36 } from "arktype";
16939
18596
  var DBX_ACTION_LOOKUP_TOOL = {
16940
18597
  name: "dbx_action_lookup",
16941
18598
  description: [
@@ -16968,13 +18625,13 @@ var DBX_ACTION_LOOKUP_TOOL = {
16968
18625
  required: ["topic"]
16969
18626
  }
16970
18627
  };
16971
- var LookupActionArgsType = type31({
18628
+ var LookupActionArgsType = type36({
16972
18629
  topic: "string",
16973
18630
  "depth?": "'brief' | 'full'"
16974
18631
  });
16975
18632
  function parseLookupActionArgs(raw) {
16976
18633
  const parsed = LookupActionArgsType(raw);
16977
- if (parsed instanceof type31.errors) {
18634
+ if (parsed instanceof type36.errors) {
16978
18635
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
16979
18636
  }
16980
18637
  const result = {
@@ -17098,7 +18755,7 @@ function formatDirectiveEntry(entry, depth) {
17098
18755
  }
17099
18756
  lines.push("## State interaction", "", formatStateInteraction(entry), "", "## Example", "", "```html", entry.example, "```");
17100
18757
  if (entry.skillRefs.length > 0) {
17101
- const skillsText = entry.skillRefs.map((s) => code5(s)).join(", ");
18758
+ const skillsText = entry.skillRefs.map((s) => code6(s)).join(", ");
17102
18759
  lines.push("", `\u2192 Skills: ${skillsText}`);
17103
18760
  }
17104
18761
  } else {
@@ -17132,7 +18789,7 @@ function formatStoreEntry(entry, depth) {
17132
18789
  }
17133
18790
  lines.push("## Example", "", "```ts", entry.example, "```");
17134
18791
  if (entry.skillRefs.length > 0) {
17135
- const skillsText = entry.skillRefs.map((s) => code5(s)).join(", ");
18792
+ const skillsText = entry.skillRefs.map((s) => code6(s)).join(", ");
17136
18793
  lines.push("", `\u2192 Skills: ${skillsText}`);
17137
18794
  }
17138
18795
  } else {
@@ -17157,7 +18814,7 @@ function formatStateDiagram(entry) {
17157
18814
  function formatStateEntry(entry, depth) {
17158
18815
  const lines = [`# DbxActionState.${entry.stateValue}`, "", entry.description, "", bullet("enum value", `\`'${entry.literal}'\``), bullet("slug", `\`${entry.slug}\``), "", "## Transitions", "", "```", formatStateDiagram(entry), "```"];
17159
18816
  if (depth === "full" && entry.skillRefs.length > 0) {
17160
- const skillsText = entry.skillRefs.map((s) => code5(s)).join(", ");
18817
+ const skillsText = entry.skillRefs.map((s) => code6(s)).join(", ");
17161
18818
  lines.push("", `\u2192 Skills: ${skillsText}`);
17162
18819
  }
17163
18820
  return lines.join("\n");
@@ -17236,12 +18893,12 @@ function formatNotFound6(normalized, candidates) {
17236
18893
  }
17237
18894
  return lines.join("\n");
17238
18895
  }
17239
- function code5(value) {
18896
+ function code6(value) {
17240
18897
  return "`" + value + "`";
17241
18898
  }
17242
18899
  function createLookupActionTool(input) {
17243
18900
  const { registry } = input;
17244
- const run = (rawArgs) => {
18901
+ const run5 = (rawArgs) => {
17245
18902
  let args;
17246
18903
  try {
17247
18904
  args = parseLookupActionArgs(rawArgs);
@@ -17268,11 +18925,11 @@ function createLookupActionTool(input) {
17268
18925
  const result = { content: [{ type: "text", text }] };
17269
18926
  return result;
17270
18927
  };
17271
- return { definition: DBX_ACTION_LOOKUP_TOOL, run };
18928
+ return { definition: DBX_ACTION_LOOKUP_TOOL, run: run5 };
17272
18929
  }
17273
18930
 
17274
18931
  // packages/dbx-components-mcp/src/tools/action-examples.tool.ts
17275
- import { type as type32 } from "arktype";
18932
+ import { type as type37 } from "arktype";
17276
18933
 
17277
18934
  // packages/dbx-components-mcp/src/tools/data/patterns/actions/action.auto-trigger-on-modify.pattern.ts
17278
18935
  var ACTION_PATTERN_AUTO_TRIGGER_ON_MODIFY = {
@@ -17632,13 +19289,13 @@ var DBX_ACTION_EXAMPLES_TOOL = {
17632
19289
  required: ["pattern"]
17633
19290
  }
17634
19291
  };
17635
- var ActionExamplesArgsType = type32({
19292
+ var ActionExamplesArgsType = type37({
17636
19293
  pattern: "string",
17637
19294
  "depth?": "'minimal' | 'brief' | 'full'"
17638
19295
  });
17639
19296
  function parseActionExamplesArgs(raw) {
17640
19297
  const parsed = ActionExamplesArgsType(raw);
17641
- if (parsed instanceof type32.errors) {
19298
+ if (parsed instanceof type37.errors) {
17642
19299
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
17643
19300
  }
17644
19301
  const result = {
@@ -17650,7 +19307,7 @@ function parseActionExamplesArgs(raw) {
17650
19307
  function formatPatternCatalog3() {
17651
19308
  const lines = [`# Action example patterns (${ACTION_EXAMPLE_PATTERNS.length})`, "", 'Call `dbx_action_examples pattern="<slug>"` for a full example.', ""];
17652
19309
  for (const pattern of ACTION_EXAMPLE_PATTERNS) {
17653
- const usesText = pattern.usesActionSlugs.map((s) => code6(s)).join(", ");
19310
+ const usesText = pattern.usesActionSlugs.map((s) => code7(s)).join(", ");
17654
19311
  lines.push(`## ${pattern.name}`, "", `- **slug:** \`${pattern.slug}\``, `- **summary:** ${pattern.summary}`, `- **uses:** ${usesText}`, "");
17655
19312
  }
17656
19313
  return lines.join("\n").trimEnd();
@@ -17658,7 +19315,7 @@ function formatPatternCatalog3() {
17658
19315
  function formatPattern3(pattern, depth) {
17659
19316
  const snippet = pattern.snippets[depth];
17660
19317
  const fence = depth === "full" ? "ts" : "html";
17661
- const usesText = pattern.usesActionSlugs.map((s) => code6(s)).join(", ");
19318
+ const usesText = pattern.usesActionSlugs.map((s) => code7(s)).join(", ");
17662
19319
  const sections = [`# ${pattern.name}`, "", pattern.summary, "", `**slug:** \`${pattern.slug}\` \xB7 **depth:** \`${depth}\` \xB7 **uses:** ${usesText}`, "", "```" + fence, snippet, "```"];
17663
19320
  if (pattern.notes && depth === "full") {
17664
19321
  sections.push("", "## Notes", "", pattern.notes);
@@ -17669,10 +19326,10 @@ function formatPattern3(pattern, depth) {
17669
19326
  return sections.join("\n");
17670
19327
  }
17671
19328
  function formatNotFound7(slug) {
17672
- const available = ACTION_EXAMPLE_PATTERNS.map((p) => code6(p.slug)).join(", ");
19329
+ const available = ACTION_EXAMPLE_PATTERNS.map((p) => code7(p.slug)).join(", ");
17673
19330
  return [`No action example pattern matched \`${slug}\`.`, "", `Available patterns: ${available}.`, "", 'Call `dbx_action_examples pattern="list"` for summaries.'].join("\n");
17674
19331
  }
17675
- function code6(value) {
19332
+ function code7(value) {
17676
19333
  return "`" + value + "`";
17677
19334
  }
17678
19335
  function runActionExamples(rawArgs) {
@@ -17700,7 +19357,7 @@ var actionExamplesTool = {
17700
19357
  };
17701
19358
 
17702
19359
  // packages/dbx-components-mcp/src/tools/action-scaffold.tool.ts
17703
- import { type as type33 } from "arktype";
19360
+ import { type as type38 } from "arktype";
17704
19361
  var TRIGGER_VALUES = ["button", "form", "auto-modify"];
17705
19362
  var SUCCESS_FEEDBACK_VALUES = ["snackbar", "redirect", "none"];
17706
19363
  var CONTEXT_PROVIDER_VALUES = ["inline", "parent", "host-component"];
@@ -17734,7 +19391,7 @@ var DBX_ACTION_SCAFFOLD_TOOL = {
17734
19391
  required: ["use_case", "trigger", "value_type"]
17735
19392
  }
17736
19393
  };
17737
- var ScaffoldArgsType3 = type33({
19394
+ var ScaffoldArgsType4 = type38({
17738
19395
  use_case: "string",
17739
19396
  trigger: "'button' | 'form' | 'auto-modify'",
17740
19397
  "confirm?": "boolean",
@@ -17744,8 +19401,8 @@ var ScaffoldArgsType3 = type33({
17744
19401
  "result_type?": "string"
17745
19402
  });
17746
19403
  function parseScaffoldArgs2(raw) {
17747
- const parsed = ScaffoldArgsType3(raw);
17748
- if (parsed instanceof type33.errors) {
19404
+ const parsed = ScaffoldArgsType4(raw);
19405
+ if (parsed instanceof type38.errors) {
17749
19406
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
17750
19407
  }
17751
19408
  const useCase = parsed.use_case.trim();
@@ -17951,16 +19608,16 @@ var actionScaffoldTool = {
17951
19608
  };
17952
19609
 
17953
19610
  // packages/dbx-components-mcp/src/tools/route-tree.tool.ts
17954
- import { type as type34 } from "arktype";
19611
+ import { type as type39 } from "arktype";
17955
19612
 
17956
19613
  // packages/dbx-components-mcp/src/tools/route/load-sources.ts
17957
- import { glob as fsGlob3, readFile as readFile5, stat as stat6 } from "node:fs/promises";
17958
- import { dirname as dirname7, isAbsolute as isAbsolute7, resolve as resolve15, sep as sep3 } from "node:path";
19614
+ import { glob as fsGlob3, readFile as readFile7, stat as stat6 } from "node:fs/promises";
19615
+ import { dirname as dirname7, isAbsolute as isAbsolute7, resolve as resolve20, sep as sep3 } from "node:path";
17959
19616
 
17960
19617
  // packages/dbx-components-mcp/src/tools/route/extract.ts
17961
- import { Node as Node12, Project as Project8, SyntaxKind as SyntaxKind8 } from "ts-morph";
19618
+ import { Node as Node13, Project as Project10, SyntaxKind as SyntaxKind9 } from "ts-morph";
17962
19619
  function extractFile3(source) {
17963
- const project = new Project8({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
19620
+ const project = new Project10({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
17964
19621
  const sourceFile = project.createSourceFile(source.name, source.text, { overwrite: true });
17965
19622
  const issues = [];
17966
19623
  const objectLiteralsByName = collectStateConsts(sourceFile);
@@ -17973,9 +19630,9 @@ function extractFile3(source) {
17973
19630
  }
17974
19631
  for (const arrayLit of findStateArrayLiterals(sourceFile)) {
17975
19632
  for (const element of arrayLit.getElements()) {
17976
- if (Node12.isObjectLiteralExpression(element)) {
19633
+ if (Node13.isObjectLiteralExpression(element)) {
17977
19634
  addNode({ file: source.name, literal: element, fallbackConstName: void 0, into: collected, issues });
17978
- } else if (Node12.isIdentifier(element)) {
19635
+ } else if (Node13.isIdentifier(element)) {
17979
19636
  const ref = objectLiteralsByName.get(element.getText());
17980
19637
  if (ref) {
17981
19638
  addNode({ file: source.name, literal: ref.literal, fallbackConstName: element.getText(), into: collected, issues });
@@ -17996,7 +19653,7 @@ function collectStateConsts(sourceFile) {
17996
19653
  for (const stmt of sourceFile.getVariableStatements()) {
17997
19654
  for (const decl of stmt.getDeclarations()) {
17998
19655
  const initializer = decl.getInitializer();
17999
- if (!initializer || !Node12.isObjectLiteralExpression(initializer)) {
19656
+ if (!initializer || !Node13.isObjectLiteralExpression(initializer)) {
18000
19657
  continue;
18001
19658
  }
18002
19659
  const typeNode = decl.getTypeNode();
@@ -18011,12 +19668,12 @@ function findStateArrayLiterals(sourceFile) {
18011
19668
  for (const stmt of sourceFile.getVariableStatements()) {
18012
19669
  for (const decl of stmt.getDeclarations()) {
18013
19670
  const initializer = decl.getInitializer();
18014
- if (initializer && Node12.isArrayLiteralExpression(initializer) && declarationIsStateArray(stmt, decl.getName(), initializer)) {
19671
+ if (initializer && Node13.isArrayLiteralExpression(initializer) && declarationIsStateArray(stmt, decl.getName(), initializer)) {
18015
19672
  arrays.push(initializer);
18016
19673
  }
18017
19674
  }
18018
19675
  }
18019
- for (const call of sourceFile.getDescendantsOfKind(SyntaxKind8.CallExpression)) {
19676
+ for (const call of sourceFile.getDescendantsOfKind(SyntaxKind9.CallExpression)) {
18020
19677
  const expr = call.getExpression();
18021
19678
  const exprText = expr.getText();
18022
19679
  const isProvide = exprText === "provideStates";
@@ -18025,17 +19682,17 @@ function findStateArrayLiterals(sourceFile) {
18025
19682
  continue;
18026
19683
  }
18027
19684
  for (const arg of call.getArguments()) {
18028
- if (!Node12.isObjectLiteralExpression(arg)) {
19685
+ if (!Node13.isObjectLiteralExpression(arg)) {
18029
19686
  continue;
18030
19687
  }
18031
19688
  const statesProp = arg.getProperty("states");
18032
- if (!statesProp || !Node12.isPropertyAssignment(statesProp)) {
19689
+ if (!statesProp || !Node13.isPropertyAssignment(statesProp)) {
18033
19690
  continue;
18034
19691
  }
18035
19692
  const initializer = statesProp.getInitializer();
18036
- if (initializer && Node12.isArrayLiteralExpression(initializer)) {
19693
+ if (initializer && Node13.isArrayLiteralExpression(initializer)) {
18037
19694
  arrays.push(initializer);
18038
- } else if (initializer && Node12.isIdentifier(initializer)) {
19695
+ } else if (initializer && Node13.isIdentifier(initializer)) {
18039
19696
  const referenced = findArrayLiteralForIdentifier(sourceFile, initializer);
18040
19697
  if (referenced) {
18041
19698
  arrays.push(referenced);
@@ -18052,10 +19709,10 @@ function declarationIsStateArray(stmt, name, literal) {
18052
19709
  return true;
18053
19710
  }
18054
19711
  for (const element of literal.getElements()) {
18055
- if (Node12.isObjectLiteralExpression(element) && hasStringNameProperty(element)) {
19712
+ if (Node13.isObjectLiteralExpression(element) && hasStringNameProperty(element)) {
18056
19713
  return true;
18057
19714
  }
18058
- if (Node12.isIdentifier(element)) {
19715
+ if (Node13.isIdentifier(element)) {
18059
19716
  return true;
18060
19717
  }
18061
19718
  }
@@ -18063,11 +19720,11 @@ function declarationIsStateArray(stmt, name, literal) {
18063
19720
  }
18064
19721
  function hasStringNameProperty(literal) {
18065
19722
  const nameProp = literal.getProperty("name");
18066
- if (!nameProp || !Node12.isPropertyAssignment(nameProp)) {
19723
+ if (!nameProp || !Node13.isPropertyAssignment(nameProp)) {
18067
19724
  return false;
18068
19725
  }
18069
19726
  const initializer = nameProp.getInitializer();
18070
- return initializer !== void 0 && (Node12.isStringLiteral(initializer) || Node12.isNoSubstitutionTemplateLiteral(initializer));
19727
+ return initializer !== void 0 && (Node13.isStringLiteral(initializer) || Node13.isNoSubstitutionTemplateLiteral(initializer));
18071
19728
  }
18072
19729
  function findArrayLiteralForIdentifier(sourceFile, identifier) {
18073
19730
  const name = identifier.getText();
@@ -18077,7 +19734,7 @@ function findArrayLiteralForIdentifier(sourceFile, identifier) {
18077
19734
  continue;
18078
19735
  }
18079
19736
  const initializer = decl.getInitializer();
18080
- if (initializer && Node12.isArrayLiteralExpression(initializer)) {
19737
+ if (initializer && Node13.isArrayLiteralExpression(initializer)) {
18081
19738
  return initializer;
18082
19739
  }
18083
19740
  }
@@ -18127,64 +19784,64 @@ function addNode(options) {
18127
19784
  }
18128
19785
  function stringPropertyValue(literal, key) {
18129
19786
  const prop = literal.getProperty(key);
18130
- if (!prop || !Node12.isPropertyAssignment(prop)) {
19787
+ if (!prop || !Node13.isPropertyAssignment(prop)) {
18131
19788
  return void 0;
18132
19789
  }
18133
19790
  const initializer = prop.getInitializer();
18134
19791
  if (!initializer) {
18135
19792
  return void 0;
18136
19793
  }
18137
- if (Node12.isStringLiteral(initializer) || Node12.isNoSubstitutionTemplateLiteral(initializer)) {
19794
+ if (Node13.isStringLiteral(initializer) || Node13.isNoSubstitutionTemplateLiteral(initializer)) {
18138
19795
  return initializer.getLiteralText();
18139
19796
  }
18140
19797
  return void 0;
18141
19798
  }
18142
19799
  function booleanPropertyValue(literal, key) {
18143
19800
  const prop = literal.getProperty(key);
18144
- if (!prop || !Node12.isPropertyAssignment(prop)) {
19801
+ if (!prop || !Node13.isPropertyAssignment(prop)) {
18145
19802
  return void 0;
18146
19803
  }
18147
19804
  const initializer = prop.getInitializer();
18148
19805
  if (!initializer) {
18149
19806
  return void 0;
18150
19807
  }
18151
- if (initializer.getKind() === SyntaxKind8.TrueKeyword) {
19808
+ if (initializer.getKind() === SyntaxKind9.TrueKeyword) {
18152
19809
  return true;
18153
19810
  }
18154
- if (initializer.getKind() === SyntaxKind8.FalseKeyword) {
19811
+ if (initializer.getKind() === SyntaxKind9.FalseKeyword) {
18155
19812
  return false;
18156
19813
  }
18157
19814
  return void 0;
18158
19815
  }
18159
19816
  function identifierPropertyValue(literal, key) {
18160
19817
  const prop = literal.getProperty(key);
18161
- if (!prop || !Node12.isPropertyAssignment(prop)) {
19818
+ if (!prop || !Node13.isPropertyAssignment(prop)) {
18162
19819
  return void 0;
18163
19820
  }
18164
19821
  const initializer = prop.getInitializer();
18165
19822
  if (!initializer) {
18166
19823
  return void 0;
18167
19824
  }
18168
- if (Node12.isIdentifier(initializer)) {
19825
+ if (Node13.isIdentifier(initializer)) {
18169
19826
  return initializer.getText();
18170
19827
  }
18171
- if (Node12.isPropertyAccessExpression(initializer)) {
19828
+ if (Node13.isPropertyAccessExpression(initializer)) {
18172
19829
  return initializer.getText();
18173
19830
  }
18174
19831
  return void 0;
18175
19832
  }
18176
19833
  function objectPropertyKeys(literal, key) {
18177
19834
  const prop = literal.getProperty(key);
18178
- if (!prop || !Node12.isPropertyAssignment(prop)) {
19835
+ if (!prop || !Node13.isPropertyAssignment(prop)) {
18179
19836
  return [];
18180
19837
  }
18181
19838
  const initializer = prop.getInitializer();
18182
- if (!initializer || !Node12.isObjectLiteralExpression(initializer)) {
19839
+ if (!initializer || !Node13.isObjectLiteralExpression(initializer)) {
18183
19840
  return [];
18184
19841
  }
18185
19842
  const out = [];
18186
19843
  for (const member of initializer.getProperties()) {
18187
- if (Node12.isPropertyAssignment(member) || Node12.isShorthandPropertyAssignment(member) || Node12.isMethodDeclaration(member)) {
19844
+ if (Node13.isPropertyAssignment(member) || Node13.isShorthandPropertyAssignment(member) || Node13.isMethodDeclaration(member)) {
18188
19845
  const nameNode = member.getNameNode();
18189
19846
  if (nameNode) {
18190
19847
  out.push(nameNode.getText());
@@ -18195,7 +19852,7 @@ function objectPropertyKeys(literal, key) {
18195
19852
  }
18196
19853
  function collectResolveKeys(literal) {
18197
19854
  const prop = literal.getProperty("resolve");
18198
- if (!prop || !Node12.isPropertyAssignment(prop)) {
19855
+ if (!prop || !Node13.isPropertyAssignment(prop)) {
18199
19856
  return [];
18200
19857
  }
18201
19858
  const initializer = prop.getInitializer();
@@ -18203,22 +19860,22 @@ function collectResolveKeys(literal) {
18203
19860
  return [];
18204
19861
  }
18205
19862
  const keys = [];
18206
- if (Node12.isObjectLiteralExpression(initializer)) {
19863
+ if (Node13.isObjectLiteralExpression(initializer)) {
18207
19864
  for (const member of initializer.getProperties()) {
18208
- if (Node12.isPropertyAssignment(member) || Node12.isShorthandPropertyAssignment(member) || Node12.isMethodDeclaration(member)) {
19865
+ if (Node13.isPropertyAssignment(member) || Node13.isShorthandPropertyAssignment(member) || Node13.isMethodDeclaration(member)) {
18209
19866
  const nameNode = member.getNameNode();
18210
19867
  if (nameNode) {
18211
19868
  keys.push(nameNode.getText());
18212
19869
  }
18213
19870
  }
18214
19871
  }
18215
- } else if (Node12.isArrayLiteralExpression(initializer)) {
19872
+ } else if (Node13.isArrayLiteralExpression(initializer)) {
18216
19873
  for (const element of initializer.getElements()) {
18217
- if (Node12.isObjectLiteralExpression(element)) {
19874
+ if (Node13.isObjectLiteralExpression(element)) {
18218
19875
  const tokenProp = element.getProperty("token");
18219
- if (tokenProp && Node12.isPropertyAssignment(tokenProp)) {
19876
+ if (tokenProp && Node13.isPropertyAssignment(tokenProp)) {
18220
19877
  const tokenInit = tokenProp.getInitializer();
18221
- if (tokenInit && (Node12.isStringLiteral(tokenInit) || Node12.isIdentifier(tokenInit))) {
19878
+ if (tokenInit && (Node13.isStringLiteral(tokenInit) || Node13.isIdentifier(tokenInit))) {
18222
19879
  keys.push(tokenInit.getText().replaceAll(/^['"]|['"]$/g, ""));
18223
19880
  }
18224
19881
  }
@@ -18270,7 +19927,7 @@ function computeRelativeSpecifiers(source) {
18270
19927
  // packages/dbx-components-mcp/src/tools/route/load-sources.ts
18271
19928
  var TRY_EXTENSIONS = [".ts", ".tsx", "/index.ts", "/index.tsx"];
18272
19929
  async function loadRouteSources(args) {
18273
- const cwdResolved = args.cwd ? resolve15(process.cwd(), args.cwd) : process.cwd();
19930
+ const cwdResolved = args.cwd ? resolve20(process.cwd(), args.cwd) : process.cwd();
18274
19931
  guardCwdInsideServer(args.cwd, cwdResolved);
18275
19932
  const collected = /* @__PURE__ */ new Map();
18276
19933
  if (args.sources) {
@@ -18342,21 +19999,21 @@ async function loadOne(relative5, cwd, into) {
18342
19999
  if (into.has(relative5)) {
18343
20000
  return;
18344
20001
  }
18345
- const absolute = resolve15(cwd, relative5);
20002
+ const absolute = resolve20(cwd, relative5);
18346
20003
  const cwdPrefix = cwd.endsWith(sep3) ? cwd : cwd + sep3;
18347
20004
  if (!absolute.startsWith(cwdPrefix) && absolute !== cwd) {
18348
20005
  throw new Error(`Path \`${relative5}\` resolves outside the server cwd and is not allowed.`);
18349
20006
  }
18350
- const text = await readFile5(absolute, "utf8");
20007
+ const text = await readFile7(absolute, "utf8");
18351
20008
  into.set(relative5, { name: relative5, text });
18352
20009
  }
18353
20010
  async function resolveRelativeImport(fromFile, specifier, cwd) {
18354
20011
  if (!specifier.startsWith(".")) {
18355
20012
  return void 0;
18356
20013
  }
18357
- const fromAbsolute = isAbsolute7(fromFile) ? fromFile : resolve15(cwd, fromFile);
20014
+ const fromAbsolute = isAbsolute7(fromFile) ? fromFile : resolve20(cwd, fromFile);
18358
20015
  const fromDir = dirname7(fromAbsolute);
18359
- const baseAbsolute = resolve15(fromDir, specifier);
20016
+ const baseAbsolute = resolve20(fromDir, specifier);
18360
20017
  const cwdPrefix = cwd.endsWith(sep3) ? cwd : cwd + sep3;
18361
20018
  for (const ext of TRY_EXTENSIONS) {
18362
20019
  const candidateAbsolute = baseAbsolute + ext;
@@ -18367,7 +20024,7 @@ async function resolveRelativeImport(fromFile, specifier, cwd) {
18367
20024
  if (!exists) {
18368
20025
  continue;
18369
20026
  }
18370
- const text = await readFile5(candidateAbsolute, "utf8");
20027
+ const text = await readFile7(candidateAbsolute, "utf8");
18371
20028
  const relativeName = candidateAbsolute.startsWith(cwdPrefix) ? candidateAbsolute.slice(cwdPrefix.length) : candidateAbsolute;
18372
20029
  const result = { name: relativeName, text };
18373
20030
  return result;
@@ -18735,8 +20392,8 @@ var DBX_ROUTE_TREE_TOOL = {
18735
20392
  }
18736
20393
  }
18737
20394
  };
18738
- var TreeArgsType = type34({
18739
- "sources?": type34({ name: "string", text: "string" }).array(),
20395
+ var TreeArgsType = type39({
20396
+ "sources?": type39({ name: "string", text: "string" }).array(),
18740
20397
  "paths?": "string[]",
18741
20398
  "glob?": "string",
18742
20399
  "format?": "'markdown' | 'json' | 'flat'",
@@ -18745,7 +20402,7 @@ var TreeArgsType = type34({
18745
20402
  });
18746
20403
  function parseArgs3(raw) {
18747
20404
  const parsed = TreeArgsType(raw);
18748
- if (parsed instanceof type34.errors) {
20405
+ if (parsed instanceof type39.errors) {
18749
20406
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
18750
20407
  }
18751
20408
  const result = {
@@ -18795,7 +20452,7 @@ var routeTreeTool = {
18795
20452
  };
18796
20453
 
18797
20454
  // packages/dbx-components-mcp/src/tools/route-lookup.tool.ts
18798
- import { type as type35 } from "arktype";
20455
+ import { type as type40 } from "arktype";
18799
20456
  var DBX_ROUTE_LOOKUP_TOOL = {
18800
20457
  name: "dbx_route_lookup",
18801
20458
  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"),
@@ -18820,17 +20477,17 @@ var DBX_ROUTE_LOOKUP_TOOL = {
18820
20477
  required: ["topic"]
18821
20478
  }
18822
20479
  };
18823
- var LookupArgsType = type35({
20480
+ var LookupArgsType2 = type40({
18824
20481
  topic: "string",
18825
- "sources?": type35({ name: "string", text: "string" }).array(),
20482
+ "sources?": type40({ name: "string", text: "string" }).array(),
18826
20483
  "paths?": "string[]",
18827
20484
  "glob?": "string",
18828
20485
  "depth?": "'brief' | 'full'",
18829
20486
  "cwd?": "string"
18830
20487
  });
18831
20488
  function parseArgs4(raw) {
18832
- const parsed = LookupArgsType(raw);
18833
- if (parsed instanceof type35.errors) {
20489
+ const parsed = LookupArgsType2(raw);
20490
+ if (parsed instanceof type40.errors) {
18834
20491
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
18835
20492
  }
18836
20493
  const result = {
@@ -18900,8 +20557,8 @@ function fuzzyCandidates3(query, byName) {
18900
20557
  return scored.slice(0, 5).map((s) => s.node);
18901
20558
  }
18902
20559
  function formatSingle(node, depth, via) {
18903
- const urlText = node.fullUrl === void 0 ? "_no url_" : code7(node.fullUrl);
18904
- const componentText = node.data.component === void 0 ? "_no component_" : code7(node.data.component);
20560
+ const urlText = node.fullUrl === void 0 ? "_no url_" : code8(node.fullUrl);
20561
+ const componentText = node.data.component === void 0 ? "_no component_" : code8(node.data.component);
18905
20562
  const lines = [`# ${node.data.name}`, "", `Matched via ${via}.`, "", `- **URL:** ${urlText}`, `- **Component:** ${componentText}`, `- **Defined in:** \`${node.data.file}:${node.data.line}\``];
18906
20563
  if (node.data.redirectTo) {
18907
20564
  lines.push(`- **Redirects to:** \`${node.data.redirectTo}\``);
@@ -18925,7 +20582,7 @@ function formatSingle(node, depth, via) {
18925
20582
  }
18926
20583
  function appendParentChainSection(lines, node) {
18927
20584
  const chain = ancestors(node);
18928
- const chainLine = chain.map((c) => code7(c.data.name)).join(" \u2192 ");
20585
+ const chainLine = chain.map((c) => code8(c.data.name)).join(" \u2192 ");
18929
20586
  lines.push("", "## Parent chain", chainLine.length > 0 ? chainLine : "_root_");
18930
20587
  }
18931
20588
  function appendKeyListSection(lines, title, keys) {
@@ -18945,8 +20602,8 @@ function appendRelatedNodesSection(lines, title, nodes) {
18945
20602
  return;
18946
20603
  }
18947
20604
  for (const child of nodes) {
18948
- const urlPart = child.fullUrl === void 0 ? "" : code7(child.fullUrl);
18949
- const componentPart = child.data.component ? ` \u2192 ${code7(child.data.component)}` : "";
20605
+ const urlPart = child.fullUrl === void 0 ? "" : code8(child.fullUrl);
20606
+ const componentPart = child.data.component ? ` \u2192 ${code8(child.data.component)}` : "";
18950
20607
  lines.push(`- \`${child.data.name}\` ${urlPart}${componentPart}`);
18951
20608
  }
18952
20609
  }
@@ -18962,8 +20619,8 @@ function ancestors(node) {
18962
20619
  function formatGroup2(title, nodes) {
18963
20620
  const lines = [`# ${title}`, "", `${nodes.length} match(es).`, ""];
18964
20621
  for (const node of nodes) {
18965
- const urlPart = node.fullUrl === void 0 ? "" : code7(node.fullUrl);
18966
- const componentPart = node.data.component ? ` \u2192 ${code7(node.data.component)}` : "";
20622
+ const urlPart = node.fullUrl === void 0 ? "" : code8(node.fullUrl);
20623
+ const componentPart = node.data.component ? ` \u2192 ${code8(node.data.component)}` : "";
18967
20624
  lines.push(`- \`${node.data.name}\` ${urlPart}${componentPart} _(${node.data.file}:${node.data.line})_`);
18968
20625
  }
18969
20626
  return lines.join("\n");
@@ -18973,8 +20630,8 @@ function formatNotFound8(query, candidates) {
18973
20630
  if (candidates.length > 0) {
18974
20631
  lines.push("Did you mean one of these?", "");
18975
20632
  for (const node of candidates) {
18976
- const urlPart = node.fullUrl === void 0 ? "" : code7(node.fullUrl);
18977
- const componentPart = node.data.component ? ` \u2192 ${code7(node.data.component)}` : "";
20633
+ const urlPart = node.fullUrl === void 0 ? "" : code8(node.fullUrl);
20634
+ const componentPart = node.data.component ? ` \u2192 ${code8(node.data.component)}` : "";
18978
20635
  lines.push(`- \`${node.data.name}\` ${urlPart}${componentPart}`);
18979
20636
  }
18980
20637
  } else {
@@ -18982,7 +20639,7 @@ function formatNotFound8(query, candidates) {
18982
20639
  }
18983
20640
  return lines.join("\n");
18984
20641
  }
18985
- function code7(value) {
20642
+ function code8(value) {
18986
20643
  return "`" + value + "`";
18987
20644
  }
18988
20645
  async function runRouteLookup(rawArgs) {
@@ -19023,7 +20680,7 @@ var routeLookupTool = {
19023
20680
  };
19024
20681
 
19025
20682
  // packages/dbx-components-mcp/src/tools/route-search.tool.ts
19026
- import { type as type36 } from "arktype";
20683
+ import { type as type41 } from "arktype";
19027
20684
  var DBX_ROUTE_SEARCH_TOOL = {
19028
20685
  name: "dbx_route_search",
19029
20686
  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"),
@@ -19047,9 +20704,9 @@ var DBX_ROUTE_SEARCH_TOOL = {
19047
20704
  required: ["query"]
19048
20705
  }
19049
20706
  };
19050
- var SearchArgsType = type36({
20707
+ var SearchArgsType = type41({
19051
20708
  query: "string",
19052
- "sources?": type36({ name: "string", text: "string" }).array(),
20709
+ "sources?": type41({ name: "string", text: "string" }).array(),
19053
20710
  "paths?": "string[]",
19054
20711
  "glob?": "string",
19055
20712
  "scope?": "'name' | 'url' | 'component' | 'resolve' | 'all'",
@@ -19057,7 +20714,7 @@ var SearchArgsType = type36({
19057
20714
  });
19058
20715
  function parseArgs5(raw) {
19059
20716
  const parsed = SearchArgsType(raw);
19060
- if (parsed instanceof type36.errors) {
20717
+ if (parsed instanceof type41.errors) {
19061
20718
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
19062
20719
  }
19063
20720
  const result = {
@@ -19150,14 +20807,14 @@ var routeSearchTool = {
19150
20807
  };
19151
20808
 
19152
20809
  // packages/dbx-components-mcp/src/tools/_lookup.factory.ts
19153
- import { type as type37 } from "arktype";
19154
- var LOOKUP_ARGS_TYPE = type37({
20810
+ import { type as type42 } from "arktype";
20811
+ var LOOKUP_ARGS_TYPE = type42({
19155
20812
  topic: "string",
19156
20813
  "depth?": "'brief' | 'full'"
19157
20814
  });
19158
20815
  function parseLookupArgs(raw) {
19159
20816
  const parsed = LOOKUP_ARGS_TYPE(raw);
19160
- if (parsed instanceof type37.errors) {
20817
+ if (parsed instanceof type42.errors) {
19161
20818
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
19162
20819
  }
19163
20820
  const result = {
@@ -19306,11 +20963,11 @@ function formatEntry2(entry, depth) {
19306
20963
  const fence = entry.kind === "pattern" ? "ts" : "html";
19307
20964
  lines.push("## Example", "", "```" + fence, entry.example, "```");
19308
20965
  if (entry.relatedSlugs.length > 0) {
19309
- const relatedText = entry.relatedSlugs.map((s) => code8(s)).join(", ");
20966
+ const relatedText = entry.relatedSlugs.map((s) => code9(s)).join(", ");
19310
20967
  lines.push("", `\u2192 Related: ${relatedText}`);
19311
20968
  }
19312
20969
  if (entry.skillRefs.length > 0) {
19313
- const skillsText = entry.skillRefs.map((s) => code8(s)).join(", ");
20970
+ const skillsText = entry.skillRefs.map((s) => code9(s)).join(", ");
19314
20971
  lines.push("", `\u2192 Skills: ${skillsText}`);
19315
20972
  }
19316
20973
  } else {
@@ -19339,7 +20996,7 @@ function formatNotFound9(normalized, candidates) {
19339
20996
  }
19340
20997
  return lines.join("\n");
19341
20998
  }
19342
- function code8(value) {
20999
+ function code9(value) {
19343
21000
  return "`" + value + "`";
19344
21001
  }
19345
21002
  function createLookupFilterTool(input) {
@@ -19359,7 +21016,7 @@ function createLookupFilterTool(input) {
19359
21016
  }
19360
21017
 
19361
21018
  // packages/dbx-components-mcp/src/tools/filter-scaffold.tool.ts
19362
- import { type as type38 } from "arktype";
21019
+ import { type as type43 } from "arktype";
19363
21020
  var DBX_FILTER_SCAFFOLD_TOOL = {
19364
21021
  name: "dbx_filter_scaffold",
19365
21022
  description: [
@@ -19384,15 +21041,15 @@ var DBX_FILTER_SCAFFOLD_TOOL = {
19384
21041
  required: ["model_name", "filter_type"]
19385
21042
  }
19386
21043
  };
19387
- var ScaffoldArgsType4 = type38({
21044
+ var ScaffoldArgsType5 = type43({
19388
21045
  model_name: "string",
19389
21046
  filter_type: "string",
19390
21047
  "preset_keys?": "string[]",
19391
21048
  "uses_collection_store?": "boolean"
19392
21049
  });
19393
21050
  function parseArgs6(raw) {
19394
- const parsed = ScaffoldArgsType4(raw);
19395
- if (parsed instanceof type38.errors) {
21051
+ const parsed = ScaffoldArgsType5(raw);
21052
+ if (parsed instanceof type43.errors) {
19396
21053
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
19397
21054
  }
19398
21055
  const modelName = parsed.model_name.trim();
@@ -19575,11 +21232,11 @@ function formatEntry3(entry, depth) {
19575
21232
  }
19576
21233
  lines.push("## Example", "", "```html", entry.example, "```");
19577
21234
  if (entry.relatedSlugs.length > 0) {
19578
- const relatedText = entry.relatedSlugs.map((s) => code9(s)).join(", ");
21235
+ const relatedText = entry.relatedSlugs.map((s) => code10(s)).join(", ");
19579
21236
  lines.push("", `\u2192 Related: ${relatedText}`);
19580
21237
  }
19581
21238
  if (entry.skillRefs.length > 0) {
19582
- const skillsText = entry.skillRefs.map((s) => code9(s)).join(", ");
21239
+ const skillsText = entry.skillRefs.map((s) => code10(s)).join(", ");
19583
21240
  lines.push("", `\u2192 Skills: ${skillsText}`);
19584
21241
  }
19585
21242
  } else {
@@ -19611,7 +21268,7 @@ function formatNotFound10(normalized, candidates) {
19611
21268
  }
19612
21269
  return lines.join("\n");
19613
21270
  }
19614
- function code9(value) {
21271
+ function code10(value) {
19615
21272
  return "`" + value + "`";
19616
21273
  }
19617
21274
  function createLookupPipeTool(input) {
@@ -19632,8 +21289,8 @@ function createLookupPipeTool(input) {
19632
21289
 
19633
21290
  // packages/dbx-components-mcp/src/tools/artifact-scaffold.tool.ts
19634
21291
  import { access } from "node:fs/promises";
19635
- import { resolve as resolve16, sep as sep4 } from "node:path";
19636
- import { type as type39 } from "arktype";
21292
+ import { resolve as resolve21, sep as sep4 } from "node:path";
21293
+ import { type as type44 } from "arktype";
19637
21294
 
19638
21295
  // packages/dbx-components-mcp/src/tools/artifact-scaffold/templates.ts
19639
21296
  function splitWords(input) {
@@ -20181,7 +21838,7 @@ var DBX_ARTIFACT_SCAFFOLD_TOOL = {
20181
21838
  required: ["artifact", "name", "componentDir", "apiDir"]
20182
21839
  }
20183
21840
  };
20184
- var ScaffoldArtifactArgsType = type39({
21841
+ var ScaffoldArtifactArgsType = type44({
20185
21842
  artifact: ARTIFACT_KIND_LITERAL_UNION,
20186
21843
  name: "string",
20187
21844
  componentDir: "string",
@@ -20194,7 +21851,7 @@ var ScaffoldArtifactArgsType = type39({
20194
21851
  });
20195
21852
  function parseArgs7(raw) {
20196
21853
  const parsed = ScaffoldArtifactArgsType(raw);
20197
- if (parsed instanceof type39.errors) {
21854
+ if (parsed instanceof type44.errors) {
20198
21855
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
20199
21856
  }
20200
21857
  const result = {
@@ -20207,7 +21864,7 @@ function parseArgs7(raw) {
20207
21864
  return result;
20208
21865
  }
20209
21866
  function ensureInsideCwd(relativePath, cwd) {
20210
- const absolute = resolve16(cwd, relativePath);
21867
+ const absolute = resolve21(cwd, relativePath);
20211
21868
  const cwdPrefix = cwd.endsWith(sep4) ? cwd : cwd + sep4;
20212
21869
  if (!absolute.startsWith(cwdPrefix) && absolute !== cwd) {
20213
21870
  throw new Error(`Path \`${relativePath}\` resolves outside the server cwd and is not allowed.`);
@@ -20247,7 +21904,7 @@ async function runArtifactScaffold(rawArgs) {
20247
21904
  const message = err instanceof Error ? err.message : String(err);
20248
21905
  return toolError(`Scaffold failed: ${message}`);
20249
21906
  }
20250
- const checked = await applyIdempotency(raw, (relativePath) => fileExists2(resolve16(cwd, relativePath)));
21907
+ const checked = await applyIdempotency(raw, (relativePath) => fileExists2(resolve21(cwd, relativePath)));
20251
21908
  const text = formatResult9(checked);
20252
21909
  const result = {
20253
21910
  content: [{ type: "text", text }]
@@ -20260,7 +21917,7 @@ var artifactScaffoldTool = {
20260
21917
  };
20261
21918
 
20262
21919
  // packages/dbx-components-mcp/src/tools/artifact-file-convention.tool.ts
20263
- import { type as type40 } from "arktype";
21920
+ import { type as type45 } from "arktype";
20264
21921
 
20265
21922
  // packages/dbx-components-mcp/src/tools/artifact-file-convention/spec.ts
20266
21923
  var FIRESTORE_MODEL = {
@@ -20696,7 +22353,7 @@ var DBX_ARTIFACT_FILE_CONVENTION_TOOL = {
20696
22353
  required: ["artifact"]
20697
22354
  }
20698
22355
  };
20699
- var FileConventionArgsType = type40({
22356
+ var FileConventionArgsType = type45({
20700
22357
  artifact: ARTIFACT_KIND_LITERAL_UNION2,
20701
22358
  "componentDir?": "string",
20702
22359
  "apiDir?": "string",
@@ -20704,7 +22361,7 @@ var FileConventionArgsType = type40({
20704
22361
  });
20705
22362
  function parseArgs8(raw) {
20706
22363
  const parsed = FileConventionArgsType(raw);
20707
- if (parsed instanceof type40.errors) {
22364
+ if (parsed instanceof type45.errors) {
20708
22365
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
20709
22366
  }
20710
22367
  const result = {
@@ -20737,7 +22394,7 @@ var artifactFileConventionTool = {
20737
22394
  };
20738
22395
 
20739
22396
  // packages/dbx-components-mcp/src/tools/lookup-semantic-type.tool.ts
20740
- import { type as type41 } from "arktype";
22397
+ import { type as type46 } from "arktype";
20741
22398
 
20742
22399
  // packages/dbx-components-mcp/src/tools/semantic-type-lookup.formatter.ts
20743
22400
  function formatSemanticTypeEntry(entry, depth) {
@@ -20918,13 +22575,13 @@ var DBX_SEMANTIC_TYPE_LOOKUP_TOOL = {
20918
22575
  required: ["name"]
20919
22576
  }
20920
22577
  };
20921
- var LookupSemanticTypeArgsType = type41({
22578
+ var LookupSemanticTypeArgsType = type46({
20922
22579
  name: "string",
20923
22580
  "depth?": "'brief' | 'full'"
20924
22581
  });
20925
22582
  function parseLookupArgs2(raw) {
20926
22583
  const parsed = LookupSemanticTypeArgsType(raw);
20927
- if (parsed instanceof type41.errors) {
22584
+ if (parsed instanceof type46.errors) {
20928
22585
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
20929
22586
  }
20930
22587
  const result = {
@@ -20935,7 +22592,7 @@ function parseLookupArgs2(raw) {
20935
22592
  }
20936
22593
  function createSemanticTypeLookupTool(config) {
20937
22594
  const { registry } = config;
20938
- function run(rawArgs) {
22595
+ function run5(rawArgs) {
20939
22596
  let args;
20940
22597
  let result;
20941
22598
  try {
@@ -20971,7 +22628,7 @@ function createSemanticTypeLookupTool(config) {
20971
22628
  }
20972
22629
  const tool = {
20973
22630
  definition: DBX_SEMANTIC_TYPE_LOOKUP_TOOL,
20974
- run
22631
+ run: run5
20975
22632
  };
20976
22633
  return tool;
20977
22634
  }
@@ -20986,7 +22643,7 @@ function formatNotFound11(name, registry) {
20986
22643
  }
20987
22644
 
20988
22645
  // packages/dbx-components-mcp/src/tools/search-semantic-type.tool.ts
20989
- import { type as type42 } from "arktype";
22646
+ import { type as type47 } from "arktype";
20990
22647
  var DEFAULT_LIMIT4 = 25;
20991
22648
  var MAX_LIMIT4 = 100;
20992
22649
  var DBX_SEMANTIC_TYPE_SEARCH_TOOL = {
@@ -21019,7 +22676,7 @@ var DBX_SEMANTIC_TYPE_SEARCH_TOOL = {
21019
22676
  }
21020
22677
  }
21021
22678
  };
21022
- var SearchSemanticTypeArgsType = type42({
22679
+ var SearchSemanticTypeArgsType = type47({
21023
22680
  "topic?": "string",
21024
22681
  "baseType?": "string",
21025
22682
  "package?": "string",
@@ -21028,7 +22685,7 @@ var SearchSemanticTypeArgsType = type42({
21028
22685
  });
21029
22686
  function parseSearchArgs2(raw) {
21030
22687
  const parsed = SearchSemanticTypeArgsType(raw);
21031
- if (parsed instanceof type42.errors) {
22688
+ if (parsed instanceof type47.errors) {
21032
22689
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
21033
22690
  }
21034
22691
  const rawLimit = parsed.limit ?? DEFAULT_LIMIT4;
@@ -21054,7 +22711,7 @@ function nonEmpty(value) {
21054
22711
  }
21055
22712
  function createSemanticTypeSearchTool(config) {
21056
22713
  const { registry } = config;
21057
- function run(rawArgs) {
22714
+ function run5(rawArgs) {
21058
22715
  let args;
21059
22716
  let result;
21060
22717
  try {
@@ -21079,7 +22736,7 @@ function createSemanticTypeSearchTool(config) {
21079
22736
  }
21080
22737
  const tool = {
21081
22738
  definition: DBX_SEMANTIC_TYPE_SEARCH_TOOL,
21082
- run
22739
+ run: run5
21083
22740
  };
21084
22741
  return tool;
21085
22742
  }
@@ -21153,6 +22810,10 @@ var DBX_TOOLS = [
21153
22810
  modelValidateApiTool,
21154
22811
  modelValidateFolderTool,
21155
22812
  modelStoreScaffoldTool,
22813
+ modelFixtureListAppTool,
22814
+ modelFixtureLookupTool,
22815
+ modelFixtureScaffoldTool,
22816
+ modelFixtureForwardTool,
21156
22817
  // storagefile_m (model extension)
21157
22818
  storageFileMValidateAppTool,
21158
22819
  storageFileMListAppTool,
@@ -21179,6 +22840,7 @@ var DBX_TOOLS = [
21179
22840
  function registerTools(server, options = {}) {
21180
22841
  const underlyingServer = server.server;
21181
22842
  const tools = [...DBX_TOOLS];
22843
+ tools.push(createModelFixtureValidateAppTool({ getRegistry: () => options.fixtureModelRegistry }));
21182
22844
  if (options.forgeFieldRegistry !== void 0) {
21183
22845
  tools.push(createLookupFormTool({ registry: options.forgeFieldRegistry }), createSearchFormTool({ registry: options.forgeFieldRegistry }), createFormScaffoldTool({ registry: options.forgeFieldRegistry }));
21184
22846
  }
@@ -21228,6 +22890,7 @@ Tool clusters (each exposes lookup, search, examples, and/or scaffold/validate):
21228
22890
 
21229
22891
  Model-extension validators (walk a downstream app to verify wiring):
21230
22892
  - storagefile_m, notification_m, system_m \u2014 *_validate_app, *_list_app, *_validate_folder
22893
+ - model_fixture \u2014 list/lookup/validate/scaffold/forward an app's \`src/test/fixture.ts\` (TestContextFixture/Instance triplets)
21231
22894
 
21232
22895
  Resource URIs are namespaced by domain:
21233
22896
  - dbx://form/fields[/{slug}|/produces/{produces}|/tier/{tier}|/array-output/{arrayOutput}]
@@ -21350,8 +23013,11 @@ async function createServer(options = {}) {
21350
23013
  filterRegistry = void 0;
21351
23014
  }
21352
23015
  }
23016
+ const fixtureModelRegistry = {
23017
+ entries: FIREBASE_MODELS.map((m) => ({ name: m.name, modelType: m.modelType, collectionPrefix: m.collectionPrefix }))
23018
+ };
21353
23019
  registerResources(server, { semanticTypeRegistry: registry, forgeFieldRegistry: forgeRegistry, pipeRegistry, uiComponentRegistry: uiRegistry, actionRegistry, filterRegistry });
21354
- registerTools(server, { semanticTypeRegistry: registry, forgeFieldRegistry: forgeRegistry, pipeRegistry, uiComponentRegistry: uiRegistry, actionRegistry, filterRegistry });
23020
+ registerTools(server, { semanticTypeRegistry: registry, forgeFieldRegistry: forgeRegistry, pipeRegistry, uiComponentRegistry: uiRegistry, actionRegistry, filterRegistry, fixtureModelRegistry });
21355
23021
  return server;
21356
23022
  }
21357
23023
  async function runStdioServer() {