@morehao/dsh-github-trending 0.5.0 → 0.5.2

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 CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [v0.5.2] - 2026-10-31
4
+
5
+ ### 修复
6
+
7
+ - **代理模式下订阅页无法增删仓库**:`mode=proxy` 的设置里 `baseURL` 为空(运行期由回环代理注入),但核心 `config.Load` 仍按必填校验,订阅命令直接报 `config invalid: baseURL为必填字段`。现在生成订阅临时配置时补一个回环占位端点(订阅命令不调用模型),`list` / `add` / `remove` 恢复正常。
8
+ - **概览 Token 用量 / 发版订阅速览块排版错乱**:v0.5.0 新增的 `.dshgt-glance-*` 等类名没有对应样式,标签与数值挤成一行。补齐两张速览卡的布局;无用量 / 无发版数据时整卡隐藏,不再铺一排「—」。
9
+ - **运行记录 token 列错位**:行网格未给 token 列预留宽度,有 token 的记录会把文件数、耗时挤到错误列。按有无 token 切换列模板,窄屏同步适配;顺带补上发版明细与订阅页缺失的样式。
10
+
11
+ ## [v0.5.1] - 2026-10-31
12
+
13
+ ### 变更
14
+
15
+ - **设置页字段改用 `?` 悬浮说明**:「摘要与用量」「发版订阅」两个分区的每个字段旁加问号(鼠标悬停或键盘聚焦展开),并移除两张卡片底部的整段说明文字。
16
+ - **发版订阅常开**:移除 `releases.enabled` 开关(设置页不再有「启用发版订阅」),写入核心配置时恒为 `true`;是否有产出只由订阅列表决定,列表为空时不产出、榜单产物不变。「订阅」页同步去掉开关状态提示。
17
+
18
+ ### 修复
19
+
20
+ - **设置页操作回执自动收起**:保存 / 导入成功提示 5 秒后自动消失;失败提示保留到下一次操作。
21
+
3
22
  ## [v0.5.0] - 2026-10-31
4
23
 
5
24
  ### 新增
package/README.md CHANGED
@@ -48,16 +48,16 @@ dsh plugin --profile <profile> add @morehao/dsh-github-trending
48
48
  - 「本次任务总量」= 榜单摘要阶段(`usage.totalTokens`)+ 发版订阅阶段(`releases.usage.totalTokens`),**订阅消耗计入总量**。
49
49
  - 累计 = 历史里全部运行 `tokens` 之和,**读时求和、不落盘**(`history.json` 只存每次的 `tokens`)。
50
50
  - 插件**不做费用估算、不内置定价表**(价格随 provider / 区域变动,易过期):只展示核心回报的 token 真值。
51
- - 展示位置:概览速览块(本次 / 累计 / 新发版 / 订阅仓库数)、运行记录(每行本次 tokens、展开明细、页脚累计)、历史。数据来自契约 `Usage`。旧核心无 `usage` / `releases` 时整块显示「—」并隐藏,绝不伪造 0。
51
+ - 展示位置:概览速览块(本次 / 累计 / 新发版 / 订阅仓库数)、运行记录(每行本次 tokens、展开明细、页脚累计)、历史。数据来自契约 `Usage`。旧核心无 `usage` / `releases` 时对应速览块整体隐藏(不铺「—」、不伪造 0)。
52
52
 
53
53
  ## 发版订阅
54
54
 
55
- - 订阅一组仓库,之后每次运行把每个仓库「**新增的 Release**(无 Release 时回退 Tag)」写成中文 changelog,渲染到 `<output.dir>/releases/`,与榜单**同分支、同 PR** 一起提交。默认 `releases.enabled=false` 旁路,不改变既有榜单产物(逐字节不变)。
55
+ - 订阅一组仓库,之后每次运行把每个仓库「**新增的 Release**(无 Release 时回退 Tag)」写成中文 changelog,渲染到 `<output.dir>/releases/`,与榜单**同分支、同 PR** 一起提交。发版阶段**常开**;没有订阅时不产出,既有榜单产物逐字节不变。
56
56
  - **订阅列表随数据仓版本化**:文件在 `<repo>/<OutputRoot(output.dir)>/subscriptions.yaml`,随产物同一次 commit / PR,可审计、可复现。
57
- - **插件不直接写仓**:列表经核心 `subscribe` IPC 命令读改——`add` / `remove` 只写 `.git/trendradar-subscriptions.pending`,下一次 `run` 切分支后落盘并随 artifact 提交。插件侧的子进程只做一次 stdin 交互:`RunRequest{command:"subscribe", action, repo?, configPath}`,`list` 的仓库由核心 stdout 逐行返回后插件解析。`configPath` 由插件生成(与 `run` 同源的临时配置),保证 `subscribe` 与 `run` 解析到同一个订阅文件。
58
- - 界面:「订阅」页管理列表(增删 / 开关状态提示);「设置 → 发版订阅」分区放行为开关(`enabled` / 含预发布 / 含草稿 / notes 截断),以及「管理订阅列表 →」入口。
57
+ - **插件不直接写仓**:列表经核心 `subscribe` IPC 命令读改——`add` / `remove` 只写 `.git/trendradar-subscriptions.pending`,下一次 `run` 切分支后落盘并随 artifact 提交。插件侧的子进程只做一次 stdin 交互:`RunRequest{command:"subscribe", action, repo?, configPath}`,`list` 的仓库由核心 stdout 逐行返回后插件解析。`configPath` 由插件生成(与 `run` 同源的临时配置),保证 `subscribe` 与 `run` 解析到同一个订阅文件;代理模式下 `model.baseURL` 为空,临时配置补一个回环占位端点以通过核心 `config.Load`(订阅命令不调用模型)。
58
+ - 界面:「订阅」页管理列表(增删);「设置 → 发版订阅」分区放行为参数(含预发布 / 含草稿 / notes 截断,字段旁 `?` 悬浮说明),以及「管理订阅列表 →」入口。
59
59
  - 周期独立:`releases.period` 默认 `daily`,不与 `trending.since` 联动。
60
- - 历史里每条运行记录带 `releases` 摘要(仓库数 / 新发版 / 已摘要 / 降级 / 失败 / 跳过)与本次 `tokens`;旧核心或 `enabled=false` 时缺省。
60
+ - 历史里每条运行记录带 `releases` 摘要(仓库数 / 新发版 / 已摘要 / 降级 / 失败 / 跳过)与本次 `tokens`;旧核心没有 `releases` 块时缺省。
61
61
 
62
62
 
63
63
 
@@ -115,8 +115,7 @@ dsh plugin --profile <profile> add @morehao/dsh-github-trending
115
115
  | `summarize.batchSize` / `maxRetries` | `10` / `1` | 摘要批量与失败重试(映射核心 `summarize.*`) |
116
116
  | `summarize.enrich` | `none` | `none` / `repo` / `readme`:是否抓取 GitHub topics / README 作为增强上下文;`repo`/`readme` 建议配只读 `GITHUB_READ_TOKEN` |
117
117
  | `summarize.readmeChars` | `800` | README 摘录长度(enrich=readme 时) |
118
- | `releases.enabled` | `false` | 是否启用发版订阅阶段;`false` 时既有榜单产物逐字节不变 |
119
- | `releases.includePrerelease` / `includeDrafts` | `false` / `false` | 是否含预发布 / 草稿 |
118
+ | `releases.includePrerelease` / `includeDrafts` | `false` / `false` | 是否含预发布 / 草稿(发版阶段常开,不提供 `enabled` 开关) |
120
119
  | `releases.fallbackToTags` / `baselineOnFirstRun` | `true` / `true` | 无 Release 时回退 Tag / 首次只记基线 |
121
120
  | `releases.perRepoLimit` / `maxNotesChars` | `5` / `4000` | 每仓单次上限(1–20)/ notes 截断(500–20000) |
122
121
  | `releases.period` | `daily` | 发版摘要周期(独立,不与 `trending.since` 联动) |
package/client.js CHANGED
@@ -393,30 +393,28 @@ var DICT = {
393
393
  "card.summarize.title": "摘要与用量",
394
394
  "card.summarize.hint": "对应核心 summarize.*(core 0.4.1+)",
395
395
  "summarize.batchSize": "批量大小",
396
+ "summarize.batchSize.help": "每次模型调用处理的仓库数;批次越大速度越快,单次提示词也越长。",
396
397
  "summarize.maxRetries": "失败重试",
398
+ "summarize.maxRetries.help": "单批摘要失败后的额外重试次数;0 表示不重试,仍失败按降级策略处理。",
397
399
  "summarize.enrich": "外部增强",
400
+ "summarize.enrich.help": "摘要前补充外部上下文:repo 抓取 GitHub topics,readme 再摘录 README;需要只读 token。",
398
401
  "summarize.enrich.none": "不增强",
399
402
  "summarize.enrich.repo": "仓库(含 GitHub topics)",
400
403
  "summarize.enrich.readme": "仓库(含 README 摘录)",
401
404
  "summarize.readmeChars": "README 摘录长度",
405
+ "summarize.readmeChars.help": "enrich 为 readme 时,每个仓库 README 摘录的最大字符数(超出截断)。",
402
406
  "summarize.enrichNote": "外部增强需要只读 token:enrich=repo/readme 建议配置 GITHUB_READ_TOKEN(独立只读);readme 模式在网络慢时可能因预算耗尽跳过部分仓库(自动降级,不影响运行)。",
403
- "summarize.usageNote": "用量展示在「运行记录 + 历史」,本页只放摘要生成参数。插件不做费用估算、不内置定价表(价格随 provider/区域变动):Usage 的 token 真值直接展示在运行结果与历史。",
404
407
  "card.releases.title": "发版订阅",
405
408
  "card.releases.hint": "对应核心 releases.*(core 0.5.0+)",
406
- "releases.enabled": "启用发版订阅",
407
- "releases.enabled.hint": "保存后与 trending 合并进同一分支/PR",
408
409
  "releases.includePrerelease": "含预发布",
410
+ "releases.includePrerelease.help": "GitHub 上标记为 pre-release 的版本也计入新发版。",
409
411
  "releases.includeDrafts": "含草稿",
412
+ "releases.includeDrafts.help": "草稿(draft)Release 也计入;草稿只有写权限的 token 才看得到。",
410
413
  "releases.notesChars": "notes 截断",
414
+ "releases.notesChars.help": "单个 Release notes 的截断长度,避免提示词过长(500–20000)。",
411
415
  "releases.manage": "管理订阅列表 →",
412
- "releases.note": "订阅列表不在此卡片编辑,跳到「订阅」页管理;列表在数据仓 <output.dir>/subscriptions.yaml,随产物版本化。",
413
416
  "subs.title": "仓库发版订阅",
414
- "subs.desc": "订阅后,每次运行会把每个仓库「新增的 Release(无 Release 时回退 Tag)」写成中文 changelog,渲染到 <output.dir>/releases/,与榜单同分支同 PR。默认 enabled=false 旁路,不改变既有榜单产物。",
415
- "subs.enabled": "订阅开关:{state}",
416
- "subs.on": "已开启",
417
- "subs.off": "未开启",
418
- "subs.disabled.title": "发版订阅当前关闭",
419
- "subs.disabled.hint": "在设置页「发版订阅」分区打开后,订阅列表才会在运行中生效。",
417
+ "subs.desc": "订阅后,每次运行会把每个仓库「新增的 Release(无 Release 时回退 Tag)」写成中文 changelog,渲染到 <output.dir>/releases/,与榜单同分支同 PR;没有订阅时不产出、也不改动榜单产物。",
420
418
  "subs.add": "添加仓库",
421
419
  "subs.add.hint": "添加订阅(owner/repo,一个或多个,逗号/空格分隔)",
422
420
  "subs.add.placeholder": "denoland/deno",
@@ -801,30 +799,28 @@ var DICT = {
801
799
  "card.summarize.title": "Summary & usage",
802
800
  "card.summarize.hint": "Maps to core summarize.* (core 0.4.1+)",
803
801
  "summarize.batchSize": "Batch size",
802
+ "summarize.batchSize.help": "Repos per model call; larger batches run faster but make each prompt longer.",
804
803
  "summarize.maxRetries": "Retries",
804
+ "summarize.maxRetries.help": "Extra retries per failed batch; 0 disables retry, and a batch that still fails follows the degrade policy.",
805
805
  "summarize.enrich": "Enrich",
806
+ "summarize.enrich.help": "Adds external context before summarizing: repo fetches GitHub topics, readme also excerpts the README. Requires a read-only token.",
806
807
  "summarize.enrich.none": "None",
807
808
  "summarize.enrich.repo": "Repo (+GitHub topics)",
808
809
  "summarize.enrich.readme": "Repo (+README excerpt)",
809
810
  "summarize.readmeChars": "README excerpt chars",
811
+ "summarize.readmeChars.help": "Max README characters excerpted per repo when enrich=readme (longer text is truncated).",
810
812
  "summarize.enrichNote": "Enrich needs a read-only token: enrich=repo/readme is best paired with GITHUB_READ_TOKEN (separate, read-only). In readme mode slow networks may skip some repos when the budget runs out (auto-degrades; the run is unaffected).",
811
- "summarize.usageNote": "Usage is shown on Runs + History; this page only holds summary-generation parameters. The plugin does no cost estimation and ships no price list (prices vary by provider/region): the Usage token truth is shown directly in run results and history.",
812
813
  "card.releases.title": "Releases",
813
814
  "card.releases.hint": "Maps to core releases.* (core 0.5.0+)",
814
- "releases.enabled": "Enable releases",
815
- "releases.enabled.hint": "Saved alongside trending into the same branch/PR",
816
815
  "releases.includePrerelease": "Include pre-releases",
816
+ "releases.includePrerelease.help": "Releases marked as pre-release on GitHub also count as new releases.",
817
817
  "releases.includeDrafts": "Include drafts",
818
+ "releases.includeDrafts.help": "Draft releases also count; drafts are only visible to tokens with write access.",
818
819
  "releases.notesChars": "Notes truncate",
820
+ "releases.notesChars.help": "Truncate each release notes to this length to keep prompts bounded (500–20000).",
819
821
  "releases.manage": "Manage subscriptions →",
820
- "releases.note": "The subscription list is not edited on this card; manage it on the Subscriptions page. The list lives in the data repo at <output.dir>/subscriptions.yaml, versioned with artifacts.",
821
822
  "subs.title": "Repo release subscriptions",
822
- "subs.desc": "Once subscribed, each run writes every repo's new releases (falling back to tags) as a Chinese changelog rendered under <output.dir>/releases/, in the same branch/PR as the board. enabled=false bypasses it by default and leaves existing board artifacts unchanged.",
823
- "subs.enabled": "Subscriptions: {state}",
824
- "subs.on": "On",
825
- "subs.off": "Off",
826
- "subs.disabled.title": "Releases are currently off",
827
- "subs.disabled.hint": "Turn on Releases in the settings page; the subscription list only takes effect during a run after that.",
823
+ "subs.desc": "Once subscribed, each run writes every repo's new releases (falling back to tags) as a Chinese changelog rendered under <output.dir>/releases/, in the same branch/PR as the board. With no subscriptions the stage produces nothing and leaves board artifacts untouched.",
828
824
  "subs.add": "Add repo",
829
825
  "subs.add.hint": "Add subscriptions (owner/repo, one or more, comma/space separated)",
830
826
  "subs.add.placeholder": "denoland/deno",
@@ -906,7 +902,13 @@ var CSS = `
906
902
  .dshgt-hint{color:var(--gt-muted);font-size:12px;}
907
903
  .dshgt-desc{margin:0;color:var(--gt-muted);font-size:12px;}
908
904
  .dshgt-row{display:flex;gap:10px;align-items:center;min-height:28px;flex-wrap:wrap;}
909
- .dshgt-row>label.dshgt-label{width:96px;color:var(--gt-muted);flex:none;font-size:12px;}
905
+ .dshgt-row>label.dshgt-label{width:96px;color:var(--gt-muted);flex:none;font-size:12px;display:flex;align-items:flex-start;gap:5px;}
906
+ .dshgt-label-text{flex:1;min-width:0;}
907
+ /* 字段说明:圆问号 + 纯 CSS 悬浮气泡(::after 读 data-tip),键盘聚焦同样展开。 */
908
+ .dshgt-help{position:relative;flex:none;margin-top:2px;width:14px;height:14px;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--gt-border);border-radius:50%;background:var(--gt-bg);color:var(--gt-muted);font-size:10px;line-height:1;font-weight:600;cursor:help;user-select:none;outline:none;}
909
+ .dshgt-help:hover,.dshgt-help:focus-visible{color:var(--gt-fg);border-color:color-mix(in srgb,var(--gt-accent) 55%,var(--gt-border));}
910
+ .dshgt-help::after{content:attr(data-tip);position:absolute;left:0;top:calc(100% + 7px);z-index:30;width:max-content;max-width:280px;padding:7px 9px;border-radius:8px;background:var(--dsw-alias-bg-layer-2,var(--gt-card));color:var(--gt-fg);border:1px solid var(--gt-border);font-size:12px;font-weight:400;line-height:1.55;letter-spacing:0;text-align:left;white-space:normal;overflow-wrap:break-word;box-shadow:0 10px 26px rgba(0,0,0,.28);opacity:0;visibility:hidden;pointer-events:none;transition:opacity .12s ease,visibility .12s;}
911
+ .dshgt-help:hover::after,.dshgt-help:focus-visible::after{opacity:1;visibility:visible;}
910
912
  .dshgt-inline{display:flex;gap:8px;align-items:center;flex-wrap:wrap;}
911
913
  .dshgt-input,.dshgt-select,.dshgt-textarea{font:inherit;color:inherit;background:var(--gt-bg);border:1px solid var(--gt-border);border-radius:7px;padding:5px 8px;min-width:0;}
912
914
  .dshgt-input:focus,.dshgt-select:focus,.dshgt-textarea:focus{outline:2px solid color-mix(in srgb,var(--gt-accent) 35%,transparent);outline-offset:1px;}
@@ -1056,6 +1058,7 @@ var CSS = `
1056
1058
  .dshgt-fact-k{font-size:11.5px;color:var(--gt-muted);margin-bottom:2px;}
1057
1059
  .dshgt-fact-v{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
1058
1060
  .dshgt-block{display:flex;flex-direction:column;gap:8px;}
1061
+ .dshgt-block > .dshgt-btn{align-self:flex-start;}
1059
1062
  .dshgt-section-label{display:flex;align-items:center;gap:9px;font-size:12px;color:var(--gt-muted);letter-spacing:.02em;}
1060
1063
  .dshgt-section-label:after{content:"";height:1px;flex:1;background:color-mix(in srgb,var(--gt-border) 70%,transparent);}
1061
1064
  .dshgt-section-tail{margin-left:auto;font-size:11.5px;color:var(--gt-muted);}
@@ -1145,6 +1148,19 @@ var CSS = `
1145
1148
  .dshgt-overview-seg{margin-bottom:8px;}
1146
1149
  .dshgt-overview-empty{padding:14px 2px;}
1147
1150
 
1151
+ /* 概览用量速览:Token / 发版两张卡,每卡两格;无数据时整卡不渲染。 */
1152
+ .dshgt-usage-glance{gap:8px;}
1153
+ .dshgt-glance-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px;}
1154
+ .dshgt-glance{border:1px solid var(--gt-border);border-radius:12px;padding:14px 16px 13px;background:var(--gt-card);display:flex;flex-direction:column;gap:10px;min-width:0;}
1155
+ .dshgt-glance-k{font-size:12px;color:var(--gt-muted);letter-spacing:.02em;}
1156
+ .dshgt-glance-vs{display:flex;gap:30px;flex-wrap:wrap;}
1157
+ .dshgt-glance-cell{display:flex;flex-direction:column;gap:2px;min-width:0;}
1158
+ .dshgt-glance-label{font-size:12px;color:var(--gt-muted);}
1159
+ .dshgt-glance-val{display:flex;align-items:baseline;gap:5px;min-width:0;}
1160
+ .dshgt-glance-num{font-size:22px;line-height:1.2;font-weight:650;letter-spacing:-.015em;color:var(--gt-fg);font-variant-numeric:tabular-nums;white-space:nowrap;}
1161
+ .dshgt-glance-unit{font-size:11.5px;color:var(--gt-muted);}
1162
+ .dshgt-glance-note{margin:0;}
1163
+
1148
1164
  /* ——— 运行记录 ——— */
1149
1165
  .dshgt-runs-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap;}
1150
1166
  .dshgt-runs-filter{display:flex;gap:4px;margin-left:auto;}
@@ -1156,6 +1172,8 @@ var CSS = `
1156
1172
  .dshgt-run-what{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px;}
1157
1173
  .dshgt-run-muted{color:var(--gt-muted);font-size:12px;margin-left:6px;}
1158
1174
  .dshgt-run-files,.dshgt-run-duration{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;color:var(--gt-muted);text-align:right;}
1175
+ .dshgt-run-tokens{font-size:11.5px;color:var(--gt-muted);text-align:right;white-space:nowrap;}
1176
+ .dshgt-run-item.has-tokens .dshgt-run-row{grid-template-columns:18px 120px 56px minmax(0,1fr) 64px 78px 74px 20px;}
1159
1177
  .dshgt-run-chev{color:var(--gt-muted);text-align:center;transition:transform .15s;}
1160
1178
  .dshgt-run-item.open .dshgt-run-chev{transform:rotate(90deg);}
1161
1179
  .dshgt-run-detail{padding:2px 6px 16px 30px;display:flex;flex-direction:column;gap:10px;}
@@ -1165,6 +1183,11 @@ var CSS = `
1165
1183
  .dshgt-detail-v a{color:var(--gt-accent);text-decoration:none;}
1166
1184
  .dshgt-detail-v a:hover{text-decoration:underline;}
1167
1185
  .dshgt-run-actions{display:flex;align-items:center;gap:10px;flex-wrap:wrap;}
1186
+ .dshgt-releases-detail{padding-top:10px;border-top:1px solid color-mix(in srgb,var(--gt-border) 70%,transparent);}
1187
+ .dshgt-releases-stats{display:flex;flex-wrap:wrap;gap:6px 20px;}
1188
+ .dshgt-releases-stat{display:inline-flex;align-items:baseline;gap:6px;}
1189
+ .dshgt-releases-stat .dshgt-hint{font-size:11.5px;}
1190
+ .dshgt-runs-foot{padding:4px 2px 0;text-align:right;}
1168
1191
 
1169
1192
  /* ——— 日志抽屉 / 关于 ——— */
1170
1193
  .dshgt-log-modal{max-width:820px;width:calc(100% - 32px);}
@@ -1197,6 +1220,20 @@ var CSS = `
1197
1220
  .dshgt-about-status.err{color:var(--gt-err);}
1198
1221
  .dshgt-about-actions{display:flex;align-items:center;gap:8px;flex:none;}
1199
1222
 
1223
+ /* ——— 订阅 ——— */
1224
+ .dshgt-subs-card{gap:10px;}
1225
+ .dshgt-subs-head{display:flex;align-items:center;gap:12px;flex-wrap:wrap;}
1226
+ .dshgt-subs-head h2{margin:0;font-size:15px;font-weight:600;}
1227
+ .dshgt-subs-head-actions{margin-left:auto;display:flex;gap:8px;}
1228
+ .dshgt-subs-list{border-top:1px solid var(--gt-border);}
1229
+ .dshgt-subs-row{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:12px;min-height:44px;padding:0 4px;border-bottom:1px solid color-mix(in srgb,var(--gt-border) 70%,transparent);}
1230
+ .dshgt-subs-row-head{min-height:30px;font-size:11.5px;color:var(--gt-muted);}
1231
+ .dshgt-subs-repo{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12.5px;}
1232
+ .dshgt-subs-actions{display:flex;justify-content:flex-end;gap:6px;}
1233
+ .dshgt-subs-add{border:1px dashed var(--gt-border);border-radius:10px;padding:10px 12px;background:color-mix(in srgb,var(--gt-fg) 2%,var(--gt-bg));display:flex;flex-direction:column;gap:7px;}
1234
+ .dshgt-subs-add-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;}
1235
+ .dshgt-subs-add .dshgt-input{max-width:100%;}
1236
+
1200
1237
  @media (max-width:1100px){
1201
1238
  .dshgt-app{grid-template-columns:190px minmax(0,1fr);}
1202
1239
  .dshgt-page-head{padding:18px 22px 12px;}
@@ -1206,6 +1243,7 @@ var CSS = `
1206
1243
  .dshgt-week{flex-wrap:wrap;}
1207
1244
  .dshgt-day{flex:1 1 88px;}
1208
1245
  .dshgt-run-row{grid-template-columns:18px 104px 52px minmax(0,1fr) 70px 20px;}
1246
+ .dshgt-run-item.has-tokens .dshgt-run-row{grid-template-columns:18px 104px 52px minmax(0,1fr) 58px 70px 20px;}
1209
1247
  .dshgt-run-files{display:none;}
1210
1248
  .dshgt-detail-grid{grid-template-columns:repeat(2,minmax(0,1fr));}
1211
1249
  .dshgt-dateselect{min-width:180px;}
@@ -1248,11 +1286,29 @@ function Card(props) {
1248
1286
  children
1249
1287
  );
1250
1288
  }
1289
+ function Help(props) {
1290
+ return h(
1291
+ "span",
1292
+ {
1293
+ className: "dshgt-help",
1294
+ tabIndex: 0,
1295
+ role: "note",
1296
+ "aria-label": props.text,
1297
+ "data-tip": props.text
1298
+ },
1299
+ "?"
1300
+ );
1301
+ }
1251
1302
  function Row(props) {
1252
1303
  return h(
1253
1304
  "div",
1254
1305
  { className: "dshgt-row" },
1255
- props.label === void 0 ? null : h("label", { className: "dshgt-label" }, props.label),
1306
+ props.label === void 0 ? null : h(
1307
+ "label",
1308
+ { className: "dshgt-label" },
1309
+ h("span", { className: "dshgt-label-text" }, props.label),
1310
+ props.help === void 0 ? null : h(Help, { text: props.help })
1311
+ ),
1256
1312
  props.children
1257
1313
  );
1258
1314
  }
@@ -1537,6 +1593,7 @@ function sectionSlice(settings, section) {
1537
1593
  return { schedule: settings.schedule };
1538
1594
  }
1539
1595
  }
1596
+ var NOTICE_TTL_MS = 5e3;
1540
1597
  function sectionEquals(a, b, section) {
1541
1598
  return JSON.stringify(sectionSlice(a, section)) === JSON.stringify(sectionSlice(b, section));
1542
1599
  }
@@ -1553,7 +1610,7 @@ function SettingsView(props) {
1553
1610
  const [savingSection, setSavingSection] = import_react.default.useState(null);
1554
1611
  const [savedSection, setSavedSection] = import_react.default.useState(null);
1555
1612
  const [problems, setProblems] = import_react.default.useState([]);
1556
- const [message, setMessage] = import_react.default.useState(null);
1613
+ const [notice, setNotice] = import_react.default.useState(null);
1557
1614
  const [preflight, setPreflight] = import_react.default.useState(null);
1558
1615
  const [preflighting, setPreflighting] = import_react.default.useState(false);
1559
1616
  const [rechecking, setRechecking] = import_react.default.useState(false);
@@ -1572,6 +1629,14 @@ function SettingsView(props) {
1572
1629
  import_react.default.useEffect(() => {
1573
1630
  setProblems([]);
1574
1631
  }, [section]);
1632
+ import_react.default.useEffect(() => {
1633
+ if (notice === null || notice.kind !== "ok") return void 0;
1634
+ const timer = setTimeout(() => {
1635
+ setNotice((current) => current === notice ? null : current);
1636
+ }, NOTICE_TTL_MS);
1637
+ return () => clearTimeout(timer);
1638
+ }, [notice]);
1639
+ const notify = (kind, text) => setNotice({ kind, text });
1575
1640
  const repoPath = draft === null ? "" : draft.repo.path;
1576
1641
  import_react.default.useEffect(() => {
1577
1642
  if (repoPath.trim() === "") {
@@ -1622,13 +1687,13 @@ function SettingsView(props) {
1622
1687
  setDraft((current) => current === null ? current : applySection(current, result.settings, section2));
1623
1688
  setDirtySections((current) => ({ ...current, [section2]: false }));
1624
1689
  setSavedSection(section2);
1625
- setMessage(null);
1690
+ setNotice(null);
1626
1691
  await store.refresh({ quiet: true });
1627
1692
  } else {
1628
1693
  setProblems(result.problems ?? []);
1629
1694
  }
1630
1695
  } catch (error) {
1631
- setMessage(error instanceof Error ? error.message : String(error));
1696
+ notify("err", error instanceof Error ? error.message : String(error));
1632
1697
  } finally {
1633
1698
  setSavingSection(null);
1634
1699
  }
@@ -1659,13 +1724,13 @@ function SettingsView(props) {
1659
1724
  const downloadCore = async () => {
1660
1725
  setDownloading(true);
1661
1726
  setProblems([]);
1662
- setMessage(null);
1727
+ setNotice(null);
1663
1728
  try {
1664
1729
  await apiCall("POST", "/core/download", {});
1665
- setMessage(t("core.downloaded"));
1730
+ notify("ok", t("core.downloaded"));
1666
1731
  await store.refresh({ quiet: true });
1667
1732
  } catch (error) {
1668
- setMessage(error instanceof Error ? error.message : String(error));
1733
+ notify("err", error instanceof Error ? error.message : String(error));
1669
1734
  } finally {
1670
1735
  setDownloading(false);
1671
1736
  }
@@ -1695,13 +1760,13 @@ function SettingsView(props) {
1695
1760
  setDraft(payload.settings);
1696
1761
  setDirtySections({ ...EMPTY_DIRTY });
1697
1762
  setSavedSection(null);
1698
- setMessage(t("settings.import.done", { fields: payload.imported.join("、") }));
1763
+ notify("ok", t("settings.import.done", { fields: payload.imported.join("、") }));
1699
1764
  await store.refresh({ quiet: true });
1700
1765
  } else {
1701
- setMessage(payload.problems[0] ?? t("settings.import.empty"));
1766
+ notify("err", payload.problems[0] ?? t("settings.import.empty"));
1702
1767
  }
1703
1768
  } catch (error) {
1704
- setMessage(error instanceof Error ? error.message : String(error));
1769
+ notify("err", error instanceof Error ? error.message : String(error));
1705
1770
  }
1706
1771
  };
1707
1772
  const copyConfig = () => {
@@ -1711,7 +1776,7 @@ function SettingsView(props) {
1711
1776
  null,
1712
1777
  2
1713
1778
  );
1714
- void navigator.clipboard?.writeText(redacted).then(() => setMessage(t("settings.copied")));
1779
+ void navigator.clipboard?.writeText(redacted).then(() => notify("ok", t("settings.copied")));
1715
1780
  };
1716
1781
  if (state === null || draft === null) {
1717
1782
  return h("div", { className: "dshgt-root" }, h("p", { className: "dshgt-hint" }, store.error ?? t("quickfill.loading")));
@@ -1994,21 +2059,21 @@ function SettingsView(props) {
1994
2059
  { title: t("card.summarize.title"), hint: t("card.summarize.hint") },
1995
2060
  h(
1996
2061
  Row,
1997
- { label: t("summarize.batchSize") },
2062
+ { label: t("summarize.batchSize"), help: t("summarize.batchSize.help") },
1998
2063
  h(Input, { mono: true, width: 90, value: String(draft.summarize.batchSize), onInput: (value) => update((next) => {
1999
2064
  next.summarize.batchSize = Math.round(Number(value) || 0);
2000
2065
  }) })
2001
2066
  ),
2002
2067
  h(
2003
2068
  Row,
2004
- { label: t("summarize.maxRetries") },
2069
+ { label: t("summarize.maxRetries"), help: t("summarize.maxRetries.help") },
2005
2070
  h(Input, { mono: true, width: 90, value: String(draft.summarize.maxRetries), onInput: (value) => update((next) => {
2006
2071
  next.summarize.maxRetries = Math.round(Number(value) || 0);
2007
2072
  }) })
2008
2073
  ),
2009
2074
  h(
2010
2075
  Row,
2011
- { label: t("summarize.enrich") },
2076
+ { label: t("summarize.enrich"), help: t("summarize.enrich.help") },
2012
2077
  h(Select, {
2013
2078
  value: draft.summarize.enrich,
2014
2079
  options: [
@@ -2023,13 +2088,12 @@ function SettingsView(props) {
2023
2088
  ),
2024
2089
  h(
2025
2090
  Row,
2026
- { label: t("summarize.readmeChars") },
2091
+ { label: t("summarize.readmeChars"), help: t("summarize.readmeChars.help") },
2027
2092
  h(Input, { mono: true, width: 90, value: String(draft.summarize.readmeChars), onInput: (value) => update((next) => {
2028
2093
  next.summarize.readmeChars = Math.round(Number(value) || 0);
2029
2094
  }) })
2030
2095
  ),
2031
- draft.summarize.enrich === "none" ? null : h(Alert, { kind: "warn" }, h("div", null, t("summarize.enrichNote"))),
2032
- h("p", { className: "dshgt-hint" }, t("summarize.usageNote"))
2096
+ draft.summarize.enrich === "none" ? null : h(Alert, { kind: "warn" }, h("div", null, t("summarize.enrichNote")))
2033
2097
  );
2034
2098
  const releasesCard = h(
2035
2099
  Card,
@@ -2040,34 +2104,25 @@ function SettingsView(props) {
2040
2104
  },
2041
2105
  h(
2042
2106
  Row,
2043
- { label: t("releases.enabled") },
2044
- h(Toggle, { checked: draft.releases.enabled, onChange: (value) => update((next) => {
2045
- next.releases.enabled = value;
2046
- }) }),
2047
- h("span", { className: "dshgt-hint" }, t("releases.enabled.hint"))
2048
- ),
2049
- h(
2050
- Row,
2051
- { label: t("releases.includePrerelease") },
2107
+ { label: t("releases.includePrerelease"), help: t("releases.includePrerelease.help") },
2052
2108
  h(Toggle, { checked: draft.releases.includePrerelease, onChange: (value) => update((next) => {
2053
2109
  next.releases.includePrerelease = value;
2054
2110
  }) })
2055
2111
  ),
2056
2112
  h(
2057
2113
  Row,
2058
- { label: t("releases.includeDrafts") },
2114
+ { label: t("releases.includeDrafts"), help: t("releases.includeDrafts.help") },
2059
2115
  h(Toggle, { checked: draft.releases.includeDrafts, onChange: (value) => update((next) => {
2060
2116
  next.releases.includeDrafts = value;
2061
2117
  }) })
2062
2118
  ),
2063
2119
  h(
2064
2120
  Row,
2065
- { label: t("releases.notesChars") },
2121
+ { label: t("releases.notesChars"), help: t("releases.notesChars.help") },
2066
2122
  h(Input, { mono: true, width: 90, value: String(draft.releases.maxNotesChars), onInput: (value) => update((next) => {
2067
2123
  next.releases.maxNotesChars = Math.round(Number(value) || 0);
2068
2124
  }) })
2069
- ),
2070
- h("p", { className: "dshgt-hint" }, t("releases.note"))
2125
+ )
2071
2126
  );
2072
2127
  const currentCard = section === "source" ? sourceCard : section === "model" ? modelCard : section === "repo" ? repoCard : section === "auth" ? authCard : section === "scope" ? scopeCard : section === "summarize" ? summarizeCard : section === "releases" ? releasesCard : scheduleCard;
2073
2128
  return h(
@@ -2097,7 +2152,7 @@ function SettingsView(props) {
2097
2152
  { className: "dshgt-vpanel" },
2098
2153
  currentCard,
2099
2154
  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,
2100
- message === null ? null : h(Alert, { kind: "ok" }, message),
2155
+ notice === null ? null : h(Alert, { kind: notice.kind }, notice.text),
2101
2156
  h(
2102
2157
  "div",
2103
2158
  { className: "dshgt-footer" },
@@ -2607,6 +2662,28 @@ function readyRows(t, state) {
2607
2662
  }
2608
2663
  ];
2609
2664
  }
2665
+ function glanceCell(label, value, unit) {
2666
+ return h(
2667
+ "div",
2668
+ { className: "dshgt-glance-cell" },
2669
+ h("span", { className: "dshgt-glance-label" }, label),
2670
+ h(
2671
+ "span",
2672
+ { className: "dshgt-glance-val" },
2673
+ h("span", { className: "dshgt-glance-num dshgt-mono" }, value),
2674
+ unit === void 0 ? null : h("span", { className: "dshgt-glance-unit" }, unit)
2675
+ )
2676
+ );
2677
+ }
2678
+ function glanceCard(title, cells) {
2679
+ if (cells.length === 0) return null;
2680
+ return h(
2681
+ "div",
2682
+ { className: "dshgt-glance" },
2683
+ h("div", { className: "dshgt-glance-k" }, title),
2684
+ h("div", { className: "dshgt-glance-vs" }, cells)
2685
+ );
2686
+ }
2610
2687
  function OverviewView(props) {
2611
2688
  const { t, lang, store, controller } = props;
2612
2689
  const state = store.state;
@@ -2630,6 +2707,21 @@ function OverviewView(props) {
2630
2707
  const todayHasDaily = groupMap.get("daily")?.days.some((day) => day.date === today) ?? false;
2631
2708
  const showWaiting = period === "daily" && !todayHasDaily && state.schedule.enabled;
2632
2709
  const lastTarget = last === null ? void 0 : digestTarget(last, timeZone);
2710
+ const lastTokens = last?.tokens;
2711
+ const releases = last?.releases;
2712
+ const totalTokens = state.status.totalTokens;
2713
+ const tokenCells = [
2714
+ ...lastTokens === void 0 ? [] : [glanceCell(t("overview.tokens.thisRun"), formatTokens(lastTokens), "tokens")],
2715
+ ...totalTokens === void 0 ? [] : [glanceCell(t("overview.tokens.total"), formatTokens(totalTokens), "tokens")]
2716
+ ];
2717
+ const releaseCells = releases === void 0 ? [] : [
2718
+ glanceCell(t("overview.releases.new"), String(releases.newReleases)),
2719
+ glanceCell(t("overview.releases.repos"), String(releases.repos))
2720
+ ];
2721
+ const glanceCards = [
2722
+ glanceCard(t("overview.tokens.title"), tokenCells),
2723
+ glanceCard(t("overview.releases.title"), releaseCells)
2724
+ ].filter((card) => card !== null);
2633
2725
  return h(
2634
2726
  "div",
2635
2727
  { className: "dshgt-view dshgt-overview" },
@@ -2702,35 +2794,10 @@ function OverviewView(props) {
2702
2794
  h("div", { className: "dshgt-fact" }, h("div", { className: "dshgt-fact-k" }, t("overview.model")), h("div", { className: "dshgt-fact-v" }, last.model?.model ?? "—"))
2703
2795
  )
2704
2796
  ),
2705
- h(
2797
+ glanceCards.length === 0 ? null : h(
2706
2798
  "section",
2707
2799
  { className: "dshgt-block dshgt-usage-glance" },
2708
- h(
2709
- "div",
2710
- { className: "dshgt-glance-grid" },
2711
- h(
2712
- "div",
2713
- { className: "dshgt-glance" },
2714
- h("div", { className: "dshgt-glance-k" }, t("overview.tokens.title")),
2715
- h(
2716
- "div",
2717
- { className: "dshgt-glance-vs" },
2718
- h("div", { className: "dshgt-glance-cell" }, h("span", { className: "dshgt-hint" }, t("overview.tokens.thisRun")), h("span", { className: "dshgt-glance-num dshgt-mono" }, last?.tokens === void 0 ? "—" : formatTokens(last.tokens)), h("span", { className: "dshgt-hint" }, "tokens")),
2719
- h("div", { className: "dshgt-glance-cell" }, h("span", { className: "dshgt-hint" }, t("overview.tokens.total")), h("span", { className: "dshgt-glance-num dshgt-mono" }, state.status.totalTokens === void 0 ? "—" : formatTokens(state.status.totalTokens)), h("span", { className: "dshgt-hint" }, "tokens"))
2720
- )
2721
- ),
2722
- h(
2723
- "div",
2724
- { className: "dshgt-glance" },
2725
- h("div", { className: "dshgt-glance-k" }, t("overview.releases.title")),
2726
- h(
2727
- "div",
2728
- { className: "dshgt-glance-vs" },
2729
- h("div", { className: "dshgt-glance-cell" }, h("span", { className: "dshgt-hint" }, t("overview.releases.new")), h("span", { className: "dshgt-glance-num dshgt-mono" }, last?.releases === void 0 ? "—" : String(last.releases.newReleases))),
2730
- h("div", { className: "dshgt-glance-cell" }, h("span", { className: "dshgt-hint" }, t("overview.releases.repos")), h("span", { className: "dshgt-glance-num dshgt-mono" }, last?.releases === void 0 ? "—" : String(last.releases.repos)))
2731
- )
2732
- )
2733
- ),
2800
+ h("div", { className: "dshgt-glance-grid" }, glanceCards),
2734
2801
  h("p", { className: "dshgt-hint dshgt-glance-note" }, t("overview.tokens.note"))
2735
2802
  ),
2736
2803
  h(
@@ -2974,7 +3041,7 @@ function RunsView(props) {
2974
3041
  const pr = prStatus(t, state, record);
2975
3042
  return h(
2976
3043
  "div",
2977
- { className: `dshgt-run-item${open ? " open" : ""}`, key: record.id },
3044
+ { className: `dshgt-run-item${open ? " open" : ""}${record.tokens === void 0 ? "" : " has-tokens"}`, key: record.id },
2978
3045
  h(
2979
3046
  "button",
2980
3047
  {
@@ -3764,14 +3831,13 @@ function metaLine(rendered) {
3764
3831
  // client/subscriptions.ts
3765
3832
  var REPO_PATTERN = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
3766
3833
  function SubscriptionsView(props) {
3767
- const { t, store } = props;
3834
+ const { t } = props;
3768
3835
  const [repos, setRepos] = import_react.default.useState(null);
3769
3836
  const [error, setError] = import_react.default.useState(null);
3770
3837
  const [busy, setBusy] = import_react.default.useState(null);
3771
3838
  const [adding, setAdding] = import_react.default.useState(false);
3772
3839
  const [input, setInput] = import_react.default.useState("");
3773
3840
  const [note, setNote] = import_react.default.useState(null);
3774
- const enabled = store.state?.settings.releases.enabled ?? false;
3775
3841
  const load = import_react.default.useCallback(() => {
3776
3842
  setError(null);
3777
3843
  getSubscriptions().then((list2) => setRepos(list2)).catch((failure) => {
@@ -3822,12 +3888,10 @@ function SubscriptionsView(props) {
3822
3888
  h(
3823
3889
  "div",
3824
3890
  { className: "dshgt-subs-head-actions" },
3825
- h("span", { className: "dshgt-hint" }, t("subs.enabled", { state: enabled ? t("subs.on") : t("subs.off") })),
3826
3891
  h(Btn, { small: true, variant: "primary", onClick: () => setAdding(true), disabled: busy !== null || adding }, t("subs.add"))
3827
3892
  )
3828
3893
  ),
3829
3894
  h("p", { className: "dshgt-desc" }, t("subs.desc")),
3830
- enabled ? null : h(Alert, { kind: "warn", title: t("subs.disabled.title") }, h("div", null, t("subs.disabled.hint"))),
3831
3895
  error === null ? null : h(Alert, { kind: "err" }, error),
3832
3896
  note === null ? null : h(Alert, { kind: "ok" }, note),
3833
3897
  repos === null ? h("p", { className: "dshgt-hint" }, t("subs.loading")) : list.length === 0 ? h("div", { className: "dshgt-empty" }, t("subs.empty")) : h(
@@ -4420,7 +4484,7 @@ function apply(ctx) {
4420
4484
  ...digestTarget2 === void 0 ? {} : { selected: digestTarget2 },
4421
4485
  onSelect: setDigestTarget,
4422
4486
  onOpenRuns: openRuns
4423
- }) : view === "runs" ? h(RunsView, { t, store: value, controller, onOpenDigest: openDigest }) : view === "subscriptions" ? h(SubscriptionsView, { t, store: value, onOpenSettings: openSettings }) : h(SettingsView, { t, store: value, pickDirectory, onOpenSubscriptions: openSubscriptions });
4487
+ }) : view === "runs" ? h(RunsView, { t, store: value, controller, onOpenDigest: openDigest }) : view === "subscriptions" ? h(SubscriptionsView, { t, onOpenSettings: openSettings }) : h(SettingsView, { t, store: value, pickDirectory, onOpenSubscriptions: openSubscriptions });
4424
4488
  return h(
4425
4489
  "div",
4426
4490
  { className: "dshgt-root dshgt-shell" },
@@ -70,7 +70,6 @@ var DEFAULT_SETTINGS = {
70
70
  enrichBudgetSeconds: 8
71
71
  },
72
72
  releases: {
73
- enabled: false,
74
73
  includePrerelease: false,
75
74
  includeDrafts: false,
76
75
  fallbackToTags: true,
@@ -215,7 +214,6 @@ function normalizeSettings(input) {
215
214
  enrichBudgetSeconds: Math.round(num(summarize.enrichBudgetSeconds, DEFAULT_SETTINGS.summarize.enrichBudgetSeconds))
216
215
  },
217
216
  releases: {
218
- enabled: bool(releases.enabled, DEFAULT_SETTINGS.releases.enabled),
219
217
  includePrerelease: bool(releases.includePrerelease, DEFAULT_SETTINGS.releases.includePrerelease),
220
218
  includeDrafts: bool(releases.includeDrafts, DEFAULT_SETTINGS.releases.includeDrafts),
221
219
  fallbackToTags: bool(releases.fallbackToTags, DEFAULT_SETTINGS.releases.fallbackToTags),
@@ -363,7 +361,8 @@ function toCoreConfig(settings, apiKey, baseURLOverride, period) {
363
361
  enrichBudgetSeconds: settings.summarize.enrichBudgetSeconds
364
362
  },
365
363
  releases: {
366
- enabled: settings.releases.enabled,
364
+ // 发版订阅常开:插件侧不再提供开关,是否产出由订阅列表决定。
365
+ enabled: true,
367
366
  includePrerelease: settings.releases.includePrerelease,
368
367
  includeDrafts: settings.releases.includeDrafts,
369
368
  fallbackToTags: settings.releases.fallbackToTags,
@@ -3415,10 +3414,12 @@ var REPO_PATTERN2 = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
3415
3414
  function isValidRepo(repo) {
3416
3415
  return REPO_PATTERN2.test(repo.trim());
3417
3416
  }
3417
+ var SUBSCRIBE_PLACEHOLDER_BASE_URL = "http://127.0.0.1:9/v1";
3418
3418
  function writeTempConfig(settings) {
3419
3419
  const dir = mkdtempSync2(path11.join(os4.tmpdir(), "dsh-subscribe-"));
3420
3420
  const file = path11.join(dir, "config.yml");
3421
- const yaml = `${toYaml(toCoreConfig(settings, ""))}
3421
+ const placeholder = effectiveBaseURL(settings.model) === "" ? SUBSCRIBE_PLACEHOLDER_BASE_URL : void 0;
3422
+ const yaml = `${toYaml(toCoreConfig(settings, "", placeholder))}
3422
3423
  `;
3423
3424
  writeFileSync2(file, yaml, { mode: 384 });
3424
3425
  return { file, dir };
package/lib/index.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  createTrendingRunTool,
9
9
  createUpdateService,
10
10
  readPluginInfo
11
- } from "./chunk-WFCULY72.js";
11
+ } from "./chunk-6HITSHK6.js";
12
12
  import "./chunk-R7BK7SJK.js";
13
13
 
14
14
  // src/index.ts
package/lib/internal.d.ts CHANGED
@@ -262,12 +262,13 @@ interface SummarizeSettings {
262
262
  enrichBudgetSeconds: number;
263
263
  }
264
264
  /**
265
- * 发版订阅阶段的行为开关(核心 `releases.*`)。
265
+ * 发版订阅阶段的行为参数(核心 `releases.*`)。
266
+ * 阶段**常开**(`releases.enabled` 恒为 true,不出现在设置里):有没有产出只由订阅列表决定,
267
+ * 列表为空时核心不产出、不改动榜单产物。
266
268
  * **订阅列表本身不落 settings.json**:它版本化在数据仓 `<output.dir>/subscriptions.yaml`,
267
269
  * 经核心 `subscribe` IPC 读改。这里只放全局行为旋钮。
268
270
  */
269
271
  interface ReleasesSettings {
270
- enabled: boolean;
271
272
  includePrerelease: boolean;
272
273
  includeDrafts: boolean;
273
274
  fallbackToTags: boolean;
package/lib/internal.js CHANGED
@@ -25,7 +25,7 @@ import {
25
25
  subscribe_exports,
26
26
  tools_exports,
27
27
  update_exports
28
- } from "./chunk-WFCULY72.js";
28
+ } from "./chunk-6HITSHK6.js";
29
29
  import {
30
30
  exec_exports
31
31
  } from "./chunk-R7BK7SJK.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morehao/dsh-github-trending",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "GitHub 趋势日报插件:每天定时 spawn 本地 trendradar 核心,抓取 Trending、生成中文简介与总结,提交到你的仓库并自动合并 PR。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",