@mandujs/core 0.32.0 → 0.33.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.
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Mandu Diagnose — aggregator.
3
+ *
4
+ * Runs all registered checks in parallel (they are pure I/O, no shared
5
+ * mutable state) and builds a unified `DiagnoseReport`.
6
+ */
7
+
8
+ import type { DiagnoseCheckResult, DiagnoseReport } from "./types";
9
+ import {
10
+ checkManifestFreshness,
11
+ checkPrerenderPollution,
12
+ checkCloneElementWarnings,
13
+ checkDevArtifactsInProd,
14
+ checkPackageExportGaps,
15
+ } from "./checks";
16
+
17
+ /**
18
+ * Registered extended checks (Issue #215). These are the five checks that
19
+ * supplement the legacy guard/contract/manifest/kitchen validation in MCP.
20
+ *
21
+ * Order matters for display purposes only — result aggregation is
22
+ * order-independent.
23
+ */
24
+ export const EXTENDED_CHECKS = [
25
+ { name: "manifest_freshness", run: checkManifestFreshness },
26
+ { name: "prerender_pollution", run: checkPrerenderPollution },
27
+ { name: "cloneelement_warnings", run: checkCloneElementWarnings },
28
+ { name: "dev_artifacts_in_prod", run: checkDevArtifactsInProd },
29
+ { name: "package_export_gaps", run: checkPackageExportGaps },
30
+ ] as const;
31
+
32
+ /**
33
+ * Run every extended check in parallel and return the aggregate report.
34
+ *
35
+ * Legacy checks (kitchen_errors, guard_check, contract_validation,
36
+ * manifest_validation) are NOT run here — they live in the MCP tool
37
+ * surface and have different dependency requirements. Instead, the MCP
38
+ * `mandu.diagnose` composite combines the extended checks with the
39
+ * legacy ones and normalizes both into a single unified report.
40
+ */
41
+ export async function runExtendedDiagnose(rootDir: string): Promise<DiagnoseReport> {
42
+ const checks = await Promise.all(
43
+ EXTENDED_CHECKS.map(async ({ run }) => {
44
+ try {
45
+ return await run(rootDir);
46
+ } catch (err) {
47
+ // Defensive fallback — individual checks shouldn't throw, but if
48
+ // one does, we surface it as an error rather than crashing the
49
+ // whole diagnose run.
50
+ return {
51
+ ok: false,
52
+ rule: "diagnose_internal_error",
53
+ severity: "error" as const,
54
+ message: `Check threw an error: ${err instanceof Error ? err.message : String(err)}`,
55
+ };
56
+ }
57
+ })
58
+ );
59
+
60
+ return buildReport(checks);
61
+ }
62
+
63
+ /**
64
+ * Aggregate a pre-computed list of check results into a `DiagnoseReport`.
65
+ * Exported so the MCP composite can pass in both extended + legacy checks
66
+ * at once.
67
+ */
68
+ export function buildReport(checks: DiagnoseCheckResult[]): DiagnoseReport {
69
+ let errorCount = 0;
70
+ let warningCount = 0;
71
+ for (const c of checks) {
72
+ if (c.ok) continue;
73
+ if (c.severity === "error") errorCount += 1;
74
+ else if (c.severity === "warning") warningCount += 1;
75
+ }
76
+ return {
77
+ healthy: errorCount === 0,
78
+ errorCount,
79
+ warningCount,
80
+ checks,
81
+ summary: {
82
+ total: checks.length,
83
+ passed: checks.filter((c) => c.ok).length,
84
+ failed: checks.filter((c) => !c.ok).length,
85
+ },
86
+ };
87
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Mandu Diagnose — unified check result shape.
3
+ *
4
+ * Every diagnose check returns a `DiagnoseCheckResult`. Severity semantics:
5
+ *
6
+ * - `error` : blocks deploy. CI should fail. Example: stale dev-mode
7
+ * manifest shipped to prod, package export gap, empty bundles
8
+ * with islands declared.
9
+ * - `warning` : degraded UX or future risk. Does NOT block deploy, but
10
+ * surfaces for operator attention. Example: suspicious
11
+ * prerendered routes, many cloneElement warnings.
12
+ * - `info` : neutral observation, no action required.
13
+ *
14
+ * The `rule` field is a stable machine-readable identifier. The `message`
15
+ * field is human-readable and MAY include route paths or counts. The
16
+ * optional `suggestion` field is a single actionable next step.
17
+ */
18
+ export type DiagnoseSeverity = "error" | "warning" | "info";
19
+
20
+ export interface DiagnoseCheckResult {
21
+ /** Overall pass/fail for this check. `true` = healthy. */
22
+ ok: boolean;
23
+ /** Stable machine-readable rule id, e.g. `manifest_freshness`. */
24
+ rule: string;
25
+ /** Severity when `ok === false`. Omitted when `ok === true`. */
26
+ severity?: DiagnoseSeverity;
27
+ /** Human-readable summary. */
28
+ message: string;
29
+ /** Single-line actionable next step, e.g. `"Run mandu build"`. */
30
+ suggestion?: string;
31
+ /** Structured details (route list, counts, file paths). */
32
+ details?: Record<string, unknown>;
33
+ }
34
+
35
+ /**
36
+ * Aggregated report across all checks for a single diagnose run.
37
+ */
38
+ export interface DiagnoseReport {
39
+ /** `true` when no check has `ok: false` with `severity: 'error'`. */
40
+ healthy: boolean;
41
+ /** Count of checks returning `ok: false` with `severity: 'error'`. */
42
+ errorCount: number;
43
+ /** Count of checks returning `ok: false` with `severity: 'warning'`. */
44
+ warningCount: number;
45
+ /** Individual check results in registration order. */
46
+ checks: DiagnoseCheckResult[];
47
+ /** Summary statistics. */
48
+ summary: {
49
+ total: number;
50
+ passed: number;
51
+ failed: number;
52
+ };
53
+ }