@klarkxy/dsh-zhihu 0.1.6 → 0.1.8
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/README.md +26 -8
- package/docs/README.zh-CN.md +25 -7
- package/icon.svg +14 -0
- package/lib/client.js +34 -213
- package/lib/index.js +4 -1
- package/lib/index.js.map +1 -1
- package/package.json +30 -21
package/README.md
CHANGED
|
@@ -2,17 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
Zhihu search, answers, knowledge bases, and usage tracking for DSH.
|
|
4
4
|
|
|
5
|
-
[简体中文](https://github.com/klarkxy/dsh-
|
|
5
|
+
[简体中文](https://github.com/klarkxy/dsh-plugins/blob/main/plugins/dsh-zhihu/docs/README.zh-CN.md)
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
|
-
Requires Node.js ≥22 and DSH `0.1.7-
|
|
9
|
+
Requires Node.js ≥22 and DSH `0.1.7-rc.2`. No repository build is needed. Install:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install @klarkxy/dsh-zhihu
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Then load it:
|
|
10
16
|
|
|
11
17
|
```sh
|
|
12
18
|
dsh plugin --profile web add @klarkxy/dsh-zhihu
|
|
13
19
|
```
|
|
14
20
|
|
|
15
|
-
Restart DSH Web, open **
|
|
21
|
+
Restart DSH Web, open **Plugins → @klarkxy/dsh-zhihu**, and enter your Access Secret (DSH credential `ZHIHU_ACCESS_TOKEN`). Use the full scoped name; the unscoped `dsh-zhihu` package belongs to another maintainer.
|
|
16
22
|
|
|
17
23
|
To enable agent tools, add this entry to the plugin list in the agent's `agent.cordis.yml`:
|
|
18
24
|
|
|
@@ -22,14 +28,26 @@ To enable agent tools, add this entry to the plugin list in the agent's `agent.c
|
|
|
22
28
|
|
|
23
29
|
## Use
|
|
24
30
|
|
|
25
|
-
DSH Web provides search, settings, usage, and knowledge-base views.
|
|
31
|
+
DSH Web provides search, settings, usage, and knowledge-base views. Open **Plugins → @klarkxy/dsh-zhihu** for configuration, usage, knowledge bases, and search; the agent tools are included.
|
|
26
32
|
|
|
27
|
-
|
|
33
|
+
Five agent tools are available once the tools entry is enabled:
|
|
28
34
|
|
|
29
|
-
|
|
35
|
+
- `zhihu_search`: search within Zhihu for community evidence; results are community/reader feedback only, never canon, and never written into project files.
|
|
36
|
+
- `zhihu_global_search`: search the wider web beyond Zhihu through the open platform's global search; reference only.
|
|
37
|
+
- `zhihu_hot_list`: pull the Zhihu hot list to see current community trends; reference for topics and hotspots only.
|
|
38
|
+
- `zhihu_ask`: ask Zhihu 直答, an OpenAI-compatible AI answer service grounded in Zhihu community content; suited for research and background investigation.
|
|
39
|
+
- `zhihu_knowledge_search`: retrieve RAG fragments from Zhihu knowledge bases — public bases by default, with personal and subscription recall scopes available after you upload material on Zhihu's web side.
|
|
40
|
+
|
|
41
|
+
Usage is tracked as daily counters of calls, failures, and returned results; usage views default to the last 30 days and accept at most 90. Knowledge-base uploads are limited to 20 MB per file.
|
|
42
|
+
|
|
43
|
+
Search covers Zhihu in-site search, the wider web, the hot list, Zhihu 直答 AI answers, and public knowledge bases. Uploaded reference files are stored in Zhihu's cloud; do not upload unpublished manuscripts.
|
|
44
|
+
|
|
45
|
+
When [@klarkxy/dsh-web-search-manager](https://www.npmjs.com/package/@klarkxy/dsh-web-search-manager) is also installed in the same profile, this plugin registers **Zhihu global search** as a provider in its web search settings. Enable that provider to use Zhihu's global search through the standard web search tool with the Access Secret from Zhihu settings. The dedicated Zhihu tools work independently.
|
|
30
46
|
|
|
31
47
|
## Development
|
|
32
48
|
|
|
33
|
-
Read [contracts](https://github.com/klarkxy/dsh-
|
|
49
|
+
Read [contracts](https://github.com/klarkxy/dsh-plugins/blob/main/plugins/dsh-zhihu/src/contracts.ts) and [tools](https://github.com/klarkxy/dsh-plugins/blob/main/plugins/dsh-zhihu/src/tools.ts) for the API.
|
|
50
|
+
|
|
51
|
+
[Publishing](https://github.com/klarkxy/dsh-plugins/blob/main/docs/editor-plugin-migration.md) · [License](https://github.com/klarkxy/dsh-plugins/blob/main/plugins/dsh-zhihu/LICENSE)
|
|
34
52
|
|
|
35
|
-
|
|
53
|
+
The client accepts structural host controls and has native HTML fallbacks. Building or using this package does not require application-private UI packages. Agent tools, credentials, RPC contracts and storage identifiers are unchanged.
|
package/docs/README.zh-CN.md
CHANGED
|
@@ -2,17 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
DSH 知乎搜索、直答、知识库与用量插件。
|
|
4
4
|
|
|
5
|
-
[English](https://github.com/klarkxy/dsh-
|
|
5
|
+
[English](https://github.com/klarkxy/dsh-plugins/blob/main/plugins/dsh-zhihu/README.md)
|
|
6
6
|
|
|
7
7
|
## 安装
|
|
8
8
|
|
|
9
|
-
需要 Node.js ≥22、DSH `0.1.7-
|
|
9
|
+
需要 Node.js ≥22、DSH `0.1.7-rc.2`,无需构建本仓库。安装:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install @klarkxy/dsh-zhihu
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
然后加载:
|
|
10
16
|
|
|
11
17
|
```sh
|
|
12
18
|
dsh plugin --profile web add @klarkxy/dsh-zhihu
|
|
13
19
|
```
|
|
14
20
|
|
|
15
|
-
重启 DSH Web
|
|
21
|
+
重启 DSH Web,从「插件」打开「知乎(@klarkxy/dsh-zhihu)」填写 Access Secret(DSH 凭据 `ZHIHU_ACCESS_TOKEN`)。请使用完整 scoped 包名;无 scope 的 `dsh-zhihu` 属于其他维护者。
|
|
16
22
|
|
|
17
23
|
模型需要使用知乎工具时,在所用 `agent.cordis.yml` 的插件列表加入:
|
|
18
24
|
|
|
@@ -22,14 +28,26 @@ dsh plugin --profile web add @klarkxy/dsh-zhihu
|
|
|
22
28
|
|
|
23
29
|
## 使用
|
|
24
30
|
|
|
25
|
-
DSH Web
|
|
31
|
+
DSH Web 提供搜索、设置、用量与知识库视图。在「插件 → 知乎(@klarkxy/dsh-zhihu)」配置、查看用量、管理知识库和搜索;模型工具随插件一同提供。
|
|
32
|
+
|
|
33
|
+
启用 tools 入口后,模型可使用五个工具:
|
|
34
|
+
|
|
35
|
+
- `zhihu_search`:知乎站内搜索,拉取社区证据;结果仅作社区/读者反馈参考,不构成 canon,也不直接写入项目文件。
|
|
36
|
+
- `zhihu_global_search`:知乎开放平台全网搜索,检索站外公开网页资料;仅作参考。
|
|
37
|
+
- `zhihu_hot_list`:拉取知乎热榜,了解当前社区热点;仅作题材与热点参考。
|
|
38
|
+
- `zhihu_ask`:调用知乎直答(OpenAI 兼容的 AI 问答),基于知乎社区内容生成综合回答;适合考据与背景调研。
|
|
39
|
+
- `zhihu_knowledge_search`:检索知乎知识库(RAG 片段),默认只查公开库;在知乎网页端上传过个人资料后可加个人/订阅召回范围。
|
|
40
|
+
|
|
41
|
+
用量按日计数(调用次数、失败次数与成功调用返回的条目数),视图默认展示最近 30 天,最多可查 90 天。知识库上传单文件上限 20 MB。
|
|
26
42
|
|
|
27
43
|
可查询站内、全网、热榜、直答和公开知识库。上传的参考文件保存在知乎云端,请勿上传未发表手稿。
|
|
28
44
|
|
|
29
|
-
同一 profile
|
|
45
|
+
同一 profile 还安装 [@klarkxy/dsh-web-search-manager](https://www.npmjs.com/package/@klarkxy/dsh-web-search-manager) 时,本插件会向网络搜索注册「知乎全网搜索」后端。在网络搜索设置中启用它,即可让通用网络搜索工具使用知乎的全网搜索能力,并共用「知乎资料」中配置的 Access Secret。专用知乎工具仍可独立使用。
|
|
30
46
|
|
|
31
47
|
## 开发
|
|
32
48
|
|
|
33
|
-
接口见 [contracts](https://github.com/klarkxy/dsh-
|
|
49
|
+
接口见 [contracts](https://github.com/klarkxy/dsh-plugins/blob/main/plugins/dsh-zhihu/src/contracts.ts) 与 [tools](https://github.com/klarkxy/dsh-plugins/blob/main/plugins/dsh-zhihu/src/tools.ts)。
|
|
50
|
+
|
|
51
|
+
[发布维护](https://github.com/klarkxy/dsh-plugins/blob/main/docs/editor-plugin-migration.md) · [许可证](https://github.com/klarkxy/dsh-plugins/blob/main/plugins/dsh-zhihu/LICENSE)
|
|
34
52
|
|
|
35
|
-
|
|
53
|
+
客户端接收宿主提供的结构化控件,缺失时使用原生 HTML 控件。构建和使用本包不依赖应用私有 UI 包;Agent 工具、凭据、RPC 合同和存储标识保持不变。
|
package/icon.svg
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36" fill="none">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="zbubble" x1="6" y1="6" x2="30" y2="28" gradientUnits="userSpaceOnUse">
|
|
4
|
+
<stop stop-color="#4D75F5"/>
|
|
5
|
+
<stop offset="1" stop-color="#8EB6FF"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
</defs>
|
|
8
|
+
<g transform="translate(3.6 3.6) scale(.8)">
|
|
9
|
+
<path d="M6 9C6 7.3 7.3 6 9 6H27C28.7 6 30 7.3 30 9V21C30 22.7 28.7 24 27 24H20L13 30V24H9C7.3 24 6 22.7 6 21V9Z" fill="url(#zbubble)"/>
|
|
10
|
+
<path d="M11 12H25M11 12V19M25 12V19M11 19H25M18 12V19" stroke="#E0EBFF" stroke-width="2" stroke-linecap="round"/>
|
|
11
|
+
<circle cx="14.5" cy="15.5" r="1.4" fill="#65DED0"/>
|
|
12
|
+
<circle cx="21.5" cy="15.5" r="1.4" fill="#65DED0"/>
|
|
13
|
+
</g>
|
|
14
|
+
</svg>
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
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
|
|
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
|
-
|
|
715
|
-
|
|
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
|
|
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)(
|
|
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)(
|
|
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)(
|
|
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)(
|
|
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)(
|
|
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)(
|
|
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)(
|
|
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)(
|
|
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
|
|
1856
|
-
|
|
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 [
|
|
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:
|
|
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:
|
|
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)(
|
|
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)(
|
|
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)(
|
|
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
|
-
|
|
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
|
-
|
|
2145
|
-
|
|
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
|
|
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
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
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;
|
package/lib/index.js
CHANGED
|
@@ -204,10 +204,13 @@ const ZHIHU_WEB_SEARCH_ID = "zhihu-global";
|
|
|
204
204
|
const ZHIHU_WEB_SEARCH_DESCRIPTOR = {
|
|
205
205
|
id: ZHIHU_WEB_SEARCH_ID,
|
|
206
206
|
label: "知乎全网搜索",
|
|
207
|
-
description: "
|
|
207
|
+
description: "融合知乎问答与全网内容,返回可溯源的搜索结果。",
|
|
208
208
|
credentialRef: ZHIHU_CREDENTIAL_REF,
|
|
209
209
|
credentialShared: true,
|
|
210
|
+
credentialHint: "与「知乎资料」共用 Access Secret",
|
|
210
211
|
billing: "request",
|
|
212
|
+
pricing: "注册可获 5,000 次/天试用额度;超额价格需向平台咨询。",
|
|
213
|
+
pricingUrl: "https://developer.zhihu.com/",
|
|
211
214
|
signupUrl: "https://developer.zhihu.com"
|
|
212
215
|
};
|
|
213
216
|
function sourceFrom(url, title, snippet) {
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/zhihu-knowledge.ts","../src/host-rpc.ts","../src/web-search-provider.ts","../src/index.ts"],"sourcesContent":["/**\n * 知乎知识库的管理侧能力:列知识库、上传文件。仅供设置页 RPC 使用,\n * 不暴露为模型工具——上传会把文件送入知乎云端,必须是用户在界面上显式发起。\n *\n * 端点(来源:github.com/klarkxy/zhihu-search,src/zhihu_search/upstream/http_client.py):\n * - 列表:GET /api/v1/knowledge/bases?Scope=all|created|subscribed\n * - 上传:POST /api/v1/knowledge/files(multipart: File + 可选 KnowledgeBaseID),同步解析\n */\nimport {\n parseZhihuEnvelope,\n zhihuFetchJson,\n ZhihuSearchError,\n type ZhihuClientOptions,\n} from './zhihu-client.ts'\n\nexport const ZHIHU_KNOWLEDGE_LIST_VERSION = 1\nexport const ZHIHU_KNOWLEDGE_UPLOAD_VERSION = 1\n/** 设置页 RPC 走 JSON/base64 传输,限额压到 20MB(平台上限 100MB)。 */\nexport const ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES = 20 * 1024 * 1024\nexport const ZHIHU_KNOWLEDGE_UPLOAD_TIMEOUT_MS = 180_000\n\nconst KNOWLEDGE_BASES_PATH = '/api/v1/knowledge/bases'\nconst KNOWLEDGE_FILES_PATH = '/api/v1/knowledge/files'\n\nexport const ZHIHU_KNOWLEDGE_FILE_EXTENSIONS = [\n '.pdf', '.md', '.txt', '.ppt', '.pptx', '.xlsx', '.xls', '.docx', '.doc',\n '.webp', '.png', '.jpg', '.mobi', '.epub', '.csv', '.azw3',\n] as const\n\nconst KNOWLEDGE_CONTENT_TYPES: Record<string, string> = {\n '.pdf': 'application/pdf',\n '.md': 'text/markdown',\n '.txt': 'text/plain',\n '.ppt': 'application/vnd.ms-powerpoint',\n '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n '.xls': 'application/vnd.ms-excel',\n '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n '.doc': 'application/msword',\n '.webp': 'image/webp',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.mobi': 'application/x-mobipocket-ebook',\n '.epub': 'application/epub+zip',\n '.csv': 'text/csv',\n '.azw3': 'application/vnd.amazon.ebook',\n}\n\nexport type ZhihuKnowledgeBase = {\n id: string\n name: string\n relation: string\n visibility: string\n isDefault: boolean\n contentCount: number\n}\n\nexport type ZhihuKnowledgeBaseList = {\n version: typeof ZHIHU_KNOWLEDGE_LIST_VERSION\n bases: ZhihuKnowledgeBase[]\n}\n\nfunction normalizeBase(raw: Record<string, unknown>): ZhihuKnowledgeBase {\n return {\n id: typeof raw.KnowledgeBaseID === 'string' ? raw.KnowledgeBaseID : '',\n name: typeof raw.Name === 'string' && raw.Name.length > 0 ? raw.Name : '(未命名知识库)',\n relation: typeof raw.Relation === 'string' ? raw.Relation : '',\n visibility: typeof raw.Visibility === 'string' ? raw.Visibility : '',\n isDefault: raw.IsDefault === true,\n contentCount: typeof raw.ContentCount === 'number' ? raw.ContentCount : 0,\n }\n}\n\nexport async function listZhihuKnowledgeBases(options: ZhihuClientOptions = {}): Promise<ZhihuKnowledgeBaseList> {\n const body = await zhihuFetchJson(KNOWLEDGE_BASES_PATH, {\n params: { Scope: 'all' },\n }, '知乎知识库列表', options)\n const data = parseZhihuEnvelope(body) as { Items?: unknown }\n const items = Array.isArray(data.Items) ? data.Items : []\n return {\n version: ZHIHU_KNOWLEDGE_LIST_VERSION,\n bases: items\n .filter((item): item is Record<string, unknown> => !!item && typeof item === 'object' && !Array.isArray(item))\n .map(normalizeBase)\n .filter((base) => base.id.length > 0),\n }\n}\n\nexport type ZhihuKnowledgeUploadInput = {\n fileName: string\n data: Uint8Array\n /** 指定目标知识库;缺省进默认库。 */\n knowledgeBaseId?: string\n}\n\nexport type ZhihuKnowledgeUpload = {\n version: typeof ZHIHU_KNOWLEDGE_UPLOAD_VERSION\n knowledgeBaseId: string\n recallContentId: string\n fileName: string\n fileSize: number\n title: string\n abstract: string\n originUrl: string\n}\n\n/** 校验文件名与大小,返回小写扩展名。 */\nexport function checkKnowledgeFile(fileName: string, size: number): string {\n const cleaned = fileName.trim()\n if (!cleaned) throw new ZhihuSearchError('BAD_RESPONSE', '知识库文件名不能为空。')\n // 去掉路径成分,只保留文件名\n const base = cleaned.split(/[\\\\/]/).pop() ?? cleaned\n for (const ch of base) {\n const code = ch.codePointAt(0) ?? 0\n if (code < 32 || code === 127) throw new ZhihuSearchError('BAD_RESPONSE', '知识库文件名不能包含控制字符。')\n }\n if (new TextEncoder().encode(base).length > 255) {\n throw new ZhihuSearchError('BAD_RESPONSE', '知识库文件名不能超过 255 个 UTF-8 字节。')\n }\n if (size <= 0) throw new ZhihuSearchError('BAD_RESPONSE', '知识库文件内容不能为空。')\n if (size > ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES) {\n throw new ZhihuSearchError('BAD_RESPONSE', `知识库文件大小不能超过 ${ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES / 1024 / 1024}MB。`)\n }\n const dot = base.lastIndexOf('.')\n const ext = dot >= 0 ? base.slice(dot).toLowerCase() : ''\n if (!(ZHIHU_KNOWLEDGE_FILE_EXTENSIONS as readonly string[]).includes(ext)) {\n throw new ZhihuSearchError('BAD_RESPONSE', `知识库上传仅支持 ${ZHIHU_KNOWLEDGE_FILE_EXTENSIONS.join('、')}。`)\n }\n return ext\n}\n\nexport async function uploadZhihuKnowledgeFile(\n input: ZhihuKnowledgeUploadInput,\n options: ZhihuClientOptions = {},\n): Promise<ZhihuKnowledgeUpload> {\n const cleaned = (input.fileName.trim().split(/[\\\\/]/).pop() ?? input.fileName.trim())\n const ext = checkKnowledgeFile(input.fileName, input.data.byteLength)\n const form = new FormData()\n if (input.knowledgeBaseId) form.set('KnowledgeBaseID', input.knowledgeBaseId)\n form.set('File', new Blob([input.data.buffer as ArrayBuffer], { type: KNOWLEDGE_CONTENT_TYPES[ext] ?? 'application/octet-stream' }), cleaned)\n const body = await zhihuFetchJson(KNOWLEDGE_FILES_PATH, {\n formData: form,\n }, '知乎知识库上传', { ...options, timeoutMs: options.timeoutMs ?? ZHIHU_KNOWLEDGE_UPLOAD_TIMEOUT_MS })\n const data = parseZhihuEnvelope(body) as Record<string, unknown>\n return {\n version: ZHIHU_KNOWLEDGE_UPLOAD_VERSION,\n knowledgeBaseId: typeof data.KnowledgeBaseID === 'string' ? data.KnowledgeBaseID : '',\n recallContentId: typeof data.RecallContentID === 'string' ? data.RecallContentID : '',\n fileName: typeof data.FileName === 'string' ? data.FileName : cleaned,\n fileSize: typeof data.FileSize === 'number' ? data.FileSize : input.data.byteLength,\n title: typeof data.Title === 'string' ? data.Title : '',\n abstract: typeof data.Abstract === 'string' ? data.Abstract : '',\n originUrl: typeof data.OriginUrl === 'string' ? data.OriginUrl : '',\n }\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\n\nconst CHANNEL_PATTERN = /^\\/[A-Za-z0-9._~-]+$/\nconst ENDPOINT_SEGMENT = /^[A-Za-z0-9_$.-]+$/\nconst MAX_BODY_BYTES = 64 * 1024 * 1024\n\nexport type HostRpcHandler = (endpoint: string, payload: unknown, signal: AbortSignal) => Promise<unknown>\n\nexport type HostRpcContext = {\n webServer: {\n register: (route: {\n kind: 'prefix'\n path: string\n handler: (req: IncomingMessage, res: ServerResponse) => void | Promise<void>\n }) => () => void\n }\n connection: {\n requestRejection?: (request: IncomingMessage) => number | undefined\n }\n}\n\n/** Standalone copy of manuscript Host RPC registration; this package cannot depend on manuscript. */\nexport function registerHostRpc(ctx: HostRpcContext, channel: string, handler: HostRpcHandler): () => void {\n if (!CHANNEL_PATTERN.test(channel) || channel === '/api') {\n throw new Error(`invalid RPC channel ${JSON.stringify(channel)}`)\n }\n return ctx.webServer.register({\n kind: 'prefix',\n path: channel,\n handler: (req, res) => dispatchHostRpc(ctx, channel, handler, req, res),\n })\n}\n\nfunction endpointFromRpcPath(channel: string, pathname: string): string | undefined {\n if (!pathname.startsWith(`${channel}/`)) return undefined\n const endpoint = pathname.slice(channel.length + 1)\n if (endpoint.split('/').some((segment) => segment === '' || segment === '.' || segment === '..' || !ENDPOINT_SEGMENT.test(segment))) {\n return undefined\n }\n return endpoint\n}\n\nasync function dispatchHostRpc(\n ctx: HostRpcContext,\n channel: string,\n handler: HostRpcHandler,\n req: IncomingMessage,\n res: ServerResponse,\n): Promise<void> {\n const rejection = ctx.connection.requestRejection?.(req)\n if (rejection !== undefined) {\n res.writeHead(rejection)\n res.end(rejection === 401 ? 'unauthorized' : 'forbidden')\n return\n }\n const abort = new AbortController()\n res.on('close', () => {\n if (!res.writableEnded) abort.abort()\n })\n const url = new URL(req.url ?? '/', 'http://dsh.internal')\n const endpoint = endpointFromRpcPath(channel, url.pathname)\n if (req.method !== 'POST' || endpoint === undefined) {\n res.writeHead(404)\n res.end('not found')\n return\n }\n const contentType = String(req.headers['content-type'] ?? '').split(';', 1)[0]?.trim().toLowerCase()\n if (contentType !== 'application/json') {\n res.writeHead(415)\n res.end('content type must be application/json')\n return\n }\n const chunks: Buffer[] = []\n let received = 0\n for await (const chunk of req) {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)\n received += buffer.byteLength\n if (received > MAX_BODY_BYTES) {\n res.writeHead(413, { connection: 'close' })\n res.end()\n req.destroy()\n return\n }\n chunks.push(buffer)\n }\n let body: unknown\n try {\n body = JSON.parse(Buffer.concat(chunks).toString('utf8') || 'null')\n } catch {\n res.writeHead(400)\n res.end('body is not JSON')\n return\n }\n const record = body && typeof body === 'object' && !Array.isArray(body) ? body as Record<string, unknown> : {}\n const rpcId = typeof record.rpcId === 'string' ? record.rpcId : 'invalid-request'\n if (record.type !== 'client-request' || record.method !== endpoint) {\n res.writeHead(200, { 'content-type': 'application/json' })\n res.end(JSON.stringify({\n type: 'server-response',\n rpcId,\n result: {\n ok: false,\n error: {\n code: 'gateway/bad-request',\n message: record.method !== endpoint\n ? `method ${JSON.stringify(record.method)} does not match endpoint ${JSON.stringify(endpoint)}`\n : 'invalid client-request message',\n details: { issues: [] },\n },\n },\n }))\n return\n }\n try {\n const result = await handler(endpoint, record.payload, abort.signal)\n res.writeHead(200, { 'content-type': 'application/json' })\n res.end(JSON.stringify({ type: 'server-response', rpcId, result }))\n } catch (error) {\n res.writeHead(500)\n res.end(`handler failure: ${String(error)}`)\n }\n}\n","/**\n * Optional web-search-manager backend. Registers only when this profile already\n * provides `webSearchManager`; Zhihu still works without that plugin.\n * Official model tool remains `web_search`. Dedicated `zhihu_global_search` is unchanged.\n */\nimport { ZHIHU_CREDENTIAL_REF } from './contracts.ts'\nimport { reportExecuted, type ZhihuClientOptions, type ZhihuSearchExecuted } from './zhihu-client.ts'\nimport {\n executeZhihuGlobalSearch,\n ZHIHU_GLOBAL_SEARCH_MAX_COUNT,\n} from './operations.ts'\n\ntype ZhihuWebSearchHost = {\n run<T>(execute: (signal: AbortSignal) => Promise<T>, signal: AbortSignal): Promise<T>\n toolOptions: ZhihuClientOptions & { onExecuted: (event: ZhihuSearchExecuted) => void }\n}\n\nexport const ZHIHU_WEB_SEARCH_ID = 'zhihu-global'\n\nexport const ZHIHU_WEB_SEARCH_DESCRIPTOR = {\n id: ZHIHU_WEB_SEARCH_ID,\n label: '知乎全网搜索',\n description: '使用已配置的知乎 Access Secret 检索公开网页。与「知乎资料」共用同一份凭证。',\n credentialRef: ZHIHU_CREDENTIAL_REF,\n credentialShared: true,\n billing: 'request' as const,\n signupUrl: 'https://developer.zhihu.com',\n}\n\nexport type ZhihuWebSearchSource = { url: string; title?: string; snippet?: string }\nexport type ZhihuWebSearchResult = { sources: ZhihuWebSearchSource[]; truncated?: boolean }\nexport type ZhihuWebSearchRequest = { query: string; maxResults?: number }\n\nexport type ZhihuWebSearchProvider = {\n readonly id: string\n available(): boolean\n search(request: ZhihuWebSearchRequest, signal?: AbortSignal): Promise<ZhihuWebSearchResult>\n}\n\nexport type ZhihuWebSearchManager = {\n registerSearchProvider(\n descriptor: typeof ZHIHU_WEB_SEARCH_DESCRIPTOR,\n factory: (options: { apiKey?: string; timeoutMs: number }) => ZhihuWebSearchProvider,\n ): () => void\n}\n\nexport type ZhihuWebSearchProviderOptions = ZhihuClientOptions & {\n apiKey?: string\n onExecuted?: (event: ZhihuSearchExecuted) => void\n}\n\nfunction sourceFrom(url: string, title: string, snippet: string): ZhihuWebSearchSource | undefined {\n let parsed: URL\n try { parsed = new URL(url) } catch { return }\n if (!['https:', 'http:'].includes(parsed.protocol) || parsed.username || parsed.password) return\n return {\n url: parsed.href,\n ...(title ? { title: title.slice(0, 1000) } : {}),\n ...(snippet ? { snippet: snippet.slice(0, 8000) } : {}),\n }\n}\n\nfunction isWebSearchManager(value: unknown): value is ZhihuWebSearchManager {\n return !!value && typeof value === 'object' && typeof (value as ZhihuWebSearchManager).registerSearchProvider === 'function'\n}\n\nexport function createZhihuWebSearchProvider(options: ZhihuWebSearchProviderOptions): ZhihuWebSearchProvider {\n const { apiKey, onExecuted, ...client } = options\n return {\n id: ZHIHU_WEB_SEARCH_ID,\n available() { return Boolean(apiKey?.trim()) },\n async search(request, signal) {\n if (!apiKey?.trim()) throw new Error('知乎全网搜索未配置 Access Secret。')\n if (!request.query?.trim() || request.query.length > 4000) throw new Error('查询无效。')\n const count = request.maxResults ?? 5\n if (!Number.isInteger(count) || count < 1 || count > ZHIHU_GLOBAL_SEARCH_MAX_COUNT) {\n throw new Error(`结果数须为 1 至 ${ZHIHU_GLOBAL_SEARCH_MAX_COUNT}。`)\n }\n try {\n signal?.throwIfAborted()\n const result = await executeZhihuGlobalSearch(request.query.trim(), count, 'all', {\n ...client,\n signal,\n env: {},\n resolveCredential: async () => apiKey,\n })\n reportExecuted(onExecuted, { ok: true, results: result.items.length })\n const sources = result.items.flatMap(item => sourceFrom(item.url, item.title, item.summary) ?? [])\n return { sources: sources.slice(0, count), truncated: sources.length > count }\n } catch (error) {\n reportExecuted(onExecuted, { ok: false, results: 0 })\n throw error\n }\n },\n }\n}\n\nexport function registerZhihuGlobalSearchProvider(\n manager: ZhihuWebSearchManager,\n service: ZhihuWebSearchHost,\n): () => void {\n return manager.registerSearchProvider(ZHIHU_WEB_SEARCH_DESCRIPTOR, options => {\n const provider = createZhihuWebSearchProvider({\n ...service.toolOptions,\n apiKey: options.apiKey,\n timeoutMs: options.timeoutMs,\n })\n return {\n id: provider.id,\n available: () => provider.available(),\n search: (request, signal) => service.run(\n combined => provider.search(request, combined),\n signal ?? new AbortController().signal,\n ),\n }\n })\n}\n\n/** Wait for `webSearchManager` if this profile loaded it; no-op otherwise. */\nexport function bindZhihuWebSearch(\n ctx: { inject(deps: readonly string[], apply: (inner: { get(name: string): unknown }) => (() => void) | void): unknown },\n service: ZhihuWebSearchHost,\n): void {\n ctx.inject(['webSearchManager'], (inner) => {\n let manager: unknown\n try { manager = inner.get('webSearchManager') }\n catch { return }\n if (!isWebSearchManager(manager)) return\n return registerZhihuGlobalSearchProvider(manager, service)\n })\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { credentialRef } from '@deepseek-ai/dsh-credentials'\nimport { executeZhihuSearch, ZHIHU_SEARCH_DEFAULT_COUNT } from './search-api.ts'\nimport {\n executeZhihuGlobalSearch, executeZhihuHotList, executeZhihuAsk, executeZhihuKnowledgeSearch,\n normalizeRecallScopes, ZHIHU_ASK_MODELS, ZHIHU_ASK_DEFAULT_MODEL,\n} from './operations.ts'\nimport { listZhihuKnowledgeBases, uploadZhihuKnowledgeFile, ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES } from './zhihu-knowledge.ts'\nimport { type ZhihuClientOptions, type ZhihuSearchExecuted, ZhihuSearchError } from './zhihu-client.ts'\nimport { createZhihuUsageRecorder, resolveDays, zhihuUsageDomainSpec, type ZhihuUsageRecorder } from './usage.ts'\nimport { ZHIHU_RPC_CHANNEL, ZHIHU_CREDENTIAL_REF, ZHIHU_SEARCH_EVENT, type ZhihuRpcResult } from './contracts.ts'\nimport { registerHostRpc, type HostRpcContext } from './host-rpc.ts'\nimport { bindZhihuWebSearch } from './web-search-provider.ts'\n\nexport const name = '@klarkxy/dsh-zhihu'\nexport const inject = ['connection', 'credentials', 'storageDomain', 'webServer'] as const\nexport type ZhihuService = {\n call(endpoint: string, payload: unknown, signal: AbortSignal): Promise<ZhihuRpcResult>\n run<T>(execute: (signal: AbortSignal) => Promise<T>, signal: AbortSignal): Promise<T>\n dispose(): Promise<void>\n usageSummary(days: unknown): Promise<{ days: unknown[] }>\n toolOptions: ZhihuClientOptions & { onExecuted: (event: ZhihuSearchExecuted) => void }\n}\n\ntype Host = Context & HostRpcContext & {\n credentials: { resolve: (ref: ReturnType<typeof credentialRef>) => Promise<{ value: string } | undefined> }\n}\nconst fail = (code: string, message: string): ZhihuRpcResult => ({ ok: false, error: { code, message, details: {} } })\n\n/** One shared service for direct UI RPC and optional Tool wrappers. */\nexport function createZhihuService(options: ZhihuClientOptions, usage: ZhihuUsageRecorder, notify: (event: ZhihuSearchExecuted) => void = () => {}): ZhihuService {\n // Serialize read-modify-write counters; concurrent tools must not lose increments.\n let pendingUsage = Promise.resolve()\n const lifetime = new AbortController()\n const active = new Set<Promise<unknown>>()\n const run: ZhihuService['run'] = (execute, signal) => {\n const combined = AbortSignal.any([signal, lifetime.signal])\n const request = Promise.resolve().then(() => { combined.throwIfAborted(); return execute(combined) })\n active.add(request)\n return request.finally(() => active.delete(request))\n }\n const record = (event: ZhihuSearchExecuted) => {\n pendingUsage = pendingUsage.then(() => usage.record(event)).catch(() => {})\n try { notify(event) } catch { /* observer failure does not change a request */ }\n }\n const service = {\n toolOptions: { ...options, onExecuted: record },\n async usageSummary(days: unknown) { await pendingUsage; return { days: await usage.read(resolveDays(days)) } },\n async call(endpoint: string, payload: unknown, signal: AbortSignal): Promise<ZhihuRpcResult> {\n if (signal.aborted) return fail('cancelled', '请求已取消')\n const body = payload && typeof payload === 'object' && !Array.isArray(payload) ? payload as Record<string, unknown> : {}\n const client = { ...options, signal }\n let counted = false\n try {\n if (endpoint === 'usage.summary') { await pendingUsage; return { ok: true, value: { days: await usage.read(resolveDays(body.days)) } } }\n const query = typeof body.query === 'string' ? body.query : ''\n if (['search', 'global.search', 'ask', 'knowledge.search'].includes(endpoint) && (!query.trim() || query.length > 4000)) {\n return fail('bad-request', '请输入不超过 4000 字符的查询')\n }\n let value: unknown\n let results = 0\n counted = true\n if (endpoint === 'search') {\n const result = await executeZhihuSearch(query, typeof body.count === 'number' ? body.count : ZHIHU_SEARCH_DEFAULT_COUNT, client)\n value = result; results = result.items.length\n } else if (endpoint === 'global.search') {\n const result = await executeZhihuGlobalSearch(query, typeof body.count === 'number' ? body.count : 10,\n body.searchDb === 'realtime' || body.searchDb === 'static' ? body.searchDb : 'all', client)\n value = result; results = result.items.length\n } else if (endpoint === 'hot.list') {\n const result = await executeZhihuHotList(typeof body.limit === 'number' ? body.limit : 10, client)\n value = result; results = result.items.length\n } else if (endpoint === 'ask') {\n const model = (ZHIHU_ASK_MODELS as readonly unknown[]).includes(body.model) ? body.model as typeof ZHIHU_ASK_MODELS[number] : ZHIHU_ASK_DEFAULT_MODEL\n value = await executeZhihuAsk(query, model, client); results = 1\n } else if (endpoint === 'knowledge.search') {\n const result = await executeZhihuKnowledgeSearch(query, typeof body.limit === 'number' ? body.limit : 5, normalizeRecallScopes(body.recallScopes), client)\n value = result; results = result.items.length\n } else if (endpoint === 'knowledge.bases') {\n const result = await listZhihuKnowledgeBases(client); value = result; results = result.bases.length\n } else if (endpoint === 'knowledge.upload') {\n const contentBase64 = typeof body.contentBase64 === 'string' ? body.contentBase64 : ''\n if (!contentBase64) throw new Error('缺少文件内容。')\n if (contentBase64.length > Math.ceil(ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES / 3) * 4 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(contentBase64)) {\n return fail('bad-request', '文件内容无效或超过 20 MB')\n }\n const upload = await uploadZhihuKnowledgeFile({\n fileName: typeof body.fileName === 'string' ? body.fileName : '',\n data: new Uint8Array(Buffer.from(contentBase64, 'base64')),\n knowledgeBaseId: typeof body.knowledgeBaseId === 'string' && body.knowledgeBaseId.trim() ? body.knowledgeBaseId.trim() : undefined,\n }, client)\n value = { upload }; results = 1\n } else {\n counted = false\n return fail('bad-request', `unknown endpoint ${endpoint}`)\n }\n record({ ok: true, results })\n return { ok: true, value }\n } catch (error) {\n if (counted) record({ ok: false, results: 0 })\n if (signal.aborted) return fail('cancelled', '请求已取消')\n const code = error instanceof ZhihuSearchError ? error.code.toLowerCase().replaceAll('_', '-') : 'internal'\n return fail(code, error instanceof Error ? error.message : '知乎请求失败')\n }\n },\n }\n return {\n ...service,\n run,\n async call(endpoint, payload, signal) {\n if (signal.aborted || lifetime.signal.aborted) return fail('cancelled', '请求已取消')\n try { return await run(combined => service.call(endpoint, payload, combined), signal) }\n catch (error) {\n if (signal.aborted || lifetime.signal.aborted) return fail('cancelled', '请求已取消')\n throw error\n }\n },\n async dispose() {\n lifetime.abort()\n await Promise.allSettled([...active])\n await pendingUsage\n },\n }\n}\n\nexport async function apply(ctx: Context): Promise<void> {\n const host = ctx as Host\n const domain = await ctx.storageDomain.open(zhihuUsageDomainSpec)\n const service = createZhihuService({\n resolveCredential: async () => (await host.credentials.resolve(credentialRef(ZHIHU_CREDENTIAL_REF)))?.value,\n }, createZhihuUsageRecorder(domain.table('daily')), event => {\n const emit = ctx.emit as unknown as (name: string, event: ZhihuSearchExecuted) => void\n emit.call(ctx, ZHIHU_SEARCH_EVENT, event)\n })\n ctx.effect(() => async () => { await service.dispose(); await domain.close() }, 'zhihu.usageDomainClose')\n ctx.provide('zhihu', service)\n ctx.effect(() => registerHostRpc(host, ZHIHU_RPC_CHANNEL, service.call))\n bindZhihuWebSearch(ctx, service)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/zhihu-knowledge.ts","../src/host-rpc.ts","../src/web-search-provider.ts","../src/index.ts"],"sourcesContent":["/**\n * 知乎知识库的管理侧能力:列知识库、上传文件。仅供设置页 RPC 使用,\n * 不暴露为模型工具——上传会把文件送入知乎云端,必须是用户在界面上显式发起。\n *\n * 端点(来源:github.com/klarkxy/zhihu-search,src/zhihu_search/upstream/http_client.py):\n * - 列表:GET /api/v1/knowledge/bases?Scope=all|created|subscribed\n * - 上传:POST /api/v1/knowledge/files(multipart: File + 可选 KnowledgeBaseID),同步解析\n */\nimport {\n parseZhihuEnvelope,\n zhihuFetchJson,\n ZhihuSearchError,\n type ZhihuClientOptions,\n} from './zhihu-client.ts'\n\nexport const ZHIHU_KNOWLEDGE_LIST_VERSION = 1\nexport const ZHIHU_KNOWLEDGE_UPLOAD_VERSION = 1\n/** 设置页 RPC 走 JSON/base64 传输,限额压到 20MB(平台上限 100MB)。 */\nexport const ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES = 20 * 1024 * 1024\nexport const ZHIHU_KNOWLEDGE_UPLOAD_TIMEOUT_MS = 180_000\n\nconst KNOWLEDGE_BASES_PATH = '/api/v1/knowledge/bases'\nconst KNOWLEDGE_FILES_PATH = '/api/v1/knowledge/files'\n\nexport const ZHIHU_KNOWLEDGE_FILE_EXTENSIONS = [\n '.pdf', '.md', '.txt', '.ppt', '.pptx', '.xlsx', '.xls', '.docx', '.doc',\n '.webp', '.png', '.jpg', '.mobi', '.epub', '.csv', '.azw3',\n] as const\n\nconst KNOWLEDGE_CONTENT_TYPES: Record<string, string> = {\n '.pdf': 'application/pdf',\n '.md': 'text/markdown',\n '.txt': 'text/plain',\n '.ppt': 'application/vnd.ms-powerpoint',\n '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n '.xls': 'application/vnd.ms-excel',\n '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n '.doc': 'application/msword',\n '.webp': 'image/webp',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.mobi': 'application/x-mobipocket-ebook',\n '.epub': 'application/epub+zip',\n '.csv': 'text/csv',\n '.azw3': 'application/vnd.amazon.ebook',\n}\n\nexport type ZhihuKnowledgeBase = {\n id: string\n name: string\n relation: string\n visibility: string\n isDefault: boolean\n contentCount: number\n}\n\nexport type ZhihuKnowledgeBaseList = {\n version: typeof ZHIHU_KNOWLEDGE_LIST_VERSION\n bases: ZhihuKnowledgeBase[]\n}\n\nfunction normalizeBase(raw: Record<string, unknown>): ZhihuKnowledgeBase {\n return {\n id: typeof raw.KnowledgeBaseID === 'string' ? raw.KnowledgeBaseID : '',\n name: typeof raw.Name === 'string' && raw.Name.length > 0 ? raw.Name : '(未命名知识库)',\n relation: typeof raw.Relation === 'string' ? raw.Relation : '',\n visibility: typeof raw.Visibility === 'string' ? raw.Visibility : '',\n isDefault: raw.IsDefault === true,\n contentCount: typeof raw.ContentCount === 'number' ? raw.ContentCount : 0,\n }\n}\n\nexport async function listZhihuKnowledgeBases(options: ZhihuClientOptions = {}): Promise<ZhihuKnowledgeBaseList> {\n const body = await zhihuFetchJson(KNOWLEDGE_BASES_PATH, {\n params: { Scope: 'all' },\n }, '知乎知识库列表', options)\n const data = parseZhihuEnvelope(body) as { Items?: unknown }\n const items = Array.isArray(data.Items) ? data.Items : []\n return {\n version: ZHIHU_KNOWLEDGE_LIST_VERSION,\n bases: items\n .filter((item): item is Record<string, unknown> => !!item && typeof item === 'object' && !Array.isArray(item))\n .map(normalizeBase)\n .filter((base) => base.id.length > 0),\n }\n}\n\nexport type ZhihuKnowledgeUploadInput = {\n fileName: string\n data: Uint8Array\n /** 指定目标知识库;缺省进默认库。 */\n knowledgeBaseId?: string\n}\n\nexport type ZhihuKnowledgeUpload = {\n version: typeof ZHIHU_KNOWLEDGE_UPLOAD_VERSION\n knowledgeBaseId: string\n recallContentId: string\n fileName: string\n fileSize: number\n title: string\n abstract: string\n originUrl: string\n}\n\n/** 校验文件名与大小,返回小写扩展名。 */\nexport function checkKnowledgeFile(fileName: string, size: number): string {\n const cleaned = fileName.trim()\n if (!cleaned) throw new ZhihuSearchError('BAD_RESPONSE', '知识库文件名不能为空。')\n // 去掉路径成分,只保留文件名\n const base = cleaned.split(/[\\\\/]/).pop() ?? cleaned\n for (const ch of base) {\n const code = ch.codePointAt(0) ?? 0\n if (code < 32 || code === 127) throw new ZhihuSearchError('BAD_RESPONSE', '知识库文件名不能包含控制字符。')\n }\n if (new TextEncoder().encode(base).length > 255) {\n throw new ZhihuSearchError('BAD_RESPONSE', '知识库文件名不能超过 255 个 UTF-8 字节。')\n }\n if (size <= 0) throw new ZhihuSearchError('BAD_RESPONSE', '知识库文件内容不能为空。')\n if (size > ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES) {\n throw new ZhihuSearchError('BAD_RESPONSE', `知识库文件大小不能超过 ${ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES / 1024 / 1024}MB。`)\n }\n const dot = base.lastIndexOf('.')\n const ext = dot >= 0 ? base.slice(dot).toLowerCase() : ''\n if (!(ZHIHU_KNOWLEDGE_FILE_EXTENSIONS as readonly string[]).includes(ext)) {\n throw new ZhihuSearchError('BAD_RESPONSE', `知识库上传仅支持 ${ZHIHU_KNOWLEDGE_FILE_EXTENSIONS.join('、')}。`)\n }\n return ext\n}\n\nexport async function uploadZhihuKnowledgeFile(\n input: ZhihuKnowledgeUploadInput,\n options: ZhihuClientOptions = {},\n): Promise<ZhihuKnowledgeUpload> {\n const cleaned = (input.fileName.trim().split(/[\\\\/]/).pop() ?? input.fileName.trim())\n const ext = checkKnowledgeFile(input.fileName, input.data.byteLength)\n const form = new FormData()\n if (input.knowledgeBaseId) form.set('KnowledgeBaseID', input.knowledgeBaseId)\n form.set('File', new Blob([input.data.buffer as ArrayBuffer], { type: KNOWLEDGE_CONTENT_TYPES[ext] ?? 'application/octet-stream' }), cleaned)\n const body = await zhihuFetchJson(KNOWLEDGE_FILES_PATH, {\n formData: form,\n }, '知乎知识库上传', { ...options, timeoutMs: options.timeoutMs ?? ZHIHU_KNOWLEDGE_UPLOAD_TIMEOUT_MS })\n const data = parseZhihuEnvelope(body) as Record<string, unknown>\n return {\n version: ZHIHU_KNOWLEDGE_UPLOAD_VERSION,\n knowledgeBaseId: typeof data.KnowledgeBaseID === 'string' ? data.KnowledgeBaseID : '',\n recallContentId: typeof data.RecallContentID === 'string' ? data.RecallContentID : '',\n fileName: typeof data.FileName === 'string' ? data.FileName : cleaned,\n fileSize: typeof data.FileSize === 'number' ? data.FileSize : input.data.byteLength,\n title: typeof data.Title === 'string' ? data.Title : '',\n abstract: typeof data.Abstract === 'string' ? data.Abstract : '',\n originUrl: typeof data.OriginUrl === 'string' ? data.OriginUrl : '',\n }\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\n\nconst CHANNEL_PATTERN = /^\\/[A-Za-z0-9._~-]+$/\nconst ENDPOINT_SEGMENT = /^[A-Za-z0-9_$.-]+$/\nconst MAX_BODY_BYTES = 64 * 1024 * 1024\n\nexport type HostRpcHandler = (endpoint: string, payload: unknown, signal: AbortSignal) => Promise<unknown>\n\nexport type HostRpcContext = {\n webServer: {\n register: (route: {\n kind: 'prefix'\n path: string\n handler: (req: IncomingMessage, res: ServerResponse) => void | Promise<void>\n }) => () => void\n }\n connection: {\n requestRejection?: (request: IncomingMessage) => number | undefined\n }\n}\n\n/** Standalone copy of manuscript Host RPC registration; this package cannot depend on manuscript. */\nexport function registerHostRpc(ctx: HostRpcContext, channel: string, handler: HostRpcHandler): () => void {\n if (!CHANNEL_PATTERN.test(channel) || channel === '/api') {\n throw new Error(`invalid RPC channel ${JSON.stringify(channel)}`)\n }\n return ctx.webServer.register({\n kind: 'prefix',\n path: channel,\n handler: (req, res) => dispatchHostRpc(ctx, channel, handler, req, res),\n })\n}\n\nfunction endpointFromRpcPath(channel: string, pathname: string): string | undefined {\n if (!pathname.startsWith(`${channel}/`)) return undefined\n const endpoint = pathname.slice(channel.length + 1)\n if (endpoint.split('/').some((segment) => segment === '' || segment === '.' || segment === '..' || !ENDPOINT_SEGMENT.test(segment))) {\n return undefined\n }\n return endpoint\n}\n\nasync function dispatchHostRpc(\n ctx: HostRpcContext,\n channel: string,\n handler: HostRpcHandler,\n req: IncomingMessage,\n res: ServerResponse,\n): Promise<void> {\n const rejection = ctx.connection.requestRejection?.(req)\n if (rejection !== undefined) {\n res.writeHead(rejection)\n res.end(rejection === 401 ? 'unauthorized' : 'forbidden')\n return\n }\n const abort = new AbortController()\n res.on('close', () => {\n if (!res.writableEnded) abort.abort()\n })\n const url = new URL(req.url ?? '/', 'http://dsh.internal')\n const endpoint = endpointFromRpcPath(channel, url.pathname)\n if (req.method !== 'POST' || endpoint === undefined) {\n res.writeHead(404)\n res.end('not found')\n return\n }\n const contentType = String(req.headers['content-type'] ?? '').split(';', 1)[0]?.trim().toLowerCase()\n if (contentType !== 'application/json') {\n res.writeHead(415)\n res.end('content type must be application/json')\n return\n }\n const chunks: Buffer[] = []\n let received = 0\n for await (const chunk of req) {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)\n received += buffer.byteLength\n if (received > MAX_BODY_BYTES) {\n res.writeHead(413, { connection: 'close' })\n res.end()\n req.destroy()\n return\n }\n chunks.push(buffer)\n }\n let body: unknown\n try {\n body = JSON.parse(Buffer.concat(chunks).toString('utf8') || 'null')\n } catch {\n res.writeHead(400)\n res.end('body is not JSON')\n return\n }\n const record = body && typeof body === 'object' && !Array.isArray(body) ? body as Record<string, unknown> : {}\n const rpcId = typeof record.rpcId === 'string' ? record.rpcId : 'invalid-request'\n if (record.type !== 'client-request' || record.method !== endpoint) {\n res.writeHead(200, { 'content-type': 'application/json' })\n res.end(JSON.stringify({\n type: 'server-response',\n rpcId,\n result: {\n ok: false,\n error: {\n code: 'gateway/bad-request',\n message: record.method !== endpoint\n ? `method ${JSON.stringify(record.method)} does not match endpoint ${JSON.stringify(endpoint)}`\n : 'invalid client-request message',\n details: { issues: [] },\n },\n },\n }))\n return\n }\n try {\n const result = await handler(endpoint, record.payload, abort.signal)\n res.writeHead(200, { 'content-type': 'application/json' })\n res.end(JSON.stringify({ type: 'server-response', rpcId, result }))\n } catch (error) {\n res.writeHead(500)\n res.end(`handler failure: ${String(error)}`)\n }\n}\n","/**\n * Optional web-search-manager backend. Registers only when this profile already\n * provides `webSearchManager`; Zhihu still works without that plugin.\n * Official model tool remains `web_search`. Dedicated `zhihu_global_search` is unchanged.\n */\nimport { ZHIHU_CREDENTIAL_REF } from './contracts.ts'\nimport { reportExecuted, type ZhihuClientOptions, type ZhihuSearchExecuted } from './zhihu-client.ts'\nimport {\n executeZhihuGlobalSearch,\n ZHIHU_GLOBAL_SEARCH_MAX_COUNT,\n} from './operations.ts'\n\ntype ZhihuWebSearchHost = {\n run<T>(execute: (signal: AbortSignal) => Promise<T>, signal: AbortSignal): Promise<T>\n toolOptions: ZhihuClientOptions & { onExecuted: (event: ZhihuSearchExecuted) => void }\n}\n\nexport const ZHIHU_WEB_SEARCH_ID = 'zhihu-global'\n\nexport const ZHIHU_WEB_SEARCH_DESCRIPTOR = {\n id: ZHIHU_WEB_SEARCH_ID,\n label: '知乎全网搜索',\n description: '融合知乎问答与全网内容,返回可溯源的搜索结果。',\n credentialRef: ZHIHU_CREDENTIAL_REF,\n credentialShared: true,\n credentialHint: '与「知乎资料」共用 Access Secret',\n billing: 'request' as const,\n pricing: '注册可获 5,000 次/天试用额度;超额价格需向平台咨询。',\n pricingUrl: 'https://developer.zhihu.com/',\n signupUrl: 'https://developer.zhihu.com',\n}\n\nexport type ZhihuWebSearchSource = { url: string; title?: string; snippet?: string }\nexport type ZhihuWebSearchResult = { sources: ZhihuWebSearchSource[]; truncated?: boolean }\nexport type ZhihuWebSearchRequest = { query: string; maxResults?: number }\n\nexport type ZhihuWebSearchProvider = {\n readonly id: string\n available(): boolean\n search(request: ZhihuWebSearchRequest, signal?: AbortSignal): Promise<ZhihuWebSearchResult>\n}\n\nexport type ZhihuWebSearchManager = {\n registerSearchProvider(\n descriptor: typeof ZHIHU_WEB_SEARCH_DESCRIPTOR,\n factory: (options: { apiKey?: string; timeoutMs: number }) => ZhihuWebSearchProvider,\n ): () => void\n}\n\nexport type ZhihuWebSearchProviderOptions = ZhihuClientOptions & {\n apiKey?: string\n onExecuted?: (event: ZhihuSearchExecuted) => void\n}\n\nfunction sourceFrom(url: string, title: string, snippet: string): ZhihuWebSearchSource | undefined {\n let parsed: URL\n try { parsed = new URL(url) } catch { return }\n if (!['https:', 'http:'].includes(parsed.protocol) || parsed.username || parsed.password) return\n return {\n url: parsed.href,\n ...(title ? { title: title.slice(0, 1000) } : {}),\n ...(snippet ? { snippet: snippet.slice(0, 8000) } : {}),\n }\n}\n\nfunction isWebSearchManager(value: unknown): value is ZhihuWebSearchManager {\n return !!value && typeof value === 'object' && typeof (value as ZhihuWebSearchManager).registerSearchProvider === 'function'\n}\n\nexport function createZhihuWebSearchProvider(options: ZhihuWebSearchProviderOptions): ZhihuWebSearchProvider {\n const { apiKey, onExecuted, ...client } = options\n return {\n id: ZHIHU_WEB_SEARCH_ID,\n available() { return Boolean(apiKey?.trim()) },\n async search(request, signal) {\n if (!apiKey?.trim()) throw new Error('知乎全网搜索未配置 Access Secret。')\n if (!request.query?.trim() || request.query.length > 4000) throw new Error('查询无效。')\n const count = request.maxResults ?? 5\n if (!Number.isInteger(count) || count < 1 || count > ZHIHU_GLOBAL_SEARCH_MAX_COUNT) {\n throw new Error(`结果数须为 1 至 ${ZHIHU_GLOBAL_SEARCH_MAX_COUNT}。`)\n }\n try {\n signal?.throwIfAborted()\n const result = await executeZhihuGlobalSearch(request.query.trim(), count, 'all', {\n ...client,\n signal,\n env: {},\n resolveCredential: async () => apiKey,\n })\n reportExecuted(onExecuted, { ok: true, results: result.items.length })\n const sources = result.items.flatMap(item => sourceFrom(item.url, item.title, item.summary) ?? [])\n return { sources: sources.slice(0, count), truncated: sources.length > count }\n } catch (error) {\n reportExecuted(onExecuted, { ok: false, results: 0 })\n throw error\n }\n },\n }\n}\n\nexport function registerZhihuGlobalSearchProvider(\n manager: ZhihuWebSearchManager,\n service: ZhihuWebSearchHost,\n): () => void {\n return manager.registerSearchProvider(ZHIHU_WEB_SEARCH_DESCRIPTOR, options => {\n const provider = createZhihuWebSearchProvider({\n ...service.toolOptions,\n apiKey: options.apiKey,\n timeoutMs: options.timeoutMs,\n })\n return {\n id: provider.id,\n available: () => provider.available(),\n search: (request, signal) => service.run(\n combined => provider.search(request, combined),\n signal ?? new AbortController().signal,\n ),\n }\n })\n}\n\n/** Wait for `webSearchManager` if this profile loaded it; no-op otherwise. */\nexport function bindZhihuWebSearch(\n ctx: { inject(deps: readonly string[], apply: (inner: { get(name: string): unknown }) => (() => void) | void): unknown },\n service: ZhihuWebSearchHost,\n): void {\n ctx.inject(['webSearchManager'], (inner) => {\n let manager: unknown\n try { manager = inner.get('webSearchManager') }\n catch { return }\n if (!isWebSearchManager(manager)) return\n return registerZhihuGlobalSearchProvider(manager, service)\n })\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { credentialRef } from '@deepseek-ai/dsh-credentials'\nimport { executeZhihuSearch, ZHIHU_SEARCH_DEFAULT_COUNT } from './search-api.ts'\nimport {\n executeZhihuGlobalSearch, executeZhihuHotList, executeZhihuAsk, executeZhihuKnowledgeSearch,\n normalizeRecallScopes, ZHIHU_ASK_MODELS, ZHIHU_ASK_DEFAULT_MODEL,\n} from './operations.ts'\nimport { listZhihuKnowledgeBases, uploadZhihuKnowledgeFile, ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES } from './zhihu-knowledge.ts'\nimport { type ZhihuClientOptions, type ZhihuSearchExecuted, ZhihuSearchError } from './zhihu-client.ts'\nimport { createZhihuUsageRecorder, resolveDays, zhihuUsageDomainSpec, type ZhihuUsageRecorder } from './usage.ts'\nimport { ZHIHU_RPC_CHANNEL, ZHIHU_CREDENTIAL_REF, ZHIHU_SEARCH_EVENT, type ZhihuRpcResult } from './contracts.ts'\nimport { registerHostRpc, type HostRpcContext } from './host-rpc.ts'\nimport { bindZhihuWebSearch } from './web-search-provider.ts'\n\nexport const name = '@klarkxy/dsh-zhihu'\nexport const inject = ['connection', 'credentials', 'storageDomain', 'webServer'] as const\nexport type ZhihuService = {\n call(endpoint: string, payload: unknown, signal: AbortSignal): Promise<ZhihuRpcResult>\n run<T>(execute: (signal: AbortSignal) => Promise<T>, signal: AbortSignal): Promise<T>\n dispose(): Promise<void>\n usageSummary(days: unknown): Promise<{ days: unknown[] }>\n toolOptions: ZhihuClientOptions & { onExecuted: (event: ZhihuSearchExecuted) => void }\n}\n\ntype Host = Context & HostRpcContext & {\n credentials: { resolve: (ref: ReturnType<typeof credentialRef>) => Promise<{ value: string } | undefined> }\n}\nconst fail = (code: string, message: string): ZhihuRpcResult => ({ ok: false, error: { code, message, details: {} } })\n\n/** One shared service for direct UI RPC and optional Tool wrappers. */\nexport function createZhihuService(options: ZhihuClientOptions, usage: ZhihuUsageRecorder, notify: (event: ZhihuSearchExecuted) => void = () => {}): ZhihuService {\n // Serialize read-modify-write counters; concurrent tools must not lose increments.\n let pendingUsage = Promise.resolve()\n const lifetime = new AbortController()\n const active = new Set<Promise<unknown>>()\n const run: ZhihuService['run'] = (execute, signal) => {\n const combined = AbortSignal.any([signal, lifetime.signal])\n const request = Promise.resolve().then(() => { combined.throwIfAborted(); return execute(combined) })\n active.add(request)\n return request.finally(() => active.delete(request))\n }\n const record = (event: ZhihuSearchExecuted) => {\n pendingUsage = pendingUsage.then(() => usage.record(event)).catch(() => {})\n try { notify(event) } catch { /* observer failure does not change a request */ }\n }\n const service = {\n toolOptions: { ...options, onExecuted: record },\n async usageSummary(days: unknown) { await pendingUsage; return { days: await usage.read(resolveDays(days)) } },\n async call(endpoint: string, payload: unknown, signal: AbortSignal): Promise<ZhihuRpcResult> {\n if (signal.aborted) return fail('cancelled', '请求已取消')\n const body = payload && typeof payload === 'object' && !Array.isArray(payload) ? payload as Record<string, unknown> : {}\n const client = { ...options, signal }\n let counted = false\n try {\n if (endpoint === 'usage.summary') { await pendingUsage; return { ok: true, value: { days: await usage.read(resolveDays(body.days)) } } }\n const query = typeof body.query === 'string' ? body.query : ''\n if (['search', 'global.search', 'ask', 'knowledge.search'].includes(endpoint) && (!query.trim() || query.length > 4000)) {\n return fail('bad-request', '请输入不超过 4000 字符的查询')\n }\n let value: unknown\n let results = 0\n counted = true\n if (endpoint === 'search') {\n const result = await executeZhihuSearch(query, typeof body.count === 'number' ? body.count : ZHIHU_SEARCH_DEFAULT_COUNT, client)\n value = result; results = result.items.length\n } else if (endpoint === 'global.search') {\n const result = await executeZhihuGlobalSearch(query, typeof body.count === 'number' ? body.count : 10,\n body.searchDb === 'realtime' || body.searchDb === 'static' ? body.searchDb : 'all', client)\n value = result; results = result.items.length\n } else if (endpoint === 'hot.list') {\n const result = await executeZhihuHotList(typeof body.limit === 'number' ? body.limit : 10, client)\n value = result; results = result.items.length\n } else if (endpoint === 'ask') {\n const model = (ZHIHU_ASK_MODELS as readonly unknown[]).includes(body.model) ? body.model as typeof ZHIHU_ASK_MODELS[number] : ZHIHU_ASK_DEFAULT_MODEL\n value = await executeZhihuAsk(query, model, client); results = 1\n } else if (endpoint === 'knowledge.search') {\n const result = await executeZhihuKnowledgeSearch(query, typeof body.limit === 'number' ? body.limit : 5, normalizeRecallScopes(body.recallScopes), client)\n value = result; results = result.items.length\n } else if (endpoint === 'knowledge.bases') {\n const result = await listZhihuKnowledgeBases(client); value = result; results = result.bases.length\n } else if (endpoint === 'knowledge.upload') {\n const contentBase64 = typeof body.contentBase64 === 'string' ? body.contentBase64 : ''\n if (!contentBase64) throw new Error('缺少文件内容。')\n if (contentBase64.length > Math.ceil(ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES / 3) * 4 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(contentBase64)) {\n return fail('bad-request', '文件内容无效或超过 20 MB')\n }\n const upload = await uploadZhihuKnowledgeFile({\n fileName: typeof body.fileName === 'string' ? body.fileName : '',\n data: new Uint8Array(Buffer.from(contentBase64, 'base64')),\n knowledgeBaseId: typeof body.knowledgeBaseId === 'string' && body.knowledgeBaseId.trim() ? body.knowledgeBaseId.trim() : undefined,\n }, client)\n value = { upload }; results = 1\n } else {\n counted = false\n return fail('bad-request', `unknown endpoint ${endpoint}`)\n }\n record({ ok: true, results })\n return { ok: true, value }\n } catch (error) {\n if (counted) record({ ok: false, results: 0 })\n if (signal.aborted) return fail('cancelled', '请求已取消')\n const code = error instanceof ZhihuSearchError ? error.code.toLowerCase().replaceAll('_', '-') : 'internal'\n return fail(code, error instanceof Error ? error.message : '知乎请求失败')\n }\n },\n }\n return {\n ...service,\n run,\n async call(endpoint, payload, signal) {\n if (signal.aborted || lifetime.signal.aborted) return fail('cancelled', '请求已取消')\n try { return await run(combined => service.call(endpoint, payload, combined), signal) }\n catch (error) {\n if (signal.aborted || lifetime.signal.aborted) return fail('cancelled', '请求已取消')\n throw error\n }\n },\n async dispose() {\n lifetime.abort()\n await Promise.allSettled([...active])\n await pendingUsage\n },\n }\n}\n\nexport async function apply(ctx: Context): Promise<void> {\n const host = ctx as Host\n const domain = await ctx.storageDomain.open(zhihuUsageDomainSpec)\n const service = createZhihuService({\n resolveCredential: async () => (await host.credentials.resolve(credentialRef(ZHIHU_CREDENTIAL_REF)))?.value,\n }, createZhihuUsageRecorder(domain.table('daily')), event => {\n const emit = ctx.emit as unknown as (name: string, event: ZhihuSearchExecuted) => void\n emit.call(ctx, ZHIHU_SEARCH_EVENT, event)\n })\n ctx.effect(() => async () => { await service.dispose(); await domain.close() }, 'zhihu.usageDomainClose')\n ctx.provide('zhihu', service)\n ctx.effect(() => registerHostRpc(host, ZHIHU_RPC_CHANNEL, service.call))\n bindZhihuWebSearch(ctx, service)\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@klarkxy/dsh-zhihu",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Zhihu search, agent tools, knowledge bases, and usage tracking for DeepSeek Harness.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"type": "module",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"./package.json": "./package.json"
|
|
37
37
|
},
|
|
38
38
|
"files": [
|
|
39
|
+
"icon.svg",
|
|
39
40
|
"lib/*.js",
|
|
40
41
|
"lib/*.js.map",
|
|
41
42
|
"lib/*.d.ts",
|
|
@@ -63,7 +64,7 @@
|
|
|
63
64
|
"entries": [
|
|
64
65
|
{
|
|
65
66
|
"id": "zhihu",
|
|
66
|
-
"title": "
|
|
67
|
+
"title": "知乎",
|
|
67
68
|
"description": "知乎搜索、知识库与用量",
|
|
68
69
|
"feature": "zhihu",
|
|
69
70
|
"service": "zhihu"
|
|
@@ -82,24 +83,37 @@
|
|
|
82
83
|
}
|
|
83
84
|
]
|
|
84
85
|
},
|
|
86
|
+
"scripts": {
|
|
87
|
+
"build": "tsdown && node ../../scripts/editor-plugins/wrap-client.mjs @klarkxy/dsh-zhihu",
|
|
88
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
89
|
+
"test": "vitest run --root ../.. --config vitest.editor-plugins.config.ts --maxWorkers=2 plugins/dsh-zhihu/src"
|
|
90
|
+
},
|
|
85
91
|
"dependencies": {
|
|
86
|
-
"@deepseek-ai/dsh-storage-domain": "0.1.7-alpha.1",
|
|
87
92
|
"zod": "^4.1.5"
|
|
88
93
|
},
|
|
89
94
|
"peerDependencies": {
|
|
90
|
-
"@deepseek-ai/cordis": "^4.0.
|
|
91
|
-
"@deepseek-ai/dsh-credentials": "0.1.7-
|
|
92
|
-
"@deepseek-ai/dsh-
|
|
95
|
+
"@deepseek-ai/cordis": "^4.0.4",
|
|
96
|
+
"@deepseek-ai/dsh-credentials": ">=0.1.7-rc.2",
|
|
97
|
+
"@deepseek-ai/dsh-storage-domain": ">=0.1.7-rc.2",
|
|
98
|
+
"@deepseek-ai/dsh-tools": ">=0.1.7-alpha.1"
|
|
93
99
|
},
|
|
94
100
|
"devDependencies": {
|
|
95
|
-
"@deepseek-ai/cordis": "^4.0.
|
|
96
|
-
"@deepseek-ai/dsh-credentials": "0.1.7-
|
|
97
|
-
"@deepseek-ai/dsh-
|
|
101
|
+
"@deepseek-ai/cordis": "^4.0.4",
|
|
102
|
+
"@deepseek-ai/dsh-credentials": "0.1.7-rc.2",
|
|
103
|
+
"@deepseek-ai/dsh-storage-domain": "0.1.7-rc.2",
|
|
104
|
+
"@deepseek-ai/dsh-tools": "0.1.7-rc.2",
|
|
98
105
|
"react": "^18.2.0",
|
|
99
106
|
"@types/react": "18.3.31",
|
|
100
|
-
"
|
|
107
|
+
"react-dom": "^18.2.0",
|
|
108
|
+
"@types/react-dom": "^18.3.1"
|
|
101
109
|
},
|
|
102
110
|
"peerDependenciesMeta": {
|
|
111
|
+
"@deepseek-ai/dsh-credentials": {
|
|
112
|
+
"optional": true
|
|
113
|
+
},
|
|
114
|
+
"@deepseek-ai/dsh-storage-domain": {
|
|
115
|
+
"optional": true
|
|
116
|
+
},
|
|
103
117
|
"@deepseek-ai/dsh-tools": {
|
|
104
118
|
"optional": true
|
|
105
119
|
}
|
|
@@ -116,23 +130,18 @@
|
|
|
116
130
|
],
|
|
117
131
|
"repository": {
|
|
118
132
|
"type": "git",
|
|
119
|
-
"url": "git+https://github.com/klarkxy/dsh-
|
|
120
|
-
"directory": "
|
|
133
|
+
"url": "git+https://github.com/klarkxy/dsh-plugins.git",
|
|
134
|
+
"directory": "plugins/dsh-zhihu"
|
|
121
135
|
},
|
|
122
|
-
"homepage": "https://github.
|
|
136
|
+
"homepage": "https://klarkxy.github.io/dsh-plugins/plugins/zhihu/",
|
|
123
137
|
"bugs": {
|
|
124
|
-
"url": "https://github.com/klarkxy/dsh-
|
|
138
|
+
"url": "https://github.com/klarkxy/dsh-plugins/issues"
|
|
125
139
|
},
|
|
126
140
|
"publishConfig": {
|
|
127
141
|
"access": "public",
|
|
128
142
|
"registry": "https://registry.npmjs.org/"
|
|
129
143
|
},
|
|
130
144
|
"dshRelease": {
|
|
131
|
-
"contentHash": "
|
|
132
|
-
},
|
|
133
|
-
"scripts": {
|
|
134
|
-
"build": "tsdown && node ../../scripts/wrap-client.mjs @klarkxy/dsh-zhihu",
|
|
135
|
-
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
136
|
-
"test": "vitest run --root ../.. packages/dsh-zhihu/src"
|
|
145
|
+
"contentHash": "abfa1b559afda73ac70b685e2d9bae00fbcc250806fbd1369f9f189fd040e0ca"
|
|
137
146
|
}
|
|
138
|
-
}
|
|
147
|
+
}
|