dsh-plugin-manager-companion 0.1.0
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.en.md +144 -0
- package/README.md +142 -0
- package/cordis.patch.yml +9 -0
- package/dist/about.d.ts +77 -0
- package/dist/about.js +179 -0
- package/dist/cli.d.ts +226 -0
- package/dist/cli.js +856 -0
- package/dist/client/AboutPage.d.ts +75 -0
- package/dist/client/ConsolePage.d.ts +79 -0
- package/dist/client/KindsPage.d.ts +21 -0
- package/dist/client/MarketplacePage.d.ts +36 -0
- package/dist/client/OfficialSlots.d.ts +35 -0
- package/dist/client/UpgradeRow.d.ts +108 -0
- package/dist/client/index.d.ts +26 -0
- package/dist/client/locales.d.ts +475 -0
- package/dist/client/pmSelect.d.ts +38 -0
- package/dist/client/shared.d.ts +928 -0
- package/dist/client/upgradeView.d.ts +278 -0
- package/dist/client/wire.d.ts +401 -0
- package/dist/client.js +9194 -0
- package/dist/diagnostics.d.ts +332 -0
- package/dist/diagnostics.js +2631 -0
- package/dist/envManager.d.ts +1047 -0
- package/dist/envManager.js +3214 -0
- package/dist/fix.d.ts +60 -0
- package/dist/fix.js +168 -0
- package/dist/guard.d.ts +133 -0
- package/dist/guard.js +232 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.js +1150 -0
- package/dist/installSession.d.ts +111 -0
- package/dist/installSession.js +150 -0
- package/dist/kinds.d.ts +464 -0
- package/dist/kinds.js +1029 -0
- package/dist/marketView.d.ts +261 -0
- package/dist/marketView.js +406 -0
- package/dist/marketplace.d.ts +248 -0
- package/dist/marketplace.js +500 -0
- package/dist/match.d.ts +67 -0
- package/dist/match.js +203 -0
- package/dist/net.d.ts +108 -0
- package/dist/net.js +163 -0
- package/dist/official.d.ts +145 -0
- package/dist/official.js +205 -0
- package/dist/paths.d.ts +108 -0
- package/dist/paths.js +236 -0
- package/dist/presets.d.ts +299 -0
- package/dist/presets.js +578 -0
- package/dist/qualityGate.d.ts +66 -0
- package/dist/qualityGate.js +247 -0
- package/dist/rank.d.ts +88 -0
- package/dist/rank.js +164 -0
- package/dist/registry.d.ts +295 -0
- package/dist/registry.js +686 -0
- package/dist/rest.d.ts +122 -0
- package/dist/rest.js +219 -0
- package/dist/scan.d.ts +134 -0
- package/dist/scan.js +396 -0
- package/dist/settings.d.ts +447 -0
- package/dist/settings.js +263 -0
- package/dist/tags.d.ts +119 -0
- package/dist/tags.js +166 -0
- package/dist/tools.d.ts +131 -0
- package/dist/tools.js +377 -0
- package/dist/types.d.ts +651 -0
- package/dist/types.js +13 -0
- package/dist/upgrade.d.ts +428 -0
- package/dist/upgrade.js +1100 -0
- package/dist/upgradeView.d.ts +313 -0
- package/dist/upgradeView.js +273 -0
- package/docs/images/readme/01-console-health.png +0 -0
- package/docs/images/readme/02-console-envs.png +0 -0
- package/docs/images/readme/03-marketplace.png +0 -0
- package/docs/images/readme/04-official-plugin-page.png +0 -0
- package/package.json +104 -0
package/dist/kinds.d.ts
ADDED
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 多类型安装:skill / agent 预设的检测、直装,以及安装记录与屏蔽名单。
|
|
3
|
+
*
|
|
4
|
+
* 归属:A 类·重写(写文件、复制目录、管持久化状态;旧 src/kinds.ts 仅作意图参考,未复制代码)。
|
|
5
|
+
* 旧实现参考:dsh-web-plugin-manager/src/kinds.ts(536 行:分层检测、SKILL.md 发现、
|
|
6
|
+
* installed-kinds.json 记录、blocked-repos.json 屏蔽名单、isUnderRoot 守卫、
|
|
7
|
+
* rmRetry/renameRetry 的 Windows 占用重试)。
|
|
8
|
+
* 官方复用:官方 skill-filesystem 扫描 <dshHome>/skills(默认 chokidar 热加载),
|
|
9
|
+
* 官方 agent-presets 每次读取都重扫 <dshHome>/.agent-presets 且以 agent.cordis.yml
|
|
10
|
+
* 为组合文件——本模块只往这两个官方根里落文件,**不复制官方发现逻辑、
|
|
11
|
+
* 不注册任何服务、不动 cordis.patch.yml**。路径基座复用 src/paths.ts 的 dshHome()。
|
|
12
|
+
* 前提检查:仍然成立且这正是我们的作业面——官方 README 明说 "loading plain plugin
|
|
13
|
+
* modules stays a file operation",skill 与 agent 预设没有安装器。旧实现的前提
|
|
14
|
+
* (官方只有只读清单、必须自建写路径)对 cordis 插件已消失,所以这里**不做**
|
|
15
|
+
* cordis 插件的安装:那种仓库交给官方 plugin_manager / CLI 的 pnpm 通道。
|
|
16
|
+
* 本模块对 cordis-plugin 只做"识别并指引"。
|
|
17
|
+
*
|
|
18
|
+
* 四条硬约束:
|
|
19
|
+
* 1. 每个落地目录都必须校验在目标根之内(isUnderRoot)——SKILL.md frontmatter
|
|
20
|
+
* 里的 name 是第三方内容,可能写成 ../.. 或绝对路径。
|
|
21
|
+
* 2. 删除/改名带重试:Windows 上 AV 扫描器与编辑器会短暂占用句柄。
|
|
22
|
+
* 3. 记录与屏蔽名单的读改写串行化,且落盘是"临时文件 + 改名"的原子写。
|
|
23
|
+
* 4. 永不执行第三方脚本:仓库里的 install.sh 只被扫描(见 scan.ts),不被运行。
|
|
24
|
+
*/
|
|
25
|
+
import type { InstalledKind, MarketItemKind } from './types.ts';
|
|
26
|
+
/** 可安装的非插件资源类型。'unknown' 表示检测不出(应拒绝安装)。 */
|
|
27
|
+
export type RepoKind = 'agent-preset' | 'cordis-plugin' | 'skill';
|
|
28
|
+
/** 检测结果:三类之一,或 unknown(非插件/技能/预设仓库)。 */
|
|
29
|
+
export type DetectedRepoKind = RepoKind | 'unknown';
|
|
30
|
+
/** 官方预设组合文件:一个目录里有它就构成一个 agent 预设(官方单文件判定)。 */
|
|
31
|
+
export declare const PRESET_COMPOSITION_FILE = "agent.cordis.yml";
|
|
32
|
+
/** 官方技能清单文件(大小写不敏感,见 findSkillRoots)。 */
|
|
33
|
+
export declare const SKILL_MANIFEST_FILE = "SKILL.md";
|
|
34
|
+
/** 技能根发现的默认上限:5 层 / 200 个。 */
|
|
35
|
+
export declare const DEFAULT_ROOT_LIMITS: {
|
|
36
|
+
readonly maxDepth: 5;
|
|
37
|
+
readonly limit: 200;
|
|
38
|
+
};
|
|
39
|
+
/** 插件根发现的默认上限(比技能浅:packages/* 这种布局三层足够)。 */
|
|
40
|
+
export declare const DEFAULT_PLUGIN_LIMITS: {
|
|
41
|
+
readonly maxDepth: 3;
|
|
42
|
+
readonly limit: 50;
|
|
43
|
+
};
|
|
44
|
+
/** 预设根发现的默认上限。 */
|
|
45
|
+
export declare const DEFAULT_PRESET_LIMITS: {
|
|
46
|
+
readonly maxDepth: 3;
|
|
47
|
+
readonly limit: 50;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* 覆盖 Harness home 并清掉全部进程内缓存(仅测试用)。
|
|
51
|
+
* @param home - 临时 home;传 null 恢复真实 home。
|
|
52
|
+
*/
|
|
53
|
+
export declare function __setHomeForTests(home: string | null): void;
|
|
54
|
+
/**
|
|
55
|
+
* 当前生效的 Harness home(含测试覆盖)。
|
|
56
|
+
*
|
|
57
|
+
* 兄弟模块(presets.ts)必须用这个而不是直接调 paths.dshHome():否则测试里
|
|
58
|
+
* 覆盖过的 home 只有一半模块看得见,落地根与归档根会分叉。
|
|
59
|
+
* @returns 绝对路径。
|
|
60
|
+
*/
|
|
61
|
+
export declare function resolvedHome(): string;
|
|
62
|
+
/** 本插件管辖的缓存目录(与旧仓库共用同一目录名,但文件名不同,见下)。 */
|
|
63
|
+
export declare function cacheRoot(): string;
|
|
64
|
+
/**
|
|
65
|
+
* 安装记录文件。
|
|
66
|
+
*
|
|
67
|
+
* 与旧仓库的 installed-kinds.json **不同文件**:那个文件由已停止维护的旧包读写,
|
|
68
|
+
* 两边并发写会互相覆盖。读取端做兼容(见 loadKindRecords),写入端只碰自己的
|
|
69
|
+
* 文件,因此两个包共存期间各自的数据都完好。
|
|
70
|
+
*/
|
|
71
|
+
export declare function kindRecordsFile(): string;
|
|
72
|
+
/** 屏蔽名单文件(同样是独立文件,避免与旧包并发写)。 */
|
|
73
|
+
export declare function blockedReposFile(): string;
|
|
74
|
+
/** 官方技能落地根。 */
|
|
75
|
+
export declare function skillsRoot(): string;
|
|
76
|
+
/** 官方 agent 预设落地根。 */
|
|
77
|
+
export declare function presetsRoot(): string;
|
|
78
|
+
/** 根发现选项。 */
|
|
79
|
+
export interface RootSearchOptions {
|
|
80
|
+
/** 递归层数上限(根为第 0 层)。 */
|
|
81
|
+
readonly maxDepth?: number;
|
|
82
|
+
/** 最多返回的根数量。 */
|
|
83
|
+
readonly limit?: number;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 路径包含判定:target 必须位于 root 之内(不等于 root)。
|
|
87
|
+
*
|
|
88
|
+
* 用途是删除/移动前的最后一道守卫:SKILL.md 的 frontmatter name、预设目录名
|
|
89
|
+
* 都可能包含 ../ 或绝对路径(第三方内容),一旦漏判就会删到用户的主目录
|
|
90
|
+
* (旧仓库记录过"删掉整个 Harness home"的事故)。大小写按平台语义处理:
|
|
91
|
+
* Windows/macOS 的文件系统大小写不敏感,用大小写精确比较会误拒合法路径
|
|
92
|
+
* (旧仓库审计 W2)。
|
|
93
|
+
*
|
|
94
|
+
* @param target - 待校验路径。
|
|
95
|
+
* @param root - 允许的根。
|
|
96
|
+
* @returns 是否严格位于根之内。
|
|
97
|
+
*/
|
|
98
|
+
export declare function isUnderRoot(target: string, root: string): boolean;
|
|
99
|
+
/**
|
|
100
|
+
* 删除一棵目录树,带短暂重试。
|
|
101
|
+
*
|
|
102
|
+
* Windows 上 AV 扫描器/编辑器会短暂持有句柄,第一次 rm 常以 EPERM/EBUSY 失败;
|
|
103
|
+
* rm 的 force 只容忍"不存在",不容忍"被占用"。退避用定时器而不是忙循环:
|
|
104
|
+
* 调用点都在 async 路径上,同步自旋会冻住整个事件循环。
|
|
105
|
+
*
|
|
106
|
+
* @param target - 要删除的路径。
|
|
107
|
+
* @throws 重试耗尽后抛出最后一次错误。
|
|
108
|
+
*/
|
|
109
|
+
export declare function rmRetry(target: string): Promise<void>;
|
|
110
|
+
/**
|
|
111
|
+
* 改名(移动),带短暂重试。归档/恢复预设目录时目标可能被占用。
|
|
112
|
+
*
|
|
113
|
+
* @param from - 源路径。
|
|
114
|
+
* @param to - 目标路径。
|
|
115
|
+
* @throws 重试耗尽后抛出最后一次错误。
|
|
116
|
+
*/
|
|
117
|
+
export declare function renameRetry(from: string, to: string): Promise<void>;
|
|
118
|
+
/** 生成文件系统安全的目录名:小写、非字母数字折叠成 '-'。 */
|
|
119
|
+
export declare function slugDirName(name: string): string;
|
|
120
|
+
/**
|
|
121
|
+
* 平台安全的目录名:Windows 保留名加后缀。
|
|
122
|
+
* @param name - 期望的目录名。
|
|
123
|
+
* @returns 可直接 mkdir 的名字。
|
|
124
|
+
*/
|
|
125
|
+
export declare function safeDirName(name: string): string;
|
|
126
|
+
/**
|
|
127
|
+
* 归一化仓库引用为小写 owner/repo。
|
|
128
|
+
*
|
|
129
|
+
* 支持 github:owner/repo、git+https://…、https://github.com/owner/repo、
|
|
130
|
+
* git@github.com:owner/repo、末尾 .git 与 #ref 片段。非 GitHub 形态(本地路径)
|
|
131
|
+
* 返回 null——调用方必须自己决定用什么做键,而不是被塞一个被改写的路径。
|
|
132
|
+
*
|
|
133
|
+
* @param value - 用户输入的仓库引用。
|
|
134
|
+
* @returns owner/repo 小写形式;无法识别的形态返回 null。
|
|
135
|
+
*/
|
|
136
|
+
export declare function normalizeRepoRef(value: string): string | null;
|
|
137
|
+
/**
|
|
138
|
+
* 判断一个 package.json 是否声明了 DSH 能力。
|
|
139
|
+
*
|
|
140
|
+
* 判据(与旧实现意图一致,重写实现):有 dsh 对象字段,或依赖/peerDependencies 里
|
|
141
|
+
* 出现 @deepseek-ai/cordis、@deepseek-ai/dsh、@deepseek-ai/dsh-*。仅带 package.json
|
|
142
|
+
* 的聚合页/桌面壳/普通 npm 项目返回 false——那种仓库不该被当成插件强装。
|
|
143
|
+
*
|
|
144
|
+
* @param manifest - 解析后的 package.json 内容(任意 JSON)。
|
|
145
|
+
* @returns true/false;不是对象时返回 null(无法判定)。
|
|
146
|
+
*/
|
|
147
|
+
export declare function looksLikeDshPlugin(manifest: unknown): boolean | null;
|
|
148
|
+
/**
|
|
149
|
+
* 找出仓库里的 SKILL.md 根(单技能仓库与技能集合仓库)。
|
|
150
|
+
*
|
|
151
|
+
* 一个目录里有 SKILL.md 就不再往下走:技能目录内部的子目录属于该技能自己的
|
|
152
|
+
* 结构(脚本、资源),把其中的 SKILL.md 当成第二个技能会装出重复内容。
|
|
153
|
+
*
|
|
154
|
+
* @param root - 仓库根目录。
|
|
155
|
+
* @param options - 层数与数量上限(默认 5 层 / 200 个)。
|
|
156
|
+
* @returns 技能根目录的绝对路径列表。
|
|
157
|
+
*/
|
|
158
|
+
export declare function findSkillRoots(root: string, options?: RootSearchOptions): Promise<string[]>;
|
|
159
|
+
/**
|
|
160
|
+
* 找出仓库里的 agent 预设根(根预设与预设集合都覆盖)。
|
|
161
|
+
*
|
|
162
|
+
* 判定只看官方组合文件 agent.cordis.yml 是否存在——preset.yml 只是可选展示元数据,
|
|
163
|
+
* 不是构成条件(官方 discovery 的口径)。
|
|
164
|
+
*
|
|
165
|
+
* @param root - 仓库根目录。
|
|
166
|
+
* @param options - 层数与数量上限(默认 3 层 / 50 个)。
|
|
167
|
+
* @returns 预设根目录的绝对路径列表。
|
|
168
|
+
*/
|
|
169
|
+
export declare function findPresetRoots(root: string, options?: RootSearchOptions): Promise<string[]>;
|
|
170
|
+
/**
|
|
171
|
+
* 找出仓库里的 DSH 插件包根(monorepo / 多包仓库)。
|
|
172
|
+
*
|
|
173
|
+
* @param root - 仓库根目录。
|
|
174
|
+
* @param options - 层数与数量上限(默认 3 层 / 50 个)。
|
|
175
|
+
* @returns 插件包目录列表。
|
|
176
|
+
*/
|
|
177
|
+
export declare function findPluginRoots(root: string, options?: RootSearchOptions): Promise<string[]>;
|
|
178
|
+
/**
|
|
179
|
+
* 分层类型检测。
|
|
180
|
+
*
|
|
181
|
+
* 顺序(旧实现的顺序保留,重写实现):
|
|
182
|
+
* 1. 根目录就是预设(agent.cordis.yml 在根)→ agent-preset;
|
|
183
|
+
* 2. 根 package.json 声明了 DSH 能力 → cordis-plugin;
|
|
184
|
+
* 3. 根有 SKILL.md → skill(工具链 package.json 在纯技能仓库上很常见,
|
|
185
|
+
* 不能因为"有 package.json"就判成插件);
|
|
186
|
+
* 4. 嵌套检测**统一放最后一层**:预设 → 插件 → 技能,三层只要有一层命中就
|
|
187
|
+
* 返回该类型;这样"技能集合里夹带一个预设目录"和"预设集合里夹带技能"
|
|
188
|
+
* 都按预设优先(预设是更具体的形态);
|
|
189
|
+
* 5. 都不命中 → unknown(调用方据此拒绝安装并加入屏蔽名单)。
|
|
190
|
+
*
|
|
191
|
+
* 与旧实现的差别:旧实现有第四类 'instructions'(带 install.sh 的仓库)。
|
|
192
|
+
* 'unknown' 已经覆盖那个语义(拒绝安装 + 指引用户自己看仓库),少一个类型名
|
|
193
|
+
* 少一处分支。**任何仓库的 install.sh 都不会被自动执行**,这一点没有变。
|
|
194
|
+
*
|
|
195
|
+
* @param root - 仓库根目录。
|
|
196
|
+
* @returns 检测到的类型;无法识别时为 'unknown'。
|
|
197
|
+
*/
|
|
198
|
+
export declare function detectRepoType(root: string): Promise<DetectedRepoKind>;
|
|
199
|
+
/**
|
|
200
|
+
* 读取 SKILL.md 的 YAML frontmatter 里的 name。
|
|
201
|
+
*
|
|
202
|
+
* 只做一件小事:'---' 块里的 name: 行。不引入 YAML 解析器——技能清单的
|
|
203
|
+
* frontmatter 由官方解析,我们只需要拿它当**建议目录名**,解析失败就回退到
|
|
204
|
+
* 仓库名/目录名,不影响技能本身能否被官方加载。
|
|
205
|
+
*
|
|
206
|
+
* @param skillDir - 技能根目录。
|
|
207
|
+
* @returns 合法的技能名;没有或非法时返回 null。
|
|
208
|
+
*/
|
|
209
|
+
export declare function skillDisplayName(skillDir: string): Promise<string | null>;
|
|
210
|
+
/** 一次直装的结果。 */
|
|
211
|
+
export interface InstallOutcome {
|
|
212
|
+
/** 单个落地时的名字;多个时是 N-skills / N-presets 这类汇总名。 */
|
|
213
|
+
readonly name: string;
|
|
214
|
+
/** 每个落地目录名。 */
|
|
215
|
+
readonly names: readonly string[];
|
|
216
|
+
/** 落地根目录。 */
|
|
217
|
+
readonly location: string;
|
|
218
|
+
/** 每个落地目录的绝对路径(与 names 同序)。 */
|
|
219
|
+
readonly dirs: readonly string[];
|
|
220
|
+
}
|
|
221
|
+
/** 直装选项。 */
|
|
222
|
+
export interface InstallOptions {
|
|
223
|
+
/** 已被其他安装记录占用的名字;命中即拒绝(避免静默覆盖别人的技能)。 */
|
|
224
|
+
readonly occupied?: ReadonlySet<string>;
|
|
225
|
+
/** 覆盖落地根(测试用;默认是官方用户根)。 */
|
|
226
|
+
readonly root?: string;
|
|
227
|
+
/**
|
|
228
|
+
* 是否写入安装记录(默认 true)。
|
|
229
|
+
*
|
|
230
|
+
* 记录是「市场已安装标记」与「uninstall-kind 卸载」的唯一依据——安装不记账等于装完就找不到。
|
|
231
|
+
* 只有明确的例外场景(例如调用方已经把多个根聚合成一条记录)才关掉它。
|
|
232
|
+
*/
|
|
233
|
+
readonly record?: boolean;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* 安装技能仓库到 <dshHome>/skills。
|
|
237
|
+
*
|
|
238
|
+
* 单技能仓库与技能集合仓库都覆盖:每个 SKILL.md 根装成一个目录,目录名优先取
|
|
239
|
+
* frontmatter 的 name,其次单根时取仓库名、多根时取该根自己的目录名。
|
|
240
|
+
*
|
|
241
|
+
* 落地前会 rm 掉同名目录(这是"重装同一技能"的语义),但**先校验包含关系**:
|
|
242
|
+
* 名字来自第三方 frontmatter,必须落在技能根之内。名字已被另一条安装记录占用时
|
|
243
|
+
* 抛错而不是覆盖——静默覆盖等于让用户丢掉另一个技能。
|
|
244
|
+
*
|
|
245
|
+
* @param repoRoot - 仓库根目录(已就绪的克隆或本地目录)。
|
|
246
|
+
* @param repoName - 仓库展示名(owner/repo 或本地目录名)。
|
|
247
|
+
* @param options - 已占用名字集合与根覆盖。
|
|
248
|
+
* @returns 落地结果。
|
|
249
|
+
* @throws 没有 SKILL.md、名字冲突、越界时。
|
|
250
|
+
*/
|
|
251
|
+
export declare function installSkill(repoRoot: string, repoName: string, options?: InstallOptions): Promise<InstallOutcome>;
|
|
252
|
+
/**
|
|
253
|
+
* 安装 agent 预设仓库到 <dshHome>/.agent-presets。
|
|
254
|
+
*
|
|
255
|
+
* 目录名即 preset id(官方语义)。嵌套预设立于子目录时用子目录名做 id;名字是
|
|
256
|
+
* 惯例的 preset 或根预设时回退到仓库名——这样常见布局 repo/preset/agent.cordis.yml
|
|
257
|
+
* 装出来是仓库名而不是一堆同名 preset。
|
|
258
|
+
*
|
|
259
|
+
* 每个落地目录写一份**中立标准归属标记**(.dsh-preset-owner.json),让插件卸载时
|
|
260
|
+
* 能分清"这个预设是谁装的、用户改过没有"(见 presets.ts)。已有标记不覆盖。
|
|
261
|
+
*
|
|
262
|
+
* @param repoRoot - 仓库根目录。
|
|
263
|
+
* @param repoName - 仓库展示名(owner/repo 或本地目录名)。
|
|
264
|
+
* @param options - 已占用 id 集合与根覆盖。
|
|
265
|
+
* @returns 落地结果。
|
|
266
|
+
* @throws 没有 agent.cordis.yml、id 冲突、越界时。
|
|
267
|
+
*/
|
|
268
|
+
export declare function installPreset(repoRoot: string, repoName: string, options?: InstallOptions): Promise<InstallOutcome>;
|
|
269
|
+
/**
|
|
270
|
+
* 删除一个已安装的 kind 目录(越界即拒绝)。
|
|
271
|
+
*
|
|
272
|
+
* @param root - 允许的根(技能根或预设根)。
|
|
273
|
+
* @param dir - 待删除目录。
|
|
274
|
+
* @throws 越界时(不删除任何东西)。
|
|
275
|
+
*/
|
|
276
|
+
export declare function removeKindDir(root: string, dir: string): Promise<void>;
|
|
277
|
+
/**
|
|
278
|
+
* 把任意仓库拼写收敛成记录表的规范键。
|
|
279
|
+
*
|
|
280
|
+
* 记录表的键一律是 normalizeRepoRef 的结果(小写 owner/repo);本地路径这类
|
|
281
|
+
* normalizeRepoRef 认不出的形态按原样当键。
|
|
282
|
+
*
|
|
283
|
+
* @param ref - 任意仓库拼写(owner/repo、URL、github:、客户端回传的展示名…)。
|
|
284
|
+
* @returns 规范键。
|
|
285
|
+
*/
|
|
286
|
+
export declare function canonicalKindKey(ref: string): string;
|
|
287
|
+
/**
|
|
288
|
+
* 落盘形态的记录。
|
|
289
|
+
*
|
|
290
|
+
* 比 wire 类型 InstalledKind 多两个**仅供本模块内部使用**的字段,它们解决的问题是
|
|
291
|
+
* 精确性:一个技能集合仓库会落下多个目录,只记 `dir` 无法回答"这次安装到底碰了哪些
|
|
292
|
+
* 目录"。孤儿扫描(findOrphanKindDirs)与将来的多目录卸载都要靠 `dirs`。
|
|
293
|
+
* 多出来的键会随记录一起落盘,客户端 wire 解析只挑它认识的字段,因此不影响契约。
|
|
294
|
+
*/
|
|
295
|
+
export interface StoredKindRecord extends InstalledKind {
|
|
296
|
+
/** 本次安装落地的全部目录(单目录安装时就是那一个)。旧记录没有这个字段。 */
|
|
297
|
+
readonly dirs?: readonly string[];
|
|
298
|
+
/** 本次安装落地的目录名(多目录安装时用于展示与归属说明)。 */
|
|
299
|
+
readonly names?: readonly string[];
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* 安装记录表。
|
|
303
|
+
*
|
|
304
|
+
* 键是 canonicalKindKey 归一化后的仓库引用,**查询接口对任何等价拼写宽容**:
|
|
305
|
+
* 市场索引里的 repo 是原样大小写(WriteAudit/Probe-Skill-Mixed),客户端把记录体里
|
|
306
|
+
* 的 repo 原样回传给卸载 op,而表键是小写——两者不相等。修复做在**查表侧**而不是
|
|
307
|
+
* 写入侧,因为记录体的 repo 是给用户看的展示名,把它小写化会让 UI 丢掉原始大小写。
|
|
308
|
+
*
|
|
309
|
+
* 宽容只作用在 get/has/delete 的入参上;遍历(entries/values/keys)与落盘仍是每个记录
|
|
310
|
+
* 一条,所以不会出现"同一个记录在列表里显示两次"。
|
|
311
|
+
*/
|
|
312
|
+
export declare class KindRecordMap extends Map<string, InstalledKind> {
|
|
313
|
+
/**
|
|
314
|
+
* 按任意等价拼写取记录。
|
|
315
|
+
*
|
|
316
|
+
* 顺序:规范键 → 原样键 → 逐条比对(键与记录体 repo 都过一遍归一化)。
|
|
317
|
+
* 逐条比对是最后的兜底:旧包写的记录可能以 URL 为键、以 owner/repo 为体。
|
|
318
|
+
*
|
|
319
|
+
* @param ref - 仓库拼写。
|
|
320
|
+
* @returns 记录;不存在时 undefined。
|
|
321
|
+
*/
|
|
322
|
+
get(ref: string): InstalledKind | undefined;
|
|
323
|
+
/**
|
|
324
|
+
* 是否存在等价拼写的记录。
|
|
325
|
+
* @param ref - 仓库拼写。
|
|
326
|
+
* @returns 是否存在。
|
|
327
|
+
*/
|
|
328
|
+
has(ref: string): boolean;
|
|
329
|
+
/**
|
|
330
|
+
* 按任意等价拼写删除记录(删的是它真正存放时用的那个键)。
|
|
331
|
+
* @param ref - 仓库拼写。
|
|
332
|
+
* @returns 是否真的删掉了一条。
|
|
333
|
+
*/
|
|
334
|
+
delete(ref: string): boolean;
|
|
335
|
+
/**
|
|
336
|
+
* 找出某个仓库拼写真正对应的键。
|
|
337
|
+
* @param ref - 仓库拼写。
|
|
338
|
+
* @returns 表中的键;不存在时 undefined。
|
|
339
|
+
*/
|
|
340
|
+
keyOf(ref: string): string | undefined;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* 组装一条安装记录(把落地结果 + 仓库身份收敛成落盘形态)。
|
|
344
|
+
*
|
|
345
|
+
* @param kind - 资源类型。
|
|
346
|
+
* @param repo - 仓库展示名(原样大小写,UI 直接展示)。
|
|
347
|
+
* @param outcome - 直装结果。
|
|
348
|
+
* @returns 可直接落盘的记录。
|
|
349
|
+
*/
|
|
350
|
+
export declare function kindRecordOf(kind: Exclude<MarketItemKind, 'unknown'>, repo: string, outcome: InstallOutcome): StoredKindRecord;
|
|
351
|
+
/** 当前记录代数(0 表示本进程还没读过记录)。 */
|
|
352
|
+
export declare function kindRecordsGeneration(): number;
|
|
353
|
+
/**
|
|
354
|
+
* 读取安装记录(带进程内缓存)。
|
|
355
|
+
*
|
|
356
|
+
* 兼容读取旧包的 installed-kinds.json:两个包可能共存一段时间,用户已经装好的
|
|
357
|
+
* 技能/预设不该在新插件里"消失"。合并规则是本文件优先(同键时以我们自己的为准),
|
|
358
|
+
* 写入永远只写本文件。
|
|
359
|
+
*
|
|
360
|
+
* @returns 记录表(副本;调用方改它不影响缓存)。
|
|
361
|
+
*/
|
|
362
|
+
export declare function loadKindRecords(): Promise<KindRecordMap>;
|
|
363
|
+
/**
|
|
364
|
+
* 写入一条记录(串行读改写)。
|
|
365
|
+
*
|
|
366
|
+
* 键走 canonicalKindKey(小写 owner/repo),记录体里的 repo 原样保留——展示名不能被
|
|
367
|
+
* 键的归一化污染,查询侧由 KindRecordMap 承担宽容。
|
|
368
|
+
*
|
|
369
|
+
* @param repoKey - 仓库引用(会被归一化)。
|
|
370
|
+
* @param record - 记录内容(可以是带 dirs/names 的落盘形态)。
|
|
371
|
+
*/
|
|
372
|
+
export declare function saveKindRecord(repoKey: string, record: InstalledKind | StoredKindRecord): Promise<void>;
|
|
373
|
+
/**
|
|
374
|
+
* 删除一条记录(串行读改写)。
|
|
375
|
+
* @param repoKey - 仓库引用(会被归一化)。
|
|
376
|
+
* @returns 是否真的存在并被删除。
|
|
377
|
+
*/
|
|
378
|
+
export declare function removeKindRecord(repoKey: string): Promise<boolean>;
|
|
379
|
+
/**
|
|
380
|
+
* 按任意等价拼写查一条安装记录(含它真正存放时用的键)。
|
|
381
|
+
*
|
|
382
|
+
* 这是写入侧与卸载侧应该用的显式入口:调用方拿到的是 `{ key, record }`,卸载时用 `key`
|
|
383
|
+
* 精确删除、用 `record.dirs` 精确清理目录,不再依赖"查表键恰好等于客户端回传字符串"。
|
|
384
|
+
*
|
|
385
|
+
* @param repoRef - 任意仓库拼写(owner/repo、URL、github:、展示名)。
|
|
386
|
+
* @returns 记录与其键;不存在时 undefined。
|
|
387
|
+
*/
|
|
388
|
+
export declare function findKindRecord(repoRef: string): Promise<{
|
|
389
|
+
readonly key: string;
|
|
390
|
+
readonly record: StoredKindRecord;
|
|
391
|
+
} | undefined>;
|
|
392
|
+
/**
|
|
393
|
+
* 一条记录应当清理的目录(越界的不返回)。
|
|
394
|
+
*
|
|
395
|
+
* 优先用落盘形态的 `dirs`(多目录安装也精确);旧记录退回 `dir`。返回的目录已经过
|
|
396
|
+
* isUnderRoot 过滤——卸载是破坏性操作,宁可少删也不越界删。
|
|
397
|
+
*
|
|
398
|
+
* @param record - 安装记录。
|
|
399
|
+
* @param root - 允许的根(技能根或预设根)。
|
|
400
|
+
* @returns 应当删除的绝对目录列表(去重、保持记录顺序)。
|
|
401
|
+
*/
|
|
402
|
+
export declare function kindDirsOf(record: InstalledKind | StoredKindRecord, root: string): string[];
|
|
403
|
+
/**
|
|
404
|
+
* 扫描技能根与预设根,找出**没有任何安装记录认领**的目录。
|
|
405
|
+
*
|
|
406
|
+
* 为什么要有它:卸载失败、用户手工放置、外部工具清理记录都会留下目录残留,而契约
|
|
407
|
+
* (KindListResult.orphans)与客户端字典都承诺展示这一节。发布一个恒为空的区块等于
|
|
408
|
+
* 让用户以为"磁盘干净",所以这里给出真实扫描。
|
|
409
|
+
*
|
|
410
|
+
* 扫描语义(刻意保守,宁可少报也不误报):
|
|
411
|
+
* - 只扫根的**下一层**目录:安装永远落在根下第一层,更深层属于技能/预设自己的内容,
|
|
412
|
+
* 把它们当成"未登记目录"没有意义;
|
|
413
|
+
* - 跳过点目录(`.dsh-preset-owner.json` 之类的标记是文件,点目录不是安装产物);
|
|
414
|
+
* - 认领判定:任一记录的 `dirs` 或 `dir` 等于该目录,或者(旧记录没有 `dirs`、且 `dir`
|
|
415
|
+
* 等于根本身时)该目录名等于仓库末段的 slug——即单根安装的命名规则。
|
|
416
|
+
* 旧的多目录记录无法精确归属其余子目录,按"宁可少报"处理。
|
|
417
|
+
*
|
|
418
|
+
* @param options - 根覆盖(测试用)。
|
|
419
|
+
* @returns 未登记目录的绝对路径(排序后)。
|
|
420
|
+
*/
|
|
421
|
+
export declare function findOrphanKindDirs(options?: {
|
|
422
|
+
readonly skillsRootDir?: string;
|
|
423
|
+
readonly presetsRootDir?: string;
|
|
424
|
+
}): Promise<string[]>;
|
|
425
|
+
/**
|
|
426
|
+
* 清理幽灵记录:目录被插件外部删掉(手工 rm、别的工具、临时目录清理)的记录。
|
|
427
|
+
*
|
|
428
|
+
* 进程内缓存看不到外部删除,所以每个读取面(列表、市场已安装标记)都要先调它,
|
|
429
|
+
* 否则已删的技能会永远显示"已安装"。
|
|
430
|
+
*
|
|
431
|
+
* @returns 被清掉的记录键。
|
|
432
|
+
*/
|
|
433
|
+
export declare function pruneGhostRecords(): Promise<string[]>;
|
|
434
|
+
/** 清空记录与屏蔽名单缓存(测试用;让下一次读取重新读盘)。 */
|
|
435
|
+
export declare function __resetKindCacheForTests(): void;
|
|
436
|
+
/**
|
|
437
|
+
* 读取屏蔽名单(带缓存,兼容旧包的 blocked-repos.json)。
|
|
438
|
+
* @returns 归一化后的仓库引用集合(副本)。
|
|
439
|
+
*/
|
|
440
|
+
export declare function loadBlockedRepos(): Promise<Set<string>>;
|
|
441
|
+
/**
|
|
442
|
+
* 加入屏蔽名单(检测为非三类的仓库)。
|
|
443
|
+
* @param repoKey - 仓库引用。
|
|
444
|
+
* @returns 归一化后的键。
|
|
445
|
+
*/
|
|
446
|
+
export declare function addBlockedRepo(repoKey: string): Promise<string>;
|
|
447
|
+
/**
|
|
448
|
+
* 移出屏蔽名单(市场页"解除屏蔽")。
|
|
449
|
+
* @param repoKey - 仓库引用。
|
|
450
|
+
* @returns 是否真的存在并被移除。
|
|
451
|
+
*/
|
|
452
|
+
export declare function removeBlockedRepo(repoKey: string): Promise<boolean>;
|
|
453
|
+
/**
|
|
454
|
+
* 判断仓库是否被屏蔽。
|
|
455
|
+
* @param repoKey - 仓库引用。
|
|
456
|
+
* @returns 是否在屏蔽名单里。
|
|
457
|
+
*/
|
|
458
|
+
export declare function isBlockedRepo(repoKey: string): Promise<boolean>;
|
|
459
|
+
/**
|
|
460
|
+
* 目录是否存在且是目录(供 UI/CLI 汇报"记录是否还活着")。
|
|
461
|
+
* @param path - 绝对路径。
|
|
462
|
+
* @returns 是否为存在的目录。
|
|
463
|
+
*/
|
|
464
|
+
export declare function isDirectory(path: string): Promise<boolean>;
|