@deepseek-ai/dsh-plugin-market 0.0.0-stage → 0.2.1-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.i18n.yaml +43 -0
- package/README.md +116 -2
- package/README.zh.md +117 -0
- package/lib/index.js +661 -0
- package/lib/typert.host.d.ts +3 -0
- package/lib/typert.host.js +407 -0
- package/lib/typert.remote-client.d.ts +31 -0
- package/lib/typert.remote-client.js +259 -0
- package/lib/types/index-url.d.ts +9 -0
- package/lib/types/index-url.js +27 -0
- package/lib/types/index.d.ts +96 -0
- package/lib/types/index.js +351 -0
- package/lib/types/parse-thread.d.ts +12 -0
- package/lib/types/parse-thread.js +61 -0
- package/lib/types/parse.d.ts +25 -0
- package/lib/types/parse.js +36 -0
- package/lib/types/search.d.ts +22 -0
- package/lib/types/search.js +135 -0
- package/lib/types/tools.d.ts +10 -0
- package/lib/types/tools.js +128 -0
- package/lib/types/types.d.ts +149 -0
- package/lib/types/types.js +2 -0
- package/lib/types/worker.d.ts +2 -0
- package/lib/types/worker.js +8 -0
- package/lib/worker.cjs +1759 -0
- package/package.json +86 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeepSeek
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
|
|
2
|
+
# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
|
|
3
|
+
# After editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write packages/boot/plugin-market/README.md
|
|
5
|
+
/:
|
|
6
|
+
en: 847c61ab6dac5fd2
|
|
7
|
+
zh: 4107ba58fbda723e
|
|
8
|
+
/deepseek-ai-dsh-plugin-market:
|
|
9
|
+
en: ee5478f5717295df
|
|
10
|
+
zh: 75a03a6db791fc6b
|
|
11
|
+
/deepseek-ai-dsh-plugin-market/summary:
|
|
12
|
+
en: 05b6a148b03fa0a4
|
|
13
|
+
zh: e5568747e1cf1d16
|
|
14
|
+
/deepseek-ai-dsh-plugin-market/table-of-contents:
|
|
15
|
+
en: 76368b6b1da79c80
|
|
16
|
+
zh: 52384aee991ac542
|
|
17
|
+
/deepseek-ai-dsh-plugin-market/use-this-package:
|
|
18
|
+
en: 880da6f2249be5dc
|
|
19
|
+
zh: af79801b129d774c
|
|
20
|
+
/deepseek-ai-dsh-plugin-market/understand-the-implementation:
|
|
21
|
+
en: fe70456b69339c7a
|
|
22
|
+
zh: 46e53647850af839
|
|
23
|
+
/deepseek-ai-dsh-plugin-market/model-experience:
|
|
24
|
+
en: 215e7ba838619b7b
|
|
25
|
+
zh: a311da3843709f90
|
|
26
|
+
/deepseek-ai-dsh-plugin-market/model-experience/market-listing-tool:
|
|
27
|
+
en: b8183cb06f3e4ba9
|
|
28
|
+
zh: 9a213e7a124f092d
|
|
29
|
+
/deepseek-ai-dsh-plugin-market/model-experience/market-listing-tool/what-the-model-sees:
|
|
30
|
+
en: bcbe6e7d5c763159
|
|
31
|
+
zh: 28cc392bc8e574e4
|
|
32
|
+
/deepseek-ai-dsh-plugin-market/model-experience/market-listing-tool/token-effect:
|
|
33
|
+
en: 2589c52e6deb5e48
|
|
34
|
+
zh: 9a71ca215165a8a5
|
|
35
|
+
/deepseek-ai-dsh-plugin-market/model-experience/market-listing-tool/kv-cache-effect:
|
|
36
|
+
en: 02cf6033092eb236
|
|
37
|
+
zh: cb928bfa6d39a7f7
|
|
38
|
+
/deepseek-ai-dsh-plugin-market/known-limitations-and-deferred-work:
|
|
39
|
+
en: 2097c5644d5b6d85
|
|
40
|
+
zh: 1deb4c97e7efbfc6
|
|
41
|
+
/deepseek-ai-dsh-plugin-market/known-limitations-and-deferred-work/dev-note:
|
|
42
|
+
en: e67f633dc6fe7773
|
|
43
|
+
zh: 3bb0c20c93f16f98
|
package/README.md
CHANGED
|
@@ -1,3 +1,117 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
description: "Host reader of the plugin market indexes a user configures, with installation status, compatibility, and the read-only plugin_market tool."
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
2
5
|
|
|
3
|
-
|
|
6
|
+
# @deepseek-ai/dsh-plugin-market
|
|
7
|
+
|
|
8
|
+
English | [中文](README.zh.md)
|
|
9
|
+
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
`pluginMarket` reads the plugin market indexes the user configures, validates them with [`dsh-plugin-market-index`](../../util/plugin-market-index/README.md), and annotates every entry with the profile's installation status, DSH compatibility, and the exact arguments that install it. The Web [Discover tab](../../client/ui-plugin-market/README.md) and the `plugin_market` agent tool read through it; installation itself goes through [`pluginManager.installBundle`](../plugin-manager/README.md). The format and its rationale live in the [index format Agent Note](../../../.agents/notes/implemented/feature/2026-10-02-plugin-market-index-format.md); the Host and Web design lives in the [Discover Agent Note](../../../.agents/notes/implemented/feature/2026-10-02-plugin-market-discover.md).
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Use this package](#use-this-package)
|
|
17
|
+
- [Understand the implementation](#understand-the-implementation)
|
|
18
|
+
- [Model Experience](#model-experience)
|
|
19
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
20
|
+
- [Dev Note](#dev-note)
|
|
21
|
+
|
|
22
|
+
-----
|
|
23
|
+
|
|
24
|
+
<a id="use-this-package"></a>
|
|
25
|
+
## Use this package
|
|
26
|
+
|
|
27
|
+
The optional [custom plugin markets bundle](../../experimental/plugin-market-bundle/README.md) mounts the service as the `plugin-market` row; shipped profiles leave the bundle off. Like `plugin-manager`, the row is disabled without a profile, and it waits for `pluginManager`. No index source is configured by default, so the Host sends no market request until a user adds one.
|
|
28
|
+
|
|
29
|
+
| Config | Default | Meaning |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| `indexes` | `[]` | Index URLs in display order. A usable URL is in canonical form and uses `http:` or `https:`, without credentials or fragment. The field is volatile: Discover, Settings, and `setIndexes` change it without remounting this service or `plugin-manager`. |
|
|
32
|
+
| `fetchTimeoutMs` | `15000` | Deadline for one index fetch, including its body. |
|
|
33
|
+
| `maxBytes` | `134217728` | Largest accepted index body. |
|
|
34
|
+
| `cacheTtlMs` | `600000` | Lifetime of a successfully read document. |
|
|
35
|
+
|
|
36
|
+
Settings and profile files can store any http(s) string, so the service validates each URL when it lists or reads it. `listIndexes` reports an unusable URL with its refusal, `search` and `entry` refuse it, and no request is sent to it; a repeated URL is listed once.
|
|
37
|
+
|
|
38
|
+
The Remote methods are:
|
|
39
|
+
|
|
40
|
+
- `listIndexes()` returns each configured URL with the title and description of its last successful read and, when the last read failed, its error. It never fetches.
|
|
41
|
+
- `setIndexes(urls)` normalizes and validates each URL not already configured, keeps configured ones as written, refuses a repeated URL, and writes it through `settings.update` to this service's profile entry. It fails with `plugin-market/settings-unavailable` without Settings or a profile entry. The committed list is announced by `plugin-market/changed`.
|
|
42
|
+
- `search(url, query)` accepts only a configured URL, so the service never fetches an arbitrary address. It returns one page of the plugins that match `query`, with the index title, description, and declarations, the document's `fetchedAt`, the `total` number of matches, and the `nextOffset`; each plugin carries its `defaultVersion` and `installation`, and each version its `install` and `compatibility`.
|
|
43
|
+
|
|
44
|
+
The service method `entry(url, name)`, which is not a Remote method, returns one plugin of a configured index in the same form, or `undefined` when the index does not list it.
|
|
45
|
+
|
|
46
|
+
A query selects plugins with every one of its conditions:
|
|
47
|
+
|
|
48
|
+
| Field | Meaning |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `text` | Fuzzy words; see below. Text without letters or digits selects every plugin. |
|
|
51
|
+
| `category` | The plugin's category id. |
|
|
52
|
+
| `labels` | Label ids the plugin must all have. An undeclared category or label id matches no plugin. |
|
|
53
|
+
| `sort` | `index` order; `relevance`, best text match first and index order without text; latest `published` time; or a declared sort `key`, with plugins lacking the value last. Each takes `asc` or `desc` where it has a direction, and ties keep index order. An undeclared sort key leaves index order. |
|
|
54
|
+
| `offset`, `limit` | The page: `offset` is a non-negative integer and `limit` an integer from 1 to 100; other values fail with `plugin-market/invalid-query`. |
|
|
55
|
+
| `refresh` | Fetch again instead of using the cached document. |
|
|
56
|
+
| `fetchedAt` | `fetchedAt` of an earlier page: answer from that document while it is cached, even after `cacheTtlMs`, so later pages continue the same results. |
|
|
57
|
+
|
|
58
|
+
Text matches the package name, author, keywords, and every language of the title, description, and category and label titles. It is split into runs of letters, marks, and digits; a run of Chinese, Japanese, or Korean characters becomes its overlapping character pairs and its last character, so text written without spaces matches without a dictionary. Words are compared after NFKC normalization and without case. Every query word must match an indexed word as a prefix or, from four characters, within an edit distance of one fifth of its length rounded to the nearest integer, at most 2. Name and title matches weigh three times, and keyword matches twice, a match elsewhere.
|
|
59
|
+
|
|
60
|
+
Failures use `plugin-market/invalid-query`, `plugin-market/invalid-index-url`, `plugin-market/unknown-index`, `plugin-market/fetch-failed`, and `plugin-market/invalid-index`; the last carries the JSON path of the offending value.
|
|
61
|
+
|
|
62
|
+
The `plugin_market` tool lists the configured indexes, pages the plugins of one index in index order or, with a `query`, by best match, or pages one plugin's versions. It requires no approval because it reads only the sources the user configured and changes nothing; each version it returns carries the `target` and `registry` to pass to `plugin_manager`'s `install_bundle`, which keeps its own approval. The tool cannot change index sources. Creator mode keeps its row beside `plugin_manager`, and the row registers the tool only while `pluginMarket` is mounted; other presets keep it disabled.
|
|
63
|
+
|
|
64
|
+
-----
|
|
65
|
+
|
|
66
|
+
<a id="understand-the-implementation"></a>
|
|
67
|
+
## Understand the implementation
|
|
68
|
+
|
|
69
|
+
The Host fetches with the process `fetch`, so the configured outbound proxy applies, and refuses redirects. The body is read up to `maxBytes`, then a fresh Worker Thread decodes it as strict UTF-8, parses it as JSON, and validates it; relative icon references resolve against the configured URL. The body's buffer moves to the Worker, and the validated index returns to the Host by structured clone. The Worker is the self-contained `lib/worker.cjs` bundle; disposal terminates it, and a Worker failure is reported as `plugin-market/fetch-failed`.
|
|
70
|
+
|
|
71
|
+
Concurrent reads of one URL share one fetch. A successful document is cached for `cacheTtlMs`; `refresh` bypasses the cache. Each fetched document gets a new `fetchedAt`, and the cached document stays answerable by its `fetchedAt` until a later fetch replaces it. A failed read records its message for `listIndexes` and keeps no document. A read that finishes after its URL left the configuration updates neither cache nor error. On `loader/volatile-update` the service drops state of removed URLs and emits `plugin-market/changed`. Disposal aborts in-flight fetches.
|
|
72
|
+
|
|
73
|
+
Filtering and ordering read only the document; installation status and compatibility are computed for the returned page on every call. The first query with text in a document builds its text index with [MiniSearch](https://github.com/lucaong/minisearch), 500 plugins per event-loop turn, and later queries reuse it until the document is replaced.
|
|
74
|
+
|
|
75
|
+
Compatibility is computed per version with `evaluatePluginCompatibility`, the version's `engines.dsh`, and the profile's version exemptions, the same check installation applies. A plugin's default version is its highest compatible version without a prerelease tag, or its highest compatible prerelease when it lists no version without one; a plugin with no compatible version has none. Installation status comes from `pluginManager.listBundles()` by package name, measured against the default version, or the highest version without one: `not-installed`, also for an on-demand catalog entry the profile has not installed; `installed` at that version; `update-available` when that version is greater; `different-version` when the installed version is unknown, not valid SemVer, or greater; and `provided` for a bundle the DSH installation ships.
|
|
76
|
+
|
|
77
|
+
`marketInstallTarget` builds install arguments: `name@version` with the version's registry for npm, and `git+<url>.git#<commit>` with `&path:/<path>` for a package directory in Git.
|
|
78
|
+
|
|
79
|
+
-----
|
|
80
|
+
|
|
81
|
+
<a id="model-experience"></a>
|
|
82
|
+
## Model Experience
|
|
83
|
+
|
|
84
|
+
### Market listing tool
|
|
85
|
+
|
|
86
|
+
#### What the model sees
|
|
87
|
+
|
|
88
|
+
The [`plugin_market` tool](../../../docs/tool-catalog.md#deepseek-aidsh-plugin-market) returns JSON: configured index URLs with English titles and last errors, one page of plugins, in index order or by best match for a `query`, with name, English title, description, and author each truncated to 300 characters, homepage, repository, category, label ids, sort-key values, installation status, the default version, and the number of versions, or one page of a plugin's versions. Each returned version carries its ISO publish time, compatibility, and install arguments. Its description states that market text is third-party content, not instructions.
|
|
89
|
+
|
|
90
|
+
#### Token effect
|
|
91
|
+
|
|
92
|
+
The tool declaration is present when a preset mounts it; each call adds its JSON result, bounded by `limit` (at most 100 plugins or versions).
|
|
93
|
+
|
|
94
|
+
#### KV Cache effect
|
|
95
|
+
|
|
96
|
+
Append-only: results enter the conversation as ordinary tool results and do not change earlier request tokens.
|
|
97
|
+
|
|
98
|
+
## Known Limitations and Deferred Work
|
|
99
|
+
|
|
100
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
101
|
+
|
|
102
|
+
- **No upgrade** — an installed bundle with a newer index version is reported as `update-available`; upgrading remains uninstall followed by install.
|
|
103
|
+
- **Unsigned indexes** — index content, including a Git entry's name and version, is the market's claim; the installed manifest decides what is installed.
|
|
104
|
+
- **Last write wins** — `setIndexes` replaces the whole list, so two windows editing sources at the same time can overwrite each other's change.
|
|
105
|
+
- **Redirects refused** — an index served only behind a redirect must be configured at its final URL.
|
|
106
|
+
- **Whole-document reads** — the Host downloads and keeps each index up to `maxBytes` and builds its text index in memory; a synthetic index of 20,000 plugins took about 0.8 s of build time and 130 MiB of heap. Parsing runs in a Worker, but receiving the validated index still blocks the Host event loop while the clone is deserialized: about 35 ms for a synthetic 7.6 MiB index of 20,000 plugins and about 190 ms for 38 MiB and 100,000 plugins. Larger markets need a server-side query protocol.
|
|
107
|
+
- **Pages can change** — `fetchedAt` pins pages only while the document is cached; after another read replaces it, a reader must start again from the first page.
|
|
108
|
+
|
|
109
|
+
<a id="dev-note"></a>
|
|
110
|
+
### Dev Note
|
|
111
|
+
|
|
112
|
+
<details>
|
|
113
|
+
<summary>Working context for maintainers — click to expand</summary>
|
|
114
|
+
|
|
115
|
+
None.
|
|
116
|
+
|
|
117
|
+
</details>
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "读取用户配置的插件市场索引的 Host 服务,提供安装状态、兼容性以及只读的 plugin_market 工具。"
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @deepseek-ai/dsh-plugin-market
|
|
7
|
+
|
|
8
|
+
[English](README.md) | 中文
|
|
9
|
+
|
|
10
|
+
## 概述
|
|
11
|
+
|
|
12
|
+
`pluginMarket` 读取用户配置的插件市场索引,用 [`dsh-plugin-market-index`](../../util/plugin-market-index/README.zh.md) 校验,并为每个条目标注 profile 中的安装状态、DSH 兼容性以及安装它所需的精确参数。Web 的[发现标签页](../../client/ui-plugin-market/README.zh.md)和 `plugin_market` agent 工具通过它读取;安装本身经由 [`pluginManager.installBundle`](../plugin-manager/README.zh.md) 进行。格式及其理由见[索引格式 Agent Note](../../../.agents/notes/implemented/feature/2026-10-02-plugin-market-index-format.zh.md);Host 与 Web 的设计见[发现 Agent Note](../../../.agents/notes/implemented/feature/2026-10-02-plugin-market-discover.zh.md)。
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [使用本包](#use-this-package)
|
|
17
|
+
- [理解实现](#understand-the-implementation)
|
|
18
|
+
- [模型体验](#model-experience)
|
|
19
|
+
- [已知限制与延期工作](#known-limitations-and-deferred-work)
|
|
20
|
+
- [开发备注](#dev-note)
|
|
21
|
+
|
|
22
|
+
-----
|
|
23
|
+
|
|
24
|
+
<a id="use-this-package"></a>
|
|
25
|
+
## 使用本包
|
|
26
|
+
|
|
27
|
+
可选的[自定义插件市场组合包](../../experimental/plugin-market-bundle/README.zh.md)把该服务挂载为 `plugin-market` 行;随附的 profile 默认不启用该组合包。与 `plugin-manager` 一样,该行在没有 profile 时被禁用,并等待 `pluginManager`。默认不配置任何索引源,因此在用户添加索引源之前,Host 不发送任何市场请求。
|
|
28
|
+
|
|
29
|
+
| 配置 | 默认值 | 含义 |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| `indexes` | `[]` | 按显示顺序排列的索引 URL。可用的 URL 采用规范形式,使用 `http:` 或 `https:`,不含凭据或片段。该字段是 volatile 字段:发现区、设置和 `setIndexes` 修改它时,不会重新挂载本服务或 `plugin-manager`。 |
|
|
32
|
+
| `fetchTimeoutMs` | `15000` | 单次索引获取(包括响应体)的时限。 |
|
|
33
|
+
| `maxBytes` | `134217728` | 接受的最大索引响应体。 |
|
|
34
|
+
| `cacheTtlMs` | `600000` | 成功读取的文档的缓存时长。 |
|
|
35
|
+
|
|
36
|
+
设置和 profile 文件可以存储任意 http(s) 字符串,因此服务在列出或读取每个 URL 时校验它。`listIndexes` 报告不可用的 URL 及其拒绝原因,`search` 和 `entry` 拒绝该 URL,且不会向它发送请求;重复的 URL 只列出一次。
|
|
37
|
+
|
|
38
|
+
Remote 方法如下:
|
|
39
|
+
|
|
40
|
+
- `listIndexes()` 返回每个已配置 URL,以及其最近一次成功读取得到的标题和描述;最近一次读取失败时,还返回其错误。它从不发起获取。
|
|
41
|
+
- `setIndexes(urls)` 规范化并校验每个尚未配置的 URL,已配置的 URL 保持原样,拒绝重复的 URL,并通过 `settings.update` 把列表写入本服务的 profile 条目。没有 Settings 或 profile 条目时,以 `plugin-market/settings-unavailable` 失败。提交后的列表通过 `plugin-market/changed` 通告。
|
|
42
|
+
- `search(url, query)` 只接受已配置的 URL,因此服务从不获取任意地址。它返回匹配 `query` 的一页插件,并附带索引的标题、描述和声明、该文档的 `fetchedAt`、匹配总数 `total` 和 `nextOffset`;每个插件携带 `defaultVersion` 和 `installation`,每个版本携带 `install` 和 `compatibility`。
|
|
43
|
+
|
|
44
|
+
服务方法 `entry(url, name)` 不是 Remote 方法,它以相同形式返回已配置索引中的一个插件;索引未列出该插件时返回 `undefined`。
|
|
45
|
+
|
|
46
|
+
查询选出同时满足其全部条件的插件:
|
|
47
|
+
|
|
48
|
+
| 字段 | 含义 |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `text` | 模糊匹配的词,见下文。不含字母或数字的文本选出所有插件。 |
|
|
51
|
+
| `category` | 插件的分类 id。 |
|
|
52
|
+
| `labels` | 插件必须全部具备的标签 id。未声明的分类或标签 id 不匹配任何插件。 |
|
|
53
|
+
| `sort` | `index` 为索引顺序;`relevance` 为文本匹配最好的在前,没有文本时为索引顺序;`published` 为最新发布时间;`key` 为已声明的排序键,缺少该值的插件排在最后。有方向的排序取 `asc` 或 `desc`,相同时保持索引顺序。未声明的排序键保持索引顺序。 |
|
|
54
|
+
| `offset`、`limit` | 页:`offset` 是非负整数,`limit` 是 1 到 100 的整数;其他值以 `plugin-market/invalid-query` 失败。 |
|
|
55
|
+
| `refresh` | 重新获取,而不使用缓存的文档。 |
|
|
56
|
+
| `fetchedAt` | 先前某页的 `fetchedAt`:只要该文档仍在缓存中,即使超过 `cacheTtlMs` 也用它回答,使后续页延续同一份结果。 |
|
|
57
|
+
|
|
58
|
+
文本匹配包名、作者、关键词,以及标题、描述、分类标题和标签标题的所有语言。文本被拆分为由字母、组合符号和数字构成的连续片段;由中文、日文或韩文字符构成的片段变为相邻的两字组合及其最后一个字符,因此不带空格书写的文本无需词典也能匹配。词在 NFKC 规范化后不区分大小写地比较。查询中的每个词都必须匹配某个已索引的词,可以是前缀,或者在词长至少四个字符时,编辑距离不超过其长度的五分之一(四舍五入),且最多为 2。名称和标题匹配的权重是其他位置的三倍,关键词匹配是两倍。
|
|
59
|
+
|
|
60
|
+
失败使用 `plugin-market/invalid-query`、`plugin-market/invalid-index-url`、`plugin-market/unknown-index`、`plugin-market/fetch-failed` 和 `plugin-market/invalid-index`;最后一种携带违规值的 JSON 路径。
|
|
61
|
+
|
|
62
|
+
`plugin_market` 工具列出已配置的索引,按索引顺序分页列出某个索引的插件,或在给出 `query` 时按最佳匹配分页列出,或分页列出某个插件的版本。它不需要批准,因为它只读取用户配置的源且不做任何改动;它返回的每个版本都携带要传给 `plugin_manager` 的 `install_bundle` 的 `target` 和 `registry`,`install_bundle` 仍保留自己的批准要求。该工具不能修改索引源。Creator 模式在 `plugin_manager` 旁边保留它的行,该行只在 `pluginMarket` 已挂载时注册工具;其他预设保持禁用。
|
|
63
|
+
|
|
64
|
+
-----
|
|
65
|
+
|
|
66
|
+
<a id="understand-the-implementation"></a>
|
|
67
|
+
## 理解实现
|
|
68
|
+
|
|
69
|
+
Host 使用进程的 `fetch` 获取,因此配置的出站代理生效,并拒绝重定向。响应体最多读取 `maxBytes`,随后由一个新的 Worker Thread 按严格 UTF-8 解码、解析为 JSON 并校验;相对图标引用基于配置的 URL 解析。响应体的缓冲区转移给 Worker,校验后的索引通过 structured clone 返回 Host。Worker 是自包含的 `lib/worker.cjs` bundle;销毁时终止它,Worker 失败报告为 `plugin-market/fetch-failed`。
|
|
70
|
+
|
|
71
|
+
对同一 URL 的并发读取共享一次获取。成功的文档缓存 `cacheTtlMs`;`refresh` 绕过缓存。每份获取到的文档都有新的 `fetchedAt`,缓存的文档在被之后的获取替换前,都可以按其 `fetchedAt` 回答。失败的读取为 `listIndexes` 记录错误消息,不保留文档。读取完成时其 URL 已不在配置中的,既不更新缓存也不更新错误。收到 `loader/volatile-update` 时,服务丢弃已移除 URL 的状态并发出 `plugin-market/changed`。销毁时中止进行中的获取。
|
|
72
|
+
|
|
73
|
+
过滤和排序只读取文档;安装状态和兼容性在每次调用时只为返回的页计算。一份文档上第一次带文本的查询使用 [MiniSearch](https://github.com/lucaong/minisearch) 构建其文本索引,每轮事件循环处理 500 个插件,之后的查询复用该索引,直到文档被替换。
|
|
74
|
+
|
|
75
|
+
兼容性按版本计算:使用 `evaluatePluginCompatibility`,传入该版本的 `engines.dsh` 和 profile 的版本豁免,与安装时执行的检查相同。插件的默认版本是其不带先行版本号的最高兼容版本;插件完全没有此类版本时,使用其最高兼容的先行版本;没有兼容版本的插件没有默认版本。安装状态按包名根据 `pluginManager.listBundles()` 计算,以默认版本为准,没有默认版本时以最高版本为准:`not-installed`(包括当前 profile 尚未安装的按需目录条目);版本相同时为 `installed`;该版本更高时为 `update-available`;已安装版本未知、不是有效的 SemVer 或更高时为 `different-version`;DSH 安装随附的组合包(bundle)为 `provided`。
|
|
76
|
+
|
|
77
|
+
`marketInstallTarget` 构建安装参数:npm 为 `name@version` 加该版本的 registry,Git 为 `git+<url>.git#<commit>`,包位于子目录时追加 `&path:/<path>`。
|
|
78
|
+
|
|
79
|
+
-----
|
|
80
|
+
|
|
81
|
+
<a id="model-experience"></a>
|
|
82
|
+
## 模型体验
|
|
83
|
+
|
|
84
|
+
### 市场列表工具
|
|
85
|
+
|
|
86
|
+
#### 模型看到什么
|
|
87
|
+
|
|
88
|
+
[`plugin_market` 工具](../../../docs/tool-catalog.zh.md#deepseek-aidsh-plugin-market)返回 JSON:已配置的索引 URL 及其英文标题和最近错误,一页插件(按索引顺序,或给出 `query` 时按最佳匹配),包含名称、英文标题、描述和作者(各截断为 300 个字符)、主页、仓库、分类、标签 id、排序键值、安装状态、默认版本和版本数量,或者某个插件的一页版本。返回的每个版本都携带 ISO 发布时间、兼容性和安装参数。其描述声明市场文本是第三方内容,不是指令。
|
|
89
|
+
|
|
90
|
+
#### Token 影响
|
|
91
|
+
|
|
92
|
+
预设挂载该工具时提供工具声明;每次调用追加其 JSON 结果,大小受 `limit` 限制(最多 100 个插件或版本)。
|
|
93
|
+
|
|
94
|
+
#### KV Cache 影响
|
|
95
|
+
|
|
96
|
+
仅追加:结果作为普通工具结果进入对话,不改变先前的请求 token。
|
|
97
|
+
|
|
98
|
+
## 已知限制与延期工作
|
|
99
|
+
|
|
100
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
101
|
+
|
|
102
|
+
- **不支持升级**——索引版本更新的已安装组合包报告为 `update-available`;升级仍需先卸载再安装。
|
|
103
|
+
- **索引没有签名**——索引内容(包括 Git 条目的名称和版本)是市场的声明;实际安装什么由已安装的 manifest(元数据清单)决定。
|
|
104
|
+
- **后写入者覆盖**——`setIndexes` 会替换整个列表,因此两个窗口同时编辑索引源时,可能互相覆盖对方的修改。
|
|
105
|
+
- **拒绝重定向**——只能经重定向访问的索引必须以其最终 URL 配置。
|
|
106
|
+
- **读取整份文档**——Host 下载并保留每个不超过 `maxBytes` 的索引,并在内存中构建其文本索引;一个包含 20,000 个插件的合成索引构建用时约 0.8 秒,占用约 130 MiB 堆内存。解析在 Worker 中运行,但接收校验后的索引时,反序列化 clone 仍会阻塞 Host 事件循环:包含 20,000 个插件的 7.6 MiB 合成索引约 35 毫秒,包含 100,000 个插件的 38 MiB 索引约 190 毫秒。更大的市场需要服务端查询协议。
|
|
107
|
+
- **分页可能变化**——`fetchedAt` 只在文档仍被缓存时固定分页;另一次读取替换文档后,读取方必须从第一页重新开始。
|
|
108
|
+
|
|
109
|
+
<a id="dev-note"></a>
|
|
110
|
+
### 开发备注
|
|
111
|
+
|
|
112
|
+
<details>
|
|
113
|
+
<summary>维护者的工作上下文——点击展开</summary>
|
|
114
|
+
|
|
115
|
+
无。
|
|
116
|
+
|
|
117
|
+
</details>
|