feat(downloads): fold download plans into download panel (DL-3)

- Waiting plans (approval / disk space / automation off / queued) are
  active-segment rows on /download-tasks/board, merged by created_at,
  counted, with approve / cancel actions; ?plan= deep links and legacy
  /downloads/plans routes redirect to the panel
- Download detail shows "why this download" (source, purpose, replaced
  version, reasons); raw evaluation in tech info
- Failed / cancelled / expired plans appear in the entity download
  history; rejected / revoked / expired approvals close draft plans
- New GET /acquisition-plans/{id}/why, POST /acquisition-plans/{id}/cancel
- User-facing copy no longer says 下载计划; glossary updated

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-30 01:15:25 +08:00
1 parent c0522f2531
commit a9147e647d
50 files changed
+1535 -348

No files matched your search

@@ -43,7 +43,7 @@ export function deniedReason(call: ToolCallView): { text: string; approvable: bo
// ── 进度行的人话计数 ──
type Group = { verb: string; nouns: { noun: string; unit: string | null; n: number }[] };
type Group = { verb: string; bare: boolean; nouns: { noun: string; unit: string | null; n: number }[] };
function activityOf(id: string) {
return (
@@ -73,7 +73,7 @@ export function activitySummary(calls: Pick<ToolCallView, "capabilityId" | "stat
if (c.status === "denied" || c.status === "failed" || authDenial(c)) continue;
let g = groups.find((x) => x.verb === a.verb);
if (!g) {
g = { verb: a.verb, nouns: [] };
g = { verb: a.verb, bare: !!a.bare, nouns: [] };
groups.push(g);
}
const n = g.nouns.find((x) => x.noun === a.noun);
@@ -81,7 +81,10 @@ export function activitySummary(calls: Pick<ToolCallView, "capabilityId" | "stat
else g.nouns.push({ noun: a.noun, unit: a.unit, n: 1 });
}
const text = (g: Group) =>
cjkJoin(`${g.verb}了`, joinNouns(g.nouns.map((x) => (x.unit ? `${x.n} ${x.unit}${x.noun}` : x.noun))));
cjkJoin(
g.bare ? g.verb : `${g.verb}了`,
joinNouns(g.nouns.map((x) => (x.unit ? `${x.n} ${x.unit}${x.noun}` : x.noun))),
);
if (groups.length > 4) return `${groups.slice(0, 3).map(text).join(",")}等 ${groups.length} 类操作`;
return groups.map(text).join(",");
}