negotium 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/agent-helpers.js +107 -6
  2. package/dist/agent-helpers.js.map +11 -11
  3. package/dist/background-bash.js +3 -2
  4. package/dist/background-bash.js.map +4 -4
  5. package/dist/browser-runtime.js +3 -2
  6. package/dist/browser-runtime.js.map +4 -4
  7. package/dist/chunk-s2gez3wg.js.map +1 -1
  8. package/dist/{chunk-1y2xw0xe.js → chunk-vvfwqxnh.js} +33 -3
  9. package/dist/{chunk-1y2xw0xe.js.map → chunk-vvfwqxnh.js.map} +8 -8
  10. package/dist/hosted-agent.js +34 -4
  11. package/dist/hosted-agent.js.map +8 -8
  12. package/dist/main.js +1179 -366
  13. package/dist/main.js.map +24 -21
  14. package/dist/mcp-catalog.js +2 -1
  15. package/dist/mcp-catalog.js.map +3 -3
  16. package/dist/mcp-factories.js +635 -256
  17. package/dist/mcp-factories.js.map +15 -13
  18. package/dist/mcp-servers.js +3 -1
  19. package/dist/mcp-servers.js.map +3 -3
  20. package/dist/prompts.js +8 -2
  21. package/dist/prompts.js.map +5 -5
  22. package/dist/query-runtime.js +3 -2
  23. package/dist/query-runtime.js.map +4 -4
  24. package/dist/registry.js +3 -3
  25. package/dist/registry.js.map +2 -2
  26. package/dist/rollout.js +1 -1
  27. package/dist/runtime/src/mcp/canonical-bridge-config.ts +1 -1
  28. package/dist/runtime/src/mcp/canonical-proxy-server.ts +74 -1
  29. package/dist/runtime/src/mcp/decision-server.ts +21 -0
  30. package/dist/runtime/src/mcp/factories/decision.ts +178 -0
  31. package/dist/runtime/src/mcp/factories/index.ts +6 -0
  32. package/dist/runtime/src/mcp/runtime-spec.ts +1 -0
  33. package/dist/runtime/src/node-host.ts +1 -0
  34. package/dist/runtime/src/platform/config.ts +2 -1
  35. package/dist/runtime/src/platform/mcp-catalog-policy.ts +1 -0
  36. package/dist/runtime/src/platform/mcp-config.ts +31 -1
  37. package/dist/runtime/src/prompts/builders.ts +5 -0
  38. package/dist/runtime/src/runtime/visual-html.ts +68 -2
  39. package/dist/runtime/src/storage/decisions.ts +231 -0
  40. package/dist/runtime/src/storage/storage-public.ts +2 -0
  41. package/dist/runtime/src/types.ts +13 -0
  42. package/dist/runtime/src/version.ts +1 -1
  43. package/dist/runtime-helpers.js +71 -4
  44. package/dist/runtime-helpers.js.map +5 -5
  45. package/dist/storage.js +261 -56
  46. package/dist/storage.js.map +5 -4
  47. package/dist/types/apps/negotium/src/mcp-servers.d.ts +1 -1
  48. package/dist/types/packages/core/src/mcp/canonical-bridge-config.d.ts +1 -1
  49. package/dist/types/packages/core/src/mcp/factories/decision.d.ts +16 -0
  50. package/dist/types/packages/core/src/mcp/factories/index.d.ts +1 -0
  51. package/dist/types/packages/core/src/mcp/runtime-spec.d.ts +1 -1
  52. package/dist/types/packages/core/src/platform/config.d.ts +2 -1
  53. package/dist/types/packages/core/src/platform/mcp-catalog-policy.d.ts +4 -0
  54. package/dist/types/packages/core/src/storage/decisions.d.ts +45 -0
  55. package/dist/types/packages/core/src/storage/storage-public.d.ts +2 -0
  56. package/dist/types/packages/core/src/types.d.ts +12 -0
  57. package/dist/types/packages/core/src/version.d.ts +1 -1
  58. package/dist/vault.js +3 -2
  59. package/dist/vault.js.map +4 -4
  60. package/install-browser-rs.mjs +3 -3
  61. package/package.json +2 -2
@@ -351,7 +351,7 @@ function resolveDefaultModel(agent, registryDefaultModel) {
351
351
  function codexAuthFilePath() {
352
352
  return process.env.NEGOTIUM_CODEX_AUTH_FILE || join(process.env.CODEX_HOME || join(homedir(), ".codex"), "auth.json");
353
353
  }
354
- var HOME, PROJECT_ROOT, STATE_DIR_ENV, STATE_DIR, WORKSPACE_DIR, TOPIC_WORKSPACE_DIR, SHARED_WIKI_DIR, CRON_WORKSPACE_DIR, BROWSER_DIR, BROWSER_PROFILES_DIR, BINARIES_DIR, SECRETS_DIR, DM_WORKSPACE_DIR, SESSION_WORKSPACE_DIR, CLAUDE_EXECUTABLE_ENV, CLAUDE_EXECUTABLE, DEFAULT_OUTPUT_LANGUAGE = "English", BROWSER_RS_VERSION = "v0.1.19", BROWSER_RS_MIN_SECURE_VERSION = "0.1.15", BROWSER_RS_VERSION_PROBE_TIMEOUT_MS = 15000, SNIPPETS_API_URL, BROWSER_RS_BIN, BASH_RS_VERSION = "v0.1.5", BASH_RS_BIN, PLAYWRIGHT_MCP_BIN, TSX_BIN, TSX_LOADER, TSCONFIG_PATH, SESSION_COMM_SERVER, TASK_SERVER, BROWSER_MCP_SSE_PROXY_SERVER, CANONICAL_MCP_PROXY_SERVER, WIKI_SERVER, TOKEN_STATS_SERVER, COMPACTION_LOG_SERVER, SYSTEM_HEALTH_SERVER, AGENT_HEALTH_SERVER, VAULT_SERVER, BG_BASH_BASE_PORT, BG_BASH_MAX_PORT, RUNTIME_MCP_SECRET, NODE_CONTROL_TOKEN, NODE_ID, VAULT_MASTER_KEY, NEGOTIUM_PORT, hostname, DATA_DIR, LOG_DIR, UPLOADS_DIR, VAULT_DIR, SESSIONS_DB, DEBUG_FILE, USERS_LOG_DIR, RUN_DIR, PROGRESS_DIR, DM_CMD_DIR, DM_RESP_DIR, SESSION_INBOX_DIR, SESSION_ASKS_DIR, BASHRS_SPILL_ROOT, PLAYWRIGHT_BASE_PORT, PLAYWRIGHT_MAX_PORT, PLAYWRIGHT_PORTS_DIR, ACTIVE_QUERY_STALE_MS, AGENTS_PROMPTS_DIR, RESOURCES_DIR, FILE_TAG_REGEX, MODEL_SONNET = "claude-sonnet-5", MODEL_OPUS = "claude-opus-5", MODEL_FABLE = "claude-fable-5", FALLBACK_AGENT, SESSION_AGENT, GATEWAY_AGENT, FALLBACK_MODEL, SESSION_MODEL, GATEWAY_MODEL, FFMPEG_BIN, FFPROBE_BIN, PYTHON_BIN, FASTER_WHISPER_WRAPPER, WHISPER_MODEL, TESSERACT_BIN, PDFTOTEXT_BIN, _envMaxTellDepth, MAX_TELL_DEPTH;
354
+ var HOME, PROJECT_ROOT, STATE_DIR_ENV, STATE_DIR, WORKSPACE_DIR, TOPIC_WORKSPACE_DIR, SHARED_WIKI_DIR, CRON_WORKSPACE_DIR, BROWSER_DIR, BROWSER_PROFILES_DIR, BINARIES_DIR, SECRETS_DIR, DM_WORKSPACE_DIR, SESSION_WORKSPACE_DIR, CLAUDE_EXECUTABLE_ENV, CLAUDE_EXECUTABLE, DEFAULT_OUTPUT_LANGUAGE = "English", BROWSER_RS_VERSION = "v0.1.21", BROWSER_RS_MIN_SECURE_VERSION = "0.1.15", BROWSER_RS_VERSION_PROBE_TIMEOUT_MS = 15000, SNIPPETS_API_URL, BROWSER_RS_BIN, BASH_RS_VERSION = "v0.1.5", BASH_RS_BIN, PLAYWRIGHT_MCP_BIN, TSX_BIN, TSX_LOADER, TSCONFIG_PATH, SESSION_COMM_SERVER, TASK_SERVER, DECISION_SERVER, BROWSER_MCP_SSE_PROXY_SERVER, CANONICAL_MCP_PROXY_SERVER, WIKI_SERVER, TOKEN_STATS_SERVER, COMPACTION_LOG_SERVER, SYSTEM_HEALTH_SERVER, AGENT_HEALTH_SERVER, VAULT_SERVER, BG_BASH_BASE_PORT, BG_BASH_MAX_PORT, RUNTIME_MCP_SECRET, NODE_CONTROL_TOKEN, NODE_ID, VAULT_MASTER_KEY, NEGOTIUM_PORT, hostname, DATA_DIR, LOG_DIR, UPLOADS_DIR, VAULT_DIR, SESSIONS_DB, DEBUG_FILE, USERS_LOG_DIR, RUN_DIR, PROGRESS_DIR, DM_CMD_DIR, DM_RESP_DIR, SESSION_INBOX_DIR, SESSION_ASKS_DIR, BASHRS_SPILL_ROOT, PLAYWRIGHT_BASE_PORT, PLAYWRIGHT_MAX_PORT, PLAYWRIGHT_PORTS_DIR, ACTIVE_QUERY_STALE_MS, AGENTS_PROMPTS_DIR, RESOURCES_DIR, FILE_TAG_REGEX, MODEL_SONNET = "claude-sonnet-5", MODEL_OPUS = "claude-opus-5", MODEL_FABLE = "claude-fable-5", FALLBACK_AGENT, SESSION_AGENT, GATEWAY_AGENT, FALLBACK_MODEL, SESSION_MODEL, GATEWAY_MODEL, FFMPEG_BIN, FFPROBE_BIN, PYTHON_BIN, FASTER_WHISPER_WRAPPER, WHISPER_MODEL, TESSERACT_BIN, PDFTOTEXT_BIN, _envMaxTellDepth, MAX_TELL_DEPTH;
355
355
  var init_config = __esm(() => {
356
356
  init_config_helpers();
357
357
  init_logger();
@@ -381,6 +381,7 @@ var init_config = __esm(() => {
381
381
  TSCONFIG_PATH = resolve2(PROJECT_ROOT, "tsconfig.json");
382
382
  SESSION_COMM_SERVER = resolve2(PROJECT_ROOT, "src/mcp/session-comm/server.ts");
383
383
  TASK_SERVER = resolve2(PROJECT_ROOT, "src/mcp/task-server.ts");
384
+ DECISION_SERVER = resolve2(PROJECT_ROOT, "src/mcp/decision-server.ts");
384
385
  BROWSER_MCP_SSE_PROXY_SERVER = resolve2(PROJECT_ROOT, "src/mcp/browser-sse-proxy-server.ts");
385
386
  CANONICAL_MCP_PROXY_SERVER = resolve2(PROJECT_ROOT, "src/mcp/canonical-proxy-server.ts");
386
387
  WIKI_SERVER = resolve2(PROJECT_ROOT, "src/mcp/wiki-server.ts");
@@ -836,6 +837,7 @@ var init_mcp_catalog_policy = __esm(() => {
836
837
  runtime: { scopes: ["forum", "manager", "fork", "cron"], forumRequired: true },
837
838
  "token-stats": { scopes: ["dm", "forum", "manager", "cron"], forumRequired: true },
838
839
  task: { scopes: ["dm", "forum", "manager", "cron"], forumRequired: true },
840
+ decision: { scopes: ["dm", "forum", "manager", "cron"], forumRequired: true },
839
841
  "session-comm": { scopes: ["forum", "fork", "manager"], forumRequired: true },
840
842
  wiki: { scopes: ["dm", "forum", "manager", "cron"], forumRequired: true },
841
843
  skills: { scopes: ["dm", "forum", "manager", "cron"], forumRequired: true },
@@ -1059,7 +1061,7 @@ function getForumMcpServers(opts) {
1059
1061
  peerBridge
1060
1062
  } = opts;
1061
1063
  const filter = (name) => {
1062
- if (silent && name === "task")
1064
+ if (silent && (name === "task" || name === "decision"))
1063
1065
  return false;
1064
1066
  if (enabled === null)
1065
1067
  return true;
@@ -1277,6 +1279,34 @@ var init_mcp_config = __esm(() => {
1277
1279
  return buildBuiltinMcpServer("task", ctx, () => buildStdioMcpServer(agent, TASK_SERVER, args));
1278
1280
  }
1279
1281
  },
1282
+ decision: {
1283
+ ...commonRuntimeMcpPolicy("decision"),
1284
+ build(ctx) {
1285
+ const { userId, session, topicId, queryId, agent, model, peerBridge } = ctx;
1286
+ if (peerBridge) {
1287
+ if (!topicId || !queryId)
1288
+ return null;
1289
+ const env = canonicalMcpBridgeEnv({
1290
+ surface: "decision",
1291
+ userId,
1292
+ topicId,
1293
+ queryId,
1294
+ peerBridge
1295
+ });
1296
+ return env ? buildStdioMcpServer(agent, CANONICAL_MCP_PROXY_SERVER, ["--surface=decision"], env) : null;
1297
+ }
1298
+ const args = [
1299
+ `--user-id=${userId}`,
1300
+ `--topic=${session}`,
1301
+ `--agent=${agent ?? FALLBACK_AGENT}`
1302
+ ];
1303
+ if (topicId)
1304
+ args.push(`--topic-id=${topicId}`);
1305
+ if (model)
1306
+ args.push(`--model=${model}`);
1307
+ return buildBuiltinMcpServer("decision", ctx, () => buildStdioMcpServer(agent, DECISION_SERVER, args));
1308
+ }
1309
+ },
1280
1310
  "session-comm": {
1281
1311
  ...commonRuntimeMcpPolicy("session-comm"),
1282
1312
  build(ctx) {
@@ -2399,7 +2429,7 @@ var init_claude_registry = __esm(() => {
2399
2429
  });
2400
2430
 
2401
2431
  // ../../packages/core/src/version.ts
2402
- var NEGOTIUM_VERSION = "0.3.0";
2432
+ var NEGOTIUM_VERSION = "0.3.2";
2403
2433
 
2404
2434
  // ../../packages/core/src/agents/codex-native-multi-agent.ts
2405
2435
  import { spawn as spawn2 } from "child_process";
@@ -6593,6 +6623,7 @@ function buildRuntimeToolSection(opts, extensions) {
6593
6623
  } = opts;
6594
6624
  const runtimeNamespace = "mcp__runtime";
6595
6625
  const taskNamespace = "mcp__task";
6626
+ const decisionNamespace = "mcp__decision";
6596
6627
  const visualToolLine = agentKind === "codex" ? `To display charts, tables, or interactive HTML results to the user, call the \`show_html\` function in the \`${runtimeNamespace}\` namespace with { html: "<complete HTML string>", title?: "optional title" }.` : `To display charts, tables, or interactive HTML results to the user, call the MCP tool "${runtimeNamespace}__show_html" with { html: "<complete HTML string>", title?: "optional title" }.`;
6597
6628
  const mermaidToolLine = agentKind === "codex" ? `For diagrams that Mermaid supports, prefer the \`show_mermaid\` function in the \`${runtimeNamespace}\` namespace with { code: "<Mermaid DSL without markdown fences>", title?: "...", theme?: "neutral" }.` : `For diagrams that Mermaid supports, prefer the MCP tool "${runtimeNamespace}__show_mermaid" with { code: "<Mermaid DSL without markdown fences>", title?: "...", theme?: "neutral" }.`;
6598
6629
  const mediaToolLine = agentKind === "codex" ? `To display an existing image or video in the visual panel, use \`show_image\` or \`show_video\` in the \`${runtimeNamespace}\` namespace with either { file_path: "...", title?: "..." } for a topic-workspace file or { file_id: "...", title?: "..." } for an uploaded file already attached in this topic.` : `To display an existing image or video in the visual panel, use MCP tool "${runtimeNamespace}__show_image" or "${runtimeNamespace}__show_video" with either { file_path: "...", title?: "..." } for a topic-workspace file or { file_id: "...", title?: "..." } for an uploaded file already attached in this topic.`;
@@ -6600,6 +6631,7 @@ function buildRuntimeToolSection(opts, extensions) {
6600
6631
  const askUserToolLine = agentKind === "codex" ? `When you need a blocking user choice, call the \`ask_user_question\` function in the \`${runtimeNamespace}\` namespace with { question: "...", choices: [{ label: "...", description?: "..." }] }.` : `When you need a blocking user choice, call the MCP tool "${runtimeNamespace}__ask_user_question" with { question: "...", choices: [{ label: "...", description?: "..." }] }.`;
6601
6632
  const scheduleSelfToolLine = agentKind === "codex" ? `For a one-shot delayed continuation within 24 hours, call the \`schedule_self\` function in the \`${runtimeNamespace}\` namespace with { delay_seconds: number, message: "self-contained future instruction" }. Only one pending self-schedule is allowed per topic; use \`get_self_schedule\`, \`update_self_schedule\`, or \`cancel_self_schedule\` in that namespace to manage it. Use cron-manager for recurring schedules.` : `For a one-shot delayed continuation within 24 hours, call the MCP tool "${runtimeNamespace}__schedule_self" with { delay_seconds: number, message: "self-contained future instruction" }. Only one pending self-schedule is allowed per topic; manage it with "${runtimeNamespace}__get_self_schedule", "${runtimeNamespace}__update_self_schedule", or "${runtimeNamespace}__cancel_self_schedule". Use cron-manager for recurring schedules.`;
6602
6633
  const taskToolLine = agentKind === "codex" ? `For task tracking, use \`task_create\`, \`task_update\`, \`task_list\`, \`task_get\`, and \`task_delete\` functions in the \`${taskNamespace}\` namespace.` : `For task tracking, use MCP tools "${taskNamespace}__task_create", "${taskNamespace}__task_update", "${taskNamespace}__task_list", "${taskNamespace}__task_get", and "${taskNamespace}__task_delete".`;
6634
+ const decisionToolLine = `Use the shared Decision tools in the \`${decisionNamespace}\` namespace when an architectural, product, or operational choice establishes or changes a durable direction or constraint. Do not record routine task progress or temporary implementation details; link causal predecessors when relevant.`;
6603
6635
  const runtimeToolRef = (name) => agentKind === "codex" ? `\`${name}\`` : `"${runtimeNamespace}__${name}"`;
6604
6636
  const spawnSubagentToolLine = `Use ${runtimeToolRef("spawn_subagent")} for self-contained parallel or long-running background work; keep quick work inline.`;
6605
6637
  const lifecycleToolLine = `For staged work, call ${runtimeToolRef("create_subagent")} then ${runtimeToolRef("start_subagent")}. Create fixes \`task\` and \`report_mode\`; start takes only the room ID, so create after inputs are known unless preparing a \`tell_session\` receiver. Manage descendants with ${runtimeToolRef("list_subagents")} and ${runtimeToolRef("delete_subagent")}, and non-parent tell routes with ${runtimeToolRef("grant_subagent_tell")} and ${runtimeToolRef("revoke_subagent_tell")}. Direct-parent reporting needs no grant. Use ${runtimeToolRef("list_memory_topics")} to select \`memory_topic\`.`;
@@ -6646,6 +6678,9 @@ function buildRuntimeToolSection(opts, extensions) {
6646
6678
  taskToolLine,
6647
6679
  "Use this shared task store for plans, progress, and checklist updates; it is visible across claude/codex/maestro turns.",
6648
6680
  nativeTaskPolicyLine,
6681
+ "",
6682
+ "## Shared Decisions",
6683
+ decisionToolLine,
6649
6684
  ...extensions.render("after-shared-tasks"),
6650
6685
  ...fileDeliverySection,
6651
6686
  ...extensions.render("before-session-communication"),
@@ -14761,6 +14796,10 @@ function buildMermaidHtml(code, theme, scriptUrl = MERMAID_BROWSER_ASSET_RELATIV
14761
14796
  .controls button:focus-visible{outline:2px solid var(--celadon);outline-offset:1px}
14762
14797
  .zoom-value{min-width:46px;color:var(--graphite);font:500 11px/1 Geist,system-ui,sans-serif;text-align:center;font-variant-numeric:tabular-nums}
14763
14798
  .error{margin:0;white-space:pre-wrap;color:#7D2E2E;background:#FFF5F2;border:1px solid #E4B9B1;border-radius:6px;padding:14px;font:13px ui-monospace,SFMono-Regular,Menlo,monospace}
14799
+ .failure{max-width:56ch;margin:0 auto}
14800
+ .failure p{margin:0 0 12px;color:var(--graphite);font:14px/1.6 Geist,system-ui,sans-serif}
14801
+ .failure details{color:var(--graphite);font:12px/1.5 Geist,system-ui,sans-serif}
14802
+ .failure summary{cursor:pointer;padding:4px 0}
14764
14803
  @media(max-width:600px){.viewport{padding:54px 14px 18px}.controls{top:10px;right:10px}}
14765
14804
  </style>
14766
14805
  </head>
@@ -14775,11 +14814,58 @@ function buildMermaidHtml(code, theme, scriptUrl = MERMAID_BROWSER_ASSET_RELATIV
14775
14814
  <script data-otium-mermaid-runtime src="${safeScriptUrl}"></script>
14776
14815
  <script>
14777
14816
  (async () => {
14817
+ // An unrendered document reports itself in more than one voice: Mermaid's
14818
+ // own 0x0 guard, and the browser refusing geometry on a path that was
14819
+ // never laid out. Both mean the same thing, so both are worth one retry
14820
+ // and, if it still fails, the same explanation.
14821
+ const unrendered = (error) => {
14822
+ const message = String(error && error.message ? error.message : error);
14823
+ return message.indexOf("not in render tree") !== -1 || message.indexOf("path is empty") !== -1;
14824
+ };
14778
14825
  try {
14779
14826
  const runtime = globalThis.mermaid;
14780
14827
  if (!runtime) throw new Error("Mermaid renderer failed to load.");
14781
14828
  runtime.initialize({ startOnLoad: false, securityLevel: "strict", theme: ${safeTheme} });
14782
- await runtime.run({ querySelector: ".mermaid" });
14829
+ const host = document.querySelector(".mermaid");
14830
+ // Mermaid sizes every label by appending a probe <svg> to the body and
14831
+ // reading getBBox(), and it throws "svg element not in render tree" the
14832
+ // moment that comes back 0x0. That is what a hidden panel looks like from
14833
+ // in here: the document exists but nothing is in the render tree, so the
14834
+ // measurement has no geometry to report. Ask the same question Mermaid
14835
+ // will ask, and only start once it has an answer.
14836
+ const measurable = () => {
14837
+ const probe = document.createElementNS("http://www.w3.org/2000/svg", "svg");
14838
+ const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
14839
+ text.textContent = "M";
14840
+ probe.appendChild(text);
14841
+ document.body.appendChild(probe);
14842
+ let box = { width: 0, height: 0 };
14843
+ try { box = text.getBBox(); } catch (ignored) {}
14844
+ probe.remove();
14845
+ return box.width > 0 || box.height > 0;
14846
+ };
14847
+ // requestAnimationFrame is the right clock here: a hidden document stops
14848
+ // being animated, so this waits without spinning and resumes on the frame
14849
+ // the panel is shown. The cap counts rendered frames, not wall time.
14850
+ const waitUntilMeasurable = async (maxFrames) => {
14851
+ for (let frame = 0; frame < maxFrames; frame += 1) {
14852
+ if (measurable()) return true;
14853
+ await new Promise((next) => requestAnimationFrame(next));
14854
+ }
14855
+ return measurable();
14856
+ };
14857
+ await waitUntilMeasurable(600);
14858
+ try {
14859
+ await runtime.run({ querySelector: ".mermaid" });
14860
+ } catch (firstAttempt) {
14861
+ if (!unrendered(firstAttempt)) throw firstAttempt;
14862
+ // The panel can be hidden again between the probe and the real measure.
14863
+ // Clear the marker Mermaid leaves behind so the retry is not skipped as
14864
+ // already done, then wait for the render tree once more.
14865
+ host.removeAttribute("data-processed");
14866
+ await waitUntilMeasurable(600);
14867
+ await runtime.run({ querySelector: ".mermaid" });
14868
+ }
14783
14869
  const viewport = document.querySelector(".viewport");
14784
14870
  const svg = document.querySelector(".mermaid svg");
14785
14871
  const value = document.querySelector(".zoom-value");
@@ -14806,7 +14892,22 @@ function buildMermaidHtml(code, theme, scriptUrl = MERMAID_BROWSER_ASSET_RELATIV
14806
14892
  applyScale(scale, false);
14807
14893
  } catch (error) {
14808
14894
  document.querySelector(".controls")?.remove();
14809
- document.querySelector(".viewport").innerHTML = '<pre class="error">' + String(error && error.message ? error.message : error).replace(/[&<>]/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;'}[c])) + '</pre>';
14895
+ const raw = String(error && error.message ? error.message : error);
14896
+ const escape = (value) => value.replace(/[&<>]/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;'}[c]));
14897
+ // Mermaid aborts the whole render when it cannot place an edge label:
14898
+ // cardinality markers ask for a point a fixed distance along the edge,
14899
+ // and a relation laid out shorter than that walks off the end. Nothing
14900
+ // is wrong with the diagram, so the raw message sends authors looking
14901
+ // for a syntax error that does not exist. Say what actually moves it.
14902
+ const note = raw.indexOf("Could not find a suitable point") !== -1
14903
+ ? "Two nodes ended up too close together for Mermaid to fit a label on the edge between them. Renaming a node, adding another, or setting an explicit direction usually spreads the layout enough to render."
14904
+ : unrendered(error)
14905
+ ? "The panel stayed hidden long enough that there was never a laid-out page to measure the diagram against. Reopening the panel renders it."
14906
+ : "This diagram could not be rendered.";
14907
+ document.querySelector(".viewport").innerHTML =
14908
+ '<div class="failure"><p>' + escape(note) +
14909
+ '</p><details><summary>Technical detail</summary><pre class="error">' +
14910
+ escape(raw) + '</pre></details></div>';
14810
14911
  }
14811
14912
  })();
14812
14913
  </script>
@@ -18895,4 +18996,4 @@ export {
18895
18996
  DEFAULT_SELF_CONFIG_PRODUCT
18896
18997
  };
18897
18998
 
18898
- //# debugId=FEB10E0CA0A5D85964756E2164756E21
18999
+ //# debugId=F55519AD891B254F64756E2164756E21