@morehao/dsh-github-trending 0.3.0 → 0.3.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/CHANGELOG.md +14 -0
- package/README.md +8 -1
- package/client.js +365 -12
- package/lib/{chunk-X4PBXIZE.js → chunk-NMINPPWO.js} +77 -0
- package/lib/index.js +13 -1
- package/lib/internal.d.ts +22 -1
- package/lib/internal.js +5 -3
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.1 - 2026-10-31
|
|
4
|
+
|
|
5
|
+
### 新增
|
|
6
|
+
|
|
7
|
+
- **插件自更新**:关于弹层显示当前版本与 npm 最新版,打开时静默检查(Host 侧 5 分钟缓存),也可手动「检查更新」(`GET /update?fresh=1`)。确认后经宿主 `pluginManager` 重装本插件:`installBundle` 返回 `already-installed` 时走 `removeBundle → installBundle`,remove 之后安装失败会尝试装回原版本,成功后提示重启 DSH 生效。`link:` / `file:` / `workspace:` 安装不提供一键更新,只给 `dsh plugin --profile <name> add ...@latest` 供复制;没有 `pluginManager` 时同样退化为手动命令。
|
|
8
|
+
- **共享引擎 `@morehao/dsh-plugin-kit`**:更新引擎(查版本 / semver / registry 计划 / 安装路径 / 事件)与客户端状态机放进共享包,本仓新增 `src/host/update.ts` 只做 `ctx.get` 与 `execCapture` 接线;`POST /update` 的业务失败返回 409 + `UPDATE_FAILED` + `updateCode`,不占 500。
|
|
9
|
+
- 客户端构建守卫允许依赖包源码进入 bundle(`link:` / `file:` 依赖会解析到仓库外),本仓 `src/`、`lib/` 仍禁止进客户端产物。
|
|
10
|
+
|
|
11
|
+
### 修复
|
|
12
|
+
|
|
13
|
+
- **关于弹层拿不到主题变量**:`AboutDialog` 挂在 `.dshgt-root` 之外,`--gt-*` 没定义,弹层背景/边框退化成透明、文字对比度极低。现在弹层外面包一层 `.dshgt-root` 再进 mask。
|
|
14
|
+
- **日报里的表格不再被拍平成一个段落**:`client/markdown-core.ts` 补上 GFM 管道表解析——表头 + 分隔行(`---` / `:---` / `:---:` / `---:` 决定列对齐)+ 数据行,单元格按行内规则解析(链接、粗体、行内代码),支持反引号里的 `|` 与 `\|` 转义;表头/分隔行列数不一致或缺少分隔行时退回段落,不丢内容。`client/markdown.ts` 渲染 `table` / `thead` / `tbody` / `th` / `td` 并按对齐写 `text-align`;此前整张表会被当成「一行满是 `|` 的文字」。
|
|
15
|
+
- 表格样式随附:表头浅底、行分隔线、偶数行斑马纹、窄容器横向滚动;单元格内 `word-break: normal`,避免 `185,423` 这类数字被拆成两行。
|
|
16
|
+
|
|
3
17
|
## 0.3.0 - 2026-10-31
|
|
4
18
|
|
|
5
19
|
### 变更(含破坏性)
|
package/README.md
CHANGED
|
@@ -37,11 +37,18 @@ dsh plugin --profile <profile> add @morehao/dsh-github-trending
|
|
|
37
37
|
|
|
38
38
|
- 运行成功后,Host 从核心本次返回的 `outcome.files` 里挑当天的 `.md`(优先 `YYYY-MM-DD.md`,否则只有一个 `.md` 时用它),**只读**复制到 `$DSH_HOME/github-trending/previews/<runId>.md`:路径必须在 `repo.path` 内(词法 + realpath 各判一次)、不超过 512 KB、sha256 与契约声明一致;失败不阻断运行,只是这次没有预览。
|
|
39
39
|
- 预览副本 0600、临时文件 + rename、最多保留 30 份;`state.json` / `history.json` 只存 `file` / `bytes` / `sha256` 元数据,不存正文。
|
|
40
|
-
- `GET /preview?id=<runId>` 只接受历史里出现过的 id、不接路径参数;返回 `{ text, truncated }`。客户端渲染 Markdown 子集(标题 / 段落 / 列表 / 引用 / 粗体 / 行内代码 / 链接 / 分隔线),**只生成 React 文本节点**,链接仅放行 http(s),不渲染图片或原始 HTML;也可以切「原文」。
|
|
40
|
+
- `GET /preview?id=<runId>` 只接受历史里出现过的 id、不接路径参数;返回 `{ text, truncated }`。客户端渲染 Markdown 子集(标题 / 段落 / 列表 / 引用 / 代码块 / 表格(GFM 管道表,含列对齐)/ 粗体 / 行内代码 / 链接 / 分隔线),**只生成 React 文本节点**,链接仅放行 http(s),不渲染图片或原始 HTML;也可以切「原文」。
|
|
41
41
|
- 日报只列最近 30 天**有记录**的日期,每天一条;默认打开最近一期有预览的日报。失败 / 无变更 / 试跑 / 旧记录 / 副本被清理都有各自的空状态,不用示例内容兜底。
|
|
42
42
|
- 预览是运行结束时的派生副本:你在仓库里事后编辑 canonical 文件,不会改变这次记录。
|
|
43
43
|
- 关于入口在左轨底部:包名 / 版本 / GitHub 来自 `/state.plugin`(`repository` 由 `package.json` 规范化),仓库缺失时隐藏外链。
|
|
44
44
|
|
|
45
|
+
## 插件更新
|
|
46
|
+
|
|
47
|
+
- 关于弹层里会显示当前版本与 npm 上的最新版:打开时静默检查一次(Host 侧缓存 5 分钟),也可以点「检查更新」强制重查。只跟随 npm 的 `latest` 稳定版。
|
|
48
|
+
- 确认后由宿主 `pluginManager` 重装本插件(`installBundle`;已装同 spec 时走 `removeBundle → installBundle`,失败会尝试装回原版本),完成后需要重启 DSH 生效。
|
|
49
|
+
- 本地安装(`link:` / `file:` / `workspace:`)**不提供一键更新**:那会把开发链接换成 npm 版。此时只显示 `dsh plugin --profile <name> add @morehao/dsh-github-trending@latest` 供复制。
|
|
50
|
+
- 更新引擎来自共享包 [`@morehao/dsh-plugin-kit`](https://www.npmjs.com/package/@morehao/dsh-plugin-kit)(`./update` + `./update/client`),本仓只做上下文与 `execCapture` 接线;`GET /update` / `POST /update` 与其它路由一样要求自定义头、`no-store`,业务失败返回 409 + `UPDATE_FAILED` + `updateCode`。
|
|
51
|
+
|
|
45
52
|
## 它需要什么 / 它访问哪里 / 它不上传什么
|
|
46
53
|
|
|
47
54
|
**需要什么**
|
package/client.js
CHANGED
|
@@ -339,7 +339,25 @@ var DICT = {
|
|
|
339
339
|
"about.license": "许可",
|
|
340
340
|
"about.core": "核心",
|
|
341
341
|
"about.env": "运行环境",
|
|
342
|
-
"about.env.value": "DSH Web · Node 插件"
|
|
342
|
+
"about.env.value": "DSH Web · Node 插件",
|
|
343
|
+
"about.update.title": "插件更新",
|
|
344
|
+
"about.update.check": "检查更新",
|
|
345
|
+
"about.update.checking": "正在检查最新版…",
|
|
346
|
+
"about.update.current": "已是最新(v{version})",
|
|
347
|
+
"about.update.available": "有新版本 v{latest}(当前 v{current})",
|
|
348
|
+
"about.update.apply": "更新到 v{version}",
|
|
349
|
+
"about.update.confirm": "确认更新到 v{version}?会重装本插件并重载面板,之后需要重启 DSH 生效。",
|
|
350
|
+
"about.update.confirmYes": "确认更新",
|
|
351
|
+
"about.update.cancel": "取消",
|
|
352
|
+
"about.update.applying": "正在更新到 v{version}…",
|
|
353
|
+
"about.update.done": "已更新到 v{version},重启 DSH 后生效。",
|
|
354
|
+
"about.update.applied": "已更新到 v{version}。",
|
|
355
|
+
"about.update.failed": "更新失败:{message}",
|
|
356
|
+
"about.update.checkFailed": "检查更新失败:拿不到 registry 上的最新版。可以稍后重试,或手动执行下面的命令。",
|
|
357
|
+
"about.update.manual": "当前是本地 {kind} 安装,不能一键更新(会把开发链接换成 npm 版)。手动更新:",
|
|
358
|
+
"about.update.copy": "复制命令",
|
|
359
|
+
"about.update.copied": "已复制",
|
|
360
|
+
"about.update.hint": "只检查 npm 上的 latest 稳定版;更新后需要重启 DSH。"
|
|
343
361
|
},
|
|
344
362
|
en: {
|
|
345
363
|
"section.title": "GitHub Trending",
|
|
@@ -635,7 +653,25 @@ var DICT = {
|
|
|
635
653
|
"about.license": "License",
|
|
636
654
|
"about.core": "Core",
|
|
637
655
|
"about.env": "Runtime",
|
|
638
|
-
"about.env.value": "DSH Web · Node plugin"
|
|
656
|
+
"about.env.value": "DSH Web · Node plugin",
|
|
657
|
+
"about.update.title": "Plugin update",
|
|
658
|
+
"about.update.check": "Check for updates",
|
|
659
|
+
"about.update.checking": "Checking the latest version…",
|
|
660
|
+
"about.update.current": "Up to date (v{version})",
|
|
661
|
+
"about.update.available": "v{latest} is available (current v{current})",
|
|
662
|
+
"about.update.apply": "Update to v{version}",
|
|
663
|
+
"about.update.confirm": "Update to v{version}? The plugin will be reinstalled and the panel reloaded; restart DSH afterwards.",
|
|
664
|
+
"about.update.confirmYes": "Update now",
|
|
665
|
+
"about.update.cancel": "Cancel",
|
|
666
|
+
"about.update.applying": "Updating to v{version}…",
|
|
667
|
+
"about.update.done": "Updated to v{version}; restart DSH to apply.",
|
|
668
|
+
"about.update.applied": "Updated to v{version}.",
|
|
669
|
+
"about.update.failed": "Update failed: {message}",
|
|
670
|
+
"about.update.checkFailed": "Update check failed: cannot reach the registry for the latest version. Retry later or run the command below.",
|
|
671
|
+
"about.update.manual": "Installed from a local {kind} spec; one-click update is disabled (it would replace the dev link). Update manually:",
|
|
672
|
+
"about.update.copy": "Copy command",
|
|
673
|
+
"about.update.copied": "Copied",
|
|
674
|
+
"about.update.hint": "Checks the npm latest stable tag only; applying requires a DSH restart."
|
|
639
675
|
}
|
|
640
676
|
};
|
|
641
677
|
function activeLang(locale) {
|
|
@@ -661,11 +697,11 @@ var CSS = `
|
|
|
661
697
|
.dshgt-root{--gt-fg:var(--dsw-alias-label-primary,#1f2328);--gt-muted:var(--dsw-alias-label-secondary,#6b7280);--gt-bg:var(--dsw-alias-bg-base,#fff);--gt-card:var(--dsw-alias-bg-layer-1,#f8fafc);--gt-border:var(--dsw-alias-border-l2,#e5e7eb);--gt-accent:var(--dsw-alias-state-business-primary,#2563eb);--gt-ok:var(--dsw-alias-state-success-primary,#16a34a);--gt-warn:var(--dsw-alias-state-warn-primary,#d97706);--gt-err:var(--dsw-alias-state-error-primary,#dc2626);color:var(--gt-fg);font-size:14px;line-height:1.55;display:flex;flex-direction:column;gap:12px;}
|
|
662
698
|
.dshgt-root *{box-sizing:border-box;}
|
|
663
699
|
.dshgt-head{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;}
|
|
664
|
-
.dshgt-title{font-size:15px;font-weight:600;}
|
|
700
|
+
.dshgt-title{font-size:15px;font-weight:600;white-space:nowrap;}
|
|
665
701
|
.dshgt-sub{color:var(--gt-muted);font-size:12px;}
|
|
666
702
|
.dshgt-tabs{display:flex;gap:6px;border-bottom:1px solid var(--gt-border);}
|
|
667
703
|
.dshgt-tab{appearance:none;border:none;background:none;padding:6px 10px;font:inherit;color:var(--gt-muted);cursor:pointer;border-bottom:2px solid transparent;}
|
|
668
|
-
.dshgt-tab[aria-selected="true"]{color:var(--gt-fg);border-bottom-color:var(--gt-accent);font-weight:600;}
|
|
704
|
+
.dshgt-tab[aria-selected="true"]{color:var(--gt-fg);border-bottom-color:var(--gt-accent);font-weight:600;white-space:nowrap;}
|
|
669
705
|
.dshgt-shell{height:100%;min-height:0;overflow:hidden;}
|
|
670
706
|
.dshgt-content{flex:1;min-height:0;display:flex;}
|
|
671
707
|
.dshgt-scroll{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:12px;padding-right:4px;}
|
|
@@ -673,12 +709,12 @@ var CSS = `
|
|
|
673
709
|
.dshgt-vtabs{display:flex;flex-direction:column;gap:2px;border-right:1px solid var(--gt-border);padding-right:8px;overflow-y:auto;}
|
|
674
710
|
.dshgt-vtab{appearance:none;border:none;background:none;text-align:left;padding:7px 10px;border-radius:7px;color:var(--gt-muted);cursor:pointer;font:inherit;font-size:12px;display:flex;align-items:center;gap:6px;}
|
|
675
711
|
.dshgt-vtab:hover{background:var(--dsw-alias-interactive-bg-hover,color-mix(in srgb,var(--gt-accent) 8%,transparent));}
|
|
676
|
-
.dshgt-vtab[aria-selected="true"]{background:color-mix(in srgb,var(--gt-accent) 12%,transparent);color:var(--gt-fg);font-weight:600;}
|
|
712
|
+
.dshgt-vtab[aria-selected="true"]{background:color-mix(in srgb,var(--gt-accent) 12%,transparent);color:var(--gt-fg);font-weight:600;white-space:nowrap;}
|
|
677
713
|
.dshgt-vtab-dirty{width:6px;height:6px;border-radius:50%;background:var(--gt-warn);flex:none;margin-left:auto;}
|
|
678
714
|
.dshgt-vpanel{min-width:0;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:12px;padding-right:4px;}
|
|
679
715
|
.dshgt-card{border:1px solid var(--gt-border);border-radius:10px;background:var(--gt-card);padding:12px 14px;display:flex;flex-direction:column;gap:8px;}
|
|
680
716
|
.dshgt-card-h{display:flex;align-items:center;gap:8px;flex-wrap:wrap;}
|
|
681
|
-
.dshgt-card-h h3{margin:0;font-size:13px;font-weight:600;}
|
|
717
|
+
.dshgt-card-h h3{margin:0;font-size:13px;font-weight:600;white-space:nowrap;}
|
|
682
718
|
.dshgt-hint{color:var(--gt-muted);font-size:12px;}
|
|
683
719
|
.dshgt-desc{margin:0;color:var(--gt-muted);font-size:12px;}
|
|
684
720
|
.dshgt-row{display:flex;gap:10px;align-items:center;min-height:28px;flex-wrap:wrap;}
|
|
@@ -736,7 +772,7 @@ var CSS = `
|
|
|
736
772
|
.dshgt-nav-item{display:flex;align-items:center;gap:9px;height:36px;padding:0 9px;border:1px solid transparent;border-radius:8px;background:none;text-align:left;font-family:inherit;font-size:13.5px;color:var(--gt-muted);width:100%;cursor:pointer;}
|
|
737
773
|
.dshgt-nav-item svg{flex:none;opacity:.82;}
|
|
738
774
|
.dshgt-nav-item:hover{background:color-mix(in srgb,var(--gt-fg) 6%,var(--gt-bg));color:var(--gt-fg);}
|
|
739
|
-
.dshgt-nav-item.on{background:var(--gt-bg);border-color:var(--gt-border);color:var(--gt-fg);font-weight:600;}
|
|
775
|
+
.dshgt-nav-item.on{background:var(--gt-bg);border-color:var(--gt-border);color:var(--gt-fg);font-weight:600;white-space:nowrap;}
|
|
740
776
|
.dshgt-nav-item.on svg{opacity:1;}
|
|
741
777
|
.dshgt-nav-tail{margin-left:auto;display:flex;align-items:center;gap:5px;font-size:11.5px;color:var(--gt-muted);font-weight:400;}
|
|
742
778
|
.dshgt-rail-spacer{flex:1;min-height:16px;}
|
|
@@ -833,14 +869,14 @@ var CSS = `
|
|
|
833
869
|
.dshgt-digest-bar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:9px 12px;border-bottom:1px solid color-mix(in srgb,var(--gt-border) 70%,transparent);background:color-mix(in srgb,var(--gt-fg) 2.5%,var(--gt-card));}
|
|
834
870
|
.dshgt-seg{display:inline-flex;border:1px solid var(--gt-border);border-radius:8px;padding:2px;background:var(--gt-bg);gap:2px;}
|
|
835
871
|
.dshgt-seg button{border:0;background:none;height:26px;padding:0 11px;border-radius:6px;font-family:inherit;font-size:12.5px;color:var(--gt-muted);cursor:pointer;}
|
|
836
|
-
.dshgt-seg button.on{background:var(--gt-card);color:var(--gt-fg);font-weight:600;}
|
|
872
|
+
.dshgt-seg button.on{background:var(--gt-card);color:var(--gt-fg);font-weight:600;white-space:nowrap;}
|
|
837
873
|
.dshgt-digest-doc{padding:26px 32px 22px;min-width:0;}
|
|
838
874
|
.dshgt-doc-meta{display:flex;gap:12px;flex-wrap:wrap;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;color:var(--gt-muted);padding-bottom:12px;border-bottom:1px solid color-mix(in srgb,var(--gt-border) 70%,transparent);}
|
|
839
875
|
.dshgt-digest-raw{margin:0;padding:22px 28px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.75;white-space:pre-wrap;word-break:break-word;color:var(--gt-muted);background:color-mix(in srgb,var(--gt-fg) 2.5%,var(--gt-card));max-height:640px;overflow:auto;}
|
|
840
876
|
.dshgt-digest-loading{padding:40px 28px;color:var(--gt-muted);font-size:13px;}
|
|
841
877
|
.dshgt-digest-empty{padding:42px 36px 46px;max-width:720px;}
|
|
842
878
|
.dshgt-status-line{display:flex;align-items:center;gap:8px;font-size:12.5px;color:var(--gt-muted);}
|
|
843
|
-
.dshgt-status-line b{color:var(--gt-fg);font-weight:600;}
|
|
879
|
+
.dshgt-status-line b{color:var(--gt-fg);font-weight:600;white-space:nowrap;}
|
|
844
880
|
.dshgt-digest-empty h2{margin:14px 0 6px;font-size:20px;font-weight:650;letter-spacing:-.012em;}
|
|
845
881
|
.dshgt-digest-empty p{margin:0;max-width:580px;font-size:13.5px;line-height:1.7;color:var(--gt-muted);}
|
|
846
882
|
.dshgt-digest-error{margin-top:10px;color:var(--gt-err);}
|
|
@@ -855,6 +891,12 @@ var CSS = `
|
|
|
855
891
|
.dshgt-md-list{margin:8px 0;padding-left:22px;}
|
|
856
892
|
.dshgt-md-list li{margin:3px 0;}
|
|
857
893
|
.dshgt-md-quote{margin:12px 0;padding:2px 0 2px 14px;border-left:3px solid var(--gt-border);color:var(--gt-muted);}
|
|
894
|
+
.dshgt-md-tablewrap{margin:12px 0;border:1px solid var(--gt-border);border-radius:8px;overflow-x:auto;}
|
|
895
|
+
.dshgt-md-table{width:100%;min-width:560px;border-collapse:collapse;font-size:13px;line-height:1.6;}
|
|
896
|
+
.dshgt-md-table th,.dshgt-md-table td{padding:7px 10px;text-align:left;vertical-align:top;border-bottom:1px solid color-mix(in srgb,var(--gt-border) 65%,transparent);word-break:normal;overflow-wrap:break-word;}
|
|
897
|
+
.dshgt-md-table th{background:color-mix(in srgb,var(--gt-fg) 4%,var(--gt-card));font-weight:600;white-space:nowrap;}
|
|
898
|
+
.dshgt-md-table tbody tr:last-child td{border-bottom:0;}
|
|
899
|
+
.dshgt-md-table tbody tr:nth-child(even){background:color-mix(in srgb,var(--gt-fg) 2%,var(--gt-card));}
|
|
858
900
|
.dshgt-md-pre{margin:12px 0;padding:12px 14px;border-radius:8px;background:color-mix(in srgb,var(--gt-fg) 5%,var(--gt-card));overflow:auto;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.6;}
|
|
859
901
|
.dshgt-md-code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;background:color-mix(in srgb,var(--gt-fg) 7%,var(--gt-card));padding:1px 4px;border-radius:4px;}
|
|
860
902
|
.dshgt-md-hr{border:0;border-top:1px solid var(--gt-border);margin:18px 0;}
|
|
@@ -899,6 +941,17 @@ var CSS = `
|
|
|
899
941
|
.dshgt-about .dshgt-kv{grid-template-columns:110px 1fr;}
|
|
900
942
|
.dshgt-about .dshgt-kv a{color:var(--gt-accent);text-decoration:none;word-break:break-all;}
|
|
901
943
|
.dshgt-about .dshgt-kv a:hover{text-decoration:underline;}
|
|
944
|
+
.dshgt-update{margin-top:14px;padding-top:12px;border-top:1px solid color-mix(in srgb,var(--gt-border) 70%,transparent);}
|
|
945
|
+
.dshgt-update-head{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;}
|
|
946
|
+
.dshgt-update-head h4{margin:0;font-size:13px;font-weight:600;}
|
|
947
|
+
.dshgt-update-head .dshgt-hint{font-size:11.5px;}
|
|
948
|
+
.dshgt-update-line{margin:6px 0 0;font-size:12.5px;color:var(--gt-muted);line-height:1.55;}
|
|
949
|
+
.dshgt-update-err{color:var(--gt-err);}
|
|
950
|
+
.dshgt-update-warn{margin:6px 0 0;font-size:12px;color:var(--gt-warn);line-height:1.55;}
|
|
951
|
+
.dshgt-update-actions{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-top:9px;}
|
|
952
|
+
.dshgt-update-manual{margin-top:9px;padding:9px 10px;border:1px solid color-mix(in srgb,var(--gt-warn) 35%,var(--gt-border));border-radius:8px;background:color-mix(in srgb,var(--gt-warn) 6%,var(--gt-card));}
|
|
953
|
+
.dshgt-update-manual .dshgt-update-warn{margin:0 0 6px;}
|
|
954
|
+
.dshgt-update-cmd{display:block;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11.5px;line-height:1.5;color:var(--gt-fg);word-break:break-all;user-select:all;}
|
|
902
955
|
|
|
903
956
|
@media (max-width:1100px){
|
|
904
957
|
.dshgt-app{grid-template-columns:190px minmax(0,1fr);}
|
|
@@ -1117,6 +1170,17 @@ function getPreview(runId, signal) {
|
|
|
1117
1170
|
function getLog(runId, signal) {
|
|
1118
1171
|
return apiCall("GET", `/log?id=${encodeURIComponent(runId)}`, void 0, signal === void 0 ? {} : { signal });
|
|
1119
1172
|
}
|
|
1173
|
+
async function getPluginUpdate(options = {}) {
|
|
1174
|
+
const query = options.fresh === true ? "?fresh=1" : "";
|
|
1175
|
+
const payload = await apiCall("GET", `/update${query}`, void 0, {
|
|
1176
|
+
...options.signal === void 0 ? {} : { signal: options.signal }
|
|
1177
|
+
});
|
|
1178
|
+
return payload.update;
|
|
1179
|
+
}
|
|
1180
|
+
async function applyPluginUpdate() {
|
|
1181
|
+
const payload = await apiCall("POST", "/update", {});
|
|
1182
|
+
return payload.result;
|
|
1183
|
+
}
|
|
1120
1184
|
|
|
1121
1185
|
// client/store.ts
|
|
1122
1186
|
var POLL_MS = 5e3;
|
|
@@ -2570,9 +2634,72 @@ var HR = /^\s*(?:-{3,}|\*{3,}|_{3,})\s*$/;
|
|
|
2570
2634
|
var QUOTE = /^\s*>\s?(.*)$/;
|
|
2571
2635
|
var BULLET = /^\s*[-*+]\s+(.*)$/;
|
|
2572
2636
|
var ORDERED = /^\s*\d+[.)]\s+(.*)$/;
|
|
2637
|
+
var TABLE_DELIM_CELL = /^:?-+:?$/;
|
|
2573
2638
|
function isBlockStart(line) {
|
|
2574
2639
|
return FENCE.test(line) || HEADING.test(line) || HR.test(line) || QUOTE.test(line) || BULLET.test(line) || ORDERED.test(line);
|
|
2575
2640
|
}
|
|
2641
|
+
function splitTableRow(line) {
|
|
2642
|
+
const cells = [];
|
|
2643
|
+
let current = "";
|
|
2644
|
+
let inCode = false;
|
|
2645
|
+
const text = line.trim();
|
|
2646
|
+
for (let cursor = 0; cursor < text.length; cursor += 1) {
|
|
2647
|
+
const char = text[cursor] ?? "";
|
|
2648
|
+
if (char === "\\" && text[cursor + 1] === "|") {
|
|
2649
|
+
current += "|";
|
|
2650
|
+
cursor += 1;
|
|
2651
|
+
continue;
|
|
2652
|
+
}
|
|
2653
|
+
if (char === "`") {
|
|
2654
|
+
inCode = !inCode;
|
|
2655
|
+
current += char;
|
|
2656
|
+
continue;
|
|
2657
|
+
}
|
|
2658
|
+
if (char === "|" && !inCode) {
|
|
2659
|
+
cells.push(current);
|
|
2660
|
+
current = "";
|
|
2661
|
+
continue;
|
|
2662
|
+
}
|
|
2663
|
+
current += char;
|
|
2664
|
+
}
|
|
2665
|
+
cells.push(current);
|
|
2666
|
+
if (cells.length > 1 && (cells[0] ?? "").trim() === "") cells.shift();
|
|
2667
|
+
if (cells.length > 1 && (cells[cells.length - 1] ?? "").trim() === "") cells.pop();
|
|
2668
|
+
return cells.map((cell) => cell.trim());
|
|
2669
|
+
}
|
|
2670
|
+
function parseAlignRow(line) {
|
|
2671
|
+
const cells = splitTableRow(line);
|
|
2672
|
+
if (cells.length === 0) return null;
|
|
2673
|
+
const align = [];
|
|
2674
|
+
for (const cell of cells) {
|
|
2675
|
+
const value = cell.trim();
|
|
2676
|
+
if (!TABLE_DELIM_CELL.test(value)) return null;
|
|
2677
|
+
const left = value.startsWith(":");
|
|
2678
|
+
const right = value.endsWith(":");
|
|
2679
|
+
align.push(left && right ? "center" : right ? "right" : left ? "left" : void 0);
|
|
2680
|
+
}
|
|
2681
|
+
return align;
|
|
2682
|
+
}
|
|
2683
|
+
function tableAt(lines, index) {
|
|
2684
|
+
const headerLine = lines[index] ?? "";
|
|
2685
|
+
if (!headerLine.includes("|")) return null;
|
|
2686
|
+
const align = parseAlignRow(lines[index + 1] ?? "");
|
|
2687
|
+
if (align === null) return null;
|
|
2688
|
+
const headerCells = splitTableRow(headerLine);
|
|
2689
|
+
if (headerCells.length === 0 || headerCells.length !== align.length) return null;
|
|
2690
|
+
const rows = [];
|
|
2691
|
+
let cursor = index + 2;
|
|
2692
|
+
while (cursor < lines.length) {
|
|
2693
|
+
const line = lines[cursor] ?? "";
|
|
2694
|
+
if (line.trim() === "" || !line.includes("|")) break;
|
|
2695
|
+
if (isBlockStart(line)) break;
|
|
2696
|
+
const cells = splitTableRow(line).slice(0, headerCells.length);
|
|
2697
|
+
while (cells.length < headerCells.length) cells.push("");
|
|
2698
|
+
rows.push(cells.map((cell) => parseInline(cell)));
|
|
2699
|
+
cursor += 1;
|
|
2700
|
+
}
|
|
2701
|
+
return { align, header: headerCells.map((cell) => parseInline(cell)), rows, next: cursor };
|
|
2702
|
+
}
|
|
2576
2703
|
function parseBlocks(body) {
|
|
2577
2704
|
const lines = body.split("\n");
|
|
2578
2705
|
const blocks = [];
|
|
@@ -2644,11 +2771,17 @@ function parseBlocks(body) {
|
|
|
2644
2771
|
blocks.push({ type: "list", ordered: true, items });
|
|
2645
2772
|
continue;
|
|
2646
2773
|
}
|
|
2774
|
+
const table = tableAt(lines, index);
|
|
2775
|
+
if (table !== null) {
|
|
2776
|
+
blocks.push({ type: "table", align: table.align, header: table.header, rows: table.rows });
|
|
2777
|
+
index = table.next;
|
|
2778
|
+
continue;
|
|
2779
|
+
}
|
|
2647
2780
|
const buffer = [];
|
|
2648
2781
|
while (index < lines.length) {
|
|
2649
2782
|
const current = lines[index] ?? "";
|
|
2650
2783
|
if (current.trim() === "") break;
|
|
2651
|
-
if (buffer.length > 0 && isBlockStart(current)) break;
|
|
2784
|
+
if (buffer.length > 0 && (isBlockStart(current) || tableAt(lines, index) !== null)) break;
|
|
2652
2785
|
buffer.push(current.trim());
|
|
2653
2786
|
index += 1;
|
|
2654
2787
|
}
|
|
@@ -2681,6 +2814,9 @@ function renderInline(nodes, prefix) {
|
|
|
2681
2814
|
}
|
|
2682
2815
|
});
|
|
2683
2816
|
}
|
|
2817
|
+
function alignStyle(align) {
|
|
2818
|
+
return align === void 0 ? void 0 : { textAlign: align };
|
|
2819
|
+
}
|
|
2684
2820
|
function renderBlock(block, key) {
|
|
2685
2821
|
switch (block.type) {
|
|
2686
2822
|
case "heading": {
|
|
@@ -2705,6 +2841,43 @@ function renderBlock(block, key) {
|
|
|
2705
2841
|
);
|
|
2706
2842
|
case "hr":
|
|
2707
2843
|
return h("hr", { key, className: "dshgt-md-hr" });
|
|
2844
|
+
case "table":
|
|
2845
|
+
return h(
|
|
2846
|
+
"div",
|
|
2847
|
+
{ key, className: "dshgt-md-tablewrap" },
|
|
2848
|
+
h(
|
|
2849
|
+
"table",
|
|
2850
|
+
{ className: "dshgt-md-table" },
|
|
2851
|
+
h(
|
|
2852
|
+
"thead",
|
|
2853
|
+
null,
|
|
2854
|
+
h(
|
|
2855
|
+
"tr",
|
|
2856
|
+
null,
|
|
2857
|
+
block.header.map(
|
|
2858
|
+
(cell, index) => h("th", { key: `h${index}`, style: alignStyle(block.align[index]) }, renderInline(cell, `${key}-h${index}`))
|
|
2859
|
+
)
|
|
2860
|
+
)
|
|
2861
|
+
),
|
|
2862
|
+
h(
|
|
2863
|
+
"tbody",
|
|
2864
|
+
null,
|
|
2865
|
+
block.rows.map(
|
|
2866
|
+
(row, rowIndex) => h(
|
|
2867
|
+
"tr",
|
|
2868
|
+
{ key: `r${rowIndex}` },
|
|
2869
|
+
row.map(
|
|
2870
|
+
(cell, cellIndex) => h(
|
|
2871
|
+
"td",
|
|
2872
|
+
{ key: `c${cellIndex}`, style: alignStyle(block.align[cellIndex]) },
|
|
2873
|
+
renderInline(cell, `${key}-r${rowIndex}c${cellIndex}`)
|
|
2874
|
+
)
|
|
2875
|
+
)
|
|
2876
|
+
)
|
|
2877
|
+
)
|
|
2878
|
+
)
|
|
2879
|
+
)
|
|
2880
|
+
);
|
|
2708
2881
|
}
|
|
2709
2882
|
}
|
|
2710
2883
|
function renderMarkdown(markdown) {
|
|
@@ -3006,10 +3179,117 @@ function metaLine(rendered) {
|
|
|
3006
3179
|
);
|
|
3007
3180
|
}
|
|
3008
3181
|
|
|
3182
|
+
// node_modules/@morehao/dsh-plugin-kit/dist/update-client.js
|
|
3183
|
+
var IDLE = { status: "idle", view: null, error: null };
|
|
3184
|
+
function errorOf(error) {
|
|
3185
|
+
if (error !== null && typeof error === "object") {
|
|
3186
|
+
const value = error;
|
|
3187
|
+
const message = typeof value.message === "string" && value.message !== "" ? value.message : "操作失败";
|
|
3188
|
+
return typeof value.code === "string" ? { code: value.code, message } : { message };
|
|
3189
|
+
}
|
|
3190
|
+
return { message: String(error ?? "操作失败") };
|
|
3191
|
+
}
|
|
3192
|
+
function createUpdateController(options) {
|
|
3193
|
+
const now = options.now ?? Date.now;
|
|
3194
|
+
let state = { ...IDLE };
|
|
3195
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
3196
|
+
let inFlight = null;
|
|
3197
|
+
function emit(next) {
|
|
3198
|
+
state = next;
|
|
3199
|
+
options.onChange?.(state);
|
|
3200
|
+
for (const listener of listeners) listener(state);
|
|
3201
|
+
}
|
|
3202
|
+
async function check(checkOptions = {}) {
|
|
3203
|
+
if (inFlight !== null) return;
|
|
3204
|
+
inFlight = "check";
|
|
3205
|
+
emit({ ...state, status: "checking", error: null });
|
|
3206
|
+
try {
|
|
3207
|
+
const view = await options.request.check(checkOptions);
|
|
3208
|
+
const checkedAt = new Date(now()).toISOString();
|
|
3209
|
+
if (view.checkFailed) {
|
|
3210
|
+
emit({
|
|
3211
|
+
status: "failed",
|
|
3212
|
+
view,
|
|
3213
|
+
error: { code: "CHECK_FAILED", message: "检查更新失败:拿不到 registry 上的最新版本" },
|
|
3214
|
+
checkedAt
|
|
3215
|
+
});
|
|
3216
|
+
} else {
|
|
3217
|
+
emit({ status: view.updateAvailable ? "available" : "current", view, error: null, checkedAt });
|
|
3218
|
+
}
|
|
3219
|
+
} catch (error) {
|
|
3220
|
+
emit({ ...state, status: "failed", error: errorOf(error) });
|
|
3221
|
+
} finally {
|
|
3222
|
+
inFlight = null;
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
3225
|
+
async function apply2() {
|
|
3226
|
+
if (inFlight !== null) return;
|
|
3227
|
+
const view = state.view;
|
|
3228
|
+
if (view === null || !view.updateAvailable) {
|
|
3229
|
+
emit({ ...state, status: "failed", error: { code: "NO_UPDATE", message: "没有可更新的版本,请先检查更新" } });
|
|
3230
|
+
return;
|
|
3231
|
+
}
|
|
3232
|
+
if (!view.canApply) {
|
|
3233
|
+
emit({
|
|
3234
|
+
...state,
|
|
3235
|
+
status: "failed",
|
|
3236
|
+
error: { code: "NO_APPLY", message: `当前环境不支持一键更新,请执行:${view.manualCommand}` }
|
|
3237
|
+
});
|
|
3238
|
+
return;
|
|
3239
|
+
}
|
|
3240
|
+
inFlight = "apply";
|
|
3241
|
+
emit({ ...state, status: "applying", error: null });
|
|
3242
|
+
try {
|
|
3243
|
+
const result = await options.request.apply();
|
|
3244
|
+
const restartRequired = result.restartRequired ?? result.application !== "applied";
|
|
3245
|
+
emit({ ...state, status: restartRequired ? "restart-required" : "applied", error: null });
|
|
3246
|
+
} catch (error) {
|
|
3247
|
+
emit({ ...state, status: "failed", error: errorOf(error) });
|
|
3248
|
+
} finally {
|
|
3249
|
+
inFlight = null;
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
return {
|
|
3253
|
+
getState: () => state,
|
|
3254
|
+
subscribe: (listener) => {
|
|
3255
|
+
listeners.add(listener);
|
|
3256
|
+
return () => {
|
|
3257
|
+
listeners.delete(listener);
|
|
3258
|
+
};
|
|
3259
|
+
},
|
|
3260
|
+
check,
|
|
3261
|
+
apply: apply2,
|
|
3262
|
+
reset: () => emit({ ...IDLE })
|
|
3263
|
+
};
|
|
3264
|
+
}
|
|
3265
|
+
|
|
3009
3266
|
// client/about.ts
|
|
3010
3267
|
function AboutDialog(props) {
|
|
3011
3268
|
const { t, state } = props;
|
|
3012
3269
|
const [copied, setCopied] = import_react.default.useState(false);
|
|
3270
|
+
const [copiedCommand, setCopiedCommand] = import_react.default.useState(false);
|
|
3271
|
+
const [confirming, setConfirming] = import_react.default.useState(false);
|
|
3272
|
+
const controllerRef = import_react.default.useRef(null);
|
|
3273
|
+
if (controllerRef.current === null) {
|
|
3274
|
+
controllerRef.current = createUpdateController({
|
|
3275
|
+
request: {
|
|
3276
|
+
check: (options) => getPluginUpdate(options.fresh === true ? { fresh: true } : {}),
|
|
3277
|
+
apply: () => applyPluginUpdate()
|
|
3278
|
+
}
|
|
3279
|
+
});
|
|
3280
|
+
}
|
|
3281
|
+
const controller = controllerRef.current;
|
|
3282
|
+
const [updateState, setUpdateState] = import_react.default.useState(() => controller.getState());
|
|
3283
|
+
import_react.default.useEffect(() => {
|
|
3284
|
+
const unsubscribe = controller.subscribe(setUpdateState);
|
|
3285
|
+
if (controller.getState().status === "idle") void controller.check();
|
|
3286
|
+
return unsubscribe;
|
|
3287
|
+
}, [controller]);
|
|
3288
|
+
import_react.default.useEffect(() => {
|
|
3289
|
+
if (updateState.status === "applying" || updateState.status === "restart-required" || updateState.status === "applied") {
|
|
3290
|
+
setConfirming(false);
|
|
3291
|
+
}
|
|
3292
|
+
}, [updateState.status]);
|
|
3013
3293
|
const plugin = state.plugin;
|
|
3014
3294
|
const fullName = `${plugin.name}@v${plugin.version}`;
|
|
3015
3295
|
const repository = plugin.repository;
|
|
@@ -3029,7 +3309,60 @@ function AboutDialog(props) {
|
|
|
3029
3309
|
setTimeout(() => setCopied(false), 1600);
|
|
3030
3310
|
});
|
|
3031
3311
|
};
|
|
3032
|
-
|
|
3312
|
+
const copyCommand = () => {
|
|
3313
|
+
const command = updateState.view?.manualCommand;
|
|
3314
|
+
if (command === void 0) return;
|
|
3315
|
+
void copyText(command).then((ok) => {
|
|
3316
|
+
if (!ok) return;
|
|
3317
|
+
setCopiedCommand(true);
|
|
3318
|
+
setTimeout(() => setCopiedCommand(false), 1600);
|
|
3319
|
+
});
|
|
3320
|
+
};
|
|
3321
|
+
const view = updateState.view;
|
|
3322
|
+
const status = updateState.status;
|
|
3323
|
+
const target = view !== null && view.updateAvailable ? view.latestVersion ?? "" : "";
|
|
3324
|
+
const busy = status === "checking" || status === "applying";
|
|
3325
|
+
const settled = status === "restart-required" || status === "applied";
|
|
3326
|
+
const actionable = view !== null && view.updateAvailable && view.canApply && !settled && !busy;
|
|
3327
|
+
const manual = view !== null && (!view.canApply || view.checkFailed) ? view.manualCommand : null;
|
|
3328
|
+
const statusLine = () => {
|
|
3329
|
+
if (status === "checking" || view === null) return t("about.update.checking");
|
|
3330
|
+
if (status === "applying") return t("about.update.applying", { version: target });
|
|
3331
|
+
if (status === "restart-required") return t("about.update.done", { version: view.latestVersion ?? target });
|
|
3332
|
+
if (status === "applied") return t("about.update.applied", { version: view.latestVersion ?? target });
|
|
3333
|
+
if (status === "failed") {
|
|
3334
|
+
if (updateState.error?.code === "CHECK_FAILED") return t("about.update.checkFailed");
|
|
3335
|
+
return t("about.update.failed", { message: updateState.error?.message ?? "" });
|
|
3336
|
+
}
|
|
3337
|
+
if (view.checkFailed) return t("about.update.checkFailed");
|
|
3338
|
+
if (view.updateAvailable) return t("about.update.available", { latest: view.latestVersion ?? "", current: view.currentVersion });
|
|
3339
|
+
return t("about.update.current", { version: view.currentVersion });
|
|
3340
|
+
};
|
|
3341
|
+
const updateActions = [
|
|
3342
|
+
h(Btn, { key: "check", small: true, disabled: busy, onClick: () => void controller.check({ fresh: true }) }, t("about.update.check")),
|
|
3343
|
+
manual === null ? null : h(
|
|
3344
|
+
Btn,
|
|
3345
|
+
{ key: "copy-command", small: true, onClick: copyCommand },
|
|
3346
|
+
copiedCommand ? t("about.update.copied") : t("about.update.copy")
|
|
3347
|
+
),
|
|
3348
|
+
actionable ? confirming ? [
|
|
3349
|
+
h(
|
|
3350
|
+
Btn,
|
|
3351
|
+
{
|
|
3352
|
+
key: "confirm",
|
|
3353
|
+
small: true,
|
|
3354
|
+
variant: "danger",
|
|
3355
|
+
onClick: () => {
|
|
3356
|
+
setConfirming(false);
|
|
3357
|
+
void controller.apply();
|
|
3358
|
+
}
|
|
3359
|
+
},
|
|
3360
|
+
t("about.update.confirmYes")
|
|
3361
|
+
),
|
|
3362
|
+
h(Btn, { key: "cancel", small: true, onClick: () => setConfirming(false) }, t("about.update.cancel"))
|
|
3363
|
+
] : h(Btn, { key: "apply", small: true, variant: "primary", onClick: () => setConfirming(true) }, t("about.update.apply", { version: target })) : null
|
|
3364
|
+
].filter((item) => item !== null);
|
|
3365
|
+
const dialog = h(
|
|
3033
3366
|
"div",
|
|
3034
3367
|
{ className: "dshgt-modal-mask", onClick: (event) => {
|
|
3035
3368
|
if (event.target === event.currentTarget) props.onClose();
|
|
@@ -3059,9 +3392,29 @@ function AboutDialog(props) {
|
|
|
3059
3392
|
[t("about.core"), state.core.version === void 0 ? "—" : `trendradar ${state.core.version}`],
|
|
3060
3393
|
[t("about.env"), t("about.env.value")]
|
|
3061
3394
|
]
|
|
3062
|
-
})
|
|
3395
|
+
}),
|
|
3396
|
+
h(
|
|
3397
|
+
"div",
|
|
3398
|
+
{ className: "dshgt-update" },
|
|
3399
|
+
h(
|
|
3400
|
+
"div",
|
|
3401
|
+
{ className: "dshgt-update-head" },
|
|
3402
|
+
h("h4", null, t("about.update.title")),
|
|
3403
|
+
h("span", { className: "dshgt-hint" }, t("about.update.hint"))
|
|
3404
|
+
),
|
|
3405
|
+
h("p", { className: `dshgt-update-line${status === "failed" ? " dshgt-update-err" : ""}` }, statusLine()),
|
|
3406
|
+
confirming ? h("p", { className: "dshgt-update-warn" }, t("about.update.confirm", { version: target })) : null,
|
|
3407
|
+
h("div", { className: "dshgt-update-actions" }, updateActions),
|
|
3408
|
+
manual === null ? null : h(
|
|
3409
|
+
"div",
|
|
3410
|
+
{ className: "dshgt-update-manual" },
|
|
3411
|
+
h("p", { className: "dshgt-update-warn" }, t("about.update.manual", { kind: view?.installKind ?? "unknown" })),
|
|
3412
|
+
h("code", { className: "dshgt-update-cmd" }, manual)
|
|
3413
|
+
)
|
|
3414
|
+
)
|
|
3063
3415
|
)
|
|
3064
3416
|
);
|
|
3417
|
+
return h("div", { className: "dshgt-root" }, dialog);
|
|
3065
3418
|
}
|
|
3066
3419
|
|
|
3067
3420
|
// client/panel-icon.ts
|
|
@@ -3096,6 +3096,7 @@ __export(routes_exports, {
|
|
|
3096
3096
|
ROUTE_PREFIX: () => ROUTE_PREFIX,
|
|
3097
3097
|
createRoutes: () => createRoutes
|
|
3098
3098
|
});
|
|
3099
|
+
import { PluginUpdateError } from "@morehao/dsh-plugin-kit/update";
|
|
3099
3100
|
var ROUTE_PREFIX = "/api/morehao/github-trending";
|
|
3100
3101
|
var HEADER = "x-dsh-github-trending";
|
|
3101
3102
|
var MAX_BODY2 = 512 * 1024;
|
|
@@ -3143,6 +3144,17 @@ function createRoutes(deps) {
|
|
|
3143
3144
|
if (!response.writableEnded) sendJson2(response, 200, { ok: true, ...result });
|
|
3144
3145
|
} catch (error) {
|
|
3145
3146
|
if (response.writableEnded) return;
|
|
3147
|
+
if (error instanceof PluginUpdateError) {
|
|
3148
|
+
deps.logger?.("update.failed", { code: error.code, message: error.message });
|
|
3149
|
+
sendJson2(response, 409, {
|
|
3150
|
+
ok: false,
|
|
3151
|
+
code: "UPDATE_FAILED",
|
|
3152
|
+
updateCode: error.code,
|
|
3153
|
+
message: redact(error.message),
|
|
3154
|
+
update: deps.update?.view() ?? null
|
|
3155
|
+
});
|
|
3156
|
+
return;
|
|
3157
|
+
}
|
|
3146
3158
|
const code = error instanceof IpcError ? error.code : "INTERNAL";
|
|
3147
3159
|
const message = redact(error instanceof Error ? error.message : String(error));
|
|
3148
3160
|
deps.logger?.("route.error", { pathname, method, code, message });
|
|
@@ -3155,6 +3167,18 @@ async function dispatch(method, pathname, url, request, deps) {
|
|
|
3155
3167
|
const env = deps.env ?? process.env;
|
|
3156
3168
|
const settings = deps.store.readSettings();
|
|
3157
3169
|
if (method === "GET" && pathname === "/state") return statePayload(deps, settings);
|
|
3170
|
+
if (method === "GET" && pathname === "/update") {
|
|
3171
|
+
if (deps.update === void 0) throw new IpcError("NOT_FOUND", "\u81EA\u66F4\u65B0\u670D\u52A1\u4E0D\u53EF\u7528");
|
|
3172
|
+
const update = await deps.update.check({ fresh: url.searchParams.get("fresh") === "1" });
|
|
3173
|
+
return { update };
|
|
3174
|
+
}
|
|
3175
|
+
if (method === "POST" && pathname === "/update") {
|
|
3176
|
+
if (deps.update === void 0) throw new IpcError("NOT_FOUND", "\u81EA\u66F4\u65B0\u670D\u52A1\u4E0D\u53EF\u7528");
|
|
3177
|
+
const body = await readBody2(request);
|
|
3178
|
+
const version = typeof body.version === "string" && body.version.trim() !== "" ? body.version.trim() : void 0;
|
|
3179
|
+
const result = await deps.update.apply(version === void 0 ? {} : { version });
|
|
3180
|
+
return { result, update: deps.update.view() };
|
|
3181
|
+
}
|
|
3158
3182
|
if (method === "GET" && pathname === "/core") {
|
|
3159
3183
|
const core = await inspectCore(settings, { env, fresh: url.searchParams.get("fresh") === "1" });
|
|
3160
3184
|
const coexistence = await detectCoexistence(core.path, { env });
|
|
@@ -3347,6 +3371,57 @@ async function statePayload(deps, settings) {
|
|
|
3347
3371
|
};
|
|
3348
3372
|
}
|
|
3349
3373
|
|
|
3374
|
+
// src/host/update.ts
|
|
3375
|
+
var update_exports = {};
|
|
3376
|
+
__export(update_exports, {
|
|
3377
|
+
createUpdateService: () => createUpdateService
|
|
3378
|
+
});
|
|
3379
|
+
import { normalizeProfile } from "@morehao/dsh-plugin-kit";
|
|
3380
|
+
import { createPluginUpdater } from "@morehao/dsh-plugin-kit/update";
|
|
3381
|
+
function pnpmViewRunner(get, env, exec) {
|
|
3382
|
+
return async (spec) => {
|
|
3383
|
+
const profile = normalizeProfile(get("profileContext"));
|
|
3384
|
+
if (profile === null || profile.dir === void 0) return null;
|
|
3385
|
+
const command = profile.packageManager?.command ?? "pnpm";
|
|
3386
|
+
const prefix = profile.packageManager?.args ?? [];
|
|
3387
|
+
let result;
|
|
3388
|
+
try {
|
|
3389
|
+
result = await exec(command, [...prefix, "view", spec, "version", "--json"], {
|
|
3390
|
+
cwd: profile.dir,
|
|
3391
|
+
env: sanitizedEnv(env),
|
|
3392
|
+
timeoutMs: 8e3,
|
|
3393
|
+
maxStdout: 64 * 1024,
|
|
3394
|
+
maxStderr: 16 * 1024
|
|
3395
|
+
});
|
|
3396
|
+
} catch {
|
|
3397
|
+
return null;
|
|
3398
|
+
}
|
|
3399
|
+
if (result.code !== 0) return null;
|
|
3400
|
+
const text = result.stdout.trim();
|
|
3401
|
+
if (text === "") return null;
|
|
3402
|
+
let parsed;
|
|
3403
|
+
try {
|
|
3404
|
+
parsed = JSON.parse(text);
|
|
3405
|
+
} catch {
|
|
3406
|
+
return null;
|
|
3407
|
+
}
|
|
3408
|
+
const value = Array.isArray(parsed) ? parsed[parsed.length - 1] : parsed;
|
|
3409
|
+
return typeof value === "string" && value.trim() !== "" ? value.trim() : null;
|
|
3410
|
+
};
|
|
3411
|
+
}
|
|
3412
|
+
function createUpdateService(deps) {
|
|
3413
|
+
const exec = deps.exec ?? execCapture;
|
|
3414
|
+
return createPluginUpdater({
|
|
3415
|
+
meta: deps.meta,
|
|
3416
|
+
getPluginManager: () => deps.get("pluginManager"),
|
|
3417
|
+
getProfile: () => deps.get("profileContext"),
|
|
3418
|
+
runPnpmView: pnpmViewRunner(deps.get, deps.env, exec),
|
|
3419
|
+
...deps.fetchImpl === void 0 ? {} : { fetchImpl: deps.fetchImpl },
|
|
3420
|
+
...deps.readFile === void 0 ? {} : { readFile: deps.readFile },
|
|
3421
|
+
...deps.logger === void 0 ? {} : { logger: deps.logger }
|
|
3422
|
+
});
|
|
3423
|
+
}
|
|
3424
|
+
|
|
3350
3425
|
// src/tools.ts
|
|
3351
3426
|
var tools_exports = {};
|
|
3352
3427
|
__export(tools_exports, {
|
|
@@ -3540,6 +3615,8 @@ export {
|
|
|
3540
3615
|
ROUTE_PREFIX,
|
|
3541
3616
|
createRoutes,
|
|
3542
3617
|
routes_exports,
|
|
3618
|
+
createUpdateService,
|
|
3619
|
+
update_exports,
|
|
3543
3620
|
createTrendingRunTool,
|
|
3544
3621
|
createTrendingHistoryTool,
|
|
3545
3622
|
tools_exports
|
package/lib/index.js
CHANGED
|
@@ -6,8 +6,9 @@ import {
|
|
|
6
6
|
createRoutes,
|
|
7
7
|
createTrendingHistoryTool,
|
|
8
8
|
createTrendingRunTool,
|
|
9
|
+
createUpdateService,
|
|
9
10
|
readPluginInfo
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-NMINPPWO.js";
|
|
11
12
|
import "./chunk-XLIFTAVL.js";
|
|
12
13
|
|
|
13
14
|
// src/index.ts
|
|
@@ -59,7 +60,18 @@ function apply(ctx, config = {}) {
|
|
|
59
60
|
onError: (error) => ctx.logger?.warn?.(`[dsh-github-trending] \u5B9A\u65F6\u8FD0\u884C\u5931\u8D25\uFF1A${error instanceof Error ? error.message : String(error)}`)
|
|
60
61
|
});
|
|
61
62
|
const pluginInfo = readPluginInfo();
|
|
63
|
+
const update = createUpdateService({
|
|
64
|
+
get,
|
|
65
|
+
env,
|
|
66
|
+
meta: {
|
|
67
|
+
name: pluginInfo.name,
|
|
68
|
+
version: VERSION,
|
|
69
|
+
...pluginInfo.repository === void 0 ? {} : { repository: pluginInfo.repository }
|
|
70
|
+
},
|
|
71
|
+
logger: log
|
|
72
|
+
});
|
|
62
73
|
const handler = createRoutes({
|
|
74
|
+
update,
|
|
63
75
|
store,
|
|
64
76
|
runner,
|
|
65
77
|
scheduler,
|
package/lib/internal.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ErrorCode, FileArtifact, ErrorInfo, RunRequest, RunResult, State, StateRun } from '@morehao/trendradar-contract';
|
|
2
2
|
import http from 'node:http';
|
|
3
|
+
import { Updater, PluginMeta, Logger } from '@morehao/dsh-plugin-kit/update';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* 错误码:核心码(契约包 `ipc.v2` / `errors.v2` 的 17 个)+ 插件自己的码。
|
|
@@ -1377,6 +1378,8 @@ interface RouteDeps {
|
|
|
1377
1378
|
/** 注入用:pendingPr 对账的 fetch 实现(测试不联网)。 */
|
|
1378
1379
|
fetchImpl?: typeof fetch;
|
|
1379
1380
|
version: string;
|
|
1381
|
+
/** 自更新服务(共享包引擎);缺省时 /update 返回 404,不影响其它路由。 */
|
|
1382
|
+
update?: Updater;
|
|
1380
1383
|
/** 包名与仓库地址都来自 package.json,由 src/index.ts 传入。 */
|
|
1381
1384
|
pluginName?: string;
|
|
1382
1385
|
repository?: string;
|
|
@@ -1392,6 +1395,24 @@ declare namespace routes {
|
|
|
1392
1395
|
export { routes_HEADER as HEADER, routes_ROUTE_PREFIX as ROUTE_PREFIX, type routes_RouteDeps as RouteDeps, routes_createRoutes as createRoutes };
|
|
1393
1396
|
}
|
|
1394
1397
|
|
|
1398
|
+
interface UpdateServiceDeps {
|
|
1399
|
+
get: (name: string) => unknown;
|
|
1400
|
+
env: NodeJS.ProcessEnv;
|
|
1401
|
+
meta: PluginMeta;
|
|
1402
|
+
logger?: Logger;
|
|
1403
|
+
fetchImpl?: typeof fetch;
|
|
1404
|
+
/** 测试注入;默认走本仓的 execCapture。 */
|
|
1405
|
+
exec?: (file: string, args: string[], options?: ExecOptions) => Promise<ExecResult>;
|
|
1406
|
+
readFile?: (path: string) => Promise<string>;
|
|
1407
|
+
}
|
|
1408
|
+
declare function createUpdateService(deps: UpdateServiceDeps): Updater;
|
|
1409
|
+
|
|
1410
|
+
type update_UpdateServiceDeps = UpdateServiceDeps;
|
|
1411
|
+
declare const update_createUpdateService: typeof createUpdateService;
|
|
1412
|
+
declare namespace update {
|
|
1413
|
+
export { type update_UpdateServiceDeps as UpdateServiceDeps, update_createUpdateService as createUpdateService };
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1395
1416
|
interface ImportCandidate {
|
|
1396
1417
|
path: string;
|
|
1397
1418
|
exists: boolean;
|
|
@@ -1633,4 +1654,4 @@ declare namespace tools {
|
|
|
1633
1654
|
export { tools_createTrendingHistoryTool as createTrendingHistoryTool, tools_createTrendingRunTool as createTrendingRunTool };
|
|
1634
1655
|
}
|
|
1635
1656
|
|
|
1636
|
-
export { channel, config, core, credentials, errors, exec, github, handshake$1 as handshake, importCli, ipc, locate, paths, pendingPr, pluginInfo, preflight, proxy, quickfill, release, repo, routes, run, runner, schedule, state, tools };
|
|
1657
|
+
export { channel, config, core, credentials, errors, exec, github, handshake$1 as handshake, importCli, ipc, locate, paths, pendingPr, pluginInfo, preflight, proxy, quickfill, release, repo, routes, run, runner, schedule, state, tools, update as updateService };
|
package/lib/internal.js
CHANGED
|
@@ -22,8 +22,9 @@ import {
|
|
|
22
22
|
runner_exports,
|
|
23
23
|
schedule_exports,
|
|
24
24
|
state_exports,
|
|
25
|
-
tools_exports
|
|
26
|
-
|
|
25
|
+
tools_exports,
|
|
26
|
+
update_exports
|
|
27
|
+
} from "./chunk-NMINPPWO.js";
|
|
27
28
|
import {
|
|
28
29
|
exec_exports
|
|
29
30
|
} from "./chunk-XLIFTAVL.js";
|
|
@@ -52,5 +53,6 @@ export {
|
|
|
52
53
|
runner_exports as runner,
|
|
53
54
|
schedule_exports as schedule,
|
|
54
55
|
state_exports as state,
|
|
55
|
-
tools_exports as tools
|
|
56
|
+
tools_exports as tools,
|
|
57
|
+
update_exports as updateService
|
|
56
58
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morehao/dsh-github-trending",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "GitHub 趋势日报插件:每天定时 spawn 本地 trendradar 核心,抓取 Trending、生成中文简介与总结,提交到你的仓库并自动合并 PR。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
}
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
+
"@morehao/dsh-plugin-kit": "0.1.0",
|
|
53
54
|
"@morehao/trendradar-contract": "0.2.0"
|
|
54
55
|
},
|
|
55
56
|
"dsh": {
|