pilotswarm 0.5.25 → 0.5.27
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.
- package/package.json +1 -1
- package/ui/core/src/controller.js +49 -4
- package/ui/core/src/selectors.js +52 -6
- package/ui/react/src/web-app.js +426 -80
- package/web/dist/assets/{abnfDiagram-VRR7QNED-C4qRR7va.js → abnfDiagram-VRR7QNED-DOZGtiQC.js} +1 -1
- package/web/dist/assets/{arc-BQw2V2pL.js → arc-CNT314TJ.js} +1 -1
- package/web/dist/assets/{architectureDiagram-ZJ3FMSHR-DMdWnLGG.js → architectureDiagram-ZJ3FMSHR-Cmi5R1em.js} +1 -1
- package/web/dist/assets/{blockDiagram-677ZJIJ3-DZnALw8j.js → blockDiagram-677ZJIJ3-CFQt6Pnc.js} +1 -1
- package/web/dist/assets/{c4Diagram-LMCZKHZV-BGGZ42iX.js → c4Diagram-LMCZKHZV-v7-eGb6Y.js} +1 -1
- package/web/dist/assets/channel-DHDU75Fc.js +1 -0
- package/web/dist/assets/{chunk-2Q5K7J3B-Dastiegd.js → chunk-2Q5K7J3B-DoLSc3k6.js} +1 -1
- package/web/dist/assets/{chunk-32BRIVSS-B4XexRzf.js → chunk-32BRIVSS-l-i2NvX3.js} +1 -1
- package/web/dist/assets/{chunk-5VM5RSS4-D66MNGCN.js → chunk-5VM5RSS4-B3s5kXyR.js} +1 -1
- package/web/dist/assets/{chunk-EX3LRPZG-DeqPS4Xm.js → chunk-EX3LRPZG-Ckctm_wZ.js} +1 -1
- package/web/dist/assets/{chunk-JWPE2WC7-DIMWiXpM.js → chunk-JWPE2WC7-D5reV4oK.js} +1 -1
- package/web/dist/assets/{chunk-MOJQB5TN-vTyL0qgx.js → chunk-MOJQB5TN-B-bgmTfa.js} +1 -1
- package/web/dist/assets/{chunk-RYQCIY6F-C7U9MKGw.js → chunk-RYQCIY6F-CLliUW3T.js} +1 -1
- package/web/dist/assets/{chunk-V7JOEXUC-BzPwQ7n3.js → chunk-V7JOEXUC-CsAyO1PL.js} +1 -1
- package/web/dist/assets/{chunk-VR4S4FIN-CmDsyK3b.js → chunk-VR4S4FIN-Df6VMLs3.js} +1 -1
- package/web/dist/assets/{chunk-XXDRQBXY-ZJn6BaGL.js → chunk-XXDRQBXY-pOkdkM00.js} +1 -1
- package/web/dist/assets/classDiagram-OUVF2IWQ-DkWfQ9TO.js +1 -0
- package/web/dist/assets/classDiagram-v2-EOCWNBFH-DkWfQ9TO.js +1 -0
- package/web/dist/assets/{cose-bilkent-JH36ORCC-CAA8JZZM.js → cose-bilkent-JH36ORCC-DF9LzGIn.js} +1 -1
- package/web/dist/assets/{cynefin-VYW2F7L2-B6pX-lUD.js → cynefin-VYW2F7L2-COwlV5eq.js} +1 -1
- package/web/dist/assets/{cynefinDiagram-TSTJHNR4-sKTHU_UH.js → cynefinDiagram-TSTJHNR4-Cmf8ISYO.js} +1 -1
- package/web/dist/assets/{dagre-VKFMJZFB-EuakJ578.js → dagre-VKFMJZFB-DanZ5sUs.js} +1 -1
- package/web/dist/assets/{diagram-FQU43EPY-DR3M_pic.js → diagram-FQU43EPY-xJWijzy7.js} +1 -1
- package/web/dist/assets/{diagram-G47NLZAW-BlS6yM0u.js → diagram-G47NLZAW-C2V1yOvV.js} +1 -1
- package/web/dist/assets/{diagram-NH7WQ7WH-CQNXe6dc.js → diagram-NH7WQ7WH-C8SrNQ_i.js} +1 -1
- package/web/dist/assets/{diagram-OA4YK3LP-BizBeSQo.js → diagram-OA4YK3LP-BATn2U0p.js} +1 -1
- package/web/dist/assets/{diagram-WEI45ONY-C-_KM6Gg.js → diagram-WEI45ONY-Dk1xkd8r.js} +1 -1
- package/web/dist/assets/{ebnfDiagram-CCIWWBDH-BapWEdic.js → ebnfDiagram-CCIWWBDH-JFfByguj.js} +1 -1
- package/web/dist/assets/{erDiagram-Q63AITRT-Btijn1Xj.js → erDiagram-Q63AITRT-DnlU9tGx.js} +1 -1
- package/web/dist/assets/{flowDiagram-23GEKE2U-D8zK8HkH.js → flowDiagram-23GEKE2U-Dnq_XrQ8.js} +1 -1
- package/web/dist/assets/{ganttDiagram-NO4QXBWP-DyjkOIMW.js → ganttDiagram-NO4QXBWP-MzgQ4Gkh.js} +1 -1
- package/web/dist/assets/{gitGraphDiagram-IHSO6WYX-3r9_QeYN.js → gitGraphDiagram-IHSO6WYX-C2LwEO5a.js} +1 -1
- package/web/dist/assets/{index-m0kBr7aj.js → index-BkjhSyx0.js} +2 -2
- package/web/dist/assets/{index-BEhdfIki.css → index-DyL_-2Du.css} +1 -1
- package/web/dist/assets/{infoDiagram-FWYZ7A6U-Ccd8ACUz.js → infoDiagram-FWYZ7A6U-UMiiYK4p.js} +1 -1
- package/web/dist/assets/{ishikawaDiagram-FXEZZL3T-DPRUC8V2.js → ishikawaDiagram-FXEZZL3T-CtzROVDb.js} +1 -1
- package/web/dist/assets/{journeyDiagram-5HDEW3XC-CkvayMsL.js → journeyDiagram-5HDEW3XC-C5UU06Ip.js} +1 -1
- package/web/dist/assets/{kanban-definition-HUTT4EX6-CAK9Z-ha.js → kanban-definition-HUTT4EX6-DYwJ4PpM.js} +1 -1
- package/web/dist/assets/{linear-B-_ZjN2w.js → linear-Dg7W_aPc.js} +1 -1
- package/web/dist/assets/{mermaid.core-BN9c--2r.js → mermaid.core-OUiCmXKB.js} +4 -4
- package/web/dist/assets/{mindmap-definition-LN4V7U3C-DuD_AHRU.js → mindmap-definition-LN4V7U3C-ffFo5mVE.js} +1 -1
- package/web/dist/assets/papaparse.min-DPfbFiel.js +10 -0
- package/web/dist/assets/{pegDiagram-2B236MQR-Cc1v58KA.js → pegDiagram-2B236MQR-DJ0r7gkW.js} +1 -1
- package/web/dist/assets/{pieDiagram-ENE6RG2P-Bc32--ur.js → pieDiagram-ENE6RG2P-BnpWDtAd.js} +1 -1
- package/web/dist/assets/pilotswarm-CU6jtK4w.js +94 -0
- package/web/dist/assets/{quadrantDiagram-ABIIQ3AL-DpPTc2EP.js → quadrantDiagram-ABIIQ3AL-Bcxo8lQJ.js} +1 -1
- package/web/dist/assets/{railroadDiagram-RFXS5EU6-DXMzwejw.js → railroadDiagram-RFXS5EU6-YtDm2Hhr.js} +1 -1
- package/web/dist/assets/{requirementDiagram-TGXJPOKE-B3ImAxw-.js → requirementDiagram-TGXJPOKE-DIIFSM-x.js} +1 -1
- package/web/dist/assets/{sankeyDiagram-HTMAVEWB-hmVMffE2.js → sankeyDiagram-HTMAVEWB-BH3EkrzA.js} +1 -1
- package/web/dist/assets/{sequenceDiagram-DBY2YBRQ-D53fk6uF.js → sequenceDiagram-DBY2YBRQ-DjD5j0HL.js} +1 -1
- package/web/dist/assets/{sizeCapture-X5ZJPWSS-4U-I5d2g.js → sizeCapture-X5ZJPWSS-L5FPJ9w8.js} +1 -1
- package/web/dist/assets/{stateDiagram-2N3HPSRC-0Y5TgWhW.js → stateDiagram-2N3HPSRC-o-MgnF-b.js} +1 -1
- package/web/dist/assets/stateDiagram-v2-6OUMAXLB-DkGZm6xe.js +1 -0
- package/web/dist/assets/{swimlanes-5IMT3BWC-Umhy4qUu.js → swimlanes-5IMT3BWC-B_7FbL2G.js} +2 -2
- package/web/dist/assets/swimlanesDiagram-G3AALYLV-D9vnXGSI.js +8 -0
- package/web/dist/assets/{timeline-definition-FHXFAJF6-D5hOg3Qu.js → timeline-definition-FHXFAJF6-C8qUL6LV.js} +1 -1
- package/web/dist/assets/{vennDiagram-L72KCM5P-QVIcE3UD.js → vennDiagram-L72KCM5P-wS-9VnAs.js} +1 -1
- package/web/dist/assets/{wardleyDiagram-EHGQE667-BEj1M2cB.js → wardleyDiagram-EHGQE667-Cz8fglhX.js} +1 -1
- package/web/dist/assets/{xychartDiagram-FW5EYKEG-xojRIXIf.js → xychartDiagram-FW5EYKEG-CmsR-UfQ.js} +1 -1
- package/web/dist/index.html +3 -3
- package/web/dist/assets/channel-CB157dQ5.js +0 -1
- package/web/dist/assets/classDiagram-OUVF2IWQ-B6JwBYlv.js +0 -1
- package/web/dist/assets/classDiagram-v2-EOCWNBFH-B6JwBYlv.js +0 -1
- package/web/dist/assets/pilotswarm-BgzdDy09.js +0 -93
- package/web/dist/assets/stateDiagram-v2-6OUMAXLB-DqIcGfAY.js +0 -1
- package/web/dist/assets/swimlanesDiagram-G3AALYLV-DA9txLi6.js +0 -8
package/package.json
CHANGED
|
@@ -1070,6 +1070,19 @@ function normalizePreviewPayload(filename, rawContent, contentType = "", metadat
|
|
|
1070
1070
|
|
|
1071
1071
|
/** How long a fetched artifact list is trusted before a refetch. */
|
|
1072
1072
|
const FILES_LIST_TTL_MS = 10_000;
|
|
1073
|
+
// How long keyboard navigation must rest on a session before it is fetched.
|
|
1074
|
+
// Long enough that scrolling past a row costs nothing, short enough that
|
|
1075
|
+
// landing on one feels immediate.
|
|
1076
|
+
const SESSION_NAV_SETTLE_MS = 140;
|
|
1077
|
+
// Ceiling on the window a session re-opens with, in events (5 history pages).
|
|
1078
|
+
//
|
|
1079
|
+
// `loadedEventLimit` is sticky: scrolling back through a long session escalates
|
|
1080
|
+
// it 300 -> 1000 -> 3000 -> 10000, and ensureSessionHistory then re-requested
|
|
1081
|
+
// that expanded size on EVERY switch-in, for the life of the tab. So one trip
|
|
1082
|
+
// through the history of a busy session made it permanently expensive to open —
|
|
1083
|
+
// 10k events re-fetched, re-derived and re-laid-out each time. Paging back
|
|
1084
|
+
// still expands freely while you are in the session; re-entering starts bounded.
|
|
1085
|
+
const HISTORY_REENTRY_MAX_EVENTS = 1_500;
|
|
1073
1086
|
|
|
1074
1087
|
export class PilotSwarmUiController {
|
|
1075
1088
|
constructor({ store, transport }) {
|
|
@@ -2292,9 +2305,12 @@ export class PilotSwarmUiController {
|
|
|
2292
2305
|
async ensureSessionHistory(sessionId, { force = false } = {}) {
|
|
2293
2306
|
if (!sessionId) return null;
|
|
2294
2307
|
const existingHistory = this.getState().history.bySessionId.get(sessionId);
|
|
2295
|
-
const requestedLimit = Math.
|
|
2296
|
-
|
|
2297
|
-
|
|
2308
|
+
const requestedLimit = Math.min(
|
|
2309
|
+
HISTORY_REENTRY_MAX_EVENTS,
|
|
2310
|
+
Math.max(
|
|
2311
|
+
DEFAULT_HISTORY_EVENT_LIMIT,
|
|
2312
|
+
Number(existingHistory?.loadedEventLimit ?? DEFAULT_HISTORY_EVENT_LIMIT) || DEFAULT_HISTORY_EVENT_LIMIT,
|
|
2313
|
+
),
|
|
2298
2314
|
);
|
|
2299
2315
|
if (!force && existingHistory?.events) {
|
|
2300
2316
|
return existingHistory;
|
|
@@ -6140,7 +6156,36 @@ export class PilotSwarmUiController {
|
|
|
6140
6156
|
const currentIndex = Math.max(0, rows.findIndex((row) => row.sessionId === currentId));
|
|
6141
6157
|
const nextIndex = Math.max(0, Math.min(rows.length - 1, currentIndex + delta));
|
|
6142
6158
|
const nextId = rows[nextIndex].sessionId;
|
|
6143
|
-
|
|
6159
|
+
this.navigateToSession(nextId);
|
|
6160
|
+
}
|
|
6161
|
+
|
|
6162
|
+
/**
|
|
6163
|
+
* Move the selection now; fetch the session once the movement settles.
|
|
6164
|
+
*
|
|
6165
|
+
* `loadSession` force-refetches history, syncs detail, re-attaches the live
|
|
6166
|
+
* event stream and refreshes the inspector — four round trips. Driving that
|
|
6167
|
+
* from every keypress meant scrolling a list of sessions fired a request
|
|
6168
|
+
* pair per row, and against a remote deployment the UI ran behind the
|
|
6169
|
+
* cursor by however long the network took. The highlight is local state and
|
|
6170
|
+
* moves immediately; only the fetching waits for the user to stop.
|
|
6171
|
+
*
|
|
6172
|
+
* A CLICK still loads immediately — that is a deliberate choice of one
|
|
6173
|
+
* session, not a scroll through many.
|
|
6174
|
+
*/
|
|
6175
|
+
navigateToSession(sessionId) {
|
|
6176
|
+
if (!sessionId) return;
|
|
6177
|
+
if (this.getState().sessions.activeSessionId !== sessionId) {
|
|
6178
|
+
this.dispatch({ type: "sessions/selected", sessionId });
|
|
6179
|
+
// Same per-session reset loadSession does, so the sequence tab does
|
|
6180
|
+
// not show another session's turn while the fetch is pending.
|
|
6181
|
+
this.dispatch({ type: "ui/sequenceExpandedTurns", turns: [] });
|
|
6182
|
+
this.dispatch({ type: "ui/sequenceSelectedTurn", turn: null });
|
|
6183
|
+
}
|
|
6184
|
+
if (this.sessionNavSettleTimer) clearTimeout(this.sessionNavSettleTimer);
|
|
6185
|
+
this.sessionNavSettleTimer = setTimeout(() => {
|
|
6186
|
+
this.sessionNavSettleTimer = null;
|
|
6187
|
+
this.loadSession(sessionId).catch(() => {});
|
|
6188
|
+
}, SESSION_NAV_SETTLE_MS);
|
|
6144
6189
|
}
|
|
6145
6190
|
|
|
6146
6191
|
getSessionPageSize() {
|
package/ui/core/src/selectors.js
CHANGED
|
@@ -509,7 +509,7 @@ function getCollapseBadge(sessionId, entry, totalDescendantCounts, visibleDescen
|
|
|
509
509
|
return { text: `[+${badgeCount}]`, color: "cyan" };
|
|
510
510
|
}
|
|
511
511
|
|
|
512
|
-
function formatCronTimestampForClient(value) {
|
|
512
|
+
export function formatCronTimestampForClient(value) {
|
|
513
513
|
if (!value) return "scheduled";
|
|
514
514
|
const date = value instanceof Date ? value : new Date(value);
|
|
515
515
|
if (Number.isNaN(date.getTime())) return "scheduled";
|
|
@@ -771,6 +771,14 @@ function buildSessionRowView(entry, session, state, totalDescendantCounts, visib
|
|
|
771
771
|
badgeRuns: [],
|
|
772
772
|
selectedMetaRuns: detailRuns,
|
|
773
773
|
detailRuns,
|
|
774
|
+
// Total descendants, for renderers that want the real number rather
|
|
775
|
+
// than the collapse badge (which counts only HIDDEN children, so it is
|
|
776
|
+
// null whenever the subtree is expanded).
|
|
777
|
+
// NOTE: `detailRuns` above computes its own childCount by indexing this
|
|
778
|
+
// Map with brackets, which always yields undefined — so its "N children"
|
|
779
|
+
// segment has never rendered. Left alone deliberately: fixing it would
|
|
780
|
+
// change TUI and mobile output.
|
|
781
|
+
childCount: totalDescendantCounts?.get?.(session?.sessionId) || 0,
|
|
774
782
|
// Structured row description for renderers that draw real chrome
|
|
775
783
|
// instead of terminal runs (the portal's rich session list): status
|
|
776
784
|
// becomes a dot, depth becomes indentation, the owner/child/cron
|
|
@@ -840,6 +848,23 @@ function collectFilterExceptionIds(sessions) {
|
|
|
840
848
|
return ids;
|
|
841
849
|
}
|
|
842
850
|
|
|
851
|
+
// Per-row memo, keyed by the `flat` list so it survives selection changes but
|
|
852
|
+
// resets whenever the tree itself is rebuilt.
|
|
853
|
+
//
|
|
854
|
+
// WHY: moving the selection re-runs this selector (once from moveSession, once
|
|
855
|
+
// from the portal's useMemo) and used to rebuild EVERY row — including
|
|
856
|
+
// flattenRunsText over each row's runs — to change one boolean on two of them.
|
|
857
|
+
// At fleet scale that is the cost of a keypress. Now only rows whose inputs
|
|
858
|
+
// actually moved are rebuilt, and the rest keep their previous object
|
|
859
|
+
// identity, which also lets the renderer skip them.
|
|
860
|
+
const sessionRowMemo = new WeakMap();
|
|
861
|
+
|
|
862
|
+
function sameRowDeps(a, b) {
|
|
863
|
+
if (!a || a.length !== b.length) return false;
|
|
864
|
+
for (let i = 0; i < a.length; i += 1) if (a[i] !== b[i]) return false;
|
|
865
|
+
return true;
|
|
866
|
+
}
|
|
867
|
+
|
|
843
868
|
export function selectSessionRows(state) {
|
|
844
869
|
const totalDescendantCounts = getTotalDescendantCounts(state.sessions.byId);
|
|
845
870
|
const visibleDescendantCounts = getVisibleDescendantCounts(state.sessions.flat, state.sessions.byId);
|
|
@@ -850,25 +875,46 @@ export function selectSessionRows(state) {
|
|
|
850
875
|
const selectedSet = new Set(Array.isArray(state.sessions?.selectedIds) ? state.sessions.selectedIds : []);
|
|
851
876
|
const filterExceptionIds = collectFilterExceptionIds(state.sessions);
|
|
852
877
|
|
|
878
|
+
let memo = sessionRowMemo.get(state.sessions.flat);
|
|
879
|
+
if (!memo) {
|
|
880
|
+
memo = new Map();
|
|
881
|
+
sessionRowMemo.set(state.sessions.flat, memo);
|
|
882
|
+
}
|
|
883
|
+
|
|
853
884
|
return state.sessions.flat.map((entry) => {
|
|
854
885
|
const session = state.sessions.byId[entry.sessionId];
|
|
886
|
+
const active = entry.sessionId === state.sessions.activeSessionId;
|
|
887
|
+
const pinned = pinnedSet.has(entry.sessionId);
|
|
888
|
+
const selected = selectedSet.has(entry.sessionId);
|
|
889
|
+
// Every input the row below is derived from. Identity comparison is
|
|
890
|
+
// enough: the reducer replaces these objects rather than mutating them.
|
|
891
|
+
const deps = [
|
|
892
|
+
entry, session, active, pinned, selected, query, ownerFilter, auth,
|
|
893
|
+
state.connection?.mode, state.sessions.selectMode,
|
|
894
|
+
totalDescendantCounts, visibleDescendantCounts,
|
|
895
|
+
];
|
|
896
|
+
const cached = memo.get(entry.sessionId);
|
|
897
|
+
if (cached && sameRowDeps(cached.deps, deps)) return cached.row;
|
|
898
|
+
|
|
855
899
|
const rowView = buildSessionRowView(entry, session, state, totalDescendantCounts, visibleDescendantCounts);
|
|
856
|
-
|
|
900
|
+
const row = {
|
|
857
901
|
sessionId: entry.sessionId,
|
|
858
902
|
text: flattenRunsText(rowView.runs),
|
|
859
903
|
...rowView,
|
|
860
904
|
depth: entry.depth,
|
|
861
905
|
status: session?.status,
|
|
862
906
|
statusColor: sessionStatusColor(session, state.connection?.mode || "local"),
|
|
863
|
-
active
|
|
907
|
+
active,
|
|
864
908
|
isSystem: Boolean(session?.isSystem),
|
|
865
909
|
isGroup: Boolean(session?.isGroup),
|
|
866
910
|
hasChildren: entry.hasChildren,
|
|
867
911
|
collapsed: entry.collapsed,
|
|
868
|
-
pinned
|
|
869
|
-
selected
|
|
912
|
+
pinned,
|
|
913
|
+
selected,
|
|
870
914
|
canPin: canPinSessionRow(session),
|
|
871
915
|
};
|
|
916
|
+
memo.set(entry.sessionId, { deps, row });
|
|
917
|
+
return row;
|
|
872
918
|
}).filter((row) => {
|
|
873
919
|
if (filterExceptionIds?.has(row.sessionId)) return true;
|
|
874
920
|
const session = state.sessions.byId[row.sessionId];
|
|
@@ -5320,7 +5366,7 @@ export function selectArtifactPickerModal(state, maxWidth = 88) {
|
|
|
5320
5366
|
|
|
5321
5367
|
// ── Stats Inspector Pane ────────────────────────────────────────────
|
|
5322
5368
|
|
|
5323
|
-
function formatCompactNumber(n) {
|
|
5369
|
+
export function formatCompactNumber(n) {
|
|
5324
5370
|
if (n == null || !Number.isFinite(n)) return "0";
|
|
5325
5371
|
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
|
|
5326
5372
|
if (n >= 10_000) return `${(n / 1_000).toFixed(1)}K`;
|