@yadsh/dsh-qa-surface 0.7.1 → 0.7.2

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
@@ -11238,10 +11238,23 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11238
11238
  this.refreshing = false;
11239
11239
  this.refusal = "";
11240
11240
  }
11241
+ /**
11242
+ * The Host's bundles win the turns they share with the projection, with one
11243
+ * exception: a bundle that collected nothing never erases a turn the
11244
+ * transcript accounts for. Both channels read the same durable tool results,
11245
+ * so a turn the projection filled and the Host reported empty means the
11246
+ * Host's collection missed that turn, not that the answer had no sources —
11247
+ * and without this guard such a turn loses the sources the reader could see
11248
+ * while it ran the moment the Host answers for it.
11249
+ */
11241
11250
  merge(projected) {
11242
11251
  const merged = /* @__PURE__ */ new Map();
11243
11252
  for (const bundle of projected) merged.set(bundle.turn, bundle);
11244
- for (const bundle of this.bundles) merged.set(bundle.turn, bundle);
11253
+ for (const bundle of this.bundles) {
11254
+ const collected = merged.get(bundle.turn);
11255
+ if (collected !== void 0 && carriesNothing(bundle) && !carriesNothing(collected)) continue;
11256
+ merged.set(bundle.turn, bundle);
11257
+ }
11245
11258
  return [...merged.values()].sort((left, right) => left.turn - right.turn);
11246
11259
  }
11247
11260
  /**
@@ -11282,6 +11295,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11282
11295
  }
11283
11296
  }
11284
11297
  };
11298
+ /** True when a bundle holds no source at all, promoted or discovered. */
11299
+ function carriesNothing(bundle) {
11300
+ return bundle.sources.length === 0 && (bundle.discovered?.length ?? 0) === 0;
11301
+ }
11285
11302
  /** Stable text for one refusal, so the same failure is not reported twice. */
11286
11303
  function refusalKey(error) {
11287
11304
  if (typeof error === "string") return error;
@@ -12085,6 +12102,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12085
12102
  }
12086
12103
  };
12087
12104
  }
12105
+ /**
12106
+ * The Host's web tool opens its result with an envelope — `Fetched <url>
12107
+ * (HTTP <code>)`, then the untrusted-content notice — before the page itself.
12108
+ * Both lines are dropped here, and so is a first line that is the page's own
12109
+ * address: the card already prints the target URL, so a snippet drawn from
12110
+ * either of them would only repeat what the reader can already see.
12111
+ */
12112
+ const WEB_FETCH_ENVELOPE = /^(?:Fetched\s+\S+\s+\(HTTP\s+\d+\)|External web content follows\..*)$/u;
12113
+ function fetchedSnippet(value, uri) {
12114
+ if (value === void 0) return void 0;
12115
+ const target = uri.replace(/\/+$/u, "");
12116
+ return snippet(value.split(/\r?\n/u).filter((line) => {
12117
+ const text = line.trim();
12118
+ if (text === "") return true;
12119
+ if (WEB_FETCH_ENVELOPE.test(text)) return false;
12120
+ return text.replace(/\/+$/u, "") !== target;
12121
+ }).join("\n"));
12122
+ }
12088
12123
  function createWebFetchExtractor(urlOptions = {}) {
12089
12124
  return {
12090
12125
  id: "dsh-web-fetch",
@@ -12100,7 +12135,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12100
12135
  if (uri === null) return [];
12101
12136
  const explicitTitle = typeof meta?.title === "string" && meta.title.trim() !== "" ? meta.title.trim() : void 0;
12102
12137
  const titleExplicit = explicitTitle !== void 0;
12103
- const sourceSnippet = snippet(firstText(context.result));
12138
+ const sourceSnippet = fetchedSnippet(firstText(context.result), uri);
12104
12139
  return [{
12105
12140
  id: `web:${uri}`,
12106
12141
  kind: "web",
@@ -14862,7 +14897,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14862
14897
  ]
14863
14898
  });
14864
14899
  }
14865
- function QaHeader({ logoUrl, title, viewingSubagent, onCloseSubagent, agentPreset, roleSelector, administration, agentCount, agentsOpen, onToggleAgents, sourcesVisible, sourcesCount, sourcesComplete, sourcesOpen, onOpenSources, fileCount, filesOpen, onOpenFiles, panelLauncher, showReset, resetDisabled, onReset }) {
14900
+ function QaHeader({ logoUrl, title, viewingSubagent, onCloseSubagent, agentPreset, roleSelector, administration, agentCount, agentsOpen, onToggleAgents, sourcesVisible, sourcesCount, sourcesComplete, sourcesOpen, onOpenSources, fileCount, filesOpen, onOpenFiles, settings, panelLauncher, showReset, resetDisabled, onReset }) {
14866
14901
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("header", {
14867
14902
  className: "dsh-qa-header",
14868
14903
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -14988,7 +15023,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14988
15023
  onClick: administration.onOpen,
14989
15024
  children: "Администрирование"
14990
15025
  }),
14991
- panelLauncher
15026
+ panelLauncher,
15027
+ settings === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
15028
+ type: "button",
15029
+ className: "dsh-qa-header__settings",
15030
+ title: settings.label,
15031
+ onClick: settings.onOpen,
15032
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
15033
+ viewBox: "0 0 16 16",
15034
+ "aria-hidden": "true",
15035
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
15036
+ cx: "8",
15037
+ cy: "8",
15038
+ r: "2.2"
15039
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 1.8v2M8 12.2v2M1.8 8h2M12.2 8h2M3.6 3.6l1.4 1.4M11 11l1.4 1.4M3.6 12.4 5 11M11 5l1.4-1.4" })]
15040
+ }), "Настройки"]
15041
+ })
14992
15042
  ]
14993
15043
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14994
15044
  className: "dsh-qa-header__tabs",
@@ -16572,8 +16622,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16572
16622
  }
16573
16623
  //#endregion
16574
16624
  //#region src/client/components/QaChangelog.tsx
16575
- const QA_VERSION = "0.7.1";
16625
+ const QA_VERSION = "0.7.2";
16576
16626
  const QA_CHANGELOG = [
16627
+ {
16628
+ version: "0.7.2",
16629
+ date: "2026-09-16",
16630
+ sections: [{
16631
+ title: "Исправления",
16632
+ items: [
16633
+ "Чаты снова открываются: сервер отказывал в допуске, потому что набор инструментов роли называл служебный инструмент проверки активации, а такой инструмент агент регистрирует у себя сам — в ограничение его подставить нельзя. Теперь ограничение ставится только на наследуемые инструменты, служебный остаётся доступным, и выдача инструментов навыком больше не теряется молча из-за того же имени.",
16634
+ "Источники, появившиеся во время ответа, больше не исчезают после его завершения. Пустой ответ сервера об источниках хода больше не затирает то, что браузер прочитал из самой истории чата: список источников, видимый во время работы агента, остаётся рядом с ответом и после её окончания.",
16635
+ "В карточке скачанной страницы больше не повторяется её адрес: вместо служебной строки веб-инструмента «Fetched … (HTTP 200)» показывается начало текста самой страницы.",
16636
+ "В разделе «Быстрые сообщения» поля «Название» и «Промпт» выровнены по одной правой границе, а кнопка удаления подсказки больше не выглядит пустым полем ввода.",
16637
+ "Список инструментов в редакторе навыка стал компактнее и выше: длинные описания занимают две строки, а полный текст виден во всплывающей подсказке.",
16638
+ "Из раздела «Общие» убран пункт «Персональные интеграции и внешние системы» из списка будущих возможностей: интеграции уже доступны отдельным разделом настроек.",
16639
+ "Настройки пользователя больше не теряются в деплоях без списка чатов: если боковая панель с чатами скрыта (это поведение по умолчанию), кнопка «Настройки» появляется в шапке рядом с «Файлами», а при включённой панели вход остаётся прежним — по своему имени внизу списка чатов."
16640
+ ]
16641
+ }]
16642
+ },
16577
16643
  {
16578
16644
  version: "0.7.1",
16579
16645
  date: "2026-09-16",
@@ -16790,7 +16856,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16790
16856
  className: "dsh-qa-changelog__date",
16791
16857
  children: entry.date
16792
16858
  }),
16793
- entry.version === "0.7.1" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16859
+ entry.version === "0.7.2" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16794
16860
  className: "dsh-qa-changelog__current",
16795
16861
  children: "текущая"
16796
16862
  }) : null
@@ -18111,10 +18177,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18111
18177
  //#region src/client/user-settings/GeneralSettingsPage.tsx
18112
18178
  /**
18113
18179
  * Placeholder with a purpose: the section exists so the dialog has a home for
18114
- * the user-scoped preferences that follow (notifications, integrations,
18115
- * privacy), and so the thing it must not become is written down — deployment
18116
- * and chat policy live in the Host settings, not here. It shows the account
18117
- * facts a user can act on today and nothing invented.
18180
+ * the user-scoped preferences that follow (notifications, privacy), and so the
18181
+ * thing it must not become is written down — deployment and chat policy live in
18182
+ * the Host settings, not here. It shows the account facts a user can act on
18183
+ * today and nothing invented, and it names only what is still missing: a
18184
+ * preference that already has its own tab does not belong on this list.
18118
18185
  */
18119
18186
  function QaGeneralSettingsPage(props) {
18120
18187
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -18152,11 +18219,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18152
18219
  title: "Скоро здесь",
18153
18220
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
18154
18221
  className: "dsh-qa-settings__list",
18155
- children: [
18156
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: "Настройки уведомлений" }),
18157
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: "Персональные интеграции и внешние системы" }),
18158
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: "Приватность и хранение данных" })
18159
- ]
18222
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: "Настройки уведомлений" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: "Приватность и хранение данных" })]
18160
18223
  })
18161
18224
  })
18162
18225
  ]
@@ -18656,6 +18719,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18656
18719
  }),
18657
18720
  tool.description === "" ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
18658
18721
  className: "dsh-qa-toolpicker__description",
18722
+ title: tool.description,
18659
18723
  children: tool.description
18660
18724
  })
18661
18725
  ]
@@ -19273,9 +19337,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19273
19337
  className: "dsh-qa-starters__list",
19274
19338
  children: rows.map((row, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
19275
19339
  className: "dsh-qa-starters__item",
19276
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
19277
- className: "dsh-qa-starters__item-head",
19278
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
19340
+ children: [
19341
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
19279
19342
  className: "dsh-qa-settings__field",
19280
19343
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
19281
19344
  className: "dsh-qa-settings__field-label",
@@ -19293,7 +19356,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19293
19356
  }
19294
19357
  })]
19295
19358
  })
19296
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
19359
+ }),
19360
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
19297
19361
  type: "button",
19298
19362
  className: "dsh-qa-starters__remove",
19299
19363
  "aria-label": `Удалить «${row.label.trim() || "без названия"}»`,
@@ -19307,27 +19371,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19307
19371
  "aria-hidden": "true",
19308
19372
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m4 4 8 8m0-8-8 8" })
19309
19373
  })
19310
- })]
19311
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
19312
- className: "dsh-qa-settings__field",
19313
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
19314
- className: "dsh-qa-settings__field-label",
19315
- children: ["Промпт", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
19316
- rows: 2,
19317
- value: row.prompt,
19318
- maxLength: QA_STARTERS_MAX_PROMPT,
19319
- placeholder: "Что уйдёт в чат при нажатии",
19320
- onChange: (event) => {
19321
- const value = event.currentTarget.value;
19322
- setRows((current) => current.map((candidate, at) => at === index ? {
19323
- ...candidate,
19324
- prompt: value
19325
- } : candidate));
19326
- setSaved(false);
19327
- }
19328
- })]
19374
+ }),
19375
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
19376
+ className: "dsh-qa-settings__field",
19377
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
19378
+ className: "dsh-qa-settings__field-label",
19379
+ children: ["Промпт", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
19380
+ rows: 2,
19381
+ value: row.prompt,
19382
+ maxLength: QA_STARTERS_MAX_PROMPT,
19383
+ placeholder: "Что уйдёт в чат при нажатии",
19384
+ onChange: (event) => {
19385
+ const value = event.currentTarget.value;
19386
+ setRows((current) => current.map((candidate, at) => at === index ? {
19387
+ ...candidate,
19388
+ prompt: value
19389
+ } : candidate));
19390
+ setSaved(false);
19391
+ }
19392
+ })]
19393
+ })
19329
19394
  })
19330
- })]
19395
+ ]
19331
19396
  }, index))
19332
19397
  }),
19333
19398
  rows.length >= 12 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
@@ -23304,6 +23369,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
23304
23369
  filesOpen: rail.railOpen && rail.railTab === "files",
23305
23370
  onOpenFiles: () => rail.openTab("files"),
23306
23371
  panelLauncher: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(QaPanelLauncher, { panels: props.panels }),
23372
+ settings: showSidebar ? void 0 : settingsEntry,
23307
23373
  showReset: showResetButton,
23308
23374
  resetDisabled: controller === void 0 || state.phase === "creating",
23309
23375
  onReset: handleNewChat
@@ -23925,21 +23991,20 @@ body[data-dsh-qa-surface="active"] div:has(>[data-shell-overlay])>:not([data-she
23925
23991
  .dsh-qa-settings__list{margin:0;padding-left:18px;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:20px}
23926
23992
  .dsh-qa-settings__list li{margin:2px 0}
23927
23993
  .dsh-qa-starters__list{display:flex;flex-direction:column;gap:10px}
23928
- .dsh-qa-starters__item{display:flex;flex-direction:column;gap:8px;padding:10px 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-layer-3)}
23929
- .dsh-qa-starters__item-head{display:flex;align-items:flex-end;gap:8px}
23930
- .dsh-qa-starters__item-head .dsh-qa-settings__field{flex:1}
23931
- .dsh-qa-starters__remove{appearance:none;flex:none;width:30px;height:30px;margin-bottom:5px;display:flex;align-items:center;justify-content:center;padding:0;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:0 0;color:var(--dsw-alias-label-tertiary);cursor:pointer}
23932
- .dsh-qa-starters__remove:hover{color:var(--dsh-qa-error);border-color:var(--dsh-alias-label-error)}
23994
+ .dsh-qa-starters__item{display:grid;grid-template-columns:minmax(0,1fr) 28px;column-gap:8px;row-gap:8px;padding:10px 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-layer-3)}
23995
+ .dsh-qa-starters__item>.dsh-qa-settings__field{grid-column:1}
23996
+ .dsh-qa-starters__remove{appearance:none;grid-column:2;grid-row:1;align-self:end;flex:none;width:28px;height:28px;margin-bottom:6px;display:flex;align-items:center;justify-content:center;padding:0;border:0;border-radius:8px;background:0 0;color:var(--dsw-alias-label-tertiary);cursor:pointer}
23997
+ .dsh-qa-starters__remove:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsh-qa-error)}
23933
23998
  .dsh-qa-starters__remove:focus-visible{outline:2px solid var(--dsh-qa-accent);outline-offset:1px}
23934
23999
  .dsh-qa-starters__remove svg{width:12px;height:12px;fill:none;stroke:currentColor;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round}
23935
- .dsh-qa-toolpicker__list{display:flex;flex-direction:column;gap:2px;max-height:320px;margin:8px 0 0;padding:0;list-style:none;overflow-y:auto}
24000
+ .dsh-qa-toolpicker__list{display:flex;flex-direction:column;gap:2px;max-height:min(52vh,440px);margin:8px 0 0;padding:0;list-style:none;overflow-y:auto}
23936
24001
  .dsh-qa-toolpicker__group{padding:8px 0 3px;color:var(--dsw-alias-label-tertiary);font-size:11px;font-weight:600;line-height:16px}
23937
24002
  .dsh-qa-toolpicker__row{margin:0}
23938
24003
  .dsh-qa-toolpicker__label{display:grid;grid-template-columns:16px minmax(0,auto) minmax(0,1fr);align-items:baseline;gap:9px;padding:6px 8px;border-radius:8px;cursor:pointer}
23939
24004
  .dsh-qa-toolpicker__label:hover{background:var(--dsw-alias-interactive-bg-hover)}
23940
24005
  .dsh-qa-toolpicker__label input{width:15px;height:15px;margin:0;accent-color:var(--dsh-qa-brand)}
23941
24006
  .dsh-qa-toolpicker__name{color:var(--dsw-alias-label-primary);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px;line-height:18px}
23942
- .dsh-qa-toolpicker__description{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;min-width:0}
24007
+ .dsh-qa-toolpicker__description{display:-webkit-box;overflow:hidden;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;min-width:0;-webkit-box-orient:vertical;-webkit-line-clamp:2}
23943
24008
  .dsh-qa-toolpicker__selected{margin-right:auto;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:17px}
23944
24009
  @media (max-width:720px){.dsh-qa-modal__panel--settings{height:min(640px,calc(100vh - 48px))}.dsh-qa-settings{grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr)}.dsh-qa-settings__nav{flex-direction:row;gap:4px;padding:8px 10px;border-right:0;border-bottom:1px solid var(--dsw-alias-border-l2);overflow-x:auto;overflow-y:hidden}.dsh-qa-settings__tab{white-space:nowrap}.dsh-qa-settings__content{padding:12px 14px 0}.dsh-qa-settings__page{padding-bottom:18px}.dsh-qa-settings__actions{margin:auto -14px -18px;padding:10px 14px}}
23945
24010
  .dsh-qa-surface *{box-sizing:border-box}
@@ -24001,6 +24066,10 @@ body[data-dsh-qa-surface="active"] div:has(>[data-shell-overlay])>:not([data-she
24001
24066
  .dsh-qa-header__files[aria-expanded="true"]{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
24002
24067
  .dsh-qa-header__files svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round}
24003
24068
  .dsh-qa-header__files:focus-visible{outline:2px solid var(--dsh-qa-accent);outline-offset:2px}
24069
+ .dsh-qa-header__settings{display:inline-flex;align-items:center;gap:6px;flex:none;padding:5px 10px;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:13px;line-height:20px;cursor:pointer}
24070
+ .dsh-qa-header__settings:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
24071
+ .dsh-qa-header__settings svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round}
24072
+ .dsh-qa-header__settings:focus-visible{outline:2px solid var(--dsh-qa-accent);outline-offset:2px}
24004
24073
  .dsh-qa-role-selector select,.dsh-qa-header__admin{height:30px;padding:4px 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;line-height:20px;cursor:pointer}
24005
24074
  .dsh-qa-role-selector select:hover,.dsh-qa-header__admin:hover{border-color:var(--dsw-alias-label-dimmed);color:var(--dsw-alias-label-primary)}
24006
24075
  .dsh-qa-role-selector select:focus-visible,.dsh-qa-header__admin:focus-visible{outline:2px solid var(--dsh-qa-accent);outline-offset:1px}