pilotswarm 0.5.40 → 0.5.42

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 (70) hide show
  1. package/package.json +2 -2
  2. package/ui/core/src/history.js +25 -1
  3. package/ui/core/src/selectors.js +15 -0
  4. package/ui/react/src/web-app.js +227 -104
  5. package/web/dist/assets/{abnfDiagram-VRR7QNED-C6FaYMB7.js → abnfDiagram-VRR7QNED-Jh9nLlRI.js} +1 -1
  6. package/web/dist/assets/{arc-iZBUHcPs.js → arc-CmN4jFMW.js} +1 -1
  7. package/web/dist/assets/{architectureDiagram-ZJ3FMSHR-D4-wnpAG.js → architectureDiagram-ZJ3FMSHR-DgUSVwl7.js} +1 -1
  8. package/web/dist/assets/{blockDiagram-677ZJIJ3-Dz-s103f.js → blockDiagram-677ZJIJ3-CCJEXNgp.js} +1 -1
  9. package/web/dist/assets/{c4Diagram-LMCZKHZV-DE7sGdHE.js → c4Diagram-LMCZKHZV-DG11zUre.js} +1 -1
  10. package/web/dist/assets/channel-BQBGhjIw.js +1 -0
  11. package/web/dist/assets/{chunk-2Q5K7J3B-DSFs_jRM.js → chunk-2Q5K7J3B-Cl8MUWGh.js} +1 -1
  12. package/web/dist/assets/{chunk-32BRIVSS-8sBVtZ4f.js → chunk-32BRIVSS-BaLutEQY.js} +1 -1
  13. package/web/dist/assets/{chunk-5VM5RSS4-CbIX7k0G.js → chunk-5VM5RSS4-BOPcnMeW.js} +1 -1
  14. package/web/dist/assets/{chunk-EX3LRPZG-ZfmPtWF8.js → chunk-EX3LRPZG-bY2tdfJ2.js} +1 -1
  15. package/web/dist/assets/{chunk-JWPE2WC7-DifZrqsQ.js → chunk-JWPE2WC7-CASBfQW6.js} +1 -1
  16. package/web/dist/assets/{chunk-MOJQB5TN-CEvg_lZT.js → chunk-MOJQB5TN-WrEHfiAj.js} +1 -1
  17. package/web/dist/assets/{chunk-RYQCIY6F-DmYOwk6-.js → chunk-RYQCIY6F-XQoZii_K.js} +1 -1
  18. package/web/dist/assets/{chunk-V7JOEXUC-DOxG9Vxu.js → chunk-V7JOEXUC-BvA5V7VF.js} +1 -1
  19. package/web/dist/assets/{chunk-VR4S4FIN-ic-KB2tF.js → chunk-VR4S4FIN-SK_jCKYo.js} +1 -1
  20. package/web/dist/assets/{chunk-XXDRQBXY-BqeYnem3.js → chunk-XXDRQBXY-CtZZImS8.js} +1 -1
  21. package/web/dist/assets/classDiagram-OUVF2IWQ-BIr20mVO.js +1 -0
  22. package/web/dist/assets/classDiagram-v2-EOCWNBFH-BIr20mVO.js +1 -0
  23. package/web/dist/assets/{cose-bilkent-JH36ORCC-uaIgs2-N.js → cose-bilkent-JH36ORCC-PRXhsdiX.js} +1 -1
  24. package/web/dist/assets/{cynefin-VYW2F7L2-DzFeugVQ.js → cynefin-VYW2F7L2-CzUocqvb.js} +1 -1
  25. package/web/dist/assets/{cynefinDiagram-TSTJHNR4-NrAChuCW.js → cynefinDiagram-TSTJHNR4-DYGEqQ23.js} +1 -1
  26. package/web/dist/assets/{dagre-VKFMJZFB-Djf9LD2t.js → dagre-VKFMJZFB-CAyb_zBo.js} +1 -1
  27. package/web/dist/assets/{diagram-FQU43EPY-BpIP2iD9.js → diagram-FQU43EPY-CvpXMmL-.js} +1 -1
  28. package/web/dist/assets/{diagram-G47NLZAW-D_DCw8Oy.js → diagram-G47NLZAW-DBQRZJS0.js} +1 -1
  29. package/web/dist/assets/{diagram-NH7WQ7WH-BztvRvrM.js → diagram-NH7WQ7WH-BGzD61gL.js} +1 -1
  30. package/web/dist/assets/{diagram-OA4YK3LP-BGIwSnbM.js → diagram-OA4YK3LP-DqQf4oMW.js} +1 -1
  31. package/web/dist/assets/{diagram-WEI45ONY-Czj2ttCt.js → diagram-WEI45ONY-CYHoWtg7.js} +1 -1
  32. package/web/dist/assets/{ebnfDiagram-CCIWWBDH-0nqAhMvJ.js → ebnfDiagram-CCIWWBDH-oMOMgcs8.js} +1 -1
  33. package/web/dist/assets/{erDiagram-Q63AITRT-uLoGb9TG.js → erDiagram-Q63AITRT-DaZaseAH.js} +1 -1
  34. package/web/dist/assets/{flowDiagram-23GEKE2U-Bgxy7CWO.js → flowDiagram-23GEKE2U-BIe9TtAL.js} +1 -1
  35. package/web/dist/assets/{ganttDiagram-NO4QXBWP-5q8zYzbu.js → ganttDiagram-NO4QXBWP-DitrY3hM.js} +1 -1
  36. package/web/dist/assets/{gitGraphDiagram-IHSO6WYX-D6-i59JZ.js → gitGraphDiagram-IHSO6WYX-DRjIH_99.js} +1 -1
  37. package/web/dist/assets/{index-BFa_e8zL.js → index-Cl6-pI9g.js} +2 -2
  38. package/web/dist/assets/index-DRLA5aNR.css +1 -0
  39. package/web/dist/assets/{infoDiagram-FWYZ7A6U-bdx9GrWW.js → infoDiagram-FWYZ7A6U-BJCx4g9_.js} +1 -1
  40. package/web/dist/assets/{ishikawaDiagram-FXEZZL3T-xzL6Bssj.js → ishikawaDiagram-FXEZZL3T-CLxmaTWp.js} +1 -1
  41. package/web/dist/assets/{journeyDiagram-5HDEW3XC-C1-18xOk.js → journeyDiagram-5HDEW3XC-D2_VI8CC.js} +1 -1
  42. package/web/dist/assets/{kanban-definition-HUTT4EX6-BS4KDL4_.js → kanban-definition-HUTT4EX6-DnUq9E7I.js} +1 -1
  43. package/web/dist/assets/{linear-Dmv3ton3.js → linear-mKMwWrAB.js} +1 -1
  44. package/web/dist/assets/{mermaid.core-Nhzw7Fl2.js → mermaid.core-CApAWULn.js} +4 -4
  45. package/web/dist/assets/{mindmap-definition-LN4V7U3C-2DSMdlsp.js → mindmap-definition-LN4V7U3C-D2twxIMO.js} +1 -1
  46. package/web/dist/assets/{papaparse.min-H4g6q6aH.js → papaparse.min-BhDLFNak.js} +1 -1
  47. package/web/dist/assets/{pegDiagram-2B236MQR-CM_rgJ2s.js → pegDiagram-2B236MQR-D2RtIeDP.js} +1 -1
  48. package/web/dist/assets/{pieDiagram-ENE6RG2P-Cbo8FtuT.js → pieDiagram-ENE6RG2P-vonumKaj.js} +1 -1
  49. package/web/dist/assets/{pilotswarm-ClLipXts.js → pilotswarm-DETFHWYc.js} +63 -63
  50. package/web/dist/assets/{quadrantDiagram-ABIIQ3AL-CVsF_pZA.js → quadrantDiagram-ABIIQ3AL-CAZL1kJH.js} +1 -1
  51. package/web/dist/assets/{railroadDiagram-RFXS5EU6-CauKYIfy.js → railroadDiagram-RFXS5EU6-CgpDomFp.js} +1 -1
  52. package/web/dist/assets/{requirementDiagram-TGXJPOKE-DoXh8EL8.js → requirementDiagram-TGXJPOKE-9B6yfsXV.js} +1 -1
  53. package/web/dist/assets/{sankeyDiagram-HTMAVEWB-gA_ej2MB.js → sankeyDiagram-HTMAVEWB-B_FAnwxi.js} +1 -1
  54. package/web/dist/assets/{sequenceDiagram-DBY2YBRQ-keYBa83Q.js → sequenceDiagram-DBY2YBRQ-BbL6OCms.js} +1 -1
  55. package/web/dist/assets/{sizeCapture-X5ZJPWSS-Y6NCdqw8.js → sizeCapture-X5ZJPWSS-DIRKFU8M.js} +1 -1
  56. package/web/dist/assets/{stateDiagram-2N3HPSRC-MvJfZXqW.js → stateDiagram-2N3HPSRC-pUX5NF32.js} +1 -1
  57. package/web/dist/assets/stateDiagram-v2-6OUMAXLB-J_okbpZN.js +1 -0
  58. package/web/dist/assets/{swimlanes-5IMT3BWC-D41i7zcr.js → swimlanes-5IMT3BWC-DO7BjQ4-.js} +2 -2
  59. package/web/dist/assets/swimlanesDiagram-G3AALYLV-gTxQyRZa.js +8 -0
  60. package/web/dist/assets/{timeline-definition-FHXFAJF6-CUA2ENV8.js → timeline-definition-FHXFAJF6-BcbYRQ7s.js} +1 -1
  61. package/web/dist/assets/{vennDiagram-L72KCM5P-CBTp-2d6.js → vennDiagram-L72KCM5P-CUt_orN5.js} +1 -1
  62. package/web/dist/assets/{wardleyDiagram-EHGQE667-BIFjtpCg.js → wardleyDiagram-EHGQE667-BlUPWQdi.js} +1 -1
  63. package/web/dist/assets/{xychartDiagram-FW5EYKEG-DiamOwOI.js → xychartDiagram-FW5EYKEG-CDW7A5_U.js} +1 -1
  64. package/web/dist/index.html +3 -3
  65. package/web/dist/assets/channel-Bk68hLPV.js +0 -1
  66. package/web/dist/assets/classDiagram-OUVF2IWQ-arTJL-2y.js +0 -1
  67. package/web/dist/assets/classDiagram-v2-EOCWNBFH-arTJL-2y.js +0 -1
  68. package/web/dist/assets/index-B3WlYEvi.css +0 -1
  69. package/web/dist/assets/stateDiagram-v2-6OUMAXLB-xTZh36yB.js +0 -1
  70. package/web/dist/assets/swimlanesDiagram-G3AALYLV-BjlBuuiD.js +0 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pilotswarm",
3
- "version": "0.5.40",
3
+ "version": "0.5.42",
4
4
  "description": "PilotSwarm application package: terminal UI, browser portal + Web API server, and MCP server — one install, three bins.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -81,7 +81,7 @@
81
81
  "ink": "^6.8.0",
82
82
  "jose": "^6.2.2",
83
83
  "mermaid": "^11.16.0",
84
- "pilotswarm-sdk": "0.5.40",
84
+ "pilotswarm-sdk": "0.5.42",
85
85
  "react": "^19.2.4",
86
86
  "react-dom": "^19.2.4",
87
87
  "ws": "^8.18.2"
@@ -1,4 +1,4 @@
1
- import { formatHumanDurationSeconds, formatTimestamp, shortSessionId, stripTerminalMarkupTags, summarizeJson } from "./formatting.js";
1
+ import { formatHumanDurationSeconds, formatTimestamp, shortModelName, shortSessionId, stripTerminalMarkupTags, summarizeJson } from "./formatting.js";
2
2
  import { isCanvasActionContent, parseCanvasActionContent } from "./canvas-actions.js";
3
3
  import { formatCompactionActivityRuns } from "./context-usage.js";
4
4
  import { canonicalSystemTitle } from "./system-titles.js";
@@ -692,6 +692,7 @@ function formatEventSnippet(event, maxLen = 96) {
692
692
  return body || "";
693
693
  }
694
694
 
695
+
695
696
  function formatToolActivityRuns(time, event, phase = "start") {
696
697
  const toolCallId = typeof event?.data?.toolCallId === "string" ? event.data.toolCallId : "";
697
698
  const requestId = typeof event?.data?.requestId === "string" ? event.data.requestId : "";
@@ -947,6 +948,29 @@ function formatActivity(event) {
947
948
  );
948
949
  break;
949
950
 
951
+ case "session.model_changed": {
952
+ // Structured data only — messageTextFromEvent finds nothing, so
953
+ // without this case the generic fallback printed a bare
954
+ // "[session.model_changed]" that named neither model.
955
+ const from = shortModelName(event?.data?.oldModel) || "default";
956
+ const to = shortModelName(event?.data?.newModel) || "default";
957
+ const effort = event?.data?.newReasoningEffort;
958
+ const effortChanged = effort && effort !== event?.data?.oldReasoningEffort;
959
+ const tier = event?.data?.newContextTier;
960
+ const tierChanged = tier && tier !== event?.data?.oldContextTier && tier !== "default";
961
+ const extras = [
962
+ ...(effortChanged ? [`effort ${effort}`] : []),
963
+ ...(tierChanged ? [`context ${tier}`] : []),
964
+ ];
965
+ runs = buildLabeledActivityRuns(
966
+ time,
967
+ "[model]",
968
+ "cyan",
969
+ `${from} → ${to}${extras.length ? ` (${extras.join(", ")})` : ""}`,
970
+ );
971
+ break;
972
+ }
973
+
950
974
  case "session.compaction_start":
951
975
  case "session.compaction_complete":
952
976
  runs = formatCompactionActivityRuns(time, event.eventType, event.data || {});
@@ -4590,6 +4590,7 @@ const SEQUENCE_ORCHESTRATOR_TYPES = new Set([
4590
4590
  "spawn",
4591
4591
  "cmd_recv",
4592
4592
  "cmd_done",
4593
+ "model",
4593
4594
  ]);
4594
4595
 
4595
4596
  function isSequenceOrchestratorType(type) {
@@ -4723,6 +4724,20 @@ function mapEventToSequenceEntry(event) {
4723
4724
  return { ...base, type: "compaction", color: "gray", detail: "compaction…" };
4724
4725
  case "session.compaction_complete":
4725
4726
  return { ...base, type: "compaction", color: "gray", detail: "compacted" };
4727
+ case "session.model_changed": {
4728
+ // The switch itself already appears as /set_model command rows;
4729
+ // this row is the one that says what actually changed.
4730
+ const from = shortModelName(event?.data?.oldModel) || "default";
4731
+ const to = shortModelName(event?.data?.newModel) || "default";
4732
+ const effort = event?.data?.newReasoningEffort;
4733
+ const effortChanged = effort && effort !== event?.data?.oldReasoningEffort;
4734
+ return {
4735
+ ...base,
4736
+ type: "model",
4737
+ color: "cyan",
4738
+ detail: `model ${from} → ${to}${effortChanged ? `:${effort}` : ""}`,
4739
+ };
4740
+ }
4726
4741
  case "session.error":
4727
4742
  return { ...base, type: "error", color: "red", detail: preview || "error" };
4728
4743
  default:
@@ -193,6 +193,53 @@ function copySessionLinkText(url) {
193
193
  if (navigator?.clipboard?.writeText) navigator.clipboard.writeText(text).catch(() => {});
194
194
  }
195
195
 
196
+ /**
197
+ * One box per entry point, each independently copyable, plus a "Copy all"
198
+ * that takes every labeled line at once.
199
+ *
200
+ * The single shared textarea this replaced forced the sender to hand over
201
+ * both URLs even when they knew which network the recipient was on, and a
202
+ * partial selection out of a monospace blob is fiddly. A sender who knows
203
+ * copies one; a sender who doesn't copies all.
204
+ *
205
+ * Single-origin deployments render exactly one unlabeled row — no labels, no
206
+ * Copy all, nothing to explain.
207
+ */
208
+ function MultiOriginLinkRows({ url, keyPrefix, copied, onCopy }) {
209
+ const links = buildPortalLinks(url, portalLinkOrigins);
210
+ const selectOnFocus = (event) => event.currentTarget.select();
211
+ if (links.length <= 1) {
212
+ return React.createElement("div", { className: "ps-link-row" },
213
+ React.createElement("input", {
214
+ className: "ps-link-input", readOnly: true, value: url, onFocus: selectOnFocus,
215
+ }),
216
+ React.createElement("button", {
217
+ type: "button", className: "ps-mini-button", onClick: () => onCopy(keyPrefix, url),
218
+ }, copied === keyPrefix ? "Copied" : "Copy"));
219
+ }
220
+ const allKey = `${keyPrefix}:all`;
221
+ return React.createElement("div", { className: "ps-link-origins" },
222
+ links.map((link, index) => {
223
+ const key = `${keyPrefix}:${index}`;
224
+ return React.createElement("div", { className: "ps-link-origin", key },
225
+ React.createElement("div", { className: "ps-link-origin-label" }, link.label),
226
+ React.createElement("div", { className: "ps-link-row" },
227
+ React.createElement("input", {
228
+ className: "ps-link-input", readOnly: true, value: link.url,
229
+ "aria-label": `${link.label} link`, onFocus: selectOnFocus,
230
+ }),
231
+ React.createElement("button", {
232
+ type: "button", className: "ps-mini-button",
233
+ onClick: () => onCopy(key, link.url),
234
+ }, copied === key ? "Copied" : "Copy")));
235
+ }),
236
+ React.createElement("div", { className: "ps-link-copy-all" },
237
+ React.createElement("button", {
238
+ type: "button", className: "ps-mini-button",
239
+ onClick: () => onCopy(allKey, formatPortalLinksForCopy(links)),
240
+ }, copied === allKey ? "Copied all" : "Copy all")));
241
+ }
242
+
196
243
  // Best-effort probe: is this session's deep link openable only by the owner/
197
244
  // admins right now (private, with no targeted grants)? Used to warn in the
198
245
  // copy-link dialog. Failure resolves false (no warning).
@@ -5222,34 +5269,27 @@ function SessionPane({ controller, actions = null, panelClassName = "", structur
5222
5269
  // (selectable), confirms the copy, and warns when the link points at a private
5223
5270
  // session no one else can open yet.
5224
5271
  function SessionLinkModal({ url, warn, onCopyAgain, onClose }) {
5225
- const inputRef = React.useRef(null);
5226
- React.useEffect(() => {
5227
- const node = inputRef.current;
5228
- if (node) { node.focus(); node.select(); }
5229
- }, []);
5272
+ const [copied, setCopied] = React.useState("");
5273
+ const multi = buildPortalLinks(url, portalLinkOrigins).length > 1;
5274
+ const copy = React.useCallback((key, text) => {
5275
+ // onCopyAgain owns the single-origin clipboard write (and its status
5276
+ // line); the per-origin buttons write their own one URL.
5277
+ if (key === "session" && !multi) { onCopyAgain?.(); }
5278
+ else if (navigator?.clipboard?.writeText) navigator.clipboard.writeText(text).catch(() => {});
5279
+ setCopied(key);
5280
+ window.setTimeout(() => setCopied(""), 1500);
5281
+ }, [multi, onCopyAgain]);
5230
5282
  const stop = (e) => e.stopPropagation();
5231
5283
  return React.createElement("div", { className: "ps-share-overlay", onClick: onClose },
5232
5284
  React.createElement("div", { className: "ps-link-modal", onClick: stop },
5233
5285
  React.createElement("div", { className: "ps-share-modal-head" },
5234
- React.createElement("span", null, portalLinkOrigins.length >= 2 ? "Session links copied" : "Link copied"),
5286
+ React.createElement("span", null, multi ? "Session links copied" : "Link copied"),
5235
5287
  React.createElement("button", { className: "ps-modal-close", onClick: onClose, "aria-label": "Close", title: "Close" }, "✕")),
5236
5288
  React.createElement("div", { className: "ps-share-section-sub" },
5237
- portalLinkOrigins.length >= 2
5238
- ? "All entry-point links were copied use the one reachable from the recipient's network."
5289
+ multi
5290
+ ? "All entry-point links were copied. Copy just the one your recipient's network can reach, or take both."
5239
5291
  : "Copied to your clipboard — anyone with access can open the session from this link."),
5240
- React.createElement("div", { className: "ps-link-row" },
5241
- portalLinkOrigins.length >= 2
5242
- ? React.createElement("textarea", {
5243
- ref: inputRef, className: "ps-link-input", readOnly: true,
5244
- rows: buildPortalLinks(url, portalLinkOrigins).length,
5245
- value: formatPortalLinksForCopy(buildPortalLinks(url, portalLinkOrigins)),
5246
- onFocus: () => inputRef.current?.select(),
5247
- })
5248
- : React.createElement("input", {
5249
- ref: inputRef, className: "ps-link-input", readOnly: true, value: url,
5250
- onFocus: () => inputRef.current?.select(),
5251
- }),
5252
- React.createElement("button", { className: "ps-mini-button", onClick: onCopyAgain }, "Copy")),
5292
+ React.createElement(MultiOriginLinkRows, { url, keyPrefix: "session", copied, onCopy: copy }),
5253
5293
  warn
5254
5294
  ? React.createElement("div", { className: "ps-link-warn" }, SESSION_LINK_PRIVATE_WARNING)
5255
5295
  : null));
@@ -6273,6 +6313,71 @@ function MobileArtifactOverlay({ controller }) {
6273
6313
  })));
6274
6314
  }
6275
6315
 
6316
+ // How much visual-viewport height must vanish before we call it a keyboard.
6317
+ // Smaller drops (URL-bar churn, iOS toolbars settling) stay under this.
6318
+ const KEYBOARD_TAKEOVER_MIN_SHRINK_PX = 140;
6319
+
6320
+ /**
6321
+ * Pure decision for the keyboard takeover, split out for tests. Returns the
6322
+ * next {baseline, takeover}. The keyboard signal is a visual-viewport height
6323
+ * drop from the tallest height seen at the current width; a width change is
6324
+ * a rotation and resets the baseline. window.innerHeight is NOT a usable
6325
+ * baseline: Android's interactive-widget=resizes-content shrinks it together
6326
+ * with the keyboard, which would read as "no shrink".
6327
+ */
6328
+ export function evaluateKeyboardTakeover(baseline, viewportWidth, viewportHeight, composerFocused) {
6329
+ let nextBaseline = baseline;
6330
+ if (!baseline || Math.abs(viewportWidth - baseline.width) > 2) {
6331
+ nextBaseline = { width: viewportWidth, height: viewportHeight };
6332
+ } else if (viewportHeight > baseline.height) {
6333
+ nextBaseline = { width: baseline.width, height: viewportHeight };
6334
+ }
6335
+ const shrunk = viewportHeight <= nextBaseline.height - KEYBOARD_TAKEOVER_MIN_SHRINK_PX;
6336
+ return { baseline: nextBaseline, takeover: shrunk && composerFocused };
6337
+ }
6338
+
6339
+ /**
6340
+ * True while the on-screen keyboard is up AND the chat composer summoned it.
6341
+ * Both conditions matter: height alone would fire for a modal's text field
6342
+ * and collapse the workspace behind the modal; focus alone would fire for
6343
+ * hardware keyboards that shrink nothing. State-driven on the keyboard
6344
+ * itself, so it reverts the moment the keyboard goes away — including the
6345
+ * iOS swipe-dismiss that closes the keyboard without blurring the input.
6346
+ */
6347
+ function useKeyboardTakeover(enabled) {
6348
+ const [takeover, setTakeover] = React.useState(false);
6349
+ React.useEffect(() => {
6350
+ if (!enabled || typeof window === "undefined" || !window.visualViewport) {
6351
+ setTakeover(false);
6352
+ return undefined;
6353
+ }
6354
+ const viewport = window.visualViewport;
6355
+ let baseline = { width: viewport.width, height: viewport.height };
6356
+ let frame = 0;
6357
+ const evaluate = () => {
6358
+ frame = 0;
6359
+ const composerFocused = Boolean(document.activeElement?.classList?.contains("ps-prompt-input"));
6360
+ const next = evaluateKeyboardTakeover(baseline, viewport.width, viewport.height, composerFocused);
6361
+ baseline = next.baseline;
6362
+ setTakeover(next.takeover);
6363
+ };
6364
+ // rAF-deferred: focusout fires while activeElement is mid-transition,
6365
+ // and visualViewport resize storms during the keyboard animation.
6366
+ const schedule = () => { if (!frame) frame = requestAnimationFrame(evaluate); };
6367
+ evaluate();
6368
+ viewport.addEventListener("resize", schedule);
6369
+ window.addEventListener("focusin", schedule);
6370
+ window.addEventListener("focusout", schedule);
6371
+ return () => {
6372
+ if (frame) cancelAnimationFrame(frame);
6373
+ viewport.removeEventListener("resize", schedule);
6374
+ window.removeEventListener("focusin", schedule);
6375
+ window.removeEventListener("focusout", schedule);
6376
+ };
6377
+ }, [enabled]);
6378
+ return enabled ? takeover : false;
6379
+ }
6380
+
6276
6381
  /**
6277
6382
  * The phone's Main pane, in one of three layouts cycled by the Main toolbar
6278
6383
  * button: split (sessions + chat), chat only, sessions only (list + the
@@ -6386,6 +6491,13 @@ function CanvasLinkGlyph() {
6386
6491
  * Link management is a session:manage operation server-side; anyone else
6387
6492
  * sees the server's refusal inline.
6388
6493
  */
6494
+ // Tab labels name the AUDIENCE, not the mechanism — the sharer is choosing
6495
+ // who should be able to open this, not which token scheme to use.
6496
+ const CANVAS_SHARE_TABS = [
6497
+ { id: "session", label: "Session access" },
6498
+ { id: "public", label: "Anyone with link" },
6499
+ ];
6500
+
6389
6501
  function CanvasShareDialog({ controller, sessionId, slot, onClose }) {
6390
6502
  const [info, setInfo] = React.useState(null); // { exists, createdAt } | null while loading
6391
6503
  const [freshLink, setFreshLink] = React.useState(null); // the just-minted URL, shown once
@@ -6393,37 +6505,19 @@ function CanvasShareDialog({ controller, sessionId, slot, onClose }) {
6393
6505
  const [error, setError] = React.useState("");
6394
6506
  const [copied, setCopied] = React.useState("");
6395
6507
 
6508
+ // Which kind of link the dialog is showing. Two tabs rather than two
6509
+ // stacked sections: the choice between "people who already have session
6510
+ // access" and "anyone holding this token" is the decision the sharer is
6511
+ // making, and stacking them put a destructive Reset next to an innocuous
6512
+ // deep link. Mirrors the Manage-session dialog's General/Access tabs.
6513
+ const [tab, setTab] = React.useState("session");
6396
6514
  const transport = controller.transport;
6397
6515
  const sessionLink = `${window.location.origin}/?session=${encodeURIComponent(sessionId)}&view=canvas&slot=${slot}&max=1`;
6398
- // Multi-entry-point deployments: ONE text box holding every labeled
6399
- // variant, ONE copy that takes all of them — the sender does not know
6400
- // which entry point the recipient can reach, so they paste both. The
6401
- // token variants all resolve the same hashed row: one token, N doors,
6516
+ // The token variants all resolve the same hashed row: one token, N doors,
6402
6517
  // single-switch revocation whichever door the bearer uses.
6403
- const linkRows = (url, keyPrefix) => {
6404
- const links = buildPortalLinks(url, portalLinkOrigins);
6405
- if (links.length <= 1) {
6406
- return React.createElement("div", { className: "ps-canvas-share-row" },
6407
- React.createElement("code", { className: "ps-canvas-share-url" }, url),
6408
- React.createElement("button", {
6409
- type: "button", className: "ps-mini-button",
6410
- onClick: () => copy(keyPrefix, url),
6411
- }, copied === keyPrefix ? "Copied" : "Copy"));
6412
- }
6413
- const text = formatPortalLinksForCopy(links);
6414
- return React.createElement("div", { className: "ps-canvas-share-row" },
6415
- React.createElement("textarea", {
6416
- className: "ps-link-input",
6417
- readOnly: true,
6418
- rows: links.length,
6419
- value: text,
6420
- onFocus: (event) => event.currentTarget.select(),
6421
- }),
6422
- React.createElement("button", {
6423
- type: "button", className: "ps-mini-button",
6424
- onClick: () => copy(keyPrefix, text),
6425
- }, copied === keyPrefix ? "Copied" : "Copy"));
6426
- };
6518
+ const linkRows = (url, keyPrefix) => React.createElement(MultiOriginLinkRows, {
6519
+ url, keyPrefix, copied, onCopy: copy,
6520
+ });
6427
6521
 
6428
6522
  const refresh = React.useCallback(() => {
6429
6523
  transport.getCanvasShareLink?.(sessionId, slot)
@@ -6464,32 +6558,55 @@ function CanvasShareDialog({ controller, sessionId, slot, onClose }) {
6464
6558
  "Share this canvas",
6465
6559
  React.createElement("button", { type: "button", className: "ps-mini-button", onClick: onClose, "aria-label": "Close" }, "✕")),
6466
6560
 
6467
- React.createElement("div", { className: "ps-canvas-share-section" },
6468
- React.createElement("div", { className: "ps-canvas-share-head" }, "Anyone with session access"),
6469
- React.createElement("div", { className: "ps-canvas-share-sub" }, "Opens the portal signed in, canvas full screen. Session visibility rules apply."),
6470
- linkRows(sessionLink, "session")),
6471
-
6472
- React.createElement("div", { className: "ps-canvas-share-section" },
6473
- React.createElement("div", { className: "ps-canvas-share-head" }, "Anyone with the link"),
6474
- React.createElement("div", { className: "ps-canvas-share-sub" },
6475
- "View only, live, no sign-in. One link at a time — resetting makes the previous link stop working immediately."),
6476
- info === null
6477
- ? React.createElement("div", { className: "ps-canvas-share-sub" }, "Checking…")
6478
- : freshLink
6479
- ? React.createElement(React.Fragment, null,
6480
- linkRows(freshLink, "public"),
6481
- React.createElement("div", { className: "ps-canvas-share-sub is-warn" },
6482
- "Copy it now the link is shown only this once."))
6483
- : info.exists
6484
- ? React.createElement("div", { className: "ps-canvas-share-sub" },
6485
- `A link exists${info.createdAt ? ` (created ${new Date(info.createdAt).toLocaleString()})` : ""}. For safety it cannot be re-shown — Reset to get a new one.`)
6486
- : React.createElement("div", { className: "ps-canvas-share-sub" }, "No public link yet."),
6487
- React.createElement("div", { className: "ps-canvas-share-actions" },
6488
- React.createElement("button", { type: "button", className: "ps-mini-button", disabled: busy, onClick: () => mint(info?.exists) },
6489
- info?.exists ? "Reset link" : "Create link"),
6490
- info?.exists
6491
- ? React.createElement("button", { type: "button", className: "ps-mini-button", disabled: busy, onClick: remove }, "Remove link")
6492
- : null)),
6561
+ React.createElement("div", { className: "ps-manage-tabs", role: "tablist" },
6562
+ CANVAS_SHARE_TABS.map((t) => React.createElement("button", {
6563
+ key: t.id,
6564
+ type: "button",
6565
+ role: "tab",
6566
+ "aria-selected": tab === t.id ? "true" : "false",
6567
+ className: `ps-manage-tab${tab === t.id ? " is-active" : ""}`,
6568
+ onClick: () => setTab(t.id),
6569
+ }, t.label))),
6570
+
6571
+ // Both panels are always rendered, stacked in one grid cell, with
6572
+ // the inactive one held at visibility:hidden. It still occupies
6573
+ // its space, so the dialog is always as tall as the TALLER tab and
6574
+ // switching tabs never resizes the box. Sizing this way (rather
6575
+ // than a min-height guess) also stays correct when the panels grow:
6576
+ // one link box on a single-origin deployment, two plus Copy all on
6577
+ // a multi-origin one. visibility:hidden also takes the hidden
6578
+ // panel's inputs and buttons out of the tab order and the
6579
+ // accessibility tree, so nothing offscreen is reachable.
6580
+ React.createElement("div", { className: "ps-canvas-share-panels" },
6581
+ React.createElement("div", {
6582
+ className: `ps-canvas-share-panel${tab === "session" ? " is-active" : ""}`,
6583
+ role: "tabpanel", "aria-hidden": tab === "session" ? undefined : "true",
6584
+ },
6585
+ React.createElement("div", { className: "ps-canvas-share-sub" }, "Opens the portal signed in, canvas full screen. Session visibility rules apply."),
6586
+ linkRows(sessionLink, "session")),
6587
+ React.createElement("div", {
6588
+ className: `ps-canvas-share-panel${tab === "public" ? " is-active" : ""}`,
6589
+ role: "tabpanel", "aria-hidden": tab === "public" ? undefined : "true",
6590
+ },
6591
+ React.createElement("div", { className: "ps-canvas-share-sub" },
6592
+ "View only, live, no sign-in. One link at a time — resetting makes the previous link stop working immediately."),
6593
+ info === null
6594
+ ? React.createElement("div", { className: "ps-canvas-share-sub" }, "Checking…")
6595
+ : freshLink
6596
+ ? React.createElement(React.Fragment, null,
6597
+ linkRows(freshLink, "public"),
6598
+ React.createElement("div", { className: "ps-canvas-share-sub is-warn" },
6599
+ "Copy it now — the link is shown only this once."))
6600
+ : info.exists
6601
+ ? React.createElement("div", { className: "ps-canvas-share-sub" },
6602
+ `A link exists${info.createdAt ? ` (created ${new Date(info.createdAt).toLocaleString()})` : ""}. For safety it cannot be re-shown — Reset to get a new one.`)
6603
+ : React.createElement("div", { className: "ps-canvas-share-sub" }, "No public link yet."),
6604
+ React.createElement("div", { className: "ps-canvas-share-actions" },
6605
+ React.createElement("button", { type: "button", className: "ps-mini-button", disabled: busy, onClick: () => mint(info?.exists) },
6606
+ info?.exists ? "Reset link" : "Create link"),
6607
+ info?.exists
6608
+ ? React.createElement("button", { type: "button", className: "ps-mini-button", disabled: busy, onClick: remove }, "Remove link")
6609
+ : null))),
6493
6610
  error ? React.createElement("div", { className: "ps-canvas-share-error" }, error) : null));
6494
6611
  }
6495
6612
 
@@ -6882,6 +6999,15 @@ function CanvasPane({ controller, mobile = false, visible = true, focusOnPromote
6882
6999
  React.createElement("span", { className: "ps-artifact-pane-type", title: view.note || undefined },
6883
7000
  view.exists ? `${view.name ? `${view.name} \u00b7 ` : ""}rev ${view.latestRev}` : ""),
6884
7001
  React.createElement(CanvasSlotControls, { controller, view, compact: true }),
7002
+ view.exists
7003
+ ? React.createElement("button", {
7004
+ type: "button",
7005
+ className: "ps-canvas-max-btn",
7006
+ onClick: () => setShareOpen(true),
7007
+ title: "Share this canvas — copy a view link",
7008
+ "aria-label": "Share canvas",
7009
+ }, React.createElement(CanvasLinkGlyph))
7010
+ : null,
6885
7011
  onToggleMaximized
6886
7012
  ? React.createElement("button", {
6887
7013
  type: "button",
@@ -7837,24 +7963,19 @@ function PromptComposer({ controller, mobile, active = true, onAfterSend = null
7837
7963
  const inputRef = React.useRef(null);
7838
7964
  const attachInputRef = React.useRef(null);
7839
7965
  const [dragOver, setDragOver] = React.useState(false);
7840
- // Expand mode: the same buffer, editor-sized. Web-local view state — the
7841
- // shared core never needs to know the box got taller.
7842
- const [expanded, setExpanded] = React.useState(false);
7843
7966
 
7844
7967
  // Auto-grow: one line idle, sized to the RENDERED content (scrollHeight
7845
7968
  // sees soft wrap; counting "\n" does not). CSS max-height provides the
7846
- // cap, after which the textarea scrolls internally. In expand mode the
7847
- // height belongs to CSS entirely.
7969
+ // cap, after which the textarea scrolls internally. The measurement
7970
+ // zeroes the height first NOT "auto": iOS Safari keeps a textarea's
7971
+ // scrollHeight at its high-water mark under "auto", so a box that grew
7972
+ // never shrank back after the text was sent or deleted.
7848
7973
  const growInput = React.useCallback(() => {
7849
7974
  const node = inputRef.current;
7850
7975
  if (!node) return;
7851
- if (expanded) {
7852
- node.style.height = "";
7853
- return;
7854
- }
7855
- node.style.height = "auto";
7976
+ node.style.height = "0px";
7856
7977
  node.style.height = `${node.scrollHeight + 2}px`;
7857
- }, [expanded]);
7978
+ }, []);
7858
7979
  React.useLayoutEffect(() => {
7859
7980
  growInput();
7860
7981
  }, [growInput, promptState.value]);
@@ -7931,9 +8052,6 @@ function PromptComposer({ controller, mobile, active = true, onAfterSend = null
7931
8052
  }, [active, mobile, promptState.cursor, promptState.value, promptState.focused, promptState.modalOpen]);
7932
8053
 
7933
8054
  const sendPrompt = React.useCallback(() => {
7934
- // Sending collapses expand mode — the tall editor was for composing
7935
- // THIS message; the reply deserves the transcript space back.
7936
- setExpanded(false);
7937
8055
  controller.handleCommand(UI_COMMANDS.SEND_PROMPT)
7938
8056
  .catch(() => {})
7939
8057
  .finally(() => {
@@ -7973,7 +8091,7 @@ function PromptComposer({ controller, mobile, active = true, onAfterSend = null
7973
8091
  const selectedReadOnly = selectedQueued || selectedCancelling;
7974
8092
 
7975
8093
  return React.createElement("div", {
7976
- className: `ps-prompt-shell${mobile ? " is-mobile" : ""}${dragOver ? " is-drag-over" : ""}${expanded ? " is-expanded" : ""}`,
8094
+ className: `ps-prompt-shell${mobile ? " is-mobile" : ""}${dragOver ? " is-drag-over" : ""}`,
7977
8095
  ...(canAttachImages ? {
7978
8096
  onDragOver: (event) => {
7979
8097
  if (event.dataTransfer?.types?.includes?.("Files")) {
@@ -8082,11 +8200,6 @@ function PromptComposer({ controller, mobile, active = true, onAfterSend = null
8082
8200
  // onSelect mirrors every move into the shared model. (The old
8083
8201
  // hijack routed through the TUI's logical-line cursor and made
8084
8202
  // Down jump whole paragraphs inside wrapped text.)
8085
- if (event.key === "Escape" && expanded && !promptState.editingPending) {
8086
- event.preventDefault();
8087
- setExpanded(false);
8088
- return;
8089
- }
8090
8203
  if (event.key === "Escape" && promptState.editingPending) {
8091
8204
  event.preventDefault();
8092
8205
  if (selectedReadOnly) {
@@ -8106,15 +8219,6 @@ function PromptComposer({ controller, mobile, active = true, onAfterSend = null
8106
8219
  // pointerdown preventDefault on every action keeps focus in the
8107
8220
  // textarea — on a phone, tapping Send must not collapse the
8108
8221
  // keyboard between messages.
8109
- React.createElement("button", {
8110
- type: "button",
8111
- className: `ps-mini-button ps-expand-button${expanded ? " is-active" : ""}`,
8112
- title: expanded ? "Collapse the editor (Esc)" : "Expand into a larger editor",
8113
- "aria-label": expanded ? "Collapse the editor" : "Expand the editor",
8114
- "aria-pressed": expanded,
8115
- onPointerDown: (event) => event.preventDefault(),
8116
- onClick: () => setExpanded((current) => !current),
8117
- }, expanded ? "⤡" : "⤢"),
8118
8222
  canAttachImages
8119
8223
  ? React.createElement(React.Fragment, null,
8120
8224
  React.createElement("input", {
@@ -11006,6 +11110,25 @@ export function PilotSwarmWebApp({ controller }) {
11006
11110
 
11007
11111
  useKeyboardShortcuts(controller, mobile);
11008
11112
 
11113
+ // Keyboard takeover (phone): while the on-screen keyboard is up and the
11114
+ // composer summoned it, the conversation owns the visual viewport — the
11115
+ // portal header, toolbar and session list fold away via a body class and
11116
+ // the transcript snaps to newest. The chat pane's own header stays as the
11117
+ // context strip (session title · status · model), and tapping anywhere
11118
+ // outside the composer dismisses the keyboard and restores everything.
11119
+ const keyboardTakeover = useKeyboardTakeover(mobile && mobilePane === "workspace" && !state.adminVisible);
11120
+ React.useEffect(() => {
11121
+ if (typeof document === "undefined") return undefined;
11122
+ document.body.classList.toggle("ps-kb-takeover", keyboardTakeover);
11123
+ return () => document.body.classList.remove("ps-kb-takeover");
11124
+ }, [keyboardTakeover]);
11125
+ React.useEffect(() => {
11126
+ if (!keyboardTakeover) return;
11127
+ // Typing means replying to the newest message; a transcript left
11128
+ // scrolled to last week would have the user typing blind.
11129
+ controller.applyPaneVisualScrollOffset?.("chat", 0, { followBottom: true });
11130
+ }, [keyboardTakeover, controller]);
11131
+
11009
11132
  // The agent-driven canvas flip, phone edition. The desktop column follows
11010
11133
  // ui.rightPaneMode by itself; the phone's pane lives in local tab state,
11011
11134
  // so it follows the flip TICK instead (which fires even when the mode was
@@ -1 +1 @@
1
- import{g as p,r as u,d as a}from"./chunk-MOJQB5TN-CEvg_lZT.js";import{p as f}from"./chunk-JWPE2WC7-DifZrqsQ.js";import{_ as n,l as o}from"./mermaid.core-Nhzw7Fl2.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-DzFeugVQ.js";import"./pilotswarm-ClLipXts.js";var v=d().RailroadAbnf.parser.LangiumParser,i=n(e=>{const r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=n(e=>{const r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=n(e=>{if(e.includes("*")){const[t,s]=e.split("*"),l=t?parseInt(t,10):0,m=s?parseInt(s,10):1/0;return{min:l,max:m}}const r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=n(e=>{const r=A(e.primary);if(!e.repeat)return r;const{min:t,max:s}=b(e.repeat);return t===0&&s===1?{type:"optional",element:r}:{type:"repetition",element:r,min:t,max:s}},"transformElement"),A=n(e=>{switch(e.$type){case"AbnfStringLiteral":return{type:"terminal",value:e.value};case"AbnfNumVal":return{type:"terminal",value:e.value};case"AbnfRuleName":return{type:"nonterminal",name:e.name};case"AbnfGroup":return i(e.element);case"AbnfOptionalGroup":return{type:"optional",element:i(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=n(e=>({name:e.name,definition:i(e.definition)}),"transformRule"),h=n(e=>{f(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:n(e=>{a.clear(),o.debug("[ABNF Parser] Starting Langium parse");const r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new c(r);const t=r.value;o.debug("[ABNF Parser] Parsed rules:",t.rules.length),h(t),o.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},B={parser:R,db:a,renderer:u,styles:p};export{B as diagram};
1
+ import{g as p,r as u,d as a}from"./chunk-MOJQB5TN-WrEHfiAj.js";import{p as f}from"./chunk-JWPE2WC7-CASBfQW6.js";import{_ as n,l as o}from"./mermaid.core-CApAWULn.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-CzUocqvb.js";import"./pilotswarm-DETFHWYc.js";var v=d().RailroadAbnf.parser.LangiumParser,i=n(e=>{const r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=n(e=>{const r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=n(e=>{if(e.includes("*")){const[t,s]=e.split("*"),l=t?parseInt(t,10):0,m=s?parseInt(s,10):1/0;return{min:l,max:m}}const r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=n(e=>{const r=A(e.primary);if(!e.repeat)return r;const{min:t,max:s}=b(e.repeat);return t===0&&s===1?{type:"optional",element:r}:{type:"repetition",element:r,min:t,max:s}},"transformElement"),A=n(e=>{switch(e.$type){case"AbnfStringLiteral":return{type:"terminal",value:e.value};case"AbnfNumVal":return{type:"terminal",value:e.value};case"AbnfRuleName":return{type:"nonterminal",name:e.name};case"AbnfGroup":return i(e.element);case"AbnfOptionalGroup":return{type:"optional",element:i(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=n(e=>({name:e.name,definition:i(e.definition)}),"transformRule"),h=n(e=>{f(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:n(e=>{a.clear(),o.debug("[ABNF Parser] Starting Langium parse");const r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new c(r);const t=r.value;o.debug("[ABNF Parser] Parsed rules:",t.rules.length),h(t),o.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},B={parser:R,db:a,renderer:u,styles:p};export{B as diagram};
@@ -1 +1 @@
1
- import{Y as ln,$ as an,a0 as F,a1 as q,a2 as j,a3 as un,a4 as y,a5 as tn,a6 as J,a7 as _,a8 as rn,a9 as o,aa as on,ab as sn,ac as fn}from"./mermaid.core-Nhzw7Fl2.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,z,a){var O=I-l,i=D-h,n=z-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function U(l,h,I,D,v,A,z){var a=l-I,O=h-D,i=(z?A:-A)/J(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,B=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*J(on(0,T*T*R-P*P)),Y=(P*g-m*S)/R,$=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=Y-B,e=$-t,r=w-B,C=p-t;return x*x+e*e>r*r+C*C&&(Y=w,$=p),{cx:Y,cy:$,x01:-n,y01:-d,x11:Y*(v/T-1),y11:$*(v/T-1)}}function hn(){var l=cn,h=yn,I=j(0),D=null,v=gn,A=dn,z=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,B=rn(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(B>tn-y)a.moveTo(s*F(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*F(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=B,S=B,Y=z.apply(this,arguments)/2,$=Y>y&&(D?+D.apply(this,arguments):J(u*u+s*s)),w=_(rn(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if($>y){var C=sn($/u*q(Y)),K=sn($/s*q(Y));(P-=C*2)>y?(C*=t?1:-1,R+=C,T-=C):(P=0,R=T=(f+c)/2),(S-=K*2)>y?(K*=t?1:-1,m+=K,g-=K):(S=0,m=g=(f+c)/2)}var G=s*F(m),H=s*q(m),L=u*F(T),M=u*q(T);if(w>y){var N=s*F(g),Q=s*q(g),V=u*F(R),W=u*q(R),E;if(B<an)if(E=pn(G,H,V,W,N,Q,L,M)){var X=G-E[0],Z=H-E[1],b=N-E[0],k=Q-E[1],nn=1/q(fn((X*b+Z*k)/(J(X*X+Z*Z)*J(b*b+k*k)))/2),en=J(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=U(V,W,G,H,s,x,t),r=U(N,Q,L,M,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(G,H),a.arc(0,0,s,m,g,!t)):a.moveTo(G,H),!(u>y)||!(P>y)?a.lineTo(L,M):p>y?(e=U(L,M,N,Q,u,-p,t),r=U(G,H,V,W,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[F(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:j(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:j(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:j(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:j(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:j(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:j(+n),i):A},i.padAngle=function(n){return arguments.length?(z=typeof n=="function"?n:j(+n),i):z},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};
1
+ import{Y as ln,$ as an,a0 as F,a1 as q,a2 as j,a3 as un,a4 as y,a5 as tn,a6 as J,a7 as _,a8 as rn,a9 as o,aa as on,ab as sn,ac as fn}from"./mermaid.core-CApAWULn.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,z,a){var O=I-l,i=D-h,n=z-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function U(l,h,I,D,v,A,z){var a=l-I,O=h-D,i=(z?A:-A)/J(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,B=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*J(on(0,T*T*R-P*P)),Y=(P*g-m*S)/R,$=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=Y-B,e=$-t,r=w-B,C=p-t;return x*x+e*e>r*r+C*C&&(Y=w,$=p),{cx:Y,cy:$,x01:-n,y01:-d,x11:Y*(v/T-1),y11:$*(v/T-1)}}function hn(){var l=cn,h=yn,I=j(0),D=null,v=gn,A=dn,z=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,B=rn(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(B>tn-y)a.moveTo(s*F(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*F(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=B,S=B,Y=z.apply(this,arguments)/2,$=Y>y&&(D?+D.apply(this,arguments):J(u*u+s*s)),w=_(rn(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if($>y){var C=sn($/u*q(Y)),K=sn($/s*q(Y));(P-=C*2)>y?(C*=t?1:-1,R+=C,T-=C):(P=0,R=T=(f+c)/2),(S-=K*2)>y?(K*=t?1:-1,m+=K,g-=K):(S=0,m=g=(f+c)/2)}var G=s*F(m),H=s*q(m),L=u*F(T),M=u*q(T);if(w>y){var N=s*F(g),Q=s*q(g),V=u*F(R),W=u*q(R),E;if(B<an)if(E=pn(G,H,V,W,N,Q,L,M)){var X=G-E[0],Z=H-E[1],b=N-E[0],k=Q-E[1],nn=1/q(fn((X*b+Z*k)/(J(X*X+Z*Z)*J(b*b+k*k)))/2),en=J(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=U(V,W,G,H,s,x,t),r=U(N,Q,L,M,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(G,H),a.arc(0,0,s,m,g,!t)):a.moveTo(G,H),!(u>y)||!(P>y)?a.lineTo(L,M):p>y?(e=U(L,M,N,Q,u,-p,t),r=U(G,H,V,W,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[F(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:j(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:j(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:j(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:j(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:j(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:j(+n),i):A},i.padAngle=function(n){return arguments.length?(z=typeof n=="function"?n:j(+n),i):z},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};