pilotswarm 0.5.61 → 0.5.63
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/mcp/dist/src/resources/models.d.ts.map +1 -1
- package/mcp/dist/src/resources/models.js +6 -1
- package/mcp/dist/src/resources/models.js.map +1 -1
- package/mcp/dist/src/tools/models.d.ts.map +1 -1
- package/mcp/dist/src/tools/models.js +11 -1
- package/mcp/dist/src/tools/models.js.map +1 -1
- package/mcp/dist/src/tools/sessions.d.ts.map +1 -1
- package/mcp/dist/src/tools/sessions.js +8 -2
- package/mcp/dist/src/tools/sessions.js.map +1 -1
- package/package.json +2 -2
- package/tui/src/node-sdk-transport.js +1 -1
- package/ui/core/src/chat-activity.js +94 -0
- package/ui/core/src/controller.js +87 -19
- package/ui/core/src/history.js +15 -0
- package/ui/core/src/moa.js +41 -11
- package/ui/core/src/reducer.js +25 -10
- package/ui/core/src/selectors.js +25 -5
- package/ui/core/src/session-errors.js +10 -2
- package/ui/core/src/state.js +6 -2
- package/ui/core/src/system-titles.js +2 -0
- package/ui/react/src/components.js +2 -1
- package/ui/react/src/web-app.js +110 -35
- package/web/dist/assets/{abnfDiagram-VRR7QNED-CCVkGWsr.js → abnfDiagram-VRR7QNED-C8iAmIqt.js} +1 -1
- package/web/dist/assets/{arc-y040btO3.js → arc-Cg8qs17j.js} +1 -1
- package/web/dist/assets/{architectureDiagram-ZJ3FMSHR-24Yt5esy.js → architectureDiagram-ZJ3FMSHR-fYr0dRm3.js} +1 -1
- package/web/dist/assets/{blockDiagram-677ZJIJ3-BlbS-_GI.js → blockDiagram-677ZJIJ3-Bpj79Dzq.js} +1 -1
- package/web/dist/assets/{c4Diagram-LMCZKHZV-_mamn0Fv.js → c4Diagram-LMCZKHZV-b26Lsm6m.js} +1 -1
- package/web/dist/assets/channel-C-ASbcRr.js +1 -0
- package/web/dist/assets/{chunk-2Q5K7J3B-TCbIB2Ni.js → chunk-2Q5K7J3B-VLYQfjgG.js} +1 -1
- package/web/dist/assets/{chunk-32BRIVSS-C9q5KNKG.js → chunk-32BRIVSS-mVx--2Hg.js} +1 -1
- package/web/dist/assets/{chunk-5VM5RSS4-BvoqfU8P.js → chunk-5VM5RSS4-jwnJmked.js} +1 -1
- package/web/dist/assets/{chunk-EX3LRPZG-zFJjZeNd.js → chunk-EX3LRPZG-DdfzAT1n.js} +1 -1
- package/web/dist/assets/{chunk-JWPE2WC7-Ce_6C5M-.js → chunk-JWPE2WC7-BHm6Udd8.js} +1 -1
- package/web/dist/assets/{chunk-MOJQB5TN-CPjpLM65.js → chunk-MOJQB5TN-Dn5qSVAS.js} +1 -1
- package/web/dist/assets/{chunk-RYQCIY6F-CsmVUSDH.js → chunk-RYQCIY6F-D4IKMROn.js} +1 -1
- package/web/dist/assets/{chunk-V7JOEXUC-CgrmPPOd.js → chunk-V7JOEXUC-BhME3pRf.js} +1 -1
- package/web/dist/assets/{chunk-VR4S4FIN-BxAHDR7h.js → chunk-VR4S4FIN-CHG_NBff.js} +1 -1
- package/web/dist/assets/{chunk-XXDRQBXY-BGfFoO5_.js → chunk-XXDRQBXY-yw4QCgiL.js} +1 -1
- package/web/dist/assets/classDiagram-OUVF2IWQ-D2vlJIb1.js +1 -0
- package/web/dist/assets/classDiagram-v2-EOCWNBFH-D2vlJIb1.js +1 -0
- package/web/dist/assets/{cose-bilkent-JH36ORCC-B6KcngJW.js → cose-bilkent-JH36ORCC-DqwPj9Kx.js} +1 -1
- package/web/dist/assets/{cynefin-VYW2F7L2-DaY7l4Ce.js → cynefin-VYW2F7L2-CVokaaE_.js} +1 -1
- package/web/dist/assets/{cynefinDiagram-TSTJHNR4-BldfGsoa.js → cynefinDiagram-TSTJHNR4-Bkhj9fuY.js} +1 -1
- package/web/dist/assets/{dagre-VKFMJZFB-C4T9X5Bs.js → dagre-VKFMJZFB-DVv-jnjb.js} +1 -1
- package/web/dist/assets/{diagram-FQU43EPY-DCVA_t-e.js → diagram-FQU43EPY-DDlZjkrF.js} +1 -1
- package/web/dist/assets/{diagram-G47NLZAW-pbTZGgE5.js → diagram-G47NLZAW-CNDUgqYa.js} +1 -1
- package/web/dist/assets/{diagram-NH7WQ7WH-P8Iks122.js → diagram-NH7WQ7WH-DywF8u8i.js} +1 -1
- package/web/dist/assets/{diagram-OA4YK3LP-hEjZPipp.js → diagram-OA4YK3LP-ZfN8nvLw.js} +1 -1
- package/web/dist/assets/{diagram-WEI45ONY-CVAzVCGu.js → diagram-WEI45ONY-S94A6Avm.js} +1 -1
- package/web/dist/assets/{ebnfDiagram-CCIWWBDH-BLL398qt.js → ebnfDiagram-CCIWWBDH-Mpt3QUnw.js} +1 -1
- package/web/dist/assets/{erDiagram-Q63AITRT-CLTADyUG.js → erDiagram-Q63AITRT-Bh-eWbdV.js} +1 -1
- package/web/dist/assets/{flowDiagram-23GEKE2U-BAdlWAt0.js → flowDiagram-23GEKE2U-BwRtDI6V.js} +1 -1
- package/web/dist/assets/{ganttDiagram-NO4QXBWP-C7Z2wavr.js → ganttDiagram-NO4QXBWP-CrZoBmcB.js} +1 -1
- package/web/dist/assets/{gitGraphDiagram-IHSO6WYX-BI546pYu.js → gitGraphDiagram-IHSO6WYX-giXv1ynk.js} +1 -1
- package/web/dist/assets/index-Br-gGWmc.js +24 -0
- package/web/dist/assets/{index-CvW-4eXF.css → index-DRFDn87d.css} +1 -1
- package/web/dist/assets/{infoDiagram-FWYZ7A6U-8C7iQydo.js → infoDiagram-FWYZ7A6U-H_5oc4-7.js} +1 -1
- package/web/dist/assets/{ishikawaDiagram-FXEZZL3T-Co4STVxQ.js → ishikawaDiagram-FXEZZL3T-BydiPDX0.js} +1 -1
- package/web/dist/assets/{journeyDiagram-5HDEW3XC-DbUt11q-.js → journeyDiagram-5HDEW3XC-DS1HXms0.js} +1 -1
- package/web/dist/assets/{kanban-definition-HUTT4EX6-DUNcFmme.js → kanban-definition-HUTT4EX6-BjY5SyYu.js} +1 -1
- package/web/dist/assets/{linear-Cjaxj94d.js → linear-BvOotjKL.js} +1 -1
- package/web/dist/assets/{mermaid.core-B3cPFf4f.js → mermaid.core-0iRu7sp-.js} +4 -4
- package/web/dist/assets/{mindmap-definition-LN4V7U3C-DaZtxB4N.js → mindmap-definition-LN4V7U3C-DB93zsvL.js} +1 -1
- package/web/dist/assets/{papaparse.min-vfdso2fs.js → papaparse.min-f5Xncedc.js} +1 -1
- package/web/dist/assets/{pegDiagram-2B236MQR-DkBpYV7m.js → pegDiagram-2B236MQR-Dh_U1cFA.js} +1 -1
- package/web/dist/assets/{pieDiagram-ENE6RG2P-By3tI-vc.js → pieDiagram-ENE6RG2P-Csv1qxMm.js} +1 -1
- package/web/dist/assets/pilotswarm-DQNSWfNK.js +105 -0
- package/web/dist/assets/{quadrantDiagram-ABIIQ3AL-DZmVm0xK.js → quadrantDiagram-ABIIQ3AL-Bo0pcrBM.js} +1 -1
- package/web/dist/assets/{railroadDiagram-RFXS5EU6-BC5Mbz7q.js → railroadDiagram-RFXS5EU6-CHPvHNWG.js} +1 -1
- package/web/dist/assets/{requirementDiagram-TGXJPOKE-CyZNX_O1.js → requirementDiagram-TGXJPOKE-DgX8l-6H.js} +1 -1
- package/web/dist/assets/{sankeyDiagram-HTMAVEWB-7603NEmu.js → sankeyDiagram-HTMAVEWB-xR6MTs5a.js} +1 -1
- package/web/dist/assets/{sequenceDiagram-DBY2YBRQ-CXJ-i2Xj.js → sequenceDiagram-DBY2YBRQ-CD_45diB.js} +1 -1
- package/web/dist/assets/{sizeCapture-X5ZJPWSS-CKT0ATnS.js → sizeCapture-X5ZJPWSS-BJVEXU0K.js} +1 -1
- package/web/dist/assets/{stateDiagram-2N3HPSRC-BIDPX4YU.js → stateDiagram-2N3HPSRC-Bwu6kd23.js} +1 -1
- package/web/dist/assets/stateDiagram-v2-6OUMAXLB-aypsN5jW.js +1 -0
- package/web/dist/assets/{swimlanes-5IMT3BWC-CPoy6vnO.js → swimlanes-5IMT3BWC-BmhEzevT.js} +2 -2
- package/web/dist/assets/swimlanesDiagram-G3AALYLV-Duf5C4YK.js +8 -0
- package/web/dist/assets/{timeline-definition-FHXFAJF6-BGdNkplk.js → timeline-definition-FHXFAJF6-DFPI_uTI.js} +1 -1
- package/web/dist/assets/{vennDiagram-L72KCM5P-ByFzarUb.js → vennDiagram-L72KCM5P-DDTpTkBC.js} +1 -1
- package/web/dist/assets/{wardleyDiagram-EHGQE667-CAk0SYuv.js → wardleyDiagram-EHGQE667-bV2_YVIL.js} +1 -1
- package/web/dist/assets/{xychartDiagram-FW5EYKEG-Np7h6_A0.js → xychartDiagram-FW5EYKEG-C7bDIXAV.js} +1 -1
- package/web/dist/index.html +3 -3
- package/web/runtime.js +1 -0
- package/web/dist/assets/channel-COFs9dqk.js +0 -1
- package/web/dist/assets/classDiagram-OUVF2IWQ-B5-KmsCx.js +0 -1
- package/web/dist/assets/classDiagram-v2-EOCWNBFH-B5-KmsCx.js +0 -1
- package/web/dist/assets/index-DsPaDrf9.js +0 -24
- package/web/dist/assets/pilotswarm-BL_NbZug.js +0 -98
- package/web/dist/assets/stateDiagram-v2-6OUMAXLB-Dr8oD9T6.js +0 -1
- package/web/dist/assets/swimlanesDiagram-G3AALYLV-BV0EQRlB.js +0 -8
|
@@ -354,6 +354,7 @@ const ChatPane = React.memo(function ChatPane({ controller, width, height, frame
|
|
|
354
354
|
connectionError: state.connection.error,
|
|
355
355
|
connectionMode: state.connection.mode,
|
|
356
356
|
chatScroll: state.ui.scroll.chat,
|
|
357
|
+
followBottom: state.ui.followBottom?.chat !== false,
|
|
357
358
|
focused: state.ui.focusRegion === "chat",
|
|
358
359
|
};
|
|
359
360
|
}, shallowEqualObject);
|
|
@@ -449,7 +450,7 @@ const ChatPane = React.memo(function ChatPane({ controller, width, height, frame
|
|
|
449
450
|
lines: elements,
|
|
450
451
|
bottomStickyLines,
|
|
451
452
|
scrollOffset: chatView.chatScroll,
|
|
452
|
-
scrollMode: "bottom",
|
|
453
|
+
scrollMode: chatView.followBottom ? "bottom" : "top",
|
|
453
454
|
paneId: "chat",
|
|
454
455
|
paneLabel: "Chat",
|
|
455
456
|
frame,
|
package/ui/react/src/web-app.js
CHANGED
|
@@ -607,12 +607,8 @@ function materializeProfileSettings(remoteSettings, defaults) {
|
|
|
607
607
|
// synthesizing one here would let a poll clobber a fresh local toggle.
|
|
608
608
|
...(hasOwn(normalizedRemote, touchScaleKey())
|
|
609
609
|
? { touchScale: normalizedRemote[touchScaleKey()] }
|
|
610
|
-
//
|
|
611
|
-
|
|
612
|
-
// inherit it, and only until it saves a slot of its own.
|
|
613
|
-
: (isNarrowViewport() && hasOwn(normalizedRemote, "touchScale")
|
|
614
|
-
? { touchScale: normalizedRemote.touchScale }
|
|
615
|
-
: {})),
|
|
610
|
+
// Never inherit the other device class's preference.
|
|
611
|
+
: {}),
|
|
616
612
|
// Read back for the same reason as touchScale above: written but never
|
|
617
613
|
// merged means the fold state resets on every reload. No default here
|
|
618
614
|
// either — absent must stay absent so a poll cannot overwrite a toggle
|
|
@@ -1079,6 +1075,18 @@ export function computeAnchoredScrollTop(
|
|
|
1079
1075
|
: Math.min(maxScroll, offsetPixels);
|
|
1080
1076
|
}
|
|
1081
1077
|
|
|
1078
|
+
function scrollLineIdentity(line) {
|
|
1079
|
+
if (!line) return "";
|
|
1080
|
+
if (line.kind === "runs") return line.runs?.map((run) => run?.text || "").join("") || "";
|
|
1081
|
+
if (line.kind === "assistantPreview") return `assistant:${line.previewKey || line.messageId || line.id || ""}`;
|
|
1082
|
+
return `${line.kind || "text"}:${line.text || line.value || line.id || ""}`;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
function scrollBoundaryIdentity(lines, fromEnd = false) {
|
|
1086
|
+
const boundary = fromEnd ? lines.slice(-8) : lines.slice(0, 8);
|
|
1087
|
+
return boundary.map(scrollLineIdentity).join("\u241e");
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1082
1090
|
function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller, { stickyBottom = false } = {}) {
|
|
1083
1091
|
const normalizedLines = React.useMemo(() => normalizeLines(lines), [lines]);
|
|
1084
1092
|
// Programmatic scrollTop assignments fire a 'scroll' event that would
|
|
@@ -1091,6 +1099,7 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
|
|
|
1091
1099
|
scrollMode,
|
|
1092
1100
|
scrollOffset,
|
|
1093
1101
|
});
|
|
1102
|
+
const previousContentRef = React.useRef(null);
|
|
1094
1103
|
// Touch scrolling relies on native momentum for speed: a hard flick keeps
|
|
1095
1104
|
// scrolling long after the finger lifts. Re-asserting scrollTop from state
|
|
1096
1105
|
// on every render (live events, status updates) kills that momentum at the
|
|
@@ -1120,30 +1129,44 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
|
|
|
1120
1129
|
const node = ref.current;
|
|
1121
1130
|
if (!node) return;
|
|
1122
1131
|
const previousViewportState = previousViewportStateRef.current;
|
|
1132
|
+
const firstLine = scrollBoundaryIdentity(normalizedLines);
|
|
1133
|
+
const lastLine = scrollBoundaryIdentity(normalizedLines, true);
|
|
1134
|
+
const previousContent = previousContentRef.current;
|
|
1123
1135
|
const interaction = userScrollRef.current;
|
|
1124
1136
|
const now = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
1125
1137
|
const interacting = interaction.touching
|
|
1126
1138
|
|| (now - (interaction.lastUserScrollAt || 0)) < TOUCH_MOMENTUM_GRACE_MS;
|
|
1127
1139
|
const isEchoOffset = interaction.lastDispatchedOffset != null
|
|
1128
1140
|
&& Math.abs((Number(scrollOffset) || 0) - interaction.lastDispatchedOffset) < 2;
|
|
1141
|
+
const preservePausedStickyScroll = stickyBottom
|
|
1142
|
+
&& scrollMode === "top"
|
|
1143
|
+
&& previousViewportState?.scrollMode === "top"
|
|
1144
|
+
&& previousViewportState?.scrollOffset === scrollOffset;
|
|
1145
|
+
// A backward page inserts DOM above the reader. Top-anchored paused
|
|
1146
|
+
// state normally preserves scrollTop, which would push the same visible
|
|
1147
|
+
// message down by the inserted height. Compensate with the measured DOM
|
|
1148
|
+
// height delta. Appended live text keeps the old scrollTop unchanged.
|
|
1149
|
+
const prependedWhilePaused = stickyBottom
|
|
1150
|
+
&& previousContent?.lastLine === lastLine
|
|
1151
|
+
&& previousContent?.firstLine !== firstLine
|
|
1152
|
+
&& node.scrollHeight > previousContent.scrollHeight
|
|
1153
|
+
&& (preservePausedStickyScroll || node.scrollTop <= PROGRAMMATIC_SCROLL_TOLERANCE_PX);
|
|
1129
1154
|
if (
|
|
1130
|
-
|
|
1155
|
+
!prependedWhilePaused
|
|
1156
|
+
&& interacting
|
|
1131
1157
|
&& scrollMode === previousViewportState?.scrollMode
|
|
1132
1158
|
&& (scrollOffset === previousViewportState?.scrollOffset || isEchoOffset)
|
|
1133
1159
|
) {
|
|
1134
1160
|
previousViewportStateRef.current = { scrollMode, scrollOffset };
|
|
1161
|
+
previousContentRef.current = { firstLine, lastLine, scrollHeight: node.scrollHeight };
|
|
1135
1162
|
return;
|
|
1136
1163
|
}
|
|
1137
|
-
const
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
node,
|
|
1143
|
-
scrollOffset,
|
|
1144
|
-
scrollMode,
|
|
1145
|
-
preservePausedStickyScroll,
|
|
1146
|
-
);
|
|
1164
|
+
const nextScrollTop = prependedWhilePaused
|
|
1165
|
+
? Math.max(0, Math.min(
|
|
1166
|
+
node.scrollTop + (node.scrollHeight - previousContent.scrollHeight),
|
|
1167
|
+
node.scrollHeight - node.clientHeight,
|
|
1168
|
+
))
|
|
1169
|
+
: computeAnchoredScrollTop(node, scrollOffset, scrollMode, preservePausedStickyScroll);
|
|
1147
1170
|
if (Math.abs(node.scrollTop - nextScrollTop) > PROGRAMMATIC_SCROLL_TOLERANCE_PX) {
|
|
1148
1171
|
const pendingProgrammaticScroll = { target: nextScrollTop };
|
|
1149
1172
|
programmaticScrollRef.current = pendingProgrammaticScroll;
|
|
@@ -1156,10 +1179,20 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
|
|
|
1156
1179
|
}
|
|
1157
1180
|
});
|
|
1158
1181
|
}
|
|
1182
|
+
if (prependedWhilePaused && paneKey && typeof controller.updatePaneScrollFromViewport === "function") {
|
|
1183
|
+
// The measured DOM compensation above is the new durable paused
|
|
1184
|
+
// position. Persist it too: otherwise switching sessions and back
|
|
1185
|
+
// reapplies the pre-page offset and moves the reader by the full
|
|
1186
|
+
// height of the newly inserted history.
|
|
1187
|
+
const rowOffset = Math.max(0, nextScrollTop) / SCROLL_ROW_HEIGHT;
|
|
1188
|
+
userScrollRef.current.lastDispatchedOffset = rowOffset;
|
|
1189
|
+
controller.updatePaneScrollFromViewport(paneKey, rowOffset, { atBottom: false });
|
|
1190
|
+
}
|
|
1159
1191
|
previousViewportStateRef.current = {
|
|
1160
1192
|
scrollMode,
|
|
1161
1193
|
scrollOffset,
|
|
1162
1194
|
};
|
|
1195
|
+
previousContentRef.current = { firstLine, lastLine, scrollHeight: node.scrollHeight };
|
|
1163
1196
|
}, [normalizedLines, ref, scrollMode, scrollOffset, stickyBottom, viewportRevision]);
|
|
1164
1197
|
|
|
1165
1198
|
const dispatchScrollOffset = useFrameCoalescedCallback((offset) => {
|
|
@@ -1193,6 +1226,13 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
|
|
|
1193
1226
|
rowOffset,
|
|
1194
1227
|
{ atBottom: isScrollViewportAtBottom(node) },
|
|
1195
1228
|
);
|
|
1229
|
+
// Pausing bottom-follow changes chat to top-anchored scroll state,
|
|
1230
|
+
// but reaching the DOM's actual top must still arm backward CMS
|
|
1231
|
+
// paging. Keep this next to the native measurement so the history
|
|
1232
|
+
// gate does not depend on which anchoring mode currently renders.
|
|
1233
|
+
if (paneKey === "chat" && node.scrollTop <= PROGRAMMATIC_SCROLL_TOLERANCE_PX) {
|
|
1234
|
+
controller.armChatTopHistoryLoad?.();
|
|
1235
|
+
}
|
|
1196
1236
|
return;
|
|
1197
1237
|
}
|
|
1198
1238
|
|
|
@@ -1211,11 +1251,11 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
|
|
|
1211
1251
|
|
|
1212
1252
|
const onWheel = React.useCallback((event) => {
|
|
1213
1253
|
const node = ref.current;
|
|
1214
|
-
if (!node || paneKey !== "chat" ||
|
|
1254
|
+
if (!node || paneKey !== "chat" || event.deltaY >= 0) return;
|
|
1215
1255
|
if (node.scrollTop > PROGRAMMATIC_SCROLL_TOLERANCE_PX) return;
|
|
1216
1256
|
const maxScroll = Math.max(0, node.scrollHeight - node.clientHeight);
|
|
1217
|
-
controller.handleChatTopHistoryScrollIntent?.(maxScroll / SCROLL_ROW_HEIGHT);
|
|
1218
|
-
}, [controller, paneKey, ref
|
|
1257
|
+
controller.handleChatTopHistoryScrollIntent?.(maxScroll / SCROLL_ROW_HEIGHT, { preserveDomAnchor: true });
|
|
1258
|
+
}, [controller, paneKey, ref]);
|
|
1219
1259
|
|
|
1220
1260
|
// Touch equivalent of the wheel-at-top gesture: touch devices never fire
|
|
1221
1261
|
// wheel events, and once scrollTop sits at 0 a further swipe-down emits no
|
|
@@ -1225,9 +1265,9 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
|
|
|
1225
1265
|
const touchPullRef = React.useRef({ startY: null, fired: false });
|
|
1226
1266
|
const onTouchStart = React.useCallback((event) => {
|
|
1227
1267
|
userScrollRef.current.touching = true;
|
|
1228
|
-
if (paneKey !== "chat"
|
|
1268
|
+
if (paneKey !== "chat") return;
|
|
1229
1269
|
touchPullRef.current = { startY: event.touches?.[0]?.clientY ?? null, fired: false };
|
|
1230
|
-
}, [paneKey
|
|
1270
|
+
}, [paneKey]);
|
|
1231
1271
|
const onTouchEnd = React.useCallback(() => {
|
|
1232
1272
|
userScrollRef.current.touching = false;
|
|
1233
1273
|
// Momentum continues past the finger lift; onScroll keeps refreshing
|
|
@@ -1237,7 +1277,7 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
|
|
|
1237
1277
|
const onTouchMove = React.useCallback((event) => {
|
|
1238
1278
|
const node = ref.current;
|
|
1239
1279
|
const pull = touchPullRef.current;
|
|
1240
|
-
if (!node || paneKey !== "chat"
|
|
1280
|
+
if (!node || paneKey !== "chat") return;
|
|
1241
1281
|
if (pull.fired || pull.startY == null) return;
|
|
1242
1282
|
if (node.scrollTop > PROGRAMMATIC_SCROLL_TOLERANCE_PX) return;
|
|
1243
1283
|
const y = event.touches?.[0]?.clientY;
|
|
@@ -1249,8 +1289,8 @@ function useScrollSync(ref, lines, scrollOffset, scrollMode, paneKey, controller
|
|
|
1249
1289
|
// on narrow viewports). The wheel path keeps the handshake — one
|
|
1250
1290
|
// physical scroll emits MANY wheel events, so it needs debouncing.
|
|
1251
1291
|
const maxScroll = Math.max(0, node.scrollHeight - node.clientHeight);
|
|
1252
|
-
controller.handleChatTopHistoryScrollIntent?.(maxScroll / SCROLL_ROW_HEIGHT + 1, { force: true });
|
|
1253
|
-
}, [controller, paneKey, ref
|
|
1292
|
+
controller.handleChatTopHistoryScrollIntent?.(maxScroll / SCROLL_ROW_HEIGHT + 1, { force: true, preserveDomAnchor: true });
|
|
1293
|
+
}, [controller, paneKey, ref]);
|
|
1254
1294
|
|
|
1255
1295
|
return { normalizedLines, onScroll, onWheel, onTouchStart, onTouchMove, onTouchEnd };
|
|
1256
1296
|
}
|
|
@@ -1331,6 +1371,22 @@ function SystemNoticeLine({ line, theme }) {
|
|
|
1331
1371
|
: null);
|
|
1332
1372
|
}
|
|
1333
1373
|
|
|
1374
|
+
function ChatCallLine({ line }) {
|
|
1375
|
+
const [open, setOpen] = React.useState(false);
|
|
1376
|
+
return React.createElement("details", {
|
|
1377
|
+
className: "ps-system-notice ps-chat-call",
|
|
1378
|
+
"data-call-id": line.callKey,
|
|
1379
|
+
onToggle: event => setOpen(event.currentTarget.open),
|
|
1380
|
+
},
|
|
1381
|
+
React.createElement("summary", { className: "ps-system-notice-summary ps-chat-call-summary" },
|
|
1382
|
+
React.createElement("span", { className: "ps-chat-call-tag" }, line.category || "Tool"),
|
|
1383
|
+
React.createElement("span", { className: "ps-system-notice-summary-text" }, line.text),
|
|
1384
|
+
line.status ? React.createElement("span", { className: `ps-chat-call-status${line.status === "Failed" ? " is-failed" : ""}` }, line.status) : null),
|
|
1385
|
+
open ? React.createElement("div", { className: "ps-system-notice-body" },
|
|
1386
|
+
line.time ? React.createElement("div", { className: "ps-chat-call-time" }, line.time) : null,
|
|
1387
|
+
React.createElement("pre", { className: "ps-chat-call-payload" }, line.body)) : null);
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1334
1390
|
/**
|
|
1335
1391
|
* A canvas action is a button press inside the drawn page, not something the
|
|
1336
1392
|
* viewer typed. Printing the raw `[canvas-action] {…}` JSON as a chat message
|
|
@@ -3230,6 +3286,13 @@ function parseStructuredChatBlocks(lines = []) {
|
|
|
3230
3286
|
for (let index = 0; index < lines.length;) {
|
|
3231
3287
|
const currentLine = lines[index];
|
|
3232
3288
|
|
|
3289
|
+
if (currentLine?.kind === "chatCall" || currentLine?.callPreview !== undefined) {
|
|
3290
|
+
blocks.push({ type: "chatCall", line: currentLine.callPreview !== undefined
|
|
3291
|
+
? { ...currentLine, text: currentLine.callPreview, category: "Agent" } : currentLine });
|
|
3292
|
+
index += 1;
|
|
3293
|
+
continue;
|
|
3294
|
+
}
|
|
3295
|
+
|
|
3233
3296
|
if (currentLine?.kind === "assistantPreview") {
|
|
3234
3297
|
blocks.push({ type: "assistantPreview", line: currentLine });
|
|
3235
3298
|
index += 1;
|
|
@@ -3655,6 +3718,9 @@ const AssistantPreviewCard = React.memo(function AssistantPreviewCard({ line, th
|
|
|
3655
3718
|
function StructuredBlockList({ blocks, theme, controller = null }) {
|
|
3656
3719
|
return React.createElement(React.Fragment, null,
|
|
3657
3720
|
(blocks || []).map((block, index) => {
|
|
3721
|
+
if (block.type === "chatCall") {
|
|
3722
|
+
return React.createElement(ChatCallLine, { key: block.line.callKey, line: block.line });
|
|
3723
|
+
}
|
|
3658
3724
|
if (block.type === "assistantPreview") {
|
|
3659
3725
|
return React.createElement(AssistantPreviewCard, {
|
|
3660
3726
|
key: block.line.previewKey,
|
|
@@ -4216,7 +4282,7 @@ export function waitReasonLabel(session) {
|
|
|
4216
4282
|
return session?.cronActive === true ? "On wake" : "Waiting";
|
|
4217
4283
|
}
|
|
4218
4284
|
|
|
4219
|
-
function SessionDetailBox({ session, childCount = 0, pause = null, controller = null, collapsed = false, onToggle = null }) {
|
|
4285
|
+
function SessionDetailBox({ session, childCount = 0, pause = null, controller = null, collapsed = false, onToggle = null, onOpenBudget = null }) {
|
|
4220
4286
|
// EVERY field renders on EVERY selection, empty ones as an em dash. The box
|
|
4221
4287
|
// is a fixed grid of rows, so moving through the list cannot change its
|
|
4222
4288
|
// height — a box that grew and shrank would shove the list under the
|
|
@@ -4313,12 +4379,12 @@ function SessionDetailBox({ session, childCount = 0, pause = null, controller =
|
|
|
4313
4379
|
pause && pause.clears
|
|
4314
4380
|
? React.createElement("span", { className: "ps-session-detail-clears" }, pause.clears)
|
|
4315
4381
|
: null,
|
|
4316
|
-
pause && controller ? React.createElement("button", {
|
|
4382
|
+
pause && (controller || onOpenBudget) ? React.createElement("button", {
|
|
4317
4383
|
type: "button", className: "ps-budget-link",
|
|
4318
4384
|
title: pause.provider
|
|
4319
4385
|
? `Open ${pause.provider} in Providers & Budgets`
|
|
4320
4386
|
: "Open providers and budgets",
|
|
4321
|
-
onClick: () => controller.openBudget(
|
|
4387
|
+
onClick: () => (onOpenBudget || (options => controller.openBudget(options)))(
|
|
4322
4388
|
pause.provider ? { provider: pause.provider } : {},
|
|
4323
4389
|
).catch(() => {}),
|
|
4324
4390
|
}, pause.provider ? `Open ${pause.provider}` : "Open providers and budgets") : null));
|
|
@@ -5548,10 +5614,14 @@ function SessionPane({ controller, actions = null, panelClassName = "", structur
|
|
|
5548
5614
|
|| focused.tagName === "SELECT"
|
|
5549
5615
|
|| focused.isContentEditable
|
|
5550
5616
|
));
|
|
5551
|
-
if (focused !== activeButton && !isTypingTarget) {
|
|
5617
|
+
if (viewState.focused && focused !== activeButton && !isTypingTarget) {
|
|
5552
5618
|
activeButton.focus({ preventScroll: true });
|
|
5553
5619
|
}
|
|
5554
|
-
|
|
5620
|
+
// Selection can change from outside this pane (deep links, newly
|
|
5621
|
+
// created sessions, MoA focus and other navigation surfaces). Center
|
|
5622
|
+
// the row once for that selection so its surrounding sessions remain
|
|
5623
|
+
// visible, without re-centering on routine status/catalog refreshes.
|
|
5624
|
+
activeButton.scrollIntoView({ block: "center" });
|
|
5555
5625
|
}, [activeRowRevealKey, viewState.activeSessionId, viewState.focused, viewState.modalOpen, viewState.sessionsFlat]);
|
|
5556
5626
|
|
|
5557
5627
|
const panelActions = React.createElement(React.Fragment, null,
|
|
@@ -6408,7 +6478,7 @@ function SessionModifyModal({ controller, sessionId, initialTitle, currentModel,
|
|
|
6408
6478
|
error ? React.createElement("div", { className: "ps-share-error" }, error) : null));
|
|
6409
6479
|
}
|
|
6410
6480
|
|
|
6411
|
-
function SessionComposer({ controller, onReadOnlyFocus = null, mobile = false, compact = false }) {
|
|
6481
|
+
function SessionComposer({ controller, onReadOnlyFocus = null, mobile = false, compact = false, autoFocus = !mobile }) {
|
|
6412
6482
|
const modal = useControllerSelector(controller, state => state.ui.modal);
|
|
6413
6483
|
const session = useControllerSelector(controller, state => state.sessions.byId[state.sessions.activeSessionId]);
|
|
6414
6484
|
const { access } = useActiveSessionAccess(controller, session?.sessionId, session?.isGroup);
|
|
@@ -6419,7 +6489,7 @@ function SessionComposer({ controller, onReadOnlyFocus = null, mobile = false, c
|
|
|
6419
6489
|
? React.createElement("div", { className: "ps-composer-readonly" }, session.serviceKind
|
|
6420
6490
|
? "⚗ Service session — runtime machinery. Its transcript is a read-only trace; it does not accept messages."
|
|
6421
6491
|
: `You have view access to this session. Ask ${access.owner?.displayName || access.owner?.email || "the owner"} for write access to participate.`)
|
|
6422
|
-
: React.createElement(PromptComposer, { controller, mobile, compact, autoFocus
|
|
6492
|
+
: React.createElement(PromptComposer, { controller, mobile, compact, autoFocus, active: true }));
|
|
6423
6493
|
}
|
|
6424
6494
|
|
|
6425
6495
|
// The compact focus views use their existing header for activity. The same
|
|
@@ -6470,6 +6540,7 @@ function ChatPane({ controller, mobile = false, fullWidth = false, showComposer
|
|
|
6470
6540
|
activeSessionStatus: activeSessionId ? String(state.sessions.byId[activeSessionId]?.status || "").toLowerCase() : "",
|
|
6471
6541
|
focused: state.ui.focusRegion === "chat",
|
|
6472
6542
|
scroll: state.ui.scroll.chat,
|
|
6543
|
+
followBottom: state.ui.followBottom?.chat !== false,
|
|
6473
6544
|
// Viewer identity — so the transcript can say "You" for the viewer's
|
|
6474
6545
|
// own messages and name others (with an "(owner)" tag).
|
|
6475
6546
|
authPrincipal: state.auth?.principal || null,
|
|
@@ -6619,7 +6690,8 @@ function ChatPane({ controller, mobile = false, fullWidth = false, showComposer
|
|
|
6619
6690
|
bottomStickyLines: activityInHeader ? EMPTY_ARRAY : stickyBottom,
|
|
6620
6691
|
reserveBottomSticky: !activityInHeader,
|
|
6621
6692
|
scrollOffset: viewState.scroll,
|
|
6622
|
-
scrollMode: "bottom",
|
|
6693
|
+
scrollMode: viewState.followBottom ? "bottom" : "top",
|
|
6694
|
+
stickyBottom: true,
|
|
6623
6695
|
paneKey: "chat",
|
|
6624
6696
|
ariaLive: "polite",
|
|
6625
6697
|
className: "is-wrapped",
|
|
@@ -8850,7 +8922,7 @@ function PromptComposer({ controller, mobile, compact = false, active = true, on
|
|
|
8850
8922
|
const inputNode = inputRef.current;
|
|
8851
8923
|
if (!active || promptState.modalOpen || !promptState.focused || !inputNode) return;
|
|
8852
8924
|
if (document.activeElement !== inputNode) {
|
|
8853
|
-
if (!autoFocus) return;
|
|
8925
|
+
if (!autoFocus || (typeof autoFocus === "function" && !autoFocus())) return;
|
|
8854
8926
|
// Programmatic focus pops the on-screen keyboard on touch devices;
|
|
8855
8927
|
// there, focus only ever comes from the user's own tap.
|
|
8856
8928
|
if (mobile) return;
|
|
@@ -9064,7 +9136,7 @@ function PromptComposer({ controller, mobile, compact = false, active = true, on
|
|
|
9064
9136
|
onClick: cancelPending,
|
|
9065
9137
|
}, selectedQueued ? "Delete" : "Cancel")
|
|
9066
9138
|
: null,
|
|
9067
|
-
|
|
9139
|
+
(promptState.canStopTurn || stoppingTurn)
|
|
9068
9140
|
? React.createElement("button", {
|
|
9069
9141
|
type: "button",
|
|
9070
9142
|
className: `ps-stop-button${stoppingTurn ? " is-stopping" : ""}`,
|
|
@@ -14302,6 +14374,9 @@ export function createWebPilotSwarmController({ transport, mode = "remote", bran
|
|
|
14302
14374
|
branding,
|
|
14303
14375
|
docs,
|
|
14304
14376
|
}));
|
|
14377
|
+
// Only the initial device default. A saved value for this device wins
|
|
14378
|
+
// when the profile loads, including an explicit mobile opt-out.
|
|
14379
|
+
store.dispatch({ type: "ui/touchScale", enabled: isNarrowViewport });
|
|
14305
14380
|
return new PilotSwarmUiController({ store, transport });
|
|
14306
14381
|
}
|
|
14307
14382
|
|
package/web/dist/assets/{abnfDiagram-VRR7QNED-CCVkGWsr.js → abnfDiagram-VRR7QNED-C8iAmIqt.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-Dn5qSVAS.js";import{p as f}from"./chunk-JWPE2WC7-BHm6Udd8.js";import{_ as n,l as o}from"./mermaid.core-0iRu7sp-.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-CVokaaE_.js";import"./pilotswarm-DQNSWfNK.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-0iRu7sp-.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};
|