@klarkxy/dsh-zhihu 0.1.7 → 0.1.9

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
@@ -216,18 +216,15 @@ function createZhihuClientState() {
216
216
  //#region src/client-styles.ts
217
217
  const standaloneOutsideTheme = ":not(.radix-themes *)";
218
218
  const zhihuClientStyles = `
219
- .zhihu-dock {
220
- position: var(--dsh-ext-dock-position, absolute);
221
- right: var(--dsh-ext-dock-right, var(--space-4, 16px));
222
- bottom: var(--dsh-ext-dock-bottom, calc(var(--space-4, 16px) + 44px));
223
- pointer-events: auto;
224
- }
219
+
225
220
  .zhihu-settings-embed {
226
221
  font: 400 var(--font-size-2)/1.5 var(--default-font-family);
227
222
  color: var(--gray-12);
228
223
  display: flex;
229
224
  flex-direction: column;
230
225
  min-width: 0;
226
+ width: 100%;
227
+ max-width: 760px;
231
228
  min-height: 0;
232
229
  gap: 0;
233
230
  }
@@ -238,73 +235,19 @@ const zhihuClientStyles = `
238
235
  padding: var(--space-4) 0 0;
239
236
  overflow: visible;
240
237
  }
241
- .zhihu-toggle {
242
- pointer-events: auto;
243
- font: inherit;
244
- font-family: var(--default-font-family);
245
- font-size: var(--font-size-2);
246
- min-height: var(--control-h, 34px);
247
- color: var(--gray-11);
248
- background: var(--color-panel-solid);
249
- border: 1px solid var(--gray-6);
250
- border-radius: 999px;
251
- padding: 0 14px;
252
- cursor: pointer;
253
- box-shadow: var(--shadow-3);
254
- }
255
- .zhihu-toggle:hover { border-color: var(--accent-9); color: var(--accent-11); background: var(--gray-a3); }
256
- .zhihu-toggle:focus-visible,
257
238
  .zhihu-panel button:focus-visible,
258
239
  .zhihu-panel input:focus-visible,
259
240
  .zhihu-panel select:focus-visible,
260
241
  .zhihu-panel a:focus-visible {
261
242
  box-shadow: 0 0 0 2px var(--accent-a8);
262
243
  }
263
- .zhihu-dock .zhihu-panel {
264
- position: absolute;
265
- top: var(--dsh-ext-panel-top, auto);
266
- right: 0;
267
- bottom: var(--dsh-ext-panel-bottom, calc(100% + 6px));
268
- z-index: 10;
269
- width: min(440px, calc(100vw - 32px));
270
- max-height: min(72vh, 620px);
271
- display: flex;
272
- flex-direction: column;
273
- pointer-events: auto;
274
- font-family: var(--default-font-family);
275
- font-size: var(--font-size-2);
276
- color: var(--gray-12);
277
- background: var(--color-panel-solid);
278
- border: 1px solid var(--gray-6);
279
- border-radius: var(--radius-3);
280
- box-shadow: var(--shadow-4);
281
- overflow: hidden;
282
- }
244
+
283
245
  .zhihu-panel {
284
246
  font-family: var(--default-font-family);
285
247
  font-size: var(--font-size-2);
286
248
  color: var(--gray-12);
287
249
  background: var(--color-panel-solid);
288
250
  }
289
- .zhihu-panel-header {
290
- display: flex;
291
- align-items: center;
292
- justify-content: space-between;
293
- padding: var(--space-2) var(--space-3);
294
- border-bottom: 1px solid var(--gray-6);
295
- }
296
- .zhihu-panel-title {
297
- margin: 0;
298
- font-size: var(--font-size-2);
299
- font-weight: var(--font-weight-medium);
300
- font-family: var(--default-font-family);
301
- }
302
- .zhihu-panel-close {
303
- font: inherit; font-size: var(--font-size-2); min-height: 32px; color: var(--gray-11); background: none; border: none;
304
- border-radius: var(--radius-2); padding: 0 8px; cursor: pointer;
305
- }
306
- .zhihu-panel-close:hover { color: var(--gray-12); background: var(--gray-a3); }
307
- .zhihu-panel-close:disabled { opacity: 0.5; cursor: default; }
308
251
  .zhihu-tabs {
309
252
  display: inline-flex;
310
253
  gap: 2px;
@@ -500,17 +443,13 @@ const zhihuClientStyles = `
500
443
  .zhihu-dots i:nth-child(2) { animation-delay: .2s; }
501
444
  .zhihu-dots i:nth-child(3) { animation-delay: .4s; }
502
445
  @media (prefers-reduced-motion: reduce) {
503
- .zhihu-dock, .zhihu-dock *, .zhihu-panel, .zhihu-panel * {
446
+ .zhihu-panel, .zhihu-panel * {
504
447
  animation: none !important; transition: none !important;
505
448
  transform: none !important; filter: none !important;
506
449
  }
507
450
  .zhihu-dots i { animation: none; }
508
451
  }
509
- /* Local tokens when this overlay is not under .radix-themes. Host Theme
510
- and --dsh-ext-* rail overrides still win inside the Theme tree. Dark
511
- follows body[data-ds-dark-theme] / :root[data-theme=dark], not OS scheme. */
512
- .zhihu-dock${standaloneOutsideTheme},
513
- .zhihu-toggle${standaloneOutsideTheme},
452
+ /* Local tokens follow the host theme when the settings page is outside Radix. */
514
453
  .zhihu-panel${standaloneOutsideTheme} {
515
454
 
516
455
  --default-font-family: "Noto Sans SC", "PingFang SC", "Microsoft YaHei UI", system-ui, sans-serif;
@@ -572,11 +511,7 @@ const zhihuClientStyles = `
572
511
  --shadow-4: 0 0 0 1px #0000000f, 0 8px 40px rgba(0, 0, 0, 0.05), 0 12px 32px -16px #0000000f;
573
512
  color-scheme: light;
574
513
  }
575
- html:not([data-theme]) body[data-ds-dark-theme] .zhihu-dock${standaloneOutsideTheme},
576
- html:not([data-theme]) body[data-ds-dark-theme] .zhihu-toggle${standaloneOutsideTheme},
577
514
  html:not([data-theme]) body[data-ds-dark-theme] .zhihu-panel${standaloneOutsideTheme},
578
- :root[data-theme="dark"] .zhihu-dock${standaloneOutsideTheme},
579
- :root[data-theme="dark"] .zhihu-toggle${standaloneOutsideTheme},
580
515
  :root[data-theme="dark"] .zhihu-panel${standaloneOutsideTheme} {
581
516
 
582
517
  --default-font-family: "Noto Sans SC", "PingFang SC", "Microsoft YaHei UI", system-ui, sans-serif;
@@ -661,12 +596,6 @@ function zhihuQueryKeyDown(event, run) {
661
596
  run.search();
662
597
  }
663
598
  }
664
- function dockEscapeKeyDown(event, run) {
665
- if (event.key !== "Escape") return;
666
- event.stopPropagation();
667
- if (run.loading) return;
668
- run.close();
669
- }
670
599
  function hostComponentsFromRenderProps(props) {
671
600
  if (!props || typeof props !== "object") return {};
672
601
  const record = props;
@@ -711,10 +640,8 @@ function renderSelect(Select, props, className) {
711
640
  }, option.value === "" ? "__empty" : option.value))
712
641
  });
713
642
  }
714
- //#endregion
715
- //#region ../dsh-editor-seats/src/seat-button.tsx
716
- const SeatButton = (0, react.forwardRef)(function SeatButton(props, ref) {
717
- const { host, variant, className, ...rest } = props;
643
+ /** Prefer a structurally supplied host control; standalone Web needs no private UI package. */
644
+ const ZhihuButton = (0, react.forwardRef)(function ZhihuButton({ host, variant, className, ...rest }, ref) {
718
645
  if (host) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(host, {
719
646
  ref,
720
647
  variant,
@@ -737,9 +664,9 @@ const inject = [
737
664
  "remote",
738
665
  "remote.credentials"
739
666
  ];
740
- const SLOT_ID = "zhihu";
667
+ const PACKAGE_NAME = "@klarkxy/dsh-zhihu";
741
668
  const SLOT_ORDER = 120;
742
- const SLOT_LABEL = "知乎资料";
669
+ const SLOT_LABEL = "知乎";
743
670
  const activityDots = () => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
744
671
  className: "zhihu-dots",
745
672
  "aria-hidden": "true",
@@ -1101,7 +1028,7 @@ function SettingsSection(props) {
1101
1028
  if (state.status === "error") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsShell, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1102
1029
  className: "zhihu-error",
1103
1030
  role: "alert",
1104
- children: [`读取失败:${state.error} `, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SeatButton, {
1031
+ children: [`读取失败:${state.error} `, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
1105
1032
  host: props.Button,
1106
1033
  className: "zhihu-button",
1107
1034
  onClick: () => void load(),
@@ -1227,14 +1154,14 @@ function SettingsSection(props) {
1227
1154
  }) : null,
1228
1155
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1229
1156
  className: "zhihu-row",
1230
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SeatButton, {
1157
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
1231
1158
  host: props.Button,
1232
1159
  variant: "danger",
1233
1160
  className: "zhihu-button zhihu-button-danger",
1234
1161
  disabled: busy || keyLocked || !configured,
1235
1162
  onClick: () => void clear(),
1236
1163
  children: busy ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [activityDots(), "处理中…"] }) : "清除"
1237
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SeatButton, {
1164
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
1238
1165
  host: props.Button,
1239
1166
  variant: "primary",
1240
1167
  className: "zhihu-button zhihu-button-primary",
@@ -1480,7 +1407,7 @@ function UsageSection(props) {
1480
1407
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1481
1408
  className: "zhihu-error",
1482
1409
  role: "alert",
1483
- children: [`读取失败:${state.error} `, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SeatButton, {
1410
+ children: [`读取失败:${state.error} `, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
1484
1411
  host: props.Button,
1485
1412
  className: "zhihu-button",
1486
1413
  onClick: () => void load(),
@@ -1737,7 +1664,7 @@ function KnowledgeSection(props) {
1737
1664
  list.status === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1738
1665
  className: "zhihu-error",
1739
1666
  role: "alert",
1740
- children: [`${list.failure.text} `, list.failure.kind !== "credential" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SeatButton, {
1667
+ children: [`${list.failure.text} `, list.failure.kind !== "credential" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
1741
1668
  host: props.Button,
1742
1669
  className: "zhihu-button",
1743
1670
  onClick: () => void load(),
@@ -1766,7 +1693,7 @@ function KnowledgeSection(props) {
1766
1693
  value: base.id,
1767
1694
  label: `${base.name}${base.isDefault ? "(默认)" : ""} · ${base.contentCount} 篇`
1768
1695
  }))]
1769
- }, "zhihu-select"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SeatButton, {
1696
+ }, "zhihu-select"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
1770
1697
  host: props.Button,
1771
1698
  className: "zhihu-button",
1772
1699
  disabled: busy,
@@ -1797,7 +1724,7 @@ function KnowledgeSection(props) {
1797
1724
  disabled: busy,
1798
1725
  onChange: (event) => setFile(event.target.files?.[0])
1799
1726
  }, fileKey),
1800
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SeatButton, {
1727
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
1801
1728
  host: props.Button,
1802
1729
  className: "zhihu-button",
1803
1730
  disabled: busy,
@@ -1812,7 +1739,7 @@ function KnowledgeSection(props) {
1812
1739
  }) : null,
1813
1740
  list.status === "ready" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1814
1741
  className: "zhihu-row",
1815
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SeatButton, {
1742
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
1816
1743
  host: props.Button,
1817
1744
  variant: "primary",
1818
1745
  className: "zhihu-button zhihu-button-primary",
@@ -1840,31 +1767,18 @@ const TAB_LABEL = {
1840
1767
  usage: "用量",
1841
1768
  knowledge: "知识库"
1842
1769
  };
1843
- const OVERLAY_TABS = [
1844
- "search",
1845
- "settings",
1846
- "usage",
1847
- "knowledge"
1848
- ];
1849
1770
  const SETTINGS_TABS = [
1850
1771
  "settings",
1851
1772
  "usage",
1852
1773
  "knowledge",
1853
1774
  "search"
1854
1775
  ];
1855
- function tabLabel(tab, surface) {
1856
- if (tab === "search" && surface === "settings") return "连接测试";
1857
- return TAB_LABEL[tab];
1858
- }
1859
- function ZhihuDock(props) {
1860
- const { rpc, credentials, Select, Dialog, Button, Input } = props;
1861
- const surface = props.surface === "settings" ? "settings" : "overlay";
1862
- const tabs = surface === "settings" ? SETTINGS_TABS : OVERLAY_TABS;
1776
+ function ZhihuSettings(props) {
1777
+ const { rpc, credentials, Select, Button, Input } = props;
1863
1778
  const gateRef = (0, react.useRef)(null);
1864
1779
  if (!gateRef.current) gateRef.current = createZhihuClientState();
1865
1780
  const gate = gateRef.current;
1866
- const [open, setOpen] = (0, react.useState)(surface === "settings");
1867
- const [tab, setTab] = (0, react.useState)(surface === "settings" ? "settings" : "search");
1781
+ const [tab, setTab] = (0, react.useState)("settings");
1868
1782
  const [query, setQuery] = (0, react.useState)("");
1869
1783
  const [mode, setMode] = (0, react.useState)("search");
1870
1784
  const [askModel, setAskModel] = (0, react.useState)("zhida-thinking-1p5");
@@ -1874,23 +1788,7 @@ function ZhihuDock(props) {
1874
1788
  const [outcome, setOutcome] = (0, react.useState)(null);
1875
1789
  const [revision, setRevision] = (0, react.useState)(0);
1876
1790
  const [resultRevision, setResultRevision] = (0, react.useState)(0);
1877
- const toggleRef = (0, react.useRef)(null);
1878
1791
  const queryRef = (0, react.useRef)(null);
1879
- const wasOpen = (0, react.useRef)(false);
1880
- (0, react.useEffect)(() => {
1881
- if (Dialog || surface === "settings") return;
1882
- if (open) {
1883
- wasOpen.current = true;
1884
- queryRef.current?.focus();
1885
- } else if (wasOpen.current) {
1886
- wasOpen.current = false;
1887
- toggleRef.current?.focus();
1888
- }
1889
- }, [
1890
- open,
1891
- Dialog,
1892
- surface
1893
- ]);
1894
1792
  (0, react.useEffect)(() => () => gate.cancel(), [gate]);
1895
1793
  const runSearch = (0, react.useCallback)(async () => {
1896
1794
  if (mode !== "hot" && !query.trim()) return;
@@ -1980,17 +1878,6 @@ function ZhihuDock(props) {
1980
1878
  setAskModel(next);
1981
1879
  resetToIdle();
1982
1880
  };
1983
- const closePanel = (0, react.useCallback)(() => {
1984
- gate.cancel();
1985
- setPhase("idle");
1986
- setOpen(false);
1987
- }, [gate]);
1988
- const onPanelKeyDown = (event) => {
1989
- dockEscapeKeyDown(event, {
1990
- loading: phase === "loading",
1991
- close: closePanel
1992
- });
1993
- };
1994
1881
  const onQueryKeyDown = (event) => {
1995
1882
  zhihuQueryKeyDown(event, {
1996
1883
  disabled: isSearchDisabled(),
@@ -2021,7 +1908,7 @@ function ZhihuDock(props) {
2021
1908
  buttons[next]?.focus();
2022
1909
  buttons[next]?.click();
2023
1910
  },
2024
- children: tabs.map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SeatButton, {
1911
+ children: SETTINGS_TABS.map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
2025
1912
  host: Button,
2026
1913
  type: "button",
2027
1914
  role: "tab",
@@ -2029,7 +1916,7 @@ function ZhihuDock(props) {
2029
1916
  tabIndex: tab === key ? 0 : -1,
2030
1917
  className: "zhihu-tab",
2031
1918
  onClick: () => onTabChange(key),
2032
- children: tabLabel(key, surface)
1919
+ children: TAB_LABEL[key]
2033
1920
  }, key))
2034
1921
  }, "tabs");
2035
1922
  const body = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -2063,7 +1950,7 @@ function ZhihuDock(props) {
2063
1950
  className: "zhihu-scopes",
2064
1951
  role: "group",
2065
1952
  "aria-label": "检索范围",
2066
- children: SCOPE_OPTIONS.map((scope) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SeatButton, {
1953
+ children: SCOPE_OPTIONS.map((scope) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
2067
1954
  host: Button,
2068
1955
  role: "checkbox",
2069
1956
  "aria-checked": scopes.includes(scope.value),
@@ -2086,7 +1973,7 @@ function ZhihuDock(props) {
2086
1973
  }),
2087
1974
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2088
1975
  className: "zhihu-row",
2089
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SeatButton, {
1976
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
2090
1977
  host: Button,
2091
1978
  variant: "primary",
2092
1979
  className: "zhihu-button zhihu-button-primary",
@@ -2094,7 +1981,7 @@ function ZhihuDock(props) {
2094
1981
  disabled: searchDisabled,
2095
1982
  onClick: () => void runSearch(),
2096
1983
  children: phase === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [activityDots(), "请求中…"] }) : mode === "hot" ? "获取热榜" : "搜索"
2097
- }), phase === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SeatButton, {
1984
+ }), phase === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
2098
1985
  host: Button,
2099
1986
  className: "zhihu-button",
2100
1987
  onClick: () => {
@@ -2104,7 +1991,7 @@ function ZhihuDock(props) {
2104
1991
  children: "取消"
2105
1992
  }) : null]
2106
1993
  }),
2107
- surface !== "settings" && phase === "idle" && mode !== "hot" && !query.trim() ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1994
+ phase === "idle" && mode !== "hot" && !query.trim() ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2108
1995
  className: "zhihu-status",
2109
1996
  role: "status",
2110
1997
  children: "输入关键词后搜索。"
@@ -2141,62 +2028,12 @@ function ZhihuDock(props) {
2141
2028
  }) : null
2142
2029
  ]
2143
2030
  }, "body");
2144
- const inner = [
2145
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
2146
- className: "zhihu-panel-header",
2147
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
2148
- className: "zhihu-panel-title",
2149
- children: "知乎资料"
2150
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SeatButton, {
2151
- host: Button,
2152
- className: "zhihu-panel-close",
2153
- disabled: phase === "loading",
2154
- onClick: closePanel,
2155
- children: "关闭"
2156
- })]
2157
- }, "header"),
2158
- tablist,
2159
- body
2160
- ];
2161
- if (surface === "settings") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2162
- className: "zhihu-settings-embed",
2031
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2032
+ className: "zhihu-panel zhihu-settings-embed",
2163
2033
  "data-testid": "zhihu-settings-embed",
2164
2034
  "aria-label": SLOT_LABEL,
2165
2035
  children: [tablist, body]
2166
2036
  });
2167
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2168
- className: "zhihu-dock",
2169
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SeatButton, {
2170
- host: Button,
2171
- ref: toggleRef,
2172
- className: "zhihu-toggle",
2173
- "data-testid": "zhihu-open",
2174
- onClick: () => setOpen(true),
2175
- children: SLOT_LABEL
2176
- }), Dialog ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dialog, {
2177
- open,
2178
- onOpenChange: (next) => {
2179
- if (!next) closePanel();
2180
- else setOpen(true);
2181
- },
2182
- title: "知乎资料",
2183
- className: "file-dialog zhihu-panel",
2184
- overlayClassName: "file-dialog-overlay",
2185
- dismissible: phase !== "loading",
2186
- initialFocusRef: queryRef,
2187
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2188
- "data-testid": "zhihu-panel",
2189
- className: "zhihu-panel-inner",
2190
- children: inner
2191
- })
2192
- }) : open ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
2193
- className: "zhihu-panel",
2194
- "data-testid": "zhihu-panel",
2195
- "aria-label": "知乎资料",
2196
- onKeyDown: onPanelKeyDown,
2197
- children: inner
2198
- }) : null]
2199
- });
2200
2037
  }
2201
2038
  function apply(ctx) {
2202
2039
  ctx.effect(() => {
@@ -2204,33 +2041,17 @@ function apply(ctx) {
2204
2041
  return () => style?.remove();
2205
2042
  }, "zhihu.styles");
2206
2043
  const client = ctx;
2207
- const overlayRender = (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuDock, {
2044
+ const settingsRender = (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuSettings, {
2208
2045
  rpc: client.connection.rpc,
2209
2046
  credentials: wrapCredentials(client.remote.credentials),
2210
- surface: "overlay",
2211
2047
  ...hostComponentsFromRenderProps(props)
2212
2048
  });
2213
- const settingsRender = (props) => {
2214
- const host = hostComponentsFromRenderProps(props);
2215
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuDock, {
2216
- rpc: client.connection.rpc,
2217
- credentials: wrapCredentials(client.remote.credentials),
2218
- surface: "settings",
2219
- ...host
2220
- });
2221
- };
2222
- client.slots.inject("shell.overlay", () => client.slots.register({
2223
- name: "shell.overlay",
2224
- id: SLOT_ID,
2225
- order: SLOT_ORDER,
2226
- label: SLOT_LABEL
2227
- }, overlayRender));
2228
- client.slots.inject("dsh-editor.settings.zhihu", () => client.slots.register({
2229
- name: "dsh-editor.settings.zhihu",
2230
- id: SLOT_ID,
2049
+ ctx.effect(() => client.slots.inject("plugins.bundle.config", () => client.slots.register({
2050
+ name: "plugins.bundle.config",
2051
+ key: PACKAGE_NAME,
2231
2052
  order: SLOT_ORDER,
2232
2053
  label: SLOT_LABEL
2233
- }, settingsRender));
2054
+ }, settingsRender)), "zhihu.settings");
2234
2055
  }
2235
2056
  //#endregion
2236
2057
  exports.apply = apply;
@@ -18,6 +18,16 @@ type ZhihuRpcResult<T = unknown> = {
18
18
  details: Record<string, unknown>;
19
19
  };
20
20
  };
21
+ declare const ZHIHU_QUESTION_RECOMMENDATIONS_TOOL_NAME = "zhihu_question_recommendations";
22
+ declare const ZHIHU_QUESTION_ANSWERS_TOOL_NAME = "zhihu_question_answers";
23
+ declare const ZHIHU_USER_CONTENT_DETAIL_TOOL_NAME = "zhihu_user_content_detail";
24
+ declare const ZHIHU_USER_CONTENT_COMMENTS_TOOL_NAME = "zhihu_user_content_comments";
25
+ declare const ZHIHU_CREATOR_ACCOUNT_STATS_TOOL_NAME = "zhihu_creator_account_stats";
26
+ declare const ZHIHU_CREATOR_CONTENT_STATS_TOOL_NAME = "zhihu_creator_content_stats";
27
+ declare const ZHIHU_QUOTA_TOOL_NAME = "zhihu_quota";
28
+ /** Official quota IDs, not local execution counters or predicted balances. */
29
+ declare const ZHIHU_QUOTA_IDS: readonly ["global_search", "zhihu_search", "hot_list", "question_answers", "zhida_openai", "tools", "knowledge", "user_data", "creator"];
30
+ type ZhihuQuotaId = typeof ZHIHU_QUOTA_IDS[number];
21
31
  //#endregion
22
- export { ZHIHU_ASK_TOOL_NAME, ZHIHU_CREDENTIAL_REF, ZHIHU_GLOBAL_SEARCH_TOOL_NAME, ZHIHU_HOT_LIST_TOOL_NAME, ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME, ZHIHU_RPC_CHANNEL, ZHIHU_SEARCH_EVENT, ZHIHU_SEARCH_TOOL_NAME, ZhihuRpcResult };
32
+ export { ZHIHU_ASK_TOOL_NAME, ZHIHU_CREATOR_ACCOUNT_STATS_TOOL_NAME, ZHIHU_CREATOR_CONTENT_STATS_TOOL_NAME, ZHIHU_CREDENTIAL_REF, ZHIHU_GLOBAL_SEARCH_TOOL_NAME, ZHIHU_HOT_LIST_TOOL_NAME, ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME, ZHIHU_QUESTION_ANSWERS_TOOL_NAME, ZHIHU_QUESTION_RECOMMENDATIONS_TOOL_NAME, ZHIHU_QUOTA_IDS, ZHIHU_QUOTA_TOOL_NAME, ZHIHU_RPC_CHANNEL, ZHIHU_SEARCH_EVENT, ZHIHU_SEARCH_TOOL_NAME, ZHIHU_USER_CONTENT_COMMENTS_TOOL_NAME, ZHIHU_USER_CONTENT_DETAIL_TOOL_NAME, ZhihuQuotaId, ZhihuRpcResult };
23
33
  //# sourceMappingURL=contracts.d.ts.map
package/lib/contracts.js CHANGED
@@ -7,7 +7,26 @@ const ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME = "zhihu_knowledge_search";
7
7
  const ZHIHU_RPC_CHANNEL = "/zhihu";
8
8
  const ZHIHU_CREDENTIAL_REF = "ZHIHU_ACCESS_TOKEN";
9
9
  const ZHIHU_SEARCH_EVENT = "dsh-editor/zhihu-search";
10
+ const ZHIHU_QUESTION_RECOMMENDATIONS_TOOL_NAME = "zhihu_question_recommendations";
11
+ const ZHIHU_QUESTION_ANSWERS_TOOL_NAME = "zhihu_question_answers";
12
+ const ZHIHU_USER_CONTENT_DETAIL_TOOL_NAME = "zhihu_user_content_detail";
13
+ const ZHIHU_USER_CONTENT_COMMENTS_TOOL_NAME = "zhihu_user_content_comments";
14
+ const ZHIHU_CREATOR_ACCOUNT_STATS_TOOL_NAME = "zhihu_creator_account_stats";
15
+ const ZHIHU_CREATOR_CONTENT_STATS_TOOL_NAME = "zhihu_creator_content_stats";
16
+ const ZHIHU_QUOTA_TOOL_NAME = "zhihu_quota";
17
+ /** Official quota IDs, not local execution counters or predicted balances. */
18
+ const ZHIHU_QUOTA_IDS = [
19
+ "global_search",
20
+ "zhihu_search",
21
+ "hot_list",
22
+ "question_answers",
23
+ "zhida_openai",
24
+ "tools",
25
+ "knowledge",
26
+ "user_data",
27
+ "creator"
28
+ ];
10
29
  //#endregion
11
- export { ZHIHU_ASK_TOOL_NAME, ZHIHU_CREDENTIAL_REF, ZHIHU_GLOBAL_SEARCH_TOOL_NAME, ZHIHU_HOT_LIST_TOOL_NAME, ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME, ZHIHU_RPC_CHANNEL, ZHIHU_SEARCH_EVENT, ZHIHU_SEARCH_TOOL_NAME };
30
+ export { ZHIHU_ASK_TOOL_NAME, ZHIHU_CREATOR_ACCOUNT_STATS_TOOL_NAME, ZHIHU_CREATOR_CONTENT_STATS_TOOL_NAME, ZHIHU_CREDENTIAL_REF, ZHIHU_GLOBAL_SEARCH_TOOL_NAME, ZHIHU_HOT_LIST_TOOL_NAME, ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME, ZHIHU_QUESTION_ANSWERS_TOOL_NAME, ZHIHU_QUESTION_RECOMMENDATIONS_TOOL_NAME, ZHIHU_QUOTA_IDS, ZHIHU_QUOTA_TOOL_NAME, ZHIHU_RPC_CHANNEL, ZHIHU_SEARCH_EVENT, ZHIHU_SEARCH_TOOL_NAME, ZHIHU_USER_CONTENT_COMMENTS_TOOL_NAME, ZHIHU_USER_CONTENT_DETAIL_TOOL_NAME };
12
31
 
13
32
  //# sourceMappingURL=contracts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"contracts.js","names":[],"sources":["../src/contracts.ts"],"sourcesContent":["export const ZHIHU_SEARCH_TOOL_NAME = 'zhihu_search'\nexport const ZHIHU_GLOBAL_SEARCH_TOOL_NAME = 'zhihu_global_search'\nexport const ZHIHU_HOT_LIST_TOOL_NAME = 'zhihu_hot_list'\nexport const ZHIHU_ASK_TOOL_NAME = 'zhihu_ask'\nexport const ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME = 'zhihu_knowledge_search'\nexport const ZHIHU_RPC_CHANNEL = '/zhihu'\nexport const ZHIHU_CREDENTIAL_REF = 'ZHIHU_ACCESS_TOKEN'\nexport const ZHIHU_SEARCH_EVENT = 'dsh-editor/zhihu-search'\nexport type ZhihuRpcResult<T = unknown> = { ok: true; value: T } | { ok: false; error: { code: string; message: string; details: Record<string, unknown> } }\n"],"mappings":";AAAA,MAAa,yBAAyB;AACtC,MAAa,gCAAgC;AAC7C,MAAa,2BAA2B;AACxC,MAAa,sBAAsB;AACnC,MAAa,mCAAmC;AAChD,MAAa,oBAAoB;AACjC,MAAa,uBAAuB;AACpC,MAAa,qBAAqB"}
1
+ {"version":3,"file":"contracts.js","names":[],"sources":["../src/contracts.ts"],"sourcesContent":["export const ZHIHU_SEARCH_TOOL_NAME = 'zhihu_search'\nexport const ZHIHU_GLOBAL_SEARCH_TOOL_NAME = 'zhihu_global_search'\nexport const ZHIHU_HOT_LIST_TOOL_NAME = 'zhihu_hot_list'\nexport const ZHIHU_ASK_TOOL_NAME = 'zhihu_ask'\nexport const ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME = 'zhihu_knowledge_search'\nexport const ZHIHU_RPC_CHANNEL = '/zhihu'\nexport const ZHIHU_CREDENTIAL_REF = 'ZHIHU_ACCESS_TOKEN'\nexport const ZHIHU_SEARCH_EVENT = 'dsh-editor/zhihu-search'\nexport type ZhihuRpcResult<T = unknown> = { ok: true; value: T } | { ok: false; error: { code: string; message: string; details: Record<string, unknown> } }\n\nexport const ZHIHU_QUESTION_RECOMMENDATIONS_TOOL_NAME = 'zhihu_question_recommendations'\nexport const ZHIHU_QUESTION_ANSWERS_TOOL_NAME = 'zhihu_question_answers'\nexport const ZHIHU_USER_CONTENT_DETAIL_TOOL_NAME = 'zhihu_user_content_detail'\nexport const ZHIHU_USER_CONTENT_COMMENTS_TOOL_NAME = 'zhihu_user_content_comments'\nexport const ZHIHU_CREATOR_ACCOUNT_STATS_TOOL_NAME = 'zhihu_creator_account_stats'\nexport const ZHIHU_CREATOR_CONTENT_STATS_TOOL_NAME = 'zhihu_creator_content_stats'\nexport const ZHIHU_QUOTA_TOOL_NAME = 'zhihu_quota'\n\n/** Official quota IDs, not local execution counters or predicted balances. */\nexport const ZHIHU_QUOTA_IDS = [\n 'global_search', 'zhihu_search', 'hot_list', 'question_answers',\n 'zhida_openai', 'tools', 'knowledge', 'user_data', 'creator',\n] as const\nexport type ZhihuQuotaId = typeof ZHIHU_QUOTA_IDS[number]\n"],"mappings":";AAAA,MAAa,yBAAyB;AACtC,MAAa,gCAAgC;AAC7C,MAAa,2BAA2B;AACxC,MAAa,sBAAsB;AACnC,MAAa,mCAAmC;AAChD,MAAa,oBAAoB;AACjC,MAAa,uBAAuB;AACpC,MAAa,qBAAqB;AAGlC,MAAa,2CAA2C;AACxD,MAAa,mCAAmC;AAChD,MAAa,sCAAsC;AACnD,MAAa,wCAAwC;AACrD,MAAa,wCAAwC;AACrD,MAAa,wCAAwC;AACrD,MAAa,wBAAwB;;AAGrC,MAAa,kBAAkB;CAC7B;CAAiB;CAAgB;CAAY;CAC7C;CAAgB;CAAS;CAAa;CAAa;AACrD"}
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ZhihuRpcResult } from "./contracts.js";
1
+ import { ZhihuQuotaId, ZhihuRpcResult } from "./contracts.js";
2
2
  import { ZhihuUsageRecorder } from "./usage.js";
3
3
  import { Context } from "@deepseek-ai/cordis";
4
4
  //#region src/zhihu-client.d.ts
@@ -10,6 +10,9 @@ type ZhihuSearchFetcher = (input: string, init?: {
10
10
  }) => Promise<{
11
11
  ok: boolean;
12
12
  status: number;
13
+ headers?: {
14
+ get(name: string): string | null;
15
+ };
13
16
  text(): Promise<string>;
14
17
  json(): Promise<unknown>;
15
18
  }>;
@@ -21,6 +24,7 @@ type ZhihuSearchResolveOptions = {
21
24
  type ZhihuSearchExecuted = {
22
25
  ok: boolean;
23
26
  results: number;
27
+ quotaId?: ZhihuQuotaId;
24
28
  };
25
29
  type ZhihuClientOptions = ZhihuSearchResolveOptions & {
26
30
  fetcher?: ZhihuSearchFetcher;
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { _ as reportExecuted, a as executeZhihuGlobalSearch, c as normalizeRecallScopes, g as parseZhihuEnvelope, h as ZhihuSearchError, i as executeZhihuAsk, n as ZHIHU_ASK_MODELS, o as executeZhihuHotList, p as executeZhihuSearch, s as executeZhihuKnowledgeSearch, t as ZHIHU_ASK_DEFAULT_MODEL, v as zhihuFetchJson } from "./operations.js";
1
+ import { S as zhihuFetchJson, _ as executeZhihuSearch, a as ZHIHU_ASK_DEFAULT_MODEL, b as parseZhihuEnvelope, c as executeZhihuAsk, d as executeZhihuKnowledgeSearch, f as normalizeRecallScopes, i as zhihuOpenPlatformResultCount, l as executeZhihuGlobalSearch, n as executeZhihuOpenPlatform, o as ZHIHU_ASK_MODELS, r as resolveZhihuOpenPlatformOperation, t as ZHIHU_OPEN_PLATFORM_APIS, u as executeZhihuHotList, x as reportExecuted, y as ZhihuSearchError } from "./open-platform.js";
2
2
  import { ZHIHU_CREDENTIAL_REF, ZHIHU_RPC_CHANNEL, ZHIHU_SEARCH_EVENT } from "./contracts.js";
3
3
  import { createZhihuUsageRecorder, resolveDays, zhihuUsageDomainSpec } from "./usage.js";
4
4
  import { credentialRef } from "@deepseek-ai/dsh-credentials";
@@ -305,12 +305,12 @@ const inject = [
305
305
  "storageDomain",
306
306
  "webServer"
307
307
  ];
308
- const fail = (code, message) => ({
308
+ const fail = (code, message, details = {}) => ({
309
309
  ok: false,
310
310
  error: {
311
311
  code,
312
312
  message,
313
- details: {}
313
+ details
314
314
  }
315
315
  });
316
316
  /** One shared service for direct UI RPC and optional Tool wrappers. */
@@ -350,6 +350,9 @@ function createZhihuService(options, usage, notify = () => {}) {
350
350
  signal
351
351
  };
352
352
  let counted = false;
353
+ const operation = resolveZhihuOpenPlatformOperation(endpoint);
354
+ const quotaId = operation ? ZHIHU_OPEN_PLATFORM_APIS[operation].quotaId : void 0;
355
+ const metering = quotaId ? { quotaId } : {};
353
356
  try {
354
357
  if (endpoint === "usage.summary") {
355
358
  await pendingUsage;
@@ -368,7 +371,12 @@ function createZhihuService(options, usage, notify = () => {}) {
368
371
  let value;
369
372
  let results = 0;
370
373
  counted = true;
371
- if (endpoint === "search") {
374
+ if (operation) {
375
+ counted = operation !== "quota";
376
+ const result = await executeZhihuOpenPlatform(operation, payload === void 0 ? {} : payload, client);
377
+ value = result;
378
+ results = zhihuOpenPlatformResultCount(result);
379
+ } else if (endpoint === "search") {
372
380
  const result = await executeZhihuSearch(query, typeof body.count === "number" ? body.count : 5, client);
373
381
  value = result;
374
382
  results = result.items.length;
@@ -406,9 +414,10 @@ function createZhihuService(options, usage, notify = () => {}) {
406
414
  counted = false;
407
415
  return fail("bad-request", `unknown endpoint ${endpoint}`);
408
416
  }
409
- record({
417
+ if (counted) record({
410
418
  ok: true,
411
- results
419
+ results,
420
+ ...metering
412
421
  });
413
422
  return {
414
423
  ok: true,
@@ -417,11 +426,21 @@ function createZhihuService(options, usage, notify = () => {}) {
417
426
  } catch (error) {
418
427
  if (counted) record({
419
428
  ok: false,
420
- results: 0
429
+ results: 0,
430
+ ...metering
421
431
  });
422
432
  if (signal.aborted) return fail("cancelled", "请求已取消");
423
433
  const code = error instanceof ZhihuSearchError ? error.code.toLowerCase().replaceAll("_", "-") : "internal";
424
- return fail(code, error instanceof Error ? error.message : "知乎请求失败");
434
+ const details = {};
435
+ if (error instanceof ZhihuSearchError) {
436
+ for (const key of [
437
+ "status",
438
+ "upstreamCode",
439
+ "retryAfter",
440
+ "retryable"
441
+ ]) if (error[key] !== void 0) details[key] = error[key];
442
+ }
443
+ return fail(code, error instanceof Error ? error.message : "知乎请求失败", details);
425
444
  }
426
445
  }
427
446
  };