pilotswarm 0.5.76 → 0.5.78
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 +2 -2
- package/tui/src/embedded-workers.js +3 -0
- package/ui/core/src/controller.js +4 -1
- package/ui/react/src/web-app.js +171 -90
- package/web/dist/assets/{abnfDiagram-VRR7QNED-DHZAKybB.js → abnfDiagram-VRR7QNED-C2HGSvvf.js} +1 -1
- package/web/dist/assets/{arc-Bw0S8L-3.js → arc-C3faoYvN.js} +1 -1
- package/web/dist/assets/{architectureDiagram-ZJ3FMSHR-CIdYlIBv.js → architectureDiagram-ZJ3FMSHR-CQhrAa5t.js} +1 -1
- package/web/dist/assets/{blockDiagram-677ZJIJ3-D9PkQfSJ.js → blockDiagram-677ZJIJ3-CVGwBieB.js} +1 -1
- package/web/dist/assets/{c4Diagram-LMCZKHZV-D9YbJQu6.js → c4Diagram-LMCZKHZV-CmdrEA77.js} +1 -1
- package/web/dist/assets/channel-CTmDTaW4.js +1 -0
- package/web/dist/assets/{chunk-2Q5K7J3B-BTdwvy5p.js → chunk-2Q5K7J3B-Bm1hu4Hq.js} +1 -1
- package/web/dist/assets/{chunk-32BRIVSS--ow0RNjy.js → chunk-32BRIVSS--_hODe_V.js} +1 -1
- package/web/dist/assets/{chunk-5VM5RSS4-DXsS8QVF.js → chunk-5VM5RSS4-COI5t4m6.js} +1 -1
- package/web/dist/assets/{chunk-EX3LRPZG-HKSF2xwD.js → chunk-EX3LRPZG-BCFKy6tL.js} +1 -1
- package/web/dist/assets/{chunk-JWPE2WC7-DY6_m3mf.js → chunk-JWPE2WC7-Ddh7J2Rp.js} +1 -1
- package/web/dist/assets/{chunk-MOJQB5TN-B-y9e9g1.js → chunk-MOJQB5TN-DuIGV22R.js} +1 -1
- package/web/dist/assets/{chunk-RYQCIY6F-UK1vqINl.js → chunk-RYQCIY6F-BNQbAlZV.js} +1 -1
- package/web/dist/assets/{chunk-V7JOEXUC-8KQ7DOjY.js → chunk-V7JOEXUC-DmoLjQx9.js} +1 -1
- package/web/dist/assets/{chunk-VR4S4FIN-CkDJLoRb.js → chunk-VR4S4FIN-BTOlqom4.js} +1 -1
- package/web/dist/assets/{chunk-XXDRQBXY-DrvpqdcI.js → chunk-XXDRQBXY-DTsc-Dgs.js} +1 -1
- package/web/dist/assets/classDiagram-OUVF2IWQ-0JetCpCm.js +1 -0
- package/web/dist/assets/classDiagram-v2-EOCWNBFH-0JetCpCm.js +1 -0
- package/web/dist/assets/{cose-bilkent-JH36ORCC-BZimjiO7.js → cose-bilkent-JH36ORCC-QEqZLCny.js} +1 -1
- package/web/dist/assets/{cynefin-VYW2F7L2-DgXpH0xt.js → cynefin-VYW2F7L2-Deleul8f.js} +1 -1
- package/web/dist/assets/{cynefinDiagram-TSTJHNR4-GhvhOnjl.js → cynefinDiagram-TSTJHNR4-D0HrNQd4.js} +1 -1
- package/web/dist/assets/{dagre-VKFMJZFB-_likmiuO.js → dagre-VKFMJZFB-CLdKXtyZ.js} +1 -1
- package/web/dist/assets/{diagram-FQU43EPY-DQctGbIk.js → diagram-FQU43EPY-C0DnCIiG.js} +1 -1
- package/web/dist/assets/{diagram-G47NLZAW-FVvT1dxp.js → diagram-G47NLZAW-DzQa8iDK.js} +1 -1
- package/web/dist/assets/{diagram-NH7WQ7WH-Xg1HHD3c.js → diagram-NH7WQ7WH-CazRIZg4.js} +1 -1
- package/web/dist/assets/{diagram-OA4YK3LP-BcQiRMrv.js → diagram-OA4YK3LP-gZanfxjg.js} +1 -1
- package/web/dist/assets/{diagram-WEI45ONY-PB48iGxu.js → diagram-WEI45ONY-CHoHyTz-.js} +1 -1
- package/web/dist/assets/{ebnfDiagram-CCIWWBDH-Cl3gvgL7.js → ebnfDiagram-CCIWWBDH-CeHz2Jh9.js} +1 -1
- package/web/dist/assets/{erDiagram-Q63AITRT-BqTsMK1r.js → erDiagram-Q63AITRT-C95MErio.js} +1 -1
- package/web/dist/assets/{flowDiagram-23GEKE2U-Defo8220.js → flowDiagram-23GEKE2U-AdgXiTao.js} +1 -1
- package/web/dist/assets/{ganttDiagram-NO4QXBWP-BNS92EuV.js → ganttDiagram-NO4QXBWP-D7Ltt8Pp.js} +1 -1
- package/web/dist/assets/{gitGraphDiagram-IHSO6WYX-BY0WUkLV.js → gitGraphDiagram-IHSO6WYX-9Xi-xmei.js} +1 -1
- package/web/dist/assets/index-C7_15DMS.css +1 -0
- package/web/dist/assets/index-IxnOJbWb.js +24 -0
- package/web/dist/assets/{infoDiagram-FWYZ7A6U-DAslesLk.js → infoDiagram-FWYZ7A6U-fRlxZHtD.js} +1 -1
- package/web/dist/assets/{ishikawaDiagram-FXEZZL3T-DRqAlMhQ.js → ishikawaDiagram-FXEZZL3T-CEVSVKfj.js} +1 -1
- package/web/dist/assets/{journeyDiagram-5HDEW3XC-cZgLClOz.js → journeyDiagram-5HDEW3XC-CJhad1Ay.js} +1 -1
- package/web/dist/assets/{kanban-definition-HUTT4EX6-CE-eXw4K.js → kanban-definition-HUTT4EX6-CE6OFSTa.js} +1 -1
- package/web/dist/assets/{linear-CZiOQoKS.js → linear-BuexMwfW.js} +1 -1
- package/web/dist/assets/{mermaid.core-AH4mlith.js → mermaid.core-DWYsDHXh.js} +4 -4
- package/web/dist/assets/{mindmap-definition-LN4V7U3C-BNghnDqd.js → mindmap-definition-LN4V7U3C-6_lFebqE.js} +1 -1
- package/web/dist/assets/{papaparse.min-DVijrOyx.js → papaparse.min-DjlrGi59.js} +1 -1
- package/web/dist/assets/{pegDiagram-2B236MQR-DoRp-9Zp.js → pegDiagram-2B236MQR-B1fuWjDp.js} +1 -1
- package/web/dist/assets/{pieDiagram-ENE6RG2P-H2Em8U8J.js → pieDiagram-ENE6RG2P-BWsDDxls.js} +1 -1
- package/web/dist/assets/pilotswarm-3GsGwA3r.js +109 -0
- package/web/dist/assets/{quadrantDiagram-ABIIQ3AL-CvUqxqnx.js → quadrantDiagram-ABIIQ3AL-CxzBQxBX.js} +1 -1
- package/web/dist/assets/{railroadDiagram-RFXS5EU6-tQwCHxpV.js → railroadDiagram-RFXS5EU6-Coqs5FXi.js} +1 -1
- package/web/dist/assets/{requirementDiagram-TGXJPOKE-D2wuvVrI.js → requirementDiagram-TGXJPOKE-v1GaofBK.js} +1 -1
- package/web/dist/assets/{sankeyDiagram-HTMAVEWB-C4r0hO5k.js → sankeyDiagram-HTMAVEWB-DGaKjdrZ.js} +1 -1
- package/web/dist/assets/{sequenceDiagram-DBY2YBRQ-DCdGwm9a.js → sequenceDiagram-DBY2YBRQ-UD5oqT-Q.js} +1 -1
- package/web/dist/assets/{sizeCapture-X5ZJPWSS-BjRhMoeP.js → sizeCapture-X5ZJPWSS-ClCMN9Ry.js} +1 -1
- package/web/dist/assets/{stateDiagram-2N3HPSRC-biMUw9ek.js → stateDiagram-2N3HPSRC-CU96VzpK.js} +1 -1
- package/web/dist/assets/stateDiagram-v2-6OUMAXLB-TNMXnnTc.js +1 -0
- package/web/dist/assets/{swimlanes-5IMT3BWC-BItVHm4_.js → swimlanes-5IMT3BWC-5pw00Cr8.js} +2 -2
- package/web/dist/assets/swimlanesDiagram-G3AALYLV-BOvR3DN_.js +8 -0
- package/web/dist/assets/{timeline-definition-FHXFAJF6-CC39ef73.js → timeline-definition-FHXFAJF6-Dfd6fPWH.js} +1 -1
- package/web/dist/assets/{vennDiagram-L72KCM5P-BgmPqz-h.js → vennDiagram-L72KCM5P-CaJB0ZOh.js} +1 -1
- package/web/dist/assets/{wardleyDiagram-EHGQE667-DRNFO87H.js → wardleyDiagram-EHGQE667-Cau_Q6Bk.js} +1 -1
- package/web/dist/assets/{xychartDiagram-FW5EYKEG-D_VfxQSu.js → xychartDiagram-FW5EYKEG-DTUEy024.js} +1 -1
- package/web/dist/index.html +3 -3
- package/web/dist/assets/channel-g-BbN7P5.js +0 -1
- package/web/dist/assets/classDiagram-OUVF2IWQ-BFAQi-H9.js +0 -1
- package/web/dist/assets/classDiagram-v2-EOCWNBFH-BFAQi-H9.js +0 -1
- package/web/dist/assets/index-CSMHeAhZ.css +0 -1
- package/web/dist/assets/index-Q9Y44qRk.js +0 -24
- package/web/dist/assets/pilotswarm-CN9fLEV0.js +0 -109
- package/web/dist/assets/stateDiagram-v2-6OUMAXLB-Dv--LJTg.js +0 -1
- package/web/dist/assets/swimlanesDiagram-G3AALYLV-CEULUMiK.js +0 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pilotswarm",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.78",
|
|
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.
|
|
84
|
+
"pilotswarm-sdk": "0.5.78",
|
|
85
85
|
"react": "^19.2.4",
|
|
86
86
|
"react-dom": "^19.2.4",
|
|
87
87
|
"ws": "^8.18.2"
|
|
@@ -44,6 +44,9 @@ export async function startEmbeddedWorkers({ count, store }) {
|
|
|
44
44
|
useManagedIdentity: ["1", "true", "yes", "on"].includes(
|
|
45
45
|
(process.env.PILOTSWARM_USE_MANAGED_IDENTITY || "").trim().toLowerCase(),
|
|
46
46
|
),
|
|
47
|
+
blobUseManagedIdentity: process.env.PILOTSWARM_BLOB_USE_MANAGED_IDENTITY?.trim()
|
|
48
|
+
? ["1", "true", "yes", "on"].includes(process.env.PILOTSWARM_BLOB_USE_MANAGED_IDENTITY.trim().toLowerCase())
|
|
49
|
+
: undefined,
|
|
47
50
|
cmsFactsDatabaseUrl: process.env.PILOTSWARM_CMS_FACTS_DATABASE_URL || undefined,
|
|
48
51
|
aadDbUser: process.env.PILOTSWARM_DB_AAD_USER || undefined,
|
|
49
52
|
blobAccountUrl: process.env.AZURE_STORAGE_ACCOUNT_URL || undefined,
|
|
@@ -9698,6 +9698,7 @@ export class PilotSwarmUiController {
|
|
|
9698
9698
|
await this.maybeAutoExpandActiveHistory(requestedScrollOffset, {
|
|
9699
9699
|
pages: AUTO_HISTORY_SCROLL_PAGE_COUNT,
|
|
9700
9700
|
preserveDomAnchor: options.preserveDomAnchor === true,
|
|
9701
|
+
onLoadStarted: options.onLoadStarted,
|
|
9701
9702
|
// Always bypass the offset gate. Every caller of this method fires
|
|
9702
9703
|
// only when the DOM scroller is already AT the top — a direct
|
|
9703
9704
|
// measurement. The gate is a second, weaker guess that compares a
|
|
@@ -10035,7 +10036,7 @@ export class PilotSwarmUiController {
|
|
|
10035
10036
|
if (targetOffset < maxOffset) return;
|
|
10036
10037
|
}
|
|
10037
10038
|
|
|
10038
|
-
|
|
10039
|
+
const load = this.expandSessionHistory(sessionId, {
|
|
10039
10040
|
requestedScrollOffset: targetOffset,
|
|
10040
10041
|
autoTriggered: true,
|
|
10041
10042
|
pages: options.pages,
|
|
@@ -10044,6 +10045,8 @@ export class PilotSwarmUiController {
|
|
|
10044
10045
|
// only, so each page is transcript instead of raw event noise.
|
|
10045
10046
|
eventTypes: CHAT_HISTORY_EVENT_TYPES,
|
|
10046
10047
|
});
|
|
10048
|
+
options.onLoadStarted?.();
|
|
10049
|
+
await load;
|
|
10047
10050
|
}
|
|
10048
10051
|
|
|
10049
10052
|
async expandSessionHistory(sessionId, options = {}) {
|
package/ui/react/src/web-app.js
CHANGED
|
@@ -94,7 +94,8 @@ const SCROLL_BOTTOM_EPSILON_PX = 0.5;
|
|
|
94
94
|
const PROGRAMMATIC_SCROLL_TOLERANCE_PX = SCROLL_BOTTOM_EPSILON_PX;
|
|
95
95
|
// Minimum downward finger travel (px) while at the top of the chat pane before
|
|
96
96
|
// a touch pull counts as a load-older-history request.
|
|
97
|
-
const TOUCH_TOP_PULL_THRESHOLD_PX =
|
|
97
|
+
const TOUCH_TOP_PULL_THRESHOLD_PX = 56;
|
|
98
|
+
const TOUCH_TOP_PULL_MAX_PX = 84;
|
|
98
99
|
// How long after the last user-driven scroll event the pane still counts as
|
|
99
100
|
// momentum-scrolling (native flick glide), during which programmatic scrollTop
|
|
100
101
|
// restores are suppressed so they don't kill the glide.
|
|
@@ -1107,7 +1108,24 @@ function scrollBoundaryIdentity(lines, fromEnd = false) {
|
|
|
1107
1108
|
return boundary.map(scrollLineIdentity).join("\u241e");
|
|
1108
1109
|
}
|
|
1109
1110
|
|
|
1110
|
-
|
|
1111
|
+
// History loading belongs to the outer transcript. Let a tool result, activity
|
|
1112
|
+
// log or agent update consume the gesture first when it still has room.
|
|
1113
|
+
function nestedViewportCanScroll(viewport, target, deltaY) {
|
|
1114
|
+
if (!deltaY) return false;
|
|
1115
|
+
for (let node = target?.nodeType === 1 ? target : target?.parentElement;
|
|
1116
|
+
node && node !== viewport; node = node.parentElement) {
|
|
1117
|
+
const maxScroll = node.scrollHeight - node.clientHeight;
|
|
1118
|
+
if (maxScroll <= 1 || !/^(auto|scroll)$/.test(getComputedStyle(node).overflowY)) continue;
|
|
1119
|
+
if (deltaY < 0 ? node.scrollTop > 1 : node.scrollTop < maxScroll - 1) return true;
|
|
1120
|
+
}
|
|
1121
|
+
return false;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller, {
|
|
1125
|
+
stickyBottom = false,
|
|
1126
|
+
historyPullEnabled = false,
|
|
1127
|
+
historySessionId = null,
|
|
1128
|
+
} = {}) {
|
|
1111
1129
|
const normalizedLines = React.useMemo(() => normalizeLines(lines), [lines]);
|
|
1112
1130
|
// Programmatic scrollTop assignments fire a 'scroll' event that would
|
|
1113
1131
|
// otherwise call onScroll → dispatch ui/scroll → clobber the user's
|
|
@@ -1122,6 +1140,9 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
|
|
|
1122
1140
|
const previousContentRef = React.useRef(null);
|
|
1123
1141
|
const historyScrollRef = React.useRef(null);
|
|
1124
1142
|
React.useEffect(() => () => { historyScrollRef.current = null; }, []);
|
|
1143
|
+
const [topPullDistance, setTopPullDistance] = React.useState(0);
|
|
1144
|
+
const [loadingHistorySessionId, setLoadingHistorySessionId] = React.useState(null);
|
|
1145
|
+
React.useEffect(() => { setTopPullDistance(0); }, [historySessionId]);
|
|
1125
1146
|
// Touch scrolling relies on native momentum for speed: a hard flick keeps
|
|
1126
1147
|
// scrolling long after the finger lifts. Re-asserting scrollTop from state
|
|
1127
1148
|
// on every render (live events, status updates) kills that momentum at the
|
|
@@ -1309,7 +1330,7 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
|
|
|
1309
1330
|
const node = ref.current;
|
|
1310
1331
|
const state = controller.getState();
|
|
1311
1332
|
const sessionId = state.sessions.activeSessionId;
|
|
1312
|
-
if (!node || !sessionId || historyScrollRef.current) return;
|
|
1333
|
+
if (!node || !sessionId || !historyPullEnabled || historyScrollRef.current) return;
|
|
1313
1334
|
const top = node.getBoundingClientRect().top;
|
|
1314
1335
|
const element = [...node.children].find(child => child.textContent?.trim() && child.getBoundingClientRect().bottom > top + 6);
|
|
1315
1336
|
const pending = {
|
|
@@ -1320,19 +1341,22 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
|
|
|
1320
1341
|
historyScrollRef.current = pending;
|
|
1321
1342
|
const load = controller.handleChatTopHistoryScrollIntent?.(
|
|
1322
1343
|
(node.scrollHeight - node.clientHeight) / SCROLL_ROW_HEIGHT,
|
|
1323
|
-
{ force: true, preserveDomAnchor: true
|
|
1344
|
+
{ force: true, preserveDomAnchor: true,
|
|
1345
|
+
onLoadStarted: () => setLoadingHistorySessionId(sessionId) },
|
|
1324
1346
|
);
|
|
1325
1347
|
Promise.resolve(load).catch(() => {}).finally(() => {
|
|
1348
|
+
setLoadingHistorySessionId(current => current === sessionId ? null : current);
|
|
1326
1349
|
if (historyScrollRef.current !== pending) return;
|
|
1327
1350
|
const oldest = controller.getState().history.bySessionId.get(sessionId)?.events?.[0]?.seq;
|
|
1328
1351
|
if (!(oldest < pending.oldestSeq)) historyScrollRef.current = null;
|
|
1329
1352
|
else setViewportRevision(revision => revision + 1);
|
|
1330
1353
|
});
|
|
1331
|
-
}, [controller, ref]);
|
|
1354
|
+
}, [controller, historyPullEnabled, ref]);
|
|
1332
1355
|
|
|
1333
1356
|
const onWheel = React.useCallback((event) => {
|
|
1334
1357
|
const node = ref.current;
|
|
1335
1358
|
if (!node || paneKey !== "chat" || !event.deltaY || event.ctrlKey) return;
|
|
1359
|
+
if (nestedViewportCanScroll(node, event.target, event.deltaY)) return;
|
|
1336
1360
|
const pending = historyScrollRef.current;
|
|
1337
1361
|
if (pending && event.deltaY > 0) historyScrollRef.current = null;
|
|
1338
1362
|
else if (pending) {
|
|
@@ -1354,13 +1378,19 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
|
|
|
1354
1378
|
// scroll events either — so mobile had no way to request older history.
|
|
1355
1379
|
// A downward pull that starts while the pane is at (or near) the top fires
|
|
1356
1380
|
// the same top-history intent, once per gesture.
|
|
1357
|
-
const touchPullRef = React.useRef({ startY: null,
|
|
1381
|
+
const touchPullRef = React.useRef({ startY: null, lastY: null, distance: 0 });
|
|
1358
1382
|
const onTouchStart = React.useCallback((event) => {
|
|
1359
1383
|
userScrollRef.current.touching = true;
|
|
1360
1384
|
if (historyScrollRef.current?.applied) historyScrollRef.current = null;
|
|
1361
|
-
|
|
1362
|
-
touchPullRef.current = {
|
|
1363
|
-
|
|
1385
|
+
const node = ref.current;
|
|
1386
|
+
touchPullRef.current = {
|
|
1387
|
+
startY: event.touches?.length === 1 && historyPullEnabled && loadingHistorySessionId !== historySessionId
|
|
1388
|
+
&& paneKey === "chat" && node?.scrollTop <= PROGRAMMATIC_SCROLL_TOLERANCE_PX
|
|
1389
|
+
? event.touches?.[0]?.clientY ?? null : null,
|
|
1390
|
+
lastY: event.touches?.[0]?.clientY ?? null,
|
|
1391
|
+
distance: 0,
|
|
1392
|
+
};
|
|
1393
|
+
}, [historyPullEnabled, historySessionId, loadingHistorySessionId, paneKey, ref]);
|
|
1364
1394
|
const onTouchEnd = React.useCallback(() => {
|
|
1365
1395
|
userScrollRef.current.touching = false;
|
|
1366
1396
|
// Momentum continues past the finger lift; onScroll keeps refreshing
|
|
@@ -1369,27 +1399,42 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
|
|
|
1369
1399
|
if (historyScrollRef.current?.applied) {
|
|
1370
1400
|
historyScrollRef.current.releaseAt = performance.now() + HISTORY_SCROLL_GESTURE_GAP_MS;
|
|
1371
1401
|
}
|
|
1402
|
+
const distance = touchPullRef.current.distance;
|
|
1403
|
+
touchPullRef.current = { startY: null, lastY: null, distance: 0 };
|
|
1404
|
+
setTopPullDistance(0);
|
|
1405
|
+
if (distance >= TOUCH_TOP_PULL_THRESHOLD_PX
|
|
1406
|
+
&& ref.current?.scrollTop <= PROGRAMMATIC_SCROLL_TOLERANCE_PX) requestHistoryPage();
|
|
1407
|
+
}, [ref, requestHistoryPage]);
|
|
1408
|
+
const onTouchCancel = React.useCallback(() => {
|
|
1409
|
+
userScrollRef.current.touching = false;
|
|
1410
|
+
touchPullRef.current = { startY: null, lastY: null, distance: 0 };
|
|
1411
|
+
setTopPullDistance(0);
|
|
1372
1412
|
}, []);
|
|
1373
1413
|
const onTouchMove = React.useCallback((event) => {
|
|
1374
1414
|
const node = ref.current;
|
|
1375
1415
|
const pull = touchPullRef.current;
|
|
1376
1416
|
if (!node || paneKey !== "chat" || event.touches?.length !== 1) return;
|
|
1417
|
+
const y = event.touches[0].clientY;
|
|
1418
|
+
const deltaY = pull.lastY == null ? 0 : pull.lastY - y;
|
|
1419
|
+
pull.lastY = y;
|
|
1420
|
+
if (nestedViewportCanScroll(node, event.target, deltaY)) {
|
|
1421
|
+
// Movement within a box must not accumulate into a history pull.
|
|
1422
|
+
if (pull.startY != null) pull.startY = y;
|
|
1423
|
+
pull.distance = 0;
|
|
1424
|
+
setTopPullDistance(0);
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1377
1427
|
if (historyScrollRef.current) {
|
|
1378
1428
|
historyScrollRef.current.releaseAt = performance.now() + HISTORY_SCROLL_GESTURE_GAP_MS;
|
|
1379
1429
|
event.preventDefault();
|
|
1380
1430
|
return;
|
|
1381
1431
|
}
|
|
1382
|
-
if (pull.
|
|
1432
|
+
if (pull.startY == null) return;
|
|
1383
1433
|
if (node.scrollTop > PROGRAMMATIC_SCROLL_TOLERANCE_PX) return;
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
pull.
|
|
1387
|
-
|
|
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]);
|
|
1434
|
+
pull.distance = Math.min(TOUCH_TOP_PULL_MAX_PX, Math.max(0, y - pull.startY));
|
|
1435
|
+
setTopPullDistance(pull.distance);
|
|
1436
|
+
if (pull.distance > 0) event.preventDefault();
|
|
1437
|
+
}, [paneKey, ref]);
|
|
1393
1438
|
|
|
1394
1439
|
React.useEffect(() => {
|
|
1395
1440
|
const node = ref.current;
|
|
@@ -1404,7 +1449,8 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
|
|
|
1404
1449
|
};
|
|
1405
1450
|
}, [ref, onWheel, onTouchMove]);
|
|
1406
1451
|
|
|
1407
|
-
return { normalizedLines, onScroll, onTouchStart, onTouchEnd
|
|
1452
|
+
return { normalizedLines, onScroll, onTouchStart, onTouchEnd, onTouchCancel,
|
|
1453
|
+
topPullDistance, loadingOlderHistory: loadingHistorySessionId === historySessionId };
|
|
1408
1454
|
}
|
|
1409
1455
|
|
|
1410
1456
|
function Runs({ runs, theme }) {
|
|
@@ -1529,15 +1575,11 @@ function ChatActivityRun({ calls }) {
|
|
|
1529
1575
|
followRef.current = getScrollDistanceToBottom(event.currentTarget) <= 24;
|
|
1530
1576
|
},
|
|
1531
1577
|
onWheel: (event) => {
|
|
1532
|
-
event.stopPropagation();
|
|
1533
1578
|
if (event.deltaY < 0) followRef.current = false;
|
|
1534
1579
|
},
|
|
1535
|
-
onTouchStart: (
|
|
1536
|
-
event.stopPropagation();
|
|
1580
|
+
onTouchStart: () => {
|
|
1537
1581
|
followRef.current = false;
|
|
1538
1582
|
},
|
|
1539
|
-
onTouchMove: (event) => event.stopPropagation(),
|
|
1540
|
-
onTouchEnd: (event) => event.stopPropagation(),
|
|
1541
1583
|
}, calls.map((call) => React.createElement(ChatCallLine, { key: call.callKey, line: call }))),
|
|
1542
1584
|
React.createElement("div", { className: "ps-activity-run-footer" },
|
|
1543
1585
|
`Showing ${calls.length} ${calls.length === 1 ? "entry" : "entries"} · Scroll for earlier activity`));
|
|
@@ -3785,7 +3827,9 @@ const PreviewMessageContent = React.memo(function PreviewMessageContent({ conten
|
|
|
3785
3827
|
});
|
|
3786
3828
|
|
|
3787
3829
|
const AssistantPreviewCard = React.memo(function AssistantPreviewCard({ line, theme, controller }) {
|
|
3788
|
-
|
|
3830
|
+
// Saved updates should be readable immediately. The viewport below keeps
|
|
3831
|
+
// long updates scrollable without taking over the whole chat pane.
|
|
3832
|
+
const [open, setOpen] = React.useState(line.text === "Agent update");
|
|
3789
3833
|
const [revealed, setRevealed] = React.useState(
|
|
3790
3834
|
!line.liveStartedAt || Date.now() - line.liveStartedAt >= 200,
|
|
3791
3835
|
);
|
|
@@ -3794,6 +3838,10 @@ const AssistantPreviewCard = React.memo(function AssistantPreviewCard({ line, th
|
|
|
3794
3838
|
const followRef = React.useRef(true);
|
|
3795
3839
|
const snapshotRef = React.useRef(null);
|
|
3796
3840
|
const expanded = open || line.final;
|
|
3841
|
+
React.useLayoutEffect(() => {
|
|
3842
|
+
// A live preview can become a saved update in the same card.
|
|
3843
|
+
if (line.text === "Agent update") setOpen(true);
|
|
3844
|
+
}, [line.text]);
|
|
3797
3845
|
// Keep already-mounted markdown/disclosures when closed, but don't parse
|
|
3798
3846
|
// new hidden deltas. Reopening catches up in a single render.
|
|
3799
3847
|
if (expanded) snapshotRef.current = line;
|
|
@@ -3856,15 +3904,12 @@ const AssistantPreviewCard = React.memo(function AssistantPreviewCard({ line, th
|
|
|
3856
3904
|
},
|
|
3857
3905
|
onWheel: (event) => {
|
|
3858
3906
|
if (!line.final) {
|
|
3859
|
-
event.stopPropagation();
|
|
3860
3907
|
if (event.deltaY < 0) followRef.current = false;
|
|
3861
3908
|
}
|
|
3862
3909
|
},
|
|
3863
|
-
onTouchStart: (
|
|
3864
|
-
if (!line.final)
|
|
3910
|
+
onTouchStart: () => {
|
|
3911
|
+
if (!line.final) followRef.current = false;
|
|
3865
3912
|
},
|
|
3866
|
-
onTouchMove: (event) => { if (!line.final) event.stopPropagation(); },
|
|
3867
|
-
onTouchEnd: (event) => { if (!line.final) event.stopPropagation(); },
|
|
3868
3913
|
onKeyDown: (event) => {
|
|
3869
3914
|
if (!line.final && ["ArrowUp", "ArrowDown", "PageUp", "PageDown", "Home", "End", " "].includes(event.key)) {
|
|
3870
3915
|
event.stopPropagation();
|
|
@@ -4224,7 +4269,7 @@ function focusRegionForPaneKey(paneKey, override = null) {
|
|
|
4224
4269
|
return PANE_KEY_FOCUS_REGIONS[String(paneKey || "")] || null;
|
|
4225
4270
|
}
|
|
4226
4271
|
|
|
4227
|
-
function ScrollLinesPanel({ title, titleRight = null, color, focused, actions, lines, stickyLines = [], bottomStickyLines = [], reserveBottomSticky = false, scrollOffset = 0, scrollMode = "top", paneKey, controller, className = "", panelClassName = "", topContent = null, bottomContent = null, structuredBlocks = false, stickyBottom = false, renderBody = null, focusRegion = null, panelRef = null, ariaLive = null }) {
|
|
4272
|
+
function ScrollLinesPanel({ title, titleRight = null, color, focused, actions, lines, stickyLines = [], bottomStickyLines = [], reserveBottomSticky = false, scrollOffset = 0, scrollMode = "top", paneKey, controller, className = "", panelClassName = "", topContent = null, bottomContent = null, structuredBlocks = false, stickyBottom = false, historyPullEnabled = false, historySessionId = null, renderBody = null, focusRegion = null, panelRef = null, ariaLive = null }) {
|
|
4228
4273
|
const themeId = useControllerSelector(controller, (state) => state.ui.themeId);
|
|
4229
4274
|
const theme = getTheme(themeId);
|
|
4230
4275
|
const ref = React.useRef(null);
|
|
@@ -4237,7 +4282,7 @@ function ScrollLinesPanel({ title, titleRight = null, color, focused, actions, l
|
|
|
4237
4282
|
}, [panelRef]);
|
|
4238
4283
|
const stickyRef = React.useRef(null);
|
|
4239
4284
|
const syncingHorizontalRef = React.useRef(false);
|
|
4240
|
-
const { normalizedLines, onScroll, onTouchStart, onTouchEnd } = useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller, { stickyBottom });
|
|
4285
|
+
const { normalizedLines, onScroll, onTouchStart, onTouchEnd, onTouchCancel, topPullDistance, loadingOlderHistory } = useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller, { stickyBottom, historyPullEnabled, historySessionId });
|
|
4241
4286
|
const normalizedSticky = React.useMemo(() => normalizeLines(stickyLines), [stickyLines]);
|
|
4242
4287
|
const normalizedBottomSticky = React.useMemo(() => normalizeLines(bottomStickyLines), [bottomStickyLines]);
|
|
4243
4288
|
const preserveHorizontalScroll = className.includes("is-preserve") && panelClassName.includes("has-preserved-sticky");
|
|
@@ -4326,7 +4371,7 @@ function ScrollLinesPanel({ title, titleRight = null, color, focused, actions, l
|
|
|
4326
4371
|
}, [preserveHorizontalScroll, syncScrollLeft]);
|
|
4327
4372
|
|
|
4328
4373
|
return React.createElement(Panel, { title, titleRight, color, focused, actions, theme, className: panelClassName },
|
|
4329
|
-
topContent,
|
|
4374
|
+
typeof topContent === "function" ? topContent({ topPullDistance, loadingOlderHistory }) : topContent,
|
|
4330
4375
|
normalizedSticky.length > 0
|
|
4331
4376
|
? React.createElement("div", {
|
|
4332
4377
|
ref: stickyRef,
|
|
@@ -4336,7 +4381,7 @@ function ScrollLinesPanel({ title, titleRight = null, color, focused, actions, l
|
|
|
4336
4381
|
normalizedSticky.map((line, index) => React.createElement(Line, { key: `sticky:${index}`, line, theme })),
|
|
4337
4382
|
)
|
|
4338
4383
|
: null,
|
|
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
|
|
4384
|
+
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 },
|
|
4340
4385
|
typeof renderBody === "function"
|
|
4341
4386
|
? renderBody(normalizedLines, theme)
|
|
4342
4387
|
: structuredBlocks
|
|
@@ -6898,6 +6943,39 @@ function SessionHeaderStatus({ controller }) {
|
|
|
6898
6943
|
queue ? React.createElement("span", { className: "ps-mobile-queue", title: queue }, queue) : null);
|
|
6899
6944
|
}
|
|
6900
6945
|
|
|
6946
|
+
function HistoryUpGlyph() {
|
|
6947
|
+
return React.createElement(Glyph, null,
|
|
6948
|
+
React.createElement("path", { d: "M12 19V5m-5 5 5-5 5 5" }));
|
|
6949
|
+
}
|
|
6950
|
+
|
|
6951
|
+
function HistorySpinnerGlyph() {
|
|
6952
|
+
return React.createElement(Glyph, null,
|
|
6953
|
+
React.createElement("path", { d: "M20.5 12a8.5 8.5 0 1 1-8.5-8.5" }));
|
|
6954
|
+
}
|
|
6955
|
+
|
|
6956
|
+
function HistoryLoadIndicator({ loading, manual, pullDistance, onManualLoad }) {
|
|
6957
|
+
const ready = pullDistance >= TOUCH_TOP_PULL_THRESHOLD_PX;
|
|
6958
|
+
const label = loading ? "Loading earlier messages…"
|
|
6959
|
+
: manual ? "Load older messages"
|
|
6960
|
+
: ready ? "Release to load earlier messages"
|
|
6961
|
+
: "Pull for earlier messages";
|
|
6962
|
+
return React.createElement("div", {
|
|
6963
|
+
className: `ps-history-load${loading ? " is-loading" : ""}${manual ? " is-manual" : ""}${ready ? " is-ready" : ""}`,
|
|
6964
|
+
style: pullDistance > 0 ? { "--ps-history-pull": `${Math.min(pullDistance, TOUCH_TOP_PULL_MAX_PX)}px` } : undefined,
|
|
6965
|
+
role: "status", "aria-live": "polite",
|
|
6966
|
+
},
|
|
6967
|
+
React.createElement("span", { className: "ps-history-track", "aria-hidden": "true" },
|
|
6968
|
+
React.createElement("span", { className: "ps-history-tick is-first" }),
|
|
6969
|
+
React.createElement("span", { className: "ps-history-tick is-second" }),
|
|
6970
|
+
React.createElement("span", { className: "ps-history-marker" },
|
|
6971
|
+
loading ? React.createElement(HistorySpinnerGlyph) : React.createElement(HistoryUpGlyph),
|
|
6972
|
+
loading ? React.createElement("span", { className: "ps-history-text-spinner" },
|
|
6973
|
+
["|", "/", "—", "\\"].map((frame, index) => React.createElement("span", { key: index }, frame))) : null)),
|
|
6974
|
+
manual && !loading
|
|
6975
|
+
? React.createElement("button", { type: "button", className: "ps-mini-button ps-load-older-button", onClick: onManualLoad }, label)
|
|
6976
|
+
: React.createElement("span", { className: "ps-history-label" }, label));
|
|
6977
|
+
}
|
|
6978
|
+
|
|
6901
6979
|
function ChatPane({ controller, mobile = false, fullWidth = false, showComposer = true, onEnterZen = null, activityInHeader = false }) {
|
|
6902
6980
|
const themeId = useControllerSelector(controller, (state) => state.ui.themeId);
|
|
6903
6981
|
const theme = getTheme(themeId);
|
|
@@ -6980,7 +7058,7 @@ function ChatPane({ controller, mobile = false, fullWidth = false, showComposer
|
|
|
6980
7058
|
() => appendAnimatedDotsToRuns(chrome.titleRight, chrome.animateTitleRight ? animatedDots : ""),
|
|
6981
7059
|
[animatedDots, chrome.animateTitleRight, chrome.titleRight],
|
|
6982
7060
|
);
|
|
6983
|
-
const [
|
|
7061
|
+
const [manualLoadingSessionId, setManualLoadingSessionId] = React.useState(null);
|
|
6984
7062
|
// Scroll-up expands the transcript automatically until the soft cap, then
|
|
6985
7063
|
// refuses — and the portal had no control to ask for more, so a busy
|
|
6986
7064
|
// session's history became unreachable from the browser. Surface the
|
|
@@ -7079,25 +7157,27 @@ function ChatPane({ controller, mobile = false, fullWidth = false, showComposer
|
|
|
7079
7157
|
scrollMode: viewState.followBottom ? "bottom" : "top",
|
|
7080
7158
|
stickyBottom: true,
|
|
7081
7159
|
paneKey: "chat",
|
|
7160
|
+
historySessionId: viewState.activeSessionId,
|
|
7161
|
+
historyPullEnabled: Boolean(viewState.activeHistory?.hasOlderEvents && !showLoadOlder),
|
|
7082
7162
|
ariaLive: "polite",
|
|
7083
7163
|
className: "is-wrapped",
|
|
7084
7164
|
panelClassName: "ps-chat-panel",
|
|
7085
7165
|
panelRef,
|
|
7086
7166
|
bottomContent: composer,
|
|
7087
|
-
topContent:
|
|
7088
|
-
|
|
7089
|
-
|
|
7090
|
-
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7095
|
-
|
|
7096
|
-
|
|
7097
|
-
|
|
7098
|
-
|
|
7099
|
-
|
|
7100
|
-
|
|
7167
|
+
topContent: ({ topPullDistance, loadingOlderHistory }) => {
|
|
7168
|
+
const loading = loadingOlderHistory || manualLoadingSessionId === viewState.activeSessionId;
|
|
7169
|
+
if (!showLoadOlder && topPullDistance <= 0 && !loading) return null;
|
|
7170
|
+
return React.createElement(HistoryLoadIndicator, {
|
|
7171
|
+
loading, manual: showLoadOlder, pullDistance: loading ? 0 : topPullDistance,
|
|
7172
|
+
onManualLoad: () => {
|
|
7173
|
+
const sessionId = viewState.activeSessionId;
|
|
7174
|
+
setManualLoadingSessionId(sessionId);
|
|
7175
|
+
controller.handleCommand(UI_COMMANDS.EXPAND_HISTORY)
|
|
7176
|
+
.catch(() => {})
|
|
7177
|
+
.finally(() => setManualLoadingSessionId(current => current === sessionId ? null : current));
|
|
7178
|
+
},
|
|
7179
|
+
});
|
|
7180
|
+
},
|
|
7101
7181
|
structuredBlocks: true,
|
|
7102
7182
|
renderBody: null,
|
|
7103
7183
|
});
|
|
@@ -9254,13 +9334,21 @@ function PromptComposer({ controller, mobile, compact = false, active = true, on
|
|
|
9254
9334
|
// A pane-splitter drag or a font-size change re-wraps the text with
|
|
9255
9335
|
// no window resize; watch the box itself.
|
|
9256
9336
|
const node = inputRef.current;
|
|
9337
|
+
let frame = 0;
|
|
9257
9338
|
const observer = node && typeof ResizeObserver !== "undefined"
|
|
9258
|
-
? new ResizeObserver(() =>
|
|
9339
|
+
? new ResizeObserver(() => {
|
|
9340
|
+
// growInput writes the same box's height. Defer those writes
|
|
9341
|
+
// out of ResizeObserver delivery to prevent WebKit's resize
|
|
9342
|
+
// loop error when a narrow pane wraps the placeholder.
|
|
9343
|
+
cancelAnimationFrame(frame);
|
|
9344
|
+
frame = requestAnimationFrame(() => growInput(true));
|
|
9345
|
+
})
|
|
9259
9346
|
: null;
|
|
9260
9347
|
if (observer && node) observer.observe(node);
|
|
9261
9348
|
return () => {
|
|
9262
9349
|
window.removeEventListener("resize", onResize);
|
|
9263
9350
|
observer?.disconnect();
|
|
9351
|
+
cancelAnimationFrame(frame);
|
|
9264
9352
|
};
|
|
9265
9353
|
}, [growInput]);
|
|
9266
9354
|
|
|
@@ -9723,7 +9811,7 @@ function IconButton({ icon, label, onClick, disabled = false, active = false, pr
|
|
|
9723
9811
|
tooltipNode);
|
|
9724
9812
|
}
|
|
9725
9813
|
|
|
9726
|
-
function Toolbar({ controller, mobile, moa = null, canvasPaneOpen = false, onToggleCanvasPane = null, mobilePane = "workspace", onSelectMobilePane = null, mobileMainLayout = "split" }) {
|
|
9814
|
+
function Toolbar({ controller, mobile, moa = null, viewNavigation = null, canvasPaneOpen = false, onToggleCanvasPane = null, mobilePane = "workspace", onSelectMobilePane = null, mobileMainLayout = "split" }) {
|
|
9727
9815
|
const [headerSlot, setHeaderSlot] = React.useState(null);
|
|
9728
9816
|
React.useEffect(() => {
|
|
9729
9817
|
if (typeof document === "undefined") return;
|
|
@@ -9877,6 +9965,15 @@ function Toolbar({ controller, mobile, moa = null, canvasPaneOpen = false, onTog
|
|
|
9877
9965
|
},
|
|
9878
9966
|
});
|
|
9879
9967
|
|
|
9968
|
+
if (!mobile && moa?.desktop !== false && viewNavigation) for (const direction of ["back", "forward"]) buttonDefs.push({
|
|
9969
|
+
key: direction,
|
|
9970
|
+
icon: React.createElement("svg", { viewBox: "0 0 20 20", width: 16, height: 16, fill: "none", stroke: "currentColor", strokeWidth: 1.7, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true },
|
|
9971
|
+
React.createElement("path", { d: direction === "back" ? "M16 10H4m5-5-5 5 5 5" : "M4 10h12m-5-5 5 5-5 5" })),
|
|
9972
|
+
label: viewNavigation[`${direction}Label`],
|
|
9973
|
+
disabled: !viewNavigation[direction === "back" ? "canBack" : "canForward"],
|
|
9974
|
+
onClick: viewNavigation[direction],
|
|
9975
|
+
});
|
|
9976
|
+
|
|
9880
9977
|
const renderButton = (def) => {
|
|
9881
9978
|
const button = React.createElement(IconButton, {
|
|
9882
9979
|
key: def.badge ? undefined : def.key,
|
|
@@ -9945,18 +10042,11 @@ function Toolbar({ controller, mobile, moa = null, canvasPaneOpen = false, onTog
|
|
|
9945
10042
|
);
|
|
9946
10043
|
}
|
|
9947
10044
|
|
|
9948
|
-
//
|
|
9949
|
-
//
|
|
9950
|
-
// left : the workspace's — new, filter, canvas, diagnostics
|
|
9951
|
-
// right : modes [workspace, budget, admin] │ theme · sign-out
|
|
9952
|
-
//
|
|
9953
|
-
// The whole left cluster belongs to the workspace — new session, filter,
|
|
9954
|
-
// canvas and diagnostics all act on it — so it exists only in Workspace
|
|
9955
|
-
// mode. Budget and the Admin Console replace the workspace; nothing on
|
|
9956
|
-
// the left applies there. Modes are exclusive (the controller closes one
|
|
9957
|
-
// when the other opens) and the Workspace button is the way back.
|
|
10045
|
+
// Keep navigation in one permanent slot in every desktop mode. Context
|
|
10046
|
+
// controls occupy equal-width flanks; empty flanks still reserve space.
|
|
9958
10047
|
const mode = moa?.active ? "moa" : adminVisible ? "admin" : (budgetOpen ? "budget" : "workspace");
|
|
9959
10048
|
const ACTIONS = ["new", "filter"];
|
|
10049
|
+
const HISTORY = ["back", "forward"];
|
|
9960
10050
|
const PANELS = ["canvas", "diagnostics"];
|
|
9961
10051
|
const MODES = ["workspace", "moa", "budget", "admin"];
|
|
9962
10052
|
|
|
@@ -9966,7 +10056,7 @@ function Toolbar({ controller, mobile, moa = null, canvasPaneOpen = false, onTog
|
|
|
9966
10056
|
// it — is the confusing half of every full-screen mode. The Canvas toggle
|
|
9967
10057
|
// is exempt: it already means "put the canvas away", and closing drops
|
|
9968
10058
|
// the flag in the reducer.
|
|
9969
|
-
const withRestore = (def) => ((!canvasMaximized || def.key === "canvas") && !(moa?.active && ["workspace", "budget", "admin"].includes(def.key)) ? def : {
|
|
10059
|
+
const withRestore = (def) => (HISTORY.includes(def.key) || (!canvasMaximized || def.key === "canvas") && !(moa?.active && ["workspace", "budget", "admin"].includes(def.key)) ? def : {
|
|
9970
10060
|
...def,
|
|
9971
10061
|
onClick: (...args) => {
|
|
9972
10062
|
controller.dispatch({ type: "ui/canvasMaximized", on: false });
|
|
@@ -9981,10 +10071,6 @@ function Toolbar({ controller, mobile, moa = null, canvasPaneOpen = false, onTog
|
|
|
9981
10071
|
.map(renderButton);
|
|
9982
10072
|
const divider = (key) => React.createElement("span", { key, className: "ps-toolbar-divider", "aria-hidden": "true" });
|
|
9983
10073
|
|
|
9984
|
-
// One run, no bar: all four act on the workspace.
|
|
9985
|
-
const leftCluster = mode === "workspace"
|
|
9986
|
-
? [...pick(ACTIONS), ...pick(PANELS)]
|
|
9987
|
-
: [];
|
|
9988
10074
|
const rightCluster = [
|
|
9989
10075
|
...pick(MODES),
|
|
9990
10076
|
divider("mode-divider"),
|
|
@@ -9992,28 +10078,21 @@ function Toolbar({ controller, mobile, moa = null, canvasPaneOpen = false, onTog
|
|
|
9992
10078
|
];
|
|
9993
10079
|
|
|
9994
10080
|
const toolbar = React.createElement("div", { className: `ps-toolbar${moa?.active ? " is-moa" : ""}` },
|
|
9995
|
-
// Three columns: left rail | main controls | right rail. Full-screen
|
|
9996
|
-
// canvas uses the otherwise-empty left rail for the normal actions so
|
|
9997
|
-
// they do not crowd the canvas metadata and controls across the top.
|
|
9998
10081
|
React.createElement("div", { className: "ps-toolbar-side is-left" },
|
|
9999
|
-
moa?.active ? React.createElement("div", { id: "ps-moa-status-slot" }) :
|
|
10000
|
-
|
|
10001
|
-
|
|
10082
|
+
moa?.active ? React.createElement("div", { id: "ps-moa-status-slot" }) : null,
|
|
10083
|
+
// Canvas controls retain their state in CanvasPane. Their portal
|
|
10084
|
+
// gets the flexible rail, so names/revisions cannot move history.
|
|
10085
|
+
canvasMaximized && !moa?.active
|
|
10086
|
+
? React.createElement("span", { className: "ps-toolbar-canvas-slot", id: "ps-toolbar-canvas-slot" })
|
|
10087
|
+
: null),
|
|
10088
|
+
React.createElement("div", { className: "ps-toolbar-actions ps-toolbar-navigation", role: "navigation", "aria-label": moa?.active ? "Master of Agents" : "View navigation" },
|
|
10089
|
+
React.createElement("div", { className: "ps-toolbar-context is-before", id: "ps-toolbar-before-history" },
|
|
10090
|
+
mode === "workspace" ? pick(ACTIONS) : null),
|
|
10091
|
+
React.createElement("div", { className: "ps-toolbar-history" }, pick(HISTORY)),
|
|
10092
|
+
React.createElement("div", { className: "ps-toolbar-context is-after", id: "ps-toolbar-after-history" },
|
|
10093
|
+
mode === "workspace" ? pick(PANELS) : null)),
|
|
10002
10094
|
React.createElement("div", { className: "ps-toolbar-side is-right" },
|
|
10003
|
-
// The portal header parks its version/status meta here, LEFT of
|
|
10004
|
-
// the tool buttons, and its sign-out glyph in the slot after
|
|
10005
|
-
// them — one right-aligned cluster: meta · mode · theme · out.
|
|
10006
10095
|
React.createElement("span", { className: "ps-toolbar-meta-slot", id: "ps-toolbar-meta-slot" }),
|
|
10007
|
-
// While the canvas is full screen its header controls (rev, zoom,
|
|
10008
|
-
// zen, restore) portal INTO this slot from CanvasPane — zoom state
|
|
10009
|
-
// lives there, so the controls come to the toolbar rather than
|
|
10010
|
-
// their state moving out.
|
|
10011
|
-
canvasMaximized
|
|
10012
|
-
? React.createElement("span", { className: "ps-toolbar-canvas-slot", id: "ps-toolbar-canvas-slot" })
|
|
10013
|
-
: null,
|
|
10014
|
-
canvasMaximized
|
|
10015
|
-
? React.createElement("span", { className: "ps-toolbar-divider", "aria-hidden": "true" })
|
|
10016
|
-
: null,
|
|
10017
10096
|
React.createElement("div", { className: "ps-toolbar-actions is-tools" }, rightCluster),
|
|
10018
10097
|
React.createElement("span", { className: "ps-toolbar-signout-slot", id: "ps-toolbar-signout-slot" })),
|
|
10019
10098
|
);
|
|
@@ -14778,7 +14857,7 @@ export function createWebPilotSwarmController({ transport, mode = "remote", bran
|
|
|
14778
14857
|
return new PilotSwarmUiController({ store, transport });
|
|
14779
14858
|
}
|
|
14780
14859
|
|
|
14781
|
-
export function PilotSwarmWebApp({ controller, suspended = false, moa = null }) {
|
|
14860
|
+
export function PilotSwarmWebApp({ controller, suspended = false, moa = null, viewNavigation = null }) {
|
|
14782
14861
|
const viewportRef = React.useRef(null);
|
|
14783
14862
|
const mainGridRef = React.useRef(null);
|
|
14784
14863
|
const viewport = useMeasuredViewport(viewportRef, suspended);
|
|
@@ -14914,7 +14993,9 @@ export function PilotSwarmWebApp({ controller, suspended = false, moa = null })
|
|
|
14914
14993
|
const appliedProfileSettingsJsonRef = React.useRef(null);
|
|
14915
14994
|
const defaultProfileSettingsRef = React.useRef(null);
|
|
14916
14995
|
const [mobilePane, setMobilePane] = React.useState("workspace");
|
|
14917
|
-
|
|
14996
|
+
// Match the CSS and MoA breakpoint. The padded shell is narrower than
|
|
14997
|
+
// the browser and otherwise flips to mobile while the header is desktop.
|
|
14998
|
+
const mobile = useMediaQuery(`(max-width: ${MOBILE_BREAKPOINT}px)`);
|
|
14918
14999
|
const readOnlyChatPane = state.activeSessionIsGroup;
|
|
14919
15000
|
const effectivePromptRows = readOnlyChatPane ? 0 : state.promptRows;
|
|
14920
15001
|
|
|
@@ -15542,7 +15623,7 @@ export function PilotSwarmWebApp({ controller, suspended = false, moa = null })
|
|
|
15542
15623
|
: null;
|
|
15543
15624
|
|
|
15544
15625
|
if (suspended) return React.createElement(ControllerContext.Provider, { value: controller },
|
|
15545
|
-
React.createElement(Toolbar, { controller, mobile: false, moa }),
|
|
15626
|
+
React.createElement(Toolbar, { controller, mobile: false, moa, viewNavigation }),
|
|
15546
15627
|
React.createElement(ModalLayer, { controller }));
|
|
15547
15628
|
return React.createElement(ControllerContext.Provider, { value: controller },
|
|
15548
15629
|
React.createElement("div", { ref: viewportRef, className: "ps-web-shell" },
|
|
@@ -15550,7 +15631,7 @@ export function PilotSwarmWebApp({ controller, suspended = false, moa = null })
|
|
|
15550
15631
|
// plus the Main layout cycle), so it renders on every pane — hiding it
|
|
15551
15632
|
// anywhere would trap the user with no way back.
|
|
15552
15633
|
React.createElement(Toolbar, {
|
|
15553
|
-
controller, moa,
|
|
15634
|
+
controller, moa, viewNavigation,
|
|
15554
15635
|
mobile,
|
|
15555
15636
|
canvasPaneOpen: mobileCanvasOpen,
|
|
15556
15637
|
onToggleCanvasPane: toggleMobileCanvas,
|
package/web/dist/assets/{abnfDiagram-VRR7QNED-DHZAKybB.js → abnfDiagram-VRR7QNED-C2HGSvvf.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{g as p,r as u,d as a}from"./chunk-MOJQB5TN-
|
|
1
|
+
import{g as p,r as u,d as a}from"./chunk-MOJQB5TN-DuIGV22R.js";import{p as f}from"./chunk-JWPE2WC7-Ddh7J2Rp.js";import{_ as n,l as o}from"./mermaid.core-DWYsDHXh.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-Deleul8f.js";import"./pilotswarm-3GsGwA3r.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-
|
|
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-DWYsDHXh.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};
|