dsh-plugin 1.6.12 → 2.0.1
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.en.md +13 -13
- package/README.md +13 -13
- package/client/client.js +791 -761
- package/client/client.js.map +1 -1
- package/lib/http/catalog.js +2 -3
- package/lib/http/diagnostics.js +6 -7
- package/lib/http/install.js +47 -213
- package/lib/http/logs.js +1 -2
- package/lib/http/npm-release-age.js +42 -0
- package/lib/http/routes.js +8 -7
- package/lib/http/settings.js +2 -2
- package/lib/http/shared.js +2 -2
- package/lib/http/task.js +1 -2
- package/lib/index.js +5 -6
- package/lib/services/install/install-types.js +4 -4
- package/lib/services/install/install.js +1 -1
- package/lib/services/install/npm-check.js +3 -2
- package/lib/services/install/npm-resolve.js +9 -96
- package/lib/services/install/operation-log.js +53 -1
- package/lib/services/install/package-entry.js +6 -11
- package/lib/services/install/registry-check.js +2 -2
- package/lib/services/install/release-target.js +8 -9
- package/lib/services/install/task-queue.js +44 -48
- package/lib/services/npm-release-age.js +119 -0
- package/lib/services/probe.js +4 -4
- package/lib/services/profile/installed-versions.js +15 -21
- package/lib/services/profile/profile.js +16 -44
- package/lib/services/profile/progress.js +8 -11
- package/lib/services/settings.js +2 -5
- package/lib/types/http/catalog.d.ts +1 -1
- package/lib/types/http/install.d.ts +2 -2
- package/lib/types/http/npm-release-age.d.ts +2 -0
- package/lib/types/http/routes.d.ts +10 -12
- package/lib/types/http/shared.d.ts +5 -6
- package/lib/types/index.d.ts +7 -8
- package/lib/types/services/install/install-types.d.ts +12 -13
- package/lib/types/services/install/install.d.ts +1 -1
- package/lib/types/services/install/npm-resolve.d.ts +4 -16
- package/lib/types/services/install/operation-log.d.ts +9 -0
- package/lib/types/services/install/package-entry.d.ts +6 -11
- package/lib/types/services/install/release-target.d.ts +7 -8
- package/lib/types/services/install/task-queue.d.ts +25 -30
- package/lib/types/services/npm-release-age.d.ts +15 -0
- package/lib/types/services/probe.d.ts +4 -4
- package/lib/types/services/profile/installed-versions.d.ts +5 -7
- package/lib/types/services/profile/profile.d.ts +14 -18
- package/lib/types/services/profile/progress.d.ts +7 -10
- package/lib/types/services/settings.d.ts +0 -4
- package/package.json +1 -1
- package/src/client/components/PluginHubSection.tsx +26 -22
- package/src/client/components/catalog/CatalogList.tsx +2 -4
- package/src/client/components/catalog/PluginCard.tsx +2 -3
- package/src/client/components/layout/CatalogControls.tsx +5 -6
- package/src/client/components/layout/CatalogHeader.tsx +1 -2
- package/src/client/components/layout/CategoryTabs.tsx +2 -3
- package/src/client/components/layout/SectionTabs.tsx +3 -5
- package/src/client/components/modals/ConfirmDialog.tsx +4 -6
- package/src/client/components/modals/InstalledDetailModal.tsx +3 -6
- package/src/client/components/modals/LogsModal.tsx +7 -12
- package/src/client/components/modals/NotificationsModal.tsx +74 -24
- package/src/client/components/modals/ProgressView.tsx +3 -4
- package/src/client/components/modals/modals.tsx +75 -26
- package/src/client/components/ui/Dropdown.tsx +4 -6
- package/src/client/components/ui/Toggle.tsx +2 -3
- package/src/client/components/ui/icons.tsx +1 -2
- package/src/client/components/views/CustomInstallView.tsx +20 -178
- package/src/client/components/views/DiagnosticsView.tsx +3 -6
- package/src/client/components/views/InstalledView.tsx +6 -11
- package/src/client/components/views/MarketView.tsx +2 -4
- package/src/client/components/views/SettingsView.tsx +9 -32
- package/src/client/css-modules.d.ts +1 -1
- package/src/client/data/catalog.ts +2 -3
- package/src/client/data/host.ts +26 -3
- package/src/client/data/hub.ts +2 -3
- package/src/client/hooks/useCatalog.ts +79 -24
- package/src/client/hooks/useIncrementalList.ts +3 -5
- package/src/client/hooks/useLanguage.ts +4 -6
- package/src/client/hooks/useSettings.ts +4 -11
- package/src/client/hooks/useTaskQueue.ts +36 -42
- package/src/client/index.tsx +2 -3
- package/src/client/locales.ts +187 -114
- package/src/client/logic/constants.ts +1 -2
- package/src/client/logic/ensure-plugin-css.ts +8 -12
- package/src/client/logic/failures.ts +20 -19
- package/src/client/logic/format.ts +1 -1
- package/src/client/logic/install-command.ts +14 -35
- package/src/client/logic/installed.ts +15 -10
- package/src/client/logic/normalize.ts +3 -3
- package/src/client/logic/release-age.ts +19 -0
- package/src/client/logic/urls.ts +24 -21
- package/src/client/styles/CustomInstallView.module.css +3 -30
- package/src/client/styles/DiagnosticsView.module.css +3 -5
- package/src/client/styles/Dropdown.module.css +2 -4
- package/src/client/styles/Header.module.css +6 -7
- package/src/client/styles/InstalledView.module.css +4 -7
- package/src/client/styles/List.module.css +4 -5
- package/src/client/styles/LogsView.module.css +2 -3
- package/src/client/styles/Modal.module.css +46 -6
- package/src/client/styles/SectionTabs.module.css +2 -4
- package/src/client/styles/SettingsView.module.css +3 -5
- package/src/client/styles/Toggle.module.css +2 -4
- package/src/client/styles/tokens.module.css +14 -18
- package/src/client/types.ts +11 -11
- package/src/server/http/catalog.ts +2 -3
- package/src/server/http/diagnostics.ts +6 -7
- package/src/server/http/install.ts +47 -208
- package/src/server/http/logs.ts +1 -2
- package/src/server/http/npm-release-age.ts +42 -0
- package/src/server/http/routes.ts +12 -12
- package/src/server/http/settings.ts +2 -2
- package/src/server/http/shared.ts +5 -6
- package/src/server/http/task.ts +1 -2
- package/src/server/index.ts +7 -8
- package/src/server/services/install/install-types.ts +12 -13
- package/src/server/services/install/install.ts +0 -1
- package/src/server/services/install/npm-check.ts +3 -2
- package/src/server/services/install/npm-resolve.ts +9 -99
- package/src/server/services/install/operation-log.ts +47 -1
- package/src/server/services/install/package-entry.ts +6 -11
- package/src/server/services/install/registry-check.ts +2 -2
- package/src/server/services/install/release-target.ts +8 -9
- package/src/server/services/install/task-queue.ts +51 -54
- package/src/server/services/npm-release-age.ts +107 -0
- package/src/server/services/probe.ts +4 -4
- package/src/server/services/profile/installed-versions.ts +16 -22
- package/src/server/services/profile/profile.ts +16 -42
- package/src/server/services/profile/progress.ts +8 -11
- package/src/server/services/settings.ts +2 -9
- package/lib/services/install/preflight.js +0 -178
- package/lib/types/services/install/preflight.d.ts +0 -23
- package/src/server/services/install/preflight.ts +0 -184
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { InstallResult, InstallTask, Invocation } from './install-types.ts';
|
|
2
2
|
import type { LoaderHandle } from '../loader.ts';
|
|
3
|
-
/**
|
|
3
|
+
/** 任务快照(避免消费方改动实时对象)。 */
|
|
4
4
|
export declare function getTask(id: number): InstallTask | undefined;
|
|
5
5
|
export interface ActiveTaskInfo {
|
|
6
6
|
id: number;
|
|
@@ -9,28 +9,26 @@ export interface ActiveTaskInfo {
|
|
|
9
9
|
status: 'pending' | 'running';
|
|
10
10
|
progress: number;
|
|
11
11
|
lines: string[];
|
|
12
|
-
/**
|
|
12
|
+
/** 尝试过的安装方式(实际执行过的命令):失败时前端 issue 预填需要 */
|
|
13
13
|
attempts: string[];
|
|
14
|
-
/** 自定义安装入口渠道(NPM
|
|
15
|
-
installChannel?: 'npm'
|
|
14
|
+
/** 自定义安装入口渠道(NPM 包卡片):前端刷新恢复后仍能精准溯源 */
|
|
15
|
+
installChannel?: 'npm';
|
|
16
16
|
}
|
|
17
|
-
/**
|
|
17
|
+
/** 全部未终态任务,按队列顺序(running 在前、pending 在后)。供客户端刷新页面后恢复队列。 */
|
|
18
18
|
export declare function activeTask(): ActiveTaskInfo[];
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* (the close event lands later) — the slot must stay held until then, otherwise
|
|
24
|
-
* a new task would start while the old pnpm still runs in the same profile dir.
|
|
20
|
+
* 变更子进程仍存活时为 true。并发占位以存活子进程集合为准,而非 task.status:
|
|
21
|
+
* 取消运行中任务会立即翻转其状态,但子进程可能仍在退出中(close 事件稍后才到)——
|
|
22
|
+
* 占位必须维持到那时,否则旧 pnpm 还在同一 profile 目录跑,新任务就开始了。
|
|
25
23
|
*/
|
|
26
24
|
export declare function hasRunningTask(): boolean;
|
|
27
|
-
/**
|
|
25
|
+
/** 目标在队列里是否已有未终态任务(安装/卸载去重)。 */
|
|
28
26
|
export declare function hasQueuedTarget(target: string): boolean;
|
|
29
27
|
/**
|
|
30
|
-
*
|
|
31
|
-
* - pending
|
|
32
|
-
* - running
|
|
33
|
-
*
|
|
28
|
+
* 取消排队中或运行中的任务。
|
|
29
|
+
* - pending:立即移出队列(从未 spawn)。
|
|
30
|
+
* - running:杀掉子进程;队列 worker 随后取下一个。
|
|
31
|
+
* 任务不存在或已结束时返回 false。
|
|
34
32
|
*/
|
|
35
33
|
export declare function cancelTask(id: number): boolean;
|
|
36
34
|
/**
|
|
@@ -41,9 +39,8 @@ export declare function cancelTask(id: number): boolean;
|
|
|
41
39
|
*/
|
|
42
40
|
export declare function desktopCliBootstrap(entry: string): string | null;
|
|
43
41
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* Progress is visible through `getTask(id)` / `activeTask()` until done.
|
|
42
|
+
* 插件变更入队并返回其任务。任务严格串行:队列 worker 只在上一个结束后才启动下一个。
|
|
43
|
+
* 完成前可通过 `getTask(id)` / `activeTask()` 查看进度。
|
|
47
44
|
*/
|
|
48
45
|
export declare function startPluginMutation(options: {
|
|
49
46
|
action: 'add' | 'remove' | 'update';
|
|
@@ -58,17 +55,17 @@ export declare function startPluginMutation(options: {
|
|
|
58
55
|
/** 运行中 loader:安装成功后热挂新条目、卸载成功后停用旧条目,两类操作都尽量立即生效
|
|
59
56
|
* (缺失时安装/卸载仍需重启) */
|
|
60
57
|
loader?: LoaderHandle;
|
|
61
|
-
/**
|
|
58
|
+
/** 入队前已尝试的安装方式:失败提 Issue 时如实展示;实际执行的命令由 spawn 时追加 */
|
|
62
59
|
attempts?: string[];
|
|
63
60
|
/** 更新已安装的 npm 包(mode=update):命令显式带 @latest,让 pnpm 真正解析最新版本 */
|
|
64
61
|
updateNpm?: boolean;
|
|
65
|
-
/**
|
|
66
|
-
*
|
|
67
|
-
installChannel?: 'npm'
|
|
62
|
+
/** 自定义安装入口渠道(NPM 包卡片):任务输出行与系统日志据此溯源「从哪个入口发起」;
|
|
63
|
+
* 目录插件安装不传 */
|
|
64
|
+
installChannel?: 'npm';
|
|
68
65
|
}): InstallTask;
|
|
69
66
|
/**
|
|
70
67
|
* 安装后校验已装包里 package.json 声明的文件(main / exports["."].default 与
|
|
71
|
-
* dsh.bundle.patch)是否真实存在。
|
|
68
|
+
* dsh.bundle.patch)是否真实存在。npm 包也可能漏发构建产物(lib/ 等),pnpm 装完没有
|
|
72
69
|
* 报错,但宿主重启加载插件树时会 ERR_MODULE_NOT_FOUND 直接崩溃、网页打不开 —— 这里在
|
|
73
70
|
* 登记「待重启」前就把这类残缺包拦下。没有声明过的文件不在这里追究:没声明入口的
|
|
74
71
|
* bundle 包(只挂技能)本来就不需要入口,宿主读的是它的 package.json 与声明的补丁。
|
|
@@ -85,13 +82,11 @@ export declare function verifyInstalledEntry(profile: string, target: string): {
|
|
|
85
82
|
*/
|
|
86
83
|
export declare function hostSpawnMarker(invocation: Invocation, error: unknown): string | null;
|
|
87
84
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* exact keys into the profile's pnpm-workspace.yaml and retry once.
|
|
94
|
-
* Other failures fall through to the single-spawn result.
|
|
85
|
+
* 执行插件变更,带一条恢复路径:当 `add` 因 pnpm 的 allowBuilds 门禁拦下构建脚本而失败 ——
|
|
86
|
+
* 或是 git 源包自己的 `prepare`(`ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED`,key 取自打印的
|
|
87
|
+
* key@url 提示),或是某依赖的原生构建(`ERR_PNPM_IGNORED_BUILDS`,key = 列出的 name@version)——
|
|
88
|
+
* 就把确切的 key 写进 profile 的 pnpm-workspace.yaml 并重试一次。
|
|
89
|
+
* 其它失败一律落到单次 spawn 的结果。
|
|
95
90
|
*/
|
|
96
91
|
export declare function runPluginMutation(options: {
|
|
97
92
|
action: 'add' | 'remove' | 'update';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface NpmRelease {
|
|
2
|
+
version: string;
|
|
3
|
+
publishedAt: string;
|
|
4
|
+
}
|
|
5
|
+
/** 请求体包名数量上限:只为已安装插件按需查询,几十个足矣,封顶防滥用。 */
|
|
6
|
+
export declare const MAX_RELEASE_AGE_PACKAGES = 50;
|
|
7
|
+
/** 单包查询超时(ms):慢网络下失败即返回 null,不拖住整个响应。 */
|
|
8
|
+
export declare const RELEASE_AGE_TIMEOUT_MS = 8000;
|
|
9
|
+
export declare const DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org";
|
|
10
|
+
/** 从完整 packument 取 dist-tags.latest 对应版本及其发布时间;缺任一字段返回 null。 */
|
|
11
|
+
export declare function latestReleaseOf(packument: unknown): NpmRelease | null;
|
|
12
|
+
/** 请求体 → 去重后的合法包名列表;非数组 / 超量 / 含非法包名一律 null(拒绝非法输入)。 */
|
|
13
|
+
export declare function parseReleaseAgeRequest(body: unknown): string[] | null;
|
|
14
|
+
/** 查询一个包的最新版本与发布时间(成功结果缓存,同会话内同包不重复请求);registry 为空回退官方源,失败返回 null。 */
|
|
15
|
+
export declare function lookupReleaseAge(packageName: string, registry: string, proxy: string, timeoutMs?: number): Promise<NpmRelease | null>;
|
|
@@ -33,7 +33,7 @@ export declare function tlsRevocationBlocked(stderr: string): boolean;
|
|
|
33
33
|
* `http=host:port;https=host:port`(按协议分别配置)。
|
|
34
34
|
* 字符类必须同时排除 `/` 与 `=`:只排除 `=` 时,带 scheme 的值会让「主机名」吞掉 `//`,
|
|
35
35
|
* 拼出 `http:////127.0.0.1:10793` 这种立刻失败的非法地址 —— 代理本来是通的,却把诊断、
|
|
36
|
-
*
|
|
36
|
+
* 目录拉取、安装前网络探测全判成「不可达」。
|
|
37
37
|
*/
|
|
38
38
|
export declare function parseWinProxyServer(stdout: string): string | null;
|
|
39
39
|
/**
|
|
@@ -49,13 +49,13 @@ export declare function systemProxy(): string | null;
|
|
|
49
49
|
*/
|
|
50
50
|
export declare function probeUrl(url: string, proxy: string, timeoutMs: number): Promise<ProbeResult>;
|
|
51
51
|
/**
|
|
52
|
-
* git
|
|
52
|
+
* git 真实克隆握手探测:spawn git ls-remote(https 传输,与 pnpm 克隆前的
|
|
53
53
|
* ref 握手一致),注入代理 env,GIT_TERMINAL_PROMPT=0 防凭据提示挂起。
|
|
54
54
|
*
|
|
55
55
|
* 为什么要真实 git 而非 curl 打网页:网页「能打开」和 git「能克隆」是两码事 ——
|
|
56
56
|
* 防火墙/代理常按端口与协议区分,HTTP 页可达不代表 git 传输可达。这里测的就是
|
|
57
|
-
*
|
|
58
|
-
* 供系统诊断 GitHub
|
|
57
|
+
* 克隆握手本身,回答「能不能连上 github.com」。
|
|
58
|
+
* 供系统诊断 GitHub 可达性使用;探测目标用 dshplugin/hello-dsh 小仓库(秒级完成,
|
|
59
59
|
* 不打 17MB 的 dsh-plugin-hub 主页)。
|
|
60
60
|
*/
|
|
61
61
|
export declare function gitLsRemote(url: string, proxy: string, timeoutMs: number): Promise<ProbeResult>;
|
|
@@ -4,21 +4,19 @@ export interface InstalledVersionRecord {
|
|
|
4
4
|
/** 安装时的仓库最近更新时间(ISO,GitHub pushed_at);无 release 仓库的更新依据 */
|
|
5
5
|
updatedAt: string;
|
|
6
6
|
installedAt: string;
|
|
7
|
-
/**
|
|
7
|
+
/** 安装时记录在案的官方 npm 包名(repo → 包名映射):目录数据可能未下发
|
|
8
8
|
* npmPackage(组织 scope 与 GitHub 用户名不一致),客户端据此把依赖 key 匹配回仓库 */
|
|
9
9
|
npmPackage?: string;
|
|
10
10
|
}
|
|
11
11
|
export type InstalledVersionTable = Record<string, InstalledVersionRecord>;
|
|
12
12
|
export declare function versionsFilePath(profile: string): string;
|
|
13
13
|
export declare function readInstalledVersions(profile: string): InstalledVersionTable;
|
|
14
|
-
/**
|
|
14
|
+
/** 记录某仓库安装时的目录信号(版本 + 仓库更新时间)。 */
|
|
15
15
|
export declare function recordInstalledVersion(profile: string, repo: string, version: string, updatedAt: string): void;
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* harmless when the repo is not (yet) installed — the client only treats a repo
|
|
20
|
-
* as installed when its dependency key actually exists.
|
|
17
|
+
* 记录某仓库解析出的 npm 包名。在 `/install` 时调用,让映射在任务完成前就存在;
|
|
18
|
+
* 仓库尚未安装时也无害 —— 客户端只在依赖 key 真实存在时才把仓库当作已安装。
|
|
21
19
|
*/
|
|
22
20
|
export declare function recordResolvedNpmPackage(profile: string, repo: string, npmPackage: string): void;
|
|
23
|
-
/**
|
|
21
|
+
/** 清除某仓库记录的版本(卸载时调用)。 */
|
|
24
22
|
export declare function removeInstalledVersion(profile: string, repo: string): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** 从启动参数解析当前 profile,取不到落回 `web`。 */
|
|
2
2
|
export declare function readProfileArg(fallback?: string): string;
|
|
3
3
|
/**
|
|
4
4
|
* 从启动参数解析当前 profile,两种宿主形态都认:
|
|
@@ -10,32 +10,28 @@ export declare function readProfileArg(fallback?: string): string;
|
|
|
10
10
|
* 位置参数按「父目录名为 profiles」精确识别 profile 目录,避免误取其它位置参数。
|
|
11
11
|
*/
|
|
12
12
|
export declare function profileFromArgv(argv: readonly string[], fallback?: string): string;
|
|
13
|
-
/**
|
|
13
|
+
/** 解析 profile 目录(`DSH_HOME` 或 `~/.dsh`)。 */
|
|
14
14
|
export declare function profileDirectory(profile: string): string;
|
|
15
|
-
/**
|
|
16
|
-
*
|
|
17
|
-
* explicitly pinned revision reaches the installer instead of being dropped. */
|
|
15
|
+
/** 把仓库身份转成规范的 GitHub 目标(git+https),仓库不合法时返回 null。
|
|
16
|
+
* 带 ref 时按 Git ref(`#tag` / `#commit`)拼接;安装通道已不再使用 git 目标,此函数仅做身份规范化。 */
|
|
18
17
|
export declare function githubTarget(repo: string, ref?: string | null): string | null;
|
|
19
|
-
export declare function githubRefOf(value: string): string | null;
|
|
20
18
|
export declare function installTargetOf(value: string): string;
|
|
21
19
|
export declare function globalNpmPackagesOf(value: string): string[] | null;
|
|
22
|
-
/**
|
|
20
|
+
/** 从目录值或已装 Git spec 中提取 owner/repo 身份。 */
|
|
23
21
|
export declare function githubRepoOf(value: string): string | null;
|
|
24
|
-
/**
|
|
22
|
+
/** 校验 npm 包名(卸载目标的语法)。 */
|
|
25
23
|
export declare function validPackageName(name: string): boolean;
|
|
26
24
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* the only reliable key is the one pnpm prints verbatim. Null when absent.
|
|
25
|
+
* 取 pnpm 在 `ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED` 提示里原样打印的 `allowBuilds` key。
|
|
26
|
+
* Git 安装时 pnpm 按 `name@<实际 fetch URL>`(如
|
|
27
|
+
* `https://codeload.github.com/<owner>/<repo>/tar.gz/<commit>`)匹配,而不是 `git+ssh://`
|
|
28
|
+
* 或分支 spec —— 裸包名与 `git+` spec 都匹配不上,唯一可靠的 key 就是 pnpm 原样输出的那个。
|
|
29
|
+
* 无则返回 null。
|
|
33
30
|
*/
|
|
34
31
|
export declare function parseAllowBuildsKey(output: string): string | null;
|
|
35
32
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* `set this to true or false` value) are dropped on rewrite.
|
|
33
|
+
* 向 profile 的 pnpm-workspace.yaml 追加一条 `allowBuilds` 记录:与已有条目合并,
|
|
34
|
+
* 其余 yaml 保持不变;重写时丢弃损坏的占位条目(pnpm 安装失败的 bug 会写入
|
|
35
|
+
* 字面量 `set this to true or false`)。
|
|
40
36
|
*/
|
|
41
37
|
export declare function addAllowBuildsKey(profile: string, key: string): void;
|
|
@@ -3,19 +3,16 @@
|
|
|
3
3
|
* Website: https://dsh-plugin.org
|
|
4
4
|
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* 安装执行器共用的纯进度估算工具。
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* line and map it onto a 0-100 estimate; keeping them free of I/O makes the
|
|
12
|
-
* estimation logic directly unit-testable (see tests/progress.test.ts).
|
|
8
|
+
* dsh CLI 包装了 pnpm,pnpm 用回车原地刷新 `Progress: …` 行,因此原始输出是一串碎片。
|
|
9
|
+
* 这些工具把单个碎片归一化成干净的终端行,并映射到 0-100 估算值;不碰 I/O
|
|
10
|
+
* 让估算逻辑可直接单测(见 tests/progress.test.ts)。
|
|
13
11
|
*/
|
|
14
|
-
/**
|
|
12
|
+
/** 剥掉 `[out]` / `[err]` 来源前缀与 ANSI 转义序列。 */
|
|
15
13
|
export declare function cleanLine(raw: string): string;
|
|
16
14
|
/**
|
|
17
|
-
*
|
|
18
|
-
* `Progress: resolved N, reused X, downloaded Y, added Z
|
|
19
|
-
* phase; resolution/install phase lines bump the estimate towards done.
|
|
15
|
+
* 从单行 CLI 输出估算 0-100 进度。pnpm 在 fetch 阶段输出
|
|
16
|
+
* `Progress: resolved N, reused X, downloaded Y, added Z`;解析/安装阶段的行把估算值推向完成。
|
|
20
17
|
*/
|
|
21
18
|
export declare function estimateProgress(line: string): number;
|
|
@@ -7,10 +7,6 @@ export interface HubSettings {
|
|
|
7
7
|
npmRegistry: string;
|
|
8
8
|
/** 启用命令行安装 NPM 包(默认开;关掉后输入 npm 包名安装被拦截) */
|
|
9
9
|
enableNpmInstall: boolean;
|
|
10
|
-
/** 启用命令行安装 GitHub 源码(默认开;关掉后输入 GitHub 地址安装被拦截) */
|
|
11
|
-
enableGitInstall: boolean;
|
|
12
|
-
/** 启用命令行粘贴 dsh plugin 命令安装(默认开;关掉后命令输入被禁用) */
|
|
13
|
-
enableDshInstall: boolean;
|
|
14
10
|
/** 日志存放位置覆盖(空串 = 默认 ~/.dsh/profiles/<profile>/hub.log;可填目录或 .log 文件路径) */
|
|
15
11
|
logPath: string;
|
|
16
12
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "A community plugin marketplace for DeepSeek Harness, built to the official plugin spec — browse, search and install 10000+ human-curated community plugins without leaving the app. · DeepSeek Harness 社区插件市场(遵循官方开发规范):10000+ 人工精选社区插件,每日更新。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -3,10 +3,8 @@
|
|
|
3
3
|
* Website: https://dsh-plugin.org
|
|
4
4
|
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* rendering is delegated to the small presentational components in this
|
|
9
|
-
* folder; it hosts the dialogs/toast and the section-level copy actions.
|
|
6
|
+
* 插件中心板块:把目录数据管道、后台任务队列与反馈状态接在一起。数据/队列逻辑在 hooks/,
|
|
7
|
+
* 渲染交给本目录下的小型展示组件;本文件托管各弹窗/Toast 与板块级复制动作。
|
|
10
8
|
*/
|
|
11
9
|
import { createElement as h, useEffect, useRef, useState } from 'react'
|
|
12
10
|
import type { MouseEvent } from 'react'
|
|
@@ -78,10 +76,10 @@ export function PluginHubSection({ t: _hostT, locale }: SectionProps) {
|
|
|
78
76
|
const [confirmPlugin, setConfirmPlugin] = useState<HubPlugin | null>(null)
|
|
79
77
|
/** 弹窗动作是否为「更新」:已安装插件点「更新」→ 走同一条 add 命令原位覆盖重装,文案区分安装/更新 */
|
|
80
78
|
const [confirmIsUpdate, setConfirmIsUpdate] = useState(false)
|
|
81
|
-
/** 命令行安装确认弹窗:记录待安装的裸目标(npm
|
|
79
|
+
/** 命令行安装确认弹窗:记录待安装的裸目标(npm 包名)——
|
|
82
80
|
* 与应用商店同一套确认/进度/结果弹窗,提供时 plugin 传 null 走 customTarget 模式 */
|
|
83
81
|
const [confirmCustomTarget, setConfirmCustomTarget] = useState<string | null>(null)
|
|
84
|
-
/**
|
|
82
|
+
/** 自定义安装入口渠道(NPM 包卡片):随确认弹窗记录,提交时上报服务端,
|
|
85
83
|
* 报错/日志据此精准溯源「从哪个入口发起」(npm 全局安装固定为 'npm') */
|
|
86
84
|
const [confirmCustomChannel, setConfirmCustomChannel] = useState<InstallChannel | null>(null)
|
|
87
85
|
/** 全局 npm 安装确认弹窗(官方 `npm install -g <pkgs>`):记录原始命令 + 解析出的包列表,
|
|
@@ -142,7 +140,7 @@ export function PluginHubSection({ t: _hostT, locale }: SectionProps) {
|
|
|
142
140
|
|
|
143
141
|
const queue = useTaskQueue({
|
|
144
142
|
t,
|
|
145
|
-
//
|
|
143
|
+
// 界面语言带给服务端:安装前网络探测等错误消息按用户语言提示(中文界面给中文,英文界面给英文)
|
|
146
144
|
langKey,
|
|
147
145
|
refreshInstalled: catalog.refreshInstalled,
|
|
148
146
|
onInstallDone: (viaModal, repo, needsRestart, update, needsReload) => {
|
|
@@ -170,6 +168,15 @@ export function PluginHubSection({ t: _hostT, locale }: SectionProps) {
|
|
|
170
168
|
setNotifications(addSuccess({ kind: 'uninstall', repo: repo ?? '' }))
|
|
171
169
|
},
|
|
172
170
|
onError: (message, repo, kind, command, attempts, update) => {
|
|
171
|
+
// 失败只由错误弹窗呈现:先关掉发起本次操作的确认/进度弹窗
|
|
172
|
+
setInstallDone(false)
|
|
173
|
+
setUninstallDone(false)
|
|
174
|
+
setConfirmPlugin(null)
|
|
175
|
+
setConfirmCustomTarget(null)
|
|
176
|
+
setConfirmCustomChannel(null)
|
|
177
|
+
setConfirmGlobalNpm(null)
|
|
178
|
+
setUninstallPlugin(null)
|
|
179
|
+
setUninstallItem(null)
|
|
173
180
|
// 提 Issue 目标先反查仓库身份:npm 包名能在已安装表/目录里反查到 owner/repo 才保留,
|
|
174
181
|
// 反查不到置 null —— 错误弹窗据此不显示「一键提 Issue」按钮(防提到错误仓库)
|
|
175
182
|
const issueRepo = issueRepoOf(repo ?? '', catalog.installedItems, catalog.plugins)
|
|
@@ -224,10 +231,12 @@ export function PluginHubSection({ t: _hostT, locale }: SectionProps) {
|
|
|
224
231
|
useEffect(() => {
|
|
225
232
|
if (startupCheckedRef.current) return
|
|
226
233
|
if (!settingsReady || catalog.plugins === null || catalog.failed) return
|
|
234
|
+
// 供应链门禁结果未就绪时先等:否则刚发布的插件会先写进通知中心,冒出装不上的更新提醒
|
|
235
|
+
if (!catalog.releaseAgeReady) return
|
|
227
236
|
startupCheckedRef.current = true
|
|
228
237
|
if (!hubSettings.checkUpdatesOnStart) return
|
|
229
238
|
syncUpdateNotices()
|
|
230
|
-
}, [settingsReady, hubSettings, catalog.plugins, catalog.failed, catalog.installedItems, queue])
|
|
239
|
+
}, [settingsReady, hubSettings, catalog.plugins, catalog.failed, catalog.installedItems, catalog.releaseAgeReady, queue])
|
|
231
240
|
|
|
232
241
|
// 信任/卸载/更新说明弹窗打开时按 Esc 关闭;任务进入后台队列后可随时关闭(任务继续)
|
|
233
242
|
useEffect(() => {
|
|
@@ -265,8 +274,7 @@ export function PluginHubSection({ t: _hostT, locale }: SectionProps) {
|
|
|
265
274
|
await navigator.clipboard.writeText(text)
|
|
266
275
|
return true
|
|
267
276
|
} catch {
|
|
268
|
-
// Clipboard API
|
|
269
|
-
// legacy hidden-textarea trick, which works in any context.
|
|
277
|
+
// Clipboard API 不可用(权限/iframe)—— 退回旧的隐藏 textarea 方案,任何环境都可用。
|
|
270
278
|
const ta = document.createElement('textarea')
|
|
271
279
|
ta.value = text
|
|
272
280
|
ta.style.position = 'fixed'
|
|
@@ -306,7 +314,7 @@ export function PluginHubSection({ t: _hostT, locale }: SectionProps) {
|
|
|
306
314
|
Object.keys(catalog.installed).some((k) => k.toLowerCase() === pkg)
|
|
307
315
|
}
|
|
308
316
|
|
|
309
|
-
/** 弹窗动作一:复制安装命令到剪贴板,引导去终端粘贴执行(npm
|
|
317
|
+
/** 弹窗动作一:复制安装命令到剪贴板,引导去终端粘贴执行(npm 安装显示包名命令)。 */
|
|
310
318
|
const copyCommand = async (p: HubPlugin) => {
|
|
311
319
|
const repo = p.source?.repo ?? ''
|
|
312
320
|
const ok = await doCopy(installCommandOf(p))
|
|
@@ -417,8 +425,8 @@ export function PluginHubSection({ t: _hostT, locale }: SectionProps) {
|
|
|
417
425
|
noticeCount: notifications.length + queue.queue.length + queue.pendingRestarts.length,
|
|
418
426
|
onOpenNotifications: () => {
|
|
419
427
|
// 打开弹窗时补齐更新提醒(受「启动时检查更新」开关约束):同一版本只一条,
|
|
420
|
-
//
|
|
421
|
-
if (hubSettings.checkUpdatesOnStart) syncUpdateNotices()
|
|
428
|
+
// 清空/删除后重开仍恢复,直到插件更新完成才消失;门禁结果未就绪时先不写,避免提示装不上的更新
|
|
429
|
+
if (hubSettings.checkUpdatesOnStart && catalog.releaseAgeReady) syncUpdateNotices()
|
|
422
430
|
setShowNotifications(true)
|
|
423
431
|
},
|
|
424
432
|
}),
|
|
@@ -489,17 +497,13 @@ export function PluginHubSection({ t: _hostT, locale }: SectionProps) {
|
|
|
489
497
|
: view === 'custom'
|
|
490
498
|
? h(CustomInstallView, {
|
|
491
499
|
t,
|
|
492
|
-
// 命令行安装:与应用商店同一套确认/进度/结果弹窗 —— 输入 npm 包名 /
|
|
493
|
-
//
|
|
500
|
+
// 命令行安装:与应用商店同一套确认/进度/结果弹窗 —— 输入 npm 包名 / npm、pnpm
|
|
501
|
+
// 安装命令即装(custom 源,受安全设置开关控制)。点安装先弹确认窗,
|
|
494
502
|
// 确认后走队列安装(实时进度 + 成功结果视图);目标已安装 → 弹窗转「更新」覆盖重装,
|
|
495
503
|
// 不会撞「already installed」报错。
|
|
496
|
-
//
|
|
504
|
+
// 安全信任开关关掉 → 卡片禁用并提示去设置打开(onOpenSettings 跳到设置页)。
|
|
497
505
|
enableNpm: hubSettings.enableNpmInstall,
|
|
498
|
-
enableGit: hubSettings.enableGitInstall,
|
|
499
|
-
enableDsh: hubSettings.enableDshInstall,
|
|
500
506
|
onOpenSettings: () => setView('settings'),
|
|
501
|
-
// 当前 profile:一键插入的 Hub 更新命令用它拼 --profile
|
|
502
|
-
profile: env?.profile ?? 'web',
|
|
503
507
|
onInstallCustom: (raw, opts) => {
|
|
504
508
|
const target = raw.trim()
|
|
505
509
|
if (!target) return
|
|
@@ -516,7 +520,7 @@ export function PluginHubSection({ t: _hostT, locale }: SectionProps) {
|
|
|
516
520
|
return
|
|
517
521
|
}
|
|
518
522
|
setConfirmGlobalNpm(null)
|
|
519
|
-
//
|
|
523
|
+
// 记录入口渠道:报错/日志据此精准提示「从哪张卡片发起的安装」
|
|
520
524
|
setConfirmCustomChannel(opts.installChannel)
|
|
521
525
|
setConfirmIsUpdate(customTargetInstalled(target))
|
|
522
526
|
setConfirmCustomTarget(target)
|
|
@@ -696,7 +700,7 @@ export function PluginHubSection({ t: _hostT, locale }: SectionProps) {
|
|
|
696
700
|
},
|
|
697
701
|
onInstall: () => void queue.installCustom(confirmCustomTarget, {
|
|
698
702
|
update: confirmIsUpdate,
|
|
699
|
-
// 入口渠道(NPM
|
|
703
|
+
// 入口渠道(NPM 包卡片):上报服务端,报错/日志据此溯源
|
|
700
704
|
channel: confirmCustomChannel ?? 'npm',
|
|
701
705
|
}),
|
|
702
706
|
onRestart: () => setShowRestartConfirm(true),
|
|
@@ -3,10 +3,8 @@
|
|
|
3
3
|
* Website: https://dsh-plugin.org
|
|
4
4
|
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* the category or install-status filter changes so the replaced content is
|
|
9
|
-
* not mistaken for a no-op update.
|
|
6
|
+
* 目录列表:承载加载/失败/空三态、插件卡片与计数页脚的滚动容器。分类或安装状态
|
|
7
|
+
* 筛选变化时重置滚动位置,避免替换后的内容被误当成「没变化」。
|
|
10
8
|
*/
|
|
11
9
|
import { createElement as h, useEffect, useRef } from 'react'
|
|
12
10
|
import styles from '../../styles/List.module.css'
|
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
* Website: https://dsh-plugin.org
|
|
4
4
|
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* uninstall actions.
|
|
6
|
+
* 目录列表里的单张插件卡片:名称/分类/verified 徽标、描述 + 标签、Star/Fork/日期
|
|
7
|
+
* 统计,以及详情/安装/卸载动作。
|
|
9
8
|
*/
|
|
10
9
|
import { createElement as h } from 'react'
|
|
11
10
|
import styles from '../../styles/List.module.css'
|
|
@@ -3,12 +3,11 @@
|
|
|
3
3
|
* Website: https://dsh-plugin.org
|
|
4
4
|
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* button shows an up/down arrow for the current direction).
|
|
6
|
+
* 市场列表上方的工具栏:
|
|
7
|
+
* 第一行 —— 整行宽的搜索框;
|
|
8
|
+
* 第二行 —— 左侧结果计数,右侧排序分段控件
|
|
9
|
+
* (与已安装视图一致:点同一排序切换正/倒序,点新排序用其默认方向;
|
|
10
|
+
* 激活按钮显示当前方向的上/下箭头)。
|
|
12
11
|
*/
|
|
13
12
|
import { createElement as h, Fragment } from 'react'
|
|
14
13
|
import type { FormEvent, ReactNode } from 'react'
|
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
* Website: https://dsh-plugin.org
|
|
4
4
|
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* by the purple ad banner that promotes the catalog stats.
|
|
6
|
+
* 板块头部:品牌标题行(H1 + 官网入口按钮)+ 副标题,其后是宣传目录统计的紫色广告条。
|
|
8
7
|
*/
|
|
9
8
|
import { createElement as h, Fragment } from 'react'
|
|
10
9
|
import styles from '../../styles/Header.module.css'
|
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
* Website: https://dsh-plugin.org
|
|
4
4
|
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* carry no counts so their widths stay uniform.
|
|
6
|
+
* 分类 Tab:先是「全部」chip,其后每个目录分类一个 chip。「全部」chip 带插件总数,
|
|
7
|
+
* 各分类 chip 不带计数以保持宽度一致。
|
|
9
8
|
*/
|
|
10
9
|
import { createElement as h } from 'react'
|
|
11
10
|
import styles from '../../styles/Header.module.css'
|
|
@@ -3,11 +3,9 @@
|
|
|
3
3
|
* Website: https://dsh-plugin.org
|
|
4
4
|
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* Kept visually distinct from the category chips so the hierarchy reads:
|
|
10
|
-
* section → category → plugin.
|
|
6
|
+
* 一级导航:紧凑分段控件,在四个顶层板块间切换 —— 市场(浏览)、已安装(管理)、
|
|
7
|
+
* 自定义(手动命令安装)与设置(网络源与偏好)。与分类 chip 视觉上区分开,
|
|
8
|
+
* 让层级清晰:板块 → 分类 → 插件。
|
|
11
9
|
*/
|
|
12
10
|
import { createElement as h } from 'react'
|
|
13
11
|
import styles from '../../styles/SectionTabs.module.css'
|
|
@@ -3,13 +3,11 @@
|
|
|
3
3
|
* Website: https://dsh-plugin.org
|
|
4
4
|
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* in-button double-click.
|
|
6
|
+
* 通用确认弹窗 —— 应用里所有「确定吗?」问题的唯一入口。规则:任何询问都必须是
|
|
7
|
+
* 弹窗,绝不用按钮内双击。
|
|
9
8
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* action glyph for destructive ones (clear / delete / uninstall / reset).
|
|
9
|
+
* 中间的图标一眼说明类型:常规确认(安装/更新/重启/忽略)用蓝色问号,
|
|
10
|
+
* 危险操作(清空/删除/卸载/重置)用红色动作图形。
|
|
13
11
|
*/
|
|
14
12
|
import { createElement as h } from 'react'
|
|
15
13
|
import type { MouseEvent } from 'react'
|
|
@@ -3,12 +3,9 @@
|
|
|
3
3
|
* Website: https://dsh-plugin.org
|
|
4
4
|
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* latest version) merged with the host runtime facts (install path, installed
|
|
10
|
-
* version, install time, last update). Update / uninstall actions are
|
|
11
|
-
* offered from here too, mirroring the row actions.
|
|
6
|
+
* 已安装插件详情弹窗:从「已安装」视图打开(行点击或详情按钮),展示我们对某个已安装项
|
|
7
|
+
* 掌握的全部信息 —— 目录元数据(分类、收录入口、Star/Fork、最新版本)与宿主运行时事实
|
|
8
|
+
* (安装路径、已装版本、安装时间、最后更新)合并呈现。此处的更新/卸载动作与行内动作一致。
|
|
12
9
|
*/
|
|
13
10
|
import { createElement as h } from 'react'
|
|
14
11
|
import type { MouseEvent } from 'react'
|
|
@@ -3,20 +3,15 @@
|
|
|
3
3
|
* Website: https://dsh-plugin.org
|
|
4
4
|
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* ~/.dsh/profiles/<profile>/hub.log) straight from the server, one page at
|
|
9
|
-
* a time.
|
|
6
|
+
* 内置日志查看器弹窗:无需外部软件 —— 应用自己开窗,从服务端直接分页加载本地系统日志
|
|
7
|
+
* (JSONL,位于 ~/.dsh/profiles/<profile>/hub.log)。
|
|
10
8
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* say, only install errors — so the exact incompatible step of an install
|
|
15
|
-
* (or uninstall) is easy to spot. Search narrows by event code or message.
|
|
9
|
+
* 每行双重归类:功能域(安装/卸载/更新/诊断/设置/系统)与严重级别(debug/info/success/
|
|
10
|
+
* warn/error)。两轴筛选可只盯某类,比如只看安装错误 —— 便于定位安装(或卸载)中真正
|
|
11
|
+
* 卡住的那一步;搜索按事件码或消息缩小范围。
|
|
16
12
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* real file location and reveals it in the system file manager.
|
|
13
|
+
* 服务端分页:GET /dsh-plugin-hub/logs?offset=&limit=&category=&level=&query=
|
|
14
|
+
* → { entries, total, hasMore, path }。底部展示日志真实路径并可在系统文件管理器中定位。
|
|
20
15
|
*/
|
|
21
16
|
import { createElement as h, useCallback, useEffect, useRef, useState } from 'react'
|
|
22
17
|
import type { MouseEvent } from 'react'
|