@morehao/dsh-github-trending 0.1.2 → 0.2.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 +35 -0
- package/README.md +17 -9
- package/client.js +616 -412
- package/contract/CONTRACT.sha256 +2 -2
- package/contract/UPSTREAM.json +5 -5
- package/contract/schema/ipc.v1.json +1 -0
- package/lib/{chunk-RXYA5WFW.js → chunk-HIJIQJCZ.js} +543 -202
- package/lib/index.js +1 -1
- package/lib/internal.d.ts +152 -10
- package/lib/internal.js +7 -1
- package/package.json +15 -10
package/client.js
CHANGED
|
@@ -50,6 +50,12 @@ var DICT = {
|
|
|
50
50
|
"section.subtitle": "每天定时把 GitHub Trending 抓取、总结并提交到你的仓库;内容全部由本地核心产出。",
|
|
51
51
|
"tab.settings": "设置",
|
|
52
52
|
"tab.runs": "运行",
|
|
53
|
+
"st.source": "内容来源",
|
|
54
|
+
"st.model": "模型",
|
|
55
|
+
"st.repo": "仓库",
|
|
56
|
+
"st.auth": "认证",
|
|
57
|
+
"st.scope": "榜单",
|
|
58
|
+
"st.schedule": "调度",
|
|
53
59
|
"card.source.title": "内容来源",
|
|
54
60
|
"card.source.hint": "唯一来源是本地二进制",
|
|
55
61
|
"card.source.desc": "插件 spawn 核心的一次性运行:核心完成抓取、总结、渲染与提交。不连接服务端,也不提供容器来源。",
|
|
@@ -69,6 +75,8 @@ var DICT = {
|
|
|
69
75
|
"core.downloaded": "核心已下载并校验通过",
|
|
70
76
|
"core.installed": "已安装",
|
|
71
77
|
"core.missing": "未安装",
|
|
78
|
+
"core.override": "覆盖路径:{path}",
|
|
79
|
+
"core.path.advancedHint": "仅开发/排障使用;留空走自动 Release 缓存/下载。",
|
|
72
80
|
"core.order": "解析顺序:TRENDING_DIGEST_CORE(仅开发/排障)→ Release 资产(缓存命中直接用,否则下载并校验);都不可用时报 CORE_UNAVAILABLE。",
|
|
73
81
|
"coexist.title": "检测到本机另有 CLI",
|
|
74
82
|
"coexist.hint": "插件仍使用自带核心,不切换、不接管它的定时。",
|
|
@@ -85,6 +93,9 @@ var DICT = {
|
|
|
85
93
|
"model.mode.direct": "DSH 凭据 / 手动密钥",
|
|
86
94
|
"model.mode.proxy": "回环代理(凭据不可导出)",
|
|
87
95
|
"model.keyRef": "凭据引用",
|
|
96
|
+
"model.credential": "凭据状态",
|
|
97
|
+
"model.credential.hint": "沿用 DSH 配置时自动带入,无需填写。",
|
|
98
|
+
"model.keyRef.advancedHint": "手动指定时才会用到;一般不填。",
|
|
88
99
|
"model.params": "参数",
|
|
89
100
|
"model.preflight": "连通性预检",
|
|
90
101
|
"model.preflighting": "预检中…",
|
|
@@ -93,22 +104,32 @@ var DICT = {
|
|
|
93
104
|
"card.repo.hint": "内容写到哪里、怎么提交",
|
|
94
105
|
"repo.path": "仓库路径",
|
|
95
106
|
"repo.path.placeholder": "绝对路径,例如 /Users/you/notes",
|
|
107
|
+
"repo.path.empty": "尚未选择目录",
|
|
96
108
|
"repo.pick": "选择目录",
|
|
97
109
|
"repo.baseBranch": "目标分支",
|
|
98
|
-
"repo.remote": "远端",
|
|
99
110
|
"repo.outputDir": "输出目录",
|
|
111
|
+
"repo.outputDir.hint": "仓库内的相对目录",
|
|
112
|
+
"branch.loading": "读取中…",
|
|
113
|
+
"branch.fromOrigin": "仓库默认分支(origin/HEAD)",
|
|
114
|
+
"branch.fromHead": "仓库当前分支(未找到 origin)",
|
|
115
|
+
"branch.readonlyHint": "自动读取,不可修改",
|
|
100
116
|
"repo.commitMode": "提交方式",
|
|
101
117
|
"repo.commitMode.branch": "分支 + PR",
|
|
102
118
|
"repo.commitMode.direct": "直接提交",
|
|
103
119
|
"repo.autoMerge": "自动合并 PR",
|
|
104
|
-
"repo.titleTemplate": "PR 标题模板",
|
|
105
120
|
"card.auth.title": "GitHub 认证",
|
|
106
121
|
"card.auth.hint": "只申请 public_repo",
|
|
107
122
|
"auth.mode": "方式",
|
|
108
|
-
"auth.device": "Device Flow",
|
|
109
123
|
"auth.pat": "PAT",
|
|
110
124
|
"auth.gh": "本机 gh",
|
|
125
|
+
"auth.gh.hint": "使用本机 gh 登录态:终端执行 `gh auth login` 完成登录,再点「测试认证」。",
|
|
126
|
+
"auth.pat.hint": "在 GitHub → Settings → Developer settings 生成 Personal Access Token(勾选 public_repo),填到下方引用或环境变量。",
|
|
111
127
|
"auth.tokenRef": "凭据引用",
|
|
128
|
+
"auth.tokenRef.hint": "凭据引用名 / 环境变量名",
|
|
129
|
+
"auth.test": "测试认证",
|
|
130
|
+
"auth.testing": "验证中…",
|
|
131
|
+
"auth.test.ok": "认证成功",
|
|
132
|
+
"auth.test.fail": "认证失败",
|
|
112
133
|
"auth.status": "状态",
|
|
113
134
|
"auth.configured": "已配置",
|
|
114
135
|
"auth.missing": "未配置",
|
|
@@ -125,6 +146,9 @@ var DICT = {
|
|
|
125
146
|
"schedule.next": "下次运行",
|
|
126
147
|
"schedule.source": "由插件自己的 60 s tick 驱动(宿主 schedule 是会话本地提醒,覆盖不到无人值守)",
|
|
127
148
|
"settings.save": "保存设置",
|
|
149
|
+
"settings.saveSection": "保存本页",
|
|
150
|
+
"settings.saveSection.hint": "每个 tab 独立保存;黄点表示该页有未保存改动",
|
|
151
|
+
"settings.dirty": "有未保存改动",
|
|
128
152
|
"settings.saving": "保存中…",
|
|
129
153
|
"settings.saved": "已保存",
|
|
130
154
|
"settings.import": "从本机 CLI 导入",
|
|
@@ -133,6 +157,9 @@ var DICT = {
|
|
|
133
157
|
"settings.troubleshoot": "排障",
|
|
134
158
|
"settings.copyConfig": "复制脱敏配置",
|
|
135
159
|
"settings.copied": "已复制",
|
|
160
|
+
"settings.advanced": "高级设置",
|
|
161
|
+
"settings.advanced.hide": "收起高级",
|
|
162
|
+
"settings.lastRun": "上次运行",
|
|
136
163
|
"run.now": "本次",
|
|
137
164
|
"run.history": "历史",
|
|
138
165
|
"run.button": "立即运行",
|
|
@@ -158,6 +185,8 @@ var DICT = {
|
|
|
158
185
|
"run.usage.hash": "内容哈希",
|
|
159
186
|
"run.usage.branch": "分支",
|
|
160
187
|
"run.usage.pr": "PR",
|
|
188
|
+
"run.pendingPr": "存在未合并 PR",
|
|
189
|
+
"run.pendingPr.hint": "同日重跑会更新该 PR(核心以 --force-with-lease 推送);若已合并/关闭,记录会自动清理。",
|
|
161
190
|
"run.error.title": "最近错误",
|
|
162
191
|
"run.history.title": "历史记录",
|
|
163
192
|
"run.history.hint": "最近 30 条,超出即裁剪",
|
|
@@ -172,15 +201,14 @@ var DICT = {
|
|
|
172
201
|
"state.skipped": "无变更",
|
|
173
202
|
"state.failed": "失败",
|
|
174
203
|
"state.dry": "试跑",
|
|
175
|
-
"widget.title": "GitHub 趋势",
|
|
176
|
-
"widget.next": "下次",
|
|
177
|
-
"widget.last": "上次",
|
|
178
|
-
"widget.never": "从未运行",
|
|
179
|
-
"widget.run": "立即运行",
|
|
180
|
-
"widget.open": "打开面板",
|
|
181
204
|
"quickfill.title": "沿用 DSH 已配置的模型",
|
|
182
|
-
"quickfill.empty": "
|
|
183
|
-
"quickfill.hint": "
|
|
205
|
+
"quickfill.empty": "没有找到已配置的模型",
|
|
206
|
+
"quickfill.hint": "优先一键沿用 DSH 当前默认模型;需要时可以展开选择其他已配置的供应商与模型。",
|
|
207
|
+
"quickfill.default": "DSH 当前默认模型",
|
|
208
|
+
"quickfill.useDefault": "使用默认模型",
|
|
209
|
+
"quickfill.applying": "应用中…",
|
|
210
|
+
"quickfill.others": "选择其他已配置模型",
|
|
211
|
+
"quickfill.others.hide": "收起其他模型",
|
|
184
212
|
"quickfill.mode.direct": "密钥可导出,直传核心",
|
|
185
213
|
"quickfill.mode.proxy": "凭据不可导出,走回环代理",
|
|
186
214
|
"quickfill.mode.missing": "缺少可用凭据,需要手动填写",
|
|
@@ -195,6 +223,12 @@ var DICT = {
|
|
|
195
223
|
"section.subtitle": "Fetch, summarize and commit GitHub Trending into your own repo on a daily schedule. All content comes from the local core binary.",
|
|
196
224
|
"tab.settings": "Settings",
|
|
197
225
|
"tab.runs": "Runs",
|
|
226
|
+
"st.source": "Source",
|
|
227
|
+
"st.model": "Model",
|
|
228
|
+
"st.repo": "Repository",
|
|
229
|
+
"st.auth": "Auth",
|
|
230
|
+
"st.scope": "Scope",
|
|
231
|
+
"st.schedule": "Schedule",
|
|
198
232
|
"card.source.title": "Content source",
|
|
199
233
|
"card.source.hint": "one source: the local binary",
|
|
200
234
|
"card.source.desc": "The plugin spawns one core run: fetch, summarize, render and commit happen inside the core. No server, no container.",
|
|
@@ -208,6 +242,8 @@ var DICT = {
|
|
|
208
242
|
"core.incompatible": "incompatible",
|
|
209
243
|
"core.installed": "installed",
|
|
210
244
|
"core.missing": "missing",
|
|
245
|
+
"core.override": "Override path: {path}",
|
|
246
|
+
"core.path.advancedHint": "Dev/troubleshooting only; leave empty to use the Release cache/download.",
|
|
211
247
|
"core.cached": "cached",
|
|
212
248
|
"core.notDownloaded": "not downloaded",
|
|
213
249
|
"core.download": "Download core",
|
|
@@ -230,6 +266,9 @@ var DICT = {
|
|
|
230
266
|
"model.mode.direct": "DSH credential / manual key",
|
|
231
267
|
"model.mode.proxy": "Loopback proxy (credential not exportable)",
|
|
232
268
|
"model.keyRef": "Credential ref",
|
|
269
|
+
"model.credential": "Credential",
|
|
270
|
+
"model.credential.hint": "Filled automatically when reusing DSH config; no need to enter it.",
|
|
271
|
+
"model.keyRef.advancedHint": "Only used when setting a ref manually; usually left empty.",
|
|
233
272
|
"model.params": "Parameters",
|
|
234
273
|
"model.preflight": "Test connection",
|
|
235
274
|
"model.preflighting": "Testing…",
|
|
@@ -238,22 +277,32 @@ var DICT = {
|
|
|
238
277
|
"card.repo.hint": "where content lands and how it is committed",
|
|
239
278
|
"repo.path": "Repository path",
|
|
240
279
|
"repo.path.placeholder": "absolute path, e.g. /Users/you/notes",
|
|
280
|
+
"repo.path.empty": "No folder chosen",
|
|
241
281
|
"repo.pick": "Choose folder",
|
|
242
282
|
"repo.baseBranch": "Base branch",
|
|
243
|
-
"repo.remote": "Remote",
|
|
244
283
|
"repo.outputDir": "Output dir",
|
|
284
|
+
"repo.outputDir.hint": "relative directory inside the repo",
|
|
285
|
+
"branch.loading": "Reading…",
|
|
286
|
+
"branch.fromOrigin": "repo default branch (origin/HEAD)",
|
|
287
|
+
"branch.fromHead": "current branch (no origin found)",
|
|
288
|
+
"branch.readonlyHint": "Read automatically, cannot be edited",
|
|
245
289
|
"repo.commitMode": "Commit mode",
|
|
246
290
|
"repo.commitMode.branch": "Branch + PR",
|
|
247
291
|
"repo.commitMode.direct": "Direct commit",
|
|
248
292
|
"repo.autoMerge": "Auto-merge PR",
|
|
249
|
-
"repo.titleTemplate": "PR title template",
|
|
250
293
|
"card.auth.title": "GitHub authentication",
|
|
251
294
|
"card.auth.hint": "public_repo only",
|
|
252
295
|
"auth.mode": "Mode",
|
|
253
|
-
"auth.device": "Device flow",
|
|
254
296
|
"auth.pat": "PAT",
|
|
255
297
|
"auth.gh": "Local gh",
|
|
298
|
+
"auth.gh.hint": "Uses your local gh login: run `gh auth login` in a terminal, then click Test authentication.",
|
|
299
|
+
"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.",
|
|
256
300
|
"auth.tokenRef": "Credential ref",
|
|
301
|
+
"auth.tokenRef.hint": "credential ref / env var name",
|
|
302
|
+
"auth.test": "Test authentication",
|
|
303
|
+
"auth.testing": "Verifying…",
|
|
304
|
+
"auth.test.ok": "Authenticated",
|
|
305
|
+
"auth.test.fail": "Authentication failed",
|
|
257
306
|
"auth.status": "Status",
|
|
258
307
|
"auth.configured": "configured",
|
|
259
308
|
"auth.missing": "missing",
|
|
@@ -270,6 +319,9 @@ var DICT = {
|
|
|
270
319
|
"schedule.next": "Next run",
|
|
271
320
|
"schedule.source": "Driven by the plugin’s own 60 s tick (host schedule is session-local and cannot cover unattended runs)",
|
|
272
321
|
"settings.save": "Save",
|
|
322
|
+
"settings.saveSection": "Save this tab",
|
|
323
|
+
"settings.saveSection.hint": "Each tab saves independently; a yellow dot marks unsaved changes",
|
|
324
|
+
"settings.dirty": "Unsaved changes",
|
|
273
325
|
"settings.saving": "Saving…",
|
|
274
326
|
"settings.saved": "Saved",
|
|
275
327
|
"settings.import": "Import from local CLI",
|
|
@@ -278,6 +330,9 @@ var DICT = {
|
|
|
278
330
|
"settings.troubleshoot": "Troubleshooting",
|
|
279
331
|
"settings.copyConfig": "Copy redacted config",
|
|
280
332
|
"settings.copied": "Copied",
|
|
333
|
+
"settings.advanced": "Advanced settings",
|
|
334
|
+
"settings.advanced.hide": "Hide advanced",
|
|
335
|
+
"settings.lastRun": "Last run",
|
|
281
336
|
"run.now": "This run",
|
|
282
337
|
"run.history": "History",
|
|
283
338
|
"run.button": "Run now",
|
|
@@ -303,6 +358,8 @@ var DICT = {
|
|
|
303
358
|
"run.usage.hash": "Content hash",
|
|
304
359
|
"run.usage.branch": "Branch",
|
|
305
360
|
"run.usage.pr": "PR",
|
|
361
|
+
"run.pendingPr": "Unmerged PR exists",
|
|
362
|
+
"run.pendingPr.hint": "Re-running the same day updates this PR (core pushes with --force-with-lease); merged/closed records are cleaned up automatically.",
|
|
306
363
|
"run.error.title": "Last error",
|
|
307
364
|
"run.history.title": "History",
|
|
308
365
|
"run.history.hint": "last 30 records",
|
|
@@ -317,15 +374,14 @@ var DICT = {
|
|
|
317
374
|
"state.skipped": "no change",
|
|
318
375
|
"state.failed": "failed",
|
|
319
376
|
"state.dry": "dry run",
|
|
320
|
-
"widget.title": "GitHub Trending",
|
|
321
|
-
"widget.next": "Next",
|
|
322
|
-
"widget.last": "Last",
|
|
323
|
-
"widget.never": "never",
|
|
324
|
-
"widget.run": "Run",
|
|
325
|
-
"widget.open": "Open panel",
|
|
326
377
|
"quickfill.title": "Reuse a configured DSH model",
|
|
327
|
-
"quickfill.empty": "No
|
|
328
|
-
"quickfill.hint": "
|
|
378
|
+
"quickfill.empty": "No configured model found",
|
|
379
|
+
"quickfill.hint": "One click reuses the current DSH default model; expand to pick another configured provider and model if needed.",
|
|
380
|
+
"quickfill.default": "Current DSH default model",
|
|
381
|
+
"quickfill.useDefault": "Use default model",
|
|
382
|
+
"quickfill.applying": "Applying…",
|
|
383
|
+
"quickfill.others": "Choose another configured model",
|
|
384
|
+
"quickfill.others.hide": "Hide other models",
|
|
329
385
|
"quickfill.mode.direct": "exportable key, passed to the core",
|
|
330
386
|
"quickfill.mode.proxy": "credential not exportable, uses the loopback proxy",
|
|
331
387
|
"quickfill.mode.missing": "no usable credential, fill it in manually",
|
|
@@ -356,7 +412,7 @@ function buildTranslate(locale) {
|
|
|
356
412
|
// client/styles.ts
|
|
357
413
|
var STYLE_ID = "dsh-github-trending-style";
|
|
358
414
|
var CSS = `
|
|
359
|
-
.dshgt-root{--gt-fg:var(--
|
|
415
|
+
.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:13px;line-height:1.5;display:flex;flex-direction:column;gap:12px;}
|
|
360
416
|
.dshgt-root *{box-sizing:border-box;}
|
|
361
417
|
.dshgt-head{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;}
|
|
362
418
|
.dshgt-title{font-size:15px;font-weight:600;}
|
|
@@ -364,6 +420,16 @@ var CSS = `
|
|
|
364
420
|
.dshgt-tabs{display:flex;gap:6px;border-bottom:1px solid var(--gt-border);}
|
|
365
421
|
.dshgt-tab{appearance:none;border:none;background:none;padding:6px 10px;font:inherit;color:var(--gt-muted);cursor:pointer;border-bottom:2px solid transparent;}
|
|
366
422
|
.dshgt-tab[aria-selected="true"]{color:var(--gt-fg);border-bottom-color:var(--gt-accent);font-weight:600;}
|
|
423
|
+
.dshgt-shell{height:100%;min-height:0;overflow:hidden;}
|
|
424
|
+
.dshgt-content{flex:1;min-height:0;display:flex;}
|
|
425
|
+
.dshgt-scroll{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:12px;padding-right:4px;}
|
|
426
|
+
.dshgt-settings{flex:1;min-height:0;display:grid;grid-template-columns:150px minmax(0,1fr);gap:16px;}
|
|
427
|
+
.dshgt-vtabs{display:flex;flex-direction:column;gap:2px;border-right:1px solid var(--gt-border);padding-right:8px;overflow-y:auto;}
|
|
428
|
+
.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;}
|
|
429
|
+
.dshgt-vtab:hover{background:var(--dsw-alias-interactive-bg-hover,color-mix(in srgb,var(--gt-accent) 8%,transparent));}
|
|
430
|
+
.dshgt-vtab[aria-selected="true"]{background:color-mix(in srgb,var(--gt-accent) 12%,transparent);color:var(--gt-fg);font-weight:600;}
|
|
431
|
+
.dshgt-vtab-dirty{width:6px;height:6px;border-radius:50%;background:var(--gt-warn);flex:none;margin-left:auto;}
|
|
432
|
+
.dshgt-vpanel{min-width:0;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:12px;padding-right:4px;}
|
|
367
433
|
.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;}
|
|
368
434
|
.dshgt-card-h{display:flex;align-items:center;gap:8px;flex-wrap:wrap;}
|
|
369
435
|
.dshgt-card-h h3{margin:0;font-size:13px;font-weight:600;}
|
|
@@ -378,7 +444,8 @@ var CSS = `
|
|
|
378
444
|
.dshgt-btn{appearance:none;font:inherit;cursor:pointer;border-radius:7px;border:1px solid var(--gt-border);background:var(--gt-bg);padding:5px 10px;color:inherit;}
|
|
379
445
|
.dshgt-btn:hover:not(:disabled){border-color:color-mix(in srgb,var(--gt-accent) 45%,var(--gt-border));}
|
|
380
446
|
.dshgt-btn:disabled{opacity:.55;cursor:not-allowed;}
|
|
381
|
-
.dshgt-btn-primary{background:var(--gt-accent);border-color:var(--gt-accent);color
|
|
447
|
+
.dshgt-btn-primary{background:var(--dsw-alias-button-primary-fill,var(--gt-accent));border-color:var(--dsw-alias-button-primary-fill,var(--gt-accent));color:var(--dsw-alias-label-primary-foreground,#fff);}
|
|
448
|
+
.dshgt-default{display:flex;align-items:center;justify-content:space-between;gap:10px;border:1px solid var(--gt-border);border-radius:9px;padding:10px 12px;background:var(--dsw-alias-bg-layer-2,var(--gt-card));}
|
|
382
449
|
.dshgt-btn-danger{background:transparent;border-color:var(--gt-err);color:var(--gt-err);}
|
|
383
450
|
.dshgt-btn-sm{padding:3px 8px;font-size:12px;}
|
|
384
451
|
.dshgt-pill{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--gt-border);border-radius:999px;padding:2px 9px;font-size:12px;background:var(--gt-bg);}
|
|
@@ -406,11 +473,9 @@ var CSS = `
|
|
|
406
473
|
.dshgt-switch::after{content:"";position:absolute;top:2px;left:2px;width:14px;height:14px;border-radius:50%;background:#fff;transition:transform .15s;}
|
|
407
474
|
.dshgt-switch[aria-checked="true"]{background:var(--gt-accent);}
|
|
408
475
|
.dshgt-switch[aria-checked="true"]::after{transform:translateX(16px);}
|
|
409
|
-
.dshgt-widget{border:1px solid var(--gt-border);border-radius:10px;padding:10px 12px;background:var(--gt-card);display:flex;flex-direction:column;gap:6px;font-size:12px;}
|
|
410
|
-
.dshgt-widget h4{margin:0;font-size:12px;font-weight:600;}
|
|
411
476
|
.dshgt-footer{display:flex;gap:8px;align-items:center;flex-wrap:wrap;}
|
|
412
477
|
.dshgt-monobox{margin:0;padding:8px;border-radius:7px;background:color-mix(in srgb,var(--gt-fg) 6%,var(--gt-bg));max-height:220px;overflow:auto;white-space:pre-wrap;word-break:break-word;}
|
|
413
|
-
.dshgt-modal-mask{position:fixed;inset:0;background:rgba(15,23,42,.38);display:flex;align-items:center;justify-content:center;z-index:2147483000;}
|
|
478
|
+
.dshgt-modal-mask{position:fixed;inset:0;background:var(--dsw-alias-bg-mask-1,rgba(15,23,42,.38));display:flex;align-items:center;justify-content:center;z-index:2147483000;}
|
|
414
479
|
.dshgt-modal{background:var(--gt-bg);border-radius:12px;border:1px solid var(--gt-border);max-width:640px;width:calc(100% - 32px);max-height:80vh;overflow:auto;padding:16px;display:flex;flex-direction:column;gap:10px;box-shadow:0 20px 50px rgba(15,23,42,.25);}
|
|
415
480
|
`;
|
|
416
481
|
function injectStyles() {
|
|
@@ -628,13 +693,42 @@ function useStore() {
|
|
|
628
693
|
|
|
629
694
|
// client/settings.ts
|
|
630
695
|
var LANGUAGES = ["all", "typescript", "python", "go", "rust", "java", "c", "cpp", "javascript", "csharp"];
|
|
696
|
+
var SECTIONS = ["source", "model", "repo", "auth", "scope", "schedule"];
|
|
697
|
+
var EMPTY_DIRTY = { source: false, model: false, repo: false, auth: false, scope: false, schedule: false };
|
|
698
|
+
function cloneSettings(settings) {
|
|
699
|
+
return JSON.parse(JSON.stringify(settings));
|
|
700
|
+
}
|
|
701
|
+
function sectionSlice(settings, section) {
|
|
702
|
+
switch (section) {
|
|
703
|
+
case "source":
|
|
704
|
+
return { corePath: settings.corePath };
|
|
705
|
+
case "model":
|
|
706
|
+
return { model: settings.model };
|
|
707
|
+
case "repo":
|
|
708
|
+
return { repo: settings.repo, pr: settings.pr, output: settings.output };
|
|
709
|
+
case "auth":
|
|
710
|
+
return { github: settings.github };
|
|
711
|
+
case "scope":
|
|
712
|
+
return { trending: settings.trending };
|
|
713
|
+
case "schedule":
|
|
714
|
+
return { schedule: settings.schedule };
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
function sectionEquals(a, b, section) {
|
|
718
|
+
return JSON.stringify(sectionSlice(a, section)) === JSON.stringify(sectionSlice(b, section));
|
|
719
|
+
}
|
|
720
|
+
function applySection(target, source, section) {
|
|
721
|
+
const next = cloneSettings(target);
|
|
722
|
+
Object.assign(next, sectionSlice(source, section));
|
|
723
|
+
return next;
|
|
724
|
+
}
|
|
631
725
|
function SettingsView(props) {
|
|
632
726
|
const { t, store } = props;
|
|
633
727
|
const state = store.state;
|
|
634
728
|
const [draft, setDraft] = import_react.default.useState(null);
|
|
635
|
-
const [
|
|
636
|
-
const [
|
|
637
|
-
const [
|
|
729
|
+
const [dirtySections, setDirtySections] = import_react.default.useState({ ...EMPTY_DIRTY });
|
|
730
|
+
const [savingSection, setSavingSection] = import_react.default.useState(null);
|
|
731
|
+
const [savedSection, setSavedSection] = import_react.default.useState(null);
|
|
638
732
|
const [problems, setProblems] = import_react.default.useState([]);
|
|
639
733
|
const [message, setMessage] = import_react.default.useState(null);
|
|
640
734
|
const [preflight, setPreflight] = import_react.default.useState(null);
|
|
@@ -642,31 +736,69 @@ function SettingsView(props) {
|
|
|
642
736
|
const [rechecking, setRechecking] = import_react.default.useState(false);
|
|
643
737
|
const [downloading, setDownloading] = import_react.default.useState(false);
|
|
644
738
|
const [quickOpen, setQuickOpen] = import_react.default.useState(false);
|
|
739
|
+
const [advanced, setAdvanced] = import_react.default.useState(false);
|
|
740
|
+
const [section, setSection] = import_react.default.useState("source");
|
|
741
|
+
const [branchInfo, setBranchInfo] = import_react.default.useState(null);
|
|
742
|
+
const [branchLoading, setBranchLoading] = import_react.default.useState(false);
|
|
743
|
+
const [testing, setTesting] = import_react.default.useState(false);
|
|
744
|
+
const [githubTest, setGithubTest] = import_react.default.useState(null);
|
|
745
|
+
const anyDirty = SECTIONS.some((id) => dirtySections[id]);
|
|
746
|
+
import_react.default.useEffect(() => {
|
|
747
|
+
if (state !== null && !anyDirty) setDraft(state.settings);
|
|
748
|
+
}, [state, anyDirty]);
|
|
749
|
+
import_react.default.useEffect(() => {
|
|
750
|
+
setProblems([]);
|
|
751
|
+
}, [section]);
|
|
752
|
+
const repoPath = draft === null ? "" : draft.repo.path;
|
|
645
753
|
import_react.default.useEffect(() => {
|
|
646
|
-
if (
|
|
647
|
-
|
|
754
|
+
if (repoPath.trim() === "") {
|
|
755
|
+
setBranchInfo(null);
|
|
756
|
+
return () => void 0;
|
|
757
|
+
}
|
|
758
|
+
let cancelled = false;
|
|
759
|
+
setBranchLoading(true);
|
|
760
|
+
apiCall("GET", `/repo/branch?path=${encodeURIComponent(repoPath)}`).then((result) => {
|
|
761
|
+
if (!cancelled) setBranchInfo(result.repo);
|
|
762
|
+
}).catch((error) => {
|
|
763
|
+
if (!cancelled) setBranchInfo({ source: "none", message: error instanceof Error ? error.message : String(error) });
|
|
764
|
+
}).finally(() => {
|
|
765
|
+
if (!cancelled) setBranchLoading(false);
|
|
766
|
+
});
|
|
767
|
+
return () => {
|
|
768
|
+
cancelled = true;
|
|
769
|
+
};
|
|
770
|
+
}, [repoPath]);
|
|
648
771
|
const update = (mutate) => {
|
|
649
772
|
if (draft === null) return;
|
|
650
|
-
const
|
|
773
|
+
const prev = draft;
|
|
774
|
+
const next = cloneSettings(draft);
|
|
651
775
|
mutate(next);
|
|
652
776
|
setDraft(next);
|
|
653
|
-
|
|
654
|
-
|
|
777
|
+
const changed = SECTIONS.filter((id) => !sectionEquals(prev, next, id));
|
|
778
|
+
if (changed.length > 0) {
|
|
779
|
+
setDirtySections((current) => {
|
|
780
|
+
const merged = { ...current };
|
|
781
|
+
for (const id of changed) merged[id] = true;
|
|
782
|
+
return merged;
|
|
783
|
+
});
|
|
784
|
+
setSavedSection((current) => current !== null && changed.includes(current) ? null : current);
|
|
785
|
+
setProblems([]);
|
|
786
|
+
}
|
|
655
787
|
};
|
|
656
|
-
const save = async () => {
|
|
788
|
+
const save = async (section2) => {
|
|
657
789
|
if (draft === null) return;
|
|
658
|
-
|
|
790
|
+
setSavingSection(section2);
|
|
659
791
|
setProblems([]);
|
|
660
792
|
try {
|
|
661
793
|
const result = await apiCall(
|
|
662
794
|
"POST",
|
|
663
795
|
"/config",
|
|
664
|
-
{ settings: draft }
|
|
796
|
+
{ settings: draft, section: section2 }
|
|
665
797
|
);
|
|
666
798
|
if (result.saved) {
|
|
667
|
-
setDraft(result.settings);
|
|
668
|
-
|
|
669
|
-
|
|
799
|
+
setDraft((current) => current === null ? current : applySection(current, result.settings, section2));
|
|
800
|
+
setDirtySections((current) => ({ ...current, [section2]: false }));
|
|
801
|
+
setSavedSection(section2);
|
|
670
802
|
setMessage(null);
|
|
671
803
|
await store.refresh({ quiet: true });
|
|
672
804
|
} else {
|
|
@@ -675,7 +807,7 @@ function SettingsView(props) {
|
|
|
675
807
|
} catch (error) {
|
|
676
808
|
setMessage(error instanceof Error ? error.message : String(error));
|
|
677
809
|
} finally {
|
|
678
|
-
|
|
810
|
+
setSavingSection(null);
|
|
679
811
|
}
|
|
680
812
|
};
|
|
681
813
|
const runPreflight = async () => {
|
|
@@ -715,6 +847,19 @@ function SettingsView(props) {
|
|
|
715
847
|
setDownloading(false);
|
|
716
848
|
}
|
|
717
849
|
};
|
|
850
|
+
const testGithub = async () => {
|
|
851
|
+
if (draft === null) return;
|
|
852
|
+
setTesting(true);
|
|
853
|
+
setGithubTest(null);
|
|
854
|
+
try {
|
|
855
|
+
const result = await apiCall("POST", "/github/test", { settings: draft });
|
|
856
|
+
setGithubTest(result.github);
|
|
857
|
+
} catch (error) {
|
|
858
|
+
setGithubTest({ ok: false, message: error instanceof Error ? error.message : String(error) });
|
|
859
|
+
} finally {
|
|
860
|
+
setTesting(false);
|
|
861
|
+
}
|
|
862
|
+
};
|
|
718
863
|
const importCli = async () => {
|
|
719
864
|
try {
|
|
720
865
|
const result = await apiCall(
|
|
@@ -725,8 +870,8 @@ function SettingsView(props) {
|
|
|
725
870
|
const payload = result.import;
|
|
726
871
|
if (payload.ok && payload.settings !== void 0) {
|
|
727
872
|
setDraft(payload.settings);
|
|
728
|
-
|
|
729
|
-
|
|
873
|
+
setDirtySections({ ...EMPTY_DIRTY });
|
|
874
|
+
setSavedSection(null);
|
|
730
875
|
setMessage(t("settings.import.done", { fields: payload.imported.join("、") }));
|
|
731
876
|
await store.refresh({ quiet: true });
|
|
732
877
|
} else {
|
|
@@ -750,313 +895,347 @@ function SettingsView(props) {
|
|
|
750
895
|
}
|
|
751
896
|
const providers = state.core.supportedProviders.length > 0 ? state.core.supportedProviders : ["deepseek", "openai-compatible"];
|
|
752
897
|
const coreKind = state.core.state === "ready" ? "ok" : state.core.state === "incompatible" ? "warn" : "err";
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
898
|
+
const branchText = branchLoading ? t("branch.loading") : branchInfo?.branch !== void 0 ? branchInfo.branch : draft.repo.baseBranch !== "" ? draft.repo.baseBranch : "—";
|
|
899
|
+
const branchHint = branchInfo?.source === "origin-head" ? t("branch.fromOrigin") : branchInfo?.source === "head" ? t("branch.fromHead") : branchInfo?.message !== void 0 ? branchInfo.message : t("branch.readonlyHint");
|
|
900
|
+
const isGh = draft.github.authMode === "gh";
|
|
901
|
+
const sections = [
|
|
902
|
+
{ id: "source", label: t("st.source") },
|
|
903
|
+
{ id: "model", label: t("st.model") },
|
|
904
|
+
{ id: "repo", label: t("st.repo") },
|
|
905
|
+
{ id: "auth", label: t("st.auth") },
|
|
906
|
+
{ id: "scope", label: t("st.scope") },
|
|
907
|
+
{ id: "schedule", label: t("st.schedule") }
|
|
908
|
+
];
|
|
909
|
+
const sourceCard = h(
|
|
910
|
+
Card,
|
|
911
|
+
{
|
|
912
|
+
title: t("card.source.title"),
|
|
913
|
+
hint: t("card.source.hint"),
|
|
914
|
+
extra: h(Btn, { small: true, onClick: () => void recheck(), disabled: rechecking }, rechecking ? t("core.checking") : t("core.recheck"))
|
|
915
|
+
},
|
|
916
|
+
h("p", { className: "dshgt-desc" }, t("card.source.desc")),
|
|
756
917
|
h(
|
|
757
|
-
|
|
758
|
-
{
|
|
759
|
-
h("span", { className: "dshgt-
|
|
760
|
-
h("span", { className: "dshgt-
|
|
761
|
-
h("span", { className: "dshgt-hint", style: { marginLeft: "auto" } }, `v${state.plugin.version}`)
|
|
918
|
+
Row,
|
|
919
|
+
{ label: t("card.source.title") },
|
|
920
|
+
h("span", { className: "dshgt-pill" }, h("span", { className: "dshgt-dot ok" }), t("source.local")),
|
|
921
|
+
h("span", { className: "dshgt-hint" }, t("source.local.hint"))
|
|
762
922
|
),
|
|
763
|
-
// ---- 来源与核心 ----
|
|
764
923
|
h(
|
|
765
|
-
|
|
766
|
-
{
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
},
|
|
771
|
-
h("p", { className: "dshgt-desc" }, t("card.source.desc")),
|
|
772
|
-
h(
|
|
773
|
-
Row,
|
|
774
|
-
{ label: t("card.source.title") },
|
|
775
|
-
h("span", { className: "dshgt-pill" }, h("span", { className: "dshgt-dot ok" }), t("source.local")),
|
|
776
|
-
h("span", { className: "dshgt-hint" }, t("source.local.hint"))
|
|
777
|
-
),
|
|
924
|
+
Row,
|
|
925
|
+
{ label: t("core.label") },
|
|
926
|
+
h("span", { className: "dshgt-pill" }, h("span", { className: `dshgt-dot ${coreKind}` }), state.core.version ?? t(`core.${state.core.state}`)),
|
|
927
|
+
state.core.ipcSchema === void 0 ? null : h("span", { className: "dshgt-hint dshgt-mono" }, `ipc ${state.core.ipcSchema} · digest ${state.core.digestSchema ?? "?"}`),
|
|
928
|
+
state.core.release === void 0 ? null : h("span", { className: "dshgt-hint dshgt-mono" }, `${state.core.release.tag} · ${state.core.release.asset}`),
|
|
778
929
|
h(
|
|
779
|
-
|
|
780
|
-
{
|
|
781
|
-
|
|
782
|
-
state.core.ipcSchema === void 0 ? null : h("span", { className: "dshgt-hint dshgt-mono" }, `ipc ${state.core.ipcSchema} · digest ${state.core.digestSchema ?? "?"}`),
|
|
783
|
-
state.core.release === void 0 ? null : h("span", { className: "dshgt-hint dshgt-mono" }, `${state.core.release.tag} · ${state.core.release.asset}`),
|
|
784
|
-
h(
|
|
785
|
-
"span",
|
|
786
|
-
{ className: "dshgt-hint" },
|
|
787
|
-
state.core.download.state === "override" ? `覆盖路径:${state.core.override?.path ?? ""}` : state.core.release?.cached === true ? t("core.cached") : t("core.notDownloaded")
|
|
788
|
-
),
|
|
789
|
-
state.core.download.state === "override" ? null : h(
|
|
790
|
-
Btn,
|
|
791
|
-
{ small: true, onClick: () => void downloadCore(), disabled: downloading },
|
|
792
|
-
downloading ? t("core.downloading") : state.core.release?.cached === true ? t("core.redownload") : t("core.download")
|
|
793
|
-
)
|
|
930
|
+
"span",
|
|
931
|
+
{ className: "dshgt-hint" },
|
|
932
|
+
state.core.download.state === "override" ? t("core.override", { path: state.core.override?.path ?? "" }) : state.core.release?.cached === true ? t("core.cached") : t("core.notDownloaded")
|
|
794
933
|
),
|
|
795
|
-
state.core.
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
next.corePath = value;
|
|
801
|
-
}) }))
|
|
934
|
+
state.core.download.state === "override" ? null : h(
|
|
935
|
+
Btn,
|
|
936
|
+
{ small: true, onClick: () => void downloadCore(), disabled: downloading },
|
|
937
|
+
downloading ? t("core.downloading") : state.core.release?.cached === true ? t("core.redownload") : t("core.download")
|
|
938
|
+
)
|
|
802
939
|
),
|
|
803
|
-
|
|
940
|
+
state.core.release === void 0 ? null : h("p", { className: "dshgt-hint dshgt-mono", style: { fontSize: 11 } }, `${state.core.release.url} → ${state.core.release.binaryPath}`),
|
|
941
|
+
state.core.state === "ready" ? null : h(Alert, { kind: "err", title: t("core.label") }, h("div", null, state.core.message ?? ""), h("div", { className: "dshgt-hint" }, t("core.order"))),
|
|
942
|
+
h("p", { className: "dshgt-hint" }, t("core.order")),
|
|
943
|
+
state.coexistence.found ? h(Alert, { kind: "warn", title: t("coexist.title") }, h("div", { className: "dshgt-mono", style: { fontSize: 12 } }, `${state.coexistence.path ?? ""} ${state.coexistence.version ?? ""}`), h("div", null, state.coexistence.message ?? ""), h("div", { className: "dshgt-hint" }, t("coexist.hint"))) : null,
|
|
944
|
+
advanced ? h(Row, { label: "TRENDING_DIGEST_CORE" }, h(Input, { mono: true, width: 420, value: draft.corePath, placeholder: "/path/to/trendradar", onInput: (value) => update((next) => {
|
|
945
|
+
next.corePath = value;
|
|
946
|
+
}) }), h("span", { className: "dshgt-hint" }, t("core.path.advancedHint"))) : null
|
|
947
|
+
);
|
|
948
|
+
const modelCard = h(
|
|
949
|
+
Card,
|
|
950
|
+
{
|
|
951
|
+
title: t("card.model.title"),
|
|
952
|
+
hint: t("card.model.hint"),
|
|
953
|
+
extra: h(Btn, { small: true, variant: "primary", onClick: () => setQuickOpen(true) }, t("model.quickfill"))
|
|
954
|
+
},
|
|
955
|
+
h("p", { className: "dshgt-desc" }, t("model.quickfill.desc")),
|
|
804
956
|
h(
|
|
805
|
-
|
|
806
|
-
{
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
)
|
|
824
|
-
|
|
957
|
+
Row,
|
|
958
|
+
{ label: t("model.provider") },
|
|
959
|
+
h(Select, {
|
|
960
|
+
value: draft.model.provider,
|
|
961
|
+
options: providers.map((provider) => ({ value: provider, label: provider })),
|
|
962
|
+
onChange: (value) => update((next) => {
|
|
963
|
+
next.model.provider = value;
|
|
964
|
+
})
|
|
965
|
+
}),
|
|
966
|
+
h("span", { className: "dshgt-hint" }, state.model.mode === "proxy" ? t("model.mode.proxy") : t("model.mode.direct"))
|
|
967
|
+
),
|
|
968
|
+
h(Row, { label: t("model.baseURL") }, h(Input, {
|
|
969
|
+
mono: true,
|
|
970
|
+
width: 420,
|
|
971
|
+
value: draft.model.baseURL,
|
|
972
|
+
placeholder: t("model.baseURL.placeholder"),
|
|
973
|
+
onInput: (value) => update((next) => {
|
|
974
|
+
next.model.baseURL = value;
|
|
975
|
+
})
|
|
976
|
+
})),
|
|
977
|
+
h(
|
|
978
|
+
Row,
|
|
979
|
+
{ label: t("model.model") },
|
|
980
|
+
h(Input, {
|
|
825
981
|
mono: true,
|
|
826
|
-
width:
|
|
827
|
-
value: draft.model.
|
|
828
|
-
placeholder: t("model.
|
|
982
|
+
width: 260,
|
|
983
|
+
value: draft.model.model,
|
|
984
|
+
placeholder: t("model.model.placeholder"),
|
|
829
985
|
onInput: (value) => update((next) => {
|
|
830
|
-
next.model.
|
|
986
|
+
next.model.model = value;
|
|
831
987
|
})
|
|
832
|
-
})
|
|
833
|
-
h(
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
h(Btn, { small: true, onClick: () => void runPreflight(), disabled: preflighting }, preflighting ? t("model.preflighting") : t("model.preflight"))
|
|
846
|
-
),
|
|
847
|
-
h(
|
|
848
|
-
Row,
|
|
849
|
-
{ label: t("model.keyRef") },
|
|
850
|
-
h(Input, { mono: true, width: 220, value: draft.model.apiKeyRef, onInput: (value) => update((next) => {
|
|
851
|
-
next.model.apiKeyRef = value;
|
|
852
|
-
}) }),
|
|
853
|
-
h(
|
|
854
|
-
Pill,
|
|
855
|
-
{ kind: state.model.credential.configured ? "ok" : "err" },
|
|
856
|
-
state.model.credential.configured ? `${t("auth.configured")}${state.model.credential.source === null ? "" : ` · ${state.model.credential.source}`}` : t("auth.missing")
|
|
857
|
-
)
|
|
858
|
-
),
|
|
988
|
+
}),
|
|
989
|
+
h(Btn, { small: true, onClick: () => void runPreflight(), disabled: preflighting }, preflighting ? t("model.preflighting") : t("model.preflight"))
|
|
990
|
+
),
|
|
991
|
+
advanced ? h(
|
|
992
|
+
Row,
|
|
993
|
+
{ label: t("model.keyRef") },
|
|
994
|
+
h(Input, { mono: true, width: 220, value: draft.model.apiKeyRef, onInput: (value) => update((next) => {
|
|
995
|
+
next.model.apiKeyRef = value;
|
|
996
|
+
}) }),
|
|
997
|
+
h("span", { className: "dshgt-hint" }, t("model.keyRef.advancedHint"))
|
|
998
|
+
) : h(
|
|
999
|
+
Row,
|
|
1000
|
+
{ label: t("model.credential") },
|
|
859
1001
|
h(
|
|
860
|
-
|
|
861
|
-
{
|
|
862
|
-
|
|
863
|
-
next.model.temperature = Number(value) || 0;
|
|
864
|
-
}) }),
|
|
865
|
-
h(Input, { mono: true, width: 90, value: String(draft.model.maxTokens), onInput: (value) => update((next) => {
|
|
866
|
-
next.model.maxTokens = Math.round(Number(value) || 0);
|
|
867
|
-
}) }),
|
|
868
|
-
h(Toggle, { checked: draft.model.allowDegraded, label: t("model.allowDegraded"), onChange: (value) => update((next) => {
|
|
869
|
-
next.model.allowDegraded = value;
|
|
870
|
-
}) })
|
|
1002
|
+
Pill,
|
|
1003
|
+
{ kind: state.model.credential.configured ? "ok" : "err" },
|
|
1004
|
+
state.model.credential.configured ? `${t("auth.configured")}${state.model.credential.source === null ? "" : ` · ${state.model.credential.source}`}` : t("auth.missing")
|
|
871
1005
|
),
|
|
872
|
-
|
|
873
|
-
Alert,
|
|
874
|
-
{ kind: preflight.ok ? "ok" : "err", title: preflight.ok ? t("state.ok") : t("error.prefix") },
|
|
875
|
-
h("div", null, `${preflight.mode} · ${duration(preflight.durationMs)}${preflight.endpoint === void 0 ? "" : ` · ${preflight.endpoint}`}`),
|
|
876
|
-
preflight.message === void 0 ? null : h("div", null, preflight.message),
|
|
877
|
-
preflight.hint === void 0 ? null : h("div", { className: "dshgt-hint" }, preflight.hint)
|
|
878
|
-
)
|
|
1006
|
+
h("span", { className: "dshgt-hint" }, t("model.credential.hint"))
|
|
879
1007
|
),
|
|
880
|
-
// ---- 仓库 ----
|
|
881
1008
|
h(
|
|
882
|
-
|
|
883
|
-
{
|
|
884
|
-
h(
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
1009
|
+
Row,
|
|
1010
|
+
{ label: t("model.params") },
|
|
1011
|
+
h(Input, { mono: true, width: 70, value: String(draft.model.temperature), onInput: (value) => update((next) => {
|
|
1012
|
+
next.model.temperature = Number(value) || 0;
|
|
1013
|
+
}) }),
|
|
1014
|
+
h(Input, { mono: true, width: 90, value: String(draft.model.maxTokens), onInput: (value) => update((next) => {
|
|
1015
|
+
next.model.maxTokens = Math.round(Number(value) || 0);
|
|
1016
|
+
}) }),
|
|
1017
|
+
h(Toggle, { checked: draft.model.allowDegraded, label: t("model.allowDegraded"), onChange: (value) => update((next) => {
|
|
1018
|
+
next.model.allowDegraded = value;
|
|
1019
|
+
}) })
|
|
1020
|
+
),
|
|
1021
|
+
preflight === null ? null : h(
|
|
1022
|
+
Alert,
|
|
1023
|
+
{ kind: preflight.ok ? "ok" : "err", title: preflight.ok ? t("state.ok") : t("error.prefix") },
|
|
1024
|
+
h("div", null, `${preflight.mode} · ${duration(preflight.durationMs)}${preflight.endpoint === void 0 ? "" : ` · ${preflight.endpoint}`}`),
|
|
1025
|
+
preflight.message === void 0 ? null : h("div", null, preflight.message),
|
|
1026
|
+
preflight.hint === void 0 ? null : h("div", { className: "dshgt-hint" }, preflight.hint)
|
|
1027
|
+
)
|
|
1028
|
+
);
|
|
1029
|
+
const repoCard = h(
|
|
1030
|
+
Card,
|
|
1031
|
+
{ title: t("card.repo.title"), hint: t("card.repo.hint") },
|
|
1032
|
+
h(
|
|
1033
|
+
Row,
|
|
1034
|
+
{ label: t("repo.path") },
|
|
1035
|
+
h("span", { className: "dshgt-mono", style: { wordBreak: "break-all" } }, draft.repo.path === "" ? t("repo.path.empty") : draft.repo.path),
|
|
1036
|
+
props.pickDirectory === void 0 ? null : h(Btn, {
|
|
1037
|
+
small: true,
|
|
1038
|
+
onClick: () => {
|
|
1039
|
+
void props.pickDirectory?.().then((picked) => {
|
|
1040
|
+
if (typeof picked === "string" && picked !== "") update((next) => {
|
|
1041
|
+
next.repo.path = picked;
|
|
903
1042
|
});
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
)
|
|
907
|
-
h(
|
|
908
|
-
Row,
|
|
909
|
-
{ label: t("repo.baseBranch") },
|
|
910
|
-
h(Input, { mono: true, width: 120, value: draft.repo.baseBranch, onInput: (value) => update((next) => {
|
|
911
|
-
next.repo.baseBranch = value;
|
|
912
|
-
}) }),
|
|
913
|
-
h("span", { className: "dshgt-hint" }, t("repo.remote")),
|
|
914
|
-
h(Input, { mono: true, width: 100, value: draft.repo.remote, onInput: (value) => update((next) => {
|
|
915
|
-
next.repo.remote = value;
|
|
916
|
-
}) }),
|
|
917
|
-
h("span", { className: "dshgt-hint" }, t("repo.outputDir")),
|
|
918
|
-
h(Input, { mono: true, width: 140, value: draft.output.dir, onInput: (value) => update((next) => {
|
|
919
|
-
next.output.dir = value;
|
|
920
|
-
}) })
|
|
921
|
-
),
|
|
922
|
-
h(
|
|
923
|
-
Row,
|
|
924
|
-
{ label: t("repo.commitMode") },
|
|
925
|
-
h(Select, {
|
|
926
|
-
value: draft.repo.commitMode,
|
|
927
|
-
options: [
|
|
928
|
-
{ value: "branch", label: t("repo.commitMode.branch") },
|
|
929
|
-
{ value: "direct", label: t("repo.commitMode.direct") }
|
|
930
|
-
],
|
|
931
|
-
onChange: (value) => update((next) => {
|
|
932
|
-
next.repo.commitMode = value === "direct" ? "direct" : "branch";
|
|
933
|
-
})
|
|
934
|
-
}),
|
|
935
|
-
h(Toggle, { checked: draft.pr.autoMerge, label: t("repo.autoMerge"), onChange: (value) => update((next) => {
|
|
936
|
-
next.pr.autoMerge = value;
|
|
937
|
-
}) })
|
|
938
|
-
),
|
|
939
|
-
h(Row, { label: t("repo.titleTemplate") }, h(Input, {
|
|
940
|
-
mono: true,
|
|
941
|
-
width: 360,
|
|
942
|
-
value: draft.pr.titleTemplate,
|
|
943
|
-
onInput: (value) => update((next) => {
|
|
944
|
-
next.pr.titleTemplate = value;
|
|
945
|
-
})
|
|
946
|
-
}))
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
}, t("repo.pick"))
|
|
947
1046
|
),
|
|
948
|
-
// ---- 认证 ----
|
|
949
1047
|
h(
|
|
950
|
-
|
|
951
|
-
{
|
|
952
|
-
h(
|
|
953
|
-
|
|
954
|
-
{ label: t("auth.mode") },
|
|
955
|
-
h(Select, {
|
|
956
|
-
value: draft.github.authMode,
|
|
957
|
-
options: [
|
|
958
|
-
{ value: "device", label: t("auth.device") },
|
|
959
|
-
{ value: "pat", label: t("auth.pat") },
|
|
960
|
-
{ value: "gh", label: t("auth.gh") }
|
|
961
|
-
],
|
|
962
|
-
onChange: (value) => update((next) => {
|
|
963
|
-
next.github.authMode = value === "pat" ? "pat" : value === "gh" ? "gh" : "device";
|
|
964
|
-
})
|
|
965
|
-
}),
|
|
966
|
-
h("span", { className: "dshgt-hint" }, t("auth.tokenRef")),
|
|
967
|
-
h(Input, { mono: true, width: 180, value: draft.github.tokenRef, onInput: (value) => update((next) => {
|
|
968
|
-
next.github.tokenRef = value;
|
|
969
|
-
}) }),
|
|
970
|
-
h(Pill, { kind: state.github.configured ? "ok" : "warn" }, state.github.configured ? `${t("auth.configured")} · ${state.github.source}` : t("auth.missing"))
|
|
971
|
-
),
|
|
972
|
-
state.github.configured ? null : h("p", { className: "dshgt-hint" }, "未配置 token 时 push / 开 PR 会以 GITHUB_AUTH 失败;试跑(dryRun)不受影响。")
|
|
1048
|
+
Row,
|
|
1049
|
+
{ label: t("repo.baseBranch") },
|
|
1050
|
+
h("span", { className: "dshgt-mono" }, branchText),
|
|
1051
|
+
h("span", { className: "dshgt-hint" }, branchHint)
|
|
973
1052
|
),
|
|
974
|
-
// ---- 榜单 ----
|
|
975
1053
|
h(
|
|
976
|
-
|
|
977
|
-
{
|
|
978
|
-
h(
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
next.
|
|
994
|
-
})
|
|
995
|
-
),
|
|
996
|
-
h(
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1054
|
+
Row,
|
|
1055
|
+
{ label: t("repo.outputDir") },
|
|
1056
|
+
h(Input, { mono: true, width: 200, value: draft.output.dir, onInput: (value) => update((next) => {
|
|
1057
|
+
next.output.dir = value;
|
|
1058
|
+
}) }),
|
|
1059
|
+
h("span", { className: "dshgt-hint" }, t("repo.outputDir.hint"))
|
|
1060
|
+
),
|
|
1061
|
+
h(
|
|
1062
|
+
Row,
|
|
1063
|
+
{ label: t("repo.commitMode") },
|
|
1064
|
+
h(Select, {
|
|
1065
|
+
value: draft.repo.commitMode,
|
|
1066
|
+
options: [
|
|
1067
|
+
{ value: "branch", label: t("repo.commitMode.branch") },
|
|
1068
|
+
{ value: "direct", label: t("repo.commitMode.direct") }
|
|
1069
|
+
],
|
|
1070
|
+
onChange: (value) => update((next) => {
|
|
1071
|
+
next.repo.commitMode = value === "direct" ? "direct" : "branch";
|
|
1072
|
+
})
|
|
1073
|
+
}),
|
|
1074
|
+
h(Toggle, { checked: draft.pr.autoMerge, label: t("repo.autoMerge"), onChange: (value) => update((next) => {
|
|
1075
|
+
next.pr.autoMerge = value;
|
|
1076
|
+
}) })
|
|
1077
|
+
)
|
|
1078
|
+
);
|
|
1079
|
+
const authCard = h(
|
|
1080
|
+
Card,
|
|
1081
|
+
{ title: t("card.auth.title"), hint: t("card.auth.hint") },
|
|
1082
|
+
h(
|
|
1083
|
+
Row,
|
|
1084
|
+
{ label: t("auth.mode") },
|
|
1085
|
+
h(Select, {
|
|
1086
|
+
value: draft.github.authMode,
|
|
1087
|
+
options: [
|
|
1088
|
+
{ value: "gh", label: t("auth.gh") },
|
|
1089
|
+
{ value: "pat", label: t("auth.pat") }
|
|
1090
|
+
],
|
|
1091
|
+
onChange: (value) => update((next) => {
|
|
1092
|
+
next.github.authMode = value === "pat" ? "pat" : "gh";
|
|
1005
1093
|
})
|
|
1094
|
+
}),
|
|
1095
|
+
h(Pill, { kind: state.github.configured ? "ok" : "warn" }, state.github.configured ? `${t("auth.configured")} · ${state.github.source}` : t("auth.missing"))
|
|
1096
|
+
),
|
|
1097
|
+
h("p", { className: "dshgt-hint" }, isGh ? t("auth.gh.hint") : t("auth.pat.hint")),
|
|
1098
|
+
isGh ? null : h(
|
|
1099
|
+
Row,
|
|
1100
|
+
{ label: t("auth.tokenRef") },
|
|
1101
|
+
h(Input, { mono: true, width: 220, value: draft.github.tokenRef, placeholder: "GITHUB_TOKEN", onInput: (value) => update((next) => {
|
|
1102
|
+
next.github.tokenRef = value;
|
|
1103
|
+
}) }),
|
|
1104
|
+
h("span", { className: "dshgt-hint" }, t("auth.tokenRef.hint"))
|
|
1105
|
+
),
|
|
1106
|
+
h(
|
|
1107
|
+
Row,
|
|
1108
|
+
{ label: t("auth.test") },
|
|
1109
|
+
h(Btn, { small: true, onClick: () => void testGithub(), disabled: testing }, testing ? t("auth.testing") : t("auth.test")),
|
|
1110
|
+
githubTest === null ? null : h(
|
|
1111
|
+
Pill,
|
|
1112
|
+
{ kind: githubTest.ok ? "ok" : "err" },
|
|
1113
|
+
githubTest.ok ? `${t("auth.test.ok")}${githubTest.login === void 0 ? "" : ` · @${githubTest.login}`}` : githubTest.message ?? t("auth.test.fail")
|
|
1006
1114
|
)
|
|
1115
|
+
)
|
|
1116
|
+
);
|
|
1117
|
+
const scopeCard = h(
|
|
1118
|
+
Card,
|
|
1119
|
+
{ title: t("card.scope.title") },
|
|
1120
|
+
h(
|
|
1121
|
+
Row,
|
|
1122
|
+
{ label: t("scope.period") },
|
|
1123
|
+
h(Select, {
|
|
1124
|
+
value: draft.trending.since,
|
|
1125
|
+
options: [
|
|
1126
|
+
{ value: "daily", label: t("scope.daily") },
|
|
1127
|
+
{ value: "weekly", label: t("scope.weekly") }
|
|
1128
|
+
],
|
|
1129
|
+
onChange: (value) => update((next) => {
|
|
1130
|
+
next.trending.since = value === "weekly" ? "weekly" : "daily";
|
|
1131
|
+
})
|
|
1132
|
+
}),
|
|
1133
|
+
h("span", { className: "dshgt-hint" }, t("scope.topN")),
|
|
1134
|
+
h(Input, { mono: true, width: 70, value: String(draft.trending.topN), onInput: (value) => update((next) => {
|
|
1135
|
+
next.trending.topN = Math.round(Number(value) || 0);
|
|
1136
|
+
}) })
|
|
1007
1137
|
),
|
|
1008
|
-
// ---- 调度 ----
|
|
1009
1138
|
h(
|
|
1010
|
-
|
|
1011
|
-
{
|
|
1012
|
-
h(
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
})
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
),
|
|
1027
|
-
h(
|
|
1139
|
+
Row,
|
|
1140
|
+
{ label: t("scope.languages") },
|
|
1141
|
+
h(Chips, {
|
|
1142
|
+
values: LANGUAGES,
|
|
1143
|
+
selected: draft.trending.languages,
|
|
1144
|
+
onChange: (next) => update((draftNext) => {
|
|
1145
|
+
draftNext.trending.languages = next;
|
|
1146
|
+
})
|
|
1147
|
+
})
|
|
1148
|
+
)
|
|
1149
|
+
);
|
|
1150
|
+
const scheduleCard = h(
|
|
1151
|
+
Card,
|
|
1152
|
+
{ title: t("card.schedule.title"), hint: state.schedule.nextRunAt === void 0 ? void 0 : `${t("schedule.next")} ${localTime(state.schedule.nextRunAt)}` },
|
|
1153
|
+
h(
|
|
1154
|
+
Row,
|
|
1155
|
+
{ label: t("schedule.enabled") },
|
|
1156
|
+
h(Toggle, { checked: draft.schedule.enabled, onChange: (value) => update((next) => {
|
|
1157
|
+
next.schedule.enabled = value;
|
|
1158
|
+
}) }),
|
|
1159
|
+
h("span", { className: "dshgt-hint" }, t("schedule.time")),
|
|
1160
|
+
h(Input, { mono: true, width: 110, value: draft.schedule.time, onInput: (value) => update((next) => {
|
|
1161
|
+
next.schedule.time = value;
|
|
1162
|
+
}) }),
|
|
1163
|
+
h("span", { className: "dshgt-hint" }, t("schedule.timezone")),
|
|
1164
|
+
h(Input, { mono: true, width: 170, value: draft.schedule.timezone, onInput: (value) => update((next) => {
|
|
1165
|
+
next.schedule.timezone = value;
|
|
1166
|
+
}) })
|
|
1167
|
+
),
|
|
1168
|
+
h("p", { className: "dshgt-hint" }, t("schedule.source"))
|
|
1169
|
+
);
|
|
1170
|
+
const currentCard = section === "source" ? sourceCard : section === "model" ? modelCard : section === "repo" ? repoCard : section === "auth" ? authCard : section === "scope" ? scopeCard : scheduleCard;
|
|
1171
|
+
return h(
|
|
1172
|
+
"div",
|
|
1173
|
+
{ className: "dshgt-settings" },
|
|
1174
|
+
h(
|
|
1175
|
+
"nav",
|
|
1176
|
+
{ className: "dshgt-vtabs", role: "tablist", "aria-orientation": "vertical" },
|
|
1177
|
+
sections.map(
|
|
1178
|
+
(item) => h(
|
|
1179
|
+
"button",
|
|
1180
|
+
{
|
|
1181
|
+
key: item.id,
|
|
1182
|
+
type: "button",
|
|
1183
|
+
className: "dshgt-vtab",
|
|
1184
|
+
role: "tab",
|
|
1185
|
+
"aria-selected": section === item.id ? "true" : "false",
|
|
1186
|
+
onClick: () => setSection(item.id)
|
|
1187
|
+
},
|
|
1188
|
+
item.label,
|
|
1189
|
+
dirtySections[item.id] ? h("span", { className: "dshgt-vtab-dirty", title: t("settings.dirty") }) : null
|
|
1190
|
+
)
|
|
1191
|
+
)
|
|
1028
1192
|
),
|
|
1029
|
-
// ---- 保存 / 排障 ----
|
|
1030
|
-
problems.length > 0 ? h(Alert, { kind: "err", title: t("error.prefix") }, h("ul", { style: { margin: 0, paddingLeft: 16 } }, problems.map((problem, index) => h("li", { key: index }, `${problem.field}:${problem.message}`)))) : null,
|
|
1031
|
-
message === null ? null : h(Alert, { kind: "ok" }, message),
|
|
1032
1193
|
h(
|
|
1033
1194
|
"div",
|
|
1034
|
-
{ className: "dshgt-
|
|
1035
|
-
|
|
1036
|
-
h(
|
|
1037
|
-
h(
|
|
1038
|
-
|
|
1195
|
+
{ className: "dshgt-vpanel" },
|
|
1196
|
+
currentCard,
|
|
1197
|
+
problems.length > 0 ? h(Alert, { kind: "err", title: t("error.prefix") }, h("ul", { style: { margin: 0, paddingLeft: 16 } }, problems.map((problem, index) => h("li", { key: index }, `${problem.field}:${problem.message}`)))) : null,
|
|
1198
|
+
message === null ? null : h(Alert, { kind: "ok" }, message),
|
|
1199
|
+
h(
|
|
1200
|
+
"div",
|
|
1201
|
+
{ className: "dshgt-footer" },
|
|
1202
|
+
h(
|
|
1203
|
+
Btn,
|
|
1204
|
+
{
|
|
1205
|
+
variant: "primary",
|
|
1206
|
+
onClick: () => void save(section),
|
|
1207
|
+
disabled: savingSection !== null || !dirtySections[section],
|
|
1208
|
+
title: t("settings.saveSection.hint")
|
|
1209
|
+
},
|
|
1210
|
+
savingSection === section ? t("settings.saving") : dirtySections[section] ? t("settings.saveSection") : savedSection === section ? t("settings.saved") : t("settings.saveSection")
|
|
1211
|
+
),
|
|
1212
|
+
h("span", { className: "dshgt-hint" }, t("settings.saveSection.hint")),
|
|
1213
|
+
h(Btn, { onClick: () => void importCli() }, t("settings.import")),
|
|
1214
|
+
h(Btn, { onClick: copyConfig }, t("settings.copyConfig")),
|
|
1215
|
+
h(Btn, { onClick: () => setAdvanced(!advanced) }, advanced ? t("settings.advanced.hide") : t("settings.advanced"))
|
|
1216
|
+
)
|
|
1039
1217
|
),
|
|
1040
1218
|
quickOpen ? h(QuickFillModal, { t, onClose: () => setQuickOpen(false), onApplied: (settings) => {
|
|
1041
1219
|
setDraft(settings);
|
|
1042
|
-
|
|
1043
|
-
|
|
1220
|
+
setDirtySections({ ...EMPTY_DIRTY });
|
|
1221
|
+
setSavedSection(null);
|
|
1044
1222
|
void store.refresh({ quiet: true });
|
|
1045
1223
|
} }) : null
|
|
1046
1224
|
);
|
|
1047
1225
|
}
|
|
1048
1226
|
function QuickFillModal(props) {
|
|
1049
1227
|
const { t } = props;
|
|
1050
|
-
const [
|
|
1228
|
+
const [data, setData] = import_react.default.useState(null);
|
|
1051
1229
|
const [error, setError] = import_react.default.useState(null);
|
|
1052
1230
|
const [selectedProvider, setSelectedProvider] = import_react.default.useState("");
|
|
1053
1231
|
const [selectedModel, setSelectedModel] = import_react.default.useState("");
|
|
1054
|
-
const [applying, setApplying] = import_react.default.useState(
|
|
1232
|
+
const [applying, setApplying] = import_react.default.useState(null);
|
|
1233
|
+
const [showOthers, setShowOthers] = import_react.default.useState(false);
|
|
1055
1234
|
import_react.default.useEffect(() => {
|
|
1056
1235
|
void (async () => {
|
|
1057
1236
|
try {
|
|
1058
1237
|
const result = await apiCall("GET", "/quickfill");
|
|
1059
|
-
|
|
1238
|
+
setData(result);
|
|
1060
1239
|
const first = result.providers[0];
|
|
1061
1240
|
if (first !== void 0) {
|
|
1062
1241
|
setSelectedProvider(first.id);
|
|
@@ -1064,22 +1243,40 @@ function QuickFillModal(props) {
|
|
|
1064
1243
|
}
|
|
1065
1244
|
} catch (failure) {
|
|
1066
1245
|
setError(failure instanceof Error ? failure.message : String(failure));
|
|
1067
|
-
|
|
1246
|
+
setData({ providers: [], defaultSelection: null });
|
|
1068
1247
|
}
|
|
1069
1248
|
})();
|
|
1070
1249
|
}, []);
|
|
1071
|
-
const
|
|
1072
|
-
const
|
|
1250
|
+
const providers = data?.providers ?? [];
|
|
1251
|
+
const defaultSelection = data?.defaultSelection ?? null;
|
|
1252
|
+
const current = providers.find((provider) => provider.id === selectedProvider);
|
|
1253
|
+
const finish = (settings) => {
|
|
1254
|
+
props.onApplied(settings);
|
|
1255
|
+
props.onClose();
|
|
1256
|
+
};
|
|
1257
|
+
const applyDefault = async () => {
|
|
1258
|
+
setApplying("default");
|
|
1259
|
+
setError(null);
|
|
1260
|
+
try {
|
|
1261
|
+
const result = await apiCall("POST", "/quickfill", { useDefault: true });
|
|
1262
|
+
finish(result.settings);
|
|
1263
|
+
} catch (failure) {
|
|
1264
|
+
setError(failure instanceof Error ? failure.message : String(failure));
|
|
1265
|
+
} finally {
|
|
1266
|
+
setApplying(null);
|
|
1267
|
+
}
|
|
1268
|
+
};
|
|
1269
|
+
const applySelected = async () => {
|
|
1073
1270
|
if (current === void 0) return;
|
|
1074
|
-
setApplying(
|
|
1271
|
+
setApplying("selected");
|
|
1272
|
+
setError(null);
|
|
1075
1273
|
try {
|
|
1076
1274
|
const result = await apiCall("POST", "/quickfill", { providerId: current.id, modelId: selectedModel });
|
|
1077
|
-
|
|
1078
|
-
props.onClose();
|
|
1275
|
+
finish(result.settings);
|
|
1079
1276
|
} catch (failure) {
|
|
1080
1277
|
setError(failure instanceof Error ? failure.message : String(failure));
|
|
1081
1278
|
} finally {
|
|
1082
|
-
setApplying(
|
|
1279
|
+
setApplying(null);
|
|
1083
1280
|
}
|
|
1084
1281
|
};
|
|
1085
1282
|
return h(
|
|
@@ -1093,37 +1290,57 @@ function QuickFillModal(props) {
|
|
|
1093
1290
|
h("h3", { style: { margin: 0, fontSize: 14 } }, t("quickfill.title")),
|
|
1094
1291
|
h("p", { className: "dshgt-hint", style: { margin: 0 } }, t("quickfill.hint")),
|
|
1095
1292
|
error === null ? null : h(Alert, { kind: "err" }, error),
|
|
1096
|
-
|
|
1293
|
+
data === null ? h("p", { className: "dshgt-hint" }, t("quickfill.loading")) : h(
|
|
1097
1294
|
"div",
|
|
1098
|
-
{ style: { display: "flex", flexDirection: "column", gap:
|
|
1099
|
-
h(
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1295
|
+
{ style: { display: "flex", flexDirection: "column", gap: 10 } },
|
|
1296
|
+
defaultSelection === null ? null : h(
|
|
1297
|
+
"div",
|
|
1298
|
+
{ className: "dshgt-default" },
|
|
1299
|
+
h(
|
|
1300
|
+
"div",
|
|
1301
|
+
{ style: { display: "flex", flexDirection: "column", gap: 2 } },
|
|
1302
|
+
h("span", { className: "dshgt-hint" }, t("quickfill.default")),
|
|
1303
|
+
h("span", { className: "dshgt-mono" }, `${defaultSelection.provider} / ${defaultSelection.model}`)
|
|
1304
|
+
),
|
|
1305
|
+
h(Btn, { variant: "primary", small: true, onClick: () => void applyDefault(), disabled: applying !== null }, applying === "default" ? t("quickfill.applying") : t("quickfill.useDefault"))
|
|
1306
|
+
),
|
|
1307
|
+
providers.length === 0 ? defaultSelection === null ? h("p", { className: "dshgt-hint" }, t("quickfill.empty")) : null : h(
|
|
1308
|
+
"div",
|
|
1309
|
+
{ style: { display: "flex", flexDirection: "column", gap: 8 } },
|
|
1310
|
+
h(Btn, { small: true, onClick: () => setShowOthers(!showOthers) }, showOthers ? t("quickfill.others.hide") : t("quickfill.others")),
|
|
1311
|
+
showOthers ? h(
|
|
1312
|
+
"div",
|
|
1313
|
+
{ style: { display: "flex", flexDirection: "column", gap: 8 } },
|
|
1314
|
+
h(Select, {
|
|
1315
|
+
value: selectedProvider,
|
|
1316
|
+
options: providers.map((provider) => ({ value: provider.id, label: `${provider.name} (${provider.id})` })),
|
|
1317
|
+
onChange: (value) => {
|
|
1318
|
+
setSelectedProvider(value);
|
|
1319
|
+
const provider = providers.find((item) => item.id === value);
|
|
1320
|
+
setSelectedModel(provider?.models[0]?.id ?? "");
|
|
1321
|
+
}
|
|
1322
|
+
}),
|
|
1323
|
+
current === void 0 ? null : h(Select, {
|
|
1324
|
+
value: selectedModel,
|
|
1325
|
+
options: current.models.map((model) => ({ value: model.id, label: model.name })),
|
|
1326
|
+
onChange: setSelectedModel
|
|
1327
|
+
}),
|
|
1328
|
+
current === void 0 ? null : h(KV, {
|
|
1329
|
+
items: [
|
|
1330
|
+
["provider", current.coreProvider],
|
|
1331
|
+
["baseURL", current.baseURL === "" ? t("label.optional") : current.baseURL],
|
|
1332
|
+
["credential", current.credential.ref ?? "—"],
|
|
1333
|
+
["mode", t(`quickfill.mode.${current.credential.mode}`)]
|
|
1334
|
+
]
|
|
1335
|
+
}),
|
|
1336
|
+
h(Btn, { variant: "primary", small: true, disabled: applying !== null || selectedModel === "", onClick: () => void applySelected() }, applying === "selected" ? t("quickfill.applying") : t("quickfill.apply"))
|
|
1337
|
+
) : null
|
|
1338
|
+
)
|
|
1121
1339
|
),
|
|
1122
1340
|
h(
|
|
1123
1341
|
"div",
|
|
1124
1342
|
{ className: "dshgt-footer", style: { justifyContent: "flex-end" } },
|
|
1125
|
-
h(Btn, { onClick: props.onClose }, t("quickfill.close"))
|
|
1126
|
-
h(Btn, { variant: "primary", disabled: applying || current === void 0 || selectedModel === "", onClick: () => void apply2() }, t("quickfill.apply"))
|
|
1343
|
+
h(Btn, { onClick: props.onClose }, t("quickfill.close"))
|
|
1127
1344
|
)
|
|
1128
1345
|
)
|
|
1129
1346
|
);
|
|
@@ -1165,6 +1382,7 @@ function RunsView(props) {
|
|
|
1165
1382
|
return h("div", { className: "dshgt-root" }, h("p", { className: "dshgt-hint" }, store.error ?? t("quickfill.loading")));
|
|
1166
1383
|
}
|
|
1167
1384
|
const running = state.status.running !== null;
|
|
1385
|
+
const pendingPr = state.status.pendingPr;
|
|
1168
1386
|
const shown = summary;
|
|
1169
1387
|
const lastRecord = state.status.history[0] === void 0 ? null : state.status.history[0];
|
|
1170
1388
|
const last = shown === null ? lastRecord : { ...lastRecord, ...shown, at: (/* @__PURE__ */ new Date()).toISOString(), model: { provider: state.settings.model.provider, model: state.settings.model.model } };
|
|
@@ -1198,6 +1416,12 @@ function RunsView(props) {
|
|
|
1198
1416
|
h(Toggle, { checked: dryRun, label: t("run.dryRun"), onChange: setDryRun }),
|
|
1199
1417
|
running || busy ? h(Btn, { variant: "danger", onClick: () => void cancel() }, t("run.cancel")) : null
|
|
1200
1418
|
),
|
|
1419
|
+
pendingPr === null ? null : h(
|
|
1420
|
+
Alert,
|
|
1421
|
+
{ kind: "warn", title: t("run.pendingPr") },
|
|
1422
|
+
h("div", null, h("a", { href: pendingPr.url, target: "_blank", rel: "noreferrer" }, pendingPr.url)),
|
|
1423
|
+
h("div", { className: "dshgt-hint" }, t("run.pendingPr.hint"))
|
|
1424
|
+
),
|
|
1201
1425
|
error === null ? null : h(Alert, { kind: "err" }, error),
|
|
1202
1426
|
h(
|
|
1203
1427
|
"ul",
|
|
@@ -1283,46 +1507,27 @@ function HistoryTable(props) {
|
|
|
1283
1507
|
);
|
|
1284
1508
|
}
|
|
1285
1509
|
|
|
1286
|
-
// client/
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
const
|
|
1291
|
-
if (state === null) {
|
|
1292
|
-
return h("div", { className: "dshgt-widget dshgt-root" }, h("h4", null, t("widget.title")), h("span", { className: "dshgt-hint" }, store.error ?? t("quickfill.loading")));
|
|
1293
|
-
}
|
|
1294
|
-
const running = state.status.running !== null;
|
|
1295
|
-
const last = state.status.lastResult;
|
|
1296
|
-
const coreKind = state.core.state === "ready" ? "ok" : state.core.state === "incompatible" ? "warn" : "err";
|
|
1297
|
-
const run = async (dryRun) => {
|
|
1298
|
-
setBusy(true);
|
|
1299
|
-
try {
|
|
1300
|
-
await apiCall("POST", "/run", { dryRun });
|
|
1301
|
-
await store.refresh({ quiet: true });
|
|
1302
|
-
} catch {
|
|
1303
|
-
} finally {
|
|
1304
|
-
setBusy(false);
|
|
1305
|
-
}
|
|
1306
|
-
};
|
|
1510
|
+
// client/panel-icon.ts
|
|
1511
|
+
var TREND_LINE = "3 16.5 9 10.5 13 14.5 21 6.5";
|
|
1512
|
+
var TREND_ARROW = "15.5 6.5 21 6.5 21 12";
|
|
1513
|
+
function SidebarPanelIcon(props) {
|
|
1514
|
+
const size = typeof props.size === "number" ? props.size : 16;
|
|
1307
1515
|
return h(
|
|
1308
|
-
"
|
|
1309
|
-
{
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
h(Btn, { small: true, disabled: busy || running, onClick: () => void run(true) }, t("run.dryRun")),
|
|
1324
|
-
props.onOpen === void 0 ? null : h(Btn, { small: true, onClick: props.onOpen }, t("widget.open"))
|
|
1325
|
-
)
|
|
1516
|
+
"svg",
|
|
1517
|
+
{
|
|
1518
|
+
width: size,
|
|
1519
|
+
height: size,
|
|
1520
|
+
viewBox: "0 0 24 24",
|
|
1521
|
+
fill: "none",
|
|
1522
|
+
stroke: "currentColor",
|
|
1523
|
+
strokeWidth: props.active === true ? 2 : 1.7,
|
|
1524
|
+
strokeLinecap: "round",
|
|
1525
|
+
strokeLinejoin: "round",
|
|
1526
|
+
"aria-hidden": "true",
|
|
1527
|
+
focusable: "false"
|
|
1528
|
+
},
|
|
1529
|
+
h("polyline", { points: TREND_LINE }),
|
|
1530
|
+
h("polyline", { points: TREND_ARROW })
|
|
1326
1531
|
);
|
|
1327
1532
|
}
|
|
1328
1533
|
|
|
@@ -1336,7 +1541,6 @@ function apply(ctx) {
|
|
|
1336
1541
|
const t = buildTranslate(locale);
|
|
1337
1542
|
const disposeStyles = injectStyles();
|
|
1338
1543
|
const disposers = [];
|
|
1339
|
-
const layout = ctx.get?.("layout");
|
|
1340
1544
|
const pickDirectory = async () => {
|
|
1341
1545
|
const workspace = ctx.get?.("uiWorkspace");
|
|
1342
1546
|
return workspace?.pickDirectory?.();
|
|
@@ -1344,44 +1548,44 @@ function apply(ctx) {
|
|
|
1344
1548
|
function store() {
|
|
1345
1549
|
return useStore();
|
|
1346
1550
|
}
|
|
1347
|
-
function
|
|
1348
|
-
const value = store();
|
|
1349
|
-
return h(SettingsView, { t, store: value, pickDirectory, ...props?.close === void 0 ? {} : { onClose: props.close } });
|
|
1350
|
-
}
|
|
1351
|
-
function RunsSurface() {
|
|
1352
|
-
const value = store();
|
|
1353
|
-
return h(RunsView, { t, store: value, page: true });
|
|
1354
|
-
}
|
|
1355
|
-
function SidebarWidget() {
|
|
1551
|
+
function PanelView() {
|
|
1356
1552
|
const value = store();
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
"
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1553
|
+
const [tab, setTab] = import_react.default.useState("runs");
|
|
1554
|
+
const tabButton = (id, label) => h(
|
|
1555
|
+
"button",
|
|
1556
|
+
{
|
|
1557
|
+
type: "button",
|
|
1558
|
+
className: "dshgt-tab",
|
|
1559
|
+
role: "tab",
|
|
1560
|
+
"aria-selected": tab === id ? "true" : "false",
|
|
1561
|
+
onClick: () => setTab(id)
|
|
1562
|
+
},
|
|
1563
|
+
label
|
|
1564
|
+
);
|
|
1565
|
+
return h(
|
|
1566
|
+
"div",
|
|
1567
|
+
{ className: "dshgt-root dshgt-shell" },
|
|
1568
|
+
h(
|
|
1569
|
+
"div",
|
|
1570
|
+
{ className: "dshgt-tabs", role: "tablist" },
|
|
1571
|
+
tabButton("runs", t("tab.runs")),
|
|
1572
|
+
tabButton("settings", t("tab.settings"))
|
|
1573
|
+
),
|
|
1574
|
+
h(
|
|
1575
|
+
"div",
|
|
1576
|
+
{ className: "dshgt-content" },
|
|
1577
|
+
tab === "settings" ? h(SettingsView, { t, store: value, pickDirectory }) : h("div", { className: "dshgt-scroll" }, h(RunsView, { t, store: value, page: true }))
|
|
1374
1578
|
)
|
|
1375
|
-
)
|
|
1376
|
-
|
|
1579
|
+
);
|
|
1580
|
+
}
|
|
1377
1581
|
disposers.push(
|
|
1378
1582
|
slots.inject("main", () => {
|
|
1379
|
-
const disposeMain = slots.register({ name: "main", key: PANEL_ID },
|
|
1583
|
+
const disposeMain = slots.register({ name: "main", key: PANEL_ID }, PanelView);
|
|
1380
1584
|
const disposeEntry = slots.inject(
|
|
1381
1585
|
"sidebar.panellist",
|
|
1382
1586
|
() => slots.register(
|
|
1383
1587
|
{ name: "sidebar.panellist", id: PANEL_ID, order: 40, label: () => t("section.title") },
|
|
1384
|
-
|
|
1588
|
+
SidebarPanelIcon
|
|
1385
1589
|
)
|
|
1386
1590
|
);
|
|
1387
1591
|
return [disposeMain, disposeEntry];
|