pilotswarm 0.5.66 → 0.5.68

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/controller.js +47 -24
  3. package/ui/core/src/reducer.js +16 -2
  4. package/ui/core/src/selectors.js +10 -0
  5. package/ui/react/src/web-app.js +9 -5
  6. package/web/dist/assets/{abnfDiagram-VRR7QNED-B-04UhgW.js → abnfDiagram-VRR7QNED-rCdnr4Zk.js} +1 -1
  7. package/web/dist/assets/{arc-C5XCnSQg.js → arc-DeoxxJ2S.js} +1 -1
  8. package/web/dist/assets/{architectureDiagram-ZJ3FMSHR-R-xjkIQE.js → architectureDiagram-ZJ3FMSHR-DAz2X6IV.js} +1 -1
  9. package/web/dist/assets/{blockDiagram-677ZJIJ3-DrthdK1L.js → blockDiagram-677ZJIJ3-DPsxUKQJ.js} +1 -1
  10. package/web/dist/assets/{c4Diagram-LMCZKHZV-DRZ4aZB3.js → c4Diagram-LMCZKHZV-Cl8IpoAZ.js} +1 -1
  11. package/web/dist/assets/channel-DCTjhzIq.js +1 -0
  12. package/web/dist/assets/{chunk-2Q5K7J3B-Df7tPwEB.js → chunk-2Q5K7J3B-WHxPHUqg.js} +1 -1
  13. package/web/dist/assets/{chunk-32BRIVSS-bNd88tsn.js → chunk-32BRIVSS-9S1suaZM.js} +1 -1
  14. package/web/dist/assets/{chunk-5VM5RSS4-ylLOcwFv.js → chunk-5VM5RSS4-DmBwY4rK.js} +1 -1
  15. package/web/dist/assets/{chunk-EX3LRPZG-CWgx_6ev.js → chunk-EX3LRPZG-BbKMT5Il.js} +1 -1
  16. package/web/dist/assets/{chunk-JWPE2WC7-BD-w4617.js → chunk-JWPE2WC7-B9Qns4SI.js} +1 -1
  17. package/web/dist/assets/{chunk-MOJQB5TN-De76fp2s.js → chunk-MOJQB5TN-G6hkDffb.js} +1 -1
  18. package/web/dist/assets/{chunk-RYQCIY6F-CpWyBMvz.js → chunk-RYQCIY6F-Ca38LebY.js} +1 -1
  19. package/web/dist/assets/{chunk-V7JOEXUC-C-NJGbbs.js → chunk-V7JOEXUC-DPeEQDsB.js} +1 -1
  20. package/web/dist/assets/{chunk-VR4S4FIN-DK28nbHC.js → chunk-VR4S4FIN-DYuh7YGE.js} +1 -1
  21. package/web/dist/assets/{chunk-XXDRQBXY-Bk5aYmwf.js → chunk-XXDRQBXY-BDRBkhU_.js} +1 -1
  22. package/web/dist/assets/classDiagram-OUVF2IWQ-Cfa6ZtJR.js +1 -0
  23. package/web/dist/assets/classDiagram-v2-EOCWNBFH-Cfa6ZtJR.js +1 -0
  24. package/web/dist/assets/{cose-bilkent-JH36ORCC-OLeC_lx0.js → cose-bilkent-JH36ORCC-CpHdEFyS.js} +1 -1
  25. package/web/dist/assets/{cynefin-VYW2F7L2-C-gW4wVJ.js → cynefin-VYW2F7L2-DRYxiNM0.js} +1 -1
  26. package/web/dist/assets/{cynefinDiagram-TSTJHNR4-CFbownfZ.js → cynefinDiagram-TSTJHNR4-B8fSzWxH.js} +1 -1
  27. package/web/dist/assets/{dagre-VKFMJZFB-e4s9tuv2.js → dagre-VKFMJZFB-CnJyU6YF.js} +1 -1
  28. package/web/dist/assets/{diagram-FQU43EPY-BjE9UaN5.js → diagram-FQU43EPY-BS2_uGW0.js} +1 -1
  29. package/web/dist/assets/{diagram-G47NLZAW-_3b8-LSz.js → diagram-G47NLZAW-DjKog-bE.js} +1 -1
  30. package/web/dist/assets/{diagram-NH7WQ7WH-2B55Dr-P.js → diagram-NH7WQ7WH-BaWtvMDL.js} +1 -1
  31. package/web/dist/assets/{diagram-OA4YK3LP-DI42Mpfa.js → diagram-OA4YK3LP-Z11ytyEX.js} +1 -1
  32. package/web/dist/assets/{diagram-WEI45ONY-DwdeclWS.js → diagram-WEI45ONY-DiiH4Od8.js} +1 -1
  33. package/web/dist/assets/{ebnfDiagram-CCIWWBDH-D0mgBmPT.js → ebnfDiagram-CCIWWBDH-xtE5CNkB.js} +1 -1
  34. package/web/dist/assets/{erDiagram-Q63AITRT-9uDmXDxu.js → erDiagram-Q63AITRT-Dj5wjLbd.js} +1 -1
  35. package/web/dist/assets/{flowDiagram-23GEKE2U-czg0H1o9.js → flowDiagram-23GEKE2U-O_1XH_-x.js} +1 -1
  36. package/web/dist/assets/{ganttDiagram-NO4QXBWP-klkCbthP.js → ganttDiagram-NO4QXBWP-AuETTA_E.js} +1 -1
  37. package/web/dist/assets/{gitGraphDiagram-IHSO6WYX-KkCVvJUf.js → gitGraphDiagram-IHSO6WYX-gTS7mo_B.js} +1 -1
  38. package/web/dist/assets/{index-CZgFyGc_.js → index-CpIHunmE.js} +2 -2
  39. package/web/dist/assets/{infoDiagram-FWYZ7A6U-Dt2S9vn1.js → infoDiagram-FWYZ7A6U-Fhv6oMjM.js} +1 -1
  40. package/web/dist/assets/{ishikawaDiagram-FXEZZL3T-Dwm-j64z.js → ishikawaDiagram-FXEZZL3T-BIWy0CgN.js} +1 -1
  41. package/web/dist/assets/{journeyDiagram-5HDEW3XC-BF0hgIwR.js → journeyDiagram-5HDEW3XC-0XQ9xC-A.js} +1 -1
  42. package/web/dist/assets/{kanban-definition-HUTT4EX6-qu3pSjQ4.js → kanban-definition-HUTT4EX6-ChyhUUfr.js} +1 -1
  43. package/web/dist/assets/{linear-D2wggRGK.js → linear-CFXBfAtq.js} +1 -1
  44. package/web/dist/assets/{mermaid.core-CEMxYLqP.js → mermaid.core-BPXpLhrQ.js} +4 -4
  45. package/web/dist/assets/{mindmap-definition-LN4V7U3C-DtDqO1Si.js → mindmap-definition-LN4V7U3C-HEv8CBmG.js} +1 -1
  46. package/web/dist/assets/{papaparse.min-Ca3zFRUj.js → papaparse.min-zNHCLHbr.js} +1 -1
  47. package/web/dist/assets/{pegDiagram-2B236MQR-Bptd8cxe.js → pegDiagram-2B236MQR-Ciaic9kL.js} +1 -1
  48. package/web/dist/assets/{pieDiagram-ENE6RG2P-Cbvo_diJ.js → pieDiagram-ENE6RG2P-CPBwQT7c.js} +1 -1
  49. package/web/dist/assets/pilotswarm-t7ZSHp3x.js +109 -0
  50. package/web/dist/assets/{quadrantDiagram-ABIIQ3AL-Dsms43Mu.js → quadrantDiagram-ABIIQ3AL-Bn1GbLE3.js} +1 -1
  51. package/web/dist/assets/{railroadDiagram-RFXS5EU6-l5T4OGip.js → railroadDiagram-RFXS5EU6-DgbTuh6h.js} +1 -1
  52. package/web/dist/assets/{requirementDiagram-TGXJPOKE-D7N_xPkI.js → requirementDiagram-TGXJPOKE-C25kl_pE.js} +1 -1
  53. package/web/dist/assets/{sankeyDiagram-HTMAVEWB-BSppPWwp.js → sankeyDiagram-HTMAVEWB-IXSFhGpB.js} +1 -1
  54. package/web/dist/assets/{sequenceDiagram-DBY2YBRQ-drRDz5Uo.js → sequenceDiagram-DBY2YBRQ-BkLHDo50.js} +1 -1
  55. package/web/dist/assets/{sizeCapture-X5ZJPWSS-BljhCGnZ.js → sizeCapture-X5ZJPWSS-DYnL5G7X.js} +1 -1
  56. package/web/dist/assets/{stateDiagram-2N3HPSRC-CssZ3S0X.js → stateDiagram-2N3HPSRC-Cyn7hAE7.js} +1 -1
  57. package/web/dist/assets/stateDiagram-v2-6OUMAXLB-CrXU-8_S.js +1 -0
  58. package/web/dist/assets/{swimlanes-5IMT3BWC-Cap4r3qG.js → swimlanes-5IMT3BWC-CZ6EgHci.js} +2 -2
  59. package/web/dist/assets/swimlanesDiagram-G3AALYLV-QcV2Vg4L.js +8 -0
  60. package/web/dist/assets/{timeline-definition-FHXFAJF6-CRlJg6Zj.js → timeline-definition-FHXFAJF6-uvqzr_O1.js} +1 -1
  61. package/web/dist/assets/{vennDiagram-L72KCM5P-BLgXv6xY.js → vennDiagram-L72KCM5P-1ca2fSuA.js} +1 -1
  62. package/web/dist/assets/{wardleyDiagram-EHGQE667-EbTHIyRd.js → wardleyDiagram-EHGQE667-DLDKHVSh.js} +1 -1
  63. package/web/dist/assets/{xychartDiagram-FW5EYKEG-DPR0SaNZ.js → xychartDiagram-FW5EYKEG-BcU1gt-_.js} +1 -1
  64. package/web/dist/index.html +2 -2
  65. package/web/dist/assets/channel-trVVWAw_.js +0 -1
  66. package/web/dist/assets/classDiagram-OUVF2IWQ-Bsdx911B.js +0 -1
  67. package/web/dist/assets/classDiagram-v2-EOCWNBFH-Bsdx911B.js +0 -1
  68. package/web/dist/assets/pilotswarm-BJidJRMR.js +0 -109
  69. package/web/dist/assets/stateDiagram-v2-6OUMAXLB-DDkaZvTf.js +0 -1
  70. package/web/dist/assets/swimlanesDiagram-G3AALYLV-CiHBj-pL.js +0 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pilotswarm",
3
- "version": "0.5.66",
3
+ "version": "0.5.68",
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.66",
84
+ "pilotswarm-sdk": "0.5.68",
85
85
  "react": "^19.2.4",
86
86
  "react-dom": "^19.2.4",
87
87
  "ws": "^8.18.2"
@@ -2530,13 +2530,16 @@ export class PilotSwarmUiController {
2530
2530
  }
2531
2531
  await this.refreshSessions();
2532
2532
  this.catalogTimer = setInterval(() => {
2533
+ // Do not queue more catalog traffic behind a slow periodic read.
2534
+ if (this.catalogPollInFlight) return;
2535
+ this.catalogPollInFlight = true;
2533
2536
  this.refreshSessions().catch((error) => {
2534
2537
  this.dispatch({
2535
2538
  type: "connection/error",
2536
2539
  error: error?.message || String(error),
2537
2540
  statusText: SESSION_REFRESH_FAILED_STATUS,
2538
2541
  });
2539
- });
2542
+ }).finally(() => { this.catalogPollInFlight = false; });
2540
2543
  }, 4000);
2541
2544
  }
2542
2545
 
@@ -2628,6 +2631,16 @@ export class PilotSwarmUiController {
2628
2631
  const recoveringConnection = !preRefreshState.connection.connected || Boolean(preRefreshState.connection.error);
2629
2632
  const shouldClearRefreshFailureBanner = preRefreshState.ui.statusText === SESSION_REFRESH_FAILED_STATUS;
2630
2633
  const previousActive = this.getState().sessions.activeSessionId;
2634
+ const previousNavigationGeneration = this.navigationGeneration;
2635
+ // The folder catalog is independent of the session pages: overlap its RTT.
2636
+ const groupRowsPromise = typeof this.transport.listSessionGroups === "function"
2637
+ ? Promise.resolve().then(() => this.transport.listSessionGroups())
2638
+ .then(groups => (Array.isArray(groups) ? groups : []).map(sessionGroupToRow).filter(Boolean))
2639
+ .catch(error => {
2640
+ console.warn(`[PilotSwarmUi] session-group fetch failed, keeping the known folders: ${error?.message || error}`);
2641
+ return null;
2642
+ })
2643
+ : Promise.resolve(null);
2631
2644
  let sessions = (await loadSessionCatalogPageWindow(this.transport)).map(normalizeSessionListRow);
2632
2645
  // Folders are NOT merged into the session payload any more: they live
2633
2646
  // in their own state slice, so a session refresh cannot drop them. A
@@ -2641,15 +2654,7 @@ export class PilotSwarmUiController {
2641
2654
  // state alone is judge which folders are still claimed, since the store
2642
2655
  // still holds the PREVIOUS membership at this point; the incoming rows
2643
2656
  // ride along on the action for exactly that.
2644
- let pendingGroupRows = null;
2645
- if (typeof this.transport.listSessionGroups === "function") {
2646
- try {
2647
- const groups = await this.transport.listSessionGroups();
2648
- pendingGroupRows = (Array.isArray(groups) ? groups : []).map(sessionGroupToRow).filter(Boolean);
2649
- } catch (error) {
2650
- console.warn(`[PilotSwarmUi] session-group fetch failed, keeping the known folders: ${error?.message || error}`);
2651
- }
2652
- }
2657
+ const pendingGroupRows = await groupRowsPromise;
2653
2658
  // A pending deep-link target may be readable but absent from the
2654
2659
  // paged catalog window — fetch it explicitly. A definitive failure
2655
2660
  // (unknown or unshared: identical 404 shapes) fails the intent; the
@@ -2753,6 +2758,8 @@ export class PilotSwarmUiController {
2753
2758
  if (!existingHistory?.events?.length) {
2754
2759
  await this.ensureSessionHistory(selected, { force: true }).catch(() => {});
2755
2760
  }
2761
+ if (this.getState().sessions.activeSessionId !== selected
2762
+ || this.navigationGeneration !== previousNavigationGeneration) return;
2756
2763
  // Boot-restore can hydrate the selection through THIS branch
2757
2764
  // instead of loadSession (whether the profile poll beats the first
2758
2765
  // sessions refresh is a race), so the canvas snapshot must be
@@ -2954,7 +2961,27 @@ export class PilotSwarmUiController {
2954
2961
  return history;
2955
2962
  }
2956
2963
 
2957
- async ensureSessionHistory(sessionId, { force = false } = {}) {
2964
+ async ensureSessionHistory(sessionId, options = {}) {
2965
+ if (!sessionId) return null;
2966
+ if (this.sessionHistoryLoads.has(sessionId)) return this.sessionHistoryLoads.get(sessionId);
2967
+ const existing = this.getState().history.bySessionId.get(sessionId);
2968
+ if (!options.force && existing?.events && existing?.loadState !== "failed") return existing;
2969
+ this.dispatch({ type: "history/loadState", sessionId, loadState: "loading" });
2970
+ const pending = this.loadSessionHistory(sessionId, { ...options, force: true });
2971
+ this.sessionHistoryLoads.set(sessionId, pending);
2972
+ try {
2973
+ const result = await pending;
2974
+ this.dispatch({ type: "history/loadState", sessionId, loadState: "loaded" });
2975
+ return result;
2976
+ } catch (error) {
2977
+ this.dispatch({ type: "history/loadState", sessionId, loadState: "failed" });
2978
+ throw error;
2979
+ } finally {
2980
+ if (this.sessionHistoryLoads.get(sessionId) === pending) this.sessionHistoryLoads.delete(sessionId);
2981
+ }
2982
+ }
2983
+
2984
+ async loadSessionHistory(sessionId, { force = false } = {}) {
2958
2985
  if (!sessionId) return null;
2959
2986
  const existingHistory = this.getState().history.bySessionId.get(sessionId);
2960
2987
  const requestedLimit = Math.min(
@@ -2967,9 +2994,6 @@ export class PilotSwarmUiController {
2967
2994
  if (!force && existingHistory?.events) {
2968
2995
  return existingHistory;
2969
2996
  }
2970
- if (!force && this.sessionHistoryLoads.has(sessionId)) {
2971
- return this.sessionHistoryLoads.get(sessionId);
2972
- }
2973
2997
 
2974
2998
  // Re-entry catch-up: when the expanded window is already in memory,
2975
2999
  // fetch only the delta after lastSeq and append — the user's pulled-in
@@ -3052,12 +3076,7 @@ export class PilotSwarmUiController {
3052
3076
  });
3053
3077
  }
3054
3078
  return history;
3055
- })()
3056
- .finally(() => {
3057
- this.sessionHistoryLoads.delete(sessionId);
3058
- });
3059
-
3060
- this.sessionHistoryLoads.set(sessionId, loadPromise);
3079
+ })();
3061
3080
  return loadPromise;
3062
3081
  }
3063
3082
 
@@ -5727,6 +5746,7 @@ export class PilotSwarmUiController {
5727
5746
 
5728
5747
  async loadSession(sessionId) {
5729
5748
  if (!sessionId) return;
5749
+ const navigationGeneration = this.navigationGeneration = (this.navigationGeneration || 0) + 1;
5730
5750
  const active = this.getState().sessions.activeSessionId;
5731
5751
  if (active !== sessionId) {
5732
5752
  if (this.getState().ui.promptEdit) {
@@ -5742,10 +5762,13 @@ export class PilotSwarmUiController {
5742
5762
  this.detachActiveSession();
5743
5763
  return;
5744
5764
  }
5745
- await this.ensureSessionHistory(sessionId, { force: true });
5746
- if (this.getState().sessions.activeSessionId !== sessionId) return;
5747
- await this.syncSessionDetail(sessionId).catch(() => {});
5748
- if (this.getState().sessions.activeSessionId !== sessionId) return;
5765
+ // Independent reads share one network-latency window. Cached chat stays visible.
5766
+ await Promise.all([
5767
+ this.ensureSessionHistory(sessionId, { force: true }),
5768
+ this.syncSessionDetail(sessionId).catch(() => {}),
5769
+ ]);
5770
+ if (this.navigationGeneration !== navigationGeneration
5771
+ || this.getState().sessions.activeSessionId !== sessionId) return;
5749
5772
  this.attachActiveSession(sessionId);
5750
5773
  this.ensureInspectorData().catch(() => {});
5751
5774
  // Canvas snapshot rides the selection burst. Invalidate-then-fetch on
@@ -1073,8 +1073,11 @@ function baseReducer(state, action) {
1073
1073
  state.sessions.navigationIntent
1074
1074
  && state.sessions.navigationIntent.status !== "failed",
1075
1075
  );
1076
+ // Saved selection is a boot preference. Once this tab navigates,
1077
+ // a slow profile read (or another device) must not navigate it back.
1076
1078
  const hasActive = Object.prototype.hasOwnProperty.call(settings, "activeSessionId")
1077
- && !navigationIntentLatched;
1079
+ && !navigationIntentLatched
1080
+ && !state.sessions.localSelectionMade;
1078
1081
  const hasLoadedSessions = Object.keys(state.sessions.byId || {}).length > 0;
1079
1082
  const nextLayout = hasLayout
1080
1083
  ? {
@@ -1889,7 +1892,7 @@ function baseReducer(state, action) {
1889
1892
  }
1890
1893
 
1891
1894
  case "sessions/selected": {
1892
- state = { ...state, sessions: { ...state.sessions, listDeselected: false } };
1895
+ state = { ...state, sessions: { ...state.sessions, listDeselected: false, localSelectionMade: true } };
1893
1896
  // Per-session chat scroll memory: stash both the outgoing offset
1894
1897
  // and whether it follows the bottom. A paused reading position
1895
1898
  // stays paused as new messages arrive and across session switches.
@@ -2192,6 +2195,17 @@ function baseReducer(state, action) {
2192
2195
  };
2193
2196
  }
2194
2197
 
2198
+ case "history/loadState": {
2199
+ // A gone-session response may already have evicted this entry.
2200
+ if (!state.sessions.byId[action.sessionId]) return state;
2201
+ const bySessionId = cloneHistoryMap(state.history.bySessionId);
2202
+ bySessionId.set(action.sessionId, {
2203
+ ...bySessionId.get(action.sessionId),
2204
+ loadState: action.loadState,
2205
+ });
2206
+ return { ...state, history: { ...state.history, bySessionId } };
2207
+ }
2208
+
2195
2209
  case "history/set": {
2196
2210
  const previousHistory = state.history.bySessionId.get(action.sessionId) || null;
2197
2211
  const previousChat = previousHistory?.chat || [];
@@ -2028,6 +2028,16 @@ export function selectActiveChat(state) {
2028
2028
  }
2029
2029
  const history = state.history.bySessionId.get(sessionId);
2030
2030
  const chat = history?.chat || [];
2031
+ if (!chat.length && ["loading", "failed"].includes(history?.loadState)) {
2032
+ return [{
2033
+ id: `history-load:${sessionId}:${history.loadState}`,
2034
+ role: "system",
2035
+ noChrome: true,
2036
+ text: history.loadState === "loading"
2037
+ ? "Loading conversation…"
2038
+ : "Could not load this conversation. Select the session again to retry.",
2039
+ }];
2040
+ }
2031
2041
  const events = history?.events || [];
2032
2042
  const pendingQuestionMessage = session?.pendingQuestion?.question
2033
2043
  && !chatAlreadyContainsPendingQuestion(chat, session.pendingQuestion.question)
@@ -14702,7 +14702,8 @@ export function PilotSwarmWebApp({ controller, suspended = false, moa = null })
14702
14702
  const profileSettingsSaveTimerRef = React.useRef(null);
14703
14703
  const profileSettingsPollTimerRef = React.useRef(null);
14704
14704
  const profileSettingsPollInFlightRef = React.useRef(false);
14705
- const profileSettingsSaveInFlightRef = React.useRef(false);
14705
+ const profileSettingsSaveInFlightRef = React.useRef(0);
14706
+ const profileSettingsEditRevisionRef = React.useRef(0);
14706
14707
  const appliedProfileSettingsJsonRef = React.useRef(null);
14707
14708
  const defaultProfileSettingsRef = React.useRef(null);
14708
14709
  const [mobilePane, setMobilePane] = React.useState("workspace");
@@ -14829,7 +14830,7 @@ export function PilotSwarmWebApp({ controller, suspended = false, moa = null })
14829
14830
  profileSettingsPollTimerRef.current = null;
14830
14831
  }
14831
14832
  profileSettingsPollInFlightRef.current = false;
14832
- profileSettingsSaveInFlightRef.current = false;
14833
+ profileSettingsSaveInFlightRef.current = 0;
14833
14834
 
14834
14835
  const transport = controller.transport;
14835
14836
  if (typeof transport?.getCurrentUserProfile !== "function"
@@ -14843,6 +14844,7 @@ export function PilotSwarmWebApp({ controller, suspended = false, moa = null })
14843
14844
  const pollProfileSettings = async () => {
14844
14845
  if (!active || profileSettingsPollInFlightRef.current) return;
14845
14846
  profileSettingsPollInFlightRef.current = true;
14847
+ const editRevision = profileSettingsEditRevisionRef.current;
14846
14848
  try {
14847
14849
  const profile = await transport.getCurrentUserProfile();
14848
14850
  if (!active) return;
@@ -14892,7 +14894,8 @@ export function PilotSwarmWebApp({ controller, suspended = false, moa = null })
14892
14894
  const hasUnpersistedLocalChange = profileSettingsHydratedRef.current
14893
14895
  && lastProfileSettingsJsonRef.current != null
14894
14896
  && currentSettingsBeforeApplyJson !== lastProfileSettingsJsonRef.current;
14895
- const hasPendingLocalWrite = Boolean(profileSettingsSaveTimerRef.current)
14897
+ const hasPendingLocalWrite = editRevision !== profileSettingsEditRevisionRef.current
14898
+ || Boolean(profileSettingsSaveTimerRef.current)
14896
14899
  || profileSettingsSaveInFlightRef.current
14897
14900
  || hasUnpersistedLocalChange
14898
14901
  || controller.getState().ui.moaDirty === true;
@@ -14968,12 +14971,13 @@ export function PilotSwarmWebApp({ controller, suspended = false, moa = null })
14968
14971
  const settingsJson = JSON.stringify(settings);
14969
14972
  if (lastProfileSettingsJsonRef.current === settingsJson) return undefined;
14970
14973
  lastProfileSettingsJsonRef.current = settingsJson;
14974
+ profileSettingsEditRevisionRef.current += 1;
14971
14975
  if (profileSettingsSaveTimerRef.current) {
14972
14976
  clearTimeout(profileSettingsSaveTimerRef.current);
14973
14977
  }
14974
14978
  profileSettingsSaveTimerRef.current = setTimeout(() => {
14975
14979
  profileSettingsSaveTimerRef.current = null;
14976
- profileSettingsSaveInFlightRef.current = true;
14980
+ profileSettingsSaveInFlightRef.current += 1;
14977
14981
  const moaRevision = controller.getState().ui.moaRevision;
14978
14982
  controller.dispatch({ type: "ui/moaSaveStatus", status: "saving" });
14979
14983
  saveProfileSettings(controller, settings)
@@ -14983,7 +14987,7 @@ export function PilotSwarmWebApp({ controller, suspended = false, moa = null })
14983
14987
  controller.dispatch({ type: "ui/moaSaveStatus", status: "error" });
14984
14988
  })
14985
14989
  .finally(() => {
14986
- profileSettingsSaveInFlightRef.current = false;
14990
+ profileSettingsSaveInFlightRef.current = Math.max(0, profileSettingsSaveInFlightRef.current - 1);
14987
14991
  });
14988
14992
  }, 400);
14989
14993
  return undefined;
@@ -1 +1 @@
1
- import{g as p,r as u,d as a}from"./chunk-MOJQB5TN-De76fp2s.js";import{p as f}from"./chunk-JWPE2WC7-BD-w4617.js";import{_ as n,l as o}from"./mermaid.core-CEMxYLqP.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-C-gW4wVJ.js";import"./pilotswarm-BJidJRMR.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-G6hkDffb.js";import{p as f}from"./chunk-JWPE2WC7-B9Qns4SI.js";import{_ as n,l as o}from"./mermaid.core-BPXpLhrQ.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-DRYxiNM0.js";import"./pilotswarm-t7ZSHp3x.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-CEMxYLqP.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-BPXpLhrQ.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};