@dereekb/dbx-components-mcp 13.10.1 → 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,7 +5,7 @@ const require = __createRequire(import.meta.url);
5
5
  // packages/dbx-components-mcp/package.json
6
6
  var package_default = {
7
7
  name: "@dereekb/dbx-components-mcp",
8
- version: "13.10.1",
8
+ version: "13.10.2",
9
9
  type: "module",
10
10
  bin: {
11
11
  "dbx-components-mcp": "dbx-components-mcp.js"
@@ -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;
@@ -6491,7 +6500,7 @@ function createLookupFormTool(config) {
6491
6500
  }
6492
6501
  return lines.join("\n").trimEnd();
6493
6502
  }
6494
- function run(rawArgs) {
6503
+ function run5(rawArgs) {
6495
6504
  let args;
6496
6505
  try {
6497
6506
  args = parseLookupFormArgs(rawArgs);
@@ -6520,7 +6529,7 @@ function createLookupFormTool(config) {
6520
6529
  }
6521
6530
  const tool = {
6522
6531
  definition: DBX_FORM_LOOKUP_TOOL,
6523
- run
6532
+ run: run5
6524
6533
  };
6525
6534
  return tool;
6526
6535
  }
@@ -6709,7 +6718,7 @@ function formatSearchResults(input) {
6709
6718
  }
6710
6719
  function createSearchFormTool(config) {
6711
6720
  const { registry } = config;
6712
- function run(rawArgs) {
6721
+ function run5(rawArgs) {
6713
6722
  return runSearchTool(
6714
6723
  {
6715
6724
  entries: registry.all,
@@ -6725,7 +6734,7 @@ function createSearchFormTool(config) {
6725
6734
  }
6726
6735
  const tool = {
6727
6736
  definition: DBX_FORM_SEARCH_TOOL,
6728
- run
6737
+ run: run5
6729
6738
  };
6730
6739
  return tool;
6731
6740
  }
@@ -7248,7 +7257,7 @@ function renderScaffold(specs, valueTypeName, wrapInSection) {
7248
7257
  }
7249
7258
  function createFormScaffoldTool(config) {
7250
7259
  const { registry } = config;
7251
- function run(rawArgs) {
7260
+ function run5(rawArgs) {
7252
7261
  let args;
7253
7262
  try {
7254
7263
  args = parseScaffoldArgs(rawArgs);
@@ -7267,7 +7276,7 @@ function createFormScaffoldTool(config) {
7267
7276
  return toolError(lines.join("\n"));
7268
7277
  }
7269
7278
  const specs = parsed;
7270
- const code10 = renderScaffold(specs, args.valueTypeName, args.wrapInSection);
7279
+ const code11 = renderScaffold(specs, args.valueTypeName, args.wrapInSection);
7271
7280
  const slugList = specs.map((s) => s.slug).join(", ");
7272
7281
  const preamble = `# Scaffold
7273
7282
 
@@ -7275,14 +7284,14 @@ Generated from \`${slugList}\` (${specs.length} field${specs.length === 1 ? "" :
7275
7284
  const text = `${preamble}
7276
7285
 
7277
7286
  \`\`\`ts
7278
- ${code10}
7287
+ ${code11}
7279
7288
  \`\`\``;
7280
7289
  const result = { content: [{ type: "text", text }] };
7281
7290
  return result;
7282
7291
  }
7283
7292
  const tool = {
7284
7293
  definition: DBX_FORM_SCAFFOLD_TOOL,
7285
- run
7294
+ run: run5
7286
7295
  };
7287
7296
  return tool;
7288
7297
  }
@@ -7543,7 +7552,7 @@ function formatNotFound3(normalized, candidates) {
7543
7552
  }
7544
7553
  function createLookupUiTool(input) {
7545
7554
  const { registry } = input;
7546
- const run = (rawArgs) => {
7555
+ const run5 = (rawArgs) => {
7547
7556
  let args;
7548
7557
  try {
7549
7558
  args = parseLookupUiArgs(rawArgs);
@@ -7570,7 +7579,7 @@ function createLookupUiTool(input) {
7570
7579
  const result = { content: [{ type: "text", text }] };
7571
7580
  return result;
7572
7581
  };
7573
- return { definition: DBX_UI_LOOKUP_TOOL, run };
7582
+ return { definition: DBX_UI_LOOKUP_TOOL, run: run5 };
7574
7583
  }
7575
7584
 
7576
7585
  // packages/dbx-components-mcp/src/tools/search-ui.tool.ts
@@ -7752,7 +7761,7 @@ function formatSearchResults2(options) {
7752
7761
  }
7753
7762
  function createSearchUiTool(input) {
7754
7763
  const { registry } = input;
7755
- const run = (rawArgs) => {
7764
+ const run5 = (rawArgs) => {
7756
7765
  let args;
7757
7766
  try {
7758
7767
  args = parseSearchUiArgs(rawArgs);
@@ -7767,7 +7776,7 @@ function createSearchUiTool(input) {
7767
7776
  const result = { content: [{ type: "text", text }] };
7768
7777
  return result;
7769
7778
  };
7770
- return { definition: DBX_UI_SEARCH_TOOL, run };
7779
+ return { definition: DBX_UI_SEARCH_TOOL, run: run5 };
7771
7780
  }
7772
7781
 
7773
7782
  // packages/dbx-components-mcp/src/tools/ui-examples.tool.ts
@@ -8956,7 +8965,7 @@ var FolderValidateArgsType = type29({
8956
8965
  });
8957
8966
  function createFolderValidateTool(config) {
8958
8967
  const { definition, inspectFolder: inspectFolder3, validate, format } = config;
8959
- async function run(rawArgs) {
8968
+ async function run5(rawArgs) {
8960
8969
  const parsed = FolderValidateArgsType(rawArgs);
8961
8970
  if (parsed instanceof type29.errors) {
8962
8971
  return toolError(`Invalid arguments: ${parsed.summary}`);
@@ -8996,7 +9005,7 @@ function createFolderValidateTool(config) {
8996
9005
  };
8997
9006
  return toolResult;
8998
9007
  }
8999
- const tool = { definition, run };
9008
+ const tool = { definition, run: run5 };
9000
9009
  return tool;
9001
9010
  }
9002
9011
  var SourceValidateArgsType = type29({
@@ -9006,7 +9015,7 @@ var SourceValidateArgsType = type29({
9006
9015
  });
9007
9016
  function createSourceValidateTool(config) {
9008
9017
  const { definition, validate, format } = config;
9009
- async function run(rawArgs) {
9018
+ async function run5(rawArgs) {
9010
9019
  const parsed = SourceValidateArgsType(rawArgs);
9011
9020
  if (parsed instanceof type29.errors) {
9012
9021
  return toolError(`Invalid arguments: ${parsed.summary}`);
@@ -9033,7 +9042,7 @@ function createSourceValidateTool(config) {
9033
9042
  };
9034
9043
  return toolResult;
9035
9044
  }
9036
- const tool = { definition, run };
9045
+ const tool = { definition, run: run5 };
9037
9046
  return tool;
9038
9047
  }
9039
9048
  var TwoSideValidateArgsType = type29({
@@ -9060,7 +9069,7 @@ function resolveTwoSideInput(parsed) {
9060
9069
  }
9061
9070
  function createTwoSideValidateTool(config) {
9062
9071
  const { definition, inspectAndValidate, format } = config;
9063
- async function run(rawArgs) {
9072
+ async function run5(rawArgs) {
9064
9073
  const parsed = TwoSideValidateArgsType(rawArgs);
9065
9074
  if (parsed instanceof type29.errors) {
9066
9075
  return toolError(`Invalid arguments: ${parsed.summary}`);
@@ -9077,7 +9086,7 @@ function createTwoSideValidateTool(config) {
9077
9086
  };
9078
9087
  return toolResult;
9079
9088
  }
9080
- const tool = { definition, run };
9089
+ const tool = { definition, run: run5 };
9081
9090
  return tool;
9082
9091
  }
9083
9092
  var ListAppArgsType = type29({
@@ -9087,7 +9096,7 @@ var ListAppArgsType = type29({
9087
9096
  });
9088
9097
  function createListAppTool(config) {
9089
9098
  const { definition, inspectAndList, formatMarkdown, formatJson } = config;
9090
- async function run(rawArgs) {
9099
+ async function run5(rawArgs) {
9091
9100
  const parsed = ListAppArgsType(rawArgs);
9092
9101
  if (parsed instanceof type29.errors) {
9093
9102
  return toolError(`Invalid arguments: ${parsed.summary}`);
@@ -9101,7 +9110,7 @@ function createListAppTool(config) {
9101
9110
  const toolResult = { content: [{ type: "text", text }] };
9102
9111
  return toolResult;
9103
9112
  }
9104
- const tool = { definition, run };
9113
+ const tool = { definition, run: run5 };
9105
9114
  return tool;
9106
9115
  }
9107
9116
 
@@ -9294,6 +9303,7 @@ function extractModel(sourceFile, identity) {
9294
9303
  const collectionFnName = variant === "root" ? `${camelName}FirestoreCollection` : `${camelName}FirestoreCollectionFactory`;
9295
9304
  const collectionFn = findFunction(sourceFile, collectionFnName);
9296
9305
  const collectionGroupFn = variant === "subcollection" ? findFunction(sourceFile, `${camelName}FirestoreCollectionGroup`) : void 0;
9306
+ const factoryCallKind = detectFactoryCallKind(sourceFile, collectionFnName);
9297
9307
  const extractedIdentity = {
9298
9308
  constName: identity.constName,
9299
9309
  exported: identity.exported,
@@ -9318,10 +9328,38 @@ function extractModel(sourceFile, identity) {
9318
9328
  collectionFactoryType,
9319
9329
  collectionGroupType,
9320
9330
  collectionFn,
9321
- collectionGroupFn
9331
+ collectionGroupFn,
9332
+ factoryCallKind
9322
9333
  };
9323
9334
  return result;
9324
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
+ }
9325
9363
  function deriveCamelName(constName) {
9326
9364
  const suffix = "Identity";
9327
9365
  return constName.endsWith(suffix) ? constName.slice(0, -suffix.length) : constName;
@@ -9788,21 +9826,37 @@ function checkCollectionType(file, model, violations) {
9788
9826
  return;
9789
9827
  }
9790
9828
  const typeText = model.collectionType.typeText ?? "";
9791
- if (model.variant === "root") {
9792
- const expected2 = `FirestoreCollection<${model.name}, ${model.name}Document>`;
9793
- if (typeText.replaceAll(/\s+/g, "") !== expected2.replaceAll(/\s+/g, "")) {
9794
- pushViolation(violations, {
9795
- code: "MODEL_COLLECTION_TYPE_WRONG_GENERIC",
9796
- message: `Type alias \`${model.name}FirestoreCollection\` must equal \`${expected2}\` (found \`${typeText || "<none>"}\`).`,
9797
- file: file.name,
9798
- line: model.collectionType.line,
9799
- model: model.name
9800
- });
9801
- }
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
+ });
9802
9840
  return;
9803
9841
  }
9804
- const parentPascal = pascalCase2(deriveCamelName2(model.identity.parentIdentityRef ?? ""));
9805
- 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);
9806
9860
  if (typeText.replaceAll(/\s+/g, "") !== expected.replaceAll(/\s+/g, "")) {
9807
9861
  pushViolation(violations, {
9808
9862
  code: "MODEL_COLLECTION_TYPE_WRONG_GENERIC",
@@ -9813,6 +9867,45 @@ function checkCollectionType(file, model, violations) {
9813
9867
  });
9814
9868
  }
9815
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
+ }
9816
9909
  function checkCollectionFn(file, model, violations) {
9817
9910
  if (model.collectionFn) {
9818
9911
  return;
@@ -11015,11 +11108,11 @@ function checkReadonlyFields(file, violations) {
11015
11108
  }
11016
11109
  }
11017
11110
  function checkInterfaceReadonly(options) {
11018
- const { file, decl, code: code10, violations } = options;
11111
+ const { file, decl, code: code11, violations } = options;
11019
11112
  for (const field of decl.fields) {
11020
11113
  if (field.readonly) continue;
11021
11114
  pushViolation2(violations, {
11022
- code: code10,
11115
+ code: code11,
11023
11116
  severity: "warning",
11024
11117
  message: `Field \`${field.name}\` on \`${decl.name}\` should be declared \`readonly\`.`,
11025
11118
  file: file.name,
@@ -11351,8 +11444,8 @@ async function inspectFolder(path) {
11351
11444
  status = "not-directory";
11352
11445
  }
11353
11446
  } catch (err) {
11354
- const code10 = err.code;
11355
- if (code10 === "ENOENT" || code10 === "ENOTDIR") {
11447
+ const code11 = err.code;
11448
+ if (code11 === "ENOENT" || code11 === "ENOTDIR") {
11356
11449
  status = "not-found";
11357
11450
  } else {
11358
11451
  throw err;
@@ -11919,140 +12012,1700 @@ function systemStateAccessorBody(args) {
11919
12012
  if (args.functionsClass !== void 0) {
11920
12013
  lines.push(` readonly ${functionsFieldName(args.functionsClass)} = inject(${args.functionsClass});`, "");
11921
12014
  }
11922
- lines.push(` constructor() {`, ` super(${typeConst});`, ` }`);
11923
- const crudLines = renderCrudLines(args, "this.systemStateDocumentStore");
11924
- if (crudLines.length > 0) {
11925
- 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}`);
11926
13569
  }
11927
- lines.push(`}`);
11928
- return { path: `${args.fileBaseName}.store.accessor.ts`, body: lines.join("\n") };
11929
- }
11930
- function documentDirectiveBody(args) {
11931
- const docType = `${args.modelName}Document`;
11932
- const storeClass = `${args.modelName}DocumentStore`;
11933
- const directiveClass = `${args.appPrefixPascal}${args.modelName}DocumentStoreDirective`;
11934
- const selector = `[${args.appPrefixCamel}${args.modelName}Document]`;
11935
- const lines = [
11936
- `import { Directive, inject } from '@angular/core';`,
11937
- `import { DbxFirebaseDocumentStoreDirective, provideDbxFirebaseDocumentStoreDirective } from '@dereekb/dbx-firebase';`,
11938
- `import { type ${args.modelName}, type ${docType} } from '${args.firebasePackage}';`,
11939
- `import { ${storeClass} } from './${args.fileBaseName}.document.store';`,
11940
- "",
11941
- `@Directive({`,
11942
- ` selector: '${selector}',`,
11943
- ` providers: provideDbxFirebaseDocumentStoreDirective(${directiveClass}, ${storeClass}),`,
11944
- ` standalone: true`,
11945
- `})`,
11946
- `export class ${directiveClass} extends DbxFirebaseDocumentStoreDirective<${args.modelName}, ${docType}, ${storeClass}> {`,
11947
- ` constructor() {`,
11948
- ` super(inject(${storeClass}));`,
11949
- ` }`,
11950
- `}`
11951
- ];
11952
- 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;
11953
13576
  }
11954
- function collectionDirectiveBody(args) {
11955
- const docType = `${args.modelName}Document`;
11956
- const storeClass = `${args.modelName}CollectionStore`;
11957
- const directiveClass = `${args.appPrefixPascal}${args.modelName}CollectionStoreDirective`;
11958
- const selector = `[${args.appPrefixCamel}${args.modelName}Collection]`;
11959
- const lines = [
11960
- `import { Directive, inject } from '@angular/core';`,
11961
- `import { DbxFirebaseCollectionStoreDirective, provideDbxFirebaseCollectionStoreDirective } from '@dereekb/dbx-firebase';`,
11962
- `import { type ${args.modelName}, type ${docType} } from '${args.firebasePackage}';`,
11963
- `import { ${storeClass} } from './${args.fileBaseName}.collection.store';`,
11964
- "",
11965
- `@Directive({`,
11966
- ` selector: '${selector}',`,
11967
- ` providers: provideDbxFirebaseCollectionStoreDirective(${directiveClass}, ${storeClass}),`,
11968
- ` standalone: true`,
11969
- `})`,
11970
- `export class ${directiveClass} extends DbxFirebaseCollectionStoreDirective<${args.modelName}, ${docType}, ${storeClass}> {`,
11971
- ` constructor() {`,
11972
- ` super(inject(${storeClass}));`,
11973
- ` }`,
11974
- `}`
11975
- ];
11976
- 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)];
11977
13587
  }
11978
- function buildBlocks(args) {
11979
- const blocks = [];
11980
- if (args.shape === "system-state") {
11981
- blocks.push(systemStateAccessorBody(args));
11982
- } else {
11983
- for (const surface of args.surfaces) {
11984
- if (surface === "document") {
11985
- if (args.shape === "sub-collection" || args.shape === "singleton-sub") {
11986
- blocks.push(subDocumentStoreBody(args));
11987
- } else {
11988
- blocks.push(rootDocumentStoreBody(args));
11989
- }
11990
- if (args.profile.emitsDirectives) {
11991
- blocks.push(documentDirectiveBody(args));
11992
- }
11993
- } else {
11994
- if (args.shape === "sub-collection") {
11995
- blocks.push(subCollectionStoreBody(args));
11996
- } else {
11997
- blocks.push(rootCollectionStoreBody(args));
11998
- }
11999
- if (args.profile.emitsDirectives) {
12000
- blocks.push(collectionDirectiveBody(args));
12001
- }
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."
12002
13611
  }
12003
- }
13612
+ },
13613
+ required: ["apiDir", "model"]
12004
13614
  }
12005
- return blocks;
12006
- }
12007
- function formatScaffold(args) {
12008
- const blocks = buildBlocks(args);
12009
- const surfaceLabel = args.shape === "system-state" ? "accessor" : args.surfaces.join(" + ");
12010
- const functionsLabel = args.functionsClass ?? "none";
12011
- const crudLabel = args.crudFunctions.length > 0 ? args.crudFunctions.map((c) => `${c.name} (${c.kind})`).join(", ") : "none";
12012
- const parentLabel = args.parentModel === void 0 ? "n/a" : args.parentModel.name;
12013
- 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/\`.`, ""];
12014
- for (const block of blocks) {
12015
- 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}`);
12016
13620
  }
12017
- 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).");
12018
- if (args.shape === "sub-collection" || args.shape === "singleton-sub") {
12019
- 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));
12020
13626
  }
12021
- if (args.shape === "system-state") {
12022
- 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)}`);
12023
13633
  }
12024
- if (args.crudFunctions.length > 0) {
12025
- 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}.`);
12026
13638
  }
12027
- lines.push('- \u2192 See `dbx_model_lookup topic="shapes"` for the full store-shape taxonomy.', "- \u2192 Skill: `dbx__guide__angular-stores`.");
12028
- 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) }] };
12029
13649
  }
12030
- function runModelStoreScaffold(rawArgs) {
12031
- 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;
12032
13656
  try {
12033
- args = parseArgs2(rawArgs);
13657
+ sourceFile = project.addSourceFileAtPath(absolutePath);
12034
13658
  } catch (err) {
12035
- const message = err instanceof Error ? err.message : String(err);
12036
- return toolError(message);
13659
+ return `Failed to load fixture file: ${toErrorMessage(err)}`;
12037
13660
  }
12038
- const text = formatScaffold(args);
12039
- const result = { content: [{ type: "text", text }] };
12040
- 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;
12041
13675
  }
12042
- var modelStoreScaffoldTool = {
12043
- definition: DBX_MODEL_STORE_SCAFFOLD_TOOL,
12044
- run: runModelStoreScaffold
12045
- };
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 };
12046
13699
 
12047
13700
  // packages/dbx-components-mcp/src/tools/storagefile-m-validate-app/extract.ts
12048
- import { Node as Node9, SyntaxKind as SyntaxKind6 } from "ts-morph";
13701
+ import { Node as Node10, SyntaxKind as SyntaxKind7 } from "ts-morph";
12049
13702
 
12050
13703
  // packages/dbx-components-mcp/src/tools/_validate/ast.ts
12051
- 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";
12052
13705
  var COMPONENT_VIRTUAL_PREFIX = "__component__/";
12053
13706
  var API_VIRTUAL_PREFIX = "__api__/";
12054
13707
  function buildInMemoryProject(input) {
12055
- const project = new Project6({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
13708
+ const project = new Project8({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
12056
13709
  const componentSources = [];
12057
13710
  const apiSources = [];
12058
13711
  for (const file of input.component.files) {
@@ -12072,28 +13725,28 @@ function componentRelPath(sourceFile) {
12072
13725
  }
12073
13726
  function unwrapAsExpressions(node) {
12074
13727
  let current = node;
12075
- while (current && Node8.isAsExpression(current)) {
13728
+ while (current && Node9.isAsExpression(current)) {
12076
13729
  current = current.getExpression();
12077
13730
  }
12078
13731
  return current;
12079
13732
  }
12080
13733
  function asObjectLiteral(node) {
12081
13734
  const inner = unwrapAsExpressions(node);
12082
- if (inner && Node8.isObjectLiteralExpression(inner)) {
13735
+ if (inner && Node9.isObjectLiteralExpression(inner)) {
12083
13736
  return inner;
12084
13737
  }
12085
13738
  return void 0;
12086
13739
  }
12087
13740
  function asArrayLiteral(node) {
12088
13741
  const inner = unwrapAsExpressions(node);
12089
- if (inner && Node8.isArrayLiteralExpression(inner)) {
13742
+ if (inner && Node9.isArrayLiteralExpression(inner)) {
12090
13743
  return inner;
12091
13744
  }
12092
13745
  return void 0;
12093
13746
  }
12094
13747
  function readStringLiteralInitializer(decl) {
12095
13748
  const initializer = unwrapAsExpressions(decl.getInitializer());
12096
- if (initializer && Node8.isStringLiteral(initializer)) {
13749
+ if (initializer && Node9.isStringLiteral(initializer)) {
12097
13750
  return initializer.getLiteralText();
12098
13751
  }
12099
13752
  return void 0;
@@ -12105,37 +13758,37 @@ function typeAnnotationText(node) {
12105
13758
  function getPropertyInitializer(obj, name) {
12106
13759
  const prop = obj.getProperty(name);
12107
13760
  if (!prop) return void 0;
12108
- if (Node8.isPropertyAssignment(prop)) {
13761
+ if (Node9.isPropertyAssignment(prop)) {
12109
13762
  return prop.getInitializer();
12110
13763
  }
12111
- if (Node8.isShorthandPropertyAssignment(prop)) {
13764
+ if (Node9.isShorthandPropertyAssignment(prop)) {
12112
13765
  return prop.getNameNode();
12113
13766
  }
12114
13767
  return void 0;
12115
13768
  }
12116
13769
  function readStringProperty2(obj, name) {
12117
13770
  const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
12118
- if (init && Node8.isStringLiteral(init)) {
13771
+ if (init && Node9.isStringLiteral(init)) {
12119
13772
  return init.getLiteralText();
12120
13773
  }
12121
13774
  return void 0;
12122
13775
  }
12123
13776
  function readIdentifierProperty(obj, name) {
12124
13777
  const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
12125
- if (init && Node8.isIdentifier(init)) {
13778
+ if (init && Node9.isIdentifier(init)) {
12126
13779
  return init.getText();
12127
13780
  }
12128
13781
  return void 0;
12129
13782
  }
12130
13783
  function findReturnExpression(fn) {
12131
- if (!Node8.isArrowFunction(fn) && !Node8.isFunctionDeclaration(fn) && !Node8.isFunctionExpression(fn)) {
13784
+ if (!Node9.isArrowFunction(fn) && !Node9.isFunctionDeclaration(fn) && !Node9.isFunctionExpression(fn)) {
12132
13785
  return void 0;
12133
13786
  }
12134
13787
  const body = fn.getBody();
12135
13788
  if (!body) return void 0;
12136
- if (Node8.isBlock(body)) {
13789
+ if (Node9.isBlock(body)) {
12137
13790
  for (const stmt of body.getStatements()) {
12138
- if (Node8.isReturnStatement(stmt)) {
13791
+ if (Node9.isReturnStatement(stmt)) {
12139
13792
  return stmt.getExpression();
12140
13793
  }
12141
13794
  }
@@ -12149,17 +13802,17 @@ function findLocalVariable(sf, name) {
12149
13802
  if (decl.getName() === name) return decl;
12150
13803
  }
12151
13804
  }
12152
- for (const decl of sf.getDescendantsOfKind(SyntaxKind5.VariableDeclaration)) {
13805
+ for (const decl of sf.getDescendantsOfKind(SyntaxKind6.VariableDeclaration)) {
12153
13806
  if (decl.getName() === name) return decl;
12154
13807
  }
12155
13808
  return void 0;
12156
13809
  }
12157
13810
  function collectTypeofReferences(node, out) {
12158
- if (Node8.isTypeQuery(node)) {
13811
+ if (Node9.isTypeQuery(node)) {
12159
13812
  out.push(node.getExprName().getText());
12160
13813
  return;
12161
13814
  }
12162
- for (const tq of node.getDescendantsOfKind(SyntaxKind5.TypeQuery)) {
13815
+ for (const tq of node.getDescendantsOfKind(SyntaxKind6.TypeQuery)) {
12163
13816
  out.push(tq.getExprName().getText());
12164
13817
  }
12165
13818
  }
@@ -12457,8 +14110,8 @@ function getFunctionType(x) {
12457
14110
  return typeof x === "function" ? x.prototype ? Object.getOwnPropertyDescriptor(x, "prototype")?.writable ? "function" : "class" : x.constructor.name === "AsyncFunction" ? "function" : "arrow" : null;
12458
14111
  }
12459
14112
  function isNonClassFunction(x) {
12460
- const type43 = getFunctionType(x);
12461
- return type43 != null && type43 !== "class";
14113
+ const type48 = getFunctionType(x);
14114
+ return type48 != null && type48 !== "class";
12462
14115
  }
12463
14116
 
12464
14117
  // packages/util/src/lib/getter/getter.ts
@@ -12535,9 +14188,9 @@ function asNumber(input) {
12535
14188
  }
12536
14189
 
12537
14190
  // packages/util/src/lib/number/round.ts
12538
- function roundingFunction(type43) {
14191
+ function roundingFunction(type48) {
12539
14192
  let fn;
12540
- switch (type43) {
14193
+ switch (type48) {
12541
14194
  case "floor":
12542
14195
  fn = Math.floor;
12543
14196
  break;
@@ -12790,9 +14443,9 @@ function filterKeyValueTuplesInputToFilter(input) {
12790
14443
  }
12791
14444
  function filterKeyValueTupleFunction(inputFilter) {
12792
14445
  const filter = filterKeyValueTuplesInputToFilter(inputFilter);
12793
- const { valueFilter: type43 = 1 /* UNDEFINED */, invertFilter: inverseFilter = false, keysFilter } = filter;
14446
+ const { valueFilter: type48 = 1 /* UNDEFINED */, invertFilter: inverseFilter = false, keysFilter } = filter;
12794
14447
  let filterFn;
12795
- switch (type43) {
14448
+ switch (type48) {
12796
14449
  case 1 /* UNDEFINED */:
12797
14450
  filterFn = ([, x]) => x !== void 0;
12798
14451
  break;
@@ -13051,7 +14704,7 @@ var NUMBER_STRING_DENCODER_64_DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcd
13051
14704
  var NUMBER_STRING_DENCODER_64_DEFAULT_NEGATIVE_PREFIX = "!";
13052
14705
  function numberStringDencoder(config) {
13053
14706
  const { negativePrefix, digits } = config;
13054
- const type43 = negativePrefix ? "integer" : "positive_integer";
14707
+ const type48 = negativePrefix ? "integer" : "positive_integer";
13055
14708
  const log2OfDigits = Math.min(6, Math.floor(Math.log2(digits.length)));
13056
14709
  const bitDepth = Math.pow(2, log2OfDigits);
13057
14710
  const bitMask = bitDepth - 1;
@@ -13088,7 +14741,7 @@ function numberStringDencoder(config) {
13088
14741
  return result;
13089
14742
  }
13090
14743
  return {
13091
- type: type43,
14744
+ type: type48,
13092
14745
  digits,
13093
14746
  bitDepth,
13094
14747
  negativePrefix,
@@ -13159,9 +14812,9 @@ function readableStreamToStringFunction(encoding) {
13159
14812
  var readableStreamToBase64 = readableStreamToStringFunction("base64");
13160
14813
  function readableStreamToBuffer(stream) {
13161
14814
  const chunks = [];
13162
- return new Promise((resolve17, reject) => {
14815
+ return new Promise((resolve22, reject) => {
13163
14816
  stream.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
13164
- stream.on("end", () => resolve17(Buffer.concat(chunks)));
14817
+ stream.on("end", () => resolve22(Buffer.concat(chunks)));
13165
14818
  stream.on("error", reject);
13166
14819
  });
13167
14820
  }
@@ -13584,7 +15237,7 @@ function extractUploadInitializerEntries(sources) {
13584
15237
  const out = [];
13585
15238
  for (const sf of sources) {
13586
15239
  const rel = apiRelPath(sf);
13587
- for (const decl of sf.getDescendantsOfKind(SyntaxKind6.VariableDeclaration)) {
15240
+ for (const decl of sf.getDescendantsOfKind(SyntaxKind7.VariableDeclaration)) {
13588
15241
  const typeText = typeAnnotationText(decl);
13589
15242
  if (typeText !== UPLOAD_SERVICE_INITIALIZER_TYPE) continue;
13590
15243
  const obj = asObjectLiteral(decl.getInitializer());
@@ -13614,7 +15267,7 @@ function buildApiFunctionIndex(sources) {
13614
15267
  for (const decl of stmt.getDeclarations()) {
13615
15268
  const initializer = unwrapAsExpressions(decl.getInitializer());
13616
15269
  if (!initializer) continue;
13617
- if (Node9.isArrowFunction(initializer) || Node9.isFunctionExpression(initializer)) {
15270
+ if (Node10.isArrowFunction(initializer) || Node10.isFunctionExpression(initializer)) {
13618
15271
  map.set(decl.getName(), { node: initializer, sourceFile: sf });
13619
15272
  }
13620
15273
  }
@@ -13627,34 +15280,34 @@ function collectInitializerBindingsFromValue(options) {
13627
15280
  const { node, sf, index, resolved, unresolved, visited } = options;
13628
15281
  const inner = unwrapAsExpressions(node);
13629
15282
  if (!inner) return false;
13630
- if (Node9.isArrayLiteralExpression(inner)) {
15283
+ if (Node10.isArrayLiteralExpression(inner)) {
13631
15284
  for (const el of inner.getElements()) {
13632
- if (Node9.isSpreadElement(el)) {
15285
+ if (Node10.isSpreadElement(el)) {
13633
15286
  const spreadInner = el.getExpression();
13634
- if (Node9.isIdentifier(spreadInner)) {
15287
+ if (Node10.isIdentifier(spreadInner)) {
13635
15288
  collectInitializerBindingsFromIdentifier({ name: spreadInner.getText(), sf, index, resolved, unresolved, visited });
13636
- } else if (Node9.isCallExpression(spreadInner)) {
15289
+ } else if (Node10.isCallExpression(spreadInner)) {
13637
15290
  const callee = spreadInner.getExpression();
13638
- if (Node9.isIdentifier(callee)) {
15291
+ if (Node10.isIdentifier(callee)) {
13639
15292
  collectInitializerBindingsFromIdentifier({ name: callee.getText(), sf, index, resolved, unresolved, visited });
13640
15293
  }
13641
15294
  }
13642
15295
  continue;
13643
15296
  }
13644
15297
  const elementInner = unwrapAsExpressions(el);
13645
- if (elementInner && Node9.isIdentifier(elementInner)) {
15298
+ if (elementInner && Node10.isIdentifier(elementInner)) {
13646
15299
  resolved.push(elementInner.getText());
13647
15300
  }
13648
15301
  }
13649
15302
  return true;
13650
15303
  }
13651
- if (Node9.isCallExpression(inner)) {
15304
+ if (Node10.isCallExpression(inner)) {
13652
15305
  const callee = inner.getExpression();
13653
- if (Node9.isIdentifier(callee)) {
15306
+ if (Node10.isIdentifier(callee)) {
13654
15307
  return collectInitializerBindingsFromIdentifier({ name: callee.getText(), sf, index, resolved, unresolved, visited });
13655
15308
  }
13656
15309
  }
13657
- if (Node9.isIdentifier(inner)) {
15310
+ if (Node10.isIdentifier(inner)) {
13658
15311
  return collectInitializerBindingsFromIdentifier({ name: inner.getText(), sf, index, resolved, unresolved, visited });
13659
15312
  }
13660
15313
  return false;
@@ -13693,15 +15346,15 @@ function collectUploadInitializerArray(options) {
13693
15346
  const { initializerArr, sf, index, direct, spreads, resolved, unresolved } = options;
13694
15347
  const visited = /* @__PURE__ */ new Set();
13695
15348
  for (const el of initializerArr.getElements()) {
13696
- if (Node9.isSpreadElement(el)) {
15349
+ if (Node10.isSpreadElement(el)) {
13697
15350
  const inner2 = el.getExpression();
13698
- if (Node9.isIdentifier(inner2)) {
15351
+ if (Node10.isIdentifier(inner2)) {
13699
15352
  const name = inner2.getText();
13700
15353
  spreads.push(name);
13701
15354
  collectInitializerBindingsFromIdentifier({ name, sf, index, resolved, unresolved, visited });
13702
- } else if (Node9.isCallExpression(inner2)) {
15355
+ } else if (Node10.isCallExpression(inner2)) {
13703
15356
  const callee = inner2.getExpression();
13704
- if (Node9.isIdentifier(callee)) {
15357
+ if (Node10.isIdentifier(callee)) {
13705
15358
  const name = callee.getText();
13706
15359
  spreads.push(name);
13707
15360
  collectInitializerBindingsFromIdentifier({ name, sf, index, resolved, unresolved, visited });
@@ -13710,7 +15363,7 @@ function collectUploadInitializerArray(options) {
13710
15363
  continue;
13711
15364
  }
13712
15365
  const inner = unwrapAsExpressions(el);
13713
- if (inner && Node9.isIdentifier(inner)) {
15366
+ if (inner && Node10.isIdentifier(inner)) {
13714
15367
  const name = inner.getText();
13715
15368
  direct.push(name);
13716
15369
  resolved.push(name);
@@ -13721,9 +15374,9 @@ function extractUploadServiceCalls(sources, index) {
13721
15374
  const out = [];
13722
15375
  for (const sf of sources) {
13723
15376
  const rel = apiRelPath(sf);
13724
- for (const call of sf.getDescendantsOfKind(SyntaxKind6.CallExpression)) {
15377
+ for (const call of sf.getDescendantsOfKind(SyntaxKind7.CallExpression)) {
13725
15378
  const expr = call.getExpression();
13726
- if (!Node9.isIdentifier(expr) || expr.getText() !== UPLOAD_SERVICE_FACTORY) continue;
15379
+ if (!Node10.isIdentifier(expr) || expr.getText() !== UPLOAD_SERVICE_FACTORY) continue;
13727
15380
  const args = call.getArguments();
13728
15381
  const first = args[0] ? resolveObjectArg(args[0], sf) : void 0;
13729
15382
  if (!first) continue;
@@ -13751,12 +15404,12 @@ function extractUploadServiceCalls(sources, index) {
13751
15404
  function resolveObjectArg(node, sf) {
13752
15405
  const inner = unwrapAsExpressions(node);
13753
15406
  if (!inner) return void 0;
13754
- if (Node9.isObjectLiteralExpression(inner)) return inner;
13755
- if (Node9.isIdentifier(inner)) {
15407
+ if (Node10.isObjectLiteralExpression(inner)) return inner;
15408
+ if (Node10.isIdentifier(inner)) {
13756
15409
  const declNode = findLocalVariable(sf, inner.getText());
13757
15410
  if (declNode) {
13758
15411
  const declInit = unwrapAsExpressions(declNode.getInitializer());
13759
- if (declInit && Node9.isObjectLiteralExpression(declInit)) {
15412
+ if (declInit && Node10.isObjectLiteralExpression(declInit)) {
13760
15413
  return declInit;
13761
15414
  }
13762
15415
  }
@@ -13766,12 +15419,12 @@ function resolveObjectArg(node, sf) {
13766
15419
  function resolveArrayFromProperty(obj, name, sf) {
13767
15420
  const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
13768
15421
  if (!init) return void 0;
13769
- if (Node9.isArrayLiteralExpression(init)) return init;
13770
- if (Node9.isIdentifier(init)) {
15422
+ if (Node10.isArrayLiteralExpression(init)) return init;
15423
+ if (Node10.isIdentifier(init)) {
13771
15424
  const declNode = findLocalVariable(sf, init.getText());
13772
15425
  if (declNode) {
13773
15426
  const declInit = unwrapAsExpressions(declNode.getInitializer());
13774
- if (declInit && Node9.isArrayLiteralExpression(declInit)) {
15427
+ if (declInit && Node10.isArrayLiteralExpression(declInit)) {
13775
15428
  return declInit;
13776
15429
  }
13777
15430
  }
@@ -13782,11 +15435,11 @@ function enclosingFactoryName(node) {
13782
15435
  let current = node.getParent();
13783
15436
  let result;
13784
15437
  while (current) {
13785
- if (Node9.isFunctionDeclaration(current)) {
15438
+ if (Node10.isFunctionDeclaration(current)) {
13786
15439
  result = current.getName() ?? void 0;
13787
15440
  break;
13788
15441
  }
13789
- if (Node9.isVariableDeclaration(current)) {
15442
+ if (Node10.isVariableDeclaration(current)) {
13790
15443
  result = current.getName();
13791
15444
  break;
13792
15445
  }
@@ -13798,7 +15451,7 @@ function extractUploadServiceWirings(sources) {
13798
15451
  const out = [];
13799
15452
  for (const sf of sources) {
13800
15453
  const rel = apiRelPath(sf);
13801
- for (const obj of sf.getDescendantsOfKind(SyntaxKind6.ObjectLiteralExpression)) {
15454
+ for (const obj of sf.getDescendantsOfKind(SyntaxKind7.ObjectLiteralExpression)) {
13802
15455
  const provideIdent = readIdentifierProperty(obj, "provide");
13803
15456
  if (provideIdent !== UPLOAD_SERVICE_PROVIDE_TOKEN) continue;
13804
15457
  const useFactory = readIdentifierProperty(obj, "useFactory");
@@ -13811,7 +15464,7 @@ function extractProcessingConfigs(sources) {
13811
15464
  const out = [];
13812
15465
  for (const sf of sources) {
13813
15466
  const rel = apiRelPath(sf);
13814
- for (const decl of sf.getDescendantsOfKind(SyntaxKind6.VariableDeclaration)) {
15467
+ for (const decl of sf.getDescendantsOfKind(SyntaxKind7.VariableDeclaration)) {
13815
15468
  const config = extractProcessingConfigFromDecl(decl, rel);
13816
15469
  if (config) {
13817
15470
  out.push(config);
@@ -13840,10 +15493,10 @@ function extractProcessingConfigFromDecl(decl, rel) {
13840
15493
  function readFlowSubtasks(obj) {
13841
15494
  const flowInit = unwrapAsExpressions(getPropertyInitializer(obj, "flow"));
13842
15495
  const subtasks = [];
13843
- if (flowInit && Node9.isArrayLiteralExpression(flowInit)) {
15496
+ if (flowInit && Node10.isArrayLiteralExpression(flowInit)) {
13844
15497
  for (const el of flowInit.getElements()) {
13845
15498
  const inner = unwrapAsExpressions(el);
13846
- if (inner && Node9.isObjectLiteralExpression(inner)) {
15499
+ if (inner && Node10.isObjectLiteralExpression(inner)) {
13847
15500
  const subtask = readIdentifierProperty(inner, "subtask");
13848
15501
  if (subtask) subtasks.push(subtask);
13849
15502
  }
@@ -13855,9 +15508,9 @@ function extractProcessingHandlerCalls(sources) {
13855
15508
  const out = [];
13856
15509
  for (const sf of sources) {
13857
15510
  const rel = apiRelPath(sf);
13858
- for (const call of sf.getDescendantsOfKind(SyntaxKind6.CallExpression)) {
15511
+ for (const call of sf.getDescendantsOfKind(SyntaxKind7.CallExpression)) {
13859
15512
  const expr = call.getExpression();
13860
- if (!Node9.isIdentifier(expr) || expr.getText() !== PROCESSING_HANDLER_FACTORY) continue;
15513
+ if (!Node10.isIdentifier(expr) || expr.getText() !== PROCESSING_HANDLER_FACTORY) continue;
13861
15514
  const args = call.getArguments();
13862
15515
  const first = args[0] ? resolveObjectArg(args[0], sf) : void 0;
13863
15516
  if (!first) continue;
@@ -13878,7 +15531,7 @@ function extractProcessingHandlerCalls(sources) {
13878
15531
  }
13879
15532
  function collectProcessorArrayElements(processorsArr, direct, spreads) {
13880
15533
  for (const el of processorsArr.getElements()) {
13881
- if (Node9.isSpreadElement(el)) {
15534
+ if (Node10.isSpreadElement(el)) {
13882
15535
  addProcessorIdentifierName(el.getExpression(), spreads);
13883
15536
  continue;
13884
15537
  }
@@ -13890,13 +15543,13 @@ function collectProcessorArrayElements(processorsArr, direct, spreads) {
13890
15543
  }
13891
15544
  function addProcessorIdentifierName(node, bucket) {
13892
15545
  if (!node) return;
13893
- if (Node9.isIdentifier(node)) {
15546
+ if (Node10.isIdentifier(node)) {
13894
15547
  bucket.push(node.getText());
13895
15548
  return;
13896
15549
  }
13897
- if (Node9.isCallExpression(node)) {
15550
+ if (Node10.isCallExpression(node)) {
13898
15551
  const callee = node.getExpression();
13899
- if (Node9.isIdentifier(callee)) {
15552
+ if (Node10.isIdentifier(callee)) {
13900
15553
  bucket.push(callee.getText());
13901
15554
  }
13902
15555
  }
@@ -13938,7 +15591,7 @@ function runRules4(inspection, extracted) {
13938
15591
  violations,
13939
15592
  codes: IO_VIOLATION_CODES,
13940
15593
  messages: IO_VIOLATION_MESSAGES,
13941
- build: (code10, message, side) => buildIoViolation(code10, message, side)
15594
+ build: (code11, message, side) => buildIoViolation(code11, message, side)
13942
15595
  });
13943
15596
  if (!proceed) {
13944
15597
  return violations;
@@ -14170,18 +15823,18 @@ function checkDuplicates(extracted, violations) {
14170
15823
  flagDuplicates({ entries: extracted.fileTypeIdentifierConstants.map(toCodeRef), code: "STORAGEFILE_FILE_TYPE_IDENTIFIER_DUPLICATE", label: "`UploadedFileTypeIdentifier`", violations });
14171
15824
  }
14172
15825
  function toCodeRef(entry) {
14173
- const code10 = "purposeCode" in entry ? entry.purposeCode : entry.typeCode;
14174
- 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 };
14175
15828
  }
14176
15829
  function flagDuplicates(options) {
14177
- const { entries, code: code10, label, violations } = options;
15830
+ const { entries, code: code11, label, violations } = options;
14178
15831
  const seen = /* @__PURE__ */ new Map();
14179
15832
  for (const entry of entries) {
14180
15833
  if (!entry.code) continue;
14181
15834
  const previous = seen.get(entry.code);
14182
15835
  if (previous) {
14183
15836
  pushViolation4(violations, {
14184
- code: code10,
15837
+ code: code11,
14185
15838
  severity: "warning",
14186
15839
  message: `${label} value \`'${entry.code}'\` is shared by \`${previous}\` and \`${entry.symbolName}\`. Choose unique string literals.`,
14187
15840
  side: "component",
@@ -14231,9 +15884,9 @@ function pushViolation4(buffer, violation) {
14231
15884
  };
14232
15885
  buffer.push(filled);
14233
15886
  }
14234
- function buildIoViolation(code10, message, side) {
15887
+ function buildIoViolation(code11, message, side) {
14235
15888
  const result = {
14236
- code: code10,
15889
+ code: code11,
14237
15890
  severity: "error",
14238
15891
  message,
14239
15892
  side,
@@ -14249,8 +15902,8 @@ function formatResult4(result) {
14249
15902
  }
14250
15903
 
14251
15904
  // packages/dbx-components-mcp/src/tools/_validate/inspect.ts
14252
- import { readdir as readdir2, readFile as readFile2, stat as stat3 } from "node:fs/promises";
14253
- 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";
14254
15907
  async function inspectSide(rootDir, subpaths) {
14255
15908
  const rootStatus = await readRootStatus(rootDir);
14256
15909
  if (rootStatus !== void 0) {
@@ -14260,7 +15913,7 @@ async function inspectSide(rootDir, subpaths) {
14260
15913
  const presentFolders = [];
14261
15914
  const collectedFiles = [];
14262
15915
  for (const sub of subpaths) {
14263
- const absFolder = join(rootDir, sub);
15916
+ const absFolder = join4(rootDir, sub);
14264
15917
  const folderPresent = await isDirectory(absFolder);
14265
15918
  if (!folderPresent) continue;
14266
15919
  presentFolders.push(sub);
@@ -14279,8 +15932,8 @@ async function readRootStatus(rootDir) {
14279
15932
  const stats = await stat3(rootDir);
14280
15933
  return stats.isDirectory() ? void 0 : "dir-not-found";
14281
15934
  } catch (err) {
14282
- const code10 = err.code;
14283
- if (code10 === "ENOENT" || code10 === "ENOTDIR") {
15935
+ const code11 = err.code;
15936
+ if (code11 === "ENOENT" || code11 === "ENOTDIR") {
14284
15937
  return "dir-not-found";
14285
15938
  }
14286
15939
  throw err;
@@ -14306,7 +15959,7 @@ async function collectTsFiles(absFolder, rootDir) {
14306
15959
  continue;
14307
15960
  }
14308
15961
  for (const entry of entries) {
14309
- const full = join(current, entry.name);
15962
+ const full = join4(current, entry.name);
14310
15963
  if (entry.isDirectory()) {
14311
15964
  stack.push(full);
14312
15965
  continue;
@@ -14315,7 +15968,7 @@ async function collectTsFiles(absFolder, rootDir) {
14315
15968
  if (!entry.name.endsWith(".ts")) continue;
14316
15969
  if (entry.name.endsWith(".spec.ts")) continue;
14317
15970
  if (entry.name.endsWith(".d.ts")) continue;
14318
- const text = await readFile2(full, "utf8");
15971
+ const text = await readFile4(full, "utf8");
14319
15972
  const rel = relative4(rootDir, full).split(sep2).join("/");
14320
15973
  out.push({ relPath: rel, text });
14321
15974
  }
@@ -14487,7 +16140,7 @@ function formatReportAsJson(report) {
14487
16140
  // packages/dbx-components-mcp/src/tools/storagefile-m-list-app/format.markdown.ts
14488
16141
  function formatReportAsMarkdown(report) {
14489
16142
  const basename4 = report.componentDir.split("/").pop() ?? report.componentDir;
14490
- const uploadServiceFactoryText = report.uploadServiceFactoryName ? code3(report.uploadServiceFactoryName) : "_Not defined._";
16143
+ const uploadServiceFactoryText = report.uploadServiceFactoryName ? code4(report.uploadServiceFactoryName) : "_Not defined._";
14491
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})`];
14492
16145
  if (report.purposes.length === 0) {
14493
16146
  lines.push("", "_None found._");
@@ -14503,15 +16156,15 @@ function formatPurposeBlock(p) {
14503
16156
  const heading = p.purposeCode ? `### ${p.purposeCode} \u2014 \`${p.purposeSymbolName}\`` : `### \`${p.purposeSymbolName}\``;
14504
16157
  parts.push(heading);
14505
16158
  if (p.fileTypeIdentifierCode) {
14506
- const codePart = p.fileTypeIdentifier ? ` (` + code3(`'${p.fileTypeIdentifier}'`) + `)` : "";
16159
+ const codePart = p.fileTypeIdentifier ? ` (` + code4(`'${p.fileTypeIdentifier}'`) + `)` : "";
14507
16160
  parts.push(`- Uploaded file type identifier: \`${p.fileTypeIdentifierCode}\`${codePart}`);
14508
16161
  } else {
14509
16162
  parts.push(`- Uploaded file type identifier: _Missing._`);
14510
16163
  }
14511
- const groupIdsText = p.fileGroupIdsFunctionName ? code3(p.fileGroupIdsFunctionName) : "_Missing._";
16164
+ const groupIdsText = p.fileGroupIdsFunctionName ? code4(p.fileGroupIdsFunctionName) : "_Missing._";
14512
16165
  parts.push(`- Group-ids helper: ${groupIdsText}`);
14513
16166
  if (p.subtasks.length > 0) {
14514
- const subtasksText = p.subtasks.map((s) => code3(s)).join(", ");
16167
+ const subtasksText = p.subtasks.map((s) => code4(s)).join(", ");
14515
16168
  parts.push(`- Processing subtasks: ${subtasksText}`);
14516
16169
  }
14517
16170
  const uploadInitSuffix = p.uploadInitializerSourceFile ? ` _(${p.uploadInitializerSourceFile})_` : "";
@@ -14522,7 +16175,7 @@ function formatPurposeBlock(p) {
14522
16175
  function formatBool(value) {
14523
16176
  return value ? "yes" : "no";
14524
16177
  }
14525
- function code3(value) {
16178
+ function code4(value) {
14526
16179
  return "`" + value + "`";
14527
16180
  }
14528
16181
 
@@ -14568,8 +16221,8 @@ var storageFileMListAppTool = createListAppTool({
14568
16221
  });
14569
16222
 
14570
16223
  // packages/dbx-components-mcp/src/tools/validate-two-side-folder.ts
14571
- import { readdir as readdir3, readFile as readFile3, stat as stat4 } from "node:fs/promises";
14572
- 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";
14573
16226
  var REEXPORT_PATTERN = /^\s*export\s+\*\s+from\s+['"]\.\/([^'"\n]+)['"]\s*;?\s*$/gm;
14574
16227
  function createTwoSideFolderValidator(config) {
14575
16228
  async function inspect(input) {
@@ -14613,7 +16266,7 @@ async function inspectSide2(input) {
14613
16266
  let indexSource;
14614
16267
  const rootStatOk = await isExistingDirectory(rootDir);
14615
16268
  if (rootStatOk) {
14616
- const absFolder = join2(rootDir, subPath);
16269
+ const absFolder = join5(rootDir, subPath);
14617
16270
  const folderStatOk = await isExistingDirectory(absFolder);
14618
16271
  if (folderStatOk) {
14619
16272
  const folder = await readFolder(absFolder, indexFile);
@@ -14642,8 +16295,8 @@ async function isExistingDirectory(path) {
14642
16295
  const stats = await stat4(path);
14643
16296
  return stats.isDirectory();
14644
16297
  } catch (err) {
14645
- const code10 = err.code;
14646
- if (code10 !== "ENOENT" && code10 !== "ENOTDIR") {
16298
+ const code11 = err.code;
16299
+ if (code11 !== "ENOENT" && code11 !== "ENOTDIR") {
14647
16300
  throw err;
14648
16301
  }
14649
16302
  return false;
@@ -14665,7 +16318,7 @@ async function readFolder(absFolder, indexFile) {
14665
16318
  let indexSource;
14666
16319
  if (collectedFiles.includes(indexFile)) {
14667
16320
  try {
14668
- indexSource = await readFile3(join2(absFolder, indexFile), "utf8");
16321
+ indexSource = await readFile5(join5(absFolder, indexFile), "utf8");
14669
16322
  } catch {
14670
16323
  indexSource = void 0;
14671
16324
  }
@@ -14884,7 +16537,7 @@ var storageFileMValidateFolderTool = createTwoSideValidateTool({
14884
16537
  });
14885
16538
 
14886
16539
  // packages/dbx-components-mcp/src/tools/notification-m-validate-app/extract.ts
14887
- import { Node as Node10, SyntaxKind as SyntaxKind7 } from "ts-morph";
16540
+ import { Node as Node11, SyntaxKind as SyntaxKind8 } from "ts-morph";
14888
16541
  var NOTIF_TEMPLATE_TYPE = "NotificationTemplateType";
14889
16542
  var NOTIF_TEMPLATE_TYPE_INFO = "NotificationTemplateTypeInfo";
14890
16543
  var NOTIF_TEMPLATE_TYPE_INFO_ARRAY = "NotificationTemplateTypeInfo[]";
@@ -15005,7 +16658,7 @@ function extractTemplateInfoAggregates(sources) {
15005
16658
  const ids = [];
15006
16659
  for (const el of arr.getElements()) {
15007
16660
  const inner = unwrapAsExpressions(el);
15008
- if (inner && Node10.isIdentifier(inner)) {
16661
+ if (inner && Node11.isIdentifier(inner)) {
15009
16662
  ids.push(inner.getText());
15010
16663
  }
15011
16664
  }
@@ -15051,7 +16704,7 @@ function extractTaskAllTypesAggregates(sources) {
15051
16704
  const ids = [];
15052
16705
  for (const el of arr.getElements()) {
15053
16706
  const inner = unwrapAsExpressions(el);
15054
- if (inner && Node10.isIdentifier(inner)) {
16707
+ if (inner && Node11.isIdentifier(inner)) {
15055
16708
  ids.push(inner.getText());
15056
16709
  }
15057
16710
  }
@@ -15079,14 +16732,14 @@ function extractTaskCheckpointAliases(sources) {
15079
16732
  return out;
15080
16733
  }
15081
16734
  function collectStringLiterals(node, out) {
15082
- if (Node10.isLiteralTypeNode(node)) {
16735
+ if (Node11.isLiteralTypeNode(node)) {
15083
16736
  const lit = node.getLiteral();
15084
- if (Node10.isStringLiteral(lit)) {
16737
+ if (Node11.isStringLiteral(lit)) {
15085
16738
  out.push(lit.getLiteralText());
15086
16739
  }
15087
16740
  return;
15088
16741
  }
15089
- if (Node10.isUnionTypeNode(node)) {
16742
+ if (Node11.isUnionTypeNode(node)) {
15090
16743
  for (const child of node.getTypeNodes()) {
15091
16744
  collectStringLiterals(child, out);
15092
16745
  }
@@ -15140,7 +16793,7 @@ function extractTemplateInfoRecord(sources, index) {
15140
16793
  }
15141
16794
  function tryReadTemplateInfoRecord(decl, rel, index) {
15142
16795
  const initializer = unwrapAsExpressions(decl.getInitializer());
15143
- if (!initializer || !Node10.isCallExpression(initializer)) return void 0;
16796
+ if (!initializer || !Node11.isCallExpression(initializer)) return void 0;
15144
16797
  if (initializer.getExpression().getText() !== TEMPLATE_INFO_RECORD_FACTORY) return void 0;
15145
16798
  const args = initializer.getArguments();
15146
16799
  const arr = args[0] ? asArrayLiteral(args[0]) : void 0;
@@ -15161,15 +16814,15 @@ function tryReadTemplateInfoRecord(decl, rel, index) {
15161
16814
  }
15162
16815
  function classifyInfoRecordArrayElements(arr, direct, spreads) {
15163
16816
  for (const el of arr.getElements()) {
15164
- if (Node10.isSpreadElement(el)) {
16817
+ if (Node11.isSpreadElement(el)) {
15165
16818
  const inner2 = el.getExpression();
15166
- if (Node10.isIdentifier(inner2)) {
16819
+ if (Node11.isIdentifier(inner2)) {
15167
16820
  spreads.push(inner2.getText());
15168
16821
  }
15169
16822
  continue;
15170
16823
  }
15171
16824
  const inner = unwrapAsExpressions(el);
15172
- if (inner && Node10.isIdentifier(inner)) {
16825
+ if (inner && Node11.isIdentifier(inner)) {
15173
16826
  direct.push(inner.getText());
15174
16827
  }
15175
16828
  }
@@ -15190,13 +16843,13 @@ function resolveTemplateInfoSpreads(direct, spreads, index) {
15190
16843
  function extractTemplateInfoRecordWiring(sources) {
15191
16844
  for (const sf of sources) {
15192
16845
  const rel = apiRelPath(sf);
15193
- for (const call of sf.getDescendantsOfKind(SyntaxKind7.CallExpression)) {
16846
+ for (const call of sf.getDescendantsOfKind(SyntaxKind8.CallExpression)) {
15194
16847
  if (call.getExpression().getText() !== TEMPLATE_INFO_RECORD_SERVICE) continue;
15195
16848
  const args = call.getArguments();
15196
16849
  const first = args[0];
15197
16850
  if (!first) continue;
15198
16851
  const inner = unwrapAsExpressions(first);
15199
- if (!inner || !Node10.isIdentifier(inner)) continue;
16852
+ if (!inner || !Node11.isIdentifier(inner)) continue;
15200
16853
  const result = {
15201
16854
  recordIdentifier: inner.getText(),
15202
16855
  sourceFile: rel
@@ -15209,7 +16862,7 @@ function extractTemplateInfoRecordWiring(sources) {
15209
16862
  function extractTemplateConfigsArrayWiring(sources) {
15210
16863
  for (const sf of sources) {
15211
16864
  const rel = apiRelPath(sf);
15212
- for (const obj of sf.getDescendantsOfKind(SyntaxKind7.ObjectLiteralExpression)) {
16865
+ for (const obj of sf.getDescendantsOfKind(SyntaxKind8.ObjectLiteralExpression)) {
15213
16866
  const provideIdent = readIdentifierProperty(obj, "provide");
15214
16867
  if (provideIdent !== TEMPLATE_CONFIGS_ARRAY_TOKEN) continue;
15215
16868
  const useFactoryIdent = readIdentifierProperty(obj, "useFactory");
@@ -15234,7 +16887,7 @@ function buildApiFunctionIndex2(sources) {
15234
16887
  for (const decl of stmt.getDeclarations()) {
15235
16888
  const initializer = unwrapAsExpressions(decl.getInitializer());
15236
16889
  if (!initializer) continue;
15237
- if (Node10.isArrowFunction(initializer) || Node10.isFunctionExpression(initializer)) {
16890
+ if (Node11.isArrowFunction(initializer) || Node11.isFunctionExpression(initializer)) {
15238
16891
  map.set(decl.getName(), { node: initializer, sourceFile: sf, relPath: rel });
15239
16892
  }
15240
16893
  }
@@ -15270,11 +16923,11 @@ function extractTemplateConfigsArrayFactory(sources, index) {
15270
16923
  const arr = returnExpr ? asArrayLiteral(returnExpr) : void 0;
15271
16924
  if (arr) {
15272
16925
  for (const el of arr.getElements()) {
15273
- if (Node10.isSpreadElement(el)) {
16926
+ if (Node11.isSpreadElement(el)) {
15274
16927
  const inner2 = el.getExpression();
15275
- if (Node10.isCallExpression(inner2)) {
16928
+ if (Node11.isCallExpression(inner2)) {
15276
16929
  const callee = inner2.getExpression();
15277
- if (Node10.isIdentifier(callee)) {
16930
+ if (Node11.isIdentifier(callee)) {
15278
16931
  const callName = callee.getText();
15279
16932
  spreadCalls.push(callName);
15280
16933
  if (!index.functionsByName.has(callName)) {
@@ -15285,9 +16938,9 @@ function extractTemplateConfigsArrayFactory(sources, index) {
15285
16938
  continue;
15286
16939
  }
15287
16940
  const inner = unwrapAsExpressions(el);
15288
- if (inner && Node10.isCallExpression(inner)) {
16941
+ if (inner && Node11.isCallExpression(inner)) {
15289
16942
  const callee = inner.getExpression();
15290
- if (Node10.isIdentifier(callee)) {
16943
+ if (Node11.isIdentifier(callee)) {
15291
16944
  directCalls.push(callee.getText());
15292
16945
  }
15293
16946
  }
@@ -15336,11 +16989,11 @@ function collectFromArrayEntryFactory(name, out, index) {
15336
16989
  const arr = asArrayLiteral(returnExpr);
15337
16990
  if (!arr) return;
15338
16991
  for (const el of arr.getElements()) {
15339
- if (Node10.isSpreadElement(el)) {
16992
+ if (Node11.isSpreadElement(el)) {
15340
16993
  const inner2 = el.getExpression();
15341
- if (Node10.isCallExpression(inner2)) {
16994
+ if (Node11.isCallExpression(inner2)) {
15342
16995
  const callee = inner2.getExpression();
15343
- if (Node10.isIdentifier(callee)) {
16996
+ if (Node11.isIdentifier(callee)) {
15344
16997
  collectFromArrayEntryFactory(callee.getText(), out, index);
15345
16998
  }
15346
16999
  }
@@ -15348,9 +17001,9 @@ function collectFromArrayEntryFactory(name, out, index) {
15348
17001
  }
15349
17002
  const inner = unwrapAsExpressions(el);
15350
17003
  if (!inner) continue;
15351
- if (Node10.isCallExpression(inner)) {
17004
+ if (Node11.isCallExpression(inner)) {
15352
17005
  const callee = inner.getExpression();
15353
- if (Node10.isIdentifier(callee)) {
17006
+ if (Node11.isIdentifier(callee)) {
15354
17007
  collectFromSingleEntryFactory(callee.getText(), out, index);
15355
17008
  }
15356
17009
  continue;
@@ -15368,9 +17021,9 @@ function extractTaskServiceCalls(sources, index, trustedExternal) {
15368
17021
  const out = [];
15369
17022
  for (const sf of sources) {
15370
17023
  const rel = apiRelPath(sf);
15371
- for (const call of sf.getDescendantsOfKind(SyntaxKind7.CallExpression)) {
17024
+ for (const call of sf.getDescendantsOfKind(SyntaxKind8.CallExpression)) {
15372
17025
  const expr = call.getExpression();
15373
- if (!Node10.isIdentifier(expr) || expr.getText() !== TASK_SERVICE_FACTORY) continue;
17026
+ if (!Node11.isIdentifier(expr) || expr.getText() !== TASK_SERVICE_FACTORY) continue;
15374
17027
  const args = call.getArguments();
15375
17028
  const first = args[0] ? asObjectLiteral(args[0]) : void 0;
15376
17029
  if (!first) continue;
@@ -15396,13 +17049,13 @@ function collectValidateArrayElements(validateArr) {
15396
17049
  const spreads = [];
15397
17050
  if (!validateArr) return { ids, spreads };
15398
17051
  for (const el of validateArr.getElements()) {
15399
- if (Node10.isSpreadElement(el)) {
17052
+ if (Node11.isSpreadElement(el)) {
15400
17053
  const inner2 = el.getExpression();
15401
- if (Node10.isIdentifier(inner2)) spreads.push(inner2.getText());
17054
+ if (Node11.isIdentifier(inner2)) spreads.push(inner2.getText());
15402
17055
  continue;
15403
17056
  }
15404
17057
  const inner = unwrapAsExpressions(el);
15405
- if (inner && Node10.isIdentifier(inner)) ids.push(inner.getText());
17058
+ if (inner && Node11.isIdentifier(inner)) ids.push(inner.getText());
15406
17059
  }
15407
17060
  return { ids, spreads };
15408
17061
  }
@@ -15415,17 +17068,17 @@ function collectHandlersArrayElements(options) {
15415
17068
  if (!handlersArr) return { handlerTypes, unresolvedSpreads, resolvedBindings, unresolvedBindings };
15416
17069
  const visited = /* @__PURE__ */ new Set();
15417
17070
  for (const el of handlersArr.getElements()) {
15418
- if (Node10.isSpreadElement(el)) {
17071
+ if (Node11.isSpreadElement(el)) {
15419
17072
  consumeHandlersSpreadElement({ inner: el.getExpression(), sf, index, trustedExternal, unresolvedSpreads, resolvedBindings, unresolvedBindings, visited });
15420
17073
  continue;
15421
17074
  }
15422
17075
  const inner = unwrapAsExpressions(el);
15423
17076
  if (!inner) continue;
15424
- if (Node10.isIdentifier(inner)) {
17077
+ if (Node11.isIdentifier(inner)) {
15425
17078
  collectHandlerBindingsFromIdentifier({ name: inner.getText(), sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
15426
- } else if (Node10.isCallExpression(inner)) {
17079
+ } else if (Node11.isCallExpression(inner)) {
15427
17080
  const callee = inner.getExpression();
15428
- if (Node10.isIdentifier(callee)) {
17081
+ if (Node11.isIdentifier(callee)) {
15429
17082
  collectHandlerBindingsFromIdentifier({ name: callee.getText(), sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
15430
17083
  }
15431
17084
  }
@@ -15434,16 +17087,16 @@ function collectHandlersArrayElements(options) {
15434
17087
  }
15435
17088
  function consumeHandlersSpreadElement(options) {
15436
17089
  const { inner, sf, index, trustedExternal, unresolvedSpreads, resolvedBindings, unresolvedBindings, visited } = options;
15437
- if (Node10.isCallExpression(inner)) {
17090
+ if (Node11.isCallExpression(inner)) {
15438
17091
  const callee = inner.getExpression();
15439
- if (Node10.isIdentifier(callee)) {
17092
+ if (Node11.isIdentifier(callee)) {
15440
17093
  const name = callee.getText();
15441
17094
  unresolvedSpreads.push(name);
15442
17095
  collectHandlerBindingsFromIdentifier({ name, sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
15443
17096
  }
15444
17097
  return;
15445
17098
  }
15446
- if (Node10.isIdentifier(inner)) {
17099
+ if (Node11.isIdentifier(inner)) {
15447
17100
  const name = inner.getText();
15448
17101
  unresolvedSpreads.push(name);
15449
17102
  collectHandlerBindingsFromIdentifier({ name, sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
@@ -15453,13 +17106,13 @@ function collectHandlerBindingsFromValue(options) {
15453
17106
  const { node, sf, index, trustedExternal, resolved, unresolved, visited } = options;
15454
17107
  const inner = unwrapAsExpressions(node);
15455
17108
  if (!inner) return false;
15456
- if (Node10.isCallExpression(inner)) {
17109
+ if (Node11.isCallExpression(inner)) {
15457
17110
  const callee = inner.getExpression();
15458
- if (Node10.isIdentifier(callee)) {
17111
+ if (Node11.isIdentifier(callee)) {
15459
17112
  return collectHandlerBindingsFromIdentifier({ name: callee.getText(), sf, index, trustedExternal, resolved, unresolved, visited });
15460
17113
  }
15461
17114
  }
15462
- if (Node10.isIdentifier(inner)) {
17115
+ if (Node11.isIdentifier(inner)) {
15463
17116
  return collectHandlerBindingsFromIdentifier({ name: inner.getText(), sf, index, trustedExternal, resolved, unresolved, visited });
15464
17117
  }
15465
17118
  return false;
@@ -15476,7 +17129,7 @@ function collectHandlerBindingsFromIdentifier(options) {
15476
17129
  const typeText = typeNode ? typeNode.getText() : void 0;
15477
17130
  const isHandlerConfigTyped = typeText !== void 0 && (typeText === NOTIF_TASK_SERVICE_HANDLER_CONFIG || typeText.startsWith(`${NOTIF_TASK_SERVICE_HANDLER_CONFIG}<`));
15478
17131
  const declInit = unwrapAsExpressions(localDecl.getInitializer());
15479
- const isObjectLit = declInit !== void 0 && Node10.isObjectLiteralExpression(declInit);
17132
+ const isObjectLit = declInit !== void 0 && Node11.isObjectLiteralExpression(declInit);
15480
17133
  if (isHandlerConfigTyped && isObjectLit) {
15481
17134
  resolved.push(localDecl.getName());
15482
17135
  resolvedAny = true;
@@ -15507,12 +17160,12 @@ function collectHandlerBindingsFromIdentifier(options) {
15507
17160
  function resolveArrayFromProperty2(obj, name, sf) {
15508
17161
  const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
15509
17162
  if (!init) return void 0;
15510
- if (Node10.isArrayLiteralExpression(init)) return init;
15511
- if (Node10.isIdentifier(init)) {
17163
+ if (Node11.isArrayLiteralExpression(init)) return init;
17164
+ if (Node11.isIdentifier(init)) {
15512
17165
  const declNode = findLocalVariable(sf, init.getText());
15513
17166
  if (declNode) {
15514
17167
  const declInit = unwrapAsExpressions(declNode.getInitializer());
15515
- if (declInit && Node10.isArrayLiteralExpression(declInit)) {
17168
+ if (declInit && Node11.isArrayLiteralExpression(declInit)) {
15516
17169
  return declInit;
15517
17170
  }
15518
17171
  }
@@ -15533,12 +17186,12 @@ function extractTaskHandlerEntries(sources) {
15533
17186
  if (!typeIdent) return;
15534
17187
  const flowInit = unwrapAsExpressions(getPropertyInitializer(obj, "flow"));
15535
17188
  let flowCount;
15536
- if (flowInit && Node10.isArrayLiteralExpression(flowInit)) {
17189
+ if (flowInit && Node11.isArrayLiteralExpression(flowInit)) {
15537
17190
  flowCount = flowInit.getElements().length;
15538
17191
  }
15539
17192
  let dataArg;
15540
17193
  let checkpointArg;
15541
- if (Node10.isTypeReference(typeNode)) {
17194
+ if (Node11.isTypeReference(typeNode)) {
15542
17195
  const tArgs = typeNode.getTypeArguments();
15543
17196
  if (tArgs.length >= 1) dataArg = tArgs[0].getText();
15544
17197
  if (tArgs.length >= 2) checkpointArg = tArgs[1].getText();
@@ -15558,7 +17211,7 @@ function extractTaskHandlerEntries(sources) {
15558
17211
  };
15559
17212
  for (const sf of sources) {
15560
17213
  const rel = apiRelPath(sf);
15561
- for (const decl of sf.getDescendantsOfKind(SyntaxKind7.VariableDeclaration)) {
17214
+ for (const decl of sf.getDescendantsOfKind(SyntaxKind8.VariableDeclaration)) {
15562
17215
  collectFromVariable(decl, rel);
15563
17216
  }
15564
17217
  }
@@ -15583,7 +17236,7 @@ function runRules6(inspection, extracted) {
15583
17236
  violations,
15584
17237
  codes: IO_VIOLATION_CODES2,
15585
17238
  messages: IO_VIOLATION_MESSAGES2,
15586
- build: (code10, message, side) => buildIoViolation2(code10, message, side)
17239
+ build: (code11, message, side) => buildIoViolation2(code11, message, side)
15587
17240
  });
15588
17241
  if (!proceed) {
15589
17242
  return violations;
@@ -15936,14 +17589,14 @@ function flagUnusedInfoAggregates(extracted, violations) {
15936
17589
  }
15937
17590
  }
15938
17591
  }
15939
- function flagDuplicates2(entries, code10, violations) {
17592
+ function flagDuplicates2(entries, code11, violations) {
15940
17593
  const seen = /* @__PURE__ */ new Map();
15941
17594
  for (const entry of entries) {
15942
17595
  if (!entry.typeCode) continue;
15943
17596
  const previous = seen.get(entry.typeCode);
15944
17597
  if (previous) {
15945
17598
  pushViolation6(violations, {
15946
- code: code10,
17599
+ code: code11,
15947
17600
  severity: "warning",
15948
17601
  message: `Type code \`'${entry.typeCode}'\` is shared by \`${previous}\` and \`${entry.symbolName}\`. Runtime aggregators reject duplicates \u2014 change one of the string literals.`,
15949
17602
  side: "component",
@@ -15977,9 +17630,9 @@ function pushViolation6(buffer, violation) {
15977
17630
  };
15978
17631
  buffer.push(filled);
15979
17632
  }
15980
- function buildIoViolation2(code10, message, side) {
17633
+ function buildIoViolation2(code11, message, side) {
15981
17634
  const result = {
15982
- code: code10,
17635
+ code: code11,
15983
17636
  severity: "error",
15984
17637
  message,
15985
17638
  side,
@@ -16179,8 +17832,8 @@ function formatReportAsJson2(report) {
16179
17832
  // packages/dbx-components-mcp/src/tools/notification-m-list-app/format.markdown.ts
16180
17833
  function formatReportAsMarkdown2(report) {
16181
17834
  const basename4 = report.componentDir.split("/").pop() ?? report.componentDir;
16182
- const aggregatorRecordText = report.aggregatorRecordName ? code4(report.aggregatorRecordName) : "_Not defined._";
16183
- 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._";
16184
17837
  const lines = [
16185
17838
  `# App notifications \u2014 ${basename4}`,
16186
17839
  "",
@@ -16220,8 +17873,8 @@ function formatTemplateBlock(t) {
16220
17873
  if (t.description) parts.push(`- Description: ${t.description}`);
16221
17874
  if (t.notificationMIdentity) parts.push(`- Notification model: \`${t.notificationMIdentity}\``);
16222
17875
  if (t.targetModelIdentity) parts.push(`- Target model: \`${t.targetModelIdentity}\``);
16223
- const infoText = t.infoSymbolName ? code4(t.infoSymbolName) : "_Missing._";
16224
- const factorySuffix = t.factoryFunctionName ? ` (${code4(t.factoryFunctionName)})` : "";
17876
+ const infoText = t.infoSymbolName ? code5(t.infoSymbolName) : "_Missing._";
17877
+ const factorySuffix = t.factoryFunctionName ? ` (${code5(t.factoryFunctionName)})` : "";
16225
17878
  parts.push(`- Info object: ${infoText}`, `- In info record: ${formatBool2(t.inInfoRecord)}`, `- Has factory: ${formatBool2(t.hasFactory)}${factorySuffix}`, `- Source: \`${t.sourceFile}\``);
16226
17879
  return parts.join("\n");
16227
17880
  }
@@ -16231,7 +17884,7 @@ function formatTaskBlock(t) {
16231
17884
  parts.push(heading);
16232
17885
  if (t.dataInterfaceName) parts.push(`- Data interface: \`${t.dataInterfaceName}\``);
16233
17886
  if (t.checkpoints.length > 0) {
16234
- const checkpointsText = t.checkpoints.map((c) => code4(c)).join(", ");
17887
+ const checkpointsText = t.checkpoints.map((c) => code5(c)).join(", ");
16235
17888
  parts.push(`- Checkpoints: ${checkpointsText}`);
16236
17889
  }
16237
17890
  let handlerSuffix = "";
@@ -16245,7 +17898,7 @@ function formatTaskBlock(t) {
16245
17898
  function formatBool2(value) {
16246
17899
  return value ? "yes" : "no";
16247
17900
  }
16248
- function code4(value) {
17901
+ function code5(value) {
16249
17902
  return "`" + value + "`";
16250
17903
  }
16251
17904
 
@@ -16387,8 +18040,8 @@ function formatResult8(result) {
16387
18040
  }
16388
18041
 
16389
18042
  // packages/dbx-components-mcp/src/tools/system-m-validate-folder/inspect.ts
16390
- import { readdir as readdir4, readFile as readFile4, stat as stat5 } from "node:fs/promises";
16391
- 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";
16392
18045
  async function inspectFolder2(path) {
16393
18046
  const name = basename3(path);
16394
18047
  let status;
@@ -16408,7 +18061,7 @@ async function inspectFolder2(path) {
16408
18061
  files = collected;
16409
18062
  if (collected.includes("system.ts")) {
16410
18063
  try {
16411
- systemSource = await readFile4(join3(path, "system.ts"), "utf8");
18064
+ systemSource = await readFile6(join6(path, "system.ts"), "utf8");
16412
18065
  } catch {
16413
18066
  systemSource = void 0;
16414
18067
  }
@@ -16417,8 +18070,8 @@ async function inspectFolder2(path) {
16417
18070
  status = "not-directory";
16418
18071
  }
16419
18072
  } catch (err) {
16420
- const code10 = err.code;
16421
- if (code10 === "ENOENT" || code10 === "ENOTDIR") {
18073
+ const code11 = err.code;
18074
+ if (code11 === "ENOENT" || code11 === "ENOTDIR") {
16422
18075
  status = "not-found";
16423
18076
  } else {
16424
18077
  throw err;
@@ -16429,14 +18082,14 @@ async function inspectFolder2(path) {
16429
18082
  }
16430
18083
 
16431
18084
  // packages/dbx-components-mcp/src/tools/system-m-validate-folder/extract.ts
16432
- import { Node as Node11, Project as Project7 } from "ts-morph";
18085
+ import { Node as Node12, Project as Project9 } from "ts-morph";
16433
18086
  var TYPE_CONSTANT_SUFFIX = "_SYSTEM_STATE_TYPE";
16434
18087
  var DATA_INTERFACE_SUFFIX = "SystemData";
16435
18088
  var CONVERTER_CONFIG_TYPE = "SystemStateStoredDataFieldConverterConfig";
16436
18089
  var CONVERTER_MAP_TYPE = "SystemStateStoredDataConverterMap";
16437
18090
  var SYSTEM_STATE_STORED_DATA = "SystemStateStoredData";
16438
18091
  function extractSystemFile(name, text) {
16439
- const project = new Project7({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
18092
+ const project = new Project9({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
16440
18093
  const sourceFile = project.createSourceFile(name, text, { overwrite: true });
16441
18094
  const typeConstants = findTypeConstants(sourceFile);
16442
18095
  const dataInterfaces = findDataInterfaces2(sourceFile);
@@ -16493,7 +18146,7 @@ function findDataInterfaces2(sourceFile) {
16493
18146
  return out;
16494
18147
  }
16495
18148
  function extendsSystemStateStoredData(iface) {
16496
- if (!Node11.isInterfaceDeclaration(iface)) return false;
18149
+ if (!Node12.isInterfaceDeclaration(iface)) return false;
16497
18150
  for (const clause of iface.getExtends()) {
16498
18151
  const text = clause.getText();
16499
18152
  if (text === SYSTEM_STATE_STORED_DATA || text.startsWith(`${SYSTEM_STATE_STORED_DATA}<`) || text === `${SYSTEM_STATE_STORED_DATA}, ${SYSTEM_STATE_STORED_DATA}`) {
@@ -16513,14 +18166,14 @@ function findConverters(sourceFile) {
16513
18166
  for (const decl of stmt.getDeclarations()) {
16514
18167
  const typeNode = decl.getTypeNode();
16515
18168
  if (!typeNode) continue;
16516
- if (!Node11.isTypeReference(typeNode)) continue;
18169
+ if (!Node12.isTypeReference(typeNode)) continue;
16517
18170
  const typeName = typeNode.getTypeName().getText();
16518
18171
  if (typeName !== CONVERTER_CONFIG_TYPE) continue;
16519
18172
  const typeArgs = typeNode.getTypeArguments();
16520
18173
  let dataTypeArgument;
16521
18174
  if (typeArgs.length >= 1) {
16522
18175
  const arg = typeArgs[0];
16523
- if (Node11.isTypeReference(arg)) {
18176
+ if (Node12.isTypeReference(arg)) {
16524
18177
  dataTypeArgument = arg.getTypeName().getText();
16525
18178
  } else {
16526
18179
  dataTypeArgument = arg.getText();
@@ -16567,19 +18220,19 @@ function collectConverterMapKeys(decl) {
16567
18220
  if (!obj) return [];
16568
18221
  const out = [];
16569
18222
  for (const prop of obj.getProperties()) {
16570
- if (!Node11.isPropertyAssignment(prop)) continue;
18223
+ if (!Node12.isPropertyAssignment(prop)) continue;
16571
18224
  const nameNode = prop.getNameNode();
16572
18225
  const line = prop.getStartLineNumber();
16573
- if (Node11.isComputedPropertyName(nameNode)) {
18226
+ if (Node12.isComputedPropertyName(nameNode)) {
16574
18227
  const inner = nameNode.getExpression();
16575
18228
  out.push({ raw: inner.getText(), kind: "identifier", line });
16576
18229
  continue;
16577
18230
  }
16578
- if (Node11.isStringLiteral(nameNode)) {
18231
+ if (Node12.isStringLiteral(nameNode)) {
16579
18232
  out.push({ raw: nameNode.getLiteralText(), kind: "string", line });
16580
18233
  continue;
16581
18234
  }
16582
- if (Node11.isIdentifier(nameNode)) {
18235
+ if (Node12.isIdentifier(nameNode)) {
16583
18236
  out.push({ raw: nameNode.getText(), kind: "string", line });
16584
18237
  continue;
16585
18238
  }
@@ -16589,10 +18242,10 @@ function collectConverterMapKeys(decl) {
16589
18242
  }
16590
18243
  function unwrapObjectLiteral(node) {
16591
18244
  let current = node;
16592
- while (current && Node11.isAsExpression(current)) {
18245
+ while (current && Node12.isAsExpression(current)) {
16593
18246
  current = current.getExpression();
16594
18247
  }
16595
- if (current && Node11.isObjectLiteralExpression(current)) {
18248
+ if (current && Node12.isObjectLiteralExpression(current)) {
16596
18249
  return current;
16597
18250
  }
16598
18251
  return void 0;
@@ -16626,10 +18279,10 @@ function findLastTopLevelExportLine(sourceFile) {
16626
18279
  return last;
16627
18280
  }
16628
18281
  function isExportedTopLevel(stmt) {
16629
- 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)) {
16630
18283
  return stmt.isExported();
16631
18284
  }
16632
- if (Node11.isExportDeclaration(stmt) || Node11.isExportAssignment(stmt)) {
18285
+ if (Node12.isExportDeclaration(stmt) || Node12.isExportAssignment(stmt)) {
16633
18286
  return true;
16634
18287
  }
16635
18288
  return false;
@@ -16939,7 +18592,7 @@ var systemMValidateFolderTool = createFolderValidateTool({
16939
18592
  });
16940
18593
 
16941
18594
  // packages/dbx-components-mcp/src/tools/lookup-action.tool.ts
16942
- import { type as type31 } from "arktype";
18595
+ import { type as type36 } from "arktype";
16943
18596
  var DBX_ACTION_LOOKUP_TOOL = {
16944
18597
  name: "dbx_action_lookup",
16945
18598
  description: [
@@ -16972,13 +18625,13 @@ var DBX_ACTION_LOOKUP_TOOL = {
16972
18625
  required: ["topic"]
16973
18626
  }
16974
18627
  };
16975
- var LookupActionArgsType = type31({
18628
+ var LookupActionArgsType = type36({
16976
18629
  topic: "string",
16977
18630
  "depth?": "'brief' | 'full'"
16978
18631
  });
16979
18632
  function parseLookupActionArgs(raw) {
16980
18633
  const parsed = LookupActionArgsType(raw);
16981
- if (parsed instanceof type31.errors) {
18634
+ if (parsed instanceof type36.errors) {
16982
18635
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
16983
18636
  }
16984
18637
  const result = {
@@ -17102,7 +18755,7 @@ function formatDirectiveEntry(entry, depth) {
17102
18755
  }
17103
18756
  lines.push("## State interaction", "", formatStateInteraction(entry), "", "## Example", "", "```html", entry.example, "```");
17104
18757
  if (entry.skillRefs.length > 0) {
17105
- const skillsText = entry.skillRefs.map((s) => code5(s)).join(", ");
18758
+ const skillsText = entry.skillRefs.map((s) => code6(s)).join(", ");
17106
18759
  lines.push("", `\u2192 Skills: ${skillsText}`);
17107
18760
  }
17108
18761
  } else {
@@ -17136,7 +18789,7 @@ function formatStoreEntry(entry, depth) {
17136
18789
  }
17137
18790
  lines.push("## Example", "", "```ts", entry.example, "```");
17138
18791
  if (entry.skillRefs.length > 0) {
17139
- const skillsText = entry.skillRefs.map((s) => code5(s)).join(", ");
18792
+ const skillsText = entry.skillRefs.map((s) => code6(s)).join(", ");
17140
18793
  lines.push("", `\u2192 Skills: ${skillsText}`);
17141
18794
  }
17142
18795
  } else {
@@ -17161,7 +18814,7 @@ function formatStateDiagram(entry) {
17161
18814
  function formatStateEntry(entry, depth) {
17162
18815
  const lines = [`# DbxActionState.${entry.stateValue}`, "", entry.description, "", bullet("enum value", `\`'${entry.literal}'\``), bullet("slug", `\`${entry.slug}\``), "", "## Transitions", "", "```", formatStateDiagram(entry), "```"];
17163
18816
  if (depth === "full" && entry.skillRefs.length > 0) {
17164
- const skillsText = entry.skillRefs.map((s) => code5(s)).join(", ");
18817
+ const skillsText = entry.skillRefs.map((s) => code6(s)).join(", ");
17165
18818
  lines.push("", `\u2192 Skills: ${skillsText}`);
17166
18819
  }
17167
18820
  return lines.join("\n");
@@ -17240,12 +18893,12 @@ function formatNotFound6(normalized, candidates) {
17240
18893
  }
17241
18894
  return lines.join("\n");
17242
18895
  }
17243
- function code5(value) {
18896
+ function code6(value) {
17244
18897
  return "`" + value + "`";
17245
18898
  }
17246
18899
  function createLookupActionTool(input) {
17247
18900
  const { registry } = input;
17248
- const run = (rawArgs) => {
18901
+ const run5 = (rawArgs) => {
17249
18902
  let args;
17250
18903
  try {
17251
18904
  args = parseLookupActionArgs(rawArgs);
@@ -17272,11 +18925,11 @@ function createLookupActionTool(input) {
17272
18925
  const result = { content: [{ type: "text", text }] };
17273
18926
  return result;
17274
18927
  };
17275
- return { definition: DBX_ACTION_LOOKUP_TOOL, run };
18928
+ return { definition: DBX_ACTION_LOOKUP_TOOL, run: run5 };
17276
18929
  }
17277
18930
 
17278
18931
  // packages/dbx-components-mcp/src/tools/action-examples.tool.ts
17279
- import { type as type32 } from "arktype";
18932
+ import { type as type37 } from "arktype";
17280
18933
 
17281
18934
  // packages/dbx-components-mcp/src/tools/data/patterns/actions/action.auto-trigger-on-modify.pattern.ts
17282
18935
  var ACTION_PATTERN_AUTO_TRIGGER_ON_MODIFY = {
@@ -17636,13 +19289,13 @@ var DBX_ACTION_EXAMPLES_TOOL = {
17636
19289
  required: ["pattern"]
17637
19290
  }
17638
19291
  };
17639
- var ActionExamplesArgsType = type32({
19292
+ var ActionExamplesArgsType = type37({
17640
19293
  pattern: "string",
17641
19294
  "depth?": "'minimal' | 'brief' | 'full'"
17642
19295
  });
17643
19296
  function parseActionExamplesArgs(raw) {
17644
19297
  const parsed = ActionExamplesArgsType(raw);
17645
- if (parsed instanceof type32.errors) {
19298
+ if (parsed instanceof type37.errors) {
17646
19299
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
17647
19300
  }
17648
19301
  const result = {
@@ -17654,7 +19307,7 @@ function parseActionExamplesArgs(raw) {
17654
19307
  function formatPatternCatalog3() {
17655
19308
  const lines = [`# Action example patterns (${ACTION_EXAMPLE_PATTERNS.length})`, "", 'Call `dbx_action_examples pattern="<slug>"` for a full example.', ""];
17656
19309
  for (const pattern of ACTION_EXAMPLE_PATTERNS) {
17657
- const usesText = pattern.usesActionSlugs.map((s) => code6(s)).join(", ");
19310
+ const usesText = pattern.usesActionSlugs.map((s) => code7(s)).join(", ");
17658
19311
  lines.push(`## ${pattern.name}`, "", `- **slug:** \`${pattern.slug}\``, `- **summary:** ${pattern.summary}`, `- **uses:** ${usesText}`, "");
17659
19312
  }
17660
19313
  return lines.join("\n").trimEnd();
@@ -17662,7 +19315,7 @@ function formatPatternCatalog3() {
17662
19315
  function formatPattern3(pattern, depth) {
17663
19316
  const snippet = pattern.snippets[depth];
17664
19317
  const fence = depth === "full" ? "ts" : "html";
17665
- const usesText = pattern.usesActionSlugs.map((s) => code6(s)).join(", ");
19318
+ const usesText = pattern.usesActionSlugs.map((s) => code7(s)).join(", ");
17666
19319
  const sections = [`# ${pattern.name}`, "", pattern.summary, "", `**slug:** \`${pattern.slug}\` \xB7 **depth:** \`${depth}\` \xB7 **uses:** ${usesText}`, "", "```" + fence, snippet, "```"];
17667
19320
  if (pattern.notes && depth === "full") {
17668
19321
  sections.push("", "## Notes", "", pattern.notes);
@@ -17673,10 +19326,10 @@ function formatPattern3(pattern, depth) {
17673
19326
  return sections.join("\n");
17674
19327
  }
17675
19328
  function formatNotFound7(slug) {
17676
- const available = ACTION_EXAMPLE_PATTERNS.map((p) => code6(p.slug)).join(", ");
19329
+ const available = ACTION_EXAMPLE_PATTERNS.map((p) => code7(p.slug)).join(", ");
17677
19330
  return [`No action example pattern matched \`${slug}\`.`, "", `Available patterns: ${available}.`, "", 'Call `dbx_action_examples pattern="list"` for summaries.'].join("\n");
17678
19331
  }
17679
- function code6(value) {
19332
+ function code7(value) {
17680
19333
  return "`" + value + "`";
17681
19334
  }
17682
19335
  function runActionExamples(rawArgs) {
@@ -17704,7 +19357,7 @@ var actionExamplesTool = {
17704
19357
  };
17705
19358
 
17706
19359
  // packages/dbx-components-mcp/src/tools/action-scaffold.tool.ts
17707
- import { type as type33 } from "arktype";
19360
+ import { type as type38 } from "arktype";
17708
19361
  var TRIGGER_VALUES = ["button", "form", "auto-modify"];
17709
19362
  var SUCCESS_FEEDBACK_VALUES = ["snackbar", "redirect", "none"];
17710
19363
  var CONTEXT_PROVIDER_VALUES = ["inline", "parent", "host-component"];
@@ -17738,7 +19391,7 @@ var DBX_ACTION_SCAFFOLD_TOOL = {
17738
19391
  required: ["use_case", "trigger", "value_type"]
17739
19392
  }
17740
19393
  };
17741
- var ScaffoldArgsType3 = type33({
19394
+ var ScaffoldArgsType4 = type38({
17742
19395
  use_case: "string",
17743
19396
  trigger: "'button' | 'form' | 'auto-modify'",
17744
19397
  "confirm?": "boolean",
@@ -17748,8 +19401,8 @@ var ScaffoldArgsType3 = type33({
17748
19401
  "result_type?": "string"
17749
19402
  });
17750
19403
  function parseScaffoldArgs2(raw) {
17751
- const parsed = ScaffoldArgsType3(raw);
17752
- if (parsed instanceof type33.errors) {
19404
+ const parsed = ScaffoldArgsType4(raw);
19405
+ if (parsed instanceof type38.errors) {
17753
19406
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
17754
19407
  }
17755
19408
  const useCase = parsed.use_case.trim();
@@ -17955,16 +19608,16 @@ var actionScaffoldTool = {
17955
19608
  };
17956
19609
 
17957
19610
  // packages/dbx-components-mcp/src/tools/route-tree.tool.ts
17958
- import { type as type34 } from "arktype";
19611
+ import { type as type39 } from "arktype";
17959
19612
 
17960
19613
  // packages/dbx-components-mcp/src/tools/route/load-sources.ts
17961
- import { glob as fsGlob3, readFile as readFile5, stat as stat6 } from "node:fs/promises";
17962
- 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";
17963
19616
 
17964
19617
  // packages/dbx-components-mcp/src/tools/route/extract.ts
17965
- 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";
17966
19619
  function extractFile3(source) {
17967
- const project = new Project8({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
19620
+ const project = new Project10({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
17968
19621
  const sourceFile = project.createSourceFile(source.name, source.text, { overwrite: true });
17969
19622
  const issues = [];
17970
19623
  const objectLiteralsByName = collectStateConsts(sourceFile);
@@ -17977,9 +19630,9 @@ function extractFile3(source) {
17977
19630
  }
17978
19631
  for (const arrayLit of findStateArrayLiterals(sourceFile)) {
17979
19632
  for (const element of arrayLit.getElements()) {
17980
- if (Node12.isObjectLiteralExpression(element)) {
19633
+ if (Node13.isObjectLiteralExpression(element)) {
17981
19634
  addNode({ file: source.name, literal: element, fallbackConstName: void 0, into: collected, issues });
17982
- } else if (Node12.isIdentifier(element)) {
19635
+ } else if (Node13.isIdentifier(element)) {
17983
19636
  const ref = objectLiteralsByName.get(element.getText());
17984
19637
  if (ref) {
17985
19638
  addNode({ file: source.name, literal: ref.literal, fallbackConstName: element.getText(), into: collected, issues });
@@ -18000,7 +19653,7 @@ function collectStateConsts(sourceFile) {
18000
19653
  for (const stmt of sourceFile.getVariableStatements()) {
18001
19654
  for (const decl of stmt.getDeclarations()) {
18002
19655
  const initializer = decl.getInitializer();
18003
- if (!initializer || !Node12.isObjectLiteralExpression(initializer)) {
19656
+ if (!initializer || !Node13.isObjectLiteralExpression(initializer)) {
18004
19657
  continue;
18005
19658
  }
18006
19659
  const typeNode = decl.getTypeNode();
@@ -18015,12 +19668,12 @@ function findStateArrayLiterals(sourceFile) {
18015
19668
  for (const stmt of sourceFile.getVariableStatements()) {
18016
19669
  for (const decl of stmt.getDeclarations()) {
18017
19670
  const initializer = decl.getInitializer();
18018
- if (initializer && Node12.isArrayLiteralExpression(initializer) && declarationIsStateArray(stmt, decl.getName(), initializer)) {
19671
+ if (initializer && Node13.isArrayLiteralExpression(initializer) && declarationIsStateArray(stmt, decl.getName(), initializer)) {
18019
19672
  arrays.push(initializer);
18020
19673
  }
18021
19674
  }
18022
19675
  }
18023
- for (const call of sourceFile.getDescendantsOfKind(SyntaxKind8.CallExpression)) {
19676
+ for (const call of sourceFile.getDescendantsOfKind(SyntaxKind9.CallExpression)) {
18024
19677
  const expr = call.getExpression();
18025
19678
  const exprText = expr.getText();
18026
19679
  const isProvide = exprText === "provideStates";
@@ -18029,17 +19682,17 @@ function findStateArrayLiterals(sourceFile) {
18029
19682
  continue;
18030
19683
  }
18031
19684
  for (const arg of call.getArguments()) {
18032
- if (!Node12.isObjectLiteralExpression(arg)) {
19685
+ if (!Node13.isObjectLiteralExpression(arg)) {
18033
19686
  continue;
18034
19687
  }
18035
19688
  const statesProp = arg.getProperty("states");
18036
- if (!statesProp || !Node12.isPropertyAssignment(statesProp)) {
19689
+ if (!statesProp || !Node13.isPropertyAssignment(statesProp)) {
18037
19690
  continue;
18038
19691
  }
18039
19692
  const initializer = statesProp.getInitializer();
18040
- if (initializer && Node12.isArrayLiteralExpression(initializer)) {
19693
+ if (initializer && Node13.isArrayLiteralExpression(initializer)) {
18041
19694
  arrays.push(initializer);
18042
- } else if (initializer && Node12.isIdentifier(initializer)) {
19695
+ } else if (initializer && Node13.isIdentifier(initializer)) {
18043
19696
  const referenced = findArrayLiteralForIdentifier(sourceFile, initializer);
18044
19697
  if (referenced) {
18045
19698
  arrays.push(referenced);
@@ -18056,10 +19709,10 @@ function declarationIsStateArray(stmt, name, literal) {
18056
19709
  return true;
18057
19710
  }
18058
19711
  for (const element of literal.getElements()) {
18059
- if (Node12.isObjectLiteralExpression(element) && hasStringNameProperty(element)) {
19712
+ if (Node13.isObjectLiteralExpression(element) && hasStringNameProperty(element)) {
18060
19713
  return true;
18061
19714
  }
18062
- if (Node12.isIdentifier(element)) {
19715
+ if (Node13.isIdentifier(element)) {
18063
19716
  return true;
18064
19717
  }
18065
19718
  }
@@ -18067,11 +19720,11 @@ function declarationIsStateArray(stmt, name, literal) {
18067
19720
  }
18068
19721
  function hasStringNameProperty(literal) {
18069
19722
  const nameProp = literal.getProperty("name");
18070
- if (!nameProp || !Node12.isPropertyAssignment(nameProp)) {
19723
+ if (!nameProp || !Node13.isPropertyAssignment(nameProp)) {
18071
19724
  return false;
18072
19725
  }
18073
19726
  const initializer = nameProp.getInitializer();
18074
- return initializer !== void 0 && (Node12.isStringLiteral(initializer) || Node12.isNoSubstitutionTemplateLiteral(initializer));
19727
+ return initializer !== void 0 && (Node13.isStringLiteral(initializer) || Node13.isNoSubstitutionTemplateLiteral(initializer));
18075
19728
  }
18076
19729
  function findArrayLiteralForIdentifier(sourceFile, identifier) {
18077
19730
  const name = identifier.getText();
@@ -18081,7 +19734,7 @@ function findArrayLiteralForIdentifier(sourceFile, identifier) {
18081
19734
  continue;
18082
19735
  }
18083
19736
  const initializer = decl.getInitializer();
18084
- if (initializer && Node12.isArrayLiteralExpression(initializer)) {
19737
+ if (initializer && Node13.isArrayLiteralExpression(initializer)) {
18085
19738
  return initializer;
18086
19739
  }
18087
19740
  }
@@ -18131,64 +19784,64 @@ function addNode(options) {
18131
19784
  }
18132
19785
  function stringPropertyValue(literal, key) {
18133
19786
  const prop = literal.getProperty(key);
18134
- if (!prop || !Node12.isPropertyAssignment(prop)) {
19787
+ if (!prop || !Node13.isPropertyAssignment(prop)) {
18135
19788
  return void 0;
18136
19789
  }
18137
19790
  const initializer = prop.getInitializer();
18138
19791
  if (!initializer) {
18139
19792
  return void 0;
18140
19793
  }
18141
- if (Node12.isStringLiteral(initializer) || Node12.isNoSubstitutionTemplateLiteral(initializer)) {
19794
+ if (Node13.isStringLiteral(initializer) || Node13.isNoSubstitutionTemplateLiteral(initializer)) {
18142
19795
  return initializer.getLiteralText();
18143
19796
  }
18144
19797
  return void 0;
18145
19798
  }
18146
19799
  function booleanPropertyValue(literal, key) {
18147
19800
  const prop = literal.getProperty(key);
18148
- if (!prop || !Node12.isPropertyAssignment(prop)) {
19801
+ if (!prop || !Node13.isPropertyAssignment(prop)) {
18149
19802
  return void 0;
18150
19803
  }
18151
19804
  const initializer = prop.getInitializer();
18152
19805
  if (!initializer) {
18153
19806
  return void 0;
18154
19807
  }
18155
- if (initializer.getKind() === SyntaxKind8.TrueKeyword) {
19808
+ if (initializer.getKind() === SyntaxKind9.TrueKeyword) {
18156
19809
  return true;
18157
19810
  }
18158
- if (initializer.getKind() === SyntaxKind8.FalseKeyword) {
19811
+ if (initializer.getKind() === SyntaxKind9.FalseKeyword) {
18159
19812
  return false;
18160
19813
  }
18161
19814
  return void 0;
18162
19815
  }
18163
19816
  function identifierPropertyValue(literal, key) {
18164
19817
  const prop = literal.getProperty(key);
18165
- if (!prop || !Node12.isPropertyAssignment(prop)) {
19818
+ if (!prop || !Node13.isPropertyAssignment(prop)) {
18166
19819
  return void 0;
18167
19820
  }
18168
19821
  const initializer = prop.getInitializer();
18169
19822
  if (!initializer) {
18170
19823
  return void 0;
18171
19824
  }
18172
- if (Node12.isIdentifier(initializer)) {
19825
+ if (Node13.isIdentifier(initializer)) {
18173
19826
  return initializer.getText();
18174
19827
  }
18175
- if (Node12.isPropertyAccessExpression(initializer)) {
19828
+ if (Node13.isPropertyAccessExpression(initializer)) {
18176
19829
  return initializer.getText();
18177
19830
  }
18178
19831
  return void 0;
18179
19832
  }
18180
19833
  function objectPropertyKeys(literal, key) {
18181
19834
  const prop = literal.getProperty(key);
18182
- if (!prop || !Node12.isPropertyAssignment(prop)) {
19835
+ if (!prop || !Node13.isPropertyAssignment(prop)) {
18183
19836
  return [];
18184
19837
  }
18185
19838
  const initializer = prop.getInitializer();
18186
- if (!initializer || !Node12.isObjectLiteralExpression(initializer)) {
19839
+ if (!initializer || !Node13.isObjectLiteralExpression(initializer)) {
18187
19840
  return [];
18188
19841
  }
18189
19842
  const out = [];
18190
19843
  for (const member of initializer.getProperties()) {
18191
- if (Node12.isPropertyAssignment(member) || Node12.isShorthandPropertyAssignment(member) || Node12.isMethodDeclaration(member)) {
19844
+ if (Node13.isPropertyAssignment(member) || Node13.isShorthandPropertyAssignment(member) || Node13.isMethodDeclaration(member)) {
18192
19845
  const nameNode = member.getNameNode();
18193
19846
  if (nameNode) {
18194
19847
  out.push(nameNode.getText());
@@ -18199,7 +19852,7 @@ function objectPropertyKeys(literal, key) {
18199
19852
  }
18200
19853
  function collectResolveKeys(literal) {
18201
19854
  const prop = literal.getProperty("resolve");
18202
- if (!prop || !Node12.isPropertyAssignment(prop)) {
19855
+ if (!prop || !Node13.isPropertyAssignment(prop)) {
18203
19856
  return [];
18204
19857
  }
18205
19858
  const initializer = prop.getInitializer();
@@ -18207,22 +19860,22 @@ function collectResolveKeys(literal) {
18207
19860
  return [];
18208
19861
  }
18209
19862
  const keys = [];
18210
- if (Node12.isObjectLiteralExpression(initializer)) {
19863
+ if (Node13.isObjectLiteralExpression(initializer)) {
18211
19864
  for (const member of initializer.getProperties()) {
18212
- if (Node12.isPropertyAssignment(member) || Node12.isShorthandPropertyAssignment(member) || Node12.isMethodDeclaration(member)) {
19865
+ if (Node13.isPropertyAssignment(member) || Node13.isShorthandPropertyAssignment(member) || Node13.isMethodDeclaration(member)) {
18213
19866
  const nameNode = member.getNameNode();
18214
19867
  if (nameNode) {
18215
19868
  keys.push(nameNode.getText());
18216
19869
  }
18217
19870
  }
18218
19871
  }
18219
- } else if (Node12.isArrayLiteralExpression(initializer)) {
19872
+ } else if (Node13.isArrayLiteralExpression(initializer)) {
18220
19873
  for (const element of initializer.getElements()) {
18221
- if (Node12.isObjectLiteralExpression(element)) {
19874
+ if (Node13.isObjectLiteralExpression(element)) {
18222
19875
  const tokenProp = element.getProperty("token");
18223
- if (tokenProp && Node12.isPropertyAssignment(tokenProp)) {
19876
+ if (tokenProp && Node13.isPropertyAssignment(tokenProp)) {
18224
19877
  const tokenInit = tokenProp.getInitializer();
18225
- if (tokenInit && (Node12.isStringLiteral(tokenInit) || Node12.isIdentifier(tokenInit))) {
19878
+ if (tokenInit && (Node13.isStringLiteral(tokenInit) || Node13.isIdentifier(tokenInit))) {
18226
19879
  keys.push(tokenInit.getText().replaceAll(/^['"]|['"]$/g, ""));
18227
19880
  }
18228
19881
  }
@@ -18274,7 +19927,7 @@ function computeRelativeSpecifiers(source) {
18274
19927
  // packages/dbx-components-mcp/src/tools/route/load-sources.ts
18275
19928
  var TRY_EXTENSIONS = [".ts", ".tsx", "/index.ts", "/index.tsx"];
18276
19929
  async function loadRouteSources(args) {
18277
- const cwdResolved = args.cwd ? resolve15(process.cwd(), args.cwd) : process.cwd();
19930
+ const cwdResolved = args.cwd ? resolve20(process.cwd(), args.cwd) : process.cwd();
18278
19931
  guardCwdInsideServer(args.cwd, cwdResolved);
18279
19932
  const collected = /* @__PURE__ */ new Map();
18280
19933
  if (args.sources) {
@@ -18346,21 +19999,21 @@ async function loadOne(relative5, cwd, into) {
18346
19999
  if (into.has(relative5)) {
18347
20000
  return;
18348
20001
  }
18349
- const absolute = resolve15(cwd, relative5);
20002
+ const absolute = resolve20(cwd, relative5);
18350
20003
  const cwdPrefix = cwd.endsWith(sep3) ? cwd : cwd + sep3;
18351
20004
  if (!absolute.startsWith(cwdPrefix) && absolute !== cwd) {
18352
20005
  throw new Error(`Path \`${relative5}\` resolves outside the server cwd and is not allowed.`);
18353
20006
  }
18354
- const text = await readFile5(absolute, "utf8");
20007
+ const text = await readFile7(absolute, "utf8");
18355
20008
  into.set(relative5, { name: relative5, text });
18356
20009
  }
18357
20010
  async function resolveRelativeImport(fromFile, specifier, cwd) {
18358
20011
  if (!specifier.startsWith(".")) {
18359
20012
  return void 0;
18360
20013
  }
18361
- const fromAbsolute = isAbsolute7(fromFile) ? fromFile : resolve15(cwd, fromFile);
20014
+ const fromAbsolute = isAbsolute7(fromFile) ? fromFile : resolve20(cwd, fromFile);
18362
20015
  const fromDir = dirname7(fromAbsolute);
18363
- const baseAbsolute = resolve15(fromDir, specifier);
20016
+ const baseAbsolute = resolve20(fromDir, specifier);
18364
20017
  const cwdPrefix = cwd.endsWith(sep3) ? cwd : cwd + sep3;
18365
20018
  for (const ext of TRY_EXTENSIONS) {
18366
20019
  const candidateAbsolute = baseAbsolute + ext;
@@ -18371,7 +20024,7 @@ async function resolveRelativeImport(fromFile, specifier, cwd) {
18371
20024
  if (!exists) {
18372
20025
  continue;
18373
20026
  }
18374
- const text = await readFile5(candidateAbsolute, "utf8");
20027
+ const text = await readFile7(candidateAbsolute, "utf8");
18375
20028
  const relativeName = candidateAbsolute.startsWith(cwdPrefix) ? candidateAbsolute.slice(cwdPrefix.length) : candidateAbsolute;
18376
20029
  const result = { name: relativeName, text };
18377
20030
  return result;
@@ -18739,8 +20392,8 @@ var DBX_ROUTE_TREE_TOOL = {
18739
20392
  }
18740
20393
  }
18741
20394
  };
18742
- var TreeArgsType = type34({
18743
- "sources?": type34({ name: "string", text: "string" }).array(),
20395
+ var TreeArgsType = type39({
20396
+ "sources?": type39({ name: "string", text: "string" }).array(),
18744
20397
  "paths?": "string[]",
18745
20398
  "glob?": "string",
18746
20399
  "format?": "'markdown' | 'json' | 'flat'",
@@ -18749,7 +20402,7 @@ var TreeArgsType = type34({
18749
20402
  });
18750
20403
  function parseArgs3(raw) {
18751
20404
  const parsed = TreeArgsType(raw);
18752
- if (parsed instanceof type34.errors) {
20405
+ if (parsed instanceof type39.errors) {
18753
20406
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
18754
20407
  }
18755
20408
  const result = {
@@ -18799,7 +20452,7 @@ var routeTreeTool = {
18799
20452
  };
18800
20453
 
18801
20454
  // packages/dbx-components-mcp/src/tools/route-lookup.tool.ts
18802
- import { type as type35 } from "arktype";
20455
+ import { type as type40 } from "arktype";
18803
20456
  var DBX_ROUTE_LOOKUP_TOOL = {
18804
20457
  name: "dbx_route_lookup",
18805
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"),
@@ -18824,17 +20477,17 @@ var DBX_ROUTE_LOOKUP_TOOL = {
18824
20477
  required: ["topic"]
18825
20478
  }
18826
20479
  };
18827
- var LookupArgsType = type35({
20480
+ var LookupArgsType2 = type40({
18828
20481
  topic: "string",
18829
- "sources?": type35({ name: "string", text: "string" }).array(),
20482
+ "sources?": type40({ name: "string", text: "string" }).array(),
18830
20483
  "paths?": "string[]",
18831
20484
  "glob?": "string",
18832
20485
  "depth?": "'brief' | 'full'",
18833
20486
  "cwd?": "string"
18834
20487
  });
18835
20488
  function parseArgs4(raw) {
18836
- const parsed = LookupArgsType(raw);
18837
- if (parsed instanceof type35.errors) {
20489
+ const parsed = LookupArgsType2(raw);
20490
+ if (parsed instanceof type40.errors) {
18838
20491
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
18839
20492
  }
18840
20493
  const result = {
@@ -18904,8 +20557,8 @@ function fuzzyCandidates3(query, byName) {
18904
20557
  return scored.slice(0, 5).map((s) => s.node);
18905
20558
  }
18906
20559
  function formatSingle(node, depth, via) {
18907
- const urlText = node.fullUrl === void 0 ? "_no url_" : code7(node.fullUrl);
18908
- 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);
18909
20562
  const lines = [`# ${node.data.name}`, "", `Matched via ${via}.`, "", `- **URL:** ${urlText}`, `- **Component:** ${componentText}`, `- **Defined in:** \`${node.data.file}:${node.data.line}\``];
18910
20563
  if (node.data.redirectTo) {
18911
20564
  lines.push(`- **Redirects to:** \`${node.data.redirectTo}\``);
@@ -18929,7 +20582,7 @@ function formatSingle(node, depth, via) {
18929
20582
  }
18930
20583
  function appendParentChainSection(lines, node) {
18931
20584
  const chain = ancestors(node);
18932
- const chainLine = chain.map((c) => code7(c.data.name)).join(" \u2192 ");
20585
+ const chainLine = chain.map((c) => code8(c.data.name)).join(" \u2192 ");
18933
20586
  lines.push("", "## Parent chain", chainLine.length > 0 ? chainLine : "_root_");
18934
20587
  }
18935
20588
  function appendKeyListSection(lines, title, keys) {
@@ -18949,8 +20602,8 @@ function appendRelatedNodesSection(lines, title, nodes) {
18949
20602
  return;
18950
20603
  }
18951
20604
  for (const child of nodes) {
18952
- const urlPart = child.fullUrl === void 0 ? "" : code7(child.fullUrl);
18953
- 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)}` : "";
18954
20607
  lines.push(`- \`${child.data.name}\` ${urlPart}${componentPart}`);
18955
20608
  }
18956
20609
  }
@@ -18966,8 +20619,8 @@ function ancestors(node) {
18966
20619
  function formatGroup2(title, nodes) {
18967
20620
  const lines = [`# ${title}`, "", `${nodes.length} match(es).`, ""];
18968
20621
  for (const node of nodes) {
18969
- const urlPart = node.fullUrl === void 0 ? "" : code7(node.fullUrl);
18970
- 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)}` : "";
18971
20624
  lines.push(`- \`${node.data.name}\` ${urlPart}${componentPart} _(${node.data.file}:${node.data.line})_`);
18972
20625
  }
18973
20626
  return lines.join("\n");
@@ -18977,8 +20630,8 @@ function formatNotFound8(query, candidates) {
18977
20630
  if (candidates.length > 0) {
18978
20631
  lines.push("Did you mean one of these?", "");
18979
20632
  for (const node of candidates) {
18980
- const urlPart = node.fullUrl === void 0 ? "" : code7(node.fullUrl);
18981
- 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)}` : "";
18982
20635
  lines.push(`- \`${node.data.name}\` ${urlPart}${componentPart}`);
18983
20636
  }
18984
20637
  } else {
@@ -18986,7 +20639,7 @@ function formatNotFound8(query, candidates) {
18986
20639
  }
18987
20640
  return lines.join("\n");
18988
20641
  }
18989
- function code7(value) {
20642
+ function code8(value) {
18990
20643
  return "`" + value + "`";
18991
20644
  }
18992
20645
  async function runRouteLookup(rawArgs) {
@@ -19027,7 +20680,7 @@ var routeLookupTool = {
19027
20680
  };
19028
20681
 
19029
20682
  // packages/dbx-components-mcp/src/tools/route-search.tool.ts
19030
- import { type as type36 } from "arktype";
20683
+ import { type as type41 } from "arktype";
19031
20684
  var DBX_ROUTE_SEARCH_TOOL = {
19032
20685
  name: "dbx_route_search",
19033
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"),
@@ -19051,9 +20704,9 @@ var DBX_ROUTE_SEARCH_TOOL = {
19051
20704
  required: ["query"]
19052
20705
  }
19053
20706
  };
19054
- var SearchArgsType = type36({
20707
+ var SearchArgsType = type41({
19055
20708
  query: "string",
19056
- "sources?": type36({ name: "string", text: "string" }).array(),
20709
+ "sources?": type41({ name: "string", text: "string" }).array(),
19057
20710
  "paths?": "string[]",
19058
20711
  "glob?": "string",
19059
20712
  "scope?": "'name' | 'url' | 'component' | 'resolve' | 'all'",
@@ -19061,7 +20714,7 @@ var SearchArgsType = type36({
19061
20714
  });
19062
20715
  function parseArgs5(raw) {
19063
20716
  const parsed = SearchArgsType(raw);
19064
- if (parsed instanceof type36.errors) {
20717
+ if (parsed instanceof type41.errors) {
19065
20718
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
19066
20719
  }
19067
20720
  const result = {
@@ -19154,14 +20807,14 @@ var routeSearchTool = {
19154
20807
  };
19155
20808
 
19156
20809
  // packages/dbx-components-mcp/src/tools/_lookup.factory.ts
19157
- import { type as type37 } from "arktype";
19158
- var LOOKUP_ARGS_TYPE = type37({
20810
+ import { type as type42 } from "arktype";
20811
+ var LOOKUP_ARGS_TYPE = type42({
19159
20812
  topic: "string",
19160
20813
  "depth?": "'brief' | 'full'"
19161
20814
  });
19162
20815
  function parseLookupArgs(raw) {
19163
20816
  const parsed = LOOKUP_ARGS_TYPE(raw);
19164
- if (parsed instanceof type37.errors) {
20817
+ if (parsed instanceof type42.errors) {
19165
20818
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
19166
20819
  }
19167
20820
  const result = {
@@ -19310,11 +20963,11 @@ function formatEntry2(entry, depth) {
19310
20963
  const fence = entry.kind === "pattern" ? "ts" : "html";
19311
20964
  lines.push("## Example", "", "```" + fence, entry.example, "```");
19312
20965
  if (entry.relatedSlugs.length > 0) {
19313
- const relatedText = entry.relatedSlugs.map((s) => code8(s)).join(", ");
20966
+ const relatedText = entry.relatedSlugs.map((s) => code9(s)).join(", ");
19314
20967
  lines.push("", `\u2192 Related: ${relatedText}`);
19315
20968
  }
19316
20969
  if (entry.skillRefs.length > 0) {
19317
- const skillsText = entry.skillRefs.map((s) => code8(s)).join(", ");
20970
+ const skillsText = entry.skillRefs.map((s) => code9(s)).join(", ");
19318
20971
  lines.push("", `\u2192 Skills: ${skillsText}`);
19319
20972
  }
19320
20973
  } else {
@@ -19343,7 +20996,7 @@ function formatNotFound9(normalized, candidates) {
19343
20996
  }
19344
20997
  return lines.join("\n");
19345
20998
  }
19346
- function code8(value) {
20999
+ function code9(value) {
19347
21000
  return "`" + value + "`";
19348
21001
  }
19349
21002
  function createLookupFilterTool(input) {
@@ -19363,7 +21016,7 @@ function createLookupFilterTool(input) {
19363
21016
  }
19364
21017
 
19365
21018
  // packages/dbx-components-mcp/src/tools/filter-scaffold.tool.ts
19366
- import { type as type38 } from "arktype";
21019
+ import { type as type43 } from "arktype";
19367
21020
  var DBX_FILTER_SCAFFOLD_TOOL = {
19368
21021
  name: "dbx_filter_scaffold",
19369
21022
  description: [
@@ -19388,15 +21041,15 @@ var DBX_FILTER_SCAFFOLD_TOOL = {
19388
21041
  required: ["model_name", "filter_type"]
19389
21042
  }
19390
21043
  };
19391
- var ScaffoldArgsType4 = type38({
21044
+ var ScaffoldArgsType5 = type43({
19392
21045
  model_name: "string",
19393
21046
  filter_type: "string",
19394
21047
  "preset_keys?": "string[]",
19395
21048
  "uses_collection_store?": "boolean"
19396
21049
  });
19397
21050
  function parseArgs6(raw) {
19398
- const parsed = ScaffoldArgsType4(raw);
19399
- if (parsed instanceof type38.errors) {
21051
+ const parsed = ScaffoldArgsType5(raw);
21052
+ if (parsed instanceof type43.errors) {
19400
21053
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
19401
21054
  }
19402
21055
  const modelName = parsed.model_name.trim();
@@ -19579,11 +21232,11 @@ function formatEntry3(entry, depth) {
19579
21232
  }
19580
21233
  lines.push("## Example", "", "```html", entry.example, "```");
19581
21234
  if (entry.relatedSlugs.length > 0) {
19582
- const relatedText = entry.relatedSlugs.map((s) => code9(s)).join(", ");
21235
+ const relatedText = entry.relatedSlugs.map((s) => code10(s)).join(", ");
19583
21236
  lines.push("", `\u2192 Related: ${relatedText}`);
19584
21237
  }
19585
21238
  if (entry.skillRefs.length > 0) {
19586
- const skillsText = entry.skillRefs.map((s) => code9(s)).join(", ");
21239
+ const skillsText = entry.skillRefs.map((s) => code10(s)).join(", ");
19587
21240
  lines.push("", `\u2192 Skills: ${skillsText}`);
19588
21241
  }
19589
21242
  } else {
@@ -19615,7 +21268,7 @@ function formatNotFound10(normalized, candidates) {
19615
21268
  }
19616
21269
  return lines.join("\n");
19617
21270
  }
19618
- function code9(value) {
21271
+ function code10(value) {
19619
21272
  return "`" + value + "`";
19620
21273
  }
19621
21274
  function createLookupPipeTool(input) {
@@ -19636,8 +21289,8 @@ function createLookupPipeTool(input) {
19636
21289
 
19637
21290
  // packages/dbx-components-mcp/src/tools/artifact-scaffold.tool.ts
19638
21291
  import { access } from "node:fs/promises";
19639
- import { resolve as resolve16, sep as sep4 } from "node:path";
19640
- import { type as type39 } from "arktype";
21292
+ import { resolve as resolve21, sep as sep4 } from "node:path";
21293
+ import { type as type44 } from "arktype";
19641
21294
 
19642
21295
  // packages/dbx-components-mcp/src/tools/artifact-scaffold/templates.ts
19643
21296
  function splitWords(input) {
@@ -20185,7 +21838,7 @@ var DBX_ARTIFACT_SCAFFOLD_TOOL = {
20185
21838
  required: ["artifact", "name", "componentDir", "apiDir"]
20186
21839
  }
20187
21840
  };
20188
- var ScaffoldArtifactArgsType = type39({
21841
+ var ScaffoldArtifactArgsType = type44({
20189
21842
  artifact: ARTIFACT_KIND_LITERAL_UNION,
20190
21843
  name: "string",
20191
21844
  componentDir: "string",
@@ -20198,7 +21851,7 @@ var ScaffoldArtifactArgsType = type39({
20198
21851
  });
20199
21852
  function parseArgs7(raw) {
20200
21853
  const parsed = ScaffoldArtifactArgsType(raw);
20201
- if (parsed instanceof type39.errors) {
21854
+ if (parsed instanceof type44.errors) {
20202
21855
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
20203
21856
  }
20204
21857
  const result = {
@@ -20211,7 +21864,7 @@ function parseArgs7(raw) {
20211
21864
  return result;
20212
21865
  }
20213
21866
  function ensureInsideCwd(relativePath, cwd) {
20214
- const absolute = resolve16(cwd, relativePath);
21867
+ const absolute = resolve21(cwd, relativePath);
20215
21868
  const cwdPrefix = cwd.endsWith(sep4) ? cwd : cwd + sep4;
20216
21869
  if (!absolute.startsWith(cwdPrefix) && absolute !== cwd) {
20217
21870
  throw new Error(`Path \`${relativePath}\` resolves outside the server cwd and is not allowed.`);
@@ -20251,7 +21904,7 @@ async function runArtifactScaffold(rawArgs) {
20251
21904
  const message = err instanceof Error ? err.message : String(err);
20252
21905
  return toolError(`Scaffold failed: ${message}`);
20253
21906
  }
20254
- const checked = await applyIdempotency(raw, (relativePath) => fileExists2(resolve16(cwd, relativePath)));
21907
+ const checked = await applyIdempotency(raw, (relativePath) => fileExists2(resolve21(cwd, relativePath)));
20255
21908
  const text = formatResult9(checked);
20256
21909
  const result = {
20257
21910
  content: [{ type: "text", text }]
@@ -20264,7 +21917,7 @@ var artifactScaffoldTool = {
20264
21917
  };
20265
21918
 
20266
21919
  // packages/dbx-components-mcp/src/tools/artifact-file-convention.tool.ts
20267
- import { type as type40 } from "arktype";
21920
+ import { type as type45 } from "arktype";
20268
21921
 
20269
21922
  // packages/dbx-components-mcp/src/tools/artifact-file-convention/spec.ts
20270
21923
  var FIRESTORE_MODEL = {
@@ -20700,7 +22353,7 @@ var DBX_ARTIFACT_FILE_CONVENTION_TOOL = {
20700
22353
  required: ["artifact"]
20701
22354
  }
20702
22355
  };
20703
- var FileConventionArgsType = type40({
22356
+ var FileConventionArgsType = type45({
20704
22357
  artifact: ARTIFACT_KIND_LITERAL_UNION2,
20705
22358
  "componentDir?": "string",
20706
22359
  "apiDir?": "string",
@@ -20708,7 +22361,7 @@ var FileConventionArgsType = type40({
20708
22361
  });
20709
22362
  function parseArgs8(raw) {
20710
22363
  const parsed = FileConventionArgsType(raw);
20711
- if (parsed instanceof type40.errors) {
22364
+ if (parsed instanceof type45.errors) {
20712
22365
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
20713
22366
  }
20714
22367
  const result = {
@@ -20741,7 +22394,7 @@ var artifactFileConventionTool = {
20741
22394
  };
20742
22395
 
20743
22396
  // packages/dbx-components-mcp/src/tools/lookup-semantic-type.tool.ts
20744
- import { type as type41 } from "arktype";
22397
+ import { type as type46 } from "arktype";
20745
22398
 
20746
22399
  // packages/dbx-components-mcp/src/tools/semantic-type-lookup.formatter.ts
20747
22400
  function formatSemanticTypeEntry(entry, depth) {
@@ -20922,13 +22575,13 @@ var DBX_SEMANTIC_TYPE_LOOKUP_TOOL = {
20922
22575
  required: ["name"]
20923
22576
  }
20924
22577
  };
20925
- var LookupSemanticTypeArgsType = type41({
22578
+ var LookupSemanticTypeArgsType = type46({
20926
22579
  name: "string",
20927
22580
  "depth?": "'brief' | 'full'"
20928
22581
  });
20929
22582
  function parseLookupArgs2(raw) {
20930
22583
  const parsed = LookupSemanticTypeArgsType(raw);
20931
- if (parsed instanceof type41.errors) {
22584
+ if (parsed instanceof type46.errors) {
20932
22585
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
20933
22586
  }
20934
22587
  const result = {
@@ -20939,7 +22592,7 @@ function parseLookupArgs2(raw) {
20939
22592
  }
20940
22593
  function createSemanticTypeLookupTool(config) {
20941
22594
  const { registry } = config;
20942
- function run(rawArgs) {
22595
+ function run5(rawArgs) {
20943
22596
  let args;
20944
22597
  let result;
20945
22598
  try {
@@ -20975,7 +22628,7 @@ function createSemanticTypeLookupTool(config) {
20975
22628
  }
20976
22629
  const tool = {
20977
22630
  definition: DBX_SEMANTIC_TYPE_LOOKUP_TOOL,
20978
- run
22631
+ run: run5
20979
22632
  };
20980
22633
  return tool;
20981
22634
  }
@@ -20990,7 +22643,7 @@ function formatNotFound11(name, registry) {
20990
22643
  }
20991
22644
 
20992
22645
  // packages/dbx-components-mcp/src/tools/search-semantic-type.tool.ts
20993
- import { type as type42 } from "arktype";
22646
+ import { type as type47 } from "arktype";
20994
22647
  var DEFAULT_LIMIT4 = 25;
20995
22648
  var MAX_LIMIT4 = 100;
20996
22649
  var DBX_SEMANTIC_TYPE_SEARCH_TOOL = {
@@ -21023,7 +22676,7 @@ var DBX_SEMANTIC_TYPE_SEARCH_TOOL = {
21023
22676
  }
21024
22677
  }
21025
22678
  };
21026
- var SearchSemanticTypeArgsType = type42({
22679
+ var SearchSemanticTypeArgsType = type47({
21027
22680
  "topic?": "string",
21028
22681
  "baseType?": "string",
21029
22682
  "package?": "string",
@@ -21032,7 +22685,7 @@ var SearchSemanticTypeArgsType = type42({
21032
22685
  });
21033
22686
  function parseSearchArgs2(raw) {
21034
22687
  const parsed = SearchSemanticTypeArgsType(raw);
21035
- if (parsed instanceof type42.errors) {
22688
+ if (parsed instanceof type47.errors) {
21036
22689
  throw new TypeError(`Invalid arguments: ${parsed.summary}`);
21037
22690
  }
21038
22691
  const rawLimit = parsed.limit ?? DEFAULT_LIMIT4;
@@ -21058,7 +22711,7 @@ function nonEmpty(value) {
21058
22711
  }
21059
22712
  function createSemanticTypeSearchTool(config) {
21060
22713
  const { registry } = config;
21061
- function run(rawArgs) {
22714
+ function run5(rawArgs) {
21062
22715
  let args;
21063
22716
  let result;
21064
22717
  try {
@@ -21083,7 +22736,7 @@ function createSemanticTypeSearchTool(config) {
21083
22736
  }
21084
22737
  const tool = {
21085
22738
  definition: DBX_SEMANTIC_TYPE_SEARCH_TOOL,
21086
- run
22739
+ run: run5
21087
22740
  };
21088
22741
  return tool;
21089
22742
  }
@@ -21157,6 +22810,10 @@ var DBX_TOOLS = [
21157
22810
  modelValidateApiTool,
21158
22811
  modelValidateFolderTool,
21159
22812
  modelStoreScaffoldTool,
22813
+ modelFixtureListAppTool,
22814
+ modelFixtureLookupTool,
22815
+ modelFixtureScaffoldTool,
22816
+ modelFixtureForwardTool,
21160
22817
  // storagefile_m (model extension)
21161
22818
  storageFileMValidateAppTool,
21162
22819
  storageFileMListAppTool,
@@ -21183,6 +22840,7 @@ var DBX_TOOLS = [
21183
22840
  function registerTools(server, options = {}) {
21184
22841
  const underlyingServer = server.server;
21185
22842
  const tools = [...DBX_TOOLS];
22843
+ tools.push(createModelFixtureValidateAppTool({ getRegistry: () => options.fixtureModelRegistry }));
21186
22844
  if (options.forgeFieldRegistry !== void 0) {
21187
22845
  tools.push(createLookupFormTool({ registry: options.forgeFieldRegistry }), createSearchFormTool({ registry: options.forgeFieldRegistry }), createFormScaffoldTool({ registry: options.forgeFieldRegistry }));
21188
22846
  }
@@ -21232,6 +22890,7 @@ Tool clusters (each exposes lookup, search, examples, and/or scaffold/validate):
21232
22890
 
21233
22891
  Model-extension validators (walk a downstream app to verify wiring):
21234
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)
21235
22894
 
21236
22895
  Resource URIs are namespaced by domain:
21237
22896
  - dbx://form/fields[/{slug}|/produces/{produces}|/tier/{tier}|/array-output/{arrayOutput}]
@@ -21354,8 +23013,11 @@ async function createServer(options = {}) {
21354
23013
  filterRegistry = void 0;
21355
23014
  }
21356
23015
  }
23016
+ const fixtureModelRegistry = {
23017
+ entries: FIREBASE_MODELS.map((m) => ({ name: m.name, modelType: m.modelType, collectionPrefix: m.collectionPrefix }))
23018
+ };
21357
23019
  registerResources(server, { semanticTypeRegistry: registry, forgeFieldRegistry: forgeRegistry, pipeRegistry, uiComponentRegistry: uiRegistry, actionRegistry, filterRegistry });
21358
- registerTools(server, { semanticTypeRegistry: registry, forgeFieldRegistry: forgeRegistry, pipeRegistry, uiComponentRegistry: uiRegistry, actionRegistry, filterRegistry });
23020
+ registerTools(server, { semanticTypeRegistry: registry, forgeFieldRegistry: forgeRegistry, pipeRegistry, uiComponentRegistry: uiRegistry, actionRegistry, filterRegistry, fixtureModelRegistry });
21359
23021
  return server;
21360
23022
  }
21361
23023
  async function runStdioServer() {