@hamak/smart-data-dico 1.12.2 → 1.12.4

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.
@@ -24921,7 +24921,7 @@ var require_main = __commonJS({
24921
24921
  }
24922
24922
  }
24923
24923
  __name(configDotenv, "configDotenv");
24924
- function config3(options2) {
24924
+ function config4(options2) {
24925
24925
  if (_dotenvKey(options2).length === 0) {
24926
24926
  return DotenvModule.configDotenv(options2);
24927
24927
  }
@@ -24932,7 +24932,7 @@ var require_main = __commonJS({
24932
24932
  }
24933
24933
  return DotenvModule._configVault(options2);
24934
24934
  }
24935
- __name(config3, "config");
24935
+ __name(config4, "config");
24936
24936
  function decrypt(encrypted, keyStr) {
24937
24937
  const key = Buffer.from(keyStr.slice(-64), "hex");
24938
24938
  let ciphertext = Buffer.from(encrypted, "base64");
@@ -24991,7 +24991,7 @@ var require_main = __commonJS({
24991
24991
  configDotenv,
24992
24992
  _configVault,
24993
24993
  _parseVault,
24994
- config: config3,
24994
+ config: config4,
24995
24995
  decrypt,
24996
24996
  parse: parse6,
24997
24997
  populate
@@ -37657,13 +37657,15 @@ function normalizeRelationshipEnds(rel) {
37657
37657
  entity: rel.source.entity,
37658
37658
  cardinality: rel.source.cardinality,
37659
37659
  role: rel.source.name,
37660
- referenceAttributes: rel.source.referenceAttributes
37660
+ referenceAttributes: rel.source.referenceAttributes,
37661
+ stereotype: rel.source.stereotype
37661
37662
  },
37662
37663
  {
37663
37664
  entity: rel.target.entity,
37664
37665
  cardinality: rel.target.cardinality,
37665
37666
  role: rel.target.name,
37666
- referenceAttributes: rel.target.referenceAttributes
37667
+ referenceAttributes: rel.target.referenceAttributes,
37668
+ stereotype: rel.target.stereotype
37667
37669
  }
37668
37670
  ];
37669
37671
  }
@@ -37675,8 +37677,8 @@ function normalizeRelationship(rel) {
37675
37677
  return {
37676
37678
  ...rel,
37677
37679
  ends: hasEnds ? rel.ends : [a, b],
37678
- source: rel.source ?? { entity: a.entity, cardinality: a.cardinality, name: a.role, referenceAttributes: a.referenceAttributes },
37679
- target: rel.target ?? { entity: b.entity, cardinality: b.cardinality, name: b.role, referenceAttributes: b.referenceAttributes }
37680
+ source: rel.source ?? { entity: a.entity, cardinality: a.cardinality, name: a.role, referenceAttributes: a.referenceAttributes, stereotype: a.stereotype },
37681
+ target: rel.target ?? { entity: b.entity, cardinality: b.cardinality, name: b.role, referenceAttributes: b.referenceAttributes, stereotype: b.stereotype }
37680
37682
  };
37681
37683
  }
37682
37684
  function validateEntity(entity) {
@@ -37830,7 +37832,8 @@ var init_EntitySchema = __esm({
37830
37832
  entity: { type: "string" },
37831
37833
  cardinality: { type: "string", enum: Object.values(Cardinality) },
37832
37834
  name: { type: "string" },
37833
- referenceAttributes: { type: "array", items: { type: "string" } }
37835
+ referenceAttributes: { type: "array", items: { type: "string" } },
37836
+ stereotype: { type: "string" }
37834
37837
  }
37835
37838
  },
37836
37839
  target: {
@@ -37840,7 +37843,8 @@ var init_EntitySchema = __esm({
37840
37843
  entity: { type: "string" },
37841
37844
  cardinality: { type: "string", enum: Object.values(Cardinality) },
37842
37845
  name: { type: "string" },
37843
- referenceAttributes: { type: "array", items: { type: "string" } }
37846
+ referenceAttributes: { type: "array", items: { type: "string" } },
37847
+ stereotype: { type: "string" }
37844
37848
  }
37845
37849
  },
37846
37850
  metadata: { type: "array" }
@@ -37853,13 +37857,14 @@ var init_EntitySchema = __esm({
37853
37857
 
37854
37858
  // backend/src/kernel/config.ts
37855
37859
  import path from "path";
37856
- var import_dotenv, isProduction, _dataDir, config;
37860
+ var import_dotenv, isProduction, AI_MAX_STEPS, _dataDir, config;
37857
37861
  var init_config = __esm({
37858
37862
  "backend/src/kernel/config.ts"() {
37859
37863
  "use strict";
37860
37864
  import_dotenv = __toESM(require_main(), 1);
37861
37865
  import_dotenv.default.config();
37862
37866
  isProduction = process.env.NODE_ENV === "production";
37867
+ AI_MAX_STEPS = 500;
37863
37868
  _dataDir = process.env.DATA_DIR || (isProduction ? path.join(process.cwd(), "data-dictionaries") : path.join(process.cwd(), "..", "samples", "eshop"));
37864
37869
  config = {
37865
37870
  /** Server port */
@@ -38702,11 +38707,11 @@ var require_dist3 = __commonJS({
38702
38707
  exports.createDeferred = exports.deferred = void 0;
38703
38708
  function deferred2() {
38704
38709
  let done;
38705
- let fail2;
38710
+ let fail3;
38706
38711
  let status = "pending";
38707
38712
  const promise2 = new Promise((_done, _fail) => {
38708
38713
  done = _done;
38709
- fail2 = _fail;
38714
+ fail3 = _fail;
38710
38715
  });
38711
38716
  return {
38712
38717
  promise: promise2,
@@ -38719,7 +38724,7 @@ var require_dist3 = __commonJS({
38719
38724
  fail(error48) {
38720
38725
  if (status === "pending") {
38721
38726
  status = "rejected";
38722
- fail2(error48);
38727
+ fail3(error48);
38723
38728
  }
38724
38729
  },
38725
38730
  get fulfilled() {
@@ -38891,13 +38896,13 @@ function useMatchesDefault() {
38891
38896
  }
38892
38897
  function createInstanceConfig(...options2) {
38893
38898
  const baseDir = process.cwd();
38894
- const config3 = Object.assign(
38899
+ const config4 = Object.assign(
38895
38900
  { baseDir, ...defaultOptions },
38896
38901
  ...options2.filter((o) => typeof o === "object" && o)
38897
38902
  );
38898
- config3.baseDir = config3.baseDir || baseDir;
38899
- config3.trimmed = config3.trimmed === true;
38900
- return config3;
38903
+ config4.baseDir = config4.baseDir || baseDir;
38904
+ config4.trimmed = config4.trimmed === true;
38905
+ return config4;
38901
38906
  }
38902
38907
  function appendTaskOptions(options2, commands = []) {
38903
38908
  if (!filterPlainObject(options2)) {
@@ -39109,11 +39114,11 @@ function isInteractiveMode(option) {
39109
39114
  return option === "--interactive";
39110
39115
  }
39111
39116
  function configListParser(text2) {
39112
- const config3 = new ConfigList();
39117
+ const config4 = new ConfigList();
39113
39118
  for (const item of configParser(text2)) {
39114
- config3.addValue(item.file, String(item.key), item.value);
39119
+ config4.addValue(item.file, String(item.key), item.value);
39115
39120
  }
39116
- return config3;
39121
+ return config4;
39117
39122
  }
39118
39123
  function configGetParser(text2, key) {
39119
39124
  let value = null;
@@ -39917,11 +39922,11 @@ function version_default() {
39917
39922
  commands: ["--version"],
39918
39923
  format: "utf-8",
39919
39924
  parser: versionParser,
39920
- onError(result, error48, done, fail2) {
39925
+ onError(result, error48, done, fail3) {
39921
39926
  if (result.exitCode === -2) {
39922
39927
  return done(Buffer.from(NOT_INSTALLED));
39923
39928
  }
39924
- fail2(error48);
39929
+ fail3(error48);
39925
39930
  }
39926
39931
  });
39927
39932
  }
@@ -40026,9 +40031,9 @@ function deleteBranchesTask(branches, forceDelete = false) {
40026
40031
  parser(stdOut, stdErr) {
40027
40032
  return parseBranchDeletions(stdOut, stdErr);
40028
40033
  },
40029
- onError({ exitCode, stdOut }, error48, done, fail2) {
40034
+ onError({ exitCode, stdOut }, error48, done, fail3) {
40030
40035
  if (!hasBranchDeletionError(String(error48), exitCode)) {
40031
- return fail2(error48);
40036
+ return fail3(error48);
40032
40037
  }
40033
40038
  done(stdOut);
40034
40039
  }
@@ -40041,9 +40046,9 @@ function deleteBranchTask(branch, forceDelete = false) {
40041
40046
  parser(stdOut, stdErr) {
40042
40047
  return parseBranchDeletions(stdOut, stdErr).branches[branch];
40043
40048
  },
40044
- onError({ exitCode, stdErr, stdOut }, error48, _, fail2) {
40049
+ onError({ exitCode, stdErr, stdOut }, error48, _, fail3) {
40045
40050
  if (!hasBranchDeletionError(String(error48), exitCode)) {
40046
- return fail2(error48);
40051
+ return fail3(error48);
40047
40052
  }
40048
40053
  throw new GitResponseError(
40049
40054
  task.parser(bufferToString(stdOut), bufferToString(stdErr)),
@@ -40114,15 +40119,15 @@ function pullTask(remote, branch, customArgs) {
40114
40119
  parser(stdOut, stdErr) {
40115
40120
  return parsePullResult(stdOut, stdErr);
40116
40121
  },
40117
- onError(result, _error, _done, fail2) {
40122
+ onError(result, _error, _done, fail3) {
40118
40123
  const pullError = parsePullErrorResult(
40119
40124
  bufferToString(result.stdOut),
40120
40125
  bufferToString(result.stdErr)
40121
40126
  );
40122
40127
  if (pullError) {
40123
- return fail2(new GitResponseError(pullError));
40128
+ return fail3(new GitResponseError(pullError));
40124
40129
  }
40125
- fail2(_error);
40130
+ fail3(_error);
40126
40131
  }
40127
40132
  };
40128
40133
  }
@@ -40293,8 +40298,8 @@ function isCloneUploadPackSwitch(char, arg) {
40293
40298
  const cleaned = arg.trim().replace(/\0/g, "");
40294
40299
  return /^(--no)?-{1,2}[\dlsqvnobucj]+(\s|$)/.test(cleaned);
40295
40300
  }
40296
- function preventConfigBuilder(config3, setting, message = String(config3)) {
40297
- const regex = typeof config3 === "string" ? new RegExp(`\\s*${config3}`, "i") : config3;
40301
+ function preventConfigBuilder(config4, setting, message = String(config4)) {
40302
+ const regex = typeof config4 === "string" ? new RegExp(`\\s*${config4}`, "i") : config4;
40298
40303
  return /* @__PURE__ */ __name(function preventCommand(options2, arg, next) {
40299
40304
  if (options2[setting] !== true && isConfigSwitch(arg) && regex.test(next)) {
40300
40305
  throw new GitPluginError(
@@ -40439,15 +40444,15 @@ function toBinaryConfig(input, allowUnsafe) {
40439
40444
  };
40440
40445
  }
40441
40446
  function customBinaryPlugin(plugins, input = ["git"], allowUnsafe = false) {
40442
- let config3 = toBinaryConfig(asArray(input), allowUnsafe);
40447
+ let config4 = toBinaryConfig(asArray(input), allowUnsafe);
40443
40448
  plugins.on("binary", (input2) => {
40444
- config3 = toBinaryConfig(asArray(input2), allowUnsafe);
40449
+ config4 = toBinaryConfig(asArray(input2), allowUnsafe);
40445
40450
  });
40446
40451
  plugins.append("spawn.binary", () => {
40447
- return config3.binary;
40452
+ return config4.binary;
40448
40453
  });
40449
40454
  plugins.append("spawn.args", (data) => {
40450
- return config3.prefix ? [config3.prefix, ...data] : data;
40455
+ return config4.prefix ? [config4.prefix, ...data] : data;
40451
40456
  });
40452
40457
  }
40453
40458
  function isTaskError(result) {
@@ -40464,11 +40469,11 @@ function errorDetectionHandler(overwrite = false, isError = isTaskError, errorMe
40464
40469
  return errorMessage(result);
40465
40470
  };
40466
40471
  }
40467
- function errorDetectionPlugin(config3) {
40472
+ function errorDetectionPlugin(config4) {
40468
40473
  return {
40469
40474
  type: "task.error",
40470
40475
  action(data, context2) {
40471
- const error48 = config3(data.error, {
40476
+ const error48 = config4(data.error, {
40472
40477
  stdErr: context2.stdErr,
40473
40478
  stdOut: context2.stdOut,
40474
40479
  exitCode: context2.exitCode
@@ -40596,30 +40601,30 @@ function suffixPathsPlugin() {
40596
40601
  }
40597
40602
  function gitInstanceFactory(baseDir, options2) {
40598
40603
  const plugins = new PluginStore();
40599
- const config3 = createInstanceConfig(
40604
+ const config4 = createInstanceConfig(
40600
40605
  baseDir && (typeof baseDir === "string" ? { baseDir } : baseDir) || {},
40601
40606
  options2
40602
40607
  );
40603
- if (!folderExists(config3.baseDir)) {
40608
+ if (!folderExists(config4.baseDir)) {
40604
40609
  throw new GitConstructError(
40605
- config3,
40610
+ config4,
40606
40611
  `Cannot use simple-git on a directory that does not exist`
40607
40612
  );
40608
40613
  }
40609
- if (Array.isArray(config3.config)) {
40610
- plugins.add(commandConfigPrefixingPlugin(config3.config));
40614
+ if (Array.isArray(config4.config)) {
40615
+ plugins.add(commandConfigPrefixingPlugin(config4.config));
40611
40616
  }
40612
- plugins.add(blockUnsafeOperationsPlugin(config3.unsafe));
40613
- plugins.add(completionDetectionPlugin(config3.completion));
40614
- config3.abort && plugins.add(abortPlugin(config3.abort));
40615
- config3.progress && plugins.add(progressMonitorPlugin(config3.progress));
40616
- config3.timeout && plugins.add(timeoutPlugin(config3.timeout));
40617
- config3.spawnOptions && plugins.add(spawnOptionsPlugin(config3.spawnOptions));
40617
+ plugins.add(blockUnsafeOperationsPlugin(config4.unsafe));
40618
+ plugins.add(completionDetectionPlugin(config4.completion));
40619
+ config4.abort && plugins.add(abortPlugin(config4.abort));
40620
+ config4.progress && plugins.add(progressMonitorPlugin(config4.progress));
40621
+ config4.timeout && plugins.add(timeoutPlugin(config4.timeout));
40622
+ config4.spawnOptions && plugins.add(spawnOptionsPlugin(config4.spawnOptions));
40618
40623
  plugins.add(suffixPathsPlugin());
40619
40624
  plugins.add(errorDetectionPlugin(errorDetectionHandler(true)));
40620
- config3.errors && plugins.add(errorDetectionPlugin(config3.errors));
40621
- customBinaryPlugin(plugins, config3.binary, config3.unsafe?.allowUnsafeCustomBinary);
40622
- return new Git(config3, plugins);
40625
+ config4.errors && plugins.add(errorDetectionPlugin(config4.errors));
40626
+ customBinaryPlugin(plugins, config4.binary, config4.unsafe?.allowUnsafeCustomBinary);
40627
+ return new Git(config4, plugins);
40623
40628
  }
40624
40629
  var import_file_exists, import_debug, import_promise_deferred, import_promise_deferred2, __defProp2, __getOwnPropDesc2, __getOwnPropNames2, __hasOwnProp2, __esm2, __commonJS2, __export2, __copyProps2, __toCommonJS, cache, init_pathspec, GitError, init_git_error, GitResponseError, init_git_response_error, TaskConfigurationError, init_task_configuration_error, NULL, NOOP, objectToString, init_util, filterArray, filterNumber, filterString, filterStringOrStringArray, filterHasLength, init_argument_filters, ExitCodes, init_exit_codes, GitOutputStreams, init_git_output_streams, LineParser, RemoteLineParser, init_line_parser, defaultOptions, init_simple_git_options, init_task_options, init_task_parser, utils_exports, init_utils, check_is_repo_exports, CheckRepoActions, onError, parser, init_check_is_repo, CleanResponse, removalRegexp, dryRunRemovalRegexp, isFolderRegexp, init_CleanSummary, task_exports, EMPTY_COMMANDS, init_task, clean_exports, CONFIG_ERROR_INTERACTIVE_MODE, CONFIG_ERROR_MODE_REQUIRED, CONFIG_ERROR_UNKNOWN_OPTION, CleanOptions, CleanOptionValues, init_clean, ConfigList, init_ConfigList, GitConfigScope, init_config2, DiffNameStatus, diffNameStatus, init_diff_name_status, disallowedOptions, Query, _a, GrepQuery, init_grep, reset_exports, ResetMode, validResetModes, init_reset, init_git_logger, TasksPendingQueue, init_tasks_pending_queue, GitExecutorChain, init_git_executor_chain, git_executor_exports, GitExecutor, init_git_executor, init_task_callback, init_change_working_directory, init_checkout, parser2, init_count_objects, parsers, init_parse_commit, init_commit, init_first_commit, init_hash_object, InitSummary, initResponseRegex, reInitResponseRegex, init_InitSummary, bareCommand, init_init, logFormatRegex, init_log_format, DiffSummary, init_DiffSummary, statParser, numStatParser, nameOnlyParser, nameStatusParser, diffSummaryParsers, init_parse_diff_summary, START_BOUNDARY, COMMIT_BOUNDARY, SPLITTER, defaultFieldNames, init_parse_list_log_summary, diff_exports, init_diff, excludeOptions, init_log, MergeSummaryConflict, MergeSummaryDetail, init_MergeSummary, PullSummary, PullFailedSummary, init_PullSummary, remoteMessagesObjectParsers, init_parse_remote_objects, parsers2, RemoteMessageSummary, init_parse_remote_messages, FILE_UPDATE_REGEX, SUMMARY_REGEX, ACTION_REGEX, parsers3, errorParsers, parsePullDetail, parsePullResult, init_parse_pull, parsers4, parseMergeResult, parseMergeDetail, init_parse_merge, init_merge, parsers5, parsePushResult, parsePushDetail, init_parse_push, push_exports, init_push, init_show, fromPathRegex, FileStatusSummary, init_FileStatusSummary, StatusSummary, parsers6, parseStatusSummary, init_StatusSummary, ignoredOptions, init_status, NOT_INSTALLED, parsers7, init_version, cloneTask, cloneMirrorTask, init_clone, simple_git_api_exports, SimpleGitApi, init_simple_git_api, scheduler_exports, createScheduledTask, Scheduler, init_scheduler, apply_patch_exports, init_apply_patch, BranchDeletionBatch, init_BranchDeleteSummary, deleteSuccessRegex, deleteErrorRegex, parsers8, parseBranchDeletions, init_parse_branch_delete, BranchSummaryResult, init_BranchSummary, parsers9, currentBranchParser, init_parse_branch, branch_exports, init_branch, parseCheckIgnore, init_CheckIgnore, check_ignore_exports, init_check_ignore, parsers10, init_parse_fetch, fetch_exports, init_fetch, parsers11, init_parse_move, move_exports, init_move, pull_exports, init_pull, init_GetRemoteSummary, remote_exports, init_remote, stash_list_exports, init_stash_list, sub_module_exports, init_sub_module, TagList, parseTagList, init_TagList, tag_exports, init_tag, require_git, GitConstructError, GitPluginError, preventUnsafeConfig, never, WRONG_NUMBER_ERR, WRONG_CHARS_ERR, PluginStore, Git, esm_default;
40625
40630
  var init_esm = __esm({
@@ -40961,11 +40966,11 @@ var init_esm = __esm({
40961
40966
  CheckRepoActions2["IS_REPO_ROOT"] = "root";
40962
40967
  return CheckRepoActions2;
40963
40968
  })(CheckRepoActions || {});
40964
- onError = /* @__PURE__ */ __name(({ exitCode }, error48, done, fail2) => {
40969
+ onError = /* @__PURE__ */ __name(({ exitCode }, error48, done, fail3) => {
40965
40970
  if (exitCode === 128 && isNotRepoMessage(error48)) {
40966
40971
  return done(Buffer.from("false"));
40967
40972
  }
40968
- fail2(error48);
40973
+ fail3(error48);
40969
40974
  }, "onError");
40970
40975
  parser = /* @__PURE__ */ __name((text2) => {
40971
40976
  return text2.trim() === "true";
@@ -41376,7 +41381,7 @@ var init_esm = __esm({
41376
41381
  }
41377
41382
  handleTaskData(task, args, result, logger2) {
41378
41383
  const { exitCode, rejection, stdOut, stdErr } = result;
41379
- return new Promise((done, fail2) => {
41384
+ return new Promise((done, fail3) => {
41380
41385
  logger2(`Preparing to handle process response exitCode=%d stdOut=`, exitCode);
41381
41386
  const { error: error48 } = this._plugins.exec(
41382
41387
  "task.error",
@@ -41401,7 +41406,7 @@ var init_esm = __esm({
41401
41406
  )
41402
41407
  );
41403
41408
  },
41404
- fail2
41409
+ fail3
41405
41410
  );
41406
41411
  }
41407
41412
  if (error48) {
@@ -41411,7 +41416,7 @@ var init_esm = __esm({
41411
41416
  stdErr.length,
41412
41417
  rejection
41413
41418
  );
41414
- return fail2(error48);
41419
+ return fail3(error48);
41415
41420
  }
41416
41421
  logger2.info(`retrieving task output complete`);
41417
41422
  done(new GitOutputStreams(Buffer.concat(stdOut), Buffer.concat(stdErr)));
@@ -43375,9 +43380,9 @@ var init_esm = __esm({
43375
43380
  static {
43376
43381
  __name(this, "GitConstructError");
43377
43382
  }
43378
- constructor(config3, message) {
43383
+ constructor(config4, message) {
43379
43384
  super(void 0, message);
43380
- this.config = config3;
43385
+ this.config = config4;
43381
43386
  }
43382
43387
  };
43383
43388
  init_git_error();
@@ -43791,8 +43796,8 @@ var init_git_service = __esm({
43791
43796
  });
43792
43797
 
43793
43798
  // backend/node_modules/@hamak/ui-remote-git-fs-backend/dist/routes/git-routes.js
43794
- function createGitRoutes(config3) {
43795
- const { gitService, debug: debug2 } = config3;
43799
+ function createGitRoutes(config4) {
43800
+ const { gitService, debug: debug2 } = config4;
43796
43801
  const router28 = (0, import_express2.Router)();
43797
43802
  const log2 = /* @__PURE__ */ __name((message, ...args) => {
43798
43803
  if (debug2) {
@@ -43961,8 +43966,8 @@ var init_git_routes = __esm({
43961
43966
 
43962
43967
  // backend/node_modules/@hamak/ui-remote-git-fs-backend/dist/enrichers/git-file-info-enricher.js
43963
43968
  import path3 from "path";
43964
- function createGitFileInfoEnricher(config3) {
43965
- return new GitFileInfoEnricher(config3);
43969
+ function createGitFileInfoEnricher(config4) {
43970
+ return new GitFileInfoEnricher(config4);
43966
43971
  }
43967
43972
  var GitFileInfoEnricher;
43968
43973
  var init_git_file_info_enricher = __esm({
@@ -43971,13 +43976,13 @@ var init_git_file_info_enricher = __esm({
43971
43976
  static {
43972
43977
  __name(this, "GitFileInfoEnricher");
43973
43978
  }
43974
- constructor(config3) {
43979
+ constructor(config4) {
43975
43980
  this.extensionKey = "git";
43976
43981
  this.priority = 50;
43977
43982
  this.statusCache = /* @__PURE__ */ new Map();
43978
43983
  this.cacheTimeout = 5e3;
43979
- this.gitService = config3.gitService;
43980
- this.workspaceRoots = config3.workspaceRoots;
43984
+ this.gitService = config4.gitService;
43985
+ this.workspaceRoots = config4.workspaceRoots;
43981
43986
  }
43982
43987
  /**
43983
43988
  * Check if git enrichment is requested
@@ -47035,7 +47040,7 @@ var init_caseService = __esm({
47035
47040
  }
47036
47041
  const visitedEntities = /* @__PURE__ */ new Set();
47037
47042
  while (queue.length > 0) {
47038
- const { entityUuid, hopDistance, pathSegments, usedRelationships, inboundNav } = queue.shift();
47043
+ const { entityUuid, hopDistance, pathSegments, usedRelationships, inboundNav, inboundIsComposition, inboundIsManual } = queue.shift();
47039
47044
  if (visitedEntities.has(entityUuid)) continue;
47040
47045
  visitedEntities.add(entityUuid);
47041
47046
  const currentPath = pathSegments.join("/");
@@ -47053,7 +47058,8 @@ var init_caseService = __esm({
47053
47058
  hopDistance,
47054
47059
  isRoot: hopDistance === 0,
47055
47060
  isFrontier,
47056
- isManualInclusion: false,
47061
+ isManualInclusion: inboundIsManual === true,
47062
+ isComposition: hopDistance === 0 ? void 0 : inboundIsComposition === true,
47057
47063
  attributes: info.attributes,
47058
47064
  metadata: info.metadata.length > 0 ? info.metadata : void 0
47059
47065
  };
@@ -47067,23 +47073,54 @@ var init_caseService = __esm({
47067
47073
  resolvedNodes.push(resolved);
47068
47074
  if (isFrontier) continue;
47069
47075
  const neighbors = adjacency.get(entityUuid) || [];
47070
- for (const { neighborUuid, navName, relationshipUuid, fromCard, toCard } of neighbors) {
47076
+ const byNeighbor = /* @__PURE__ */ new Map();
47077
+ for (const edge of neighbors) {
47078
+ if (!byNeighbor.has(edge.neighborUuid)) byNeighbor.set(edge.neighborUuid, []);
47079
+ byNeighbor.get(edge.neighborUuid).push(edge);
47080
+ }
47081
+ for (const [neighborUuid, parallelEdges] of byNeighbor) {
47071
47082
  if (visitedEntities.has(neighborUuid)) continue;
47072
- if (usedRelationships.has(relationshipUuid)) continue;
47083
+ const edges = parallelEdges.filter((e) => !usedRelationships.has(e.relationshipUuid));
47084
+ if (edges.length === 0) continue;
47073
47085
  const neighborInfo = entityMap.get(neighborUuid);
47074
47086
  if (!neighborInfo) continue;
47075
47087
  const newPath = [...pathSegments, neighborInfo.name];
47076
47088
  const newPathStr = newPath.join("/");
47077
47089
  const prefixNode = nodesByPath.get(newPathStr);
47078
47090
  if (prefixNode?.exclude) continue;
47091
+ const edge = edges.find((e) => e.isComposition) ?? edges.find((e) => e.navName) ?? edges[0];
47092
+ const isComposition = edge.isComposition;
47093
+ const cross = prefixNode?.traverse ?? isComposition;
47094
+ if (!cross) {
47095
+ resolvedNodes.push({
47096
+ entityUuid: neighborUuid,
47097
+ entityName: neighborInfo.name,
47098
+ service: neighborInfo.service,
47099
+ path: newPathStr,
47100
+ hopDistance: hopDistance + 1,
47101
+ isRoot: false,
47102
+ isFrontier: true,
47103
+ isManualInclusion: false,
47104
+ isComposition,
47105
+ isExpandable: true,
47106
+ navName: edge.navName,
47107
+ navCardinality: { from: edge.fromCard, to: edge.toCard },
47108
+ attributes: neighborInfo.attributes,
47109
+ metadata: neighborInfo.metadata.length > 0 ? neighborInfo.metadata : void 0
47110
+ });
47111
+ continue;
47112
+ }
47079
47113
  const newUsed = new Set(usedRelationships);
47080
- newUsed.add(relationshipUuid);
47114
+ newUsed.add(edge.relationshipUuid);
47081
47115
  queue.push({
47082
47116
  entityUuid: neighborUuid,
47083
47117
  hopDistance: hopDistance + 1,
47084
47118
  pathSegments: newPath,
47085
47119
  usedRelationships: newUsed,
47086
- inboundNav: { navName, fromCard, toCard }
47120
+ inboundNav: { navName: edge.navName, fromCard: edge.fromCard, toCard: edge.toCard },
47121
+ inboundIsComposition: isComposition,
47122
+ // Manual inclusion = the user force-expanded a non-composition edge.
47123
+ inboundIsManual: prefixNode?.traverse === true && !isComposition
47087
47124
  });
47088
47125
  }
47089
47126
  }
@@ -47160,16 +47197,18 @@ var init_caseService = __esm({
47160
47197
  for (const { relationships } of allRels) {
47161
47198
  for (const rel of relationships) {
47162
47199
  const [endA, endB] = normalizeRelationshipEnds(rel);
47163
- const fallback = rel.description || rel.uuid;
47164
- const roleA = endA.role || fallback;
47165
- const roleB = endB.role || fallback;
47200
+ const roleA = endA.role;
47201
+ const roleB = endB.role;
47202
+ const aIsOwner = endA.stereotype === "composition";
47203
+ const bIsOwner = endB.stereotype === "composition";
47166
47204
  if (!adjacency.has(endA.entity)) adjacency.set(endA.entity, []);
47167
47205
  adjacency.get(endA.entity).push({
47168
47206
  neighborUuid: endB.entity,
47169
47207
  navName: roleA,
47170
47208
  relationshipUuid: rel.uuid,
47171
47209
  fromCard: endA.cardinality,
47172
- toCard: endB.cardinality
47210
+ toCard: endB.cardinality,
47211
+ isComposition: aIsOwner
47173
47212
  });
47174
47213
  if (!adjacency.has(endB.entity)) adjacency.set(endB.entity, []);
47175
47214
  adjacency.get(endB.entity).push({
@@ -47177,7 +47216,8 @@ var init_caseService = __esm({
47177
47216
  navName: roleB,
47178
47217
  relationshipUuid: rel.uuid,
47179
47218
  fromCard: endB.cardinality,
47180
- toCard: endA.cardinality
47219
+ toCard: endA.cardinality,
47220
+ isComposition: bIsOwner
47181
47221
  });
47182
47222
  }
47183
47223
  }
@@ -47976,6 +48016,155 @@ var init_serviceService = __esm({
47976
48016
  }
47977
48017
  });
47978
48018
 
48019
+ // backend/src/services/dicoConfigService.ts
48020
+ async function readConfig() {
48021
+ try {
48022
+ const raw = await storageRegistry.getBackend().read(DICT_WS2, CONFIG_PATH);
48023
+ const parsed = JSON.parse(raw);
48024
+ if (typeof parsed.version !== "number") parsed.version = 1;
48025
+ return parsed;
48026
+ } catch (e) {
48027
+ if (e.code === "not-found") return { version: 1 };
48028
+ logger.error(`Failed to read dico.config.json: ${e}`);
48029
+ return { version: 1 };
48030
+ }
48031
+ }
48032
+ async function writeConfig(next) {
48033
+ const body = JSON.stringify(next, null, 2) + "\n";
48034
+ await storageRegistry.getBackend().write(DICT_WS2, CONFIG_PATH, body);
48035
+ }
48036
+ async function listDerivedTypes() {
48037
+ const cfg = await readConfig();
48038
+ return Array.isArray(cfg.types) ? cfg.types : [];
48039
+ }
48040
+ async function replaceDerivedTypes(next) {
48041
+ const errors = validateDerivedTypes(next);
48042
+ if (errors.length > 0) return { success: false, errors };
48043
+ const cfg = await readConfig();
48044
+ cfg.types = next;
48045
+ await writeConfig(cfg);
48046
+ return { success: true };
48047
+ }
48048
+ function validateDerivedTypes(types) {
48049
+ const errors = [];
48050
+ const byName = /* @__PURE__ */ new Map();
48051
+ for (const t of types) {
48052
+ if (!t?.name || typeof t.name !== "string") {
48053
+ errors.push("Each derived type must have a `name` string");
48054
+ continue;
48055
+ }
48056
+ if (STANDARD_TYPES.has(t.name)) {
48057
+ errors.push(`Derived type name '${t.name}' shadows a standard AttributeType`);
48058
+ }
48059
+ if (byName.has(t.name)) {
48060
+ errors.push(`Duplicate derived type name: '${t.name}'`);
48061
+ } else {
48062
+ byName.set(t.name, t);
48063
+ }
48064
+ if (!t.basedOn || typeof t.basedOn !== "string") {
48065
+ errors.push(`Derived type '${t.name}' must declare a \`basedOn\``);
48066
+ }
48067
+ if (t.domain) errors.push(...validateDomain(t.name, t.domain));
48068
+ }
48069
+ for (const t of types) {
48070
+ if (!t?.name || !t?.basedOn) continue;
48071
+ const visited = /* @__PURE__ */ new Set();
48072
+ let cursor = t.basedOn;
48073
+ while (cursor && !STANDARD_TYPES.has(cursor)) {
48074
+ if (visited.has(cursor)) {
48075
+ errors.push(`Circular derivation starting at '${t.name}' (cycle via '${cursor}')`);
48076
+ break;
48077
+ }
48078
+ visited.add(cursor);
48079
+ const next = byName.get(cursor);
48080
+ if (!next) {
48081
+ errors.push(`Derived type '${t.name}' references unknown type '${cursor}'`);
48082
+ break;
48083
+ }
48084
+ cursor = next.basedOn;
48085
+ }
48086
+ }
48087
+ return errors;
48088
+ }
48089
+ function validateDomain(typeName, domain2) {
48090
+ const errors = [];
48091
+ if (!DOMAIN_KINDS.has(domain2.kind)) {
48092
+ errors.push(`Derived type '${typeName}' has invalid domain kind '${domain2.kind}'`);
48093
+ return errors;
48094
+ }
48095
+ const hasValues = Array.isArray(domain2.values) && domain2.values.length > 0;
48096
+ const hasSource = typeof domain2.source === "string" && domain2.source.trim().length > 0;
48097
+ if (domain2.kind === "enum") {
48098
+ if (!hasValues) errors.push(`Enum domain '${typeName}' must list at least one value`);
48099
+ if (hasSource) errors.push(`Enum domain '${typeName}' must not declare a \`source\``);
48100
+ } else if (domain2.kind === "codelist") {
48101
+ if (!hasSource) errors.push(`Codelist domain '${typeName}' must declare a \`source\` name`);
48102
+ } else if (domain2.kind === "reference") {
48103
+ if (!hasSource) errors.push(`Reference domain '${typeName}' must declare a \`source\` name`);
48104
+ if (hasValues) errors.push(`Reference domain '${typeName}' must not carry inline \`values\` (they come from the source)`);
48105
+ }
48106
+ return errors;
48107
+ }
48108
+ function resolveDomain(typeName, derivedTypes) {
48109
+ if (STANDARD_TYPES.has(typeName)) return null;
48110
+ const byName = new Map(derivedTypes.map((t) => [t.name, t]));
48111
+ const visited = /* @__PURE__ */ new Set();
48112
+ let cursor = typeName;
48113
+ while (!STANDARD_TYPES.has(cursor)) {
48114
+ if (visited.has(cursor)) return null;
48115
+ visited.add(cursor);
48116
+ const dt = byName.get(cursor);
48117
+ if (!dt) return null;
48118
+ if (dt.domain) return dt.domain;
48119
+ cursor = dt.basedOn;
48120
+ }
48121
+ return null;
48122
+ }
48123
+ function resolveAttributeType(typeName, derivedTypes) {
48124
+ if (STANDARD_TYPES.has(typeName)) {
48125
+ return { baseType: typeName, validation: {} };
48126
+ }
48127
+ const byName = new Map(derivedTypes.map((t) => [t.name, t]));
48128
+ const chain = [];
48129
+ const visited = /* @__PURE__ */ new Set();
48130
+ let cursor = typeName;
48131
+ while (!STANDARD_TYPES.has(cursor)) {
48132
+ if (visited.has(cursor)) return null;
48133
+ visited.add(cursor);
48134
+ const dt = byName.get(cursor);
48135
+ if (!dt) return null;
48136
+ chain.push(dt);
48137
+ cursor = dt.basedOn;
48138
+ }
48139
+ const merged = {};
48140
+ for (let i = chain.length - 1; i >= 0; i--) {
48141
+ Object.assign(merged, chain[i].validation || {});
48142
+ }
48143
+ return { baseType: cursor, validation: merged };
48144
+ }
48145
+ var DOMAIN_KINDS, DICT_WS2, CONFIG_PATH, STANDARD_TYPES;
48146
+ var init_dicoConfigService = __esm({
48147
+ "backend/src/services/dicoConfigService.ts"() {
48148
+ "use strict";
48149
+ init_EntitySchema();
48150
+ init_logger();
48151
+ init_StorageBackendToken();
48152
+ init_types();
48153
+ DOMAIN_KINDS = /* @__PURE__ */ new Set(["enum", "codelist", "reference"]);
48154
+ DICT_WS2 = wsId("dictionaries");
48155
+ CONFIG_PATH = pathOf("dico.config.json");
48156
+ STANDARD_TYPES = new Set(Object.values(AttributeType));
48157
+ __name(readConfig, "readConfig");
48158
+ __name(writeConfig, "writeConfig");
48159
+ __name(listDerivedTypes, "listDerivedTypes");
48160
+ __name(replaceDerivedTypes, "replaceDerivedTypes");
48161
+ __name(validateDerivedTypes, "validateDerivedTypes");
48162
+ __name(validateDomain, "validateDomain");
48163
+ __name(resolveDomain, "resolveDomain");
48164
+ __name(resolveAttributeType, "resolveAttributeType");
48165
+ }
48166
+ });
48167
+
47979
48168
  // backend/src/services/versionService.ts
47980
48169
  var versionService_exports = {};
47981
48170
  __export(versionService_exports, {
@@ -49030,10 +49219,10 @@ function prefixIssues(path14, issues) {
49030
49219
  function unwrapMessage(message) {
49031
49220
  return typeof message === "string" ? message : message?.message;
49032
49221
  }
49033
- function finalizeIssue(iss, ctx, config3) {
49222
+ function finalizeIssue(iss, ctx, config4) {
49034
49223
  const full = { ...iss, path: iss.path ?? [] };
49035
49224
  if (!iss.message) {
49036
- const message = unwrapMessage(iss.inst?._zod.def?.error?.(iss)) ?? unwrapMessage(ctx?.error?.(iss)) ?? unwrapMessage(config3.customError?.(iss)) ?? unwrapMessage(config3.localeError?.(iss)) ?? "Invalid input";
49225
+ const message = unwrapMessage(iss.inst?._zod.def?.error?.(iss)) ?? unwrapMessage(ctx?.error?.(iss)) ?? unwrapMessage(config4.customError?.(iss)) ?? unwrapMessage(config4.localeError?.(iss)) ?? "Invalid input";
49037
49226
  full.message = message;
49038
49227
  }
49039
49228
  delete full.inst;
@@ -70145,13 +70334,13 @@ var require_auth_config = __commonJS({
70145
70334
  }
70146
70335
  }
70147
70336
  __name(readAuthConfig, "readAuthConfig");
70148
- function writeAuthConfig(config3) {
70337
+ function writeAuthConfig(config4) {
70149
70338
  const authPath = getAuthConfigPath();
70150
70339
  const authDir = path14.dirname(authPath);
70151
70340
  if (!fs6.existsSync(authDir)) {
70152
70341
  fs6.mkdirSync(authDir, { mode: 504, recursive: true });
70153
70342
  }
70154
- fs6.writeFileSync(authPath, JSON.stringify(config3, null, 2), { mode: 384 });
70343
+ fs6.writeFileSync(authPath, JSON.stringify(config4, null, 2), { mode: 384 });
70155
70344
  }
70156
70345
  __name(writeAuthConfig, "writeAuthConfig");
70157
70346
  function isValidAccessToken(authConfig) {
@@ -71297,8 +71486,8 @@ Run 'npx vercel link' to link your project, then 'vc env pull' to fetch the toke
71297
71486
  static {
71298
71487
  __name(this, "GatewayFetchMetadata");
71299
71488
  }
71300
- constructor(config3) {
71301
- this.config = config3;
71489
+ constructor(config4) {
71490
+ this.config = config4;
71302
71491
  }
71303
71492
  async getAvailableModels() {
71304
71493
  try {
@@ -71387,8 +71576,8 @@ Run 'npx vercel link' to link your project, then 'vc env pull' to fetch the toke
71387
71576
  static {
71388
71577
  __name(this, "GatewaySpendReport");
71389
71578
  }
71390
- constructor(config3) {
71391
- this.config = config3;
71579
+ constructor(config4) {
71580
+ this.config = config4;
71392
71581
  }
71393
71582
  async getSpendReport(params) {
71394
71583
  try {
@@ -71488,8 +71677,8 @@ Run 'npx vercel link' to link your project, then 'vc env pull' to fetch the toke
71488
71677
  static {
71489
71678
  __name(this, "GatewayGenerationInfoFetcher");
71490
71679
  }
71491
- constructor(config3) {
71492
- this.config = config3;
71680
+ constructor(config4) {
71681
+ this.config = config4;
71493
71682
  }
71494
71683
  async getGenerationInfo(params) {
71495
71684
  try {
@@ -71574,9 +71763,9 @@ Run 'npx vercel link' to link your project, then 'vc env pull' to fetch the toke
71574
71763
  static {
71575
71764
  __name(this, "GatewayLanguageModel");
71576
71765
  }
71577
- constructor(modelId, config3) {
71766
+ constructor(modelId, config4) {
71578
71767
  this.modelId = modelId;
71579
- this.config = config3;
71768
+ this.config = config4;
71580
71769
  this.specificationVersion = "v3";
71581
71770
  this.supportedUrls = { "*/*": [/.*/] };
71582
71771
  }
@@ -71722,9 +71911,9 @@ Run 'npx vercel link' to link your project, then 'vc env pull' to fetch the toke
71722
71911
  static {
71723
71912
  __name(this, "GatewayEmbeddingModel");
71724
71913
  }
71725
- constructor(modelId, config3) {
71914
+ constructor(modelId, config4) {
71726
71915
  this.modelId = modelId;
71727
- this.config = config3;
71916
+ this.config = config4;
71728
71917
  this.specificationVersion = "v3";
71729
71918
  this.maxEmbeddingsPerCall = 2048;
71730
71919
  this.supportsParallelCalls = true;
@@ -71801,9 +71990,9 @@ Run 'npx vercel link' to link your project, then 'vc env pull' to fetch the toke
71801
71990
  static {
71802
71991
  __name(this, "GatewayImageModel");
71803
71992
  }
71804
- constructor(modelId, config3) {
71993
+ constructor(modelId, config4) {
71805
71994
  this.modelId = modelId;
71806
- this.config = config3;
71995
+ this.config = config4;
71807
71996
  this.specificationVersion = "v3";
71808
71997
  this.maxImagesPerCall = Number.MAX_SAFE_INTEGER;
71809
71998
  }
@@ -71927,9 +72116,9 @@ Run 'npx vercel link' to link your project, then 'vc env pull' to fetch the toke
71927
72116
  static {
71928
72117
  __name(this, "GatewayVideoModel");
71929
72118
  }
71930
- constructor(modelId, config3) {
72119
+ constructor(modelId, config4) {
71931
72120
  this.modelId = modelId;
71932
- this.config = config3;
72121
+ this.config = config4;
71933
72122
  this.specificationVersion = "v3";
71934
72123
  this.maxVideosPerCall = Number.MAX_SAFE_INTEGER;
71935
72124
  }
@@ -72187,7 +72376,7 @@ Run 'npx vercel link' to link your project, then 'vc env pull' to fetch the toke
72187
72376
  inputSchema: parallelSearchInputSchema,
72188
72377
  outputSchema: parallelSearchOutputSchema
72189
72378
  });
72190
- parallelSearch = /* @__PURE__ */ __name((config3 = {}) => parallelSearchToolFactory(config3), "parallelSearch");
72379
+ parallelSearch = /* @__PURE__ */ __name((config4 = {}) => parallelSearchToolFactory(config4), "parallelSearch");
72191
72380
  perplexitySearchInputSchema = lazySchema(
72192
72381
  () => zodSchema(
72193
72382
  external_exports.object({
@@ -72266,7 +72455,7 @@ Run 'npx vercel link' to link your project, then 'vc env pull' to fetch the toke
72266
72455
  inputSchema: perplexitySearchInputSchema,
72267
72456
  outputSchema: perplexitySearchOutputSchema
72268
72457
  });
72269
- perplexitySearch = /* @__PURE__ */ __name((config3 = {}) => perplexitySearchToolFactory(config3), "perplexitySearch");
72458
+ perplexitySearch = /* @__PURE__ */ __name((config4 = {}) => perplexitySearchToolFactory(config4), "perplexitySearch");
72270
72459
  gatewayTools = {
72271
72460
  /**
72272
72461
  * Search the web using Parallel AI's Search API for LLM-optimized excerpts.
@@ -81337,9 +81526,9 @@ function readAppConfig() {
81337
81526
  if (!fs.existsSync(CONFIG_FILE) && fs.existsSync(LEGACY_CONFIG)) {
81338
81527
  try {
81339
81528
  const legacy = JSON.parse(fs.readFileSync(LEGACY_CONFIG, "utf8"));
81340
- const config3 = { ai: legacy };
81341
- writeConfigFileAtomic(JSON.stringify(config3, null, 2));
81342
- return config3;
81529
+ const config4 = { ai: legacy };
81530
+ writeConfigFileAtomic(JSON.stringify(config4, null, 2));
81531
+ return config4;
81343
81532
  } catch {
81344
81533
  }
81345
81534
  }
@@ -81359,8 +81548,8 @@ function writeAppConfig(updates) {
81359
81548
  writeConfigFileAtomic(JSON.stringify(merged, null, 2));
81360
81549
  }
81361
81550
  function getConfigSection(section) {
81362
- const config3 = readAppConfig();
81363
- return config3[section];
81551
+ const config4 = readAppConfig();
81552
+ return config4[section];
81364
81553
  }
81365
81554
  function setConfigSection(section, value) {
81366
81555
  writeAppConfig({ [section]: value });
@@ -98199,21 +98388,21 @@ var init_client2 = __esm({
98199
98388
  * Handlers are silently skipped if the server doesn't advertise the corresponding listChanged capability.
98200
98389
  * @internal
98201
98390
  */
98202
- _setupListChangedHandlers(config3) {
98203
- if (config3.tools && this._serverCapabilities?.tools?.listChanged) {
98204
- this._setupListChangedHandler("tools", ToolListChangedNotificationSchema, config3.tools, async () => {
98391
+ _setupListChangedHandlers(config4) {
98392
+ if (config4.tools && this._serverCapabilities?.tools?.listChanged) {
98393
+ this._setupListChangedHandler("tools", ToolListChangedNotificationSchema, config4.tools, async () => {
98205
98394
  const result = await this.listTools();
98206
98395
  return result.tools;
98207
98396
  });
98208
98397
  }
98209
- if (config3.prompts && this._serverCapabilities?.prompts?.listChanged) {
98210
- this._setupListChangedHandler("prompts", PromptListChangedNotificationSchema, config3.prompts, async () => {
98398
+ if (config4.prompts && this._serverCapabilities?.prompts?.listChanged) {
98399
+ this._setupListChangedHandler("prompts", PromptListChangedNotificationSchema, config4.prompts, async () => {
98211
98400
  const result = await this.listPrompts();
98212
98401
  return result.prompts;
98213
98402
  });
98214
98403
  }
98215
- if (config3.resources && this._serverCapabilities?.resources?.listChanged) {
98216
- this._setupListChangedHandler("resources", ResourceListChangedNotificationSchema, config3.resources, async () => {
98404
+ if (config4.resources && this._serverCapabilities?.resources?.listChanged) {
98405
+ this._setupListChangedHandler("resources", ResourceListChangedNotificationSchema, config4.resources, async () => {
98217
98406
  const result = await this.listResources();
98218
98407
  return result.resources;
98219
98408
  });
@@ -101124,6 +101313,443 @@ var init_mcpClientRegistry = __esm({
101124
101313
  }
101125
101314
  });
101126
101315
 
101316
+ // backend/src/controllers/aiMutationTools.ts
101317
+ function fail2(error48) {
101318
+ return { success: false, error: error48 };
101319
+ }
101320
+ function cardinalityLabel(c) {
101321
+ return c === "many" /* MANY */ || c === "many" ? "0..*" : "1";
101322
+ }
101323
+ async function ensurePackage(packageName) {
101324
+ const { listPackages: listPackages2, ensurePackageDirectoryStructure: ensurePackageDirectoryStructure2 } = await Promise.resolve().then(() => (init_fileOperations(), fileOperations_exports));
101325
+ const existing = await listPackages2();
101326
+ if (!existing.includes(packageName)) {
101327
+ await ensurePackageDirectoryStructure2(packageName);
101328
+ }
101329
+ }
101330
+ async function packageExists(packageName) {
101331
+ const { listPackages: listPackages2 } = await Promise.resolve().then(() => (init_fileOperations(), fileOperations_exports));
101332
+ const existing = await listPackages2();
101333
+ return existing.includes(packageName);
101334
+ }
101335
+ function buildEntity(input, existing) {
101336
+ const existingByName = new Map((existing?.attributes ?? []).map((a) => [a.name, a]));
101337
+ const attributes = input.attributes.map((a) => {
101338
+ const prior = existingByName.get(a.name);
101339
+ return {
101340
+ uuid: prior?.uuid ?? generateUUID(),
101341
+ name: a.name,
101342
+ type: a.type,
101343
+ description: a.description ?? "",
101344
+ required: a.required ?? false,
101345
+ ...a.primaryKey !== void 0 ? { primaryKey: a.primaryKey } : {},
101346
+ ...a.enumValues ? { validation: { enumValues: a.enumValues } } : {}
101347
+ };
101348
+ });
101349
+ return {
101350
+ uuid: existing?.uuid ?? generateUUID(),
101351
+ name: input.name,
101352
+ description: input.description ?? existing?.description ?? "",
101353
+ ...input.stereotype !== void 0 ? { stereotype: input.stereotype } : existing?.stereotype ? { stereotype: existing.stereotype } : {},
101354
+ status: existing?.status ?? "draft" /* DRAFT */,
101355
+ attributes,
101356
+ createdAt: existing?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
101357
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
101358
+ };
101359
+ }
101360
+ async function validateEntityMutation(input, entity, services, kind) {
101361
+ if (kind === "update" && !await packageExists(input.packageName)) {
101362
+ return { ok: false, error: `Package "${input.packageName}" does not exist.` };
101363
+ }
101364
+ const seen = /* @__PURE__ */ new Set();
101365
+ for (const a of input.attributes) {
101366
+ if (seen.has(a.name)) {
101367
+ return { ok: false, error: `Duplicate attribute name "${a.name}" in entity ${input.name}.` };
101368
+ }
101369
+ seen.add(a.name);
101370
+ }
101371
+ const derivedTypes = await listDerivedTypes();
101372
+ for (const a of input.attributes) {
101373
+ if (resolveAttributeType(a.type, derivedTypes) == null) {
101374
+ return {
101375
+ ok: false,
101376
+ error: `Attribute "${a.name}" has unknown type "${a.type}". Use a standard AttributeType (${Object.values(AttributeType).join(", ")}) or a defined derived type.`
101377
+ };
101378
+ }
101379
+ }
101380
+ if (input.stereotype) {
101381
+ const stereotypes = await services.stereotypeService.getAllStereotypes("entity");
101382
+ const known = stereotypes.some((s) => s.id === input.stereotype || s.name === input.stereotype);
101383
+ if (!known) {
101384
+ const ids = stereotypes.map((s) => s.id).join(", ") || "(none defined)";
101385
+ return { ok: false, error: `Unknown entity stereotype "${input.stereotype}". Known: ${ids}.` };
101386
+ }
101387
+ }
101388
+ if (kind === "create") {
101389
+ const existing = await services.serviceService.getEntitySchema(input.packageName, input.name);
101390
+ if (existing) {
101391
+ return { ok: false, error: `Entity "${input.name}" already exists in package "${input.packageName}".` };
101392
+ }
101393
+ }
101394
+ const schemaResult = validateEntity(entity);
101395
+ if (!schemaResult.valid) {
101396
+ return { ok: false, error: `Entity failed schema validation: ${schemaResult.errors.join("; ")}` };
101397
+ }
101398
+ return { ok: true };
101399
+ }
101400
+ async function executeCreateEntity(input, services) {
101401
+ try {
101402
+ await ensurePackage(input.packageName);
101403
+ const entity = buildEntity(input);
101404
+ const validation = await validateEntityMutation(input, entity, services, "create");
101405
+ if (!validation.ok) return fail2(validation.error);
101406
+ const result = await services.serviceService.createEntity(input.packageName, entity);
101407
+ if (!result.success) return fail2(result.errors.join("; ") || "Failed to create entity.");
101408
+ const attrCount = entity.attributes.length;
101409
+ const stereoNote = entity.stereotype ? `, stereotype ${entity.stereotype}` : "";
101410
+ const summary = `Created entity ${entity.name} (+${attrCount} attribute${attrCount === 1 ? "" : "s"}${stereoNote})`;
101411
+ return {
101412
+ success: true,
101413
+ changeKind: "created",
101414
+ elementType: "entity",
101415
+ name: entity.name,
101416
+ packageName: input.packageName,
101417
+ summary,
101418
+ navigate: `/packages/${input.packageName}/entities/${entity.name}`,
101419
+ highlight: entity.name,
101420
+ message: summary
101421
+ };
101422
+ } catch (err) {
101423
+ return fail2(err instanceof Error ? err.message : String(err));
101424
+ }
101425
+ }
101426
+ async function executeUpdateEntity(input, services) {
101427
+ try {
101428
+ const existing = await services.serviceService.getEntitySchema(input.packageName, input.name);
101429
+ if (!existing) {
101430
+ return fail2(`Entity "${input.name}" not found in package "${input.packageName}".`);
101431
+ }
101432
+ const entity = buildEntity(input, existing);
101433
+ const validation = await validateEntityMutation(input, entity, services, "update");
101434
+ if (!validation.ok) return fail2(validation.error);
101435
+ const result = await services.serviceService.updateEntity(input.packageName, entity);
101436
+ if (!result.success) return fail2(result.errors.join("; ") || "Failed to update entity.");
101437
+ const before = existing.attributes.length;
101438
+ const after = entity.attributes.length;
101439
+ const delta = after - before;
101440
+ const deltaNote = delta === 0 ? "attributes unchanged" : delta > 0 ? `+${delta} attribute${delta === 1 ? "" : "s"}` : `-${Math.abs(delta)} attribute${Math.abs(delta) === 1 ? "" : "s"}`;
101441
+ const summary = `Updated ${entity.name} (${deltaNote})`;
101442
+ return {
101443
+ success: true,
101444
+ changeKind: "updated",
101445
+ elementType: "entity",
101446
+ name: entity.name,
101447
+ packageName: input.packageName,
101448
+ summary,
101449
+ navigate: `/packages/${input.packageName}/entities/${entity.name}`,
101450
+ highlight: entity.name,
101451
+ message: summary
101452
+ };
101453
+ } catch (err) {
101454
+ return fail2(err instanceof Error ? err.message : String(err));
101455
+ }
101456
+ }
101457
+ async function executeDeleteEntity(input, services) {
101458
+ try {
101459
+ const result = await services.serviceService.deleteEntity(input.packageName, input.name);
101460
+ if (!result.success) return fail2(result.errors.join("; ") || "Failed to delete entity.");
101461
+ const summary = `Deleted entity ${input.name}`;
101462
+ return {
101463
+ success: true,
101464
+ changeKind: "deleted",
101465
+ elementType: "entity",
101466
+ name: input.name,
101467
+ packageName: input.packageName,
101468
+ summary,
101469
+ // Deletes navigate to the package page (the entity page no longer exists).
101470
+ navigate: `/packages/${input.packageName}`,
101471
+ message: summary
101472
+ };
101473
+ } catch (err) {
101474
+ return fail2(err instanceof Error ? err.message : String(err));
101475
+ }
101476
+ }
101477
+ async function resolveRelationshipEnds(sourceEntityName, targetEntityName, sourcePackage, targetPackage, services) {
101478
+ let src;
101479
+ try {
101480
+ src = await services.serviceService.findEntityAcrossPackages(sourceEntityName, sourcePackage);
101481
+ } catch (e) {
101482
+ return fail2(`Source: ${e instanceof Error ? e.message : String(e)}`);
101483
+ }
101484
+ if (!src) return fail2(`Source entity "${sourceEntityName}" not found in any package.`);
101485
+ let tgt;
101486
+ try {
101487
+ tgt = await services.serviceService.findEntityAcrossPackages(targetEntityName, targetPackage);
101488
+ } catch (e) {
101489
+ return fail2(`Target: ${e instanceof Error ? e.message : String(e)}`);
101490
+ }
101491
+ if (!tgt) return fail2(`Target entity "${targetEntityName}" not found in any package.`);
101492
+ return { src, tgt, homePackage: src.packageName };
101493
+ }
101494
+ function validateRelationshipMutation(relationship) {
101495
+ const result = validateRelationship(relationship);
101496
+ if (!result.valid) {
101497
+ return { ok: false, error: `Relationship failed schema validation: ${result.errors.join("; ")}` };
101498
+ }
101499
+ return { ok: true };
101500
+ }
101501
+ function relationshipName(sourceName, targetName) {
101502
+ return `${sourceName} \u2192 ${targetName}`;
101503
+ }
101504
+ async function executeCreateRelationship(input, services) {
101505
+ try {
101506
+ const ends = await resolveRelationshipEnds(
101507
+ input.sourceEntityName,
101508
+ input.targetEntityName,
101509
+ input.sourcePackage,
101510
+ input.targetPackage,
101511
+ services
101512
+ );
101513
+ if ("success" in ends) return ends;
101514
+ const relationship = {
101515
+ uuid: generateUUID(),
101516
+ description: input.description ?? "",
101517
+ source: { entity: ends.src.entity.uuid, cardinality: input.sourceCardinality },
101518
+ target: { entity: ends.tgt.entity.uuid, cardinality: input.targetCardinality }
101519
+ };
101520
+ const validation = validateRelationshipMutation(relationship);
101521
+ if (!validation.ok) return fail2(validation.error);
101522
+ const result = await services.serviceService.createRelationship(ends.homePackage, relationship);
101523
+ if (!result.success) return fail2(result.errors.join("; ") || "Failed to create relationship.");
101524
+ const name21 = relationshipName(input.sourceEntityName, input.targetEntityName);
101525
+ const crossNote = ends.src.packageName !== ends.tgt.packageName ? `, cross-package ${ends.src.packageName} \u2192 ${ends.tgt.packageName}` : "";
101526
+ const summary = `Created relationship ${name21} (${cardinalityLabel(input.sourceCardinality)} \u2192 ${cardinalityLabel(input.targetCardinality)}${crossNote})`;
101527
+ return {
101528
+ success: true,
101529
+ changeKind: "created",
101530
+ elementType: "relationship",
101531
+ name: name21,
101532
+ packageName: ends.homePackage,
101533
+ summary,
101534
+ message: summary
101535
+ };
101536
+ } catch (err) {
101537
+ return fail2(err instanceof Error ? err.message : String(err));
101538
+ }
101539
+ }
101540
+ async function findRelationshipUuid(homePackage, srcUuid, tgtUuid, sourceName, targetName, services) {
101541
+ const rels = await services.serviceService.getPackageRelationships(homePackage);
101542
+ const match = rels.find((r) => r.source?.entity === srcUuid && r.target?.entity === tgtUuid);
101543
+ if (!match) {
101544
+ return fail2(`No relationship ${relationshipName(sourceName, targetName)} found in package "${homePackage}".`);
101545
+ }
101546
+ return match.uuid;
101547
+ }
101548
+ async function executeUpdateRelationship(input, services) {
101549
+ try {
101550
+ const ends = await resolveRelationshipEnds(
101551
+ input.sourceEntityName,
101552
+ input.targetEntityName,
101553
+ input.sourcePackage,
101554
+ input.targetPackage,
101555
+ services
101556
+ );
101557
+ if ("success" in ends) return ends;
101558
+ const uuidOrFail = await findRelationshipUuid(
101559
+ ends.homePackage,
101560
+ ends.src.entity.uuid,
101561
+ ends.tgt.entity.uuid,
101562
+ input.sourceEntityName,
101563
+ input.targetEntityName,
101564
+ services
101565
+ );
101566
+ if (typeof uuidOrFail !== "string") return uuidOrFail;
101567
+ const relationship = {
101568
+ uuid: uuidOrFail,
101569
+ description: input.description ?? "",
101570
+ source: { entity: ends.src.entity.uuid, cardinality: input.sourceCardinality },
101571
+ target: { entity: ends.tgt.entity.uuid, cardinality: input.targetCardinality }
101572
+ };
101573
+ const validation = validateRelationshipMutation(relationship);
101574
+ if (!validation.ok) return fail2(validation.error);
101575
+ const result = await services.serviceService.updateRelationship(ends.homePackage, uuidOrFail, relationship);
101576
+ if (!result.success) return fail2(result.errors.join("; ") || "Failed to update relationship.");
101577
+ const name21 = relationshipName(input.sourceEntityName, input.targetEntityName);
101578
+ const summary = `Updated relationship ${name21} (${cardinalityLabel(input.sourceCardinality)} \u2192 ${cardinalityLabel(input.targetCardinality)})`;
101579
+ return {
101580
+ success: true,
101581
+ changeKind: "updated",
101582
+ elementType: "relationship",
101583
+ name: name21,
101584
+ packageName: ends.homePackage,
101585
+ summary,
101586
+ message: summary
101587
+ };
101588
+ } catch (err) {
101589
+ return fail2(err instanceof Error ? err.message : String(err));
101590
+ }
101591
+ }
101592
+ async function executeDeleteRelationship(input, services) {
101593
+ try {
101594
+ let src;
101595
+ let tgt;
101596
+ try {
101597
+ src = await services.serviceService.findEntityAcrossPackages(input.sourceEntityName, input.packageName);
101598
+ } catch (e) {
101599
+ return fail2(`Source: ${e instanceof Error ? e.message : String(e)}`);
101600
+ }
101601
+ if (!src) return fail2(`Source entity "${input.sourceEntityName}" not found in any package.`);
101602
+ try {
101603
+ tgt = await services.serviceService.findEntityAcrossPackages(input.targetEntityName, input.packageName);
101604
+ } catch (e) {
101605
+ return fail2(`Target: ${e instanceof Error ? e.message : String(e)}`);
101606
+ }
101607
+ if (!tgt) return fail2(`Target entity "${input.targetEntityName}" not found in any package.`);
101608
+ const uuidOrFail = await findRelationshipUuid(
101609
+ input.packageName,
101610
+ src.entity.uuid,
101611
+ tgt.entity.uuid,
101612
+ input.sourceEntityName,
101613
+ input.targetEntityName,
101614
+ services
101615
+ );
101616
+ if (typeof uuidOrFail !== "string") return uuidOrFail;
101617
+ const result = await services.serviceService.deleteRelationship(input.packageName, uuidOrFail);
101618
+ if (!result.success) return fail2(result.errors.join("; ") || "Failed to delete relationship.");
101619
+ const name21 = relationshipName(input.sourceEntityName, input.targetEntityName);
101620
+ const summary = `Deleted relationship ${name21}`;
101621
+ return {
101622
+ success: true,
101623
+ changeKind: "deleted",
101624
+ elementType: "relationship",
101625
+ name: name21,
101626
+ packageName: input.packageName,
101627
+ summary,
101628
+ navigate: `/packages/${input.packageName}`,
101629
+ message: summary
101630
+ };
101631
+ } catch (err) {
101632
+ return fail2(err instanceof Error ? err.message : String(err));
101633
+ }
101634
+ }
101635
+ var attributeInputSchema, createEntityInputSchema, updateEntityInputSchema, deleteEntityInputSchema, cardinalityValues, createRelationshipInputSchema, updateRelationshipInputSchema, deleteRelationshipInputSchema, attributeJsonSchema, createEntityParameters, updateEntityParameters, deleteEntityParameters, createRelationshipParameters, updateRelationshipParameters, deleteRelationshipParameters;
101636
+ var init_aiMutationTools = __esm({
101637
+ "backend/src/controllers/aiMutationTools.ts"() {
101638
+ "use strict";
101639
+ init_zod();
101640
+ init_EntitySchema();
101641
+ init_dicoConfigService();
101642
+ init_uuid();
101643
+ attributeInputSchema = external_exports.object({
101644
+ name: external_exports.string().describe("Attribute name (camelCase)"),
101645
+ type: external_exports.string().describe("Standard AttributeType (string, integer, number, boolean, date, datetime, uuid, enum, \u2026) or a derived type name"),
101646
+ description: external_exports.string().optional().describe("Attribute description"),
101647
+ required: external_exports.boolean().optional().describe("Whether the attribute is required"),
101648
+ primaryKey: external_exports.boolean().optional().describe("Whether the attribute is (part of) the primary key"),
101649
+ enumValues: external_exports.array(external_exports.string()).optional().describe("Allowed values when type is enum")
101650
+ });
101651
+ createEntityInputSchema = external_exports.object({
101652
+ packageName: external_exports.string().describe("Package/service the entity belongs to"),
101653
+ name: external_exports.string().describe("Entity name (PascalCase)"),
101654
+ description: external_exports.string().optional().describe("Entity description"),
101655
+ stereotype: external_exports.string().optional().describe("Stereotype id (must applyTo entity), e.g. aggregate-root"),
101656
+ attributes: external_exports.array(attributeInputSchema).describe("Entity attributes")
101657
+ });
101658
+ updateEntityInputSchema = createEntityInputSchema;
101659
+ deleteEntityInputSchema = external_exports.object({
101660
+ packageName: external_exports.string().describe("Package/service the entity belongs to"),
101661
+ name: external_exports.string().describe("Entity name to delete")
101662
+ });
101663
+ cardinalityValues = ["one", "many"];
101664
+ createRelationshipInputSchema = external_exports.object({
101665
+ sourceEntityName: external_exports.string().describe("Source entity name"),
101666
+ targetEntityName: external_exports.string().describe("Target entity name"),
101667
+ sourcePackage: external_exports.string().optional().describe("Package containing the source entity (omit to scan all)"),
101668
+ targetPackage: external_exports.string().optional().describe("Package containing the target entity (omit to scan all)"),
101669
+ sourceCardinality: external_exports.enum(cardinalityValues).describe("Source-end cardinality"),
101670
+ targetCardinality: external_exports.enum(cardinalityValues).describe("Target-end cardinality"),
101671
+ description: external_exports.string().optional().describe("Relationship description")
101672
+ });
101673
+ updateRelationshipInputSchema = createRelationshipInputSchema;
101674
+ deleteRelationshipInputSchema = external_exports.object({
101675
+ packageName: external_exports.string().describe("Package the relationship is stored under (the source entity's package)"),
101676
+ sourceEntityName: external_exports.string().describe("Source entity name"),
101677
+ targetEntityName: external_exports.string().describe("Target entity name")
101678
+ });
101679
+ attributeJsonSchema = {
101680
+ type: "object",
101681
+ required: ["name", "type"],
101682
+ properties: {
101683
+ name: { type: "string", description: "Attribute name (camelCase)" },
101684
+ type: { type: "string", description: "Standard AttributeType or a derived type name" },
101685
+ description: { type: "string" },
101686
+ required: { type: "boolean" },
101687
+ primaryKey: { type: "boolean" },
101688
+ enumValues: { type: "array", items: { type: "string" } }
101689
+ }
101690
+ };
101691
+ createEntityParameters = {
101692
+ type: "object",
101693
+ required: ["packageName", "name", "attributes"],
101694
+ properties: {
101695
+ packageName: { type: "string", description: "Package/service the entity belongs to" },
101696
+ name: { type: "string", description: "Entity name (PascalCase)" },
101697
+ description: { type: "string" },
101698
+ stereotype: { type: "string", description: "Stereotype id (entity), e.g. aggregate-root" },
101699
+ attributes: { type: "array", items: attributeJsonSchema }
101700
+ }
101701
+ };
101702
+ updateEntityParameters = createEntityParameters;
101703
+ deleteEntityParameters = {
101704
+ type: "object",
101705
+ required: ["packageName", "name"],
101706
+ properties: {
101707
+ packageName: { type: "string" },
101708
+ name: { type: "string", description: "Entity name to delete" }
101709
+ }
101710
+ };
101711
+ createRelationshipParameters = {
101712
+ type: "object",
101713
+ required: ["sourceEntityName", "targetEntityName", "sourceCardinality", "targetCardinality"],
101714
+ properties: {
101715
+ sourceEntityName: { type: "string" },
101716
+ targetEntityName: { type: "string" },
101717
+ sourcePackage: { type: "string", description: "Package of source entity (omit to scan all)" },
101718
+ targetPackage: { type: "string", description: "Package of target entity (omit to scan all)" },
101719
+ sourceCardinality: { type: "string", enum: ["one", "many"] },
101720
+ targetCardinality: { type: "string", enum: ["one", "many"] },
101721
+ description: { type: "string" }
101722
+ }
101723
+ };
101724
+ updateRelationshipParameters = createRelationshipParameters;
101725
+ deleteRelationshipParameters = {
101726
+ type: "object",
101727
+ required: ["packageName", "sourceEntityName", "targetEntityName"],
101728
+ properties: {
101729
+ packageName: { type: "string", description: "Package the relationship is stored under (source entity's package)" },
101730
+ sourceEntityName: { type: "string" },
101731
+ targetEntityName: { type: "string" }
101732
+ }
101733
+ };
101734
+ __name(fail2, "fail");
101735
+ __name(cardinalityLabel, "cardinalityLabel");
101736
+ __name(ensurePackage, "ensurePackage");
101737
+ __name(packageExists, "packageExists");
101738
+ __name(buildEntity, "buildEntity");
101739
+ __name(validateEntityMutation, "validateEntityMutation");
101740
+ __name(executeCreateEntity, "executeCreateEntity");
101741
+ __name(executeUpdateEntity, "executeUpdateEntity");
101742
+ __name(executeDeleteEntity, "executeDeleteEntity");
101743
+ __name(resolveRelationshipEnds, "resolveRelationshipEnds");
101744
+ __name(validateRelationshipMutation, "validateRelationshipMutation");
101745
+ __name(relationshipName, "relationshipName");
101746
+ __name(executeCreateRelationship, "executeCreateRelationship");
101747
+ __name(findRelationshipUuid, "findRelationshipUuid");
101748
+ __name(executeUpdateRelationship, "executeUpdateRelationship");
101749
+ __name(executeDeleteRelationship, "executeDeleteRelationship");
101750
+ }
101751
+ });
101752
+
101127
101753
  // backend/node_modules/@ai-sdk/anthropic/dist/index.mjs
101128
101754
  var dist_exports2 = {};
101129
101755
  __export(dist_exports2, {
@@ -104125,12 +104751,12 @@ var init_dist7 = __esm({
104125
104751
  static {
104126
104752
  __name(this, "AnthropicMessagesLanguageModel");
104127
104753
  }
104128
- constructor(modelId, config3) {
104754
+ constructor(modelId, config4) {
104129
104755
  this.specificationVersion = "v3";
104130
104756
  var _a21;
104131
104757
  this.modelId = modelId;
104132
- this.config = config3;
104133
- this.generateId = (_a21 = config3.generateId) != null ? _a21 : generateId;
104758
+ this.config = config4;
104759
+ this.generateId = (_a21 = config4.generateId) != null ? _a21 : generateId;
104134
104760
  }
104135
104761
  supportsUrl(url2) {
104136
104762
  return url2.protocol === "https:";
@@ -108177,13 +108803,13 @@ var init_dist8 = __esm({
108177
108803
  static {
108178
108804
  __name(this, "OpenAIChatLanguageModel");
108179
108805
  }
108180
- constructor(modelId, config3) {
108806
+ constructor(modelId, config4) {
108181
108807
  this.specificationVersion = "v3";
108182
108808
  this.supportedUrls = {
108183
108809
  "image/*": [/^https?:\/\/.*$/]
108184
108810
  };
108185
108811
  this.modelId = modelId;
108186
- this.config = config3;
108812
+ this.config = config4;
108187
108813
  }
108188
108814
  get provider() {
108189
108815
  return this.config.provider;
@@ -108764,13 +109390,13 @@ var init_dist8 = __esm({
108764
109390
  static {
108765
109391
  __name(this, "OpenAICompletionLanguageModel");
108766
109392
  }
108767
- constructor(modelId, config3) {
109393
+ constructor(modelId, config4) {
108768
109394
  this.specificationVersion = "v3";
108769
109395
  this.supportedUrls = {
108770
109396
  // No URLs are supported for completion models.
108771
109397
  };
108772
109398
  this.modelId = modelId;
108773
- this.config = config3;
109399
+ this.config = config4;
108774
109400
  }
108775
109401
  get providerOptionsName() {
108776
109402
  return this.config.provider.split(".")[0].trim();
@@ -109018,12 +109644,12 @@ var init_dist8 = __esm({
109018
109644
  static {
109019
109645
  __name(this, "OpenAIEmbeddingModel");
109020
109646
  }
109021
- constructor(modelId, config3) {
109647
+ constructor(modelId, config4) {
109022
109648
  this.specificationVersion = "v3";
109023
109649
  this.maxEmbeddingsPerCall = 2048;
109024
109650
  this.supportsParallelCalls = true;
109025
109651
  this.modelId = modelId;
109026
- this.config = config3;
109652
+ this.config = config4;
109027
109653
  }
109028
109654
  get provider() {
109029
109655
  return this.config.provider;
@@ -109125,9 +109751,9 @@ var init_dist8 = __esm({
109125
109751
  static {
109126
109752
  __name(this, "OpenAIImageModel");
109127
109753
  }
109128
- constructor(modelId, config3) {
109754
+ constructor(modelId, config4) {
109129
109755
  this.modelId = modelId;
109130
- this.config = config3;
109756
+ this.config = config4;
109131
109757
  this.specificationVersion = "v3";
109132
109758
  }
109133
109759
  get maxImagesPerCall() {
@@ -110958,14 +111584,14 @@ var init_dist8 = __esm({
110958
111584
  static {
110959
111585
  __name(this, "OpenAIResponsesLanguageModel");
110960
111586
  }
110961
- constructor(modelId, config3) {
111587
+ constructor(modelId, config4) {
110962
111588
  this.specificationVersion = "v3";
110963
111589
  this.supportedUrls = {
110964
111590
  "image/*": [/^https?:\/\/.*$/],
110965
111591
  "application/pdf": [/^https?:\/\/.*$/]
110966
111592
  };
110967
111593
  this.modelId = modelId;
110968
- this.config = config3;
111594
+ this.config = config4;
110969
111595
  }
110970
111596
  get provider() {
110971
111597
  return this.config.provider;
@@ -112590,9 +113216,9 @@ var init_dist8 = __esm({
112590
113216
  static {
112591
113217
  __name(this, "OpenAISpeechModel");
112592
113218
  }
112593
- constructor(modelId, config3) {
113219
+ constructor(modelId, config4) {
112594
113220
  this.modelId = modelId;
112595
- this.config = config3;
113221
+ this.config = config4;
112596
113222
  this.specificationVersion = "v3";
112597
113223
  }
112598
113224
  get provider() {
@@ -112809,9 +113435,9 @@ var init_dist8 = __esm({
112809
113435
  static {
112810
113436
  __name(this, "OpenAITranscriptionModel");
112811
113437
  }
112812
- constructor(modelId, config3) {
113438
+ constructor(modelId, config4) {
112813
113439
  this.modelId = modelId;
112814
- this.config = config3;
113440
+ this.config = config4;
112815
113441
  this.specificationVersion = "v3";
112816
113442
  }
112817
113443
  get provider() {
@@ -112926,26 +113552,27 @@ __export(aiDirectClient_exports, {
112926
113552
  AbortError: () => AbortError,
112927
113553
  callWithTools: () => callWithTools
112928
113554
  });
112929
- async function callWithTools(config3, messages, tools, executeToolFn, maxSteps = 10, onEvent, signal) {
113555
+ async function callWithTools(config4, messages, tools, executeToolFn, maxSteps = 10, onEvent, signal) {
112930
113556
  let currentMessages = [...messages];
112931
113557
  const allToolCalls = [];
112932
113558
  let finalText = "";
112933
113559
  const callSeq = {};
112934
113560
  const usage = { inputTokens: 0, outputTokens: 0 };
113561
+ let stoppedAtStepLimit = true;
112935
113562
  for (let step = 0; step < maxSteps; step++) {
112936
113563
  if (signal?.aborted) {
112937
- return { text: finalText, toolCalls: allToolCalls, aborted: true, usage };
113564
+ return { text: finalText, toolCalls: allToolCalls, aborted: true, usage, stoppedAtStepLimit: false };
112938
113565
  }
112939
113566
  let response;
112940
113567
  try {
112941
- response = await fetch(`${config3.baseURL}/chat/completions`, {
113568
+ response = await fetch(`${config4.baseURL}/chat/completions`, {
112942
113569
  method: "POST",
112943
113570
  headers: {
112944
- "Authorization": `Bearer ${config3.apiKey}`,
113571
+ "Authorization": `Bearer ${config4.apiKey}`,
112945
113572
  "Content-Type": "application/json"
112946
113573
  },
112947
113574
  body: JSON.stringify({
112948
- model: config3.model,
113575
+ model: config4.model,
112949
113576
  messages: currentMessages,
112950
113577
  tools: tools.length > 0 ? tools : void 0,
112951
113578
  tool_choice: tools.length > 0 ? "auto" : void 0,
@@ -112955,7 +113582,7 @@ async function callWithTools(config3, messages, tools, executeToolFn, maxSteps =
112955
113582
  });
112956
113583
  } catch (err) {
112957
113584
  if (err?.name === "AbortError" || signal?.aborted) {
112958
- return { text: finalText, toolCalls: allToolCalls, aborted: true, usage };
113585
+ return { text: finalText, toolCalls: allToolCalls, aborted: true, usage, stoppedAtStepLimit: false };
112959
113586
  }
112960
113587
  throw err;
112961
113588
  }
@@ -113006,7 +113633,7 @@ async function callWithTools(config3, messages, tools, executeToolFn, maxSteps =
113006
113633
  });
113007
113634
  for (const tc of msg.tool_calls) {
113008
113635
  if (signal?.aborted) {
113009
- return { text: finalText, toolCalls: allToolCalls, aborted: true, usage };
113636
+ return { text: finalText, toolCalls: allToolCalls, aborted: true, usage, stoppedAtStepLimit: false };
113010
113637
  }
113011
113638
  const toolName = tc.function.name;
113012
113639
  let toolArgs = {};
@@ -113035,9 +113662,53 @@ async function callWithTools(config3, messages, tools, executeToolFn, maxSteps =
113035
113662
  }
113036
113663
  continue;
113037
113664
  }
113665
+ stoppedAtStepLimit = false;
113038
113666
  break;
113039
113667
  }
113040
- return { text: finalText, toolCalls: allToolCalls, usage };
113668
+ if (stoppedAtStepLimit && !signal?.aborted) {
113669
+ const nudgeMessages = [
113670
+ ...currentMessages,
113671
+ {
113672
+ role: "user",
113673
+ content: "You've reached the step limit and can't call more tools. Summarize what you changed and list the remaining steps to finish."
113674
+ }
113675
+ ];
113676
+ try {
113677
+ const response = await fetch(`${config4.baseURL}/chat/completions`, {
113678
+ method: "POST",
113679
+ headers: {
113680
+ "Authorization": `Bearer ${config4.apiKey}`,
113681
+ "Content-Type": "application/json"
113682
+ },
113683
+ body: JSON.stringify({
113684
+ model: config4.model,
113685
+ messages: nudgeMessages,
113686
+ // tools omitted on purpose — the model cannot call more tools.
113687
+ max_tokens: 4096
113688
+ }),
113689
+ signal
113690
+ });
113691
+ if (response.ok) {
113692
+ const data = await response.json();
113693
+ if (data.usage) {
113694
+ const u = data.usage;
113695
+ const inTok = typeof u.prompt_tokens === "number" ? u.prompt_tokens : typeof u.input_tokens === "number" ? u.input_tokens : 0;
113696
+ const outTok = typeof u.completion_tokens === "number" ? u.completion_tokens : typeof u.output_tokens === "number" ? u.output_tokens : 0;
113697
+ usage.inputTokens += inTok;
113698
+ usage.outputTokens += outTok;
113699
+ }
113700
+ const summary = data.choices?.[0]?.message?.content || "";
113701
+ if (summary) {
113702
+ finalText = summary;
113703
+ }
113704
+ }
113705
+ } catch (err) {
113706
+ if (!(err?.name === "AbortError" || signal?.aborted)) {
113707
+ logger.warn(`AI summary turn failed: ${err?.message ?? err}`);
113708
+ }
113709
+ }
113710
+ }
113711
+ return { text: finalText, toolCalls: allToolCalls, usage, stoppedAtStepLimit };
113041
113712
  }
113042
113713
  var AbortError;
113043
113714
  var init_aiDirectClient = __esm({
@@ -113375,8 +114046,12 @@ async function handleDirectChat(req, res, cfg, rawMessages, services, pageContex
113375
114046
  if (text2) messages.push({ role: msg.role, content: text2 });
113376
114047
  }
113377
114048
  const builtinToolDefs = [
113378
- { type: "function", function: { name: "createEntity", description: "Create an entity. entityJson is a JSON string with packageName, name, description, stereotype, attributes array.", parameters: { type: "object", required: ["entityJson"], properties: { entityJson: { type: "string", description: 'JSON: {"packageName":"pkg","name":"Entity","description":"...","attributes":[{"name":"id","type":"string","required":true,"primaryKey":true}]}' } } } } },
113379
- { type: "function", function: { name: "createRelationship", description: "Create a relationship. Endpoints may live in the same package or in different packages (cross-package is first-class). JSON string parameter.", parameters: { type: "object", required: ["relationshipJson"], properties: { relationshipJson: { type: "string", description: `JSON: {"packageName":"home-pkg","sourceEntityName":"A","sourcePackage":"pkg-of-A","targetEntityName":"B","targetPackage":"pkg-of-B","sourceCardinality":"one","targetCardinality":"many","description":"..."}. sourcePackage/targetPackage are optional \u2014 if omitted the resolver scans every package and errors on ambiguity. The relationship is stored under the source's package.` } } } } },
114049
+ { type: "function", function: { name: "createEntity", description: "Create a new entity with attributes in a package. Structured fields: packageName, name, description, stereotype, attributes[].", parameters: createEntityParameters } },
114050
+ { type: "function", function: { name: "updateEntity", description: "Update an existing entity. description/stereotype/attributes become the new desired state; uuid and createdAt are preserved.", parameters: updateEntityParameters } },
114051
+ { type: "function", function: { name: "deleteEntity", description: "Delete an entity by package and name. Fails if still referenced by relationships (no auto-cascade).", parameters: deleteEntityParameters } },
114052
+ { type: "function", function: { name: "createRelationship", description: "Create a relationship between two entities. Cross-package is first-class; omit sourcePackage/targetPackage to scan all packages. Stored under the source entity's package.", parameters: createRelationshipParameters } },
114053
+ { type: "function", function: { name: "updateRelationship", description: "Update an existing relationship (resolved by matching source/target). Cardinalities and description become the new desired state.", parameters: updateRelationshipParameters } },
114054
+ { type: "function", function: { name: "deleteRelationship", description: "Delete a relationship by its package (source entity's package) and source/target entity names.", parameters: deleteRelationshipParameters } },
113380
114055
  { 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)" } } } } },
113381
114056
  { type: "function", function: { name: "listStereotypes", description: "List available stereotypes", parameters: { type: "object", properties: {} } } },
113382
114057
  { 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" } } } } },
@@ -113395,70 +114070,24 @@ async function handleDirectChat(req, res, cfg, rawMessages, services, pageContex
113395
114070
  const toolDefs = allToolDefs.filter((t) => isToolAllowedForMode(t.function.name, mode));
113396
114071
  const executeTool2 = /* @__PURE__ */ __name(async (name21, args) => {
113397
114072
  try {
114073
+ const mutationServices = services;
113398
114074
  if (name21 === "createEntity") {
113399
- let parsed;
113400
- try {
113401
- parsed = JSON.parse(args.entityJson || "{}");
113402
- } catch {
113403
- return { success: false, error: "Invalid JSON" };
113404
- }
113405
- if (!parsed.name || !parsed.attributes) return { success: false, error: "Missing name or attributes" };
113406
- const pkgName = parsed.packageName || "default";
113407
- const { listPackages: listPackages2, ensurePackageDirectoryStructure: ensurePackageDirectoryStructure2 } = await Promise.resolve().then(() => (init_fileOperations(), fileOperations_exports));
113408
- const existing = await listPackages2();
113409
- if (!existing.includes(pkgName)) await ensurePackageDirectoryStructure2(pkgName);
113410
- const entity = {
113411
- uuid: crypto.randomUUID(),
113412
- name: parsed.name,
113413
- description: parsed.description || "",
113414
- stereotype: parsed.stereotype,
113415
- status: "draft",
113416
- attributes: (parsed.attributes || []).map((a) => ({
113417
- uuid: crypto.randomUUID(),
113418
- name: a.name,
113419
- type: a.type || "string",
113420
- description: a.description || "",
113421
- required: a.required ?? false,
113422
- primaryKey: a.primaryKey,
113423
- validation: a.enumValues ? { enumValues: a.enumValues } : void 0
113424
- })),
113425
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
113426
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
113427
- };
113428
- await services.serviceService.createEntity(pkgName, entity);
113429
- return { success: true, message: `Created entity ${parsed.name} with ${entity.attributes.length} attributes`, navigate: `/packages/${pkgName}/entities/${parsed.name}` };
114075
+ return await executeCreateEntity(args, mutationServices);
114076
+ }
114077
+ if (name21 === "updateEntity") {
114078
+ return await executeUpdateEntity(args, mutationServices);
114079
+ }
114080
+ if (name21 === "deleteEntity") {
114081
+ return await executeDeleteEntity(args, mutationServices);
113430
114082
  }
113431
114083
  if (name21 === "createRelationship") {
113432
- let p;
113433
- try {
113434
- p = JSON.parse(args.relationshipJson || "{}");
113435
- } catch {
113436
- return { success: false, error: "Invalid JSON" };
113437
- }
113438
- if (!p.sourceEntityName || !p.targetEntityName) return { success: false, error: "Missing entity names" };
113439
- const defaultPkg = p.packageName || "default";
113440
- let src, tgt;
113441
- try {
113442
- src = await services.serviceService.findEntityAcrossPackages(p.sourceEntityName, p.sourcePackage || defaultPkg);
113443
- } catch (e) {
113444
- return { success: false, error: `Source: ${e instanceof Error ? e.message : String(e)}` };
113445
- }
113446
- if (!src) return { success: false, error: `Source entity "${p.sourceEntityName}" not found in any package` };
113447
- try {
113448
- tgt = await services.serviceService.findEntityAcrossPackages(p.targetEntityName, p.targetPackage || defaultPkg);
113449
- } catch (e) {
113450
- return { success: false, error: `Target: ${e instanceof Error ? e.message : String(e)}` };
113451
- }
113452
- if (!tgt) return { success: false, error: `Target entity "${p.targetEntityName}" not found in any package` };
113453
- const homePackage = src.packageName;
113454
- await services.serviceService.createRelationship(homePackage, {
113455
- uuid: crypto.randomUUID(),
113456
- description: p.description || "",
113457
- source: { entity: src.entity.uuid, cardinality: p.sourceCardinality || "one" },
113458
- target: { entity: tgt.entity.uuid, cardinality: p.targetCardinality || "many" }
113459
- });
113460
- const crossNote = src.packageName !== tgt.packageName ? ` (cross-package: ${src.packageName} \u2192 ${tgt.packageName})` : "";
113461
- return { success: true, message: `Created relationship: ${p.sourceEntityName} -> ${p.targetEntityName}${crossNote}` };
114084
+ return await executeCreateRelationship(args, mutationServices);
114085
+ }
114086
+ if (name21 === "updateRelationship") {
114087
+ return await executeUpdateRelationship(args, mutationServices);
114088
+ }
114089
+ if (name21 === "deleteRelationship") {
114090
+ return await executeDeleteRelationship(args, mutationServices);
113462
114091
  }
113463
114092
  if (name21 === "listEntities") {
113464
114093
  if (args.packageName) {
@@ -113502,7 +114131,7 @@ async function handleDirectChat(req, res, cfg, rawMessages, services, pageContex
113502
114131
  messages,
113503
114132
  toolDefs,
113504
114133
  executeTool2,
113505
- 15,
114134
+ AI_MAX_STEPS,
113506
114135
  (event) => {
113507
114136
  if (event.type === "text") {
113508
114137
  const id = crypto.randomUUID();
@@ -113543,6 +114172,9 @@ async function handleDirectChat(req, res, cfg, rawMessages, services, pageContex
113543
114172
  ...cost !== void 0 ? { cost } : {}
113544
114173
  });
113545
114174
  }
114175
+ if (result.stoppedAtStepLimit) {
114176
+ sendEvent({ type: "step-limit-reached", limit: AI_MAX_STEPS });
114177
+ }
113546
114178
  sendEvent({ type: "finish", finishReason: "stop" });
113547
114179
  }
113548
114180
  } catch (err) {
@@ -113605,11 +114237,12 @@ var init_aiController = __esm({
113605
114237
  init_dist6();
113606
114238
  init_zod();
113607
114239
  init_logger();
114240
+ init_config();
113608
114241
  init_appDir();
113609
114242
  init_conversationService();
113610
114243
  init_promptService();
113611
- init_EntitySchema();
113612
114244
  init_mcpClientRegistry();
114245
+ init_aiMutationTools();
113613
114246
  TOOL_CATEGORY_MAP = {
113614
114247
  // read
113615
114248
  listEntities: "read",
@@ -113677,18 +114310,17 @@ When creating data models:
113677
114310
  - Suggest stereotypes when applicable (aggregate-root, reference-data, event, value-object for entities)
113678
114311
  - Create relationships with proper cardinality
113679
114312
 
113680
- IMPORTANT: For createEntity and createRelationship tools, you must pass a SINGLE parameter called entityJson or relationshipJson containing a valid JSON string with all the data.
113681
-
113682
- Example createEntity call:
113683
- entityJson: '{"packageName":"e-commerce","name":"Product","description":"A product in the catalog","stereotype":"aggregate-root","attributes":[{"name":"productId","type":"string","description":"Unique product ID","required":true,"primaryKey":true},{"name":"name","type":"string","description":"Product name","required":true},{"name":"price","type":"number","description":"Product price","required":true}]}'
114313
+ Mutation tools take STRUCTURED parameters (not JSON strings):
114314
+ - createEntity / updateEntity: { packageName, name, description?, stereotype?, attributes: [{ name, type, description?, required?, primaryKey?, enumValues? }] }. For updateEntity the provided description/stereotype/attributes become the new desired state.
114315
+ - deleteEntity: { packageName, name }. Fails if the entity is still referenced by relationships \u2014 delete those relationships first (no auto-cascade).
114316
+ - createRelationship / updateRelationship: { sourceEntityName, targetEntityName, sourcePackage?, targetPackage?, sourceCardinality, targetCardinality, description? }. Cardinality is "one" or "many".
114317
+ - deleteRelationship: { packageName, sourceEntityName, targetEntityName } where packageName is the source entity's package.
113684
114318
 
113685
- Cross-package relationships are first-class. When source and target live in different packages, pass sourcePackage and targetPackage explicitly:
113686
- relationshipJson: '{"sourceEntityName":"Order","sourcePackage":"order-service","targetEntityName":"User","targetPackage":"user-service","sourceCardinality":"many","targetCardinality":"one","description":"placed by"}'
113687
- The relationship is stored under the source's package. If sourcePackage/targetPackage are omitted the resolver scans every package and errors on ambiguity.
114319
+ Cross-package relationships are first-class. When source and target live in different packages, pass sourcePackage and targetPackage explicitly. The relationship is stored under the source's package. If sourcePackage/targetPackage are omitted the resolver scans every package and errors on ambiguity.
113688
114320
 
113689
114321
  When the user asks to create a model:
113690
114322
  1. Infer a package name from context (e.g. "e-commerce data model" \u2192 packageName: "e-commerce").
113691
- 2. ALWAYS include packageName in every entityJson. For relationshipJson include sourcePackage/targetPackage when the endpoints span multiple packages.
114323
+ 2. ALWAYS include packageName when creating entities. For relationships include sourcePackage/targetPackage when the endpoints span multiple packages.
113692
114324
  3. Create ALL entities first, then ALL relationships.
113693
114325
  4. After creating everything, use navigateTo to show the package page.
113694
114326
 
@@ -113755,6 +114387,7 @@ Be concise in your responses. Show a summary of what you created.`;
113755
114387
  req.on("close", onAbort);
113756
114388
  req.on("aborted", onAbort);
113757
114389
  let aggregatedUsage = null;
114390
+ let stoppedAtStepLimit = false;
113758
114391
  const result = streamText({
113759
114392
  model,
113760
114393
  system: buildSystemPrompt(enrichedPageContext, conversationSystemPrompt, mode),
@@ -113768,112 +114401,61 @@ Be concise in your responses. Show a summary of what you created.`;
113768
114401
  outputTokens: tu.outputTokens ?? 0
113769
114402
  };
113770
114403
  }
114404
+ stoppedAtStepLimit = event.finishReason === "tool-calls" && event.steps.length >= AI_MAX_STEPS;
113771
114405
  }, "onFinish"),
113772
114406
  tools: filterToolsForMode({
113773
114407
  createEntity: tool({
113774
- description: 'Create a new entity with attributes in a package. The entityJson parameter must be a JSON string with this structure: {"packageName":"pkg","name":"EntityName","description":"...","stereotype":"aggregate-root","attributes":[{"name":"id","type":"string","description":"...","required":true,"primaryKey":true}]}',
113775
- inputSchema: external_exports.object({
113776
- entityJson: external_exports.string().describe("JSON string containing packageName, name, description, stereotype (optional), and attributes array. Each attribute has name, type, description, required, primaryKey (optional), enumValues (optional).")
113777
- }),
114408
+ description: "Create a new entity with attributes in a package. Provide structured fields (packageName, name, description, stereotype, attributes[]). Each attribute: { name, type, description, required, primaryKey, enumValues }.",
114409
+ inputSchema: createEntityInputSchema,
113778
114410
  execute: /* @__PURE__ */ __name(async (params) => {
113779
- try {
113780
- let parsed;
113781
- try {
113782
- parsed = JSON.parse(params.entityJson || "{}");
113783
- } catch {
113784
- return { success: false, error: "Invalid JSON in entityJson parameter" };
113785
- }
113786
- if (!parsed.name || !parsed.attributes) {
113787
- return {
113788
- success: false,
113789
- error: 'entityJson must contain name and attributes. Example: {"packageName":"e-commerce","name":"Product","description":"...","attributes":[{"name":"id","type":"string","description":"...","required":true}]}'
113790
- };
113791
- }
113792
- const pkgName = parsed.packageName || "default";
113793
- const { listPackages: listPackages2, ensurePackageDirectoryStructure: ensurePackageDirectoryStructure2 } = await Promise.resolve().then(() => (init_fileOperations(), fileOperations_exports));
113794
- const existingServices = await listPackages2();
113795
- if (!existingServices.includes(pkgName)) {
113796
- await ensurePackageDirectoryStructure2(pkgName);
113797
- }
113798
- const attrs = (parsed.attributes || []).map((a) => ({
113799
- uuid: crypto.randomUUID(),
113800
- name: a.name,
113801
- type: a.type || "string",
113802
- description: a.description || "",
113803
- required: a.required ?? false,
113804
- primaryKey: a.primaryKey,
113805
- validation: a.enumValues ? { enumValues: a.enumValues } : void 0
113806
- }));
113807
- const entity = {
113808
- uuid: crypto.randomUUID(),
113809
- name: parsed.name,
113810
- description: parsed.description || "",
113811
- stereotype: parsed.stereotype,
113812
- status: "draft" /* DRAFT */,
113813
- attributes: attrs,
113814
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
113815
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
113816
- };
113817
- await services.serviceService.createEntity(pkgName, entity);
113818
- logger.info(`AI created entity: ${pkgName}/${parsed.name}`);
113819
- return {
113820
- success: true,
113821
- message: `Created entity ${parsed.name} with ${attrs.length} attributes`,
113822
- navigate: `/packages/${pkgName}/entities/${parsed.name}`
113823
- };
113824
- } catch (err) {
113825
- return { success: false, error: err.message };
113826
- }
114411
+ const result2 = await executeCreateEntity(params, services);
114412
+ if (result2.success) logger.info(`AI created entity: ${result2.packageName}/${result2.name}`);
114413
+ return result2;
114414
+ }, "execute")
114415
+ }),
114416
+ updateEntity: tool({
114417
+ description: "Update an existing entity. The provided description/stereotype/attributes become the new desired state; the entity uuid and createdAt are preserved. Same structured shape as createEntity.",
114418
+ inputSchema: updateEntityInputSchema,
114419
+ execute: /* @__PURE__ */ __name(async (params) => {
114420
+ const result2 = await executeUpdateEntity(params, services);
114421
+ if (result2.success) logger.info(`AI updated entity: ${result2.packageName}/${result2.name}`);
114422
+ return result2;
114423
+ }, "execute")
114424
+ }),
114425
+ deleteEntity: tool({
114426
+ description: "Delete an entity by package and name. Fails (and reports) if the entity is still referenced by relationships \u2014 remove those relationships first; the tool never auto-cascades.",
114427
+ inputSchema: deleteEntityInputSchema,
114428
+ execute: /* @__PURE__ */ __name(async (params) => {
114429
+ const result2 = await executeDeleteEntity(params, services);
114430
+ if (result2.success) logger.info(`AI deleted entity: ${result2.packageName}/${result2.name}`);
114431
+ return result2;
113827
114432
  }, "execute")
113828
114433
  }),
113829
114434
  createRelationship: tool({
113830
- description: `Create a relationship between two entities. Endpoints may live in the same package or in different packages (cross-package is first-class). Pass a JSON string: {"packageName":"home-pkg","sourceEntityName":"Order","sourcePackage":"order-service","targetEntityName":"User","targetPackage":"user-service","description":"...","sourceCardinality":"many","targetCardinality":"one"}. sourcePackage/targetPackage are optional \u2014 if omitted the resolver falls back to packageName and then scans every package, erroring on ambiguity. The relationship is stored under the source's package by convention.`,
113831
- inputSchema: external_exports.object({
113832
- relationshipJson: external_exports.string().describe("JSON with packageName (optional, fallback), sourceEntityName, sourcePackage (optional), targetEntityName, targetPackage (optional), description, sourceCardinality (one|many), targetCardinality (one|many)")
113833
- }),
114435
+ description: "Create a relationship between two entities. Endpoints may live in the same or different packages (cross-package is first-class). Provide sourceEntityName, targetEntityName, optional sourcePackage/targetPackage (omit to scan all packages, errors on ambiguity), sourceCardinality and targetCardinality (one|many), and an optional description. The relationship is stored under the source entity's package.",
114436
+ inputSchema: createRelationshipInputSchema,
113834
114437
  execute: /* @__PURE__ */ __name(async (params) => {
113835
- try {
113836
- let p;
113837
- try {
113838
- p = JSON.parse(params.relationshipJson || "{}");
113839
- } catch {
113840
- return { success: false, error: "Invalid JSON in relationshipJson" };
113841
- }
113842
- if (!p.sourceEntityName || !p.targetEntityName) {
113843
- return { success: false, error: "Missing sourceEntityName or targetEntityName in JSON" };
113844
- }
113845
- const defaultPkg = p.packageName || "default";
113846
- let src, tgt;
113847
- try {
113848
- src = await services.serviceService.findEntityAcrossPackages(p.sourceEntityName, p.sourcePackage || defaultPkg);
113849
- } catch (e) {
113850
- return { success: false, error: `Source: ${e instanceof Error ? e.message : String(e)}` };
113851
- }
113852
- if (!src) {
113853
- return { success: false, error: `Source entity "${p.sourceEntityName}" not found in any package` };
113854
- }
113855
- try {
113856
- tgt = await services.serviceService.findEntityAcrossPackages(p.targetEntityName, p.targetPackage || defaultPkg);
113857
- } catch (e) {
113858
- return { success: false, error: `Target: ${e instanceof Error ? e.message : String(e)}` };
113859
- }
113860
- if (!tgt) {
113861
- return { success: false, error: `Target entity "${p.targetEntityName}" not found in any package` };
113862
- }
113863
- const homePackage = src.packageName;
113864
- const relationship = {
113865
- uuid: crypto.randomUUID(),
113866
- description: p.description || "",
113867
- source: { entity: src.entity.uuid, cardinality: p.sourceCardinality || "one" },
113868
- target: { entity: tgt.entity.uuid, cardinality: p.targetCardinality || "many" }
113869
- };
113870
- await services.serviceService.createRelationship(homePackage, relationship);
113871
- const crossNote = src.packageName !== tgt.packageName ? ` (cross-package: ${src.packageName} \u2192 ${tgt.packageName}, stored under ${homePackage})` : "";
113872
- logger.info(`AI created relationship: ${p.sourceEntityName} -> ${p.targetEntityName}${crossNote}`);
113873
- return { success: true, message: `Created relationship: ${p.sourceEntityName} -> ${p.targetEntityName}${crossNote}` };
113874
- } catch (err) {
113875
- return { success: false, error: err.message };
113876
- }
114438
+ const result2 = await executeCreateRelationship(params, services);
114439
+ if (result2.success) logger.info(`AI created relationship: ${result2.name}`);
114440
+ return result2;
114441
+ }, "execute")
114442
+ }),
114443
+ updateRelationship: tool({
114444
+ description: "Update an existing relationship between two entities. The relationship is resolved by matching source/target entities; cardinalities and description become the new desired state.",
114445
+ inputSchema: updateRelationshipInputSchema,
114446
+ execute: /* @__PURE__ */ __name(async (params) => {
114447
+ const result2 = await executeUpdateRelationship(params, services);
114448
+ if (result2.success) logger.info(`AI updated relationship: ${result2.name}`);
114449
+ return result2;
114450
+ }, "execute")
114451
+ }),
114452
+ deleteRelationship: tool({
114453
+ description: "Delete a relationship by its package (the source entity's package) and the source/target entity names.",
114454
+ inputSchema: deleteRelationshipInputSchema,
114455
+ execute: /* @__PURE__ */ __name(async (params) => {
114456
+ const result2 = await executeDeleteRelationship(params, services);
114457
+ if (result2.success) logger.info(`AI deleted relationship: ${result2.name}`);
114458
+ return result2;
113877
114459
  }, "execute")
113878
114460
  }),
113879
114461
  listEntities: tool({
@@ -113960,7 +114542,7 @@ Be concise in your responses. Show a summary of what you created.`;
113960
114542
  // #178 — MCP tools merged at chat-request time
113961
114543
  ...mcpToolEntries
113962
114544
  }, mode),
113963
- stopWhen: stepCountIs(20)
114545
+ stopWhen: stepCountIs(AI_MAX_STEPS)
113964
114546
  });
113965
114547
  const response = result.toUIMessageStreamResponse();
113966
114548
  res.status(response.status || 200);
@@ -114023,6 +114605,44 @@ Be concise in your responses. Show a summary of what you created.`;
114023
114605
  }
114024
114606
  const { done, value } = chunk;
114025
114607
  if (done) {
114608
+ if (stoppedAtStepLimit && !ac.signal.aborted) {
114609
+ try {
114610
+ const prior = await result.response;
114611
+ const summary = await generateText({
114612
+ model,
114613
+ system: buildSystemPrompt(enrichedPageContext, conversationSystemPrompt, mode),
114614
+ messages: [
114615
+ ...messages,
114616
+ ...prior.messages,
114617
+ {
114618
+ role: "user",
114619
+ content: "You've reached the step limit and can't call more tools. Summarize what you changed and list the remaining steps to finish."
114620
+ }
114621
+ ],
114622
+ // No tools — the model cannot call more this turn.
114623
+ abortSignal: ac.signal
114624
+ });
114625
+ if (summary.text) {
114626
+ const summaryId = crypto.randomUUID();
114627
+ res.write(`data: ${JSON.stringify({ type: "text-start", id: summaryId })}
114628
+
114629
+ `);
114630
+ for (const word of summary.text.split(" ")) {
114631
+ res.write(`data: ${JSON.stringify({ type: "text-delta", id: summaryId, delta: word + " " })}
114632
+
114633
+ `);
114634
+ }
114635
+ if (summary.usage && aggregatedUsage) {
114636
+ aggregatedUsage = {
114637
+ inputTokens: aggregatedUsage.inputTokens + (summary.usage.inputTokens ?? 0),
114638
+ outputTokens: aggregatedUsage.outputTokens + (summary.usage.outputTokens ?? 0)
114639
+ };
114640
+ }
114641
+ }
114642
+ } catch (err) {
114643
+ logger.warn(`AI SDK summary turn failed: ${err instanceof Error ? err.message : String(err)}`);
114644
+ }
114645
+ }
114026
114646
  if (aggregatedUsage && (aggregatedUsage.inputTokens > 0 || aggregatedUsage.outputTokens > 0)) {
114027
114647
  const cost = computeCost(
114028
114648
  aggregatedUsage.inputTokens,
@@ -114039,6 +114659,14 @@ Be concise in your responses. Show a summary of what you created.`;
114039
114659
  ...cost !== void 0 ? { cost } : {}
114040
114660
  })}
114041
114661
 
114662
+ `);
114663
+ } catch {
114664
+ }
114665
+ }
114666
+ if (stoppedAtStepLimit) {
114667
+ try {
114668
+ res.write(`data: ${JSON.stringify({ type: "step-limit-reached", limit: AI_MAX_STEPS })}
114669
+
114042
114670
  `);
114043
114671
  } catch {
114044
114672
  }
@@ -114178,26 +114806,70 @@ Be concise in your responses. Show a summary of what you created.`;
114178
114806
  parameters: [
114179
114807
  { name: "packageName", type: "string", required: true, description: "Package/service name" },
114180
114808
  { name: "name", type: "string", required: true, description: "Entity name (PascalCase)" },
114181
- { name: "description", type: "string", required: true, description: "Entity description" },
114809
+ { name: "description", type: "string", required: false, description: "Entity description" },
114182
114810
  { name: "stereotype", type: "string", required: false, description: "Stereotype: aggregate-root, reference-data, event, value-object" },
114183
114811
  { name: "attributes", type: "array", required: true, description: "Array of {name, type, description, required, primaryKey?, enumValues?}" }
114184
114812
  ]
114185
114813
  },
114814
+ {
114815
+ name: "updateEntity",
114816
+ description: "Update an existing entity; provided fields become the new desired state (uuid/createdAt preserved)",
114817
+ source: "builtin",
114818
+ parameters: [
114819
+ { name: "packageName", type: "string", required: true, description: "Package/service name" },
114820
+ { name: "name", type: "string", required: true, description: "Entity name (PascalCase)" },
114821
+ { name: "description", type: "string", required: false, description: "Entity description" },
114822
+ { name: "stereotype", type: "string", required: false, description: "Stereotype id" },
114823
+ { name: "attributes", type: "array", required: true, description: "New desired attribute set: {name, type, description, required, primaryKey?, enumValues?}" }
114824
+ ]
114825
+ },
114826
+ {
114827
+ name: "deleteEntity",
114828
+ description: "Delete an entity by package and name (fails if referenced by relationships)",
114829
+ source: "builtin",
114830
+ parameters: [
114831
+ { name: "packageName", type: "string", required: true, description: "Package/service name" },
114832
+ { name: "name", type: "string", required: true, description: "Entity name to delete" }
114833
+ ]
114834
+ },
114186
114835
  {
114187
114836
  name: "createRelationship",
114188
114837
  description: "Create a relationship between two entities. Endpoints may live in the same package or in different packages.",
114189
114838
  source: "builtin",
114190
114839
  parameters: [
114191
- { name: "packageName", type: "string", required: false, description: "Fallback package for both endpoints when sourcePackage/targetPackage are omitted" },
114192
114840
  { name: "sourceEntityName", type: "string", required: true, description: "Source entity name" },
114193
- { name: "sourcePackage", type: "string", required: false, description: "Package containing the source entity (defaults to packageName)" },
114194
114841
  { name: "targetEntityName", type: "string", required: true, description: "Target entity name" },
114195
- { name: "targetPackage", type: "string", required: false, description: "Package containing the target entity (defaults to packageName)" },
114196
- { name: "description", type: "string", required: true, description: "Relationship description" },
114842
+ { name: "sourcePackage", type: "string", required: false, description: "Package containing the source entity (omit to scan all)" },
114843
+ { name: "targetPackage", type: "string", required: false, description: "Package containing the target entity (omit to scan all)" },
114844
+ { name: "description", type: "string", required: false, description: "Relationship description" },
114845
+ { name: "sourceCardinality", type: "one|many", required: true, description: "Source cardinality" },
114846
+ { name: "targetCardinality", type: "one|many", required: true, description: "Target cardinality" }
114847
+ ]
114848
+ },
114849
+ {
114850
+ name: "updateRelationship",
114851
+ description: "Update an existing relationship (resolved by matching source/target entities)",
114852
+ source: "builtin",
114853
+ parameters: [
114854
+ { name: "sourceEntityName", type: "string", required: true, description: "Source entity name" },
114855
+ { name: "targetEntityName", type: "string", required: true, description: "Target entity name" },
114856
+ { name: "sourcePackage", type: "string", required: false, description: "Package containing the source entity (omit to scan all)" },
114857
+ { name: "targetPackage", type: "string", required: false, description: "Package containing the target entity (omit to scan all)" },
114858
+ { name: "description", type: "string", required: false, description: "Relationship description" },
114197
114859
  { name: "sourceCardinality", type: "one|many", required: true, description: "Source cardinality" },
114198
114860
  { name: "targetCardinality", type: "one|many", required: true, description: "Target cardinality" }
114199
114861
  ]
114200
114862
  },
114863
+ {
114864
+ name: "deleteRelationship",
114865
+ description: "Delete a relationship by its package (source entity's package) and source/target entity names",
114866
+ source: "builtin",
114867
+ parameters: [
114868
+ { name: "packageName", type: "string", required: true, description: "Package the relationship is stored under (source entity's package)" },
114869
+ { name: "sourceEntityName", type: "string", required: true, description: "Source entity name" },
114870
+ { name: "targetEntityName", type: "string", required: true, description: "Target entity name" }
114871
+ ]
114872
+ },
114201
114873
  {
114202
114874
  name: "listEntities",
114203
114875
  description: "List all entities in a package or all packages",
@@ -114829,14 +115501,14 @@ var init_file_router = __esm({
114829
115501
  });
114830
115502
 
114831
115503
  // backend/node_modules/@hamak/filesystem-server-impl/dist/routing/create-router.js
114832
- function createFileSystemRouter(workspaceManager2, config3) {
115504
+ function createFileSystemRouter(workspaceManager2, config4) {
114833
115505
  const app2 = (0, import_express30.Router)();
114834
- if (config3.enableCors ?? DEFAULT_FILESYSTEM_SERVER_CONFIG.enableCors) {
115506
+ if (config4.enableCors ?? DEFAULT_FILESYSTEM_SERVER_CONFIG.enableCors) {
114835
115507
  app2.use((0, import_cors.default)());
114836
115508
  }
114837
115509
  app2.use(import_body_parser.default.json());
114838
115510
  const fileRouter2 = new FileRouter(workspaceManager2);
114839
- const mountPath = config3.mountPath ?? DEFAULT_FILESYSTEM_SERVER_CONFIG.mountPath;
115511
+ const mountPath = config4.mountPath ?? DEFAULT_FILESYSTEM_SERVER_CONFIG.mountPath;
114840
115512
  app2.use(mountPath, fileRouter2.router);
114841
115513
  return app2;
114842
115514
  }
@@ -114871,17 +115543,17 @@ var init_filesystem_server_plugin = __esm({
114871
115543
  */
114872
115544
  initialize(ctx) {
114873
115545
  console.log("[FileSystemServerPlugin] Initializing...");
114874
- const config3 = ctx.resolve(FILESYSTEM_SERVER_CONFIG_TOKEN);
114875
- const workspaceManager2 = new WorkspaceManager(config3.workspaces, {
114876
- baseDirectory: config3.baseDirectory
115546
+ const config4 = ctx.resolve(FILESYSTEM_SERVER_CONFIG_TOKEN);
115547
+ const workspaceManager2 = new WorkspaceManager(config4.workspaces, {
115548
+ baseDirectory: config4.baseDirectory
114877
115549
  });
114878
115550
  ctx.provide({
114879
115551
  provide: WORKSPACE_MANAGER_TOKEN,
114880
115552
  useValue: workspaceManager2
114881
115553
  });
114882
115554
  console.log("[FileSystemServerPlugin] WorkspaceManager service registered");
114883
- console.log(`[FileSystemServerPlugin] Base directory: ${config3.baseDirectory}`);
114884
- console.log(`[FileSystemServerPlugin] Workspaces:`, Object.keys(config3.workspaces));
115555
+ console.log(`[FileSystemServerPlugin] Base directory: ${config4.baseDirectory}`);
115556
+ console.log(`[FileSystemServerPlugin] Workspaces:`, Object.keys(config4.workspaces));
114885
115557
  }
114886
115558
  /**
114887
115559
  * Activate phase - create router and make ready for use
@@ -114889,10 +115561,10 @@ var init_filesystem_server_plugin = __esm({
114889
115561
  activate(ctx) {
114890
115562
  console.log("[FileSystemServerPlugin] Activating...");
114891
115563
  const workspaceManager2 = ctx.resolve(WORKSPACE_MANAGER_TOKEN);
114892
- const config3 = ctx.resolve(FILESYSTEM_SERVER_CONFIG_TOKEN);
114893
- this.router = createFileSystemRouter(workspaceManager2, config3);
115564
+ const config4 = ctx.resolve(FILESYSTEM_SERVER_CONFIG_TOKEN);
115565
+ this.router = createFileSystemRouter(workspaceManager2, config4);
114894
115566
  console.log("[FileSystemServerPlugin] Activated successfully");
114895
- console.log(`[FileSystemServerPlugin] Mount path: ${config3.mountPath ?? "/api/workspaces"}`);
115567
+ console.log(`[FileSystemServerPlugin] Mount path: ${config4.mountPath ?? "/api/workspaces"}`);
114896
115568
  }
114897
115569
  /**
114898
115570
  * Deactivate phase - cleanup
@@ -114919,8 +115591,8 @@ var init_filesystem_server_plugin = __esm({
114919
115591
  });
114920
115592
 
114921
115593
  // backend/node_modules/@hamak/filesystem-server-impl/dist/middleware/workspace-validator.js
114922
- function createWorkspaceValidator(config3) {
114923
- const workspaces = config3.workspaces;
115594
+ function createWorkspaceValidator(config4) {
115595
+ const workspaces = config4.workspaces;
114924
115596
  return (req, res, next) => {
114925
115597
  const workspace = req.params.workspace;
114926
115598
  if (!workspace) {
@@ -156395,150 +157067,8 @@ var model_metadata_routes_default = router9;
156395
157067
  // backend/src/routes/data-dictionary/dico-config.routes.ts
156396
157068
  var import_express11 = __toESM(require_express2(), 1);
156397
157069
 
156398
- // backend/src/services/dicoConfigService.ts
156399
- init_EntitySchema();
156400
- init_logger();
156401
- init_StorageBackendToken();
156402
- init_types();
156403
- var DOMAIN_KINDS = /* @__PURE__ */ new Set(["enum", "codelist", "reference"]);
156404
- var DICT_WS2 = wsId("dictionaries");
156405
- var CONFIG_PATH = pathOf("dico.config.json");
156406
- var STANDARD_TYPES = new Set(Object.values(AttributeType));
156407
- async function readConfig() {
156408
- try {
156409
- const raw = await storageRegistry.getBackend().read(DICT_WS2, CONFIG_PATH);
156410
- const parsed = JSON.parse(raw);
156411
- if (typeof parsed.version !== "number") parsed.version = 1;
156412
- return parsed;
156413
- } catch (e) {
156414
- if (e.code === "not-found") return { version: 1 };
156415
- logger.error(`Failed to read dico.config.json: ${e}`);
156416
- return { version: 1 };
156417
- }
156418
- }
156419
- __name(readConfig, "readConfig");
156420
- async function writeConfig(next) {
156421
- const body = JSON.stringify(next, null, 2) + "\n";
156422
- await storageRegistry.getBackend().write(DICT_WS2, CONFIG_PATH, body);
156423
- }
156424
- __name(writeConfig, "writeConfig");
156425
- async function listDerivedTypes() {
156426
- const cfg = await readConfig();
156427
- return Array.isArray(cfg.types) ? cfg.types : [];
156428
- }
156429
- __name(listDerivedTypes, "listDerivedTypes");
156430
- async function replaceDerivedTypes(next) {
156431
- const errors = validateDerivedTypes(next);
156432
- if (errors.length > 0) return { success: false, errors };
156433
- const cfg = await readConfig();
156434
- cfg.types = next;
156435
- await writeConfig(cfg);
156436
- return { success: true };
156437
- }
156438
- __name(replaceDerivedTypes, "replaceDerivedTypes");
156439
- function validateDerivedTypes(types) {
156440
- const errors = [];
156441
- const byName = /* @__PURE__ */ new Map();
156442
- for (const t of types) {
156443
- if (!t?.name || typeof t.name !== "string") {
156444
- errors.push("Each derived type must have a `name` string");
156445
- continue;
156446
- }
156447
- if (STANDARD_TYPES.has(t.name)) {
156448
- errors.push(`Derived type name '${t.name}' shadows a standard AttributeType`);
156449
- }
156450
- if (byName.has(t.name)) {
156451
- errors.push(`Duplicate derived type name: '${t.name}'`);
156452
- } else {
156453
- byName.set(t.name, t);
156454
- }
156455
- if (!t.basedOn || typeof t.basedOn !== "string") {
156456
- errors.push(`Derived type '${t.name}' must declare a \`basedOn\``);
156457
- }
156458
- if (t.domain) errors.push(...validateDomain(t.name, t.domain));
156459
- }
156460
- for (const t of types) {
156461
- if (!t?.name || !t?.basedOn) continue;
156462
- const visited = /* @__PURE__ */ new Set();
156463
- let cursor = t.basedOn;
156464
- while (cursor && !STANDARD_TYPES.has(cursor)) {
156465
- if (visited.has(cursor)) {
156466
- errors.push(`Circular derivation starting at '${t.name}' (cycle via '${cursor}')`);
156467
- break;
156468
- }
156469
- visited.add(cursor);
156470
- const next = byName.get(cursor);
156471
- if (!next) {
156472
- errors.push(`Derived type '${t.name}' references unknown type '${cursor}'`);
156473
- break;
156474
- }
156475
- cursor = next.basedOn;
156476
- }
156477
- }
156478
- return errors;
156479
- }
156480
- __name(validateDerivedTypes, "validateDerivedTypes");
156481
- function validateDomain(typeName, domain2) {
156482
- const errors = [];
156483
- if (!DOMAIN_KINDS.has(domain2.kind)) {
156484
- errors.push(`Derived type '${typeName}' has invalid domain kind '${domain2.kind}'`);
156485
- return errors;
156486
- }
156487
- const hasValues = Array.isArray(domain2.values) && domain2.values.length > 0;
156488
- const hasSource = typeof domain2.source === "string" && domain2.source.trim().length > 0;
156489
- if (domain2.kind === "enum") {
156490
- if (!hasValues) errors.push(`Enum domain '${typeName}' must list at least one value`);
156491
- if (hasSource) errors.push(`Enum domain '${typeName}' must not declare a \`source\``);
156492
- } else if (domain2.kind === "codelist") {
156493
- if (!hasSource) errors.push(`Codelist domain '${typeName}' must declare a \`source\` name`);
156494
- } else if (domain2.kind === "reference") {
156495
- if (!hasSource) errors.push(`Reference domain '${typeName}' must declare a \`source\` name`);
156496
- if (hasValues) errors.push(`Reference domain '${typeName}' must not carry inline \`values\` (they come from the source)`);
156497
- }
156498
- return errors;
156499
- }
156500
- __name(validateDomain, "validateDomain");
156501
- function resolveDomain(typeName, derivedTypes) {
156502
- if (STANDARD_TYPES.has(typeName)) return null;
156503
- const byName = new Map(derivedTypes.map((t) => [t.name, t]));
156504
- const visited = /* @__PURE__ */ new Set();
156505
- let cursor = typeName;
156506
- while (!STANDARD_TYPES.has(cursor)) {
156507
- if (visited.has(cursor)) return null;
156508
- visited.add(cursor);
156509
- const dt = byName.get(cursor);
156510
- if (!dt) return null;
156511
- if (dt.domain) return dt.domain;
156512
- cursor = dt.basedOn;
156513
- }
156514
- return null;
156515
- }
156516
- __name(resolveDomain, "resolveDomain");
156517
- function resolveAttributeType(typeName, derivedTypes) {
156518
- if (STANDARD_TYPES.has(typeName)) {
156519
- return { baseType: typeName, validation: {} };
156520
- }
156521
- const byName = new Map(derivedTypes.map((t) => [t.name, t]));
156522
- const chain = [];
156523
- const visited = /* @__PURE__ */ new Set();
156524
- let cursor = typeName;
156525
- while (!STANDARD_TYPES.has(cursor)) {
156526
- if (visited.has(cursor)) return null;
156527
- visited.add(cursor);
156528
- const dt = byName.get(cursor);
156529
- if (!dt) return null;
156530
- chain.push(dt);
156531
- cursor = dt.basedOn;
156532
- }
156533
- const merged = {};
156534
- for (let i = chain.length - 1; i >= 0; i--) {
156535
- Object.assign(merged, chain[i].validation || {});
156536
- }
156537
- return { baseType: cursor, validation: merged };
156538
- }
156539
- __name(resolveAttributeType, "resolveAttributeType");
156540
-
156541
157070
  // backend/src/controllers/dicoConfigController.ts
157071
+ init_dicoConfigService();
156542
157072
  init_logger();
156543
157073
  var getDerivedTypes = /* @__PURE__ */ __name(async (_req, res) => {
156544
157074
  try {
@@ -158878,7 +159408,7 @@ var PhysicalConfigService = class {
158878
159408
  * service directory doesn't exist — configs for unknown services are a
158879
159409
  * caller bug, not something to silently create.
158880
159410
  */
158881
- async set(serviceName, config3) {
159411
+ async set(serviceName, config4) {
158882
159412
  try {
158883
159413
  await this.storage.stat(this.ws, pathOf(serviceName));
158884
159414
  } catch (e) {
@@ -158888,8 +159418,8 @@ var PhysicalConfigService = class {
158888
159418
  throw e;
158889
159419
  }
158890
159420
  const safe = {
158891
- dialect: config3.dialect,
158892
- connection: { ...config3.connection }
159421
+ dialect: config4.dialect,
159422
+ connection: { ...config4.connection }
158893
159423
  };
158894
159424
  const conn = safe.connection;
158895
159425
  delete conn.user;
@@ -158912,11 +159442,11 @@ var _instance = new PhysicalConfigService();
158912
159442
  var getPhysicalConfig = /* @__PURE__ */ __name((s) => _instance.get(s), "getPhysicalConfig");
158913
159443
  var setPhysicalConfig = /* @__PURE__ */ __name((s, c) => _instance.set(s, c), "setPhysicalConfig");
158914
159444
  var deletePhysicalConfig = /* @__PURE__ */ __name((s) => _instance.delete(s), "deletePhysicalConfig");
158915
- function mergeCredentials(config3, credentials) {
159445
+ function mergeCredentials(config4, credentials) {
158916
159446
  return {
158917
- dialect: config3.dialect,
159447
+ dialect: config4.dialect,
158918
159448
  connection: {
158919
- ...config3.connection,
159449
+ ...config4.connection,
158920
159450
  user: credentials.user,
158921
159451
  password: credentials.password
158922
159452
  }
@@ -160023,13 +160553,13 @@ var exportMigration = /* @__PURE__ */ __name(async (req, res) => {
160023
160553
  }
160024
160554
  }, "exportMigration");
160025
160555
  async function introspectServiceLive(serviceName, credentials, connectionOverrides) {
160026
- const config3 = await getPhysicalConfig(serviceName);
160027
- if (!config3) {
160556
+ const config4 = await getPhysicalConfig(serviceName);
160557
+ if (!config4) {
160028
160558
  throw new Error(`No physical.yaml config for service '${serviceName}'`);
160029
160559
  }
160030
- const hydrated = mergeCredentials(config3, credentials);
160560
+ const hydrated = mergeCredentials(config4, credentials);
160031
160561
  const connection = { ...hydrated.connection, ...connectionOverrides || {} };
160032
- switch (config3.dialect) {
160562
+ switch (config4.dialect) {
160033
160563
  case "oracle": {
160034
160564
  const result = await introspectOracle({
160035
160565
  connection
@@ -160067,7 +160597,7 @@ async function introspectServiceLive(serviceName, credentials, connectionOverrid
160067
160597
  return result.entities;
160068
160598
  }
160069
160599
  default:
160070
- throw new Error(`Unknown dialect '${config3.dialect}'`);
160600
+ throw new Error(`Unknown dialect '${config4.dialect}'`);
160071
160601
  }
160072
160602
  }
160073
160603
  __name(introspectServiceLive, "introspectServiceLive");
@@ -160334,6 +160864,7 @@ var import_express13 = __toESM(require_express2(), 1);
160334
160864
  // backend/src/services/exportService.ts
160335
160865
  init_EntitySchema();
160336
160866
  init_fileOperations();
160867
+ init_dicoConfigService();
160337
160868
  init_metadata();
160338
160869
  var ATTR_TO_JSON_SCHEMA = {
160339
160870
  ["string" /* STRING */]: "string",