pilotswarm 0.5.71 → 0.5.73

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 (69) hide show
  1. package/package.json +2 -2
  2. package/ui/react/src/web-app.js +211 -58
  3. package/web/dist/assets/{abnfDiagram-VRR7QNED-C1caNr4U.js → abnfDiagram-VRR7QNED-BnkQIEhH.js} +1 -1
  4. package/web/dist/assets/{arc-BufdFJYK.js → arc-CGyB8bDx.js} +1 -1
  5. package/web/dist/assets/{architectureDiagram-ZJ3FMSHR-C0vQblUK.js → architectureDiagram-ZJ3FMSHR-DWKmcDN1.js} +1 -1
  6. package/web/dist/assets/{blockDiagram-677ZJIJ3-B6PYWI9u.js → blockDiagram-677ZJIJ3-rn5c_Stz.js} +1 -1
  7. package/web/dist/assets/{c4Diagram-LMCZKHZV-DFoaVeMm.js → c4Diagram-LMCZKHZV-DyDQ7Ifb.js} +1 -1
  8. package/web/dist/assets/channel-BTptNqYp.js +1 -0
  9. package/web/dist/assets/{chunk-2Q5K7J3B-CxFBb-8y.js → chunk-2Q5K7J3B-C5VqT-KF.js} +1 -1
  10. package/web/dist/assets/{chunk-32BRIVSS-DO1G8AVc.js → chunk-32BRIVSS-DT-sPck4.js} +1 -1
  11. package/web/dist/assets/{chunk-5VM5RSS4-spE4bKSd.js → chunk-5VM5RSS4-yOTPomtB.js} +1 -1
  12. package/web/dist/assets/{chunk-EX3LRPZG-Bc_eUP5F.js → chunk-EX3LRPZG-DmFxJ0dk.js} +1 -1
  13. package/web/dist/assets/{chunk-JWPE2WC7-CGM2GAMX.js → chunk-JWPE2WC7-pjfQBm7p.js} +1 -1
  14. package/web/dist/assets/{chunk-MOJQB5TN-CHdrVT1z.js → chunk-MOJQB5TN-CHa4SOoq.js} +1 -1
  15. package/web/dist/assets/{chunk-RYQCIY6F-BWJK7-AW.js → chunk-RYQCIY6F-DgRDTwUy.js} +1 -1
  16. package/web/dist/assets/{chunk-V7JOEXUC-D8tgpQwK.js → chunk-V7JOEXUC-BdxruVNZ.js} +1 -1
  17. package/web/dist/assets/{chunk-VR4S4FIN-BP86JfVu.js → chunk-VR4S4FIN-DVyRDA0m.js} +1 -1
  18. package/web/dist/assets/{chunk-XXDRQBXY-Ctq_LUrs.js → chunk-XXDRQBXY-C_SZSWHx.js} +1 -1
  19. package/web/dist/assets/classDiagram-OUVF2IWQ-D_z8OghZ.js +1 -0
  20. package/web/dist/assets/classDiagram-v2-EOCWNBFH-D_z8OghZ.js +1 -0
  21. package/web/dist/assets/{cose-bilkent-JH36ORCC-DNvC4thT.js → cose-bilkent-JH36ORCC-B4ttgAJ8.js} +1 -1
  22. package/web/dist/assets/{cynefin-VYW2F7L2-3zVj2GvI.js → cynefin-VYW2F7L2-B8cRqvMz.js} +1 -1
  23. package/web/dist/assets/{cynefinDiagram-TSTJHNR4-DQbITfsJ.js → cynefinDiagram-TSTJHNR4-CEubmFl-.js} +1 -1
  24. package/web/dist/assets/{dagre-VKFMJZFB-BkGAcDyj.js → dagre-VKFMJZFB-CgRi7BXz.js} +1 -1
  25. package/web/dist/assets/{diagram-FQU43EPY-D3lsgelm.js → diagram-FQU43EPY-DfLMLNvB.js} +1 -1
  26. package/web/dist/assets/{diagram-G47NLZAW-C2rO9e3d.js → diagram-G47NLZAW-DMBnhSjJ.js} +1 -1
  27. package/web/dist/assets/{diagram-NH7WQ7WH-DJBwtT8q.js → diagram-NH7WQ7WH-CsVx_EMq.js} +1 -1
  28. package/web/dist/assets/{diagram-OA4YK3LP-C-SAwEHZ.js → diagram-OA4YK3LP-Cd8z9ubn.js} +1 -1
  29. package/web/dist/assets/{diagram-WEI45ONY-BpXMlmKz.js → diagram-WEI45ONY-BIjozLvB.js} +1 -1
  30. package/web/dist/assets/{ebnfDiagram-CCIWWBDH-DwxUgEmE.js → ebnfDiagram-CCIWWBDH-BvEyKaUx.js} +1 -1
  31. package/web/dist/assets/{erDiagram-Q63AITRT-DNZMCmYz.js → erDiagram-Q63AITRT-C1KyyEXS.js} +1 -1
  32. package/web/dist/assets/{flowDiagram-23GEKE2U-CUlGtnWV.js → flowDiagram-23GEKE2U-8vv4Bw3F.js} +1 -1
  33. package/web/dist/assets/{ganttDiagram-NO4QXBWP-DCj6zkyt.js → ganttDiagram-NO4QXBWP-BQXnAu0k.js} +1 -1
  34. package/web/dist/assets/{gitGraphDiagram-IHSO6WYX-Q6UP_dgi.js → gitGraphDiagram-IHSO6WYX-BGtXqY1X.js} +1 -1
  35. package/web/dist/assets/{index-23y0f1it.js → index-BixB0dRp.js} +2 -2
  36. package/web/dist/assets/index-CSMHeAhZ.css +1 -0
  37. package/web/dist/assets/{infoDiagram-FWYZ7A6U-Cwn8XNQT.js → infoDiagram-FWYZ7A6U-CVJezXGw.js} +1 -1
  38. package/web/dist/assets/{ishikawaDiagram-FXEZZL3T-BaMvGBAo.js → ishikawaDiagram-FXEZZL3T-D_Fi5Rxo.js} +1 -1
  39. package/web/dist/assets/{journeyDiagram-5HDEW3XC-DK95FJ0t.js → journeyDiagram-5HDEW3XC-Di1In_FH.js} +1 -1
  40. package/web/dist/assets/{kanban-definition-HUTT4EX6-C6W6RJLm.js → kanban-definition-HUTT4EX6-ozcJ7MQ3.js} +1 -1
  41. package/web/dist/assets/{linear-Un37Oyxr.js → linear-BCHWKN_x.js} +1 -1
  42. package/web/dist/assets/{mermaid.core-i8uqvLPa.js → mermaid.core-DPy_PtTG.js} +4 -4
  43. package/web/dist/assets/{mindmap-definition-LN4V7U3C-d_cgq1KW.js → mindmap-definition-LN4V7U3C-BUPXSGdc.js} +1 -1
  44. package/web/dist/assets/{papaparse.min-BiJEkQ8f.js → papaparse.min-DLMQN21E.js} +1 -1
  45. package/web/dist/assets/{pegDiagram-2B236MQR-5QRWM5AP.js → pegDiagram-2B236MQR-B0VRzHj8.js} +1 -1
  46. package/web/dist/assets/{pieDiagram-ENE6RG2P-VIZXsjFV.js → pieDiagram-ENE6RG2P-DJDr0spg.js} +1 -1
  47. package/web/dist/assets/pilotswarm-BchtZfEr.js +109 -0
  48. package/web/dist/assets/{quadrantDiagram-ABIIQ3AL-DMOx841b.js → quadrantDiagram-ABIIQ3AL-D80hp41u.js} +1 -1
  49. package/web/dist/assets/{railroadDiagram-RFXS5EU6-lTWzjdcd.js → railroadDiagram-RFXS5EU6-BVZxxDDn.js} +1 -1
  50. package/web/dist/assets/{requirementDiagram-TGXJPOKE-BE5SpiNy.js → requirementDiagram-TGXJPOKE-BYBz1YgE.js} +1 -1
  51. package/web/dist/assets/{sankeyDiagram-HTMAVEWB-C3LYWQTA.js → sankeyDiagram-HTMAVEWB-Cm0EjuqP.js} +1 -1
  52. package/web/dist/assets/{sequenceDiagram-DBY2YBRQ-BTCp88tQ.js → sequenceDiagram-DBY2YBRQ-C08lIz44.js} +1 -1
  53. package/web/dist/assets/{sizeCapture-X5ZJPWSS-Ppzj8n5l.js → sizeCapture-X5ZJPWSS-xEVPLUiU.js} +1 -1
  54. package/web/dist/assets/{stateDiagram-2N3HPSRC-Ch_iZ_cQ.js → stateDiagram-2N3HPSRC-C54U2MIf.js} +1 -1
  55. package/web/dist/assets/stateDiagram-v2-6OUMAXLB-CQXFWqsn.js +1 -0
  56. package/web/dist/assets/{swimlanes-5IMT3BWC-BX4-Oeby.js → swimlanes-5IMT3BWC-DRPOWaFR.js} +2 -2
  57. package/web/dist/assets/swimlanesDiagram-G3AALYLV-BuWCDUQa.js +8 -0
  58. package/web/dist/assets/{timeline-definition-FHXFAJF6-B1l-6l6u.js → timeline-definition-FHXFAJF6-BUhUcJ_i.js} +1 -1
  59. package/web/dist/assets/{vennDiagram-L72KCM5P-Grpa6wFZ.js → vennDiagram-L72KCM5P-DFFa7JWQ.js} +1 -1
  60. package/web/dist/assets/{wardleyDiagram-EHGQE667-B5bXnFlL.js → wardleyDiagram-EHGQE667-Bjv--ELM.js} +1 -1
  61. package/web/dist/assets/{xychartDiagram-FW5EYKEG-BkELQtgc.js → xychartDiagram-FW5EYKEG-BnGbWQJK.js} +1 -1
  62. package/web/dist/index.html +3 -3
  63. package/web/dist/assets/channel-CDzPwSI9.js +0 -1
  64. package/web/dist/assets/classDiagram-OUVF2IWQ-DdcABn-U.js +0 -1
  65. package/web/dist/assets/classDiagram-v2-EOCWNBFH-DdcABn-U.js +0 -1
  66. package/web/dist/assets/index-BXR-II2L.css +0 -1
  67. package/web/dist/assets/pilotswarm-D7Q48waO.js +0 -109
  68. package/web/dist/assets/stateDiagram-v2-6OUMAXLB-BbJN7t8_.js +0 -1
  69. package/web/dist/assets/swimlanesDiagram-G3AALYLV-0UA1VebA.js +0 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pilotswarm",
3
- "version": "0.5.71",
3
+ "version": "0.5.73",
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.71",
84
+ "pilotswarm-sdk": "0.5.73",
85
85
  "react": "^19.2.4",
86
86
  "react-dom": "^19.2.4",
87
87
  "ws": "^8.18.2"
@@ -89,6 +89,7 @@ const PORTAL_MIN_CHAT_COLUMN_PX = 224;
89
89
  const PORTAL_SESSION_COMPACT_COLUMN_PX = 190;
90
90
  const PORTAL_SESSION_HIDDEN_COLUMN_PX = 48;
91
91
  const SCROLL_ROW_HEIGHT = 16;
92
+ const HISTORY_SCROLL_GESTURE_GAP_MS = 200;
92
93
  const SCROLL_BOTTOM_EPSILON_PX = 0.5;
93
94
  const PROGRAMMATIC_SCROLL_TOLERANCE_PX = SCROLL_BOTTOM_EPSILON_PX;
94
95
  // Minimum downward finger travel (px) while at the top of the chat pane before
@@ -1119,6 +1120,8 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
1119
1120
  scrollOffset,
1120
1121
  });
1121
1122
  const previousContentRef = React.useRef(null);
1123
+ const historyScrollRef = React.useRef(null);
1124
+ React.useEffect(() => () => { historyScrollRef.current = null; }, []);
1122
1125
  // Touch scrolling relies on native momentum for speed: a hard flick keeps
1123
1126
  // scrolling long after the finger lifts. Re-asserting scrollTop from state
1124
1127
  // on every render (live events, status updates) kills that momentum at the
@@ -1151,6 +1154,31 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
1151
1154
  const firstLine = scrollBoundaryIdentity(normalizedLines);
1152
1155
  const lastLine = scrollBoundaryIdentity(normalizedLines, true);
1153
1156
  const previousContent = previousContentRef.current;
1157
+ let historyScroll = historyScrollRef.current;
1158
+ const activeSessionId = controller.getState().sessions.activeSessionId;
1159
+ if (historyScroll && historyScroll.sessionId !== activeSessionId) {
1160
+ historyScrollRef.current = null;
1161
+ historyScroll = null;
1162
+ }
1163
+ const oldestSeq = controller.getState().history.bySessionId.get(activeSessionId)?.events?.[0]?.seq;
1164
+ const pageArrived = historyScroll && !historyScroll.applied && oldestSeq < historyScroll.oldestSeq;
1165
+ let pageScrollTop = null;
1166
+ if (pageArrived) {
1167
+ // Measure the same visible block, not the total transcript height:
1168
+ // live content can also grow at the bottom while a page is loading.
1169
+ const anchor = historyScroll.anchor;
1170
+ const element = anchor?.element.isConnected && anchor.element.textContent === anchor.text
1171
+ ? anchor.element
1172
+ : [...node.children].find(child => child.textContent === anchor?.text);
1173
+ const delta = element
1174
+ ? element.getBoundingClientRect().top - anchor.top
1175
+ : node.scrollHeight - historyScroll.height;
1176
+ pageScrollTop = Math.max(0, Math.min(node.scrollHeight - node.clientHeight,
1177
+ node.scrollTop + delta - SCROLL_ROW_HEIGHT));
1178
+ historyScroll.applied = true;
1179
+ historyScroll.target = pageScrollTop;
1180
+ historyScroll.releaseAt = performance.now() + HISTORY_SCROLL_GESTURE_GAP_MS;
1181
+ }
1154
1182
  const interaction = userScrollRef.current;
1155
1183
  const now = typeof performance !== "undefined" ? performance.now() : Date.now();
1156
1184
  const interacting = interaction.touching
@@ -1165,13 +1193,13 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
1165
1193
  // state normally preserves scrollTop, which would push the same visible
1166
1194
  // message down by the inserted height. Compensate with the measured DOM
1167
1195
  // height delta. Appended live text keeps the old scrollTop unchanged.
1168
- const prependedWhilePaused = stickyBottom
1196
+ const prependedWhilePaused = !historyScroll && stickyBottom
1169
1197
  && previousContent?.lastLine === lastLine
1170
1198
  && previousContent?.firstLine !== firstLine
1171
1199
  && node.scrollHeight > previousContent.scrollHeight
1172
1200
  && (preservePausedStickyScroll || node.scrollTop <= PROGRAMMATIC_SCROLL_TOLERANCE_PX);
1173
1201
  if (
1174
- !prependedWhilePaused
1202
+ !pageArrived && !prependedWhilePaused
1175
1203
  && interacting
1176
1204
  && scrollMode === previousViewportState?.scrollMode
1177
1205
  && (scrollOffset === previousViewportState?.scrollOffset || isEchoOffset)
@@ -1180,7 +1208,7 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
1180
1208
  previousContentRef.current = { firstLine, lastLine, scrollHeight: node.scrollHeight };
1181
1209
  return;
1182
1210
  }
1183
- const nextScrollTop = prependedWhilePaused
1211
+ const nextScrollTop = pageArrived ? pageScrollTop : prependedWhilePaused
1184
1212
  ? Math.max(0, Math.min(
1185
1213
  node.scrollTop + (node.scrollHeight - previousContent.scrollHeight),
1186
1214
  node.scrollHeight - node.clientHeight,
@@ -1198,7 +1226,7 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
1198
1226
  }
1199
1227
  });
1200
1228
  }
1201
- if (prependedWhilePaused && paneKey && typeof controller.updatePaneScrollFromViewport === "function") {
1229
+ if ((pageArrived || prependedWhilePaused) && paneKey && typeof controller.updatePaneScrollFromViewport === "function") {
1202
1230
  // The measured DOM compensation above is the new durable paused
1203
1231
  // position. Persist it too: otherwise switching sessions and back
1204
1232
  // reapplies the pre-page offset and moves the reader by the full
@@ -1221,6 +1249,15 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
1221
1249
  const onScroll = React.useCallback(() => {
1222
1250
  const node = ref.current;
1223
1251
  if (!node || !paneKey) return;
1252
+ const historyScroll = historyScrollRef.current;
1253
+ if (historyScroll?.applied && performance.now() <= historyScroll.releaseAt
1254
+ && node.scrollTop < historyScroll.target) {
1255
+ // Native touch momentum may continue without another touchmove.
1256
+ node.scrollTop = historyScroll.target;
1257
+ historyScroll.releaseAt = performance.now() + HISTORY_SCROLL_GESTURE_GAP_MS;
1258
+ return;
1259
+ }
1260
+ if (historyScroll?.applied && performance.now() > historyScroll.releaseAt) historyScrollRef.current = null;
1224
1261
  const pendingProgrammatic = programmaticScrollRef.current;
1225
1262
  if (pendingProgrammatic) {
1226
1263
  if (Math.abs(node.scrollTop - pendingProgrammatic.target) <= PROGRAMMATIC_SCROLL_TOLERANCE_PX) {
@@ -1268,13 +1305,49 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
1268
1305
  }
1269
1306
  }, [controller, dispatchScrollOffset, paneKey, ref, scrollMode, stickyBottom]);
1270
1307
 
1308
+ const requestHistoryPage = React.useCallback(() => {
1309
+ const node = ref.current;
1310
+ const state = controller.getState();
1311
+ const sessionId = state.sessions.activeSessionId;
1312
+ if (!node || !sessionId || historyScrollRef.current) return;
1313
+ const top = node.getBoundingClientRect().top;
1314
+ const element = [...node.children].find(child => child.textContent?.trim() && child.getBoundingClientRect().bottom > top + 6);
1315
+ const pending = {
1316
+ sessionId, oldestSeq: state.history.bySessionId.get(sessionId)?.events?.[0]?.seq,
1317
+ height: node.scrollHeight, applied: false,
1318
+ anchor: element ? { element, text: element.textContent, top: element.getBoundingClientRect().top } : null,
1319
+ };
1320
+ historyScrollRef.current = pending;
1321
+ const load = controller.handleChatTopHistoryScrollIntent?.(
1322
+ (node.scrollHeight - node.clientHeight) / SCROLL_ROW_HEIGHT,
1323
+ { force: true, preserveDomAnchor: true },
1324
+ );
1325
+ Promise.resolve(load).catch(() => {}).finally(() => {
1326
+ if (historyScrollRef.current !== pending) return;
1327
+ const oldest = controller.getState().history.bySessionId.get(sessionId)?.events?.[0]?.seq;
1328
+ if (!(oldest < pending.oldestSeq)) historyScrollRef.current = null;
1329
+ else setViewportRevision(revision => revision + 1);
1330
+ });
1331
+ }, [controller, ref]);
1332
+
1271
1333
  const onWheel = React.useCallback((event) => {
1272
1334
  const node = ref.current;
1273
- if (!node || paneKey !== "chat" || event.deltaY >= 0) return;
1335
+ if (!node || paneKey !== "chat" || !event.deltaY || event.ctrlKey) return;
1336
+ const pending = historyScrollRef.current;
1337
+ if (pending && event.deltaY > 0) historyScrollRef.current = null;
1338
+ else if (pending) {
1339
+ if (!pending.applied || performance.now() <= pending.releaseAt) {
1340
+ pending.releaseAt = performance.now() + HISTORY_SCROLL_GESTURE_GAP_MS;
1341
+ event.preventDefault();
1342
+ return;
1343
+ }
1344
+ historyScrollRef.current = null;
1345
+ }
1346
+ if (event.deltaY >= 0) return;
1274
1347
  if (node.scrollTop > PROGRAMMATIC_SCROLL_TOLERANCE_PX) return;
1275
- const maxScroll = Math.max(0, node.scrollHeight - node.clientHeight);
1276
- controller.handleChatTopHistoryScrollIntent?.(maxScroll / SCROLL_ROW_HEIGHT, { preserveDomAnchor: true });
1277
- }, [controller, paneKey, ref]);
1348
+ event.preventDefault();
1349
+ requestHistoryPage();
1350
+ }, [paneKey, ref, requestHistoryPage]);
1278
1351
 
1279
1352
  // Touch equivalent of the wheel-at-top gesture: touch devices never fire
1280
1353
  // wheel events, and once scrollTop sits at 0 a further swipe-down emits no
@@ -1284,6 +1357,7 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
1284
1357
  const touchPullRef = React.useRef({ startY: null, fired: false });
1285
1358
  const onTouchStart = React.useCallback((event) => {
1286
1359
  userScrollRef.current.touching = true;
1360
+ if (historyScrollRef.current?.applied) historyScrollRef.current = null;
1287
1361
  if (paneKey !== "chat") return;
1288
1362
  touchPullRef.current = { startY: event.touches?.[0]?.clientY ?? null, fired: false };
1289
1363
  }, [paneKey]);
@@ -1292,26 +1366,45 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
1292
1366
  // Momentum continues past the finger lift; onScroll keeps refreshing
1293
1367
  // lastUserScrollAt for as long as the glide emits scroll events.
1294
1368
  userScrollRef.current.lastUserScrollAt = typeof performance !== "undefined" ? performance.now() : Date.now();
1369
+ if (historyScrollRef.current?.applied) {
1370
+ historyScrollRef.current.releaseAt = performance.now() + HISTORY_SCROLL_GESTURE_GAP_MS;
1371
+ }
1295
1372
  }, []);
1296
1373
  const onTouchMove = React.useCallback((event) => {
1297
1374
  const node = ref.current;
1298
1375
  const pull = touchPullRef.current;
1299
- if (!node || paneKey !== "chat") return;
1376
+ if (!node || paneKey !== "chat" || event.touches?.length !== 1) return;
1377
+ if (historyScrollRef.current) {
1378
+ historyScrollRef.current.releaseAt = performance.now() + HISTORY_SCROLL_GESTURE_GAP_MS;
1379
+ event.preventDefault();
1380
+ return;
1381
+ }
1300
1382
  if (pull.fired || pull.startY == null) return;
1301
1383
  if (node.scrollTop > PROGRAMMATIC_SCROLL_TOLERANCE_PX) return;
1302
1384
  const y = event.touches?.[0]?.clientY;
1303
1385
  if (y == null || y - pull.startY < TOUCH_TOP_PULL_THRESHOLD_PX) return;
1304
1386
  pull.fired = true;
1305
1387
  // A deliberate pull at the top of the pane is an unambiguous request:
1306
- // force the load, bypassing both the arm/load two-stage handshake and
1307
- // the DOM-vs-render-metric offset gate (the two measurements disagree
1308
- // on narrow viewports). The wheel path keeps the handshake — one
1309
- // physical scroll emits MANY wheel events, so it needs debouncing.
1310
- const maxScroll = Math.max(0, node.scrollHeight - node.clientHeight);
1311
- controller.handleChatTopHistoryScrollIntent?.(maxScroll / SCROLL_ROW_HEIGHT + 1, { force: true, preserveDomAnchor: true });
1312
- }, [controller, paneKey, ref]);
1388
+ // Request one page at the measured DOM boundary. The shared gesture
1389
+ // guard absorbs repeated wheel events and the remainder of this pull.
1390
+ event.preventDefault();
1391
+ requestHistoryPage();
1392
+ }, [paneKey, ref, requestHistoryPage]);
1313
1393
 
1314
- return { normalizedLines, onScroll, onWheel, onTouchStart, onTouchMove, onTouchEnd };
1394
+ React.useEffect(() => {
1395
+ const node = ref.current;
1396
+ if (!node) return;
1397
+ // React's delegated wheel/touch listeners are passive. These must be
1398
+ // cancellable so one in-flight gesture cannot consume the new page.
1399
+ node.addEventListener("wheel", onWheel, { passive: false });
1400
+ node.addEventListener("touchmove", onTouchMove, { passive: false });
1401
+ return () => {
1402
+ node.removeEventListener("wheel", onWheel);
1403
+ node.removeEventListener("touchmove", onTouchMove);
1404
+ };
1405
+ }, [ref, onWheel, onTouchMove]);
1406
+
1407
+ return { normalizedLines, onScroll, onTouchStart, onTouchEnd };
1315
1408
  }
1316
1409
 
1317
1410
  function Runs({ runs, theme }) {
@@ -4144,7 +4237,7 @@ function ScrollLinesPanel({ title, titleRight = null, color, focused, actions, l
4144
4237
  }, [panelRef]);
4145
4238
  const stickyRef = React.useRef(null);
4146
4239
  const syncingHorizontalRef = React.useRef(false);
4147
- const { normalizedLines, onScroll, onWheel, onTouchStart, onTouchMove, onTouchEnd } = useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller, { stickyBottom });
4240
+ const { normalizedLines, onScroll, onTouchStart, onTouchEnd } = useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller, { stickyBottom });
4148
4241
  const normalizedSticky = React.useMemo(() => normalizeLines(stickyLines), [stickyLines]);
4149
4242
  const normalizedBottomSticky = React.useMemo(() => normalizeLines(bottomStickyLines), [bottomStickyLines]);
4150
4243
  const preserveHorizontalScroll = className.includes("is-preserve") && panelClassName.includes("has-preserved-sticky");
@@ -4243,7 +4336,7 @@ function ScrollLinesPanel({ title, titleRight = null, color, focused, actions, l
4243
4336
  normalizedSticky.map((line, index) => React.createElement(Line, { key: `sticky:${index}`, line, theme })),
4244
4337
  )
4245
4338
  : null,
4246
- React.createElement("div", { ref: setPanelNode, className: `ps-scroll-panel ${className}${scrollShadow.down ? " is-scrolled-down" : ""}${scrollShadow.up ? " is-scrolled-up" : ""}`.trim(), "data-session-scroll": focusRegion === "sessions" ? "1" : undefined, "aria-live": ariaLive || undefined, "aria-atomic": ariaLive ? "false" : undefined, onScroll: handleBodyScroll, onMouseDown: claimFocus, onTouchStart, onWheel, onTouchMove, onTouchEnd, onTouchCancel: onTouchEnd },
4339
+ React.createElement("div", { ref: setPanelNode, className: `ps-scroll-panel ${className}${scrollShadow.down ? " is-scrolled-down" : ""}${scrollShadow.up ? " is-scrolled-up" : ""}`.trim(), "data-session-scroll": focusRegion === "sessions" ? "1" : undefined, "aria-live": ariaLive || undefined, "aria-atomic": ariaLive ? "false" : undefined, onScroll: handleBodyScroll, onMouseDown: claimFocus, onTouchStart, onTouchEnd, onTouchCancel: onTouchEnd },
4247
4340
  typeof renderBody === "function"
4248
4341
  ? renderBody(normalizedLines, theme)
4249
4342
  : structuredBlocks
@@ -4558,28 +4651,26 @@ function SessionDetailBox({ session, childCount = 0, pause = null, controller =
4558
4651
  * fleet. That only holds while every prop is referentially stable — hence the
4559
4652
  * hoisted click handler and ref setter rather than closures built per row.
4560
4653
  */
4561
- /**
4562
- * True when the primary input is a finger. Drag-to-folder is armed on
4563
- * pointerdown and needs `touch-action: none` to receive a move stream — which
4564
- * on a touch screen also means the list can no longer be scrolled by dragging
4565
- * it, so the gesture is withheld there entirely.
4566
- */
4567
- function useCoarsePointer() {
4568
- const query = "(pointer: coarse)";
4654
+ /** Subscribe to viewport or input changes without remounting the pane. */
4655
+ function useMediaQuery(query) {
4569
4656
  const read = () => (typeof window !== "undefined" && typeof window.matchMedia === "function"
4570
4657
  ? window.matchMedia(query).matches
4571
4658
  : false);
4572
- const [coarse, setCoarse] = React.useState(read);
4659
+ const [matches, setMatches] = React.useState(read);
4573
4660
  React.useEffect(() => {
4574
4661
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return undefined;
4575
4662
  const media = window.matchMedia(query);
4576
- const onChange = (event) => setCoarse(event.matches);
4663
+ const onChange = (event) => setMatches(event.matches);
4664
+ setMatches(media.matches);
4577
4665
  media.addEventListener?.("change", onChange);
4578
4666
  return () => media.removeEventListener?.("change", onChange);
4579
- }, []);
4580
- return coarse;
4667
+ }, [query]);
4668
+ return matches;
4581
4669
  }
4582
4670
 
4671
+ // Withhold drag-to-folder on touch screens so finger drags can scroll the list.
4672
+ function useCoarsePointer() { return useMediaQuery("(pointer: coarse)"); }
4673
+
4583
4674
  const RAIL_ORIGIN_PX = 13;
4584
4675
  const RAIL_STEP_PX = 11;
4585
4676
  const RAIL_WIDTH_PX = 1.5;
@@ -5052,11 +5143,10 @@ function useAxisLockedPan(ref, enabled = true) {
5052
5143
  }, [ref, enabled]);
5053
5144
  }
5054
5145
 
5055
- const SessionSearchControl = React.memo(function SessionSearchControl({ query = "", onQuery, matchCount = 0, mobile = false, listRef = null }) {
5146
+ const SessionSearchControl = React.memo(function SessionSearchControl({ query = "", onQuery, matchCount = 0, mobile = false, expanded = false, onOpen, onClose, triggerRef, listRef = null }) {
5056
5147
  // Keep typing local: expensive list filtering and external-store updates
5057
5148
  // must never be part of the input's immediate render path.
5058
5149
  const [draft, setDraft] = React.useState(query);
5059
- const [mobileOpen, setMobileOpen] = React.useState(Boolean(query));
5060
5150
  const timer = React.useRef(null);
5061
5151
  const published = React.useRef(query);
5062
5152
  const composing = React.useRef(false);
@@ -5075,29 +5165,24 @@ const SessionSearchControl = React.memo(function SessionSearchControl({ query =
5075
5165
  cancel(); published.current = query; setDraft(query);
5076
5166
  }, [query]);
5077
5167
  const inputRef = React.useRef(null);
5078
- React.useEffect(() => {
5079
- if (query) setMobileOpen(true);
5080
- }, [query]);
5081
- const open = () => {
5082
- setMobileOpen(true);
5083
- requestAnimationFrame(() => inputRef.current?.focus({ preventScroll: true }));
5084
- };
5085
5168
  const closeOrClear = () => {
5086
5169
  if (draft || query) { setDraft(""); publish(""); }
5087
- else setMobileOpen(false);
5170
+ else onClose?.();
5088
5171
  };
5089
5172
  const resultLabel = draft !== query ? "Searching…" : draft
5090
5173
  ? `${matchCount} ${matchCount === 1 ? "match" : "matches"}` : "";
5091
5174
  return React.createElement("div", {
5092
- className: `ps-session-search${mobileOpen ? " is-open" : ""}`,
5175
+ className: `ps-session-search${expanded ? " is-open" : ""}`,
5093
5176
  "data-session-search": "true",
5094
5177
  },
5095
5178
  mobile ? React.createElement("button", {
5096
5179
  type: "button",
5097
5180
  className: "ps-session-search-trigger",
5181
+ ref: triggerRef,
5182
+ "aria-expanded": expanded,
5098
5183
  "aria-label": "Search sessions",
5099
5184
  title: "Search sessions",
5100
- onClick: open,
5185
+ onClick: onOpen,
5101
5186
  }, React.createElement(SearchGlyph)) : null,
5102
5187
  React.createElement("div", { className: "ps-session-search-fields" },
5103
5188
  React.createElement(SearchGlyph),
@@ -5128,7 +5213,7 @@ const SessionSearchControl = React.memo(function SessionSearchControl({ query =
5128
5213
  role: "status",
5129
5214
  "aria-live": "polite",
5130
5215
  }, resultLabel) : null,
5131
- (draft || mobile) ? React.createElement("button", {
5216
+ draft ? React.createElement("button", {
5132
5217
  type: "button",
5133
5218
  className: "ps-session-search-clear",
5134
5219
  "aria-label": draft ? "Clear session search" : "Close session search",
@@ -5145,6 +5230,11 @@ function SessionPane({ controller, actions = null, panelClassName = "", structur
5145
5230
  // sessions-ONLY layout is the exception: it has the whole screen and the
5146
5231
  // detail box is the point of asking for it.
5147
5232
  const isMobilePane = String(panelClassName).includes("ps-mobile-session-pane");
5233
+ const compactSearch = useMediaQuery("(max-width: 920px)");
5234
+ const [searchOpen, setSearchOpen] = React.useState(false);
5235
+ const searchOverlay = compactSearch && searchOpen;
5236
+ const searchDialogRef = React.useRef(null);
5237
+ const searchTriggerRef = React.useRef(null);
5148
5238
  // Vertical is the primary scroll axis; sideways takes a deliberate swipe.
5149
5239
  const sessionListRef = React.useRef(null);
5150
5240
  // Selection reverts to plain taps wherever the primary input is a finger:
@@ -5253,6 +5343,35 @@ function SessionPane({ controller, actions = null, panelClassName = "", structur
5253
5343
  }
5254
5344
  searchEnvRef.current?.setQuery?.(next);
5255
5345
  }, []);
5346
+ const closeSearch = React.useCallback(() => {
5347
+ setSearchOpen(false);
5348
+ setSearchQuery("");
5349
+ requestAnimationFrame(() => searchTriggerRef.current?.focus({ preventScroll: true }));
5350
+ }, [setSearchQuery]);
5351
+ React.useLayoutEffect(() => {
5352
+ const dialog = searchDialogRef.current;
5353
+ if (!searchOverlay || !dialog) return undefined;
5354
+ const viewport = window.visualViewport;
5355
+ const resize = () => {
5356
+ dialog.style.top = `${(viewport?.offsetTop || 0) + 8}px`;
5357
+ dialog.style.left = `${(viewport?.offsetLeft || 0) + 8}px`;
5358
+ dialog.style.width = `${(viewport?.width || window.innerWidth) - 16}px`;
5359
+ dialog.style.height = `${(viewport?.height || window.innerHeight) - 16}px`;
5360
+ };
5361
+ resize();
5362
+ dialog.showModal();
5363
+ dialog.querySelector("input")?.focus({ preventScroll: true });
5364
+ viewport?.addEventListener("resize", resize);
5365
+ viewport?.addEventListener("scroll", resize);
5366
+ window.addEventListener("resize", resize);
5367
+ return () => {
5368
+ viewport?.removeEventListener("resize", resize);
5369
+ viewport?.removeEventListener("scroll", resize);
5370
+ window.removeEventListener("resize", resize);
5371
+ dialog.close();
5372
+ };
5373
+ }, [searchOverlay]);
5374
+ React.useEffect(() => { if (!compactSearch) setSearchOpen(false); }, [compactSearch]);
5256
5375
  React.useLayoutEffect(() => {
5257
5376
  if (viewState.filterQuery || !searchScrollRef.current.restore || !sessionListRef.current) return;
5258
5377
  sessionListRef.current.scrollTop = searchScrollRef.current.top;
@@ -5386,7 +5505,7 @@ function SessionPane({ controller, actions = null, panelClassName = "", structur
5386
5505
  // rows/viewState from a ref that is refreshed on every render instead of
5387
5506
  // closing over them.
5388
5507
  const clickEnv = React.useRef(null);
5389
- clickEnv.current = { rows, viewState, controller, selection };
5508
+ clickEnv.current = { rows, viewState, controller, selection, searchOverlay, closeSearch };
5390
5509
  // ── Drag sessions into / out of groups ────────────────────────────
5391
5510
  // Pointer-driven so it works from <button> rows, can render a collection
5392
5511
  // ghost for a multi-selection, and can highlight the destination folder.
@@ -5712,6 +5831,15 @@ function SessionPane({ controller, actions = null, panelClassName = "", structur
5712
5831
 
5713
5832
  const handleRowClick = React.useCallback((event, row) => {
5714
5833
  const { rows: currentRows, viewState: current, controller: ctl, selection: pick } = clickEnv.current;
5834
+ if (clickEnv.current.searchOverlay && !row.isGroup) {
5835
+ if (pick) pick.onSelect(row.sessionId);
5836
+ else {
5837
+ ctl.setFocus("sessions");
5838
+ ctl.loadSession(row.sessionId).catch(() => {});
5839
+ }
5840
+ clickEnv.current.closeSearch();
5841
+ return;
5842
+ }
5715
5843
  if (pick) {
5716
5844
  if (row.isGroup || (row.hasChildren && row.active)) ctl.dispatch({ type: row.collapsed ? "sessions/expand" : "sessions/collapse", sessionId: row.sessionId });
5717
5845
  if (!row.isGroup) pick.onSelect(row.sessionId);
@@ -5955,14 +6083,12 @@ function SessionPane({ controller, actions = null, panelClassName = "", structur
5955
6083
  : "Release to cancel"))
5956
6084
  : null;
5957
6085
 
5958
- return React.createElement(React.Fragment, null,
5959
- dragGhost,
5960
- actionsOnly ? (actionsHost ? createPortal(React.createElement("div", { className: "ps-moa-control-actions", onClick: onAction }, panelActions), actionsHost) : null) : React.createElement(Panel, {
5961
- title: [{ text: "Sessions", color: "yellow", bold: true }],
6086
+ const sessionPanel = actionsOnly ? (actionsHost ? createPortal(React.createElement("div", { className: "ps-moa-control-actions", onClick: onAction }, panelActions), actionsHost) : null) : React.createElement(Panel, {
6087
+ title: [{ text: searchOverlay ? "Find a session" : "Sessions", color: "yellow", bold: true }],
5962
6088
  color: "yellow",
5963
6089
  focused: viewState.focused,
5964
6090
  theme,
5965
- actions: selection ? React.createElement(React.Fragment, null,
6091
+ actions: searchOverlay ? React.createElement(IconButton, { label: "Close session search", icon: "×", onClick: closeSearch }) : selection ? React.createElement(React.Fragment, null,
5966
6092
  selection.onCreate ? React.createElement(IconButton, {
5967
6093
  className: "ps-mini-button", icon: React.createElement(PlusGlyph),
5968
6094
  label: "Create New Session", onClick: selection.onCreate,
@@ -6010,7 +6136,16 @@ function SessionPane({ controller, actions = null, panelClassName = "", structur
6010
6136
  // touch hijacks the finger that should be scrolling the list.
6011
6137
  drag: selection || touchInput || viewState.sortMode !== "saved" ? null : dragHandlers,
6012
6138
  }))),
6013
- React.createElement("div", { className: "ps-session-find-controls" },
6139
+ React.createElement("div", {
6140
+ className: "ps-session-find-controls",
6141
+ onPointerDown: (event) => {
6142
+ // Keep the search keyboard open while tapping sort, refresh, or clear.
6143
+ // Safari otherwise blurs the field without focusing the button.
6144
+ if (compactSearch && event.button === 0 && event.target.closest?.("button")
6145
+ && event.currentTarget.contains(document.activeElement)
6146
+ && document.activeElement?.matches("input")) event.preventDefault();
6147
+ },
6148
+ },
6014
6149
  React.createElement("div", { className: "ps-session-sort-controls" },
6015
6150
  React.createElement("div", { className: "ps-session-sort-modes", role: "group", "aria-label": "Session sort order" },
6016
6151
  ...[["used", "Recently used", "M12 8v4l3 2", true], ["updated", "Recently updated", "M3 12h4l3-7 4 14 3-7h4"], ["saved", "Saved order", "M6 3h12v18l-6-4-6 4Z"]].map(([mode, label, path, clock]) => React.createElement(IconButton, {
@@ -6030,10 +6165,14 @@ function SessionPane({ controller, actions = null, panelClassName = "", structur
6030
6165
  query: viewState.filterQuery,
6031
6166
  onQuery: setSearchQuery,
6032
6167
  matchCount: searchMatchCount,
6033
- mobile: isMobilePane,
6168
+ mobile: compactSearch,
6169
+ expanded: searchOverlay,
6170
+ onOpen: () => setSearchOpen(true),
6171
+ onClose: closeSearch,
6172
+ triggerRef: searchTriggerRef,
6034
6173
  listRef: sessionListRef,
6035
6174
  })),
6036
- (showDetailBox === null ? !isMobilePane : showDetailBox)
6175
+ !searchOverlay && (showDetailBox === null ? !isMobilePane : showDetailBox)
6037
6176
  ? React.createElement(SessionDetailBox, {
6038
6177
  session: activeSession,
6039
6178
  childCount: activeRow?.childCount || 0,
@@ -6047,7 +6186,21 @@ function SessionPane({ controller, actions = null, panelClassName = "", structur
6047
6186
  collapsed: !detailCollapsed,
6048
6187
  }),
6049
6188
  })
6050
- : null),
6189
+ : null);
6190
+
6191
+ return React.createElement(React.Fragment, null,
6192
+ dragGhost,
6193
+ !searchOverlay ? sessionPanel : null,
6194
+ React.createElement("dialog", {
6195
+ ref: searchDialogRef,
6196
+ className: "ps-session-search-overlay",
6197
+ "aria-label": "Find a session",
6198
+ onCancel: event => { event.preventDefault(); closeSearch(); },
6199
+ onKeyDownCapture: event => {
6200
+ if (event.key === "Escape") { event.preventDefault(); event.stopPropagation(); closeSearch(); }
6201
+ },
6202
+ onClick: event => { if (event.target === event.currentTarget) closeSearch(); },
6203
+ }, searchOverlay ? sessionPanel : null),
6051
6204
  (manageOpen && activeSession && !activeSession.isGroup)
6052
6205
  ? React.createElement(SessionModifyModal, {
6053
6206
  controller,
@@ -7225,14 +7378,14 @@ export function evaluateKeyboardTakeover(baseline, viewportWidth, viewportHeight
7225
7378
  }
7226
7379
 
7227
7380
  /**
7228
- * True while the on-screen keyboard is up AND the chat composer summoned it.
7381
+ * True while the on-screen keyboard is up AND a matching control has focus.
7229
7382
  * Both conditions matter: height alone would fire for a modal's text field
7230
7383
  * and collapse the workspace behind the modal; focus alone would fire for
7231
7384
  * hardware keyboards that shrink nothing. State-driven on the keyboard
7232
7385
  * itself, so it reverts the moment the keyboard goes away — including the
7233
7386
  * iOS swipe-dismiss that closes the keyboard without blurring the input.
7234
7387
  */
7235
- function useKeyboardTakeover(enabled) {
7388
+ function useKeyboardTakeover(enabled, focusSelector = ".ps-prompt-input") {
7236
7389
  const [takeover, setTakeover] = React.useState(false);
7237
7390
  React.useEffect(() => {
7238
7391
  if (!enabled || typeof window === "undefined" || !window.visualViewport) {
@@ -7244,7 +7397,7 @@ function useKeyboardTakeover(enabled) {
7244
7397
  let frame = 0;
7245
7398
  const evaluate = () => {
7246
7399
  frame = 0;
7247
- const composerFocused = Boolean(document.activeElement?.classList?.contains("ps-prompt-input"));
7400
+ const composerFocused = Boolean(document.activeElement?.matches?.(focusSelector));
7248
7401
  const next = evaluateKeyboardTakeover(baseline, viewport.width, viewport.height, composerFocused);
7249
7402
  baseline = next.baseline;
7250
7403
  setTakeover(next.takeover);
@@ -7262,7 +7415,7 @@ function useKeyboardTakeover(enabled) {
7262
7415
  window.removeEventListener("focusin", schedule);
7263
7416
  window.removeEventListener("focusout", schedule);
7264
7417
  };
7265
- }, [enabled]);
7418
+ }, [enabled, focusSelector]);
7266
7419
  return enabled ? takeover : false;
7267
7420
  }
7268
7421
 
@@ -1 +1 @@
1
- import{g as p,r as u,d as a}from"./chunk-MOJQB5TN-CHdrVT1z.js";import{p as f}from"./chunk-JWPE2WC7-CGM2GAMX.js";import{_ as n,l as o}from"./mermaid.core-i8uqvLPa.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-3zVj2GvI.js";import"./pilotswarm-D7Q48waO.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-CHa4SOoq.js";import{p as f}from"./chunk-JWPE2WC7-pjfQBm7p.js";import{_ as n,l as o}from"./mermaid.core-DPy_PtTG.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-B8cRqvMz.js";import"./pilotswarm-BchtZfEr.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-i8uqvLPa.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-DPy_PtTG.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};