@prettier-ai/dsh-client-ui-chat 0.1.2-alpha.3 → 0.1.2-alpha.4

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/lib/client.js CHANGED
@@ -32,11 +32,25 @@ window.__ModuleLoader__.load({
32
32
  //#endregion
33
33
  //#region lib/types/client/contract/snapshot.js
34
34
  const EMPTY_LIST$1 = [];
35
+ const EMPTY_TIMELINE = {
36
+ turnOrder: EMPTY_LIST$1,
37
+ turns: /* @__PURE__ */ new Map()
38
+ };
39
+ const EMPTY_NODE_SOURCE = {
40
+ getSnapshot: () => void 0,
41
+ subscribe: () => () => {}
42
+ };
43
+ const EMPTY_NODE_PROCESS_SOURCE = {
44
+ getSnapshot: () => void 0,
45
+ subscribe: () => () => {}
46
+ };
35
47
  /** Empty Chat target used before a view builder is registered. */
36
48
  const EMPTY_CHAT_SNAPSHOT = {
37
49
  order: EMPTY_LIST$1,
38
50
  nodes: {
39
51
  get: () => void 0,
52
+ source: () => EMPTY_NODE_SOURCE,
53
+ processSource: () => EMPTY_NODE_PROCESS_SOURCE,
40
54
  values: () => EMPTY_LIST$1
41
55
  },
42
56
  locations: {
@@ -44,10 +58,7 @@ window.__ModuleLoader__.load({
44
58
  getStep: () => EMPTY_LIST$1
45
59
  },
46
60
  navigation: { items: () => EMPTY_LIST$1 },
47
- timeline: {
48
- turnOrder: EMPTY_LIST$1,
49
- turns: /* @__PURE__ */ new Map()
50
- },
61
+ timeline: EMPTY_TIMELINE,
51
62
  legacy: {
52
63
  nodes: EMPTY_LIST$1,
53
64
  turnTimings: /* @__PURE__ */ new Map(),
@@ -206,7 +217,7 @@ window.__ModuleLoader__.load({
206
217
  });
207
218
  //#endregion
208
219
  //#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/chat/ContextBody.module.css.mjs
209
- const css$14 = ".abgUBa_text{color:var(--dsw-alias-label-secondary);font:inherit;white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.abgUBa_fields{border-top:1px solid var(--dsw-alias-line-secondary);flex-direction:column;gap:2px;margin:8px 0 0;padding-top:8px;display:flex}.abgUBa_field{gap:8px;min-width:0;display:flex}.abgUBa_fieldKey{min-width:96px;color:var(--dsw-alias-label-caption);flex:none}.abgUBa_fieldValue{min-width:0;color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;flex:auto;margin:0}.abgUBa_files{flex-wrap:wrap;gap:4px 12px;margin:0 0 8px;padding:0;list-style:none;display:flex}.abgUBa_file{align-items:baseline;gap:6px;min-width:0;display:flex}.abgUBa_filePath{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere}.abgUBa_fileAction{color:var(--dsw-alias-label-caption)}.abgUBa_catalogNotice{color:var(--dsw-alias-label-caption);margin:0 0 6px}.abgUBa_entries{flex-direction:column;gap:4px;margin:0;padding:0;list-style:none;display:flex}.abgUBa_entry{gap:8px;min-width:0;display:flex}.abgUBa_entryName{color:var(--dsw-alias-label-secondary);flex:none}.abgUBa_entryDescription{min-width:0;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;flex:auto;overflow:hidden}.abgUBa_sections{flex-direction:column;gap:8px;margin:0;display:flex}.abgUBa_section{flex-direction:column;gap:2px;min-width:0;display:flex}.abgUBa_sectionName{color:var(--dsw-alias-label-caption)}.abgUBa_sectionText{color:var(--dsw-alias-label-secondary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.abgUBa_relaySender{color:var(--dsw-alias-label-caption);overflow-wrap:anywhere;margin:0 0 6px}.abgUBa_recalls{flex-direction:column;gap:2px;margin:0 0 8px;padding:0;list-style:none;display:flex}.abgUBa_recall{gap:8px;min-width:0;display:flex}.abgUBa_recallLabel{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere}.abgUBa_recallCounts{color:var(--dsw-alias-label-caption);flex:none}";
220
+ const css$14 = ".abgUBa_text{color:var(--dsw-alias-label-secondary);font:inherit;white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.abgUBa_fields{border-top:.5px solid var(--dsw-alias-border-l2);flex-direction:column;gap:2px;margin:8px 0 0;padding-top:8px;display:flex}.abgUBa_field{gap:8px;min-width:0;display:flex}.abgUBa_fieldKey{min-width:96px;color:var(--dsw-alias-label-caption);flex:none}.abgUBa_fieldValue{min-width:0;color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;flex:auto;margin:0}.abgUBa_files{flex-wrap:wrap;gap:4px 12px;margin:0 0 8px;padding:0;list-style:none;display:flex}.abgUBa_file{align-items:baseline;gap:6px;min-width:0;display:flex}.abgUBa_filePath{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere}.abgUBa_fileAction{color:var(--dsw-alias-label-caption)}.abgUBa_catalogNotice{color:var(--dsw-alias-label-caption);margin:0 0 6px}.abgUBa_entries{flex-direction:column;gap:4px;margin:0;padding:0;list-style:none;display:flex}.abgUBa_entry{gap:8px;min-width:0;display:flex}.abgUBa_entryName{color:var(--dsw-alias-label-secondary);flex:none}.abgUBa_entryDescription{min-width:0;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;flex:auto;overflow:hidden}.abgUBa_sections{flex-direction:column;gap:8px;margin:0;display:flex}.abgUBa_section{flex-direction:column;gap:2px;min-width:0;display:flex}.abgUBa_sectionName{color:var(--dsw-alias-label-caption)}.abgUBa_sectionText{color:var(--dsw-alias-label-secondary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.abgUBa_relaySender{color:var(--dsw-alias-label-caption);overflow-wrap:anywhere;margin:0 0 6px}.abgUBa_recalls{flex-direction:column;gap:2px;margin:0 0 8px;padding:0;list-style:none;display:flex}.abgUBa_recall{gap:8px;min-width:0;display:flex}.abgUBa_recallLabel{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere}.abgUBa_recallCounts{color:var(--dsw-alias-label-caption);flex:none}";
210
221
  const tagId$14 = "@prettier-ai/dsh-client-ui-chat/ContextBody.module.css";
211
222
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$14) + "]") === null) {
212
223
  const tag = document.createElement("style");
@@ -947,7 +958,7 @@ window.__ModuleLoader__.load({
947
958
  }
948
959
  //#endregion
949
960
  //#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/chat/MessageIconActions.module.css.mjs
950
- const css$12 = ".BmHDMW_actions{height:calc(28px + var(--dsh-content-font-delta,0px));align-items:center;gap:8px;display:flex}.BmHDMW_timeStart{font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);white-space:nowrap;padding-right:12px}.BmHDMW_timeEnd{font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);white-space:nowrap}@media (hover:hover){[data-actions-reveal=hover] .BmHDMW_actions{opacity:0;transition:opacity 80ms}[data-actions-reveal=hover]:hover .BmHDMW_actions,[data-actions-reveal=hover]:focus-within .BmHDMW_actions{opacity:1}}.BmHDMW_action{width:calc(28px + var(--dsh-content-font-delta,0px));height:calc(28px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:6px;display:inline-flex}.BmHDMW_action svg{width:calc(15px + var(--dsh-content-font-delta,0px));height:calc(15px + var(--dsh-content-font-delta,0px))}.BmHDMW_action:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.BmHDMW_action[data-unavailable]{cursor:default;opacity:.4}.BmHDMW_action[data-unavailable]:hover{color:var(--dsw-alias-label-tertiary);background:0 0}.BmHDMW_visuallyHidden{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}";
961
+ const css$12 = ".BmHDMW_actions{height:calc(28px + var(--dsh-content-font-delta,0px));align-items:center;gap:8px;display:flex}.BmHDMW_timeStart{font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);white-space:nowrap;padding-right:12px}.BmHDMW_timeEnd{font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);white-space:nowrap}@media (hover:hover){[data-actions-reveal=hover] .BmHDMW_actions,:is([data-chat-flow-kind=user],[data-chat-flow-kind=steering]):has(~:is([data-chat-flow-kind=user],[data-chat-flow-kind=steering])) .BmHDMW_actions{opacity:0;transition:opacity 80ms}[data-actions-reveal=hover]:hover .BmHDMW_actions,[data-actions-reveal=hover]:focus-within .BmHDMW_actions,:is([data-chat-flow-kind=user],[data-chat-flow-kind=steering]):has(~:is([data-chat-flow-kind=user],[data-chat-flow-kind=steering])):hover .BmHDMW_actions,:is([data-chat-flow-kind=user],[data-chat-flow-kind=steering]):has(~:is([data-chat-flow-kind=user],[data-chat-flow-kind=steering])):focus-within .BmHDMW_actions{opacity:1}}.BmHDMW_action{width:calc(28px + var(--dsh-content-font-delta,0px));height:calc(28px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:6px;display:inline-flex}.BmHDMW_action svg{width:calc(15px + var(--dsh-content-font-delta,0px));height:calc(15px + var(--dsh-content-font-delta,0px))}.BmHDMW_action:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.BmHDMW_action[data-unavailable]{cursor:default;opacity:.4}.BmHDMW_action[data-unavailable]:hover{color:var(--dsw-alias-label-tertiary);background:0 0}.BmHDMW_visuallyHidden{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}";
951
962
  const tagId$12 = "@prettier-ai/dsh-client-ui-chat/MessageIconActions.module.css";
952
963
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$12) + "]") === null) {
953
964
  const tag = document.createElement("style");
@@ -1169,7 +1180,7 @@ window.__ModuleLoader__.load({
1169
1180
  });
1170
1181
  }
1171
1182
  /** Right-aligned bubble shared by user and steering rows. */
1172
- function UserStyleBubble({ content, renderMessageImages, actions, pending = false, echo = false, referenceLabels = [], previewImages, reveal = "always", t }) {
1183
+ function UserStyleBubble({ content, renderMessageImages, actions, pending = false, echo = false, referenceLabels = [], previewImages, t }) {
1173
1184
  const { text, images: contentImages, rest } = contentParts(content);
1174
1185
  const images = previewImages ?? contentImages;
1175
1186
  const truncated = (total) => t("json.truncated", { total });
@@ -1178,7 +1189,6 @@ window.__ModuleLoader__.load({
1178
1189
  className: MessageItem_module_css_default.userRow,
1179
1190
  "data-pending-steering": pending || void 0,
1180
1191
  "data-submission-echo": echo || void 0,
1181
- "data-actions-reveal": reveal,
1182
1192
  children: [(0, react_jsx_runtime.jsxs)("div", {
1183
1193
  className: MessageItem_module_css_default.userStack,
1184
1194
  children: [
@@ -1256,20 +1266,12 @@ window.__ModuleLoader__.load({
1256
1266
  });
1257
1267
  }
1258
1268
  /** User and admitted-steering keyed Chat renderer. */
1259
- const UserMessageNodeView = (0, react.memo)(function UserMessageNodeView({ node, renderMessageImages, useChat, t }) {
1269
+ const UserMessageNodeView = (0, react.memo)(function UserMessageNodeView({ node, renderMessageImages, t }) {
1260
1270
  const data = node.data;
1261
- const isLatestUserRow = useChat((snapshot) => {
1262
- for (let index = snapshot.order.length - 1; index >= 0; index -= 1) {
1263
- const candidate = snapshot.nodes.get(snapshot.order[index] ?? "");
1264
- if (candidate?.kind === "user" || candidate?.kind === "steering") return candidate.key === node.key;
1265
- }
1266
- return true;
1267
- });
1268
1271
  return (0, react_jsx_runtime.jsx)(UserStyleBubble, {
1269
1272
  content: data.content,
1270
1273
  renderMessageImages,
1271
1274
  ...data.referenceLabels === void 0 ? {} : { referenceLabels: data.referenceLabels },
1272
- reveal: isLatestUserRow ? "always" : "hover",
1273
1275
  t,
1274
1276
  actions: (text) => (0, react_jsx_runtime.jsx)(MessageIconActions, {
1275
1277
  text,
@@ -1341,49 +1343,13 @@ window.__ModuleLoader__.load({
1341
1343
  "turn-tail"
1342
1344
  ]);
1343
1345
  /**
1344
- * Identify one finalized answer generation without using its ordering anchor.
1345
- * @param spec - current Turn process specification.
1346
- * @returns stable identity until the finalized answer Step is withdrawn or replaced.
1347
- */
1348
- function turnProcessGeneration(spec) {
1349
- return `${String(spec.turn)}|${spec.answerStep === null ? "" : String(spec.answerStep)}`;
1350
- }
1351
- /**
1352
- * Encode one process specification as a primitive Location-data value.
1353
- * @param spec - current Turn process specification.
1354
- * @returns reference-stable scalar for equal specifications.
1355
- */
1356
- function encodeTurnProcess(spec) {
1357
- return [
1358
- spec.turn,
1359
- spec.controlAnchorSeq,
1360
- spec.processStartSeq,
1361
- spec.answerAnchorSeq ?? "",
1362
- spec.answerStep ?? "",
1363
- spec.inlineReasoning ? 1 : 0,
1364
- spec.messageCount,
1365
- spec.toolCallCount,
1366
- spec.subagentCount
1367
- ].join("|");
1368
- }
1369
- /**
1370
- * Decode a same-process signature produced by {@link encodeTurnProcess}.
1371
- * @param signature - encoded Turn process value.
1372
- * @returns decoded process specification.
1346
+ * Compare immutable Turn-process specifications by their published fields.
1347
+ * @param left - previous specification.
1348
+ * @param right - next specification.
1349
+ * @returns whether both values describe the same process presentation.
1373
1350
  */
1374
- function decodeTurnProcess(signature) {
1375
- const [turn, controlAnchorSeq, processStartSeq, answerAnchorSeq, answerStep, inlineReasoning, messageCount, toolCallCount, subagentCount] = signature.split("|");
1376
- return {
1377
- turn: Number(turn),
1378
- controlAnchorSeq: Number(controlAnchorSeq),
1379
- processStartSeq: Number(processStartSeq),
1380
- answerAnchorSeq: answerAnchorSeq === "" ? null : Number(answerAnchorSeq),
1381
- answerStep: answerStep === "" ? null : Number(answerStep),
1382
- inlineReasoning: inlineReasoning === "1",
1383
- messageCount: Number(messageCount),
1384
- toolCallCount: Number(toolCallCount),
1385
- subagentCount: Number(subagentCount)
1386
- };
1351
+ function sameTurnProcessSpec(left, right) {
1352
+ return left.turn === right.turn && left.controlAnchorSeq === right.controlAnchorSeq && left.processStartSeq === right.processStartSeq && left.answerAnchorSeq === right.answerAnchorSeq && left.answerStep === right.answerStep && left.inlineReasoning === right.inlineReasoning && left.messageCount === right.messageCount && left.toolCallCount === right.toolCallCount && left.subagentCount === right.subagentCount;
1387
1353
  }
1388
1354
  /**
1389
1355
  * Recognize the shipped subagent delegation name and its configured variants.
@@ -1398,7 +1364,7 @@ window.__ModuleLoader__.load({
1398
1364
  //#region lib/types/client/stores.js
1399
1365
  /** Per-Session Chat selection store shared by the transcript and details panel. */
1400
1366
  /**
1401
- * Resolve any stored generation for one Turn.
1367
+ * Resolve the manually expanded answer for one Turn.
1402
1368
  * @param state - Chat store snapshot.
1403
1369
  * @param turn - owning Turn.
1404
1370
  * @returns the Turn's stored entry, when present.
@@ -1420,7 +1386,7 @@ window.__ModuleLoader__.load({
1420
1386
  select: (draft, target) => {
1421
1387
  draft.selection = target;
1422
1388
  },
1423
- setTurnProcessOpen: (draft, turn, generation, open) => {
1389
+ setTurnProcessOpen: (draft, turn, answerStep, open) => {
1424
1390
  const index = draft.turnProcesses.findIndex((entry) => entry.turn === turn);
1425
1391
  if (!open) {
1426
1392
  if (index >= 0) draft.turnProcesses.splice(index, 1);
@@ -1428,7 +1394,7 @@ window.__ModuleLoader__.load({
1428
1394
  }
1429
1395
  const next = {
1430
1396
  turn,
1431
- generation
1397
+ answerStep
1432
1398
  };
1433
1399
  if (index < 0) draft.turnProcesses.push(next);
1434
1400
  else draft.turnProcesses[index] = next;
@@ -1468,7 +1434,7 @@ window.__ModuleLoader__.load({
1468
1434
  }
1469
1435
  //#endregion
1470
1436
  //#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/chat/ChatView.module.css.mjs
1471
- const css$11 = ".fnEpAq_root{flex-direction:column;flex:auto;min-height:0;display:flex;position:relative}.fnEpAq_scroll{min-height:0;padding:16px calc(var(--dsh-composer-side-clearance) + 16px);flex:auto;overflow-y:auto;container-type:inline-size}[data-conversation-scroll] .fnEpAq_root{flex:none;height:auto;min-height:auto}[data-conversation-scroll] .fnEpAq_scroll{flex:none;min-height:auto;overflow:visible}.fnEpAq_column{max-width:var(--dsh-chat-content-width);flex-direction:column;width:100%;margin:0 auto;display:flex}.fnEpAq_column>:not([hidden]):not(.fnEpAq_flowItem:empty)~:not([hidden]):not(.fnEpAq_flowItem:empty){margin-top:var(--dsh-chat-flow-gap,16px)}.fnEpAq_flowItem{min-width:0}.fnEpAq_flowItem[data-turn-process-answer]{--dsh-chat-flow-gap:8px}.fnEpAq_flowItem:empty{display:none}.fnEpAq_callRow{border-radius:6px}.fnEpAq_turnStatus{height:calc(26px + var(--dsh-content-font-delta,0px));font:var(--dsw-font-s-strong-14);font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px));white-space:nowrap;background:linear-gradient(90deg, var(--dsw-static-deepseek-500) 0%, var(--dsw-static-deepseek-500) 40%, var(--dsw-static-deepseek-200) 50%, var(--dsw-static-deepseek-500) 60%, var(--dsw-static-deepseek-500) 100%);color:#0000;-webkit-text-fill-color:transparent;background-position:100% 0;background-size:250% 100%;-webkit-background-clip:text;background-clip:text;flex:none;align-self:flex-start;align-items:center;animation:1.8s linear infinite fnEpAq_dsh-turn-status-shimmer;display:inline-flex}.fnEpAq_turnStatusClock{font:var(--dsw-font-xs-13);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-caption);-webkit-text-fill-color:var(--dsw-alias-label-caption);margin-left:8px;font-weight:400}@keyframes fnEpAq_dsh-turn-status-shimmer{to{background-position:0 0}}@media (prefers-reduced-motion:reduce){.fnEpAq_turnStatus{background-position:0 0;background-size:100% 100%;animation:none}}.fnEpAq_hint{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(18px + var(--dsh-content-font-delta-secondary,0px))}.fnEpAq_openError{color:var(--dsw-alias-state-error-primary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(18px + var(--dsh-content-font-delta-secondary,0px))}.fnEpAq_older{justify-content:center;display:flex}.fnEpAq_older button{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover-solid);cursor:pointer;border:none;border-radius:14px;padding:4px 12px;font-size:12px}.fnEpAq_older button:disabled{cursor:default;opacity:.6}.fnEpAq_toBottomSlot{z-index:8;height:0;padding-right:max(0px, calc((100% - var(--dsh-chat-content-width)) / 2));pointer-events:none;justify-content:flex-end;display:flex;position:sticky;bottom:16px}[data-conversation-scroll] .fnEpAq_toBottomSlot{bottom:calc(var(--dsh-composer-height,152px) + 16px)}.fnEpAq_toBottom{border:1px solid var(--dsw-alias-border-l2);width:34px;height:34px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-button-floating-fill);box-shadow:var(--dsw-shadow-lv2);cursor:pointer;pointer-events:auto;border-radius:100px;justify-content:center;align-items:center;margin-top:-34px;padding:0;display:flex}.fnEpAq_toBottom:hover{background:var(--dsw-alias-button-floating-hover)}.fnEpAq_modalAction{min-width:72px}";
1437
+ const css$11 = ".fnEpAq_root{flex-direction:column;flex:auto;min-height:0;display:flex;position:relative}.fnEpAq_scroll{min-height:0;padding:16px calc(var(--dsh-composer-side-clearance) + 16px);flex:auto;overflow-y:auto;container-type:inline-size}[data-conversation-scroll] .fnEpAq_root{flex:none;height:auto;min-height:auto}[data-conversation-scroll] .fnEpAq_scroll{flex:none;min-height:auto;overflow:visible}.fnEpAq_column{max-width:var(--dsh-chat-content-width);flex-direction:column;width:100%;margin:0 auto;display:flex}.fnEpAq_column>:not([hidden]):not(.fnEpAq_flowItem:empty)~:not([hidden]):not(.fnEpAq_flowItem:empty){margin-top:var(--dsh-chat-flow-gap,16px)}.fnEpAq_flowItem{min-width:0}.fnEpAq_flowItem[data-turn-process-answer]{--dsh-chat-flow-gap:8px}.fnEpAq_flowItem:empty{display:none}.fnEpAq_callRow{border-radius:6px}.fnEpAq_turnStatus{height:calc(26px + var(--dsh-content-font-delta,0px));font:var(--dsw-font-s-strong-14);font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px));white-space:nowrap;background:linear-gradient(90deg, var(--dsw-static-deepseek-500) 0%, var(--dsw-static-deepseek-500) 40%, var(--dsw-static-deepseek-200) 50%, var(--dsw-static-deepseek-500) 60%, var(--dsw-static-deepseek-500) 100%);color:#0000;-webkit-text-fill-color:transparent;background-position:100% 0;background-size:250% 100%;-webkit-background-clip:text;background-clip:text;flex:none;align-self:flex-start;align-items:center;animation:1.8s linear infinite fnEpAq_dsh-turn-status-shimmer;display:inline-flex}.fnEpAq_turnStatusClock{font:var(--dsw-font-xs-13);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-caption);-webkit-text-fill-color:var(--dsw-alias-label-caption);margin-left:8px;font-weight:400}@keyframes fnEpAq_dsh-turn-status-shimmer{to{background-position:0 0}}@media (prefers-reduced-motion:reduce){.fnEpAq_turnStatus{background-position:0 0;background-size:100% 100%;animation:none}}.fnEpAq_hint{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(18px + var(--dsh-content-font-delta-secondary,0px))}.fnEpAq_openError{color:var(--dsw-alias-state-error-primary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(18px + var(--dsh-content-font-delta-secondary,0px))}.fnEpAq_older{justify-content:center;display:flex}.fnEpAq_older button{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover-solid);cursor:pointer;border:none;border-radius:14px;padding:4px 12px;font-size:12px}.fnEpAq_older button:disabled{cursor:default;opacity:.6}.fnEpAq_toBottomSlot{z-index:8;height:0;padding-right:max(0px, calc((100% - var(--dsh-chat-content-width)) / 2));pointer-events:none;justify-content:flex-end;display:flex;position:sticky;bottom:16px}[data-conversation-scroll] .fnEpAq_toBottomSlot{bottom:calc(var(--dsh-composer-height,152px) + 16px)}.fnEpAq_toBottom{--dsw-elevation-stroke-color:var(--dsw-alias-border-l3);corner-shape:round;width:34px;height:34px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-button-floating-fill);box-shadow:var(--dsw-elevation-panel);cursor:pointer;pointer-events:auto;border:0;border-radius:100px;justify-content:center;align-items:center;margin-top:-34px;padding:0;display:flex}.fnEpAq_toBottom:hover{background:var(--dsw-alias-button-floating-hover)}.fnEpAq_modalAction{min-width:72px}";
1472
1438
  const tagId$11 = "@prettier-ai/dsh-client-ui-chat/ChatView.module.css";
1473
1439
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$11) + "]") === null) {
1474
1440
  const tag = document.createElement("style");
@@ -1495,85 +1461,44 @@ window.__ModuleLoader__.load({
1495
1461
  };
1496
1462
  //#endregion
1497
1463
  //#region lib/types/client/chat/ChatNodeSeat.js
1498
- const EMPTY_PROCESS_KEYS = [];
1499
- function turnProcessOpeningHumanAnchor(keys, nodes, spec) {
1500
- let anchor;
1501
- for (const key of keys) {
1502
- const node = nodes.get(key);
1503
- if ((node?.kind === "user" || node?.kind === "steering") && node.anchorSeq < spec.controlAnchorSeq) anchor = Math.min(anchor ?? node.anchorSeq, node.anchorSeq);
1504
- }
1505
- return anchor;
1464
+ function turnDataOf(node) {
1465
+ const location = node?.location;
1466
+ return location?.kind === "turn" || location?.kind === "step" ? location.turn.data : void 0;
1506
1467
  }
1507
- /** Derive disclosure facts from one content-revisioned Turn index. */
1508
- function turnProcessLayout(keys, nodes, spec) {
1509
- let hasExternalProcess = false;
1510
- let compactAnswer = true;
1511
- const openingHumanAnchor = turnProcessOpeningHumanAnchor(keys, nodes, spec);
1512
- for (const key of keys) {
1513
- const node = nodes.get(key);
1514
- if (node === void 0 || node.kind === "turn-process") continue;
1515
- if ((node.kind === "user" || node.kind === "steering") && (openingHumanAnchor === void 0 || node.anchorSeq > openingHumanAnchor) && (spec.answerAnchorSeq === null || node.anchorSeq < spec.answerAnchorSeq)) compactAnswer = false;
1516
- if (TURN_PROCESS_INDEPENDENT_KINDS.has(node.kind) || node.anchorSeq < spec.processStartSeq || spec.answerAnchorSeq !== null && node.anchorSeq >= spec.answerAnchorSeq) continue;
1517
- if (node.kind !== "assistant-step" || spec.answerStep === null || node.data.step !== spec.answerStep) hasExternalProcess = true;
1518
- }
1519
- return {
1520
- hasExternalProcess,
1521
- compactAnswer
1522
- };
1468
+ function turnOf(node) {
1469
+ const location = node?.location;
1470
+ return location?.kind === "turn" || location?.kind === "step" ? location.turn.turn : void 0;
1523
1471
  }
1524
1472
  /** Subscribe, apply Turn-process visibility, and dispatch one stable Context key. */
1525
- const ChatNodeSeat = (0, react.memo)(function ChatNodeSeat({ nodeKey, historyIncomplete, compactTranscript, selectedCallId, cwd, openFile, inspectCall, forkAt, renderMessageImages, fileMentions, useChat, useStore, actions, renderSlot, t }) {
1526
- const node = useChat((snapshot) => snapshot.nodes.get(nodeKey));
1527
- const processSignature = useChat((snapshot) => {
1528
- const location = snapshot.nodes.get(nodeKey)?.location;
1529
- return location?.kind === "turn" || location?.kind === "step" ? location.turn.data.get("turn-process") : void 0;
1530
- });
1531
- const processSpec = (0, react.useMemo)(() => processSignature === void 0 ? void 0 : decodeTurnProcess(processSignature), [processSignature]);
1532
- const nodeStore = useChat((snapshot) => snapshot.nodes);
1533
- const processLayoutKeys = useChat((snapshot) => {
1534
- if (!compactTranscript || historyIncomplete || processSpec === void 0) return EMPTY_PROCESS_KEYS;
1535
- const current = snapshot.nodes.get(nodeKey);
1536
- const location = current?.location;
1537
- if (current === void 0 || location?.kind !== "turn" && location?.kind !== "step" || location.turn.status !== "closed" || location.turn.turn !== processSpec.turn) return EMPTY_PROCESS_KEYS;
1538
- return current.kind === "turn-process" || current.kind === "assistant-step" && current.data.step === processSpec.answerStep ? snapshot.locations.getTurn(processSpec.turn) : EMPTY_PROCESS_KEYS;
1539
- });
1540
- const processLayout = (0, react.useMemo)(() => processSpec === void 0 || processLayoutKeys.length === 0 ? void 0 : turnProcessLayout(processLayoutKeys, nodeStore, processSpec), [
1541
- nodeStore,
1542
- processLayoutKeys,
1543
- processSpec
1544
- ]);
1545
- const processGeneration = (0, react.useMemo)(() => processSpec === void 0 ? void 0 : turnProcessGeneration(processSpec), [processSpec]);
1473
+ const ChatNodeSeat = (0, react.memo)(function ChatNodeSeat({ nodeKey, useChatNode, useChatNodeProcess, historyIncomplete, compactTranscript, selectedCallId, cwd, openFile, inspectCall, forkAt, renderMessageImages, fileMentions, useStore, actions, renderSlot, t }) {
1474
+ const node = useChatNode(nodeKey);
1475
+ const routedNode = node;
1476
+ const turn = turnOf(routedNode);
1477
+ const processPresentation = useChatNodeProcess(nodeKey);
1478
+ const processSpec = processPresentation?.spec;
1546
1479
  const storedEntry = useStore((state) => processSpec === void 0 ? void 0 : storedTurnProcessEntry(state, processSpec.turn));
1547
- const processOpen = (storedEntry?.generation === processGeneration ? storedEntry : void 0) !== void 0;
1480
+ const processOpen = (processSpec !== void 0 && processSpec.answerStep !== null && storedEntry?.answerStep === processSpec.answerStep ? storedEntry : void 0) !== void 0;
1548
1481
  const setOpen = (0, react.useCallback)((open) => {
1549
- if (processGeneration !== void 0 && processSpec !== void 0) actions.setTurnProcessOpen(processSpec.turn, processGeneration, open);
1550
- }, [
1551
- actions,
1552
- processGeneration,
1553
- processSpec
1554
- ]);
1555
- const routedNode = node;
1556
- const sameTurn = routedNode !== void 0 && processSpec !== void 0 && (routedNode.location.kind === "turn" || routedNode.location.kind === "step") && routedNode.location.turn.turn === processSpec.turn;
1557
- const turnClosed = sameTurn && routedNode.location.turn.status === "closed";
1558
- const processWindowReady = processSpec !== void 0 && compactTranscript && processSpec.answerAnchorSeq !== null && turnClosed && !historyIncomplete;
1559
- const processMember = sameTurn && processWindowReady && !TURN_PROCESS_INDEPENDENT_KINDS.has(routedNode.kind) && routedNode.anchorSeq >= processSpec.processStartSeq && routedNode.anchorSeq < processSpec.answerAnchorSeq;
1560
- const processAnswer = sameTurn && processWindowReady && routedNode.kind === "assistant-step" && routedNode.data.step === processSpec.answerStep;
1482
+ if (processSpec !== void 0 && processSpec.answerStep !== null) actions.setTurnProcessOpen(processSpec.turn, processSpec.answerStep, open);
1483
+ }, [actions, processSpec]);
1484
+ const processWindowReady = processSpec !== void 0 && processPresentation !== void 0 && compactTranscript && processSpec.answerAnchorSeq !== null && processPresentation.turn === processSpec.turn && processPresentation.turnClosed && !historyIncomplete;
1485
+ const processMember = routedNode !== void 0 && processWindowReady && !TURN_PROCESS_INDEPENDENT_KINDS.has(routedNode.kind) && routedNode.anchorSeq >= processSpec.processStartSeq && routedNode.anchorSeq < processSpec.answerAnchorSeq;
1486
+ const processAnswer = routedNode !== void 0 && processWindowReady && routedNode.kind === "assistant-step" && routedNode.data.step === processSpec.answerStep;
1561
1487
  const ownsDisclosure = routedNode?.kind === "turn-process" || processAnswer;
1562
- const foldable = processWindowReady && (processMember || ownsDisclosure && ((processLayout?.hasExternalProcess ?? false) || processSpec.inlineReasoning));
1563
- const turnProcess = (0, react.useMemo)(() => processGeneration === void 0 || processSpec === void 0 ? void 0 : {
1488
+ const foldable = processWindowReady && (processMember || ownsDisclosure && (processPresentation.hasExternalProcess || processSpec.inlineReasoning));
1489
+ const turnProcess = (0, react.useMemo)(() => processSpec === void 0 ? void 0 : {
1564
1490
  spec: processSpec,
1565
1491
  foldable,
1566
1492
  open: processOpen,
1567
1493
  setOpen
1568
1494
  }, [
1569
1495
  foldable,
1570
- processGeneration,
1571
1496
  processOpen,
1572
1497
  processSpec,
1573
1498
  setOpen
1574
1499
  ]);
1575
1500
  const controllerInactive = routedNode?.kind === "turn-process" && !foldable;
1576
- const compactAnswer = processAnswer && foldable && processLayout?.compactAnswer === true && !processOpen;
1501
+ const compactAnswer = processAnswer && foldable && processPresentation.compactAnswer && !processOpen;
1577
1502
  const processHidden = controllerInactive || foldable && processMember && !processOpen;
1578
1503
  const wrapperRef = useSearchableHidden(processHidden, (0, react.useCallback)(() => {
1579
1504
  if (processMember) setOpen(true);
@@ -1599,8 +1524,7 @@ window.__ModuleLoader__.load({
1599
1524
  turnProcess
1600
1525
  ]);
1601
1526
  if (routedNode === void 0 || owner === null) return null;
1602
- const location = routedNode.location;
1603
- const turn = location.kind === "turn" || location.kind === "step" ? location.turn.turn : void 0;
1527
+ const turnData = turnDataOf(routedNode);
1604
1528
  const routedOwner = {
1605
1529
  ...owner,
1606
1530
  node: routedNode
@@ -1617,7 +1541,7 @@ window.__ModuleLoader__.load({
1617
1541
  "data-turn-process-answer": compactAnswer || void 0,
1618
1542
  children: renderSlot("conversation.chat.node", routedOwner, {
1619
1543
  entryKey: routedNode.kind,
1620
- hookContext: nodeKey,
1544
+ hookContext: turnData,
1621
1545
  fallback: (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.JsonBlock, {
1622
1546
  label: t("message.unknownSurface", { type: routedNode.kind }),
1623
1547
  payload: routedNode.data,
@@ -1628,7 +1552,7 @@ window.__ModuleLoader__.load({
1628
1552
  });
1629
1553
  //#endregion
1630
1554
  //#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/chat/TurnNavigator.module.css.mjs
1631
- const css$10 = ".alqd3G_slot{z-index:6;pointer-events:none;height:0;position:sticky;top:0}.alqd3G_frame{--turn-rail-band:calc(var(--dsh-conversation-viewport-height,100dvh) - var(--dsh-composer-height,152px));--turn-preview-height:100px;top:calc(var(--turn-rail-band) / 2);right:calc(12px - (var(--dsh-composer-side-clearance) + 16px));width:28px;height:min(var(--turn-natural-height), max(0px, calc(var(--turn-rail-band) - 64px)), 420px);cursor:pointer;pointer-events:auto;transition:height .22s cubic-bezier(.2,.8,.2,1);position:absolute;transform:translateY(-50%)}.alqd3G_scroller{overscroll-behavior:contain;scrollbar-width:none;position:absolute;inset:0;overflow-y:auto}.alqd3G_scroller::-webkit-scrollbar{display:none}.alqd3G_fadeTop{mask-image:linear-gradient(#0000 0,#000 24px 100%)}.alqd3G_fadeBottom{mask-image:linear-gradient(#000 0 calc(100% - 24px),#0000 100%)}.alqd3G_fadeTop.alqd3G_fadeBottom{mask-image:linear-gradient(#0000 0,#000 24px calc(100% - 24px),#0000 100%)}.alqd3G_marks{height:var(--turn-natural-height);position:relative}.alqd3G_markPosition{top:calc(var(--turn-natural-position) + var(--turn-rail-inset));height:10px;transition:top .22s cubic-bezier(.2,.8,.2,1);animation:.15s ease-out alqd3G_dsh-turn-mark-enter;position:absolute;left:0;right:0;transform:translateY(-50%)}.alqd3G_mark{cursor:pointer;pointer-events:none;background:0 0;border:0;border-radius:8px;width:20px;padding:0;position:absolute;inset:0 0 0 auto}.alqd3G_mark:before{background:var(--dsw-alias-border-l4);content:\"\";border-radius:2px;width:12px;height:2px;transition:width .14s,background-color .14s;position:absolute;top:50%;right:0;transform:translateY(-50%)}.alqd3G_markUnloaded:before{opacity:.6;width:8px}.alqd3G_markPreview:before{background:var(--dsw-alias-label-tertiary);width:18px}.alqd3G_markBusy:before{animation:1s ease-in-out infinite alqd3G_dsh-turn-mark-busy}.alqd3G_markActive:before{background:var(--dsw-alias-label-primary);width:20px}.alqd3G_mark:focus-visible:before{background:var(--dsw-alias-state-business-primary);width:20px}.alqd3G_mark:focus-visible{outline:1px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.alqd3G_preview{top:clamp(0px, calc(var(--turn-natural-position) + var(--turn-rail-inset) - var(--turn-scroll-top,0px) - var(--turn-preview-height) / 2), calc(100% - var(--turn-preview-height)));box-sizing:border-box;width:min(300px,100cqw - 120px);max-height:var(--turn-preview-height);border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);box-shadow:var(--dsw-shadow-lv2);pointer-events:none;border-radius:10px;padding:10px 12px;transition:top .14s cubic-bezier(.2,.8,.2,1);animation:.12s ease-out alqd3G_dsh-turn-preview-enter;position:absolute;right:calc(100% + 10px);overflow:hidden}.alqd3G_previewPrompt,.alqd3G_previewResponse{-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.alqd3G_previewPrompt{font:var(--dsw-font-xs-strong-13);-webkit-line-clamp:1}.alqd3G_previewResponse{color:var(--dsw-alias-label-caption);font:var(--dsw-font-xxs-12);-webkit-line-clamp:3;margin-top:4px}@keyframes alqd3G_dsh-turn-mark-enter{0%{opacity:0}to{opacity:1}}@keyframes alqd3G_dsh-turn-preview-enter{0%{opacity:0;transform:translate(4px)}to{opacity:1;transform:translate(0)}}@keyframes alqd3G_dsh-turn-mark-busy{0%,to{opacity:1}50%{opacity:.35}}@container (width<=900px){.alqd3G_slot{display:none}}@media (prefers-reduced-motion:reduce){.alqd3G_frame,.alqd3G_scroller,.alqd3G_markPosition,.alqd3G_mark:before,.alqd3G_markBusy:before,.alqd3G_preview{scroll-behavior:auto;transition:none;animation:none}}";
1555
+ const css$10 = ".alqd3G_slot{z-index:7;pointer-events:none;height:0;position:sticky;top:0}.alqd3G_frame{--turn-rail-band:calc(var(--dsh-conversation-viewport-height,100dvh) - var(--dsh-composer-height,152px));--turn-preview-height:100px;top:calc(var(--turn-rail-band) / 2);right:calc(12px - (var(--dsh-composer-side-clearance) + 16px));width:28px;height:min(var(--turn-natural-height), max(0px, calc(var(--turn-rail-band) - 64px)), 420px);cursor:pointer;pointer-events:auto;transition:height .22s cubic-bezier(.2,.8,.2,1);position:absolute;transform:translateY(-50%)}.alqd3G_scroller{overscroll-behavior:contain;scrollbar-width:none;position:absolute;inset:0;overflow-y:auto}.alqd3G_scroller::-webkit-scrollbar{display:none}.alqd3G_fadeTop{mask-image:linear-gradient(#0000 0,#000 24px 100%)}.alqd3G_fadeBottom{mask-image:linear-gradient(#000 0 calc(100% - 24px),#0000 100%)}.alqd3G_fadeTop.alqd3G_fadeBottom{mask-image:linear-gradient(#0000 0,#000 24px calc(100% - 24px),#0000 100%)}.alqd3G_marks{height:var(--turn-natural-height);position:relative}.alqd3G_markPosition{top:calc(var(--turn-natural-position) + var(--turn-rail-inset));height:10px;transition:top .22s cubic-bezier(.2,.8,.2,1);animation:.15s ease-out alqd3G_dsh-turn-mark-enter;position:absolute;left:0;right:0;transform:translateY(-50%)}.alqd3G_mark{cursor:pointer;pointer-events:none;background:0 0;border:0;border-radius:8px;width:20px;padding:0;position:absolute;inset:0 0 0 auto}.alqd3G_mark:before{background:var(--dsw-alias-border-l4);content:\"\";border-radius:2px;width:12px;height:2px;transition:width .14s,background-color .14s;position:absolute;top:50%;right:0;transform:translateY(-50%)}.alqd3G_markUnloaded:before{opacity:.6;width:8px}.alqd3G_markPreview:before{background:var(--dsw-alias-label-tertiary);width:18px}.alqd3G_markBusy:before{animation:1s ease-in-out infinite alqd3G_dsh-turn-mark-busy}.alqd3G_markActive:before{background:var(--dsw-alias-label-primary);width:20px}.alqd3G_mark:focus-visible:before{background:var(--dsw-alias-state-business-primary);width:20px}.alqd3G_mark:focus-visible{outline:1px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.alqd3G_preview{top:clamp(0px, calc(var(--turn-natural-position) + var(--turn-rail-inset) - var(--turn-scroll-top,0px) - var(--turn-preview-height) / 2), calc(100% - var(--turn-preview-height)));box-sizing:border-box;width:min(300px,100cqw - 120px);max-height:var(--turn-preview-height);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);box-shadow:var(--dsw-elevation-panel);pointer-events:none;border:0;border-radius:10px;padding:10px 12px;transition:top .14s cubic-bezier(.2,.8,.2,1);animation:.12s ease-out alqd3G_dsh-turn-preview-enter;position:absolute;right:calc(100% + 10px);overflow:hidden}.alqd3G_previewPrompt,.alqd3G_previewResponse{-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.alqd3G_previewPrompt{font:var(--dsw-font-xs-strong-13);-webkit-line-clamp:1}.alqd3G_previewResponse{color:var(--dsw-alias-label-caption);font:var(--dsw-font-xxs-12);-webkit-line-clamp:3;margin-top:4px}@keyframes alqd3G_dsh-turn-mark-enter{0%{opacity:0}to{opacity:1}}@keyframes alqd3G_dsh-turn-preview-enter{0%{opacity:0;transform:translate(4px)}to{opacity:1;transform:translate(0)}}@keyframes alqd3G_dsh-turn-mark-busy{0%,to{opacity:1}50%{opacity:.35}}@container (width<=900px){.alqd3G_slot{display:none}}@media (prefers-reduced-motion:reduce){.alqd3G_frame,.alqd3G_scroller,.alqd3G_markPosition,.alqd3G_mark:before,.alqd3G_markBusy:before,.alqd3G_preview{scroll-behavior:auto;transition:none;animation:none}}";
1632
1556
  const tagId$10 = "@prettier-ai/dsh-client-ui-chat/TurnNavigator.module.css";
1633
1557
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$10) + "]") === null) {
1634
1558
  const tag = document.createElement("style");
@@ -1836,6 +1760,27 @@ window.__ModuleLoader__.load({
1836
1760
  */
1837
1761
  const TurnNavigator = (0, react.memo)(TurnNavigatorRail);
1838
1762
  //#endregion
1763
+ //#region ../../util/brand/src/index.ts
1764
+ /**
1765
+ * Apply a compile-time number brand without changing the value.
1766
+ * @param value - number admitted by the domain that owns the target brand.
1767
+ * @returns the same number with the requested compile-time brand.
1768
+ */
1769
+ function brandNumber(value) {
1770
+ return value;
1771
+ }
1772
+ //#endregion
1773
+ //#region ../../core/session/src/types.ts
1774
+ /**
1775
+ * Admit a numeric value as an existing Session event position.
1776
+ * @param value - non-negative safe integer admitted by the owning log operation.
1777
+ * @returns the same number with the Session-sequence brand.
1778
+ */
1779
+ function SessionSeq(value) {
1780
+ if (!Number.isSafeInteger(value) || value < 0 || Object.is(value, -0)) throw new TypeError(`SessionSeq must be a non-negative safe integer, got ${String(value)}`);
1781
+ return brandNumber(value);
1782
+ }
1783
+ //#endregion
1839
1784
  //#region lib/types/client/chat/turn-rail-items.js
1840
1785
  /**
1841
1786
  * View-layer union of the host turn outline and the loaded rail items. The
@@ -1856,10 +1801,10 @@ window.__ModuleLoader__.load({
1856
1801
  if (typeof value !== "object" || value === null) return void 0;
1857
1802
  const entry = value;
1858
1803
  if (typeof entry.turn !== "number" || !Number.isSafeInteger(entry.turn) || entry.turn < 0) return void 0;
1859
- if (typeof entry.seq !== "number" || !Number.isSafeInteger(entry.seq) || entry.seq < 0) return void 0;
1804
+ if (typeof entry.seq !== "number" || !Number.isSafeInteger(entry.seq) || entry.seq < 0 || Object.is(entry.seq, -0)) return void 0;
1860
1805
  return {
1861
1806
  turn: entry.turn,
1862
- seq: entry.seq,
1807
+ seq: SessionSeq(entry.seq),
1863
1808
  prompt: typeof entry.prompt === "string" ? entry.prompt : "",
1864
1809
  response: typeof entry.response === "string" ? entry.response : ""
1865
1810
  };
@@ -1910,6 +1855,7 @@ window.__ModuleLoader__.load({
1910
1855
  }
1911
1856
  //#endregion
1912
1857
  //#region lib/types/client/chat/ChatView.js
1858
+ const SCROLL_SAMPLE_INTERVAL_MS = 500;
1913
1859
  /** Active column host when present; otherwise the view-local scroller. */
1914
1860
  function scrollerOf(from) {
1915
1861
  return from.closest("[data-conversation-scroll]") ?? from;
@@ -2042,11 +1988,17 @@ window.__ModuleLoader__.load({
2042
1988
  })]
2043
1989
  });
2044
1990
  }
1991
+ const ChatNodeList = (0, react.memo)(function ChatNodeList({ order, ...seatProps }) {
1992
+ return order.map((nodeKey) => (0, react_jsx_runtime.jsx)(ChatNodeSeat, {
1993
+ nodeKey,
1994
+ ...seatProps
1995
+ }, nodeKey));
1996
+ });
2045
1997
  /**
2046
1998
  * The chat view slot entry: pure component over the composed props; each
2047
1999
  * ordered business Node crosses the keyed renderer seat.
2048
2000
  */
2049
- function ChatView({ useSession, useChat, useSessions, useStore, actions, renderSlot, sessionId, openFile, loadOlder, loadThrough, loadImage, openView, chatScroll, forkAt, fileMentions, useTranscriptView, useProjection, t }) {
2001
+ function ChatView({ useSession, useChat, useChatNode, useChatNodeProcess, useSessions, useStore, actions, renderSlot, sessionId, openFile, loadOlder, loadThrough, loadImage, openView, chatScroll, forkAt, fileMentions, useTranscriptView, useProjection, t }) {
2050
2002
  const order = useChat((s) => s.order);
2051
2003
  const nodeStore = useChat((s) => s.nodes);
2052
2004
  const turnNavigationItems = useChat((s) => s.navigation.items());
@@ -2110,6 +2062,8 @@ window.__ModuleLoader__.load({
2110
2062
  const columnRef = (0, react.useRef)(null);
2111
2063
  const [atBottom, setAtBottom] = (0, react.useState)(() => chatScroll.read() === null);
2112
2064
  const atBottomRef = (0, react.useRef)(atBottom);
2065
+ const scrollSamplePendingRef = (0, react.useRef)(false);
2066
+ const [, setScrollSampleTick] = (0, react.useState)(0);
2113
2067
  const [activeTurn, setActiveTurn] = (0, react.useState)(() => turnNavigationItems.at(-1)?.turn ?? null);
2114
2068
  /** Last position delivered or written on the main thread. */
2115
2069
  const observedTopRef = (0, react.useRef)(0);
@@ -2142,6 +2096,7 @@ window.__ModuleLoader__.load({
2142
2096
  const lastSubmissionId = visibleSubmissions[visibleSubmissions.length - 1]?.requestId ?? null;
2143
2097
  const followSig = `${openState}:${firstSeq}:${lastKey}:${order.length}:${running ? 1 : 0}:${lastSteeringId ?? ""}:${lastSubmissionId ?? ""}`;
2144
2098
  const syncActiveTurn = (0, react.useCallback)(() => {
2099
+ if (scrollSamplePendingRef.current) return;
2145
2100
  const local = listRef.current;
2146
2101
  const first = turnNavigationItems[0];
2147
2102
  if (local === null || first === void 0) {
@@ -2238,6 +2193,7 @@ window.__ModuleLoader__.load({
2238
2193
  return true;
2239
2194
  };
2240
2195
  (0, react.useLayoutEffect)(() => {
2196
+ if (scrollSamplePendingRef.current) return;
2241
2197
  const local = listRef.current;
2242
2198
  /* v8 ignore next -- ref-null guard: React attaches the ref before layout effects run. */
2243
2199
  if (local === null) return;
@@ -2329,16 +2285,31 @@ window.__ModuleLoader__.load({
2329
2285
  /* v8 ignore next -- ref-null guard: effect runs after the list node commits. */
2330
2286
  if (local === null) return;
2331
2287
  const el = scrollerOf(local);
2332
- const onScroll = () => {
2288
+ let sampleTimer;
2289
+ const sample = () => {
2290
+ if (!scrollSamplePendingRef.current) return;
2291
+ scrollSamplePendingRef.current = false;
2292
+ if (sampleTimer !== void 0) window.clearTimeout(sampleTimer);
2293
+ sampleTimer = void 0;
2333
2294
  onScrollRef.current();
2295
+ setScrollSampleTick((tick) => tick + 1);
2296
+ };
2297
+ const onScroll = () => {
2298
+ scrollSamplePendingRef.current = true;
2299
+ sampleTimer ??= window.setTimeout(sample, SCROLL_SAMPLE_INTERVAL_MS);
2334
2300
  };
2335
2301
  el.addEventListener("scroll", onScroll, { passive: true });
2302
+ el.addEventListener("scrollend", sample, { passive: true });
2336
2303
  return () => {
2337
2304
  el.removeEventListener("scroll", onScroll);
2305
+ el.removeEventListener("scrollend", sample);
2306
+ if (sampleTimer !== void 0) window.clearTimeout(sampleTimer);
2307
+ scrollSamplePendingRef.current = false;
2338
2308
  };
2339
2309
  }, []);
2340
2310
  const followRef = (0, react.useRef)(null);
2341
2311
  followRef.current = () => {
2312
+ if (scrollSamplePendingRef.current) return;
2342
2313
  const local = listRef.current;
2343
2314
  if (local !== null && atBottomRef.current) {
2344
2315
  const el = scrollerOf(local);
@@ -2484,11 +2455,12 @@ window.__ModuleLoader__.load({
2484
2455
  children: loadingOlder ? t("loading") : t("chat.loadOlder")
2485
2456
  })
2486
2457
  }),
2487
- order.map((nodeKey) => (0, react_jsx_runtime.jsx)(ChatNodeSeat, {
2488
- nodeKey,
2458
+ (0, react_jsx_runtime.jsx)(ChatNodeList, {
2459
+ order,
2460
+ useChatNode,
2461
+ useChatNodeProcess,
2489
2462
  historyIncomplete: hasMore,
2490
2463
  compactTranscript,
2491
- useChat,
2492
2464
  useStore,
2493
2465
  actions,
2494
2466
  selectedCallId,
@@ -2500,7 +2472,7 @@ window.__ModuleLoader__.load({
2500
2472
  fileMentions,
2501
2473
  renderSlot,
2502
2474
  t
2503
- }, nodeKey)),
2475
+ }),
2504
2476
  running && (0, react_jsx_runtime.jsx)(TurnStatus, {
2505
2477
  startTime: runningTurnStart,
2506
2478
  t
@@ -2798,40 +2770,6 @@ window.__ModuleLoader__.load({
2798
2770
  "clock.ymd": "{y}-{m}-{d}"
2799
2771
  };
2800
2772
  //#endregion
2801
- //#region lib/types/client/chat/use-throttled-visual-update.js
2802
- /** Frame-throttled scheduling for non-essential visual alignment. */
2803
- const DEFAULT_INTERVAL_FRAMES = 3;
2804
- /**
2805
- * Return a stable scheduler that coalesces visual updates over a frame interval.
2806
- * @param update - DOM alignment to run after the throttle interval.
2807
- * @param intervalFrames - frames to wait before applying the latest alignment.
2808
- * @returns a stable function that schedules the latest update.
2809
- */
2810
- function useThrottledVisualUpdate(update, intervalFrames = DEFAULT_INTERVAL_FRAMES) {
2811
- const updateRef = (0, react.useRef)(update);
2812
- updateRef.current = update;
2813
- const pendingFrameRef = (0, react.useRef)(null);
2814
- (0, react.useLayoutEffect)(() => () => {
2815
- if (pendingFrameRef.current === null) return;
2816
- cancelAnimationFrame(pendingFrameRef.current);
2817
- pendingFrameRef.current = null;
2818
- }, []);
2819
- return (0, react.useCallback)(() => {
2820
- if (pendingFrameRef.current !== null) return;
2821
- let remainingFrames = intervalFrames;
2822
- const advance = () => {
2823
- remainingFrames -= 1;
2824
- if (remainingFrames > 0) {
2825
- pendingFrameRef.current = requestAnimationFrame(advance);
2826
- return;
2827
- }
2828
- pendingFrameRef.current = null;
2829
- updateRef.current();
2830
- };
2831
- pendingFrameRef.current = requestAnimationFrame(advance);
2832
- }, [intervalFrames]);
2833
- }
2834
- //#endregion
2835
2773
  //#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/chat/accessibility.module.css.mjs
2836
2774
  const css$9 = ".nrZFeq_visuallyHidden{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}";
2837
2775
  const tagId$9 = "@prettier-ai/dsh-client-ui-chat/accessibility.module.css";
@@ -2845,7 +2783,7 @@ window.__ModuleLoader__.load({
2845
2783
  var accessibility_module_css_default = { "visuallyHidden": "nrZFeq_visuallyHidden" };
2846
2784
  //#endregion
2847
2785
  //#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/chat/ReasoningRow.module.css.mjs
2848
- const css$8 = ".xhC5dq_root{flex-direction:column;display:flex}.xhC5dq_row{position:relative;overflow:hidden}.xhC5dq_root[data-state=running] .xhC5dq_row:after{content:\"\";inset-block:0;background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite xhC5dq_dsh-reasoning-row-sweep;position:absolute;left:0}@keyframes xhC5dq_dsh-reasoning-row-sweep{0%{left:-300px}90%,to{left:100%}}.xhC5dq_leading{flex-shrink:0}.xhC5dq_chevron{color:var(--dsw-alias-label-secondary)}.xhC5dq_title{font-weight:400}.xhC5dq_separator{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.xhC5dq_summary{min-width:0;color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));text-overflow:ellipsis;white-space:nowrap;flex:auto;overflow:hidden}.xhC5dq_summary[data-follow-end]{text-overflow:clip}.xhC5dq_thinkBody{padding:4px 0 4px calc(22px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));white-space:pre-wrap;word-break:break-word}@media (prefers-reduced-motion:reduce){.xhC5dq_root[data-state=running] .xhC5dq_row:after{animation:none}}";
2786
+ const css$8 = ".xhC5dq_root{flex-direction:column;display:flex}.xhC5dq_root:not([data-expanded]){contain:size layout;height:calc(24px + var(--dsh-content-font-delta,0px))}.xhC5dq_row{position:relative;overflow:hidden}.xhC5dq_root[data-state=running] .xhC5dq_row:after{content:\"\";inset-block:0;background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite xhC5dq_dsh-reasoning-row-sweep;position:absolute;left:0}@keyframes xhC5dq_dsh-reasoning-row-sweep{0%{left:-300px}90%,to{left:100%}}.xhC5dq_leading{flex-shrink:0}.xhC5dq_chevron{color:var(--dsw-alias-label-secondary)}.xhC5dq_title{font-weight:400}.xhC5dq_separator{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.xhC5dq_summary{min-width:0;color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));white-space:nowrap;flex:auto;overflow:hidden}.xhC5dq_summaryText{text-overflow:ellipsis;display:block;overflow:hidden}.xhC5dq_summary[data-follow-end]{justify-content:flex-end;display:flex}.xhC5dq_summary[data-follow-end] .xhC5dq_summaryText{text-align:start;text-overflow:clip;flex:none;width:max-content;min-width:100%;overflow:visible}.xhC5dq_thinkBody{padding:4px 0 4px calc(22px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));white-space:pre-wrap;word-break:break-word}@media (prefers-reduced-motion:reduce){.xhC5dq_root[data-state=running] .xhC5dq_row:after{animation:none}}";
2849
2787
  const tagId$8 = "@prettier-ai/dsh-client-ui-chat/ReasoningRow.module.css";
2850
2788
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$8) + "]") === null) {
2851
2789
  const tag = document.createElement("style");
@@ -2862,6 +2800,7 @@ window.__ModuleLoader__.load({
2862
2800
  "row": "xhC5dq_row",
2863
2801
  "separator": "xhC5dq_separator",
2864
2802
  "summary": "xhC5dq_summary",
2803
+ "summaryText": "xhC5dq_summaryText",
2865
2804
  "thinkBody": "xhC5dq_thinkBody",
2866
2805
  "title": "xhC5dq_title"
2867
2806
  };
@@ -2886,24 +2825,12 @@ window.__ModuleLoader__.load({
2886
2825
  */
2887
2826
  function ReasoningRow({ text, running, t }) {
2888
2827
  const [expanded, setExpanded] = (0, react.useState)(false);
2889
- const summaryRef = (0, react.useRef)(null);
2890
2828
  const summary = running ? latestLine(text) : firstLine(text);
2891
- const scheduleSummaryScroll = useThrottledVisualUpdate(() => {
2892
- const element = summaryRef.current;
2893
- if (element === null) return;
2894
- element.scrollLeft = running ? element.scrollWidth - element.clientWidth : 0;
2895
- });
2896
- (0, react.useEffect)(() => {
2897
- scheduleSummaryScroll();
2898
- }, [
2899
- running,
2900
- scheduleSummaryScroll,
2901
- summary
2902
- ]);
2903
2829
  return (0, react_jsx_runtime.jsxs)("div", {
2904
2830
  className: ReasoningRow_module_css_default.root,
2905
2831
  "data-variant": "think",
2906
2832
  "data-state": running ? "running" : "ok",
2833
+ "data-expanded": expanded || void 0,
2907
2834
  children: [running && (0, react_jsx_runtime.jsx)("span", {
2908
2835
  className: accessibility_module_css_default.visuallyHidden,
2909
2836
  children: t("row.running")
@@ -2924,10 +2851,12 @@ window.__ModuleLoader__.load({
2924
2851
  className: ReasoningRow_module_css_default.separator,
2925
2852
  "aria-hidden": true
2926
2853
  }), (0, react_jsx_runtime.jsx)("span", {
2927
- ref: summaryRef,
2928
2854
  className: ReasoningRow_module_css_default.summary,
2929
2855
  "data-follow-end": running || void 0,
2930
- children: summary
2856
+ children: (0, react_jsx_runtime.jsx)("span", {
2857
+ className: ReasoningRow_module_css_default.summaryText,
2858
+ children: summary
2859
+ })
2931
2860
  })] }),
2932
2861
  children: (0, react_jsx_runtime.jsx)("div", {
2933
2862
  className: ReasoningRow_module_css_default.thinkBody,
@@ -3066,7 +2995,7 @@ window.__ModuleLoader__.load({
3066
2995
  });
3067
2996
  //#endregion
3068
2997
  //#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/chat/GenericCommandCard.module.css.mjs
3069
- const css$6 = "._0R17eG_root{flex-direction:column;display:flex}._0R17eG_row{position:relative;overflow:hidden}._0R17eG_root[data-state=running] ._0R17eG_row:after{content:\"\";inset-block:0;background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite _0R17eG_dsh-command-row-sweep;position:absolute;left:0}@keyframes _0R17eG_dsh-command-row-sweep{0%{left:-300px}90%,to{left:100%}}._0R17eG_leading{flex-shrink:0}._0R17eG_chevron{color:var(--dsw-alias-label-secondary)}._0R17eG_title{font-weight:400}._0R17eG_separator{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}._0R17eG_summary{min-width:0;color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));text-overflow:ellipsis;white-space:nowrap;flex:auto;overflow:hidden}._0R17eG_summary[data-error],._0R17eG_body[data-error]{color:var(--dsw-alias-state-error-primary)}._0R17eG_body{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-markdown-code-block);max-height:260px;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block-small);white-space:pre-wrap;border-radius:12px;margin:4px 0 4px 4px;padding:12px 16px;overflow:auto}@media (prefers-reduced-motion:reduce){._0R17eG_root[data-state=running] ._0R17eG_row:after{animation:none}}";
2998
+ const css$6 = "._0R17eG_root{flex-direction:column;display:flex}._0R17eG_row{position:relative;overflow:hidden}._0R17eG_root[data-state=running] ._0R17eG_row:after{content:\"\";inset-block:0;background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite _0R17eG_dsh-command-row-sweep;position:absolute;left:0}@keyframes _0R17eG_dsh-command-row-sweep{0%{left:-300px}90%,to{left:100%}}._0R17eG_leading{flex-shrink:0}._0R17eG_chevron{color:var(--dsw-alias-label-secondary)}._0R17eG_title{font-weight:400}._0R17eG_separator{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}._0R17eG_summary{min-width:0;color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));text-overflow:ellipsis;white-space:nowrap;flex:auto;overflow:hidden}._0R17eG_summary[data-error],._0R17eG_body[data-error]{color:var(--dsw-alias-state-error-primary)}._0R17eG_body{border:.5px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-markdown-code-block);max-height:260px;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block-small);white-space:pre-wrap;border-radius:12px;margin:4px 0 4px 4px;padding:12px 16px;overflow:auto}@media (prefers-reduced-motion:reduce){._0R17eG_root[data-state=running] ._0R17eG_row:after{animation:none}}";
3070
2999
  const tagId$6 = "@prettier-ai/dsh-client-ui-chat/GenericCommandCard.module.css";
3071
3000
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$6) + "]") === null) {
3072
3001
  const tag = document.createElement("style");
@@ -3242,7 +3171,7 @@ window.__ModuleLoader__.load({
3242
3171
  });
3243
3172
  //#endregion
3244
3173
  //#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/chat/TurnProcessNodeView.module.css.mjs
3245
- const css$5 = ".SfQmhG_root{box-sizing:border-box;border:none;border-bottom:1px solid var(--dsw-alias-border-l2);width:100%;min-width:0;height:33px;color:var(--dsw-alias-label-secondary);cursor:pointer;text-align:left;background:0 0;align-items:center;padding:0 0 8px;display:flex}.SfQmhG_root:not([data-open]){margin-bottom:8px}.SfQmhG_chevron{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;margin-left:6px;transition:transform .1s;transform:rotate(-90deg)}.SfQmhG_root[data-open] .SfQmhG_chevron{transform:rotate(0)}.SfQmhG_label{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:14px;line-height:24px;overflow:hidden}@media (prefers-reduced-motion:reduce){.SfQmhG_chevron{transition:none}}";
3174
+ const css$5 = ".SfQmhG_root{box-sizing:border-box;border:none;border-bottom:.5px solid var(--dsw-alias-border-l2);width:100%;min-width:0;height:33px;color:var(--dsw-alias-label-secondary);cursor:pointer;text-align:left;background:0 0;align-items:center;padding:0 0 8px;display:flex}.SfQmhG_root:not([data-open]){margin-bottom:8px}.SfQmhG_chevron{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;margin-left:6px;transition:transform .1s;transform:rotate(-90deg)}.SfQmhG_root[data-open] .SfQmhG_chevron{transform:rotate(0)}.SfQmhG_label{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:14px;line-height:24px;overflow:hidden}@media (prefers-reduced-motion:reduce){.SfQmhG_chevron{transition:none}}";
3246
3175
  const tagId$5 = "@prettier-ai/dsh-client-ui-chat/TurnProcessNodeView.module.css";
3247
3176
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$5) + "]") === null) {
3248
3177
  const tag = document.createElement("style");
@@ -3370,7 +3299,7 @@ window.__ModuleLoader__.load({
3370
3299
  }
3371
3300
  //#endregion
3372
3301
  //#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/chat/TurnUsagePanel.module.css.mjs
3373
- const css$4 = ".ZVOUHW_root{min-width:0;display:inline-flex}.ZVOUHW_root+.ZVOUHW_root{margin-left:-6px}.ZVOUHW_trigger{min-width:0;height:calc(28px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);font-variant-numeric:tabular-nums;line-height:calc(24px + var(--dsh-content-font-delta,0px));white-space:nowrap;cursor:pointer;background:0 0;border:none;border-radius:28px;align-items:center;gap:4px;padding:6px 8px;display:inline-flex}.ZVOUHW_label{text-overflow:ellipsis;min-width:0;overflow:hidden}.ZVOUHW_trigger svg{width:calc(15px + var(--dsh-content-font-delta,0px));height:calc(15px + var(--dsh-content-font-delta,0px));flex:none}.ZVOUHW_trigger:hover,.ZVOUHW_trigger[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}@media (width<=480px){.ZVOUHW_trigger{width:calc(28px + var(--dsh-content-font-delta,0px));justify-content:center;padding:6px}.ZVOUHW_trigger .ZVOUHW_label{display:none}.ZVOUHW_root+.ZVOUHW_root{margin-left:0}}.ZVOUHW_panel{z-index:1100;box-sizing:border-box;border:1px solid var(--dsw-alias-border-inverted);background:var(--dsw-specific-menu);width:max-content;min-width:min(300px,100vw - 24px);max-width:min(440px,100vw - 24px);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-secondary);cursor:default;border-radius:12px;padding:16px;font-size:12px;line-height:18px;position:fixed}.ZVOUHW_title{color:var(--dsw-alias-label-primary);justify-content:space-between;gap:16px;margin-bottom:8px;font-weight:500;display:flex}.ZVOUHW_titleRule{border-top:1px solid var(--dsw-alias-border-l2);margin-bottom:10px}.ZVOUHW_titleValue{font-variant-numeric:tabular-nums}.ZVOUHW_titleLabel{align-items:center;gap:6px;min-width:0;display:inline-flex}.ZVOUHW_titleLabel svg{flex:none;width:14px;height:14px}.ZVOUHW_details{color:var(--dsw-alias-label-tertiary);grid-template-columns:minmax(76px,auto) minmax(0,1fr);gap:6px 16px;margin:0;display:grid}.ZVOUHW_details dt,.ZVOUHW_details dd{min-width:0;margin:0}.ZVOUHW_details dd{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;text-align:right}.ZVOUHW_details .ZVOUHW_route{overflow-wrap:anywhere}.ZVOUHW_reasoning{color:var(--dsw-alias-label-tertiary);white-space:nowrap}";
3302
+ const css$4 = ".ZVOUHW_root{min-width:0;display:inline-flex}.ZVOUHW_root+.ZVOUHW_root{margin-left:-6px}.ZVOUHW_trigger{min-width:0;height:calc(28px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);font-variant-numeric:tabular-nums;line-height:calc(24px + var(--dsh-content-font-delta,0px));white-space:nowrap;cursor:pointer;background:0 0;border:none;border-radius:28px;align-items:center;gap:4px;padding:6px 8px;display:inline-flex}.ZVOUHW_label{text-overflow:ellipsis;min-width:0;overflow:hidden}.ZVOUHW_trigger svg{width:calc(15px + var(--dsh-content-font-delta,0px));height:calc(15px + var(--dsh-content-font-delta,0px));flex:none}.ZVOUHW_trigger:hover,.ZVOUHW_trigger[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}@media (width<=480px){.ZVOUHW_trigger{width:calc(28px + var(--dsh-content-font-delta,0px));justify-content:center;padding:6px}.ZVOUHW_trigger .ZVOUHW_label{display:none}.ZVOUHW_root+.ZVOUHW_root{margin-left:0}}.ZVOUHW_panel{z-index:1100;box-sizing:border-box;background:var(--dsw-specific-menu);--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);width:max-content;min-width:min(300px,100vw - 24px);max-width:min(440px,100vw - 24px);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-secondary);cursor:default;border:0;border-radius:12px;padding:16px;font-size:12px;line-height:18px;position:fixed}.ZVOUHW_title{color:var(--dsw-alias-label-primary);justify-content:space-between;gap:16px;margin-bottom:8px;font-weight:500;display:flex}.ZVOUHW_titleRule{border-top:.5px solid var(--dsw-alias-border-l2);margin-bottom:10px}.ZVOUHW_titleValue{font-variant-numeric:tabular-nums}.ZVOUHW_titleLabel{align-items:center;gap:6px;min-width:0;display:inline-flex}.ZVOUHW_titleLabel svg{flex:none;width:14px;height:14px}.ZVOUHW_details{color:var(--dsw-alias-label-tertiary);grid-template-columns:minmax(76px,auto) minmax(0,1fr);gap:6px 16px;margin:0;display:grid}.ZVOUHW_details dt,.ZVOUHW_details dd{min-width:0;margin:0}.ZVOUHW_details dd{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;text-align:right}.ZVOUHW_details .ZVOUHW_route{overflow-wrap:anywhere}.ZVOUHW_reasoning{color:var(--dsw-alias-label-tertiary);white-space:nowrap}";
3374
3303
  const tagId$4 = "@prettier-ai/dsh-client-ui-chat/TurnUsagePanel.module.css";
3375
3304
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
3376
3305
  const tag = document.createElement("style");
@@ -3901,6 +3830,42 @@ window.__ModuleLoader__.load({
3901
3830
  function billedInputTokens(usage) {
3902
3831
  return usage.uncachedInputTokens + usage.cacheReadTokens + usage.cacheWriteTokens;
3903
3832
  }
3833
+ /** Render and measure one non-empty statistics line. */
3834
+ const StatsLineContent = (0, react.memo)(function StatsLineContent({ groups, line }) {
3835
+ const rootRef = (0, react.useRef)(null);
3836
+ const [truncated, setTruncated] = (0, react.useState)(false);
3837
+ const measure = (0, react.useCallback)(() => {
3838
+ const el = rootRef.current;
3839
+ if (el === null) return;
3840
+ const next = el.scrollWidth > el.clientWidth;
3841
+ setTruncated((current) => current === next ? current : next);
3842
+ }, []);
3843
+ (0, react.useLayoutEffect)(() => {
3844
+ const el = rootRef.current;
3845
+ if (el === null || typeof ResizeObserver === "undefined") return;
3846
+ const observer = new ResizeObserver(measure);
3847
+ observer.observe(el);
3848
+ return () => {
3849
+ observer.disconnect();
3850
+ };
3851
+ }, [measure]);
3852
+ (0, react.useLayoutEffect)(measure, [line, measure]);
3853
+ return (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.Tooltip, {
3854
+ label: line,
3855
+ side: "top",
3856
+ delayMs: 500,
3857
+ disabled: !truncated,
3858
+ children: (0, react_jsx_runtime.jsx)("div", {
3859
+ ref: rootRef,
3860
+ className: StatsLine_module_css_default.root,
3861
+ children: groups.map((group, i) => (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [i > 0 && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("span", {
3862
+ className: StatsLine_module_css_default.sep,
3863
+ "aria-hidden": true,
3864
+ children: "|"
3865
+ }), " "] }), (0, react_jsx_runtime.jsx)("span", { children: group })] }, group))
3866
+ })
3867
+ });
3868
+ });
3904
3869
  const StatsLine = (0, react.memo)(function StatsLine({ useChat, useProjection, t }) {
3905
3870
  const settledNodes = useChat((s) => s.legacy.nodes);
3906
3871
  const usage = useProjection("tokenUsage");
@@ -3930,37 +3895,10 @@ window.__ModuleLoader__.load({
3930
3895
  }));
3931
3896
  }
3932
3897
  const line = groups.join(" | ");
3933
- const rootRef = (0, react.useRef)(null);
3934
- const [truncated, setTruncated] = (0, react.useState)(false);
3935
- (0, react.useLayoutEffect)(() => {
3936
- const el = rootRef.current;
3937
- if (el === null) return;
3938
- const measure = () => {
3939
- setTruncated(el.scrollWidth > el.clientWidth);
3940
- };
3941
- measure();
3942
- if (typeof ResizeObserver === "undefined") return;
3943
- const observer = new ResizeObserver(measure);
3944
- observer.observe(el);
3945
- return () => {
3946
- observer.disconnect();
3947
- };
3948
- }, [line]);
3949
3898
  if (groups.length === 0) return null;
3950
- return (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.Tooltip, {
3951
- label: line,
3952
- side: "top",
3953
- delayMs: 500,
3954
- disabled: !truncated,
3955
- children: (0, react_jsx_runtime.jsx)("div", {
3956
- ref: rootRef,
3957
- className: StatsLine_module_css_default.root,
3958
- children: groups.map((group, i) => (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [i > 0 && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("span", {
3959
- className: StatsLine_module_css_default.sep,
3960
- "aria-hidden": true,
3961
- children: "|"
3962
- }), " "] }), (0, react_jsx_runtime.jsx)("span", { children: group })] }, group))
3963
- })
3899
+ return (0, react_jsx_runtime.jsx)(StatsLineContent, {
3900
+ groups,
3901
+ line
3964
3902
  });
3965
3903
  });
3966
3904
  //#endregion
@@ -4518,6 +4456,10 @@ window.__ModuleLoader__.load({
4518
4456
  }
4519
4457
  };
4520
4458
  }
4459
+ function publishedAssistantData(context) {
4460
+ const location = context.start?.location ?? context.matches.at(-1)?.location;
4461
+ return location?.kind === "step" ? location.step.data.get("assistant-step") : void 0;
4462
+ }
4521
4463
  /** Per-step Assistant streaming/final/interruption Definition. */
4522
4464
  const assistantDefinition = {
4523
4465
  kind: "assistant-step",
@@ -4582,15 +4524,17 @@ window.__ModuleLoader__.load({
4582
4524
  };
4583
4525
  },
4584
4526
  buildViewNode: (context) => {
4585
- const projected = projectAssistant(context);
4586
- if (projected === void 0) return null;
4587
- if (projected.settled === void 0 && !projected.visible) {
4588
- const state = context.state ?? fallbackState$5(context);
4589
- if (state === void 0) return null;
4527
+ const state = context.state ?? fallbackState$5(context);
4528
+ if (state === void 0) return null;
4529
+ const data = publishedAssistantData(context);
4530
+ if (data === void 0) return null;
4531
+ const settled = data.finalNode;
4532
+ const visible = settled === void 0 ? state.visibleBlocks > 0 : hasVisibleContent(data.blocks);
4533
+ if (settled === void 0 && !visible) {
4590
4534
  const current = context.current.get("chat");
4591
4535
  if (!state.hidden || current === void 0 || current === null) return null;
4592
4536
  }
4593
- return chatNode(context, "assistant-step", projected.anchorSeq, projected.data, { visibility: projected.settled?.interrupted === true || projected.visible ? "visible" : "hidden" });
4537
+ return chatNode(context, "assistant-step", settled?.seq ?? state.firstVisibleSeq ?? context.matches[0]?.event.seq ?? 0, data, { visibility: settled?.interrupted === true || visible ? "visible" : "hidden" });
4594
4538
  }
4595
4539
  };
4596
4540
  /**
@@ -4689,6 +4633,92 @@ window.__ModuleLoader__.load({
4689
4633
  };
4690
4634
  }
4691
4635
  //#endregion
4636
+ //#region lib/types/client/conversation-nodes/turn-process-presentation.js
4637
+ function nodeTurn(node) {
4638
+ const location = node?.location;
4639
+ return location?.kind === "turn" || location?.kind === "step" ? location.turn.turn : void 0;
4640
+ }
4641
+ function samePresentation(left, right) {
4642
+ return left === right || left !== void 0 && right !== void 0 && left.spec === right.spec && left.turn === right.turn && left.turnClosed === right.turnClosed && left.hasExternalProcess === right.hasExternalProcess && left.compactAnswer === right.compactAnswer;
4643
+ }
4644
+ function derivePresentation(turn, locations, nodes) {
4645
+ const keys = locations.getTurn(turn);
4646
+ const control = keys.map((key) => nodes.get(key)).find((node) => node?.kind === "turn-process");
4647
+ if (control === void 0) return void 0;
4648
+ const spec = control.data;
4649
+ const location = control.location;
4650
+ if (location.kind !== "turn" && location.kind !== "step") return void 0;
4651
+ let openingHumanAnchor;
4652
+ for (const key of keys) {
4653
+ const node = nodes.get(key);
4654
+ if ((node?.kind === "user" || node?.kind === "steering") && node.anchorSeq < spec.controlAnchorSeq) openingHumanAnchor = Math.min(openingHumanAnchor ?? node.anchorSeq, node.anchorSeq);
4655
+ }
4656
+ let hasExternalProcess = false;
4657
+ let compactAnswer = true;
4658
+ for (const key of keys) {
4659
+ const node = nodes.get(key);
4660
+ if (node === void 0 || node.kind === "turn-process") continue;
4661
+ if ((node.kind === "user" || node.kind === "steering") && (openingHumanAnchor === void 0 || node.anchorSeq > openingHumanAnchor) && (spec.answerAnchorSeq === null || node.anchorSeq < spec.answerAnchorSeq)) compactAnswer = false;
4662
+ if (TURN_PROCESS_INDEPENDENT_KINDS.has(node.kind) || node.anchorSeq < spec.processStartSeq || spec.answerAnchorSeq !== null && node.anchorSeq >= spec.answerAnchorSeq) continue;
4663
+ if (node.kind !== "assistant-step" || spec.answerStep === null || node.data.step !== spec.answerStep) hasExternalProcess = true;
4664
+ }
4665
+ return {
4666
+ turn,
4667
+ spec,
4668
+ turnClosed: location.turn.status === "closed",
4669
+ hasExternalProcess,
4670
+ compactAnswer
4671
+ };
4672
+ }
4673
+ /** Mutable projection of cross-Node process layout facts by Turn. */
4674
+ var ChatTurnProcessProjector = class {
4675
+ presentations = /* @__PURE__ */ new Map();
4676
+ /**
4677
+ * Read the retained process presentation for a Node's Turn.
4678
+ * @param node - Current Chat Node.
4679
+ * @returns The Turn's process presentation, when present.
4680
+ */
4681
+ get(node) {
4682
+ const turn = nodeTurn(node);
4683
+ return turn === void 0 ? void 0 : this.presentations.get(turn);
4684
+ }
4685
+ /**
4686
+ * Replace every projected Turn.
4687
+ * @param order - visible Chat Node order.
4688
+ * @param locations - current Chat Location index.
4689
+ * @param nodes - current Chat Node store.
4690
+ * @returns Turns whose process presentation changed.
4691
+ */
4692
+ replace(order, locations, nodes) {
4693
+ const turns = /* @__PURE__ */ new Set();
4694
+ for (const key of order) {
4695
+ const turn = nodeTurn(nodes.get(key));
4696
+ if (turn !== void 0) turns.add(turn);
4697
+ }
4698
+ const changed = /* @__PURE__ */ new Set();
4699
+ for (const turn of new Set([...this.presentations.keys(), ...turns])) if (this.set(turn, turns.has(turn) ? derivePresentation(turn, locations, nodes) : void 0)) changed.add(turn);
4700
+ return changed;
4701
+ }
4702
+ /**
4703
+ * Recompute selected Turns after incremental Node changes.
4704
+ * @param turns - affected Turn numbers.
4705
+ * @param locations - current Chat Location index.
4706
+ * @param nodes - current Chat Node store.
4707
+ * @returns Turns whose process presentation changed.
4708
+ */
4709
+ update(turns, locations, nodes) {
4710
+ const changed = /* @__PURE__ */ new Set();
4711
+ for (const turn of turns) if (this.set(turn, derivePresentation(turn, locations, nodes))) changed.add(turn);
4712
+ return changed;
4713
+ }
4714
+ set(turn, next) {
4715
+ if (samePresentation(this.presentations.get(turn), next)) return false;
4716
+ if (next === void 0) this.presentations.delete(turn);
4717
+ else this.presentations.set(turn, next);
4718
+ return true;
4719
+ }
4720
+ };
4721
+ //#endregion
4692
4722
  //#region lib/types/client/conversation-nodes/chat-snapshot-builder.js
4693
4723
  const EMPTY_KEYS = [];
4694
4724
  const EMPTY_TURNS = [];
@@ -4697,13 +4727,59 @@ window.__ModuleLoader__.load({
4697
4727
  function sameReferences$1(left, right) {
4698
4728
  return left.length === right.length && left.every((value, index) => value === right[index]);
4699
4729
  }
4730
+ function cachedSource(sources, key, create) {
4731
+ let source = sources.get(key);
4732
+ if (source === void 0) {
4733
+ source = create();
4734
+ sources.set(key, source);
4735
+ }
4736
+ return source;
4737
+ }
4738
+ var MutableChatSource = class {
4739
+ read;
4740
+ label;
4741
+ listeners = /* @__PURE__ */ new Set();
4742
+ published;
4743
+ constructor(read, label) {
4744
+ this.read = read;
4745
+ this.label = label;
4746
+ this.published = read();
4747
+ }
4748
+ getSnapshot = () => this.read();
4749
+ subscribe = (listener) => {
4750
+ this.listeners.add(listener);
4751
+ return () => {
4752
+ this.listeners.delete(listener);
4753
+ };
4754
+ };
4755
+ publish() {
4756
+ const next = this.getSnapshot();
4757
+ if (this.published === next) return;
4758
+ this.published = next;
4759
+ (0, _prettier_ai_dsh_client_store.notifySubscribers)(this.listeners, this.label);
4760
+ }
4761
+ };
4700
4762
  var MutableChatNodeStore = class {
4701
4763
  byKey = /* @__PURE__ */ new Map();
4764
+ turnProcesses = new ChatTurnProcessProjector();
4765
+ sources = /* @__PURE__ */ new Map();
4766
+ processSources = /* @__PURE__ */ new Map();
4767
+ dirtyKeys = /* @__PURE__ */ new Set();
4768
+ dirtyProcessKeys = /* @__PURE__ */ new Set();
4702
4769
  valuesCache = EMPTY_LIST;
4703
4770
  valuesDirty = false;
4704
4771
  get(key) {
4705
4772
  return this.byKey.get(key);
4706
4773
  }
4774
+ source(key) {
4775
+ return cachedSource(this.sources, key, () => new MutableChatSource(() => this.get(key), `[ui-chat] node source ${key}`));
4776
+ }
4777
+ processSource(key) {
4778
+ return cachedSource(this.processSources, key, () => new MutableChatSource(() => this.process(key), `[ui-chat] node process source ${key}`));
4779
+ }
4780
+ process(key) {
4781
+ return this.turnProcesses.get(this.get(key));
4782
+ }
4707
4783
  values() {
4708
4784
  if (this.valuesDirty) {
4709
4785
  this.valuesCache = [...this.byKey.values()];
@@ -4712,8 +4788,20 @@ window.__ModuleLoader__.load({
4712
4788
  return this.valuesCache;
4713
4789
  }
4714
4790
  replace(nodes) {
4791
+ const previous = new Map(this.byKey);
4715
4792
  this.byKey.clear();
4716
- for (const node of nodes) this.byKey.set(node.key, node);
4793
+ for (const node of nodes) {
4794
+ this.byKey.set(node.key, node);
4795
+ if (previous.get(node.key) !== node) {
4796
+ this.dirtyKeys.add(node.key);
4797
+ this.dirtyProcessKeys.add(node.key);
4798
+ }
4799
+ previous.delete(node.key);
4800
+ }
4801
+ for (const key of previous.keys()) {
4802
+ this.dirtyKeys.add(key);
4803
+ this.dirtyProcessKeys.add(key);
4804
+ }
4717
4805
  this.valuesCache = [...this.byKey.values()];
4718
4806
  this.valuesDirty = false;
4719
4807
  }
@@ -4722,10 +4810,29 @@ window.__ModuleLoader__.load({
4722
4810
  for (const node of nodes) {
4723
4811
  if (this.byKey.get(node.key) === node) continue;
4724
4812
  this.byKey.set(node.key, node);
4813
+ this.dirtyKeys.add(node.key);
4814
+ this.dirtyProcessKeys.add(node.key);
4725
4815
  changed = true;
4726
4816
  }
4727
4817
  if (changed) this.valuesDirty = true;
4728
4818
  }
4819
+ touchProcesses(turns, locations) {
4820
+ for (const turn of turns) for (const key of locations.getTurn(turn)) this.dirtyProcessKeys.add(key);
4821
+ }
4822
+ replaceProcesses(order, locations) {
4823
+ this.touchProcesses(this.turnProcesses.replace(order, locations, this), locations);
4824
+ }
4825
+ updateProcesses(turns, locations) {
4826
+ this.touchProcesses(this.turnProcesses.update(turns, locations, this), locations);
4827
+ }
4828
+ publish() {
4829
+ const dirty = [...this.dirtyKeys];
4830
+ const dirtyProcesses = [...this.dirtyProcessKeys];
4831
+ this.dirtyKeys.clear();
4832
+ this.dirtyProcessKeys.clear();
4833
+ for (const key of dirty) this.sources.get(key)?.publish();
4834
+ for (const key of dirtyProcesses) this.processSources.get(key)?.publish();
4835
+ }
4729
4836
  };
4730
4837
  var MutableChatLocationIndex = class {
4731
4838
  turns = /* @__PURE__ */ new Map();
@@ -4841,6 +4948,15 @@ window.__ModuleLoader__.load({
4841
4948
  if (location.kind === "turn") return { turn: location.turn.turn };
4842
4949
  return {};
4843
4950
  }
4951
+ function locationTurnStatus(location) {
4952
+ return location.kind === "turn" || location.kind === "step" ? location.turn.status : void 0;
4953
+ }
4954
+ function processPresentationInputChanged(previous, next, structural) {
4955
+ if (structural || previous === void 0) return true;
4956
+ if (locationTurnStatus(previous.location) !== locationTurnStatus(next.location)) return true;
4957
+ if (previous.kind === "turn-process" && next.kind === "turn-process") return previous.data !== next.data;
4958
+ return previous.kind === "assistant-step" && next.kind === "assistant-step" && previous.data.step !== next.data.step;
4959
+ }
4844
4960
  function turnProcessPresentations(nodes) {
4845
4961
  const presentations = /* @__PURE__ */ new Map();
4846
4962
  for (const raw of nodes) {
@@ -5199,12 +5315,16 @@ window.__ModuleLoader__.load({
5199
5315
  this.store.replace(nodes);
5200
5316
  this.order = orderedVisibleChatNodes(nodes).map((node) => node.key);
5201
5317
  this.locations.rebuild(this.order, this.store);
5318
+ this.store.replaceProcesses(this.order, this.locations);
5202
5319
  this.navigation.rebuild(input.timeline, this.locations, this.store);
5203
5320
  this.timeline = input.timeline;
5204
- return this.snapshot(input.timeline, this.legacy.replace(nodes, input.timeline));
5321
+ const snapshot = this.snapshot(input.timeline, this.legacy.replace(nodes, input.timeline));
5322
+ this.store.publish();
5323
+ return snapshot;
5205
5324
  }
5206
5325
  apply(input) {
5207
5326
  const upserts = this.referenceLabels.apply(input.upserts, this.store);
5327
+ const processTurns = /* @__PURE__ */ new Set();
5208
5328
  let structural = false;
5209
5329
  const contentOnly = [];
5210
5330
  for (const node of upserts) {
@@ -5212,6 +5332,12 @@ window.__ModuleLoader__.load({
5212
5332
  const nodeStructural = previous === void 0 || previous.kind !== node.kind || previous.anchorSeq !== node.anchorSeq || previous.visibility !== node.visibility || locationIdentity(previous.location) !== locationIdentity(node.location);
5213
5333
  structural ||= nodeStructural;
5214
5334
  if (!nodeStructural) contentOnly.push(node);
5335
+ if (processPresentationInputChanged(previous, node, nodeStructural)) {
5336
+ const previousTurn = previous === void 0 ? void 0 : locationCoordinates(previous.location).turn;
5337
+ const nextTurn = locationCoordinates(node.location).turn;
5338
+ if (previousTurn !== void 0) processTurns.add(previousTurn);
5339
+ if (nextTurn !== void 0) processTurns.add(nextTurn);
5340
+ }
5215
5341
  }
5216
5342
  this.store.upsert(upserts);
5217
5343
  if (structural) {
@@ -5220,10 +5346,13 @@ window.__ModuleLoader__.load({
5220
5346
  this.locations.rebuild(this.order, this.store);
5221
5347
  }
5222
5348
  this.locations.touch(contentOnly);
5349
+ this.store.updateProcesses(processTurns, this.locations);
5223
5350
  if (structural || input.timeline !== this.timeline) this.navigation.rebuild(input.timeline, this.locations, this.store);
5224
5351
  else this.navigation.touch(turnsOf(contentOnly), this.locations, this.store);
5225
5352
  this.timeline = input.timeline;
5226
- return this.snapshot(input.timeline, this.legacy.apply(upserts, input.timeline));
5353
+ const snapshot = this.snapshot(input.timeline, this.legacy.apply(upserts, input.timeline));
5354
+ this.store.publish();
5355
+ return snapshot;
5227
5356
  }
5228
5357
  snapshot(timeline, legacy = this.legacy.replace(EMPTY_LIST, timeline)) {
5229
5358
  return {
@@ -6265,6 +6394,7 @@ window.__ModuleLoader__.load({
6265
6394
  turn,
6266
6395
  assistantStartByStep: /* @__PURE__ */ new Map(),
6267
6396
  messageCountByStep: /* @__PURE__ */ new Map(),
6397
+ messageCount: 0,
6268
6398
  toolCallCount: 0,
6269
6399
  subagentCount: 0
6270
6400
  };
@@ -6280,11 +6410,11 @@ window.__ModuleLoader__.load({
6280
6410
  return data.blocks.some((block) => block.kind === "tool-call") ? null : data;
6281
6411
  }
6282
6412
  function processSpec(state, turn) {
6283
- const controlAnchorSeq = Math.min(state.otherStartSeq ?? Number.POSITIVE_INFINITY, ...state.assistantStartByStep.values());
6284
- if (!Number.isFinite(controlAnchorSeq)) return null;
6413
+ const controlAnchorSeq = state.controlAnchorSeq;
6414
+ if (controlAnchorSeq === void 0) return null;
6285
6415
  const answer = latestAnswer(turn);
6286
6416
  const counts = {
6287
- messageCount: answer === null ? [...state.messageCountByStep.values()].reduce((total, count) => total + count, 0) : [...state.messageCountByStep].filter(([step]) => step < answer.step).reduce((total, [, count]) => total + count, 0),
6417
+ messageCount: answer === null ? state.messageCount : [...state.messageCountByStep].filter(([step]) => step < answer.step).reduce((total, [, count]) => total + count, 0),
6288
6418
  toolCallCount: state.toolCallCount,
6289
6419
  subagentCount: state.subagentCount
6290
6420
  };
@@ -6317,7 +6447,8 @@ window.__ModuleLoader__.load({
6317
6447
  messageCountByStep.set(event.data.step, (messageCountByStep.get(event.data.step) ?? 0) + 1);
6318
6448
  current = {
6319
6449
  ...current,
6320
- messageCountByStep
6450
+ messageCountByStep,
6451
+ messageCount: current.messageCount + 1
6321
6452
  };
6322
6453
  }
6323
6454
  if (event.type === "tool/call") {
@@ -6332,14 +6463,16 @@ window.__ModuleLoader__.load({
6332
6463
  if (evidence === void 0) return current;
6333
6464
  if (evidence.kind === "other") return current.otherStartSeq === void 0 ? {
6334
6465
  ...current,
6335
- otherStartSeq: evidence.seq
6466
+ otherStartSeq: evidence.seq,
6467
+ controlAnchorSeq: Math.min(current.controlAnchorSeq ?? Number.POSITIVE_INFINITY, evidence.seq)
6336
6468
  } : current;
6337
6469
  if (current.assistantStartByStep.has(evidence.step)) return current;
6338
6470
  const assistantStartByStep = new Map(current.assistantStartByStep);
6339
6471
  assistantStartByStep.set(evidence.step, evidence.seq);
6340
6472
  return {
6341
6473
  ...current,
6342
- assistantStartByStep
6474
+ assistantStartByStep,
6475
+ controlAnchorSeq: Math.min(current.controlAnchorSeq ?? Number.POSITIVE_INFINITY, evidence.seq)
6343
6476
  };
6344
6477
  }
6345
6478
  /** Turn-scoped process range and answer-boundary Definition. */
@@ -6365,6 +6498,7 @@ window.__ModuleLoader__.load({
6365
6498
  turn: match.event.data.turn,
6366
6499
  assistantStartByStep: /* @__PURE__ */ new Map(),
6367
6500
  messageCountByStep: /* @__PURE__ */ new Map(),
6501
+ messageCount: 0,
6368
6502
  toolCallCount: 0,
6369
6503
  subagentCount: 0
6370
6504
  };
@@ -6378,25 +6512,32 @@ window.__ModuleLoader__.load({
6378
6512
  }
6379
6513
  return "immediate";
6380
6514
  },
6381
- buildLocationData: (context, scope) => {
6515
+ buildLocationData: (context, scope, previous) => {
6382
6516
  if (scope !== "turn") return null;
6383
6517
  const state = context.state ?? fallbackState(context);
6384
6518
  if (state === void 0) return null;
6385
6519
  const turn = turnLocation$1(context);
6386
6520
  if (turn === void 0) return null;
6521
+ const current = context.current.get("chat");
6522
+ const latestStep = turn.steps.at(-1);
6523
+ if (previous?.kind === "turn" && previous.key === "turn-process" && current?.kind === "turn-process" && current.data.answerAnchorSeq === null && current.data.controlAnchorSeq === state.controlAnchorSeq && current.data.messageCount === state.messageCount && current.data.toolCallCount === state.toolCallCount && current.data.subagentCount === state.subagentCount && turn.status !== "closed" && latestStep?.status !== "closed") return previous;
6387
6524
  const spec = processSpec(state, turn);
6388
- return spec === null ? null : {
6525
+ if (spec === null) return null;
6526
+ if (previous?.kind === "turn" && previous.turn === spec.turn && previous.key === "turn-process" && sameTurnProcessSpec(previous.value, spec)) return previous;
6527
+ return {
6389
6528
  kind: "turn",
6390
6529
  turn: turn.turn,
6391
6530
  key: "turn-process",
6392
- value: encodeTurnProcess(spec)
6531
+ value: spec
6393
6532
  };
6394
6533
  },
6395
6534
  buildViewNode: (context) => {
6396
6535
  const turn = turnLocation$1(context);
6397
- const signature = turn?.data.get("turn-process");
6398
- if (turn === void 0 || signature === void 0) return null;
6399
- const data = decodeTurnProcess(signature);
6536
+ const data = turn?.data.get("turn-process");
6537
+ if (turn === void 0 || data === void 0) return null;
6538
+ const current = context.current.get("chat");
6539
+ const state = context.state;
6540
+ if (current?.kind === "turn-process" && state !== void 0 && current.data.answerAnchorSeq === null && current.data.controlAnchorSeq === state.controlAnchorSeq && current.data.messageCount === state.messageCount && current.data.toolCallCount === state.toolCallCount && current.data.subagentCount === state.subagentCount && turn.status !== "closed" && turn.steps.at(-1)?.status !== "closed" && current.location === (context.start?.location ?? context.matches[0]?.location)) return current;
6400
6541
  return chatNode(context, "turn-process", data.controlAnchorSeq + CHAT_SYNTHETIC_SEQ_OFFSETS.processControl, data);
6401
6542
  }
6402
6543
  };
@@ -6686,7 +6827,7 @@ window.__ModuleLoader__.load({
6686
6827
  return data.finalNode !== void 0 && data.blocks.some((block) => block.kind === "text" && block.text.trim() !== "");
6687
6828
  }
6688
6829
  function tailData(context) {
6689
- const end = context.state?.end ?? context.matches.find((match) => match.event.type === "turn/end");
6830
+ const end = context.state === void 0 ? context.matches.find((match) => match.event.type === "turn/end") : context.state.end;
6690
6831
  if (end?.event.type !== "turn/end") return null;
6691
6832
  const turn = turnLocation(context);
6692
6833
  if (turn === void 0) return null;
@@ -6816,7 +6957,7 @@ window.__ModuleLoader__.load({
6816
6957
  }
6817
6958
  //#endregion
6818
6959
  //#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/details/DetailsPanel.module.css.mjs
6819
- const css$1 = "._9bk3za_root{border-left:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex-direction:column;min-width:0;height:100%;display:flex}._9bk3za_header{border-bottom:1px solid var(--dsw-alias-border-l2);justify-content:space-between;align-items:center;gap:8px;padding:14px 12px 12px;display:flex}._9bk3za_title{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:500;line-height:20px;overflow:hidden}._9bk3za_close{width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:999px;flex:none;place-items:center;display:grid}._9bk3za_close:hover{background:var(--dsw-alias-interactive-bg-hover)}._9bk3za_body{flex:1;min-height:0;padding:12px 16px;overflow-y:auto}._9bk3za_empty{color:var(--dsw-alias-label-tertiary);padding:8px 0;font-size:13px;line-height:20px}._9bk3za_section{margin-bottom:16px}._9bk3za_sectionLabel{color:var(--dsw-alias-label-secondary);margin-bottom:6px;font-size:12px;font-weight:500;line-height:18px}._9bk3za_code{background:var(--dsw-alias-markdown-code-block);font-family:var(--ds-font-family-code);color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;border-radius:12px;margin:0;padding:16px;font-size:13px;line-height:22px}._9bk3za_code[data-error]{color:var(--dsw-alias-state-error-primary)}";
6960
+ const css$1 = "._9bk3za_root{border-left:.5px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex-direction:column;min-width:0;height:100%;display:flex}._9bk3za_header{border-bottom:.5px solid var(--dsw-alias-border-l2);justify-content:space-between;align-items:center;gap:8px;padding:14px 12px 12px;display:flex}._9bk3za_title{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:500;line-height:20px;overflow:hidden}._9bk3za_close{corner-shape:round;width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:999px;flex:none;place-items:center;display:grid}._9bk3za_close:hover{background:var(--dsw-alias-interactive-bg-hover)}._9bk3za_body{flex:1;min-height:0;padding:12px 16px;overflow-y:auto}._9bk3za_empty{color:var(--dsw-alias-label-tertiary);padding:8px 0;font-size:13px;line-height:20px}._9bk3za_section{margin-bottom:16px}._9bk3za_sectionLabel{color:var(--dsw-alias-label-secondary);margin-bottom:6px;font-size:12px;font-weight:500;line-height:18px}._9bk3za_code{background:var(--dsw-alias-markdown-code-block);font-family:var(--ds-font-family-code);color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;border-radius:12px;margin:0;padding:16px;font-size:13px;line-height:22px}._9bk3za_code[data-error]{color:var(--dsw-alias-state-error-primary)}";
6820
6961
  const tagId$1 = "@prettier-ai/dsh-client-ui-chat/DetailsPanel.module.css";
6821
6962
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
6822
6963
  const tag = document.createElement("style");
@@ -6944,7 +7085,7 @@ window.__ModuleLoader__.load({
6944
7085
  }
6945
7086
  //#endregion
6946
7087
  //#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/settings/TranscriptViewRow.module.css.mjs
6947
- const css = ".EKfs7G_row{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:16px 0;display:flex}.EKfs7G_rowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}.EKfs7G_title{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.EKfs7G_desc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.EKfs7G_selector{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.EKfs7G_selector:hover{background:var(--dsw-alias-interactive-bg-hover)}.EKfs7G_chevron{flex:none}";
7088
+ const css = ".EKfs7G_row{border-bottom:.5px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:16px 0;display:flex}.EKfs7G_rowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}.EKfs7G_title{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.EKfs7G_desc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.EKfs7G_selector{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.EKfs7G_selector:hover{background:var(--dsw-alias-interactive-bg-hover)}.EKfs7G_chevron{flex:none}";
6948
7089
  const tagId = "@prettier-ai/dsh-client-ui-chat/TranscriptViewRow.module.css";
6949
7090
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
6950
7091
  const tag = document.createElement("style");
@@ -7862,12 +8003,25 @@ window.__ModuleLoader__.load({
7862
8003
  }
7863
8004
  };
7864
8005
  //#endregion
8006
+ //#region lib/types/client/chat/use-turn-data.js
8007
+ const EMPTY_SOURCE = {
8008
+ getSnapshot: () => void 0,
8009
+ subscribe: () => () => {}
8010
+ };
8011
+ /**
8012
+ * Subscribe to one value from a Turn's keyed Location-data store.
8013
+ * @param data - current Turn data store, or absence for a Node outside a Turn.
8014
+ * @param key - declaration-merged business key.
8015
+ * @returns the current value for that key.
8016
+ */
8017
+ function useTurnDataValue(data, key) {
8018
+ const source = data?.source(key) ?? EMPTY_SOURCE;
8019
+ return (0, react.useSyncExternalStore)(source.subscribe, source.getSnapshot);
8020
+ }
8021
+ //#endregion
7865
8022
  //#region lib/types/client/apply.js
7866
- const CHAT_NODE_INJECT = { hooks: { turnData: ({ useChat }, nodeKey) => function useTurnData(key) {
7867
- return useChat((snapshot) => {
7868
- const location = snapshot.nodes.get(nodeKey)?.location;
7869
- return location?.kind === "turn" || location?.kind === "step" ? location.turn.data.get(key) : void 0;
7870
- });
8023
+ const CHAT_NODE_INJECT = { hooks: { turnData: (_standard, data) => function useTurnData(key) {
8024
+ return useTurnDataValue(data, key);
7871
8025
  } } };
7872
8026
  /** Services required by the Chat target and its presentation registrations. */
7873
8027
  const inject = [
@@ -7945,10 +8099,16 @@ window.__ModuleLoader__.load({
7945
8099
  },
7946
8100
  store: chatStore,
7947
8101
  inject: (sessionId, actions) => {
7948
- const session = ctx.sessions.binding(sessionId)?.session;
7949
- if (session === void 0) throw new Error(`ui-chat: unknown session "${sessionId}"`);
8102
+ const binding = ctx.sessions.binding(sessionId);
8103
+ if (binding === void 0) throw new Error(`ui-chat: unknown session "${sessionId}"`);
8104
+ const session = binding.session;
8105
+ const chat = chatSource(binding);
7950
8106
  return {
7951
8107
  hooks: { transcriptView: transcriptView.mode },
8108
+ keyedHooks: {
8109
+ chatNode: (key) => chat.getSnapshot().nodes.source(key),
8110
+ chatNodeProcess: (key) => chat.getSnapshot().nodes.processSource(key)
8111
+ },
7952
8112
  openDetails: (target) => {
7953
8113
  actions.select(target);
7954
8114
  ctx.layout.openDetails();