@morehao/dsh-github-trending 0.7.10 → 0.8.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/CHANGELOG.md +12 -0
- package/README.en.md +92 -0
- package/README.md +4 -0
- package/client.js +157 -21
- package/lib/{chunk-YJ5GF3MW.js → chunk-6PVBPJXO.js} +445 -13
- package/lib/index.d.ts +1 -0
- package/lib/index.js +9 -2
- package/lib/internal.d.ts +159 -8
- package/lib/internal.js +3 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [v0.7.11] - 2026-11-01
|
|
4
|
+
|
|
5
|
+
### Refactors
|
|
6
|
+
|
|
7
|
+
- **settings**: merge schedule into scope card and link subscription repos (#65)
|
|
8
|
+
|
|
9
|
+
### Docs
|
|
10
|
+
|
|
11
|
+
- 新增英文版 README.en.md,中文 README 默认并加语言切换 (#64)
|
|
12
|
+
|
|
13
|
+
**Full Changelog**: https://github.com/morehao/dsh-github-trending/compare/v0.7.10...v0.7.11
|
|
14
|
+
|
|
3
15
|
## [v0.7.10] - 2026-11-01
|
|
4
16
|
|
|
5
17
|
> 修复 peer / engine 版本区间漏掉 `0.2.2-*` 预发布的问题,让插件在宿主升到 `0.2.2` 线后仍能正常安装。
|
package/README.en.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="icon.svg" alt="dsh-github-trending logo" width="88" height="88">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">dsh-github-trending</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
A DeepSeek Harness plugin for the GitHub Trending board
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="README.md">简体中文</a> | English
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
<p align="center">
|
|
16
|
+
<a href="https://github.com/morehao/dsh-github-trending/actions/workflows/check.yml"><img alt="check" src="https://github.com/morehao/dsh-github-trending/actions/workflows/check.yml/badge.svg"></a>
|
|
17
|
+
<a href="https://www.npmjs.com/package/@morehao/dsh-github-trending"><img alt="npm version" src="https://img.shields.io/npm/v/@morehao/dsh-github-trending.svg"></a>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
A **DeepSeek Harness plugin** for the GitHub Trending board: it schedules daily / weekly / monthly digests, hands them to the local [`trendradar`](https://github.com/morehao/trendradar) core to scrape Trending, write Chinese intros and period summaries, and commits the result to your own repository with a PR merged automatically. You follow status, read digests and manage subscriptions from the workbench — no command line needed.
|
|
21
|
+
|
|
22
|
+
## Positioning
|
|
23
|
+
|
|
24
|
+
- **An entry point, not an engine**. Scraping, parsing, model summarization, rendering, git and PR all live in one place — the local `trendradar` core. The plugin only handles **configuration, scheduling, spawning the core and displaying results**, so there is no second implementation to drift.
|
|
25
|
+
- **Deliver the artifact as-is**. Content is written byte-for-byte exactly as the core produces it; the plugin does not rewrite, reorder or re-invoke a model on it.
|
|
26
|
+
- **Local execution, no telemetry**. The core runs on your machine; the plugin has no cloud account, and secrets are handed to the core only over a runtime channel — never written to config files or logs.
|
|
27
|
+
|
|
28
|
+
> For deeper material — requirements, config fields, error codes, subscription stages and implementation details — see **[docs/reference.md](docs/reference.md)**.
|
|
29
|
+
|
|
30
|
+
## Features
|
|
31
|
+
|
|
32
|
+
Open the workbench from the sidebar **GitHub Trending** or `Settings → GitHub Trending`. It has five views:
|
|
33
|
+
|
|
34
|
+
### Overview
|
|
35
|
+
|
|
36
|
+
Answers "when will it run next, are the four readiness checks all green, what was delivered last time" at a glance. The top shows the plugin identity bar (version / package name / check for updates); the right side keeps the next run and readiness N/4 always visible.
|
|
37
|
+
|
|
38
|
+

|
|
39
|
+
|
|
40
|
+
### Digest
|
|
41
|
+
|
|
42
|
+
Browse past digests by period (daily / weekly / monthly). Markdown is rendered directly (headings, lists, tables, links), and you can switch to **Raw**. Only issues whose preview copy was kept can be read; failed / unchanged / dry-run / old records each have their own empty state.
|
|
43
|
+
|
|
44
|
+

|
|
45
|
+
|
|
46
|
+
### Runs
|
|
47
|
+
|
|
48
|
+
The last 30 runs, filterable by success / failure / dry-run. Expand a run to see its deliverables (commit, content hash, branch, PR link) and a read-only log; the footer shows cumulative tokens.
|
|
49
|
+
|
|
50
|
+

|
|
51
|
+
|
|
52
|
+
### Settings
|
|
53
|
+
|
|
54
|
+
Six sections — Content source / Model / Repository / Auth / Digest / Schedule — each saved and validated independently; an unsaved section shows a yellow dot next to its item on the left.
|
|
55
|
+
|
|
56
|
+

|
|
57
|
+
|
|
58
|
+
### Subscriptions
|
|
59
|
+
|
|
60
|
+
(Optional) Subscribe to a set of repositories; each week the new Releases from each of them are merged into one Chinese summary and committed alongside the digest on the same branch and PR. The subscription list is versioned with the data repo, auditable and reproducible.
|
|
61
|
+
|
|
62
|
+

|
|
63
|
+
|
|
64
|
+
## Installation
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
dsh plugin --profile <profile> add @morehao/dsh-github-trending
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Restart the host after installing, then open **GitHub Trending** from the sidebar or `Settings → GitHub Trending`.
|
|
71
|
+
|
|
72
|
+
### Quick start in three steps
|
|
73
|
+
|
|
74
|
+
1. **Pick a repository**: enter the absolute path of a local git repository (the plugin does not run `git init` for you; a non-repo path returns `REPO_NOT_GIT`).
|
|
75
|
+
2. **Pick a model**: click "Use DSH config" to choose a provider and model from the host's provider directory; providers that can export a key pass it straight to the core, while OAuth-type credentials go through a local loopback proxy.
|
|
76
|
+
3. **Dry-run once**: "Dry run (no commit)" only scrapes and renders — it writes no files and makes no commit.
|
|
77
|
+
|
|
78
|
+
Requirements: DSH `0.2.1-rc.3` or later, Node.js `^22.20.0 || >=24.0.0`, a local git ≥ 2.30 with a writable remote, and git / GitHub credentials (needed only for push and opening PRs). On first run the core binary is downloaded from GitHub Releases and verified by sha256, then reused offline.
|
|
79
|
+
|
|
80
|
+
## Development and release
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm install
|
|
84
|
+
npm run check # typecheck + contract check + build + all tests
|
|
85
|
+
node scripts/ac/run.mjs # AC-P mechanical checks
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Releases go through **tag-triggered CI** (Trusted Publishing / OIDC): merge the PR → push an annotated tag `vX.Y.Z` on `main` → CI publishes to npm and creates the Release from the annotation body. See [docs/publishing.md](docs/publishing.md) for details.
|
|
89
|
+
|
|
90
|
+
## License
|
|
91
|
+
|
|
92
|
+
MIT
|
package/README.md
CHANGED
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
GitHub 趋势榜的 DeepSeek Harness 插件
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
|
+
<p align="center">
|
|
12
|
+
简体中文 | <a href="README.en.md">English</a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
11
15
|
<p align="center">
|
|
12
16
|
<a href="https://github.com/morehao/dsh-github-trending/actions/workflows/check.yml"><img alt="check" src="https://github.com/morehao/dsh-github-trending/actions/workflows/check.yml/badge.svg"></a>
|
|
13
17
|
<a href="https://www.npmjs.com/package/@morehao/dsh-github-trending"><img alt="npm version" src="https://img.shields.io/npm/v/@morehao/dsh-github-trending.svg"></a>
|
package/client.js
CHANGED
|
@@ -54,7 +54,7 @@ var DICT = {
|
|
|
54
54
|
"st.model": "模型",
|
|
55
55
|
"st.repo": "仓库",
|
|
56
56
|
"st.auth": "认证",
|
|
57
|
-
"st.scope": "
|
|
57
|
+
"st.scope": "榜单与调度",
|
|
58
58
|
"st.summarize": "摘要与用量",
|
|
59
59
|
"st.releases": "订阅",
|
|
60
60
|
"st.schedule": "调度",
|
|
@@ -123,7 +123,19 @@ var DICT = {
|
|
|
123
123
|
"auth.mode": "方式",
|
|
124
124
|
"auth.pat": "PAT",
|
|
125
125
|
"auth.gh": "本机 gh",
|
|
126
|
+
"auth.browser": "浏览器登录",
|
|
126
127
|
"auth.gh.hint": "使用本机 gh 登录态:终端执行 `gh auth login` 完成登录,再点「测试认证」。",
|
|
128
|
+
"auth.browser.hint": "在浏览器里完成 GitHub 授权,token 由 DSH 安全保存,无需手工粘贴。",
|
|
129
|
+
"auth.browser.signin": "用 GitHub 登录",
|
|
130
|
+
"auth.browser.waiting": "等待浏览器授权…",
|
|
131
|
+
"auth.browser.code": "在打开的页面输入验证码:",
|
|
132
|
+
"auth.browser.cancel": "取消",
|
|
133
|
+
"auth.browser.done": "已登录",
|
|
134
|
+
"auth.browser.device": "用设备码登录",
|
|
135
|
+
"auth.browser.unavailable": "当前环境未配置 GitHub OAuth client_id,浏览器登录不可用:请改用「本机 gh」或 PAT。",
|
|
136
|
+
"auth.browser.openHint": "若浏览器未自动打开,请手动打开发起授权,或复制链接:",
|
|
137
|
+
"auth.browser.copy": "复制链接",
|
|
138
|
+
"auth.browser.copied": "授权链接已复制",
|
|
127
139
|
"auth.pat.hint": "在 GitHub → Settings → Developer settings 生成 Personal Access Token(勾选 public_repo),填到下方引用或环境变量。",
|
|
128
140
|
"auth.tokenRef": "凭据引用",
|
|
129
141
|
"auth.tokenRef.hint": "凭据引用名 / 环境变量名",
|
|
@@ -583,7 +595,7 @@ var DICT = {
|
|
|
583
595
|
"st.model": "Model",
|
|
584
596
|
"st.repo": "Repository",
|
|
585
597
|
"st.auth": "Auth",
|
|
586
|
-
"st.scope": "Scope",
|
|
598
|
+
"st.scope": "Scope & Schedule",
|
|
587
599
|
"st.summarize": "Summary & usage",
|
|
588
600
|
"st.releases": "Subscriptions",
|
|
589
601
|
"st.schedule": "Schedule",
|
|
@@ -652,7 +664,19 @@ var DICT = {
|
|
|
652
664
|
"auth.mode": "Mode",
|
|
653
665
|
"auth.pat": "PAT",
|
|
654
666
|
"auth.gh": "Local gh",
|
|
667
|
+
"auth.browser": "Browser login",
|
|
655
668
|
"auth.gh.hint": "Uses your local gh login: run `gh auth login` in a terminal, then click Test authentication.",
|
|
669
|
+
"auth.browser.hint": "Authorize GitHub in your browser; DSH stores the token securely, no manual paste.",
|
|
670
|
+
"auth.browser.signin": "Sign in with GitHub",
|
|
671
|
+
"auth.browser.waiting": "Waiting for browser authorization…",
|
|
672
|
+
"auth.browser.code": "Enter this code on the opened page:",
|
|
673
|
+
"auth.browser.cancel": "Cancel",
|
|
674
|
+
"auth.browser.done": "Signed in",
|
|
675
|
+
"auth.browser.device": "Use a device code",
|
|
676
|
+
"auth.browser.unavailable": "No GitHub OAuth client_id configured in this environment, so browser sign-in is unavailable: use Local gh or PAT instead.",
|
|
677
|
+
"auth.browser.openHint": "If the browser did not open, open the authorization page manually, or copy the link:",
|
|
678
|
+
"auth.browser.copy": "Copy link",
|
|
679
|
+
"auth.browser.copied": "Authorization link copied",
|
|
656
680
|
"auth.pat.hint": "Create a Personal Access Token under GitHub → Settings → Developer settings (scope public_repo) and put it in the ref below or an env var.",
|
|
657
681
|
"auth.tokenRef": "Credential ref",
|
|
658
682
|
"auth.tokenRef.hint": "credential ref / env var name",
|
|
@@ -1147,6 +1171,7 @@ var CSS = `
|
|
|
1147
1171
|
.dshgt-card-h h3{margin:0;font-size:13px;font-weight:600;white-space:nowrap;}
|
|
1148
1172
|
.dshgt-hint{color:var(--gt-muted);font-size:12px;}
|
|
1149
1173
|
.dshgt-desc{margin:0;color:var(--gt-muted);font-size:12px;}
|
|
1174
|
+
.dshgt-subhead{margin:4px 0 0;padding-top:8px;border-top:1px solid var(--gt-border);font-size:12px;font-weight:600;color:var(--gt-muted);}
|
|
1150
1175
|
.dshgt-row{display:flex;gap:10px;align-items:center;min-height:28px;flex-wrap:wrap;}
|
|
1151
1176
|
.dshgt-row>label.dshgt-label{width:96px;color:var(--gt-muted);flex:none;font-size:12px;display:flex;align-items:flex-start;gap:5px;}
|
|
1152
1177
|
.dshgt-label-text{flex:1;min-width:0;}
|
|
@@ -1521,6 +1546,8 @@ var CSS = `
|
|
|
1521
1546
|
.dshgt-subs-cb{width:14px;height:14px;margin:0;accent-color:var(--gt-accent);justify-self:center;}
|
|
1522
1547
|
.dshgt-subs-ident{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12.5px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
|
1523
1548
|
.dshgt-subs-ident mark{background:color-mix(in srgb,var(--gt-accent) 18%,transparent);color:inherit;border-radius:3px;padding:0 1px;}
|
|
1549
|
+
.dshgt-subs-ident-link{color:inherit;text-decoration:none;min-width:0;overflow:hidden;text-overflow:ellipsis;}
|
|
1550
|
+
.dshgt-subs-ident-link:hover{color:var(--gt-accent);text-decoration:underline;text-underline-offset:2px;}
|
|
1524
1551
|
.dshgt-subs-ver{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;color:var(--gt-fg);text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;}
|
|
1525
1552
|
.dshgt-subs-sum{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11.5px;color:var(--gt-muted);text-align:right;white-space:nowrap;}
|
|
1526
1553
|
.dshgt-subs-stat{display:flex;align-items:center;gap:6px;padding-left:4px;font-size:12px;color:var(--gt-muted);white-space:nowrap;}
|
|
@@ -1848,6 +1875,23 @@ async function apiCall(method, path, body, options = {}) {
|
|
|
1848
1875
|
}
|
|
1849
1876
|
return json;
|
|
1850
1877
|
}
|
|
1878
|
+
async function beginGithubSignIn(method = "browser") {
|
|
1879
|
+
const payload = await apiCall("POST", "/github/browser/begin", { method });
|
|
1880
|
+
return payload.attempt;
|
|
1881
|
+
}
|
|
1882
|
+
async function getGithubSignInStatus(signal) {
|
|
1883
|
+
const payload = await apiCall(
|
|
1884
|
+
"GET",
|
|
1885
|
+
"/github/browser/status",
|
|
1886
|
+
void 0,
|
|
1887
|
+
signal === void 0 ? {} : { signal }
|
|
1888
|
+
);
|
|
1889
|
+
return payload.attempt;
|
|
1890
|
+
}
|
|
1891
|
+
async function cancelGithubSignIn() {
|
|
1892
|
+
const payload = await apiCall("POST", "/github/browser/cancel", {});
|
|
1893
|
+
return payload.attempt;
|
|
1894
|
+
}
|
|
1851
1895
|
function releaseRunsOf(state) {
|
|
1852
1896
|
if (state === null || state === void 0) return [];
|
|
1853
1897
|
const root = Array.isArray(state.releaseRuns) ? state.releaseRuns : void 0;
|
|
@@ -2024,8 +2068,8 @@ function credentialView(model, t) {
|
|
|
2024
2068
|
|
|
2025
2069
|
// client/settings.ts
|
|
2026
2070
|
var LANGUAGES = ["all", "typescript", "python", "go", "rust", "java", "c", "cpp", "javascript", "csharp"];
|
|
2027
|
-
var SECTIONS = ["source", "model", "repo", "auth", "scope", "summarize", "releases"
|
|
2028
|
-
var EMPTY_DIRTY = { source: false, model: false, repo: false, auth: false, scope: false, summarize: false, releases: false
|
|
2071
|
+
var SECTIONS = ["source", "model", "repo", "auth", "scope", "summarize", "releases"];
|
|
2072
|
+
var EMPTY_DIRTY = { source: false, model: false, repo: false, auth: false, scope: false, summarize: false, releases: false };
|
|
2029
2073
|
function cloneSettings(settings) {
|
|
2030
2074
|
return JSON.parse(JSON.stringify(settings));
|
|
2031
2075
|
}
|
|
@@ -2040,13 +2084,11 @@ function sectionSlice(settings, section) {
|
|
|
2040
2084
|
case "auth":
|
|
2041
2085
|
return { github: settings.github };
|
|
2042
2086
|
case "scope":
|
|
2043
|
-
return { trending: settings.trending };
|
|
2087
|
+
return { trending: settings.trending, schedule: settings.schedule };
|
|
2044
2088
|
case "summarize":
|
|
2045
2089
|
return { summarize: settings.summarize };
|
|
2046
2090
|
case "releases":
|
|
2047
2091
|
return { releases: settings.releases };
|
|
2048
|
-
case "schedule":
|
|
2049
|
-
return { schedule: settings.schedule };
|
|
2050
2092
|
}
|
|
2051
2093
|
}
|
|
2052
2094
|
var NOTICE_TTL_MS = 5e3;
|
|
@@ -2077,6 +2119,7 @@ function SettingsView(props) {
|
|
|
2077
2119
|
const [branchLoading, setBranchLoading] = import_react.default.useState(false);
|
|
2078
2120
|
const [testing, setTesting] = import_react.default.useState(false);
|
|
2079
2121
|
const [githubTest, setGithubTest] = import_react.default.useState(null);
|
|
2122
|
+
const [signIn, setSignIn] = import_react.default.useState({ phase: "idle" });
|
|
2080
2123
|
const anyDirty = SECTIONS.some((id) => dirtySections[id]);
|
|
2081
2124
|
const sectionEditable = section !== "source";
|
|
2082
2125
|
import_react.default.useEffect(() => {
|
|
@@ -2204,6 +2247,52 @@ function SettingsView(props) {
|
|
|
2204
2247
|
setTesting(false);
|
|
2205
2248
|
}
|
|
2206
2249
|
};
|
|
2250
|
+
const startSignIn = async (method) => {
|
|
2251
|
+
try {
|
|
2252
|
+
const view = await beginGithubSignIn(method);
|
|
2253
|
+
setSignIn(view);
|
|
2254
|
+
if (view.phase === "waiting-browser" && view.authorizeUrl !== void 0) {
|
|
2255
|
+
try {
|
|
2256
|
+
window.open(view.authorizeUrl, "_blank", "noopener,noreferrer");
|
|
2257
|
+
} catch {
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
} catch (error) {
|
|
2261
|
+
notify("err", error instanceof Error ? error.message : String(error));
|
|
2262
|
+
}
|
|
2263
|
+
};
|
|
2264
|
+
const cancelSignIn = async () => {
|
|
2265
|
+
try {
|
|
2266
|
+
setSignIn(await cancelGithubSignIn());
|
|
2267
|
+
} catch (error) {
|
|
2268
|
+
notify("err", error instanceof Error ? error.message : String(error));
|
|
2269
|
+
}
|
|
2270
|
+
};
|
|
2271
|
+
const copyAuthorizeLink = () => {
|
|
2272
|
+
if (signIn.authorizeUrl === void 0) return;
|
|
2273
|
+
void navigator.clipboard?.writeText(signIn.authorizeUrl).then(() => notify("ok", t("auth.browser.copied")));
|
|
2274
|
+
};
|
|
2275
|
+
const signInActive = signIn.phase === "waiting-browser" || signIn.phase === "waiting-device" || signIn.phase === "exchanging";
|
|
2276
|
+
import_react.default.useEffect(() => {
|
|
2277
|
+
if (!signInActive) return void 0;
|
|
2278
|
+
let alive = true;
|
|
2279
|
+
const timer = setInterval(() => {
|
|
2280
|
+
void getGithubSignInStatus().then((view) => {
|
|
2281
|
+
if (!alive) return;
|
|
2282
|
+
setSignIn(view);
|
|
2283
|
+
if (view.phase === "done") {
|
|
2284
|
+
setGithubTest(view.login === void 0 ? { ok: true } : { ok: true, login: view.login });
|
|
2285
|
+
notify("ok", t("auth.browser.done"));
|
|
2286
|
+
void store.refresh({ quiet: true });
|
|
2287
|
+
}
|
|
2288
|
+
}).catch(() => {
|
|
2289
|
+
});
|
|
2290
|
+
}, 1500);
|
|
2291
|
+
return () => {
|
|
2292
|
+
alive = false;
|
|
2293
|
+
clearInterval(timer);
|
|
2294
|
+
};
|
|
2295
|
+
}, [signInActive]);
|
|
2207
2296
|
const importCli = async () => {
|
|
2208
2297
|
try {
|
|
2209
2298
|
const result = await apiCall(
|
|
@@ -2242,6 +2331,8 @@ function SettingsView(props) {
|
|
|
2242
2331
|
const branchText = branchLoading ? t("branch.loading") : branchInfo?.branch !== void 0 ? branchInfo.branch : draft.repo.baseBranch !== "" ? draft.repo.baseBranch : "—";
|
|
2243
2332
|
const branchHint = branchInfo?.source === "origin-head" ? t("branch.fromOrigin") : branchInfo?.source === "head" ? t("branch.fromHead") : branchInfo?.message !== void 0 ? branchInfo.message : t("branch.readonlyHint");
|
|
2244
2333
|
const isGh = draft.github.authMode === "gh";
|
|
2334
|
+
const isBrowser = draft.github.authMode === "browser";
|
|
2335
|
+
const browserAvailable = state.github.browserAvailable === true;
|
|
2245
2336
|
const sections = [
|
|
2246
2337
|
{ id: "source", label: t("st.source") },
|
|
2247
2338
|
{ id: "model", label: t("st.model") },
|
|
@@ -2249,8 +2340,7 @@ function SettingsView(props) {
|
|
|
2249
2340
|
{ id: "auth", label: t("st.auth") },
|
|
2250
2341
|
{ id: "scope", label: t("st.scope") },
|
|
2251
2342
|
{ id: "summarize", label: t("st.summarize") },
|
|
2252
|
-
{ id: "releases", label: t("st.releases") }
|
|
2253
|
-
{ id: "schedule", label: t("st.schedule") }
|
|
2343
|
+
{ id: "releases", label: t("st.releases") }
|
|
2254
2344
|
];
|
|
2255
2345
|
const sourceCard = h(
|
|
2256
2346
|
Card,
|
|
@@ -2419,16 +2509,32 @@ function SettingsView(props) {
|
|
|
2419
2509
|
value: draft.github.authMode,
|
|
2420
2510
|
options: [
|
|
2421
2511
|
{ value: "gh", label: t("auth.gh") },
|
|
2422
|
-
{ value: "pat", label: t("auth.pat") }
|
|
2512
|
+
{ value: "pat", label: t("auth.pat") },
|
|
2513
|
+
{ value: "browser", label: t("auth.browser") }
|
|
2423
2514
|
],
|
|
2424
2515
|
onChange: (value) => update((next) => {
|
|
2425
|
-
next.github.authMode = value === "pat" ? "pat" : "gh";
|
|
2516
|
+
next.github.authMode = value === "pat" ? "pat" : value === "browser" ? "browser" : "gh";
|
|
2426
2517
|
})
|
|
2427
2518
|
}),
|
|
2428
2519
|
h(Pill, { kind: state.github.configured ? "ok" : "warn" }, state.github.configured ? `${t("auth.configured")} · ${state.github.source}` : t("auth.missing"))
|
|
2429
2520
|
),
|
|
2430
|
-
h("p", { className: "dshgt-hint" }, isGh ? t("auth.gh.hint") : t("auth.pat.hint")),
|
|
2431
|
-
isGh ? null : h(
|
|
2521
|
+
h("p", { className: "dshgt-hint" }, isGh ? t("auth.gh.hint") : isBrowser ? t("auth.browser.hint") : t("auth.pat.hint")),
|
|
2522
|
+
isGh ? null : isBrowser ? h(
|
|
2523
|
+
Row,
|
|
2524
|
+
{ label: t("auth.status") },
|
|
2525
|
+
browserAvailable ? h(
|
|
2526
|
+
Btn,
|
|
2527
|
+
{
|
|
2528
|
+
small: true,
|
|
2529
|
+
variant: "primary",
|
|
2530
|
+
onClick: () => void startSignIn("browser"),
|
|
2531
|
+
disabled: signInActive
|
|
2532
|
+
},
|
|
2533
|
+
signIn.phase === "done" && signIn.login !== void 0 ? `${t("auth.browser.done")} · @${signIn.login}` : signInActive ? t("auth.browser.waiting") : t("auth.browser.signin")
|
|
2534
|
+
) : h("span", { className: "dshgt-hint" }, t("auth.browser.unavailable")),
|
|
2535
|
+
browserAvailable ? h(Btn, { small: true, variant: "ghost", onClick: () => void startSignIn("device"), disabled: signInActive }, t("auth.browser.device")) : null,
|
|
2536
|
+
signInActive ? h(Btn, { small: true, variant: "ghost", onClick: () => void cancelSignIn() }, t("auth.browser.cancel")) : null
|
|
2537
|
+
) : h(
|
|
2432
2538
|
Row,
|
|
2433
2539
|
{ label: t("auth.tokenRef") },
|
|
2434
2540
|
h(Input, { mono: true, width: 220, value: draft.github.tokenRef, placeholder: "GITHUB_TOKEN", onInput: (value) => update((next) => {
|
|
@@ -2436,6 +2542,19 @@ function SettingsView(props) {
|
|
|
2436
2542
|
}) }),
|
|
2437
2543
|
h("span", { className: "dshgt-hint" }, t("auth.tokenRef.hint"))
|
|
2438
2544
|
),
|
|
2545
|
+
// 浏览器登录进行中的状态行:授权页链接(可复制)+ 设备码。
|
|
2546
|
+
isBrowser && signIn.phase !== "idle" && signIn.phase !== "done" ? h(
|
|
2547
|
+
"div",
|
|
2548
|
+
{ className: "dshgt-hint" },
|
|
2549
|
+
signIn.authorizeUrl !== void 0 ? h(
|
|
2550
|
+
"div",
|
|
2551
|
+
{ className: "dshgt-desc" },
|
|
2552
|
+
h("span", null, t("auth.browser.openHint")),
|
|
2553
|
+
" ",
|
|
2554
|
+
h(Btn, { small: true, variant: "ghost", onClick: () => copyAuthorizeLink() }, t("auth.browser.copy"))
|
|
2555
|
+
) : null,
|
|
2556
|
+
signIn.userCode !== void 0 ? h("div", { className: "dshgt-mono" }, `${t("auth.browser.code")} ${signIn.userCode}`) : null
|
|
2557
|
+
) : null,
|
|
2439
2558
|
h(
|
|
2440
2559
|
Row,
|
|
2441
2560
|
{ label: t("auth.test") },
|
|
@@ -2449,7 +2568,10 @@ function SettingsView(props) {
|
|
|
2449
2568
|
);
|
|
2450
2569
|
const scopeCard = h(
|
|
2451
2570
|
Card,
|
|
2452
|
-
{
|
|
2571
|
+
{
|
|
2572
|
+
title: t("card.scope.title"),
|
|
2573
|
+
hint: state.schedule.nextRunAt === void 0 ? void 0 : `${t("schedule.next")} ${localTime(state.schedule.nextRunAt)}`
|
|
2574
|
+
},
|
|
2453
2575
|
h(
|
|
2454
2576
|
Row,
|
|
2455
2577
|
{ label: t("scope.period") },
|
|
@@ -2483,11 +2605,8 @@ function SettingsView(props) {
|
|
|
2483
2605
|
draftNext.trending.languages = next;
|
|
2484
2606
|
})
|
|
2485
2607
|
})
|
|
2486
|
-
)
|
|
2487
|
-
|
|
2488
|
-
const scheduleCard = h(
|
|
2489
|
-
Card,
|
|
2490
|
-
{ title: t("card.schedule.title"), hint: state.schedule.nextRunAt === void 0 ? void 0 : `${t("schedule.next")} ${localTime(state.schedule.nextRunAt)}` },
|
|
2608
|
+
),
|
|
2609
|
+
h("h4", { className: "dshgt-subhead" }, t("card.schedule.title")),
|
|
2491
2610
|
h(
|
|
2492
2611
|
Row,
|
|
2493
2612
|
{ label: t("schedule.enabled") },
|
|
@@ -2657,7 +2776,7 @@ function SettingsView(props) {
|
|
|
2657
2776
|
})
|
|
2658
2777
|
)
|
|
2659
2778
|
);
|
|
2660
|
-
const currentCard = section === "source" ? sourceCard : section === "model" ? modelCard : section === "repo" ? repoCard : section === "auth" ? authCard : section === "scope" ? scopeCard : section === "summarize" ? summarizeCard :
|
|
2779
|
+
const currentCard = section === "source" ? sourceCard : section === "model" ? modelCard : section === "repo" ? repoCard : section === "auth" ? authCard : section === "scope" ? scopeCard : section === "summarize" ? summarizeCard : releasesCard;
|
|
2661
2780
|
return h(
|
|
2662
2781
|
"div",
|
|
2663
2782
|
{ className: "dshgt-settings" },
|
|
@@ -4574,6 +4693,9 @@ function highlight(text, needle) {
|
|
|
4574
4693
|
if (index < text.length) parts.push(text.slice(index));
|
|
4575
4694
|
return parts;
|
|
4576
4695
|
}
|
|
4696
|
+
function repoUrl(name) {
|
|
4697
|
+
return /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(name) ? `https://github.com/${name}` : void 0;
|
|
4698
|
+
}
|
|
4577
4699
|
function isMissingDoc(code, message) {
|
|
4578
4700
|
if (code !== void 0 && /NOT_?FOUND|MISSING|NO_?DOC/i.test(code)) return true;
|
|
4579
4701
|
return /not\s*found|no such file|enoent|404|不存在|no release document|has no release|无发版记录/i.test(message);
|
|
@@ -4885,7 +5007,21 @@ function SubscriptionsView(props) {
|
|
|
4885
5007
|
}
|
|
4886
5008
|
},
|
|
4887
5009
|
checkbox,
|
|
4888
|
-
h(
|
|
5010
|
+
h(
|
|
5011
|
+
"span",
|
|
5012
|
+
{ key: "name", role: "cell", className: "dshgt-subs-ident", title: row.name },
|
|
5013
|
+
repoUrl(row.name) === void 0 ? highlight(row.name, needle) : h(
|
|
5014
|
+
"a",
|
|
5015
|
+
{
|
|
5016
|
+
className: "dshgt-subs-ident-link",
|
|
5017
|
+
href: repoUrl(row.name),
|
|
5018
|
+
target: "_blank",
|
|
5019
|
+
rel: "noreferrer",
|
|
5020
|
+
onClick: (event) => event.stopPropagation()
|
|
5021
|
+
},
|
|
5022
|
+
highlight(row.name, needle)
|
|
5023
|
+
)
|
|
5024
|
+
),
|
|
4889
5025
|
h("span", { key: "tag", role: "cell", className: "dshgt-subs-ver", title: item?.latestTag ?? "" }, item?.latestTag ?? "—"),
|
|
4890
5026
|
h(
|
|
4891
5027
|
"span",
|