raven-mcp 1.7.0 → 1.9.0

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/README.md CHANGED
@@ -67,6 +67,7 @@ cd raven-mcp && npm install && npm run build
67
67
  | `audit_layout` | Evaluate visual rhythm, alignment, and optical balance |
68
68
  | `audit_responsive_visibility` | Render a URL at multiple breakpoints and flag content elements that are visible on desktop but hidden on mobile (display:none/opacity:0/zero-size) — categorises each as likely-oversight (content vanishing on mobile) vs intentional (decorative) |
69
69
  | `audit_contrast` | Compute WCAG contrast ratios for every text element on a rendered page and report AA (4.5:1 / 3:1 large) and AAA pass-fail per element, with delta-to-pass for failures |
70
+ | `audit_url` | Render a live URL at each viewport×theme, scroll-settle, fire interactions, capture real pixels + DOM, then run the page/contrast/responsive/blank-media checks **plus** sliced-image edge-symmetry and hover-state white-wash detection over the captures — every finding tagged confirmed/likely-artifact/inconclusive, ranked by severity |
70
71
  | `audit_swiftui` | Audit SwiftUI source against Apple HIG — Dynamic Type, semantic colors, 44pt targets, 4/8pt spacing, AccentColor |
71
72
  | `audit_ios_screen` | Score a rendered iOS screen from an accessibility/view-hierarchy snapshot — 44pt targets + contrast + rhythm, in points |
72
73
  | `audit_ios_privacy` | Audit Info.plist (or Expo app.json) /PRIVACY.md/entitlements/source — usage-string honesty, ATS, Android permissions, bundled secrets, undisclosed default data-egress |
@@ -0,0 +1,36 @@
1
+ export type ShapeSchema = {
2
+ required?: string[];
3
+ types?: Record<string, "string" | "number" | "boolean" | "object" | "array">;
4
+ };
5
+ export type Query = {
6
+ name: string;
7
+ method?: "GET" | "POST";
8
+ path?: string;
9
+ headers?: Record<string, string>;
10
+ body?: unknown;
11
+ expect?: {
12
+ contains?: string[];
13
+ equals?: Record<string, unknown>;
14
+ };
15
+ };
16
+ export type QueryVerdict = {
17
+ name: string;
18
+ verdict: "shape-valid" | "shape-invalid" | "confident-wrong" | "uncertain";
19
+ reason: string;
20
+ offending?: string;
21
+ status?: number;
22
+ };
23
+ export type ApiContractResult = {
24
+ results: QueryVerdict[];
25
+ shape_valid_count: number;
26
+ confident_wrong_count: number;
27
+ shape_invalid_count: number;
28
+ uncertain_count: number;
29
+ };
30
+ export declare function getPath(obj: unknown, path: string): unknown;
31
+ export declare function validateShape(response: unknown, schema: ShapeSchema): {
32
+ valid: boolean;
33
+ offending?: string;
34
+ reason: string;
35
+ };
36
+ export declare function runApiContract(endpointUrl: string, queries: Query[], schema: ShapeSchema): Promise<ApiContractResult>;
@@ -0,0 +1,235 @@
1
+ export function getPath(obj, path) {
2
+ const segments = path.split(".");
3
+ let current = obj;
4
+ for (let index = 0; index < segments.length; index += 1) {
5
+ const segment = segments[index];
6
+ if (Array.isArray(current)) {
7
+ if (!isArrayIndex(segment)) {
8
+ return undefined;
9
+ }
10
+ const arrayIndex = Number(segment);
11
+ if (arrayIndex >= current.length) {
12
+ return undefined;
13
+ }
14
+ current = current[arrayIndex];
15
+ continue;
16
+ }
17
+ if (!isRecord(current)) {
18
+ return undefined;
19
+ }
20
+ if (!Object.prototype.hasOwnProperty.call(current, segment)) {
21
+ return undefined;
22
+ }
23
+ current = current[segment];
24
+ }
25
+ return current;
26
+ }
27
+ export function validateShape(response, schema) {
28
+ const required = schema.required || [];
29
+ for (let index = 0; index < required.length; index += 1) {
30
+ const path = required[index];
31
+ if (getPath(response, path) === undefined) {
32
+ return {
33
+ valid: false,
34
+ offending: path,
35
+ reason: "missing required path: " + path
36
+ };
37
+ }
38
+ }
39
+ const types = schema.types || {};
40
+ const entries = Object.entries(types);
41
+ for (let index = 0; index < entries.length; index += 1) {
42
+ const path = entries[index][0];
43
+ const expected = entries[index][1];
44
+ const value = getPath(response, path);
45
+ if (value === undefined) {
46
+ continue;
47
+ }
48
+ if (!matchesType(value, expected)) {
49
+ return {
50
+ valid: false,
51
+ offending: path,
52
+ reason: "type mismatch at " + path + ": expected " + expected
53
+ };
54
+ }
55
+ }
56
+ return { valid: true, reason: "all checks passed" };
57
+ }
58
+ export async function runApiContract(endpointUrl, queries, schema) {
59
+ const results = [];
60
+ for (let index = 0; index < queries.length; index += 1) {
61
+ const query = queries[index];
62
+ const controller = new AbortController();
63
+ const timeout = setTimeout(function abortRequest() {
64
+ controller.abort();
65
+ }, 10000);
66
+ let response;
67
+ try {
68
+ response = await fetch(endpointUrl + (query.path || ""), {
69
+ method: query.method || "GET",
70
+ headers: requestHeaders(query),
71
+ body: query.method === "POST" ? JSON.stringify(query.body) : undefined,
72
+ signal: controller.signal
73
+ });
74
+ }
75
+ catch (error) {
76
+ results.push({
77
+ name: query.name,
78
+ verdict: "uncertain",
79
+ reason: errorMessage(error)
80
+ });
81
+ clearTimeout(timeout);
82
+ continue;
83
+ }
84
+ clearTimeout(timeout);
85
+ let parsed;
86
+ try {
87
+ parsed = await response.json();
88
+ }
89
+ catch {
90
+ results.push({
91
+ name: query.name,
92
+ verdict: "uncertain",
93
+ reason: "non-JSON response",
94
+ status: response.status
95
+ });
96
+ continue;
97
+ }
98
+ if (response.status < 200 || response.status >= 300) {
99
+ results.push({
100
+ name: query.name,
101
+ verdict: "uncertain",
102
+ reason: "HTTP " + response.status,
103
+ status: response.status
104
+ });
105
+ continue;
106
+ }
107
+ const shape = validateShape(parsed, schema);
108
+ if (!shape.valid) {
109
+ results.push({
110
+ name: query.name,
111
+ verdict: "shape-invalid",
112
+ reason: shape.reason,
113
+ offending: shape.offending,
114
+ status: response.status
115
+ });
116
+ continue;
117
+ }
118
+ const expected = query.expect;
119
+ const confidentWrong = expected ? checkExpectations(parsed, expected) : null;
120
+ if (confidentWrong) {
121
+ results.push({
122
+ name: query.name,
123
+ verdict: "confident-wrong",
124
+ reason: confidentWrong.reason,
125
+ offending: confidentWrong.offending,
126
+ status: response.status
127
+ });
128
+ continue;
129
+ }
130
+ results.push({
131
+ name: query.name,
132
+ verdict: "shape-valid",
133
+ reason: "all checks passed",
134
+ status: response.status
135
+ });
136
+ }
137
+ return tallyResults(results);
138
+ }
139
+ function isArrayIndex(segment) {
140
+ return /^\d+$/.test(segment);
141
+ }
142
+ function isRecord(value) {
143
+ return typeof value === "object" && value !== null;
144
+ }
145
+ function matchesType(value, expected) {
146
+ if (expected === "array") {
147
+ return Array.isArray(value);
148
+ }
149
+ if (expected === "object") {
150
+ return typeof value === "object" && value !== null && !Array.isArray(value);
151
+ }
152
+ return typeof value === expected;
153
+ }
154
+ function requestHeaders(query) {
155
+ if (!query.headers && query.method !== "POST") {
156
+ return undefined;
157
+ }
158
+ const headers = { ...(query.headers || {}) };
159
+ if (query.method === "POST" && !hasHeader(headers, "content-type")) {
160
+ headers["Content-Type"] = "application/json";
161
+ }
162
+ return headers;
163
+ }
164
+ function hasHeader(headers, name) {
165
+ const names = Object.keys(headers);
166
+ const target = name.toLowerCase();
167
+ for (let index = 0; index < names.length; index += 1) {
168
+ if (names[index].toLowerCase() === target) {
169
+ return true;
170
+ }
171
+ }
172
+ return false;
173
+ }
174
+ function checkExpectations(parsed, expected) {
175
+ const serialized = JSON.stringify(parsed);
176
+ const contains = expected.contains || [];
177
+ for (let index = 0; index < contains.length; index += 1) {
178
+ const expectedString = contains[index];
179
+ if (!serialized.includes(expectedString)) {
180
+ return {
181
+ reason: "expected string not found: " + expectedString,
182
+ offending: expectedString
183
+ };
184
+ }
185
+ }
186
+ const equals = expected.equals || {};
187
+ const entries = Object.entries(equals);
188
+ for (let index = 0; index < entries.length; index += 1) {
189
+ const path = entries[index][0];
190
+ const expectedValue = entries[index][1];
191
+ const actualValue = getPath(parsed, path);
192
+ if (JSON.stringify(actualValue) !== JSON.stringify(expectedValue)) {
193
+ return {
194
+ reason: "value mismatch at " + path,
195
+ offending: path
196
+ };
197
+ }
198
+ }
199
+ return null;
200
+ }
201
+ function tallyResults(results) {
202
+ let shapeValidCount = 0;
203
+ let confidentWrongCount = 0;
204
+ let shapeInvalidCount = 0;
205
+ let uncertainCount = 0;
206
+ for (let index = 0; index < results.length; index += 1) {
207
+ const result = results[index];
208
+ if (result.verdict === "shape-valid") {
209
+ shapeValidCount += 1;
210
+ }
211
+ else if (result.verdict === "confident-wrong") {
212
+ confidentWrongCount += 1;
213
+ }
214
+ else if (result.verdict === "shape-invalid") {
215
+ shapeInvalidCount += 1;
216
+ }
217
+ else if (result.verdict === "uncertain") {
218
+ uncertainCount += 1;
219
+ }
220
+ }
221
+ return {
222
+ results,
223
+ shape_valid_count: shapeValidCount,
224
+ confident_wrong_count: confidentWrongCount,
225
+ shape_invalid_count: shapeInvalidCount,
226
+ uncertain_count: uncertainCount
227
+ };
228
+ }
229
+ function errorMessage(error) {
230
+ if (error instanceof Error) {
231
+ return error.message;
232
+ }
233
+ return String(error);
234
+ }
235
+ //# sourceMappingURL=api-contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-contract.js","sourceRoot":"","sources":["../src/api-contract.ts"],"names":[],"mappings":"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"}
@@ -11,3 +11,33 @@ export type AssetIntegrityOptions = {
11
11
  varianceThreshold?: number;
12
12
  };
13
13
  export declare function auditAssetIntegrity(imagePaths: string[], opts?: AssetIntegrityOptions): Promise<AssetIntegrityResult[]>;
14
+ export type ImageEdgeSample = {
15
+ selector: string;
16
+ width: number;
17
+ height: number;
18
+ edges: {
19
+ top: number;
20
+ bottom: number;
21
+ left: number;
22
+ right: number;
23
+ };
24
+ tainted: boolean;
25
+ };
26
+ export type ImageEdgeVerdict = {
27
+ selector: string;
28
+ verdict: "clean" | "likely-sliced" | "inconclusive";
29
+ cut_edge: "top" | "bottom" | "left" | "right" | null;
30
+ confidence: number;
31
+ edges: {
32
+ top: number;
33
+ bottom: number;
34
+ left: number;
35
+ right: number;
36
+ };
37
+ reason: string;
38
+ };
39
+ export type ImageEdgeOptions = {
40
+ highVarianceThreshold?: number;
41
+ uniformRatio?: number;
42
+ };
43
+ export declare function auditImageEdges(samples: ImageEdgeSample[], opts?: ImageEdgeOptions): ImageEdgeVerdict[];
@@ -101,4 +101,70 @@ function errorMessage(error) {
101
101
  }
102
102
  return String(error);
103
103
  }
104
+ export function auditImageEdges(samples, opts = {}) {
105
+ const highVar = opts.highVarianceThreshold ?? 200;
106
+ const uniformRatio = opts.uniformRatio ?? 0.25;
107
+ return (samples || []).map(function (sample) {
108
+ const e = sample.edges;
109
+ if (sample.tainted) {
110
+ return {
111
+ selector: sample.selector,
112
+ verdict: "inconclusive",
113
+ cut_edge: null,
114
+ confidence: 0,
115
+ edges: e,
116
+ reason: "image pixels unreadable (cross-origin canvas taint) — could not sample edges"
117
+ };
118
+ }
119
+ // Opposite-edge pairs: an edge "looks cut" when it carries high-variance
120
+ // content while the edge facing it is near-uniform.
121
+ const pairs = [
122
+ { edge: "bottom", v: e.bottom, opposite: e.top },
123
+ { edge: "top", v: e.top, opposite: e.bottom },
124
+ { edge: "right", v: e.right, opposite: e.left },
125
+ { edge: "left", v: e.left, opposite: e.right }
126
+ ];
127
+ let worst = null;
128
+ for (const p of pairs) {
129
+ const asymmetric = p.v > highVar && p.opposite < highVar * uniformRatio;
130
+ if (asymmetric && (worst === null || p.v > worst.v)) {
131
+ worst = p;
132
+ }
133
+ }
134
+ if (worst === null) {
135
+ return {
136
+ selector: sample.selector,
137
+ verdict: "clean",
138
+ cut_edge: null,
139
+ confidence: clamp(1 - maxEdge(e) / highVar, 0, 1),
140
+ edges: e,
141
+ reason: "all edges uniform — no content running into a frame edge"
142
+ };
143
+ }
144
+ // Confidence grows with how far the cut edge exceeds the threshold and how
145
+ // uniform the opposite edge is.
146
+ const overshoot = clamp(worst.v / (highVar * 4), 0, 1);
147
+ const oppositeUniformity = clamp(1 - worst.opposite / (highVar * uniformRatio), 0, 1);
148
+ const confidence = Math.max(0.5, (overshoot + oppositeUniformity) / 2);
149
+ return {
150
+ selector: sample.selector,
151
+ verdict: "likely-sliced",
152
+ cut_edge: worst.edge,
153
+ confidence: Math.round(confidence * 100) / 100,
154
+ edges: e,
155
+ reason: "high-variance content at the " +
156
+ worst.edge +
157
+ " edge (variance " +
158
+ Math.round(worst.v) +
159
+ ") with a uniform opposite edge (variance " +
160
+ Math.round(worst.opposite) +
161
+ ") — content appears cut off at the " +
162
+ worst.edge +
163
+ " frame edge"
164
+ };
165
+ });
166
+ }
167
+ function maxEdge(e) {
168
+ return Math.max(e.top, e.bottom, e.left, e.right);
169
+ }
104
170
  //# sourceMappingURL=asset-integrity.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"asset-integrity.js","sourceRoot":"","sources":["../src/asset-integrity.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"asset-integrity.js","sourceRoot":"","sources":["../src/asset-integrity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * audit-url.ts — Layer 0 render-and-capture transport.
3
+ *
4
+ * Renders a live URL at each viewport×theme, scroll-settles, fires interactions,
5
+ * captures real pixels + DOM, then runs the EXISTING checks (audit_page rule
6
+ * engine, contrast, responsive-visibility, video-blank, screenshot diff) plus
7
+ * pixel checks (image edge symmetry) over the captured output. Every finding is
8
+ * tagged confirmed | likely-artifact | inconclusive with its evidence, and
9
+ * ranked by severity.
10
+ *
11
+ * This tool does NOT reimplement the checks — it reuses:
12
+ * · runPageChecks (the audit_page rule engine, shared verbatim)
13
+ * · verifyFindings (the adversarial confirmed/likely-artifact tagger)
14
+ * · captureResponsiveVisibility (desktop-visible / mobile-hidden divergence)
15
+ * · auditContrastUrl (per-element WCAG AA/AAA)
16
+ * · capturePage video-blank detection
17
+ * · auditImageEdges (sliced/cropped image edge symmetry)
18
+ * · diffScreenshots (baseline vs post-interaction state diff)
19
+ */
20
+ import type { Interaction, Theme } from "./capture.js";
21
+ export type ViewportSpec = {
22
+ w: number;
23
+ h: number;
24
+ label?: string;
25
+ };
26
+ export type Verdict = "confirmed" | "likely-artifact" | "inconclusive";
27
+ export type FindingSource = "page" | "contrast" | "responsive-visibility" | "video" | "asset-integrity" | "hover-state";
28
+ export type AuditUrlFinding = {
29
+ source: FindingSource;
30
+ rule: string;
31
+ severity: "error" | "warning" | "info";
32
+ message: string;
33
+ fix: string;
34
+ selector?: string;
35
+ viewport: string;
36
+ theme: Theme;
37
+ verdict: Verdict;
38
+ evidence: string;
39
+ };
40
+ export type AuditUrlCapture = {
41
+ viewport: string;
42
+ theme: Theme;
43
+ scrolledToBottom: boolean;
44
+ screenshot_bytes: number;
45
+ screenshot?: string;
46
+ };
47
+ export type AuditUrlResult = {
48
+ tool: "audit_url";
49
+ url: string;
50
+ viewports: ViewportSpec[];
51
+ themes: Theme[];
52
+ findings: AuditUrlFinding[];
53
+ counts: {
54
+ total: number;
55
+ confirmed: number;
56
+ likely_artifact: number;
57
+ inconclusive: number;
58
+ errors: number;
59
+ warnings: number;
60
+ };
61
+ summary: string;
62
+ captures: AuditUrlCapture[];
63
+ warnings: string[];
64
+ };
65
+ export type AuditUrlOptions = {
66
+ viewports?: ViewportSpec[];
67
+ themes?: Theme[];
68
+ scroll_settle?: boolean;
69
+ interactions?: Interaction[];
70
+ containerMaxWidth?: number;
71
+ timeoutMs?: number;
72
+ includeScreenshots?: boolean;
73
+ };
74
+ export declare function auditUrl(url: string, opts?: AuditUrlOptions): Promise<AuditUrlResult>;