report: storebound report writes one shareable, self-contained readiness page (.storebound/reports/readiness-<date>.html; --md, --json, --no-open, --offline, --out) from scan, check and validate: a verdict per store (Ready to submit / N blockers / Not checked with the reason), findings per store by severity with guideline, evidence, fix and console button, the owner's compliance questions as a checklist, secrets masked; storebound.dev look, light / dark, print; desktop Checks > Report (same code path, opens through project_reveal) and its Markdown export on the same renderer; read-only MCP tool report

This commit is contained in:
CRTkafa 2026-10-18 01:42:03 +08:00
parent 6d95ea00f5
commit af349b3db1
18 changed files with 792 additions and 12 deletions

View file

@ -4,6 +4,7 @@
import type { AnalyticsCompare, AppStatus, DeclarationsResult, ListingText, PricesCurrent } from '../api';
import type { CatalogDiff, HealthSnapshot, Review, ValidateResult } from './model';
import { isError } from './model';
import { buildReport, renderMarkdown } from '../../../../cli/lib/report';
type Cell = string | number | boolean | null | undefined;
@ -62,11 +63,12 @@ export function healthMd(app: string, h: HealthSnapshot): string {
return out.join('\n');
}
export function validateMd(app: string, v: ValidateResult, at: string | null): string {
const lvl = (l: string) => (l === 'blocker' ? 'Blocker' : l === 'warn' ? 'Warning' : 'OK');
return [`# ${app}: store readiness`, '', `Read ${at ?? 'now'} · ${v.blockers} blocker(s), ${v.findings.filter(f => f.level === 'warn').length} warning(s)`, '',
mdTable(['store', 'level', 'check', 'finding', 'fix'], v.findings.map(f => [f.store === 'apple' ? 'App Store' : 'Google Play', lvl(f.level), f.code, f.msg, f.fix ?? ''])),
].join('\n');
/** The store readiness export: the same report and Markdown renderer as `storebound report --md` (cli/lib/report.ts),
* from what the Checks tab read (validate, the offline check, the scan when it ran). */
export function validateMd(app: string, v: ValidateResult, at: string | null, more: { check?: { problems: string[]; warnings: string[] } | null; scan?: unknown; version?: string; stores?: ('apple' | 'play')[] } = {}): string {
const r = buildReport({ app: { name: app }, ...(more.stores ? { stores: more.stores } : {}), generatedAt: at ?? new Date().toISOString(), storebound: more.version ?? 'desktop',
validate: v as never, check: more.check ?? null, scan: (more.scan ?? null) as never, storeRead: { apple: true, play: true } });
return renderMarkdown(r);
}
export function catalogMd(app: string, c: CatalogDiff): string {