@morehao/dsh-github-trending 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## [v0.7.1] - 2026-11-01
4
+
5
+ > 依赖升级:`dsh.core.version` 0.7.1 → **0.8.0**,`@morehao/trendradar-contract` 0.4.0 → **0.5.0**。
6
+ > 两者均已发布(核心 `v0.8.0` / 契约 `0.5.0`)。wire 仍 `ipcSchema=2` / `digestSchema=2`。
7
+
8
+ ### 新增 — 发版单仓分析
9
+
10
+ - **订阅页重做**:一个列表 + 上方工具条(搜索 / +添加仓库 / 选择 / **生成变更分析**);
11
+ 去掉 ⌘K 命令栏、底部快捷键行与冗长说明。
12
+ - **行操作**:「触发分析」(只分析该仓)· 「查看变更」(原「变更」改名)· 「移除」。
13
+ - **生成变更分析**:`POST /releases/run`——不传 repo 跑全部,传 repo 只跑该仓;单仓按行显示
14
+ 「分析中…」,全局给结果横幅;完成后刷新列表。
15
+ - 单仓触发**不推进 `lastReleaseWeek`**(避免把本周误标已检查、导致周调度跳过),全量仍推进;
16
+ 旧核心(< 0.8.0)单仓触发降级为全量、不传 `--repo`。
17
+ - 发版运行记录新增 `scopeRepo`;并发触发由后端拒绝(409)。
18
+ - 文档抽屉(发版记录 markdown)保持不变。
19
+
3
20
  ## [v0.6.1] - 2026-11-01
4
21
 
5
22
  ### 变更
package/client.js CHANGED
@@ -454,7 +454,7 @@ var DICT = {
454
454
  "releases.budget.auto": "自动",
455
455
  "releases.budget.fixed": "指定",
456
456
  "subs.title": "订阅",
457
- "subs.desc": "输入 owner/repo 立刻知道订没订;每行带最近版本、最近总结与状态,点「变更」看每周记录。",
457
+ "subs.desc": "管理发版订阅仓库,查看每周变更记录。",
458
458
  "subs.select": "选择",
459
459
  "subs.select.done": "完成",
460
460
  "subs.cmd.placeholder": "搜索 owner/repo,或输入完整仓库名直接添加",
@@ -481,8 +481,18 @@ var DICT = {
481
481
  "subs.removed.many": "已移除 {count} 个仓库,下次运行随产物提交。",
482
482
  "subs.remove": "移除",
483
483
  "subs.removing": "移除中…",
484
- "subs.row.changes": "变更",
484
+ "subs.row.changes": "查看变更",
485
485
  "subs.row.changesRepo": "查看 {repo} 的变更",
486
+ "subs.row.trigger": "触发分析",
487
+ "subs.row.triggerRepo": "只对 {repo} 生成变更分析",
488
+ "subs.search.placeholder": "搜索仓库",
489
+ "subs.search.label": "搜索仓库",
490
+ "subs.toolbar.add": "+ 添加仓库",
491
+ "subs.toolbar.analyze": "生成变更分析",
492
+ "subs.analyzing": "分析中…",
493
+ "subs.analyze.done": "变更分析已生成 · {count} 个仓库有更新",
494
+ "subs.analyze.doneOne": "{repo} 已更新",
495
+ "subs.analyze.failed": "分析失败:{message}",
486
496
  "subs.row.removeRepo": "移除 {repo}",
487
497
  "subs.col.repo": "仓库",
488
498
  "subs.col.tag": "最近版本",
@@ -966,7 +976,7 @@ var DICT = {
966
976
  "releases.budget.auto": "Auto",
967
977
  "releases.budget.fixed": "Fixed",
968
978
  "subs.title": "Subscriptions",
969
- "subs.desc": "Type owner/repo to see instantly whether it is subscribed; each row carries its latest version, latest weekly summary and status, and “Changes” opens the weekly record.",
979
+ "subs.desc": "Manage release-subscription repos and review weekly change records.",
970
980
  "subs.select": "Select",
971
981
  "subs.select.done": "Done",
972
982
  "subs.cmd.placeholder": "Search owner/repo, or type a full repo name to add it",
@@ -993,8 +1003,18 @@ var DICT = {
993
1003
  "subs.removed.many": "Removed {count} repos; committed with artifacts on the next run.",
994
1004
  "subs.remove": "Remove",
995
1005
  "subs.removing": "Removing…",
996
- "subs.row.changes": "Changes",
1006
+ "subs.row.changes": "View changes",
997
1007
  "subs.row.changesRepo": "Show changes for {repo}",
1008
+ "subs.row.trigger": "Analyze",
1009
+ "subs.row.triggerRepo": "Generate change analysis for {repo} only",
1010
+ "subs.search.placeholder": "Search repositories",
1011
+ "subs.search.label": "Search repositories",
1012
+ "subs.toolbar.add": "+ Add repository",
1013
+ "subs.toolbar.analyze": "Generate change analysis",
1014
+ "subs.analyzing": "Analyzing…",
1015
+ "subs.analyze.done": "Change analysis ready · {count} repos updated",
1016
+ "subs.analyze.doneOne": "{repo} updated",
1017
+ "subs.analyze.failed": "Analysis failed: {message}",
998
1018
  "subs.row.removeRepo": "Remove {repo}",
999
1019
  "subs.col.repo": "Repo",
1000
1020
  "subs.col.tag": "Latest version",
@@ -1434,6 +1454,24 @@ var CSS = `
1434
1454
 
1435
1455
  /* ——— 订阅:命令栏 + 四列表格 + 选择条 + 发版记录抽屉 ——— */
1436
1456
  .dshgt-subs{gap:12px;padding-bottom:10px;}
1457
+ /* 工具条:搜索 + 添加 + 选择 + 生成变更分析;列表在上方操作区之下 */
1458
+ .dshgt-subs-toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding-bottom:12px;border-bottom:1px solid color-mix(in srgb,var(--gt-border) 70%,transparent);}
1459
+ .dshgt-subs-search{position:relative;flex:1;min-width:180px;max-width:340px;display:flex;align-items:center;}
1460
+ .dshgt-subs-search svg{position:absolute;left:9px;color:var(--gt-muted);pointer-events:none;}
1461
+ .dshgt-subs-search input{width:100%;height:32px;box-sizing:border-box;padding:0 10px 0 30px;border:1px solid var(--gt-border);border-radius:8px;background:var(--gt-bg);color:var(--gt-fg);font:inherit;font-size:13px;}
1462
+ .dshgt-subs-search input:focus{outline:2px solid color-mix(in srgb,var(--gt-accent) 30%,transparent);outline-offset:1px;border-color:color-mix(in srgb,var(--gt-accent) 45%,var(--gt-border));}
1463
+ .dshgt-subs-search input::placeholder{color:var(--gt-muted);}
1464
+ .dshgt-subs-toolbar-spacer{flex:1 1 auto;min-width:0;}
1465
+ .dshgt-subs-addform{display:flex;align-items:center;gap:6px;}
1466
+ .dshgt-subs-addform input{height:32px;box-sizing:border-box;width:200px;padding:0 9px;border:1px solid var(--gt-border);border-radius:8px;background:var(--gt-bg);color:var(--gt-fg);font:inherit;font-size:12.5px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;}
1467
+ .dshgt-subs-addform input:focus{outline:2px solid color-mix(in srgb,var(--gt-accent) 30%,transparent);outline-offset:1px;}
1468
+ .dshgt-subs-act.gen{color:var(--gt-muted);}
1469
+ .dshgt-subs-act.gen:hover{color:var(--gt-accent);background:color-mix(in srgb,var(--gt-accent) 10%,transparent);}
1470
+ .dshgt-subs-act.gen:disabled{opacity:.5;cursor:not-allowed;}
1471
+ .dshgt-subs-rowbusy{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--gt-accent);padding:3px 4px;white-space:nowrap;}
1472
+ .dshgt-spin{width:12px;height:12px;border-radius:50%;border:2px solid color-mix(in srgb,var(--gt-accent) 30%,transparent);border-top-color:var(--gt-accent);animation:dshgt-spin .7s linear infinite;display:inline-block;flex:none;}
1473
+ @keyframes dshgt-spin{to{transform:rotate(360deg);}}
1474
+ .dshgt-subs-row.is-analyzing{background:color-mix(in srgb,var(--gt-accent) 6%,var(--gt-bg));}
1437
1475
  .dshgt-subs-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap;}
1438
1476
  .dshgt-subs-head-main{min-width:0;}
1439
1477
  .dshgt-subs-head h2{margin:0;font-size:17px;font-weight:650;letter-spacing:-.01em;}
@@ -1781,11 +1819,6 @@ function releaseRunsOf(state) {
1781
1819
  const nested = Array.isArray(state.status?.releaseRuns) ? state.status.releaseRuns : void 0;
1782
1820
  return root ?? nested ?? [];
1783
1821
  }
1784
- function lastReleaseAtOf(state) {
1785
- if (state === null || state === void 0) return void 0;
1786
- const value = state.lastReleaseAt ?? state.status?.lastReleaseAt;
1787
- return typeof value === "string" && value !== "" ? value : void 0;
1788
- }
1789
1822
  function getPreview(runId, signal) {
1790
1823
  return apiCall("GET", `/preview?id=${encodeURIComponent(runId)}`, void 0, signal === void 0 ? {} : { signal });
1791
1824
  }
@@ -1833,6 +1866,45 @@ async function postSubscriptions(action, repos) {
1833
1866
  const payload = await apiCall("POST", "/subscriptions", { action, repos });
1834
1867
  return normalizeSubscriptionList(payload);
1835
1868
  }
1869
+ async function postReleasesRun(repo) {
1870
+ const payload = await apiCall("POST", "/releases/run", repo === void 0 ? {} : { repo });
1871
+ return normalizeReleaseRun(payload.release);
1872
+ }
1873
+ function normalizeReleaseRun(raw) {
1874
+ const r = typeof raw === "object" && raw !== null ? raw : {};
1875
+ const str = (v, fallback = "") => typeof v === "string" ? v : fallback;
1876
+ const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
1877
+ const opt = (v) => typeof v === "string" && v !== "" ? v : void 0;
1878
+ const status = r.status === "ok" || r.status === "failed" || r.status === "skipped" || r.status === "cancelled" ? r.status : "failed";
1879
+ const record = {
1880
+ id: str(r.id),
1881
+ startedAt: str(r.startedAt),
1882
+ finishedAt: str(r.finishedAt),
1883
+ status,
1884
+ checked: num(r.checked),
1885
+ changed: num(r.changed),
1886
+ newTags: num(r.newTags),
1887
+ summarized: num(r.summarized),
1888
+ degraded: num(r.degraded),
1889
+ failed: num(r.failed),
1890
+ rateLimited: num(r.rateLimited),
1891
+ durationMs: num(r.durationMs)
1892
+ };
1893
+ const maybe = {
1894
+ tokens: typeof r.tokens === "number" ? r.tokens : void 0,
1895
+ commit: opt(r.commit),
1896
+ prUrl: opt(r.prUrl),
1897
+ branch: opt(r.branch),
1898
+ errorCode: opt(r.errorCode),
1899
+ errorMessage: opt(r.errorMessage),
1900
+ coreVersion: opt(r.coreVersion),
1901
+ scopeRepo: opt(r.scopeRepo)
1902
+ };
1903
+ for (const [k, v] of Object.entries(maybe)) {
1904
+ if (v !== void 0) record[k] = v;
1905
+ }
1906
+ return record;
1907
+ }
1836
1908
  async function getSubscriptionDoc(repo, volume, signal) {
1837
1909
  const query = `?repo=${encodeURIComponent(repo)}${volume === void 0 ? "" : `&volume=${encodeURIComponent(String(volume))}`}`;
1838
1910
  const payload = await apiCall(
@@ -4403,12 +4475,6 @@ function monthDay(value) {
4403
4475
  if (value === void 0 || value === "") return "—";
4404
4476
  return DATE_RE2.test(value) ? value.slice(5) : value;
4405
4477
  }
4406
- function clock(value) {
4407
- return /^\d{2}:\d{2}/.test(value) ? value.slice(0, 5) : value;
4408
- }
4409
- function weekdayLabel(t, weekday) {
4410
- return weekday >= 1 && weekday <= 7 ? t(`weekday.${weekday}`) : String(weekday);
4411
- }
4412
4478
  function toneOf(status) {
4413
4479
  if (status === "ok") return "ok";
4414
4480
  if (status === "rate_limited") return "warn";
@@ -4466,47 +4532,6 @@ function highlight(text, needle) {
4466
4532
  if (index < text.length) parts.push(text.slice(index));
4467
4533
  return parts;
4468
4534
  }
4469
- function weekStart(date) {
4470
- const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(date);
4471
- if (match === null) return date;
4472
- const value = new Date(Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3])));
4473
- const dayIndex = (value.getUTCDay() + 6) % 7;
4474
- value.setUTCDate(value.getUTCDate() - dayIndex);
4475
- return value.toISOString().slice(0, 10);
4476
- }
4477
- function metaOf(t, store) {
4478
- const state = store?.state ?? null;
4479
- const schedule = state?.schedule;
4480
- const releaseSchedule = state?.settings?.releases?.schedule;
4481
- const weekday = typeof schedule?.releaseWeekday === "number" ? schedule.releaseWeekday : releaseSchedule?.weekday;
4482
- const time = typeof schedule?.releaseTime === "string" && schedule.releaseTime !== "" ? schedule.releaseTime : releaseSchedule?.time;
4483
- const timezone = (typeof schedule?.releaseTimezone === "string" && schedule.releaseTimezone !== "" ? schedule.releaseTimezone : releaseSchedule?.timezone) ?? schedule?.timezone ?? "Asia/Shanghai";
4484
- const cadence = weekday === void 0 || time === void 0 || time === "" ? t("subs.meta.cadence") : t("subs.meta.cadence.full", { weekday: weekdayLabel(t, weekday), time: clock(time) });
4485
- const nextAt = typeof schedule?.nextReleaseAt === "string" && schedule.nextReleaseAt !== "" ? schedule.nextReleaseAt : void 0;
4486
- const next = nextAt === void 0 ? void 0 : shortTime(nextAt);
4487
- const runs = releaseRunsOf(state);
4488
- const newest = runs.length === 0 ? void 0 : runs.reduce((a, b) => Date.parse(b.finishedAt || b.startedAt) > Date.parse(a.finishedAt || a.startedAt) ? b : a);
4489
- const lastCheckAt = newest?.finishedAt ?? lastReleaseAtOf(state);
4490
- const lastCheck = typeof lastCheckAt === "string" && lastCheckAt !== "" ? shortTime(lastCheckAt) : void 0;
4491
- let lastWeek;
4492
- if (newest !== void 0) {
4493
- const today = zonedDateString(/* @__PURE__ */ new Date(), timezone);
4494
- const currentFrom = weekStart(today);
4495
- const lastFrom = addDays(currentFrom, -7);
4496
- const at = newest.finishedAt !== "" ? newest.finishedAt : newest.startedAt;
4497
- const runDate = zonedDateString(new Date(at), timezone);
4498
- if (runDate >= lastFrom && runDate <= addDays(lastFrom, 6)) {
4499
- lastWeek = t("subs.meta.lastWeek", { from: monthDay(lastFrom), to: monthDay(addDays(lastFrom, 6)), changed: newest.changed });
4500
- } else if (runDate >= currentFrom && runDate <= addDays(currentFrom, 6)) {
4501
- lastWeek = t("subs.meta.thisWeek", { from: monthDay(currentFrom), to: monthDay(addDays(currentFrom, 6)), changed: newest.changed });
4502
- }
4503
- }
4504
- const info = { cadence };
4505
- if (next !== void 0) info.next = next;
4506
- if (lastWeek !== void 0) info.lastWeek = lastWeek;
4507
- if (lastCheck !== void 0) info.lastCheck = lastCheck;
4508
- return info;
4509
- }
4510
4535
  function isMissingDoc(code, message) {
4511
4536
  if (code !== void 0 && /NOT_?FOUND|MISSING|NO_?DOC/i.test(code)) return true;
4512
4537
  return /not\s*found|no such file|enoent|404|不存在|no release document|has no release|无发版记录/i.test(message);
@@ -4661,7 +4686,10 @@ function SubscriptionsView(props) {
4661
4686
  const [selected, setSelected] = import_react.default.useState([]);
4662
4687
  const [confirming, setConfirming] = import_react.default.useState(null);
4663
4688
  const [openRepo, setOpenRepo] = import_react.default.useState(null);
4664
- const [focus, setFocus] = import_react.default.useState(-1);
4689
+ const [addOpen, setAddOpen] = import_react.default.useState(false);
4690
+ const [addValue, setAddValue] = import_react.default.useState("");
4691
+ const [analyzing, setAnalyzing] = import_react.default.useState(null);
4692
+ const [result, setResult] = import_react.default.useState(null);
4665
4693
  const load = import_react.default.useCallback((signal) => {
4666
4694
  getSubscriptions(signal).then((next) => {
4667
4695
  if (signal?.aborted === true) return;
@@ -4678,23 +4706,10 @@ function SubscriptionsView(props) {
4678
4706
  load(controller.signal);
4679
4707
  return () => controller.abort();
4680
4708
  }, [load]);
4681
- const inputRef = import_react.default.useRef(null);
4682
- import_react.default.useEffect(() => {
4683
- const onKey = (event) => {
4684
- if (event.key.toLowerCase() !== "k" || !(event.metaKey || event.ctrlKey)) return;
4685
- event.preventDefault();
4686
- inputRef.current?.focus?.();
4687
- };
4688
- document.addEventListener("keydown", onKey);
4689
- return () => document.removeEventListener("keydown", onKey);
4690
- }, []);
4691
4709
  const rows = mergeRows(list);
4692
4710
  const needle = query.trim().toLowerCase();
4693
4711
  const matched = needle === "" ? rows : rows.filter((row) => row.name.toLowerCase().includes(needle));
4694
4712
  const sorted = sortRows(matched, sort);
4695
- const candidate = needle !== "" && REPO_PATTERN.test(query.trim()) ? query.trim() : void 0;
4696
- const subscribed = candidate !== void 0 && rows.some((row) => row.name.toLowerCase() === candidate.toLowerCase());
4697
- const activeFocus = focus >= 0 && focus < sorted.length ? focus : -1;
4698
4713
  const toggleSelect = (repo) => {
4699
4714
  setSelected((current) => current.includes(repo) ? current.filter((item) => item !== repo) : [...current, repo]);
4700
4715
  };
@@ -4704,8 +4719,8 @@ function SubscriptionsView(props) {
4704
4719
  setNote(null);
4705
4720
  postSubscriptions("add", [repo]).then((next) => {
4706
4721
  setList(next);
4707
- setQuery("");
4708
- setFocus(-1);
4722
+ setAddValue("");
4723
+ setAddOpen(false);
4709
4724
  setNote(t("subs.add.queued", { repo }));
4710
4725
  }).catch((failure) => setError(errorText(failure))).finally(() => setBusy(null));
4711
4726
  };
@@ -4734,6 +4749,22 @@ function SubscriptionsView(props) {
4734
4749
  setConfirming(null);
4735
4750
  }).finally(() => setBusy(null));
4736
4751
  };
4752
+ const runAnalyze = (repo) => {
4753
+ if (analyzing !== null) return;
4754
+ setAnalyzing(repo === void 0 ? { scope: "all" } : { scope: "one", repo });
4755
+ setError(null);
4756
+ setResult(null);
4757
+ postReleasesRun(repo).then((record) => {
4758
+ setResult({ scope: repo === void 0 ? "all" : "one", ...repo === void 0 ? {} : { repo }, ok: record.status !== "failed", changed: record.changed });
4759
+ if (record.status === "failed" && record.errorMessage !== void 0) {
4760
+ setError(t("subs.analyze.failed", { message: record.errorMessage }));
4761
+ }
4762
+ load();
4763
+ }).catch((failure) => {
4764
+ setError(errorText(failure));
4765
+ setResult({ scope: repo === void 0 ? "all" : "one", ...repo === void 0 ? {} : { repo }, ok: false, changed: 0 });
4766
+ }).finally(() => setAnalyzing(null));
4767
+ };
4737
4768
  const onSort = (key) => {
4738
4769
  setSort((current) => current.key === key ? { key, dir: current.dir === 1 ? -1 : 1 } : { key, dir: 1 });
4739
4770
  };
@@ -4754,48 +4785,19 @@ function SubscriptionsView(props) {
4754
4785
  active ? h("span", { className: "dshgt-subs-ord" }, sort.dir === 1 ? "▲" : "▼") : null
4755
4786
  );
4756
4787
  };
4757
- const onCommandKey = (event) => {
4758
- if (event.isComposing === true) return;
4759
- if (event.key === "Escape") {
4760
- setQuery("");
4761
- setFocus(-1);
4762
- if (selecting) {
4763
- setSelecting(false);
4764
- setSelected([]);
4765
- }
4766
- return;
4767
- }
4768
- if (event.key === "Enter") {
4769
- if (candidate !== void 0 && !subscribed) {
4770
- event.preventDefault();
4771
- addRepo(candidate);
4772
- return;
4773
- }
4774
- if (activeFocus >= 0) {
4775
- event.preventDefault();
4776
- setOpenRepo(sorted[activeFocus]?.name ?? null);
4777
- }
4778
- return;
4779
- }
4780
- if (event.key === "ArrowDown") {
4781
- event.preventDefault();
4782
- setFocus(Math.min(sorted.length - 1, focus + 1));
4783
- return;
4784
- }
4785
- if (event.key === "ArrowUp") {
4786
- event.preventDefault();
4787
- setFocus(Math.max(-1, focus - 1));
4788
- }
4789
- };
4790
- const meta = metaOf(t, props.store);
4791
- const metaRight = needle !== "" ? [t("subs.meta.match", { matched: sorted.length, total: rows.length })] : [
4792
- meta.lastCheck === void 0 ? void 0 : t("subs.meta.lastCheck", { time: meta.lastCheck }),
4793
- meta.lastWeek
4794
- ].filter((item) => item !== void 0);
4788
+ const canAdd = REPO_PATTERN.test(addValue.trim());
4789
+ const alreadySubscribed = canAdd && rows.some((row) => row.name.toLowerCase() === addValue.trim().toLowerCase());
4795
4790
  const drawerRow = openRepo === null ? void 0 : rows.find((row) => row.name === openRepo);
4796
- const rowNodes = sorted.map((row, index) => {
4791
+ const globalBusy = analyzing !== null;
4792
+ const banner = result === null ? null : result.ok ? h(
4793
+ Alert,
4794
+ { kind: "ok" },
4795
+ result.scope === "all" ? t("subs.analyze.done", { count: result.changed }) : t("subs.analyze.doneOne", { repo: result.repo ?? "" })
4796
+ ) : null;
4797
+ const rowNodes = sorted.map((row) => {
4797
4798
  const item = row.item;
4798
4799
  const tone = toneOf(item?.status);
4800
+ const rowAnalyzing = analyzing !== null && analyzing.scope === "one" && analyzing.repo === row.name;
4799
4801
  const checkbox = selecting ? h(
4800
4802
  "span",
4801
4803
  { key: "cb", role: "cell", className: "dshgt-subs-cbwrap" },
@@ -4813,7 +4815,7 @@ function SubscriptionsView(props) {
4813
4815
  {
4814
4816
  key: row.name,
4815
4817
  role: "row",
4816
- className: `dshgt-subs-row${index === activeFocus ? " is-focus" : ""}`,
4818
+ className: `dshgt-subs-row${rowAnalyzing ? " is-analyzing" : ""}`,
4817
4819
  onClick: () => {
4818
4820
  if (selecting) toggleSelect(row.name);
4819
4821
  else setOpenRepo(row.name);
@@ -4836,6 +4838,21 @@ function SubscriptionsView(props) {
4836
4838
  h(
4837
4839
  "span",
4838
4840
  { key: "act", role: "cell", className: "dshgt-subs-actions" },
4841
+ rowAnalyzing ? h("span", { className: "dshgt-subs-rowbusy" }, h("span", { className: "dshgt-spin" }), t("subs.analyzing")) : h(
4842
+ "button",
4843
+ {
4844
+ type: "button",
4845
+ className: "dshgt-subs-act gen",
4846
+ "aria-label": t("subs.row.triggerRepo", { repo: row.name }),
4847
+ title: t("subs.row.triggerRepo", { repo: row.name }),
4848
+ disabled: globalBusy || busy !== null,
4849
+ onClick: (event) => {
4850
+ event.stopPropagation();
4851
+ runAnalyze(row.name);
4852
+ }
4853
+ },
4854
+ t("subs.row.trigger")
4855
+ ),
4839
4856
  h(
4840
4857
  "button",
4841
4858
  {
@@ -4871,10 +4888,7 @@ function SubscriptionsView(props) {
4871
4888
  { className: "dshgt-subs-empty" },
4872
4889
  h("b", null, t("subs.empty")),
4873
4890
  h("span", null, t("subs.empty.hint"))
4874
- ) : sorted.length === 0 ? candidate !== void 0 && !subscribed ? (
4875
- // 输入完整 owner/repo 时上方已给出「+ 添加」建议,这里不再叠一句「没有匹配」。
4876
- null
4877
- ) : h(
4891
+ ) : sorted.length === 0 ? h(
4878
4892
  "div",
4879
4893
  { className: "dshgt-subs-empty" },
4880
4894
  h("b", null, t("subs.empty.match")),
@@ -4898,101 +4912,94 @@ function SubscriptionsView(props) {
4898
4912
  return h(
4899
4913
  "div",
4900
4914
  { className: "dshgt-view dshgt-subs" },
4901
- h(
4902
- "section",
4903
- { className: "dshgt-subs-head" },
4904
- h(
4905
- "div",
4906
- { className: "dshgt-subs-head-main" },
4907
- h("h2", null, t("subs.title")),
4908
- h("p", { className: "dshgt-subs-dek" }, t("subs.desc"))
4909
- ),
4910
- h(
4911
- "div",
4912
- { className: "dshgt-subs-head-actions" },
4913
- h(
4914
- Btn,
4915
- {
4916
- small: true,
4917
- onClick: () => {
4918
- if (selecting) setSelected([]);
4919
- setSelecting(!selecting);
4920
- }
4921
- },
4922
- selecting ? t("subs.select.done") : t("subs.select")
4923
- )
4924
- )
4925
- ),
4915
+ // 工具条:搜索 + 添加 + 选择 + 生成变更分析(主操作)
4926
4916
  h(
4927
4917
  "div",
4928
- { className: "dshgt-subs-cmdwrap" },
4918
+ { className: "dshgt-subs-toolbar" },
4929
4919
  h(
4930
4920
  "div",
4931
- { className: "dshgt-subs-cmd" },
4921
+ { className: "dshgt-subs-search" },
4922
+ h(
4923
+ "svg",
4924
+ { width: 15, height: 15, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": 2, "stroke-linecap": "round", "aria-hidden": "true" },
4925
+ h("circle", { cx: 11, cy: 11, r: 7 }),
4926
+ h("path", { d: "m20 20-3.5-3.5" })
4927
+ ),
4932
4928
  h("input", {
4933
4929
  type: "text",
4934
- ref: inputRef,
4935
4930
  value: query,
4936
- placeholder: t("subs.cmd.placeholder"),
4937
- "aria-label": t("subs.cmd.label"),
4938
- "aria-keyshortcuts": "Meta+K Control+K",
4931
+ placeholder: t("subs.search.placeholder"),
4932
+ "aria-label": t("subs.search.label"),
4939
4933
  autoComplete: "off",
4940
4934
  spellCheck: false,
4941
- onInput: (event) => {
4942
- setQuery(event.target.value);
4943
- setFocus(-1);
4944
- },
4945
- onKeyDown: onCommandKey
4946
- }),
4947
- h("kbd", { className: "dshgt-subs-kbd" }, "⌘K")
4935
+ onInput: (event) => setQuery(event.target.value)
4936
+ })
4948
4937
  ),
4949
- h(
4938
+ h("div", { className: "dshgt-subs-toolbar-spacer" }),
4939
+ addOpen ? h(
4950
4940
  "div",
4951
- { className: "dshgt-subs-meta" },
4941
+ { className: "dshgt-subs-addform" },
4942
+ h("input", {
4943
+ type: "text",
4944
+ value: addValue,
4945
+ placeholder: t("subs.add.placeholder"),
4946
+ "aria-label": t("subs.add.placeholder"),
4947
+ autoComplete: "off",
4948
+ spellCheck: false,
4949
+ autoFocus: true,
4950
+ onInput: (event) => setAddValue(event.target.value),
4951
+ onKeyDown: (event) => {
4952
+ if (event.isComposing === true) return;
4953
+ if (event.key === "Enter" && canAdd && !alreadySubscribed) addRepo(addValue.trim());
4954
+ if (event.key === "Escape") {
4955
+ setAddOpen(false);
4956
+ setAddValue("");
4957
+ }
4958
+ }
4959
+ }),
4952
4960
  h(
4953
- "span",
4954
- null,
4955
- t("subs.meta.count", { count: rows.length }),
4956
- " · ",
4957
- h(
4958
- "button",
4959
- { type: "button", className: "dshgt-subs-linkbtn", title: t("subs.param.link"), onClick: () => props.onOpenSettings() },
4960
- meta.cadence
4961
- ),
4962
- meta.next === void 0 ? null : ` · ${t("subs.meta.next", { time: meta.next })}`
4963
- ),
4964
- metaRight.length === 0 ? null : h(
4965
- "span",
4966
- { className: "dshgt-subs-meta-right" },
4967
- metaRight.flatMap((part, index) => index === 0 ? [part] : [h("span", { key: `sep${index}`, className: "dshgt-subs-meta-sep" }, "·"), part])
4961
+ Btn,
4962
+ { small: true, variant: "primary", disabled: busy !== null || !canAdd || alreadySubscribed, onClick: () => canAdd && !alreadySubscribed && addRepo(addValue.trim()) },
4963
+ t("subs.add.confirm")
4968
4964
  )
4965
+ ) : h(
4966
+ Btn,
4967
+ {
4968
+ small: true,
4969
+ disabled: busy !== null,
4970
+ onClick: () => {
4971
+ setAddOpen(true);
4972
+ setAddValue("");
4973
+ }
4974
+ },
4975
+ t("subs.toolbar.add")
4976
+ ),
4977
+ h(
4978
+ Btn,
4979
+ {
4980
+ small: true,
4981
+ onClick: () => {
4982
+ if (selecting) setSelected([]);
4983
+ setSelecting(!selecting);
4984
+ }
4985
+ },
4986
+ selecting ? t("subs.select.done") : t("subs.select")
4987
+ ),
4988
+ h(
4989
+ Btn,
4990
+ {
4991
+ small: true,
4992
+ variant: "primary",
4993
+ disabled: globalBusy || busy !== null,
4994
+ onClick: () => runAnalyze()
4995
+ },
4996
+ analyzing !== null && analyzing.scope === "all" ? t("subs.analyzing") : t("subs.toolbar.analyze")
4969
4997
  )
4970
4998
  ),
4971
- candidate === void 0 ? null : h(
4972
- "div",
4973
- { className: "dshgt-subs-suggest" },
4974
- subscribed ? [
4975
- h("span", { key: "pill", className: "dshgt-tag" }, t("subs.cmd.subscribed")),
4976
- h("span", { key: "repo", className: "repo" }, candidate),
4977
- h("span", { key: "hint", className: "hint" }, t("subs.cmd.subscribed.hint"))
4978
- ] : [
4979
- h("span", { key: "plus", className: "plus" }, "+"),
4980
- h("span", { key: "add" }, t("subs.cmd.add")),
4981
- h("span", { key: "repo", className: "repo" }, candidate),
4982
- h("span", { key: "hint", className: "hint" }, t("subs.cmd.add.hint"))
4983
- ]
4984
- ),
4999
+ banner,
4985
5000
  error === null ? null : h(Alert, { kind: "err" }, error),
4986
5001
  note === null ? null : h(Alert, { kind: "ok" }, note),
4987
5002
  tableBody,
4988
- h(
4989
- "div",
4990
- { className: "dshgt-subs-keys" },
4991
- h("span", null, t("subs.keys.move")),
4992
- h("span", null, t("subs.keys.enter")),
4993
- h("span", null, t("subs.keys.esc")),
4994
- h("span", null, t("subs.keys.sort"))
4995
- ),
4996
5003
  selecting && rows.length > 0 ? h(
4997
5004
  "div",
4998
5005
  { className: "dshgt-subs-selbar" },
@@ -1612,6 +1612,7 @@ function buildCoreArgs(channelPath, options) {
1612
1612
  if (options.period !== void 0) args.push("--period", options.period);
1613
1613
  if (options.stages !== void 0 && options.stages.length > 0) args.push("--stages", options.stages.join(","));
1614
1614
  if (options.force === true) args.push("--force");
1615
+ if (options.repo !== void 0 && options.repo !== "") args.push("--repo", options.repo);
1615
1616
  return args;
1616
1617
  }
1617
1618
  async function runCore(options) {
@@ -1627,7 +1628,8 @@ async function runCore(options) {
1627
1628
  date: options.date,
1628
1629
  period: options.period,
1629
1630
  stages: options.stages,
1630
- force: options.force
1631
+ force: options.force,
1632
+ ...options.repo === void 0 ? {} : { repo: options.repo }
1631
1633
  });
1632
1634
  const child = spawn2(options.core.path, args, {
1633
1635
  env: sanitizedEnv(process.env, {
@@ -2751,6 +2753,7 @@ function versionAtLeast(a, b) {
2751
2753
  var runner_exports = {};
2752
2754
  __export(runner_exports, {
2753
2755
  FORCE_MIN_CORE_VERSION: () => FORCE_MIN_CORE_VERSION,
2756
+ REPO_MIN_CORE_VERSION: () => REPO_MIN_CORE_VERSION,
2754
2757
  Runner: () => Runner,
2755
2758
  isoWeekName: () => isoWeekName,
2756
2759
  periodFileBase: () => periodFileBase,
@@ -2760,6 +2763,7 @@ import { createHash as createHash2 } from "crypto";
2760
2763
  import { existsSync as existsSync4, readFileSync as readFileSync3, realpathSync, statSync as statSync5 } from "fs";
2761
2764
  import path9 from "path";
2762
2765
  var FORCE_MIN_CORE_VERSION = "0.7.1";
2766
+ var REPO_MIN_CORE_VERSION = "0.8.0";
2763
2767
  function repoProblem(repoPath) {
2764
2768
  if (repoPath.trim() === "") return { code: "CONFIG_INVALID", message: "\u8FD8\u6CA1\u6709\u9009\u62E9\u5F52\u6863\u4ED3\u5E93" };
2765
2769
  if (!existsSync4(repoPath)) return { code: "REPO_NOT_GIT", message: `\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${repoPath}` };
@@ -3010,6 +3014,7 @@ var Runner = class {
3010
3014
  this.active = { id, controller, startedAt };
3011
3015
  const logFile = store.newLogPath(id);
3012
3016
  let proxy;
3017
+ const requestedRepo = options.repo !== void 0 && options.repo !== "" ? options.repo : void 0;
3013
3018
  try {
3014
3019
  const core = await locateCore({ settings, env, allowDownload: settings.coreAutoDownload });
3015
3020
  if (core.downloaded === true) {
@@ -3022,6 +3027,14 @@ var Runner = class {
3022
3027
  `\u6838\u5FC3\u4E0D\u652F\u6301 provider\u300C${settings.model.provider}\u300D\uFF1B\u53EF\u7528\uFF1A${handshakeResult.supportedProviders.join(" / ")}`
3023
3028
  );
3024
3029
  }
3030
+ let effectiveRepo = requestedRepo;
3031
+ if (requestedRepo !== void 0 && !versionAtLeast(handshakeResult.version.version, REPO_MIN_CORE_VERSION)) {
3032
+ store.appendLog(
3033
+ logFile,
3034
+ `[release] \u6838\u5FC3 ${handshakeResult.version.version} \u4F4E\u4E8E ${REPO_MIN_CORE_VERSION}\uFF0C\u5355\u4ED3\u5206\u6790\u964D\u7EA7\u4E3A\u5168\u91CF`
3035
+ );
3036
+ effectiveRepo = void 0;
3037
+ }
3025
3038
  const model = await this.openModelChannel({ settings, credentials, env, logFile });
3026
3039
  proxy = model.proxy;
3027
3040
  const github = await resolveGithubToken(credentials, settings.github.authMode, settings.github.tokenRef, { env });
@@ -3041,6 +3054,7 @@ var Runner = class {
3041
3054
  dryRun: false,
3042
3055
  trigger: options.trigger === "schedule" ? "schedule" : "manual",
3043
3056
  stages: ["releases"],
3057
+ ...effectiveRepo === void 0 ? {} : { repo: effectiveRepo },
3044
3058
  repoCount,
3045
3059
  ...model.baseURLOverride === void 0 ? {} : { baseURLOverride: model.baseURLOverride },
3046
3060
  signal: controller.signal,
@@ -3053,11 +3067,12 @@ var Runner = class {
3053
3067
  settings,
3054
3068
  startedAt,
3055
3069
  logFile,
3056
- cancelled: controller.signal.aborted
3070
+ cancelled: controller.signal.aborted,
3071
+ ...requestedRepo === void 0 ? {} : { scopeRepo: requestedRepo }
3057
3072
  });
3058
3073
  } catch (error) {
3059
3074
  const aborted = controller.signal.aborted || error instanceof IpcError && error.code === "CORE_CANCELLED";
3060
- return this.recordReleaseFailure({ id, error, aborted, settings, startedAt, startedMs, logFile });
3075
+ return this.recordReleaseFailure({ id, error, aborted, settings, startedAt, startedMs, logFile, ...requestedRepo === void 0 ? {} : { scopeRepo: requestedRepo } });
3061
3076
  } finally {
3062
3077
  if (proxy !== void 0) {
3063
3078
  const port = proxy.port;
@@ -3135,9 +3150,10 @@ var Runner = class {
3135
3150
  ...outcome.prUrl === void 0 ? {} : { prUrl: outcome.prUrl },
3136
3151
  ...outcome.branch === void 0 ? {} : { branch: outcome.branch },
3137
3152
  ...outcome.error === void 0 ? input.cancelled ? { errorCode: "CORE_CANCELLED", errorMessage: "\u8FD0\u884C\u5DF2\u53D6\u6D88\uFF1A\u6838\u5FC3\u8FDB\u7A0B\u5DF2\u7EC8\u6B62\uFF0C\u672A\u63D0\u4EA4\u4EFB\u4F55\u72B6\u6001" } : {} : { errorCode: outcome.error.code, errorMessage: redact(outcome.error.message) },
3138
- ...outcome.coreVersion === "" ? {} : { coreVersion: outcome.coreVersion }
3153
+ ...outcome.coreVersion === "" ? {} : { coreVersion: outcome.coreVersion },
3154
+ ...input.scopeRepo === void 0 ? {} : { scopeRepo: input.scopeRepo }
3139
3155
  };
3140
- this.persistReleaseRun(record, settings, input.logFile);
3156
+ this.persistReleaseRun(record, settings, input.logFile, { advanceWeek: input.scopeRepo === void 0 });
3141
3157
  return record;
3142
3158
  }
3143
3159
  /** 运行在拿到信封之前就失败(定位/握手/模型/代理/超时/取消):也要留一条可复盘记录。 */
@@ -3158,20 +3174,24 @@ var Runner = class {
3158
3174
  rateLimited: 0,
3159
3175
  durationMs: Date.now() - input.startedMs,
3160
3176
  errorCode: code,
3161
- errorMessage: message
3177
+ errorMessage: message,
3178
+ ...input.scopeRepo === void 0 ? {} : { scopeRepo: input.scopeRepo }
3162
3179
  };
3163
- this.persistReleaseRun(record, input.settings, input.logFile);
3180
+ this.persistReleaseRun(record, input.settings, input.logFile, { advanceWeek: input.scopeRepo === void 0 });
3164
3181
  return record;
3165
3182
  }
3166
3183
  /**
3167
3184
  * 落盘发版运行:只写 state(history.json 是榜单的),顺带推进 lastReleaseAt;
3168
3185
  * 只有 ok/skipped 才锁 `lastReleaseWeek`——失败不锁,调度下一 tick 才有机会重试。
3186
+ * `advanceWeek=false`(单仓手动触发)时:仍写 releaseRuns 与 lastReleaseAt,但**不**锁
3187
+ * lastReleaseWeek——否则会把本周标记为已检查,导致周调度跳过本周真正的检查。
3169
3188
  */
3170
- persistReleaseRun(record, settings, logFile) {
3189
+ persistReleaseRun(record, settings, logFile, opts = {}) {
3171
3190
  const store = this.deps.store;
3191
+ const advanceWeek = opts.advanceWeek !== false;
3172
3192
  const succeeded = record.status === "ok" || record.status === "skipped";
3173
3193
  let week;
3174
- if (succeeded) {
3194
+ if (succeeded && advanceWeek) {
3175
3195
  try {
3176
3196
  week = isoWeekKey(new Date(record.finishedAt), settings.releases.schedule.timezone);
3177
3197
  } catch {
@@ -4038,7 +4058,10 @@ function createRoutes(deps) {
4038
4058
  const code = error instanceof IpcError ? error.code : "INTERNAL";
4039
4059
  const message = redact(error instanceof Error ? error.message : String(error));
4040
4060
  deps.logger?.("route.error", { pathname, method, code, message });
4041
- const status = code === "CONFIG_INVALID" ? 400 : code === "NOT_FOUND" ? 404 : 500;
4061
+ const status = code === "CONFIG_INVALID" ? (
4062
+ // 「已有一次运行在进行中」是并发冲突而非参数错误:用 409,前端据此禁用按钮并提示。
4063
+ message.includes("\u8FD0\u884C\u5728\u8FDB\u884C\u4E2D") ? 409 : 400
4064
+ ) : code === "NOT_FOUND" ? 404 : 500;
4042
4065
  sendJson2(response, status, { ok: false, code, message });
4043
4066
  }
4044
4067
  };
@@ -4117,6 +4140,18 @@ async function dispatch(method, pathname, url, request, deps) {
4117
4140
  if (method === "POST" && pathname === "/run/cancel") {
4118
4141
  return { cancelled: deps.runner.cancel() };
4119
4142
  }
4143
+ if (method === "POST" && pathname === "/releases/run") {
4144
+ const body = await readBody2(request);
4145
+ let repo;
4146
+ if (body.repo !== void 0) {
4147
+ if (typeof body.repo !== "string" || !isValidRepo(body.repo.trim())) {
4148
+ throw new IpcError("CONFIG_INVALID", `repo \u5FC5\u987B\u662F owner/repo \u5F62\u6001\uFF1A${String(body.repo)}`);
4149
+ }
4150
+ repo = body.repo.trim();
4151
+ }
4152
+ const release = await deps.runner.runReleases({ trigger: "manual", ...repo === void 0 ? {} : { repo } });
4153
+ return { release };
4154
+ }
4120
4155
  if (method === "GET" && pathname === "/repo/branch") {
4121
4156
  const repoPath = url.searchParams.get("path") ?? settings.repo.path;
4122
4157
  return { repo: await readDefaultBranch(repoPath, { env }) };
package/lib/index.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  createTrendingRunTool,
9
9
  createUpdateService,
10
10
  readPluginInfo
11
- } from "./chunk-VF6DOIQQ.js";
11
+ } from "./chunk-R3EDPRRO.js";
12
12
  import "./chunk-R7BK7SJK.js";
13
13
 
14
14
  // src/index.ts
package/lib/internal.d.ts CHANGED
@@ -631,6 +631,8 @@ interface ReleaseRunRecord {
631
631
  errorCode?: string;
632
632
  errorMessage?: string;
633
633
  coreVersion?: string;
634
+ /** 单仓手动触发时记录该仓库(owner/repo);全量运行缺省。仅展示用。 */
635
+ scopeRepo?: string;
634
636
  }
635
637
  /** 发版运行记录上限:一周一次的话正好留半年,够复盘又不会让 state.json 膨胀。 */
636
638
  declare const RELEASE_RUN_LIMIT = 30;
@@ -984,6 +986,8 @@ interface RunCoreOptions {
984
986
  * `['releases']` 就是「只跑发版订阅」——不抓榜单、不渲染 digest、也不合并订阅 pending。
985
987
  */
986
988
  stages?: string[];
989
+ /** 单仓发版分析(核心 `run --stages releases --repo owner/repo`):只处理该仓库;须与 stages=['releases'] 搭配。 */
990
+ repo?: string;
987
991
  /** 订阅仓库数:用于把配置里的 `auto` 并发/预算解析成数字(发版运行传入)。 */
988
992
  repoCount?: number;
989
993
  signal?: AbortSignal;
@@ -1004,6 +1008,7 @@ declare function buildCoreArgs(channelPath: string, options: {
1004
1008
  period?: Period;
1005
1009
  stages?: string[];
1006
1010
  force?: boolean;
1011
+ repo?: string;
1007
1012
  }): string[];
1008
1013
  declare function runCore(options: RunCoreOptions): Promise<RunCoreResult>;
1009
1014
 
@@ -1446,6 +1451,11 @@ declare namespace pendingPr {
1446
1451
  * 与 core patch 发版 `0.7.1` 对齐;`dsh.core.version` 应 >= 它,dev override 指向更旧核心时靠闸门降级。
1447
1452
  */
1448
1453
  declare const FORCE_MIN_CORE_VERSION = "0.7.1";
1454
+ /**
1455
+ * 支持 `run --stages releases --repo`(单仓发版分析)的最低核心版本。
1456
+ * 与 core v0.8.0 对齐;核心更旧时单仓触发降级为全量(不传 --repo)。
1457
+ */
1458
+ declare const REPO_MIN_CORE_VERSION = "0.8.0";
1449
1459
  interface RunSummary {
1450
1460
  id: string;
1451
1461
  ok: boolean;
@@ -1553,6 +1563,7 @@ declare class Runner {
1553
1563
  */
1554
1564
  runReleases(options: {
1555
1565
  trigger: 'manual' | 'schedule';
1566
+ repo?: string;
1556
1567
  }): Promise<ReleaseRunRecord>;
1557
1568
  /** 发版运行用哪一天:发版调度时区下的「今天」(不是榜单调度时区,两者可独立配置)。 */
1558
1569
  private releaseDate;
@@ -1572,6 +1583,8 @@ declare class Runner {
1572
1583
  /**
1573
1584
  * 落盘发版运行:只写 state(history.json 是榜单的),顺带推进 lastReleaseAt;
1574
1585
  * 只有 ok/skipped 才锁 `lastReleaseWeek`——失败不锁,调度下一 tick 才有机会重试。
1586
+ * `advanceWeek=false`(单仓手动触发)时:仍写 releaseRuns 与 lastReleaseAt,但**不**锁
1587
+ * lastReleaseWeek——否则会把本周标记为已检查,导致周调度跳过本周真正的检查。
1575
1588
  */
1576
1589
  private persistReleaseRun;
1577
1590
  private summarize;
@@ -1592,6 +1605,7 @@ declare class Runner {
1592
1605
  }
1593
1606
 
1594
1607
  declare const runner_FORCE_MIN_CORE_VERSION: typeof FORCE_MIN_CORE_VERSION;
1608
+ declare const runner_REPO_MIN_CORE_VERSION: typeof REPO_MIN_CORE_VERSION;
1595
1609
  type runner_RunRequestOptions = RunRequestOptions;
1596
1610
  type runner_RunSummary = RunSummary;
1597
1611
  type runner_Runner = Runner;
@@ -1601,7 +1615,7 @@ declare const runner_isoWeekName: typeof isoWeekName;
1601
1615
  declare const runner_periodFileBase: typeof periodFileBase;
1602
1616
  declare const runner_projectUsage: typeof projectUsage;
1603
1617
  declare namespace runner {
1604
- export { runner_FORCE_MIN_CORE_VERSION as FORCE_MIN_CORE_VERSION, type runner_RunRequestOptions as RunRequestOptions, type runner_RunSummary as RunSummary, runner_Runner as Runner, type runner_RunnerDeps as RunnerDeps, runner_isoWeekName as isoWeekName, runner_periodFileBase as periodFileBase, runner_projectUsage as projectUsage };
1618
+ export { runner_FORCE_MIN_CORE_VERSION as FORCE_MIN_CORE_VERSION, runner_REPO_MIN_CORE_VERSION as REPO_MIN_CORE_VERSION, type runner_RunRequestOptions as RunRequestOptions, type runner_RunSummary as RunSummary, runner_Runner as Runner, type runner_RunnerDeps as RunnerDeps, runner_isoWeekName as isoWeekName, runner_periodFileBase as periodFileBase, runner_projectUsage as projectUsage };
1605
1619
  }
1606
1620
 
1607
1621
  /** 订阅命令超时:核心只做一次 GitHub 请求/本地文件读写,8 s 足够。 */
package/lib/internal.js CHANGED
@@ -26,7 +26,7 @@ import {
26
26
  tools_exports,
27
27
  update_exports,
28
28
  version_exports
29
- } from "./chunk-VF6DOIQQ.js";
29
+ } from "./chunk-R3EDPRRO.js";
30
30
  import {
31
31
  exec_exports
32
32
  } from "./chunk-R7BK7SJK.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morehao/dsh-github-trending",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "GitHub 趋势日报插件:每天定时 spawn 本地 trendradar 核心,抓取 Trending、生成中文简介与总结,提交到你的仓库并自动合并 PR。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -51,7 +51,7 @@
51
51
  },
52
52
  "dependencies": {
53
53
  "@morehao/dsh-plugin-kit": "0.1.0",
54
- "@morehao/trendradar-contract": "0.4.0"
54
+ "@morehao/trendradar-contract": "0.5.0"
55
55
  },
56
56
  "dsh": {
57
57
  "bundle": {
@@ -59,7 +59,7 @@
59
59
  },
60
60
  "core": {
61
61
  "repo": "morehao/trendradar",
62
- "version": "0.7.1"
62
+ "version": "0.8.0"
63
63
  },
64
64
  "client": {
65
65
  "platform": "web",