@hamak/smart-data-dico 1.20.0 → 1.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26807,9 +26807,9 @@ var require_range2 = __commonJS({
26807
26807
  parseRange(range) {
26808
26808
  const memoOpts = (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) | (this.options.loose && FLAG_LOOSE);
26809
26809
  const memoKey = memoOpts + ":" + range;
26810
- const cached2 = cache2.get(memoKey);
26811
- if (cached2) {
26812
- return cached2;
26810
+ const cached3 = cache2.get(memoKey);
26811
+ if (cached3) {
26812
+ return cached3;
26813
26813
  }
26814
26814
  const loose = this.options.loose;
26815
26815
  const hr = loose ? re2[t.HYPHENRANGELOOSE] : re2[t.HYPHENRANGE];
@@ -44016,10 +44016,10 @@ var init_git_file_info_enricher = __esm({
44016
44016
  * Get cached status or fetch new one
44017
44017
  */
44018
44018
  async getCachedStatus(cacheKey, workspaceId, relativePath) {
44019
- const cached2 = this.statusCache.get(cacheKey);
44019
+ const cached3 = this.statusCache.get(cacheKey);
44020
44020
  const now2 = Date.now();
44021
- if (cached2 && now2 - cached2.timestamp < this.cacheTimeout) {
44022
- return cached2.status;
44021
+ if (cached3 && now2 - cached3.timestamp < this.cacheTimeout) {
44022
+ return cached3.status;
44023
44023
  }
44024
44024
  try {
44025
44025
  const status = await this.gitService.getStatus(workspaceId, relativePath);
@@ -44604,8 +44604,8 @@ function invalidatePackageCache(packageName) {
44604
44604
  else _packageCache.delete(packageName);
44605
44605
  }
44606
44606
  async function loadPackage(packageName) {
44607
- const cached2 = _packageCache.get(packageName);
44608
- if (cached2 && cached2.expires > Date.now()) return cached2.model;
44607
+ const cached3 = _packageCache.get(packageName);
44608
+ if (cached3 && cached3.expires > Date.now()) return cached3.model;
44609
44609
  const files = await listPackageYamlFilePaths(packageName);
44610
44610
  const parsed = await Promise.all(
44611
44611
  files.map(async (p) => ({
@@ -48508,9 +48508,25 @@ var init_serviceService = __esm({
48508
48508
  * user to disambiguate.
48509
48509
  */
48510
48510
  async findEntityAcrossPackages(entityName, preferredPackage) {
48511
+ const matches = await this.findEntityMatches(entityName, preferredPackage);
48512
+ if (matches.length === 0) return null;
48513
+ if (matches.length === 1) return matches[0];
48514
+ const where = matches.map((m) => m.packageName).join(", ");
48515
+ throw new Error(
48516
+ `Entity "${entityName}" exists in multiple packages: ${where}. Specify the package explicitly.`
48517
+ );
48518
+ }
48519
+ /**
48520
+ * All `{ entity, packageName }` matches for a name. A hit in
48521
+ * `preferredPackage` wins outright (single match, no wider scan) —
48522
+ * same precedence findEntityAcrossPackages always had. Callers that
48523
+ * want a disambiguation list instead of a thrown ambiguity error
48524
+ * (e.g. the AI getEntityDetails tool) consume this directly.
48525
+ */
48526
+ async findEntityMatches(entityName, preferredPackage) {
48511
48527
  if (preferredPackage) {
48512
48528
  const e = await this.getEntitySchema(preferredPackage, entityName);
48513
- if (e) return { entity: e, packageName: preferredPackage };
48529
+ if (e) return [{ entity: e, packageName: preferredPackage }];
48514
48530
  }
48515
48531
  const allPackages = await listMicroservices();
48516
48532
  const matches = [];
@@ -48519,12 +48535,7 @@ var init_serviceService = __esm({
48519
48535
  const e = await this.getEntitySchema(p, entityName);
48520
48536
  if (e) matches.push({ entity: e, packageName: p });
48521
48537
  }
48522
- if (matches.length === 0) return null;
48523
- if (matches.length === 1) return matches[0];
48524
- const where = matches.map((m) => m.packageName).join(", ");
48525
- throw new Error(
48526
- `Entity "${entityName}" exists in multiple packages: ${where}. Specify the package explicitly.`
48527
- );
48538
+ return matches;
48528
48539
  }
48529
48540
  async createEntity(service, entity) {
48530
48541
  logger.info(`Creating entity: ${service}.${entity.name}`);
@@ -83510,6 +83521,79 @@ var init_authoringRules = __esm({
83510
83521
  }
83511
83522
  });
83512
83523
 
83524
+ // backend/src/services/ai/physicalMapping.ts
83525
+ function metaValue2(meta3, name21) {
83526
+ const e = meta3?.find((m) => m.name === name21);
83527
+ return e && e.value != null ? String(e.value) : void 0;
83528
+ }
83529
+ function metaFlag(meta3, name21) {
83530
+ const v = meta3?.find((m) => m.name === name21)?.value;
83531
+ return v === true || /^(true|yes|1)$/i.test(String(v ?? ""));
83532
+ }
83533
+ function resolveAttributePhysical(a) {
83534
+ const columnName = metaValue2(a.metadata, "physical.columnName");
83535
+ const dbType = metaValue2(a.metadata, "physical.dbType");
83536
+ return {
83537
+ ...columnName ? { columnName } : {},
83538
+ ...dbType ? { dbType } : {},
83539
+ // == null: a YAML `primaryKey:` left empty means "unset", not false —
83540
+ // fall back to the legacy metadata flag in that case too.
83541
+ primaryKey: a.primaryKey == null ? metaFlag(a.metadata, "isPrimaryKey") : !!a.primaryKey
83542
+ };
83543
+ }
83544
+ var init_physicalMapping = __esm({
83545
+ "backend/src/services/ai/physicalMapping.ts"() {
83546
+ "use strict";
83547
+ __name(metaValue2, "metaValue");
83548
+ __name(metaFlag, "metaFlag");
83549
+ __name(resolveAttributePhysical, "resolveAttributePhysical");
83550
+ }
83551
+ });
83552
+
83553
+ // backend/src/services/ai/modelOverviewCache.ts
83554
+ var modelOverviewCache_exports = {};
83555
+ __export(modelOverviewCache_exports, {
83556
+ MODEL_OVERVIEW_TTL_MS: () => MODEL_OVERVIEW_TTL_MS,
83557
+ getModelOverviewCached: () => getModelOverviewCached,
83558
+ invalidateModelOverviewCache: () => invalidateModelOverviewCache,
83559
+ subscribeModelOverviewCache: () => subscribeModelOverviewCache
83560
+ });
83561
+ function invalidateModelOverviewCache() {
83562
+ cached2 = null;
83563
+ generation++;
83564
+ }
83565
+ function subscribeModelOverviewCache(projection) {
83566
+ return projection.onInvalidate(() => invalidateModelOverviewCache());
83567
+ }
83568
+ async function getModelOverviewCached(build) {
83569
+ if (cached2 && Date.now() - cached2.builtAt < MODEL_OVERVIEW_TTL_MS) {
83570
+ return cached2.value;
83571
+ }
83572
+ if (!inflight) {
83573
+ const startedAt = generation;
83574
+ inflight = build().then((value) => {
83575
+ if (generation === startedAt) cached2 = { value, builtAt: Date.now() };
83576
+ return value;
83577
+ }).finally(() => {
83578
+ inflight = null;
83579
+ });
83580
+ }
83581
+ return inflight;
83582
+ }
83583
+ var MODEL_OVERVIEW_TTL_MS, cached2, inflight, generation;
83584
+ var init_modelOverviewCache = __esm({
83585
+ "backend/src/services/ai/modelOverviewCache.ts"() {
83586
+ "use strict";
83587
+ MODEL_OVERVIEW_TTL_MS = 6e4;
83588
+ cached2 = null;
83589
+ inflight = null;
83590
+ generation = 0;
83591
+ __name(invalidateModelOverviewCache, "invalidateModelOverviewCache");
83592
+ __name(subscribeModelOverviewCache, "subscribeModelOverviewCache");
83593
+ __name(getModelOverviewCached, "getModelOverviewCached");
83594
+ }
83595
+ });
83596
+
83513
83597
  // backend/src/services/systemPromptStore.ts
83514
83598
  import { createHash as createHash2 } from "crypto";
83515
83599
  function systemPromptDigest(body) {
@@ -104542,10 +104626,6 @@ var init_aiMermaid = __esm({
104542
104626
  });
104543
104627
 
104544
104628
  // backend/src/controllers/aiSql.ts
104545
- function metaValue2(meta3, name21) {
104546
- const e = meta3?.find((m) => m.name === name21);
104547
- return e && e.value != null ? String(e.value) : void 0;
104548
- }
104549
104629
  function nameList(names, max = 8) {
104550
104630
  if (!names.length) return "";
104551
104631
  return names.length <= max ? names.join(", ") : `${names.slice(0, max).join(", ")} +${names.length - max} more`;
@@ -104587,44 +104667,107 @@ function sqlType(base, v, dialect) {
104587
104667
  }
104588
104668
  }
104589
104669
  function columnFor(a, derived, dialect) {
104590
- const physName = metaValue2(a.metadata, "physical.columnName");
104591
- const physType = metaValue2(a.metadata, "physical.dbType");
104670
+ const phys = resolveAttributePhysical(a);
104592
104671
  const resolved = resolveBase(String(a.type || "string"), a.validation, derived);
104593
104672
  return {
104594
104673
  attribute: a.name,
104595
- column: physName ?? a.name,
104596
- dbType: physType ?? sqlType(resolved.base, resolved.validation, dialect),
104674
+ column: phys.columnName ?? a.name,
104675
+ dbType: phys.dbType ?? sqlType(resolved.base, resolved.validation, dialect),
104597
104676
  nullable: !a.required,
104598
- primaryKey: !!a.primaryKey,
104599
- ...physName || physType ? {} : { physicalMappingMissing: true }
104677
+ primaryKey: phys.primaryKey,
104678
+ ...phys.columnName || phys.dbType ? {} : { physicalMappingMissing: true }
104600
104679
  };
104601
104680
  }
104602
104681
  async function buildSqlSchema(input, services, opts) {
104603
104682
  const dialect = input.dialect ?? "generic";
104604
104683
  const { listMicroservices: listMicroservices2 } = await Promise.resolve().then(() => (init_fileOperations(), fileOperations_exports));
104605
- const pkgs = input.packageName ? [input.packageName] : await listMicroservices2();
104684
+ const allPkgs = await listMicroservices2();
104685
+ if (input.entityNames !== void 0 && !Array.isArray(input.entityNames)) {
104686
+ return {
104687
+ error: `entityNames must be an array of entity names, e.g. entityNames: ['Order']. Retry with an array, or call searchModel({ query: '<entity or business term>' }) to locate the entity first.`
104688
+ };
104689
+ }
104690
+ const requestedNames = Array.isArray(input.entityNames) ? input.entityNames.map((n) => String(n).trim()).filter(Boolean) : void 0;
104691
+ if (input.packageName && !allPkgs.includes(input.packageName)) {
104692
+ return {
104693
+ error: `Package '${input.packageName}' not found. Known packages: ${nameList(allPkgs, 12) || "none"}. Call searchModel({ query: '<entity or business term>' }) to locate the element, or retry with entityNames: ['<EntityName>'] \u2014 entity names resolve across all packages.`
104694
+ };
104695
+ }
104606
104696
  const derivedList = await services.derivedTypes.list().catch(() => []);
104607
104697
  const derived = new Map(derivedList.map((d) => [d.name, d]));
104608
- const allPkgs = await listMicroservices2();
104609
- const nameByUuid = /* @__PURE__ */ new Map();
104698
+ const entitiesByPkg = /* @__PURE__ */ new Map();
104610
104699
  for (const p of allPkgs) {
104611
- for (const e of await services.serviceService.getServiceEntities(p).catch(() => [])) nameByUuid.set(e.uuid, e.name);
104700
+ entitiesByPkg.set(p, await services.serviceService.getServiceEntities(p).catch(() => []));
104701
+ }
104702
+ const nameByUuid = /* @__PURE__ */ new Map();
104703
+ for (const ents of entitiesByPkg.values()) {
104704
+ for (const e of ents) nameByUuid.set(e.uuid, e.name);
104705
+ }
104706
+ const relsByPkg = /* @__PURE__ */ new Map();
104707
+ const relsFor = /* @__PURE__ */ __name(async (p) => {
104708
+ if (!relsByPkg.has(p)) relsByPkg.set(p, await services.serviceService.getPackageRelationships(p).catch(() => []));
104709
+ return relsByPkg.get(p);
104710
+ }, "relsFor");
104711
+ let pkgs;
104712
+ let include = null;
104713
+ let scope;
104714
+ const unresolved = [];
104715
+ if (requestedNames?.length) {
104716
+ pkgs = allPkgs;
104717
+ const wanted = /* @__PURE__ */ new Set();
104718
+ for (const name21 of requestedNames) {
104719
+ const exact = [];
104720
+ const loose = [];
104721
+ for (const ents of entitiesByPkg.values()) {
104722
+ for (const e of ents) {
104723
+ if (e.name === name21) exact.push(e.uuid);
104724
+ else if (e.name.toLowerCase() === name21.toLowerCase()) loose.push(e.uuid);
104725
+ }
104726
+ }
104727
+ const hits = exact.length ? exact : loose;
104728
+ if (hits.length) hits.forEach((u) => wanted.add(u));
104729
+ else unresolved.push(name21);
104730
+ }
104731
+ if (!wanted.size) {
104732
+ return {
104733
+ error: `None of the requested entities (${requestedNames.join(", ")}) exist in any package. Call searchModel({ query: '<entity or business term>' }) to locate the right entity names, then retry.`
104734
+ };
104735
+ }
104736
+ include = new Set(wanted);
104737
+ for (const p of allPkgs) {
104738
+ for (const r of await relsFor(p)) {
104739
+ if (wanted.has(r.source.entity)) include.add(r.target.entity);
104740
+ if (wanted.has(r.target.entity)) include.add(r.source.entity);
104741
+ }
104742
+ }
104743
+ const resolved = requestedNames.filter((n) => !unresolved.includes(n));
104744
+ scope = `entities: ${resolved.join(", ")} (+directly related)`;
104745
+ } else {
104746
+ pkgs = input.packageName ? [input.packageName] : allPkgs;
104747
+ scope = input.packageName ?? "all packages";
104612
104748
  }
104613
104749
  const tables = [];
104614
104750
  const relationships = [];
104615
104751
  let missing = 0;
104752
+ const fallbackTables = [];
104616
104753
  for (const p of pkgs) {
104617
- const entities = await services.serviceService.getServiceEntities(p).catch(() => []);
104754
+ const entities = (entitiesByPkg.get(p) ?? []).filter((e) => !include || include.has(e.uuid));
104618
104755
  for (const e of entities) {
104619
104756
  const schema = metaValue2(e.metadata, "physical.schema") ?? (opts?.defaultSchema?.trim() || void 0);
104620
104757
  const table = metaValue2(e.metadata, "physical.tableName") ?? e.name;
104758
+ let entityMissing = 0;
104621
104759
  const columns = (e.attributes ?? []).map((a) => {
104622
104760
  const c = columnFor(a, derived, dialect);
104623
- if ("physicalMappingMissing" in c) missing++;
104761
+ if ("physicalMappingMissing" in c) entityMissing++;
104624
104762
  return c;
104625
104763
  });
104764
+ if (entityMissing > 0) {
104765
+ missing += entityMissing;
104766
+ if (!fallbackTables.includes(table)) fallbackTables.push(table);
104767
+ }
104626
104768
  tables.push({
104627
104769
  entity: e.name,
104770
+ package: p,
104628
104771
  table,
104629
104772
  ...schema ? { schema } : {},
104630
104773
  // Ready-to-use name for SQL — schema.table when a schema is known.
@@ -104632,7 +104775,8 @@ async function buildSqlSchema(input, services, opts) {
104632
104775
  columns
104633
104776
  });
104634
104777
  }
104635
- for (const r of await services.serviceService.getPackageRelationships(p).catch(() => [])) {
104778
+ for (const r of await relsFor(p)) {
104779
+ if (include && !(include.has(r.source.entity) && include.has(r.target.entity))) continue;
104636
104780
  const from = nameByUuid.get(r.source.entity);
104637
104781
  const to = nameByUuid.get(r.target.entity);
104638
104782
  if (!from || !to) continue;
@@ -104645,7 +104789,6 @@ async function buildSqlSchema(input, services, opts) {
104645
104789
  });
104646
104790
  }
104647
104791
  }
104648
- const scope = input.packageName ?? "all packages";
104649
104792
  const tableNames = tables.map((t) => t.entity);
104650
104793
  return {
104651
104794
  // #tool-summary — concise line, NAMES the tables for the tool card.
@@ -104655,7 +104798,9 @@ async function buildSqlSchema(input, services, opts) {
104655
104798
  schemaQualifyTables: !!opts?.schemaQualifyTables,
104656
104799
  tables,
104657
104800
  relationships,
104658
- note: "Use these PHYSICAL table/column names and dbTypes when writing SQL. " + (opts?.schemaQualifyTables ? "Schema-qualify every table (use each table's qualifiedName). " : "") + (missing > 0 ? `${missing} column(s) have no physical mapping \u2014 their dbType is a fallback derived from the logical type; flag this to the user.` : "All columns have an explicit physical mapping.")
104801
+ ...unresolved.length ? { unresolvedEntityNames: unresolved } : {},
104802
+ ...fallbackTables.length ? { tablesWithFallbackColumns: fallbackTables } : {},
104803
+ note: "Use these PHYSICAL table/column names and dbTypes when writing SQL. " + (opts?.schemaQualifyTables ? "Schema-qualify every table (use each table's qualifiedName). " : "") + (missing > 0 ? `${missing} column(s) in table(s) ${nameList(fallbackTables, 6)} have no explicit physical mapping \u2014 their column names/dbTypes are derived from the logical model; WARN the user before relying on them.` : "All columns have an explicit physical mapping.") + (unresolved.length ? ` Requested entities not found: ${unresolved.join(", ")} \u2014 call searchModel({ query: '<name>' }) to locate them.` : "")
104659
104804
  };
104660
104805
  }
104661
104806
  var getSqlSchemaInputSchema, getSqlSchemaParameters;
@@ -104663,18 +104808,20 @@ var init_aiSql = __esm({
104663
104808
  "backend/src/controllers/aiSql.ts"() {
104664
104809
  "use strict";
104665
104810
  init_zod();
104811
+ init_physicalMapping();
104666
104812
  getSqlSchemaInputSchema = external_exports.object({
104667
104813
  packageName: external_exports.string().optional().describe("Scope to one package (omit for the whole model)"),
104814
+ entityNames: external_exports.array(external_exports.string()).optional().describe("PREFERRED scope on large models: the target entity names (resolved across all packages). Their directly-related entities are included automatically so JOINs can be derived."),
104668
104815
  dialect: external_exports.enum(["generic", "postgres", "mysql", "mssql", "oracle", "sqlite"]).optional().describe("Target SQL dialect \u2014 tunes fallback column types (default generic)")
104669
104816
  });
104670
104817
  getSqlSchemaParameters = {
104671
104818
  type: "object",
104672
104819
  properties: {
104673
104820
  packageName: { type: "string", description: "Scope to one package (omit for the whole model)" },
104821
+ entityNames: { type: "array", items: { type: "string" }, description: "PREFERRED scope on large models: target entity names, resolved across all packages; directly-related entities are included automatically for JOINs" },
104674
104822
  dialect: { type: "string", enum: ["generic", "postgres", "mysql", "mssql", "oracle", "sqlite"], description: "Target SQL dialect (default generic)" }
104675
104823
  }
104676
104824
  };
104677
- __name(metaValue2, "metaValue");
104678
104825
  __name(nameList, "nameList");
104679
104826
  __name(resolveBase, "resolveBase");
104680
104827
  __name(sqlType, "sqlType");
@@ -116875,16 +117022,15 @@ function buildEntityDetails(entity, packageName) {
116875
117022
  const tableName = metaValue3(entity.metadata, "physical.tableName");
116876
117023
  const schema = metaValue3(entity.metadata, "physical.schema");
116877
117024
  const attributes = (entity.attributes ?? []).map((a) => {
116878
- const columnName = metaValue3(a.metadata, "physical.columnName");
116879
- const dbType = metaValue3(a.metadata, "physical.dbType");
117025
+ const phys = resolveAttributePhysical(a);
116880
117026
  return {
116881
117027
  name: a.name,
116882
117028
  type: a.type,
116883
117029
  description: a.description,
116884
117030
  required: a.required,
116885
- primaryKey: a.primaryKey,
117031
+ primaryKey: phys.primaryKey,
116886
117032
  ...a.validation ? { validation: a.validation } : {},
116887
- ...columnName || dbType ? { physical: { ...columnName ? { columnName } : {}, ...dbType ? { dbType } : {} } } : {}
117033
+ ...phys.columnName || phys.dbType ? { physical: { ...phys.columnName ? { columnName: phys.columnName } : {}, ...phys.dbType ? { dbType: phys.dbType } : {} } } : {}
116888
117034
  };
116889
117035
  });
116890
117036
  const hasPhysical = !!(tableName || schema) || attributes.some((a) => a.physical);
@@ -116896,6 +117042,7 @@ function buildEntityDetails(entity, packageName) {
116896
117042
  // #tool-summary — concise self-describing line for the tool card.
116897
117043
  summary: `${entity.name}${packageName ? ` (${packageName})` : ""} \u2014 ${attributes.length} attribute${attributes.length === 1 ? "" : "s"}${extras.length ? ` (${extras.join(", ")})` : ""}`,
116898
117044
  name: entity.name,
117045
+ ...packageName ? { packageName } : {},
116899
117046
  description: entity.description,
116900
117047
  stereotype: entity.stereotype,
116901
117048
  ...tableName || schema ? { physical: { ...tableName ? { tableName } : {}, ...schema ? { schema } : {} } } : {},
@@ -116904,6 +117051,46 @@ function buildEntityDetails(entity, packageName) {
116904
117051
  ...entity.rules?.length ? { rules: entity.rules.map((r) => ({ name: r.name, description: r.description, severity: r.severity })) } : {}
116905
117052
  };
116906
117053
  }
117054
+ async function executeGetEntityDetails(args, services) {
117055
+ if (!args?.entityName) return { error: "entityName is required." };
117056
+ const matches = await services.serviceService.findEntityMatches(args.entityName, args.packageName || void 0);
117057
+ if (matches.length === 1) {
117058
+ return buildEntityDetails(matches[0].entity, matches[0].packageName);
117059
+ }
117060
+ if (matches.length > 1) {
117061
+ return {
117062
+ summary: `'${args.entityName}' matches ${matches.length} entities \u2014 specify packageName`,
117063
+ ambiguous: true,
117064
+ candidates: matches.map((m) => ({
117065
+ entityName: m.entity.name,
117066
+ packageName: m.packageName,
117067
+ ...m.entity.description ? { description: m.entity.description } : {}
117068
+ })),
117069
+ note: "Several packages define an entity with this name. Call getEntityDetails again with the intended packageName."
117070
+ };
117071
+ }
117072
+ return {
117073
+ error: `Entity '${args.entityName}' not found in ${args.packageName ? `package '${args.packageName}' or ` : ""}any package. Call searchModel({ query: '${args.entityName}' }) to locate it by full-text search \u2014 the model may use a different name.`
117074
+ };
117075
+ }
117076
+ async function executeListEntities(args, services) {
117077
+ const { listMicroservices: listMicroservices2 } = await Promise.resolve().then(() => (init_fileOperations(), fileOperations_exports));
117078
+ if (args?.packageName) {
117079
+ const packages2 = await listMicroservices2().catch(() => []);
117080
+ if (!packages2.includes(args.packageName)) {
117081
+ return {
117082
+ error: `Package '${args.packageName}' not found. Known packages: ${nameList2(packages2, 12) || "none"}. Call searchModel({ query: '<entity or business term>' }) to locate the element you are after.`
117083
+ };
117084
+ }
117085
+ const entities = await services.serviceService.getServiceEntities(args.packageName);
117086
+ return {
117087
+ summary: `${args.packageName}: ${nameList2(entities.map((e) => e.name)) || "no entities"}`,
117088
+ entities: entities.map((e) => ({ name: e.name, description: e.description, attrCount: e.attributes?.length || 0 }))
117089
+ };
117090
+ }
117091
+ const packages = await listMicroservices2();
117092
+ return { summary: `packages: ${nameList2(packages) || "none"}`, packages };
117093
+ }
116907
117094
  async function buildModelOverview(services) {
116908
117095
  const { listMicroservices: listMicroservices2 } = await Promise.resolve().then(() => (init_fileOperations(), fileOperations_exports));
116909
117096
  const pkgNames = await listMicroservices2().catch(() => []);
@@ -116962,9 +117149,35 @@ function formatModelOutline(o) {
116962
117149
  Packages:
116963
117150
  ${pkgLines}${extra.length ? "\n" + extra.join("\n") : ""}`;
116964
117151
  }
117152
+ function formatModelOutlineWithinBudget(o, maxChars = MODEL_OUTLINE_MAX_CHARS) {
117153
+ const full = formatModelOutline(o);
117154
+ if (full.length <= maxChars) return full;
117155
+ const t = o.totals;
117156
+ const head = `Current model snapshot \u2014 ${t.packages} package(s), ${t.entities} entities, ${t.relationships} relationships, ${t.cases} cases, ${t.rules} rules, ${t.events} events, ${t.actions} actions, ${t.stateMachines} state machines, ${t.derivedTypes} derived types, ${t.stereotypes} stereotypes.`;
117157
+ const banner = `Entity lists omitted (${t.entities} entities across ${t.packages} packages \u2014 too large to inline). You do NOT have the full entity list. To locate any entity, call searchModel with its name or a business term, then getEntityDetails (packageName optional) or getSqlSchema with entityNames. Do NOT guess entity, package, or table names.`;
117158
+ const pkgLines = o.packages.map((p) => ` - ${p.name}: ${p.entities.length} entit${p.entities.length === 1 ? "y" : "ies"}, ${p.relationships} relationship${p.relationships === 1 ? "" : "s"}`);
117159
+ const fixed = head.length + banner.length + "Packages:\n".length + 4;
117160
+ const lines = [];
117161
+ let used = fixed;
117162
+ for (let i = 0; i < pkgLines.length; i++) {
117163
+ const remaining = pkgLines.length - i;
117164
+ if (used + pkgLines[i].length + 1 > maxChars - 80 && remaining > 1) {
117165
+ lines.push(` \u2026 +${remaining} more packages (call listEntities to enumerate)`);
117166
+ break;
117167
+ }
117168
+ lines.push(pkgLines[i]);
117169
+ used += pkgLines[i].length + 1;
117170
+ }
117171
+ return `${head}
117172
+ ${banner}
117173
+ Packages:
117174
+ ${lines.join("\n")}`;
117175
+ }
116965
117176
  async function safeModelOutline(services) {
116966
117177
  try {
116967
- return formatModelOutline(await buildModelOverview(services));
117178
+ return formatModelOutlineWithinBudget(
117179
+ await getModelOverviewCached(() => buildModelOverview(services))
117180
+ );
116968
117181
  } catch {
116969
117182
  return "";
116970
117183
  }
@@ -117130,7 +117343,7 @@ function buildSystemPrompt(pageContext, conversationSystemPrompt, mode = "design
117130
117343
  if (typeof modelOutline === "string" && modelOutline.trim().length > 0) {
117131
117344
  out += `
117132
117345
 
117133
- ${modelOutline.trim().slice(0, 2e3)}`;
117346
+ ${modelOutline.trim().slice(0, MODEL_OUTLINE_MAX_CHARS)}`;
117134
117347
  }
117135
117348
  if (typeof pageContext === "string") {
117136
117349
  const trimmed2 = pageContext.trim();
@@ -117142,7 +117355,7 @@ Page context: ${trimmed2.slice(0, 500)}`;
117142
117355
  }
117143
117356
  return out;
117144
117357
  }
117145
- function buildDirectChatMessages(rawMessages, maxToolResultChars = 2e3) {
117358
+ function buildDirectChatMessages(rawMessages, maxToolResultChars = DIRECT_TOOL_RESULT_MAX_CHARS) {
117146
117359
  const out = [];
117147
117360
  for (const msg of rawMessages) {
117148
117361
  const text2 = msg.parts?.find((p) => p.type === "text")?.text || msg.content || "";
@@ -117158,10 +117371,13 @@ function buildDirectChatMessages(rawMessages, maxToolResultChars = 2e3) {
117158
117371
  }))
117159
117372
  });
117160
117373
  for (const tc of toolCalls) {
117374
+ const serialized = JSON.stringify(tc.output ?? {});
117161
117375
  out.push({
117162
117376
  role: "tool",
117163
117377
  tool_call_id: String(tc.id),
117164
- content: JSON.stringify(tc.output ?? {}).slice(0, maxToolResultChars)
117378
+ // Truncation must be LOUD — a silent cut reads as a complete result
117379
+ // and the model trusts a partial schema instead of narrowing scope.
117380
+ content: serialized.length > maxToolResultChars ? serialized.slice(0, maxToolResultChars) + TOOL_RESULT_TRUNCATION_MARKER : serialized
117165
117381
  });
117166
117382
  }
117167
117383
  } else if (text2) {
@@ -117216,10 +117432,10 @@ async function handleDirectChat(req, res, cfg, rawMessages, services, pageContex
117216
117432
  { type: "function", function: { name: "createAction", description: "Create an Action/command (e.g. PlaceOrder) on an aggregate entity (ownerEntityName), optionally CQRS-classified, with an optional flow of steps. Use flow steps emitEvent {name} and wait {for} to wire a saga/process across actions+events.", parameters: createActionParameters } },
117217
117433
  { type: "function", function: { name: "createStateMachine", description: "Create a state machine on an entity (ownerEntityName) \u2014 its states, initialState, and transitions (from/to/on). Model an entity lifecycle, e.g. Order PENDING\u2192PAID\u2192SHIPPED.", parameters: createStateMachineParameters } },
117218
117434
  { type: "function", function: { name: "listEntities", description: "List packages or entities in a package", parameters: { type: "object", properties: { packageName: { type: "string", description: "Package name (omit to list all)" } } } } },
117219
- { type: "function", function: { name: "getEntityDetails", description: "Get full detail for one entity: attributes with type/required/primaryKey AND field validation, the PHYSICAL mapping (entity table name + schema, each attribute physical column name + DB type), physical constraints, and inline business rules. Call this before writing SQL/DDL so you use the real physical names and types.", parameters: { type: "object", required: ["packageName", "entityName"], properties: { packageName: { type: "string" }, entityName: { type: "string" } } } } },
117435
+ { type: "function", function: { name: "getEntityDetails", description: "Get full detail for one entity: attributes with type/required/primaryKey AND field validation, the PHYSICAL mapping (entity table name + schema, each attribute physical column name + DB type), physical constraints, and inline business rules. packageName is OPTIONAL \u2014 omit it and the entity name is resolved across every package (ambiguous names return a candidate list). Call this before writing SQL/DDL so you use the real physical names and types.", parameters: { type: "object", required: ["entityName"], properties: { packageName: { type: "string", description: "Owning package if known (optional \u2014 resolved across packages when omitted)" }, entityName: { type: "string" } } } } },
117220
117436
  { type: "function", function: { name: "getModelOverview", description: "Get a whole-model outline: every package with its entity names, and a count of each concept (entities, relationships, cases, rules, events, actions, state machines, derived types, stereotypes). A snapshot is already in your context; call this to refresh after changes.", parameters: { type: "object", properties: {} } } },
117221
117437
  { type: "function", function: { name: "generateMermaid", description: 'Convert the model to Mermaid diagram source. diagram: "er" (entity-relationship of a package, or all), "class" (class diagram), "state" (a single entity state machine \u2014 pass entityName), "flow" (actions+events saga). Returns { mermaid }. Present it inside a ```mermaid code block.', parameters: generateMermaidParameters } },
117222
- { type: "function", function: { name: "getSqlSchema", description: "Get the PHYSICAL relational schema for writing SQL: per-entity table name + schema, each column (physical name, dbType, nullable, primaryKey), and relationships as join hints. Optional packageName scope and dialect. Call this before writing any SQL query or DDL so you use real physical names/types, not the conceptual (logical) names.", parameters: getSqlSchemaParameters } },
117438
+ { type: "function", function: { name: "getSqlSchema", description: "Get the PHYSICAL relational schema for writing SQL: per-entity table name + schema, each column (physical name, dbType, nullable, primaryKey), and relationships as join hints. PREFER scoping with entityNames (target entities, resolved across packages; directly-related entities are included automatically for JOINs) or packageName \u2014 an unscoped call on a large model returns a huge result that may be truncated. Optional dialect. Call this before writing any SQL query or DDL so you use real physical names/types, not the conceptual (logical) names.", parameters: getSqlSchemaParameters } },
117223
117439
  { type: "function", function: { name: "listStereotypes", description: "List available stereotypes", parameters: { type: "object", properties: {} } } },
117224
117440
  { type: "function", function: { name: "navigateTo", description: 'Navigate user to a page. The path MUST be an absolute URL beginning with "/" that matches one of the patterns returned by listRoutes \u2014 call listRoutes first if you are unsure of the exact shape.', parameters: { type: "object", required: ["path", "reason"], properties: { path: { type: "string" }, reason: { type: "string" } } } } },
117225
117441
  { type: "function", function: { name: "listRoutes", description: "List every valid URL pattern in the app with a short description and (where useful) a concrete example. Call this BEFORE navigateTo if you are unsure of the exact path shape \u2014 e.g. plural vs singular, where attribute pages live, what the case route is.", parameters: { type: "object", properties: {} } } }
@@ -117281,21 +117497,13 @@ async function handleDirectChat(req, res, cfg, rawMessages, services, pageContex
117281
117497
  return await executeCreateStateMachine(args, conceptServices);
117282
117498
  }
117283
117499
  if (name21 === "listEntities") {
117284
- if (args.packageName) {
117285
- const entities = await services.serviceService.getServiceEntities(args.packageName);
117286
- return { summary: `${args.packageName}: ${nameList2(entities.map((e) => e.name)) || "no entities"}`, entities: entities.map((e) => ({ name: e.name, description: e.description })) };
117287
- }
117288
- const { listMicroservices: listMicroservices2 } = await Promise.resolve().then(() => (init_fileOperations(), fileOperations_exports));
117289
- const packages = await listMicroservices2();
117290
- return { summary: `packages: ${nameList2(packages) || "none"}`, packages };
117500
+ return await executeListEntities(args, services);
117291
117501
  }
117292
117502
  if (name21 === "getEntityDetails") {
117293
- const entity = await services.serviceService.getEntitySchema(args.packageName || "default", args.entityName);
117294
- if (!entity) return { error: "Entity not found" };
117295
- return buildEntityDetails(entity, args.packageName);
117503
+ return await executeGetEntityDetails(args, services);
117296
117504
  }
117297
117505
  if (name21 === "getModelOverview") {
117298
- return await buildModelOverview(services);
117506
+ return await getModelOverviewCached(() => buildModelOverview(services));
117299
117507
  }
117300
117508
  if (name21 === "generateMermaid") {
117301
117509
  return await generateMermaidDiagram(args, services);
@@ -117334,8 +117542,11 @@ async function handleDirectChat(req, res, cfg, rawMessages, services, pageContex
117334
117542
  }
117335
117543
  }
117336
117544
  const out = await runTool(name21, args);
117337
- if (isGatedCategory(category) && out && typeof out === "object" && out.success === true) {
117338
- mutatingSuccessCount++;
117545
+ if (isGatedCategory(category)) {
117546
+ invalidateModelOverviewCache();
117547
+ if (out && typeof out === "object" && out.success === true) {
117548
+ mutatingSuccessCount++;
117549
+ }
117339
117550
  }
117340
117551
  return out;
117341
117552
  }, "executeTool");
@@ -117461,7 +117672,7 @@ ${lines.join("\n")}` : "";
117461
117672
  return "";
117462
117673
  }
117463
117674
  }
117464
- var TOOL_CATEGORY_MAP, READ_ONLY_TOOLS, MODE_SYSTEM_SUFFIX, GATED_CATEGORIES, DENIED_RESULT, SYSTEM_PROMPT, aiChat, aiChatApprove, aiStatus, aiGetConfig, aiSaveConfig, aiTestTools, aiTools, aiMentionsSearch, listConversations, getConversation, saveConversation, patchConversation, deleteConversation, getSystemPromptByDigest, listPrompts, getPrompt, createPrompt, updatePrompt, deletePrompt;
117675
+ var TOOL_CATEGORY_MAP, READ_ONLY_TOOLS, MODE_SYSTEM_SUFFIX, GATED_CATEGORIES, MODEL_OUTLINE_MAX_CHARS, DENIED_RESULT, SYSTEM_PROMPT, DIRECT_TOOL_RESULT_MAX_CHARS, TOOL_RESULT_TRUNCATION_MARKER, aiChat, aiChatApprove, aiStatus, aiGetConfig, aiSaveConfig, aiTestTools, aiTools, aiMentionsSearch, listConversations, getConversation, saveConversation, patchConversation, deleteConversation, getSystemPromptByDigest, listPrompts, getPrompt, createPrompt, updatePrompt, deletePrompt;
117465
117676
  var init_aiController = __esm({
117466
117677
  "backend/src/controllers/aiController.ts"() {
117467
117678
  "use strict";
@@ -117471,6 +117682,8 @@ var init_aiController = __esm({
117471
117682
  init_config();
117472
117683
  init_agentToolRegistry();
117473
117684
  init_authoringRules();
117685
+ init_physicalMapping();
117686
+ init_modelOverviewCache();
117474
117687
  init_systemPromptStore();
117475
117688
  init_appDir();
117476
117689
  init_conversationService();
@@ -117542,8 +117755,12 @@ Mode: REVIEW. You are reviewing the data model for quality issues. Use read-only
117542
117755
  __name(nameList2, "nameList");
117543
117756
  __name(metaValue3, "metaValue");
117544
117757
  __name(buildEntityDetails, "buildEntityDetails");
117758
+ __name(executeGetEntityDetails, "executeGetEntityDetails");
117759
+ __name(executeListEntities, "executeListEntities");
117545
117760
  __name(buildModelOverview, "buildModelOverview");
117546
117761
  __name(formatModelOutline, "formatModelOutline");
117762
+ MODEL_OUTLINE_MAX_CHARS = 4e3;
117763
+ __name(formatModelOutlineWithinBudget, "formatModelOutlineWithinBudget");
117547
117764
  __name(safeModelOutline, "safeModelOutline");
117548
117765
  __name(isGatedCategory, "isGatedCategory");
117549
117766
  __name(resolveToolCategory, "resolveToolCategory");
@@ -117569,21 +117786,24 @@ This system models a RICH domain \u2014 not just entities. You can author all of
117569
117786
  - Events \u2014 domain events emitted by aggregates, e.g. OrderPlaced (createEvent)
117570
117787
  - Actions \u2014 commands/queries on aggregates with a flow; emitEvent/wait steps wire a saga/process (createAction)
117571
117788
  - State machines \u2014 entity lifecycles: states + transitions, e.g. Order PENDING\u2192PAID\u2192SHIPPED (createStateMachine)
117572
- - Read/inspect: searchModel (full-text search across the whole dictionary \u2014 use it to LOCATE an entity/attribute/rule when you don't know its exact name, then drill in), getModelOverview (whole-model outline \u2014 packages, entities, and concept counts; a current snapshot is already shown to you below), getEntityDetails (one entity in full incl. physical mapping), listEntities, listStereotypes; navigate with navigateTo (call listRoutes first if unsure)
117789
+ - Read/inspect: searchModel (full-text search across the whole dictionary \u2014 use it to LOCATE an entity/attribute/rule when you don't know its exact name, then drill in), getModelOverview (whole-model outline \u2014 packages, entities, and concept counts; a current snapshot is already shown to you below), getEntityDetails (one entity in full incl. physical mapping; packageName optional \u2014 the name resolves across packages), listEntities, listStereotypes; navigate with navigateTo (call listRoutes first if unsure)
117573
117790
  - Diagram: generateMermaid converts the model to Mermaid source \u2014 diagram: "er" (entity-relationship of a package/all), "class" (class diagram), "state" (an entity's state machine, needs entityName), or "flow" (actions+events saga). Use it when the user asks for a diagram, ERD, or visualization, and present the result in a fenced mermaid code block.
117574
117791
 
117575
117792
  A "process" or "saga" is NOT a separate object \u2014 it is the graph that emerges from Actions (with emitEvent/wait flow steps) and Events. To model a process, create the Actions and Events; the saga view is derived automatically.
117576
117793
 
117577
117794
  CONCEPTUAL vs PHYSICAL model \u2014 keep these two layers distinct:
117578
117795
  - CONCEPTUAL / LOGICAL is the business model: entity names (PascalCase, e.g. Order), attribute names (camelCase, e.g. orderNumber), and logical or derived types (e.g. money, email, currency-code). This is what you author and what users discuss.
117579
- - PHYSICAL is how it is persisted in a database: a table name (physical.tableName) in a schema, per-column physical names (physical.columnName) and DB types (physical.dbType), plus constraints. The two layers can differ completely (logical Order.orderNumber \u2192 physical orders.order_no VARCHAR). getEntityDetails returns the physical mapping for one entity; getSqlSchema returns the whole physical relational schema.
117796
+ - PHYSICAL is how it is persisted in a database: a table name (physical.tableName) in a schema, per-column physical names (physical.columnName) and DB types (physical.dbType), plus constraints. The two layers can differ completely (logical Order.orderNumber \u2192 physical orders.order_no VARCHAR). getEntityDetails returns the physical mapping for one entity; getSqlSchema returns the physical relational schema (scope it with entityNames or packageName on anything but a small model).
117580
117797
  - A logical/derived type (money, email) is NOT a DB type \u2014 it maps to a physical dbType (money \u2192 DECIMAL(12,2), email \u2192 VARCHAR(254)).
117581
117798
  - NEVER write DDL or SQL using conceptual names. Always resolve to the physical table/column names and dbTypes first. If an element has no physical mapping yet, getSqlSchema returns a fallback dbType derived from the logical type and flags it \u2014 pass that flag on to the user.
117582
117799
 
117583
117800
  Generating database queries: when the user asks for a SQL query (SELECT / INSERT / UPDATE / DELETE), a report, or DDL \u2014
117584
- 1. Call getSqlSchema (optionally a packageName scope and the target dialect) to get the real table names, columns + dbTypes, primary keys, and relationships.
117585
- 2. Write the query using ONLY physical names; derive JOINs from the relationships (join the PK of the "one" side to the FK on the "many" side) and respect the requested dialect.
117586
- 3. Present the query in a fenced sql code block, and briefly note any assumption (an inferred join column, a missing physical mapping). You generate queries for the user to run \u2014 you do NOT execute them against a live database.
117801
+ 1. LOCATE the entity first. Unless you already know its owning package (from the snapshot, page context, or an @mention), call searchModel with the entity name or business term to resolve entity \u2192 package. NEVER guess a package, entity, or table name \u2014 the snapshot above may not list every entity.
117802
+ 2. Call getSqlSchema scoped NARROWLY: pass entityNames: [...] for the target entities (their directly-related entities are included automatically so you can derive JOINs), or a packageName; pass the target dialect. Do not call it unscoped on a large model \u2014 the result gets truncated and misleads you.
117803
+ 3. Write the query using ONLY the physical names returned by the tool; derive JOINs from the relationships (join the PK of the "one" side to the FK on the "many" side) and respect the requested dialect.
117804
+ 4. If any column is flagged physicalMappingMissing, tell the user those column names/types are unverified fallbacks derived from the logical model \u2014 do not silently pass them off as real.
117805
+ 5. Present the query in a fenced sql code block, and briefly note any assumption (an inferred join column, a missing physical mapping). You generate queries for the user to run \u2014 you do NOT execute them against a live database.
117806
+ If a lookup tool returns an error or an empty result, do not retry the same guess \u2014 follow the error's guidance (usually: call searchModel), or ask the user.
117587
117807
 
117588
117808
  When creating data models:
117589
117809
  - Use meaningful names (PascalCase for entities/events, camelCase for attributes)
@@ -117614,6 +117834,8 @@ Be concise in your responses. Show a summary of what you created.`;
117614
117834
  __name(sqlSettingsInstruction, "sqlSettingsInstruction");
117615
117835
  __name(standingSystemPrompt, "standingSystemPrompt");
117616
117836
  __name(buildSystemPrompt, "buildSystemPrompt");
117837
+ DIRECT_TOOL_RESULT_MAX_CHARS = 2e4;
117838
+ TOOL_RESULT_TRUNCATION_MARKER = "\u2026[truncated \u2014 result too large; retry with a narrower scope, e.g. packageName or entityNames filter]";
117617
117839
  __name(buildDirectChatMessages, "buildDirectChatMessages");
117618
117840
  __name(buildUiMessagesWithToolParts, "buildUiMessagesWithToolParts");
117619
117841
  __name(handleDirectChat, "handleDirectChat");
@@ -117666,7 +117888,11 @@ Be concise in your responses. Show a summary of what you created.`;
117666
117888
  const decision = await awaitApproval(streamId, toolCallId);
117667
117889
  if (decision === "deny") return { ...DENIED_RESULT };
117668
117890
  }
117669
- return run();
117891
+ try {
117892
+ return await run();
117893
+ } finally {
117894
+ if (isGatedCategory(category)) invalidateModelOverviewCache();
117895
+ }
117670
117896
  }, "gate");
117671
117897
  const mcpToolEntries = {};
117672
117898
  for (const mcpTool of mcpTools) {
@@ -117837,29 +118063,21 @@ Be concise in your responses. Show a summary of what you created.`;
117837
118063
  }),
117838
118064
  execute: /* @__PURE__ */ __name(async (params) => {
117839
118065
  try {
117840
- if (params.packageName) {
117841
- const entities = await services.serviceService.getServiceEntities(params.packageName || "default");
117842
- return { summary: `${params.packageName}: ${nameList2(entities.map((e) => e.name)) || "no entities"}`, entities: entities.map((e) => ({ name: e.name, description: e.description, attrCount: e.attributes?.length || 0 })) };
117843
- }
117844
- const { listMicroservices: listMicroservices2 } = await Promise.resolve().then(() => (init_fileOperations(), fileOperations_exports));
117845
- const packages = await listMicroservices2();
117846
- return { summary: `packages: ${nameList2(packages) || "none"}`, packages };
118066
+ return await executeListEntities(params, services);
117847
118067
  } catch (err) {
117848
118068
  return { error: err.message };
117849
118069
  }
117850
118070
  }, "execute")
117851
118071
  }),
117852
118072
  getEntityDetails: tool({
117853
- description: "Get full detail for an entity: attributes with type/required/primaryKey AND field validation, the PHYSICAL mapping (entity table name + schema, each attribute physical column name + DB type), physical constraints, and inline business rules. Use this before writing SQL/DDL so you use the real physical names and types.",
118073
+ description: "Get full detail for an entity: attributes with type/required/primaryKey AND field validation, the PHYSICAL mapping (entity table name + schema, each attribute physical column name + DB type), physical constraints, and inline business rules. packageName is OPTIONAL \u2014 omit it and the entity name is resolved across every package (ambiguous names return a candidate list). Use this before writing SQL/DDL so you use the real physical names and types.",
117854
118074
  inputSchema: external_exports.object({
117855
- packageName: external_exports.string(),
118075
+ packageName: external_exports.string().optional().describe("Owning package if known (optional \u2014 resolved across packages when omitted)"),
117856
118076
  entityName: external_exports.string()
117857
118077
  }),
117858
118078
  execute: /* @__PURE__ */ __name(async (params) => {
117859
118079
  try {
117860
- const entity = await services.serviceService.getEntitySchema(params.packageName || "default", params.entityName);
117861
- if (!entity) return { error: "Entity not found" };
117862
- return buildEntityDetails(entity, params.packageName);
118080
+ return await executeGetEntityDetails(params, services);
117863
118081
  } catch (err) {
117864
118082
  return { error: err.message };
117865
118083
  }
@@ -117870,7 +118088,7 @@ Be concise in your responses. Show a summary of what you created.`;
117870
118088
  inputSchema: external_exports.object({}),
117871
118089
  execute: /* @__PURE__ */ __name(async () => {
117872
118090
  try {
117873
- return await buildModelOverview(services);
118091
+ return await getModelOverviewCached(() => buildModelOverview(services));
117874
118092
  } catch (err) {
117875
118093
  return { error: err.message };
117876
118094
  }
@@ -117888,7 +118106,7 @@ Be concise in your responses. Show a summary of what you created.`;
117888
118106
  }, "execute")
117889
118107
  }),
117890
118108
  getSqlSchema: tool({
117891
- description: "Get the PHYSICAL relational schema for writing SQL: per-entity table name + schema, each column (physical name, dbType, nullable, primaryKey), and relationships as join hints. Optional packageName scope and dialect. Call this before writing any SQL query or DDL so you use real physical names/types, not the conceptual (logical) names.",
118109
+ description: "Get the PHYSICAL relational schema for writing SQL: per-entity table name + schema, each column (physical name, dbType, nullable, primaryKey), and relationships as join hints. PREFER scoping with entityNames (target entities, resolved across packages; directly-related entities are included automatically for JOINs) or packageName \u2014 an unscoped call on a large model returns a huge result that may be truncated. Optional dialect. Call this before writing any SQL query or DDL so you use real physical names/types, not the conceptual (logical) names.",
117892
118110
  inputSchema: getSqlSchemaInputSchema,
117893
118111
  execute: /* @__PURE__ */ __name(async (params) => {
117894
118112
  try {
@@ -118321,7 +118539,7 @@ Be concise in your responses. Show a summary of what you created.`;
118321
118539
  description: "Get full entity detail: attributes + validation, the physical mapping (table/schema, column names, DB types), constraints, and inline rules. Use before writing SQL/DDL.",
118322
118540
  source: "builtin",
118323
118541
  parameters: [
118324
- { name: "packageName", type: "string", required: true, description: "Package name" },
118542
+ { name: "packageName", type: "string", required: false, description: "Owning package if known (omit to resolve the entity name across all packages)" },
118325
118543
  { name: "entityName", type: "string", required: true, description: "Entity name" }
118326
118544
  ]
118327
118545
  },
@@ -118343,10 +118561,11 @@ Be concise in your responses. Show a summary of what you created.`;
118343
118561
  },
118344
118562
  {
118345
118563
  name: "getSqlSchema",
118346
- description: "Physical relational schema for writing SQL: tables, columns (physical name + dbType + nullable + PK), and relationships as join hints. Use before generating any SQL query/DDL.",
118564
+ description: "Physical relational schema for writing SQL: tables, columns (physical name + dbType + nullable + PK), and relationships as join hints. Use before generating any SQL query/DDL. Prefer scoping with entityNames or packageName on large models.",
118347
118565
  source: "builtin",
118348
118566
  parameters: [
118349
118567
  { name: "packageName", type: "string", required: false, description: "Scope to one package (omit for all)" },
118568
+ { name: "entityNames", type: "string[]", required: false, description: "Preferred scope: target entity names, resolved across packages; directly-related entities are included automatically for JOINs" },
118350
118569
  { name: "dialect", type: "generic|postgres|mysql|mssql|oracle|sqlite", required: false, description: "Target SQL dialect (default generic)" }
118351
118570
  ]
118352
118571
  },
@@ -150141,8 +150360,8 @@ var require_inflight = __commonJS({
150141
150360
  var wrappy = require_wrappy();
150142
150361
  var reqs = /* @__PURE__ */ Object.create(null);
150143
150362
  var once = require_once();
150144
- module.exports = wrappy(inflight);
150145
- function inflight(key2, cb) {
150363
+ module.exports = wrappy(inflight2);
150364
+ function inflight2(key2, cb) {
150146
150365
  if (reqs[key2]) {
150147
150366
  reqs[key2].push(cb);
150148
150367
  return null;
@@ -150151,7 +150370,7 @@ var require_inflight = __commonJS({
150151
150370
  return makeres(key2);
150152
150371
  }
150153
150372
  }
150154
- __name(inflight, "inflight");
150373
+ __name(inflight2, "inflight");
150155
150374
  function makeres(key2) {
150156
150375
  return once(/* @__PURE__ */ __name(function RES() {
150157
150376
  var cbs = reqs[key2];
@@ -150203,7 +150422,7 @@ var require_glob = __commonJS({
150203
150422
  var alphasorti = common.alphasorti;
150204
150423
  var setopts = common.setopts;
150205
150424
  var ownProp = common.ownProp;
150206
- var inflight = require_inflight();
150425
+ var inflight2 = require_inflight();
150207
150426
  var util2 = __require("util");
150208
150427
  var childrenIgnored = common.childrenIgnored;
150209
150428
  var isIgnored = common.isIgnored;
@@ -150535,7 +150754,7 @@ var require_glob = __commonJS({
150535
150754
  return this._readdir(abs, false, cb);
150536
150755
  var lstatkey = "lstat\0" + abs;
150537
150756
  var self2 = this;
150538
- var lstatcb = inflight(lstatkey, lstatcb_);
150757
+ var lstatcb = inflight2(lstatkey, lstatcb_);
150539
150758
  if (lstatcb)
150540
150759
  fs16.lstat(abs, lstatcb);
150541
150760
  function lstatcb_(er, lstat) {
@@ -150554,7 +150773,7 @@ var require_glob = __commonJS({
150554
150773
  Glob.prototype._readdir = function(abs, inGlobStar, cb) {
150555
150774
  if (this.aborted)
150556
150775
  return;
150557
- cb = inflight("readdir\0" + abs + "\0" + inGlobStar, cb);
150776
+ cb = inflight2("readdir\0" + abs + "\0" + inGlobStar, cb);
150558
150777
  if (!cb)
150559
150778
  return;
150560
150779
  if (inGlobStar && !ownProp(this.symlinks, abs))
@@ -150712,7 +150931,7 @@ var require_glob = __commonJS({
150712
150931
  }
150713
150932
  }
150714
150933
  var self2 = this;
150715
- var statcb = inflight("stat\0" + abs, lstatcb_);
150934
+ var statcb = inflight2("stat\0" + abs, lstatcb_);
150716
150935
  if (statcb)
150717
150936
  fs16.lstat(abs, statcb);
150718
150937
  function lstatcb_(er, lstat) {
@@ -174311,6 +174530,12 @@ async function mountFrameworkRoutes() {
174311
174530
  } catch (searchError) {
174312
174531
  logger.warn(`SearchIndex initialization failed: ${searchError instanceof Error ? searchError.message : String(searchError)}`);
174313
174532
  }
174533
+ try {
174534
+ const { subscribeModelOverviewCache: subscribeModelOverviewCache2 } = await Promise.resolve().then(() => (init_modelOverviewCache(), modelOverviewCache_exports));
174535
+ subscribeModelOverviewCache2(projection);
174536
+ } catch (cacheError) {
174537
+ logger.warn(`ModelOverviewCache subscription failed: ${cacheError instanceof Error ? cacheError.message : String(cacheError)}`);
174538
+ }
174314
174539
  } catch (e) {
174315
174540
  logger.warn(`Projection/UuidIndex initialization failed: ${e instanceof Error ? e.message : String(e)}`);
174316
174541
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hamak/smart-data-dico",
3
- "version": "1.20.0",
3
+ "version": "1.22.0",
4
4
  "description": "Collaborative data dictionary management system — model, document, and govern your data landscape",
5
5
  "type": "module",
6
6
  "bin": {