ghost-qa 0.0.0-stage → 1.3.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.
Files changed (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +273 -3
  3. package/SKILL.md +105 -0
  4. package/dist/bin/ghost-qa.d.ts +35 -0
  5. package/dist/bin/ghost-qa.d.ts.map +1 -0
  6. package/dist/bin/ghost-qa.js +406 -0
  7. package/dist/bin/ghost-qa.js.map +1 -0
  8. package/dist/src/engine/audit-runner.d.ts +10 -0
  9. package/dist/src/engine/audit-runner.d.ts.map +1 -0
  10. package/dist/src/engine/audit-runner.js +138 -0
  11. package/dist/src/engine/audit-runner.js.map +1 -0
  12. package/dist/src/engine/browser-session.d.ts +37 -0
  13. package/dist/src/engine/browser-session.d.ts.map +1 -0
  14. package/dist/src/engine/browser-session.js +114 -0
  15. package/dist/src/engine/browser-session.js.map +1 -0
  16. package/dist/src/engine/interaction-runner.d.ts +41 -0
  17. package/dist/src/engine/interaction-runner.d.ts.map +1 -0
  18. package/dist/src/engine/interaction-runner.js +274 -0
  19. package/dist/src/engine/interaction-runner.js.map +1 -0
  20. package/dist/src/engine/route-crawler.d.ts +31 -0
  21. package/dist/src/engine/route-crawler.d.ts.map +1 -0
  22. package/dist/src/engine/route-crawler.js +110 -0
  23. package/dist/src/engine/route-crawler.js.map +1 -0
  24. package/dist/src/engine/server-lifecycle.d.ts +41 -0
  25. package/dist/src/engine/server-lifecycle.d.ts.map +1 -0
  26. package/dist/src/engine/server-lifecycle.js +154 -0
  27. package/dist/src/engine/server-lifecycle.js.map +1 -0
  28. package/dist/src/index.d.ts +16 -0
  29. package/dist/src/index.d.ts.map +1 -0
  30. package/dist/src/index.js +16 -0
  31. package/dist/src/index.js.map +1 -0
  32. package/dist/src/mcp/server.d.ts +111 -0
  33. package/dist/src/mcp/server.d.ts.map +1 -0
  34. package/dist/src/mcp/server.js +267 -0
  35. package/dist/src/mcp/server.js.map +1 -0
  36. package/dist/src/reporter/agent-diagnostic.d.ts +17 -0
  37. package/dist/src/reporter/agent-diagnostic.d.ts.map +1 -0
  38. package/dist/src/reporter/agent-diagnostic.js +80 -0
  39. package/dist/src/reporter/agent-diagnostic.js.map +1 -0
  40. package/dist/src/reporter/html-report.d.ts +9 -0
  41. package/dist/src/reporter/html-report.d.ts.map +1 -0
  42. package/dist/src/reporter/html-report.js +142 -0
  43. package/dist/src/reporter/html-report.js.map +1 -0
  44. package/dist/src/reporter/terminal-summary.d.ts +5 -0
  45. package/dist/src/reporter/terminal-summary.d.ts.map +1 -0
  46. package/dist/src/reporter/terminal-summary.js +71 -0
  47. package/dist/src/reporter/terminal-summary.js.map +1 -0
  48. package/dist/src/traps/a11y-trap.d.ts +27 -0
  49. package/dist/src/traps/a11y-trap.d.ts.map +1 -0
  50. package/dist/src/traps/a11y-trap.js +173 -0
  51. package/dist/src/traps/a11y-trap.js.map +1 -0
  52. package/dist/src/traps/console-trap.d.ts +28 -0
  53. package/dist/src/traps/console-trap.d.ts.map +1 -0
  54. package/dist/src/traps/console-trap.js +151 -0
  55. package/dist/src/traps/console-trap.js.map +1 -0
  56. package/dist/src/traps/layout-trap.d.ts +31 -0
  57. package/dist/src/traps/layout-trap.d.ts.map +1 -0
  58. package/dist/src/traps/layout-trap.js +150 -0
  59. package/dist/src/traps/layout-trap.js.map +1 -0
  60. package/dist/src/traps/network-trap.d.ts +24 -0
  61. package/dist/src/traps/network-trap.d.ts.map +1 -0
  62. package/dist/src/traps/network-trap.js +132 -0
  63. package/dist/src/traps/network-trap.js.map +1 -0
  64. package/dist/src/traps/perf-trap.d.ts +42 -0
  65. package/dist/src/traps/perf-trap.d.ts.map +1 -0
  66. package/dist/src/traps/perf-trap.js +196 -0
  67. package/dist/src/traps/perf-trap.js.map +1 -0
  68. package/dist/src/types.d.ts +95 -0
  69. package/dist/src/types.d.ts.map +1 -0
  70. package/dist/src/types.js +80 -0
  71. package/dist/src/types.js.map +1 -0
  72. package/package.json +91 -6
  73. package/scripts/prepare-build.mjs +40 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-lifecycle.d.ts","sourceRoot":"","sources":["../../../src/engine/server-lifecycle.ts"],"names":[],"mappings":"AAIA,gFAAgF;AAChF,wBAAgB,UAAU,CACxB,GAAG,EAAE,MAAM,EACX,SAAS,SAAS,EAClB,cAAc,SAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED,MAAM,WAAW,oBAAoB;IACnC,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,wEAAwE;IACxE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;GAKG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,MAAM,CAAM;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;gBAEnC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,oBAAyB;IAK/D,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,IAAI,GAAG,IAAI,MAAM,GAAG,SAAS,CAE5B;IAED,kFAAkF;IAClF,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,KAAK,IAAI,IAAI;IAmBb,4FAA4F;IACtF,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBpE,wEAAwE;IAClE,IAAI,CAAC,OAAO,SAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAyB1C,OAAO,CAAC,UAAU;CAgBnB;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,CAAC,EAC1C,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,GAAE,oBAAoB,GAAG;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/D,OAAO,CAAC,CAAC,CAAC,CASZ"}
@@ -0,0 +1,154 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { get as httpGet } from 'node:http';
3
+ import { get as httpsGet } from 'node:https';
4
+ /** Polls a URL until it answers with any HTTP status (even 404 = server up). */
5
+ export function waitForUrl(url, timeoutMs = 30_000, pollIntervalMs = 400) {
6
+ const deadline = Date.now() + timeoutMs;
7
+ return new Promise((resolvePromise, rejectPromise) => {
8
+ const attempt = () => {
9
+ const getter = url.startsWith('https:') ? httpsGet : httpGet;
10
+ const request = getter(url, (response) => {
11
+ response.resume();
12
+ resolvePromise();
13
+ });
14
+ request.setTimeout(2_000, () => request.destroy(new Error('poll timeout')));
15
+ request.on('error', () => {
16
+ if (Date.now() >= deadline) {
17
+ rejectPromise(new Error(`Timed out after ${timeoutMs}ms waiting for ${url} to respond.`));
18
+ }
19
+ else {
20
+ setTimeout(attempt, pollIntervalMs);
21
+ }
22
+ });
23
+ };
24
+ attempt();
25
+ });
26
+ }
27
+ /**
28
+ * Owns a spawned dev-server process tree: `start()` spawns it through the
29
+ * platform shell in its own process group, `waitUntilReady()` polls the
30
+ * target URL, and `stop()` terminates the whole tree (SIGTERM, then SIGKILL)
31
+ * so no orphaned dev servers survive a ghost-qa run.
32
+ */
33
+ export class ManagedDevServer {
34
+ child = null;
35
+ output = '';
36
+ command;
37
+ options;
38
+ constructor(command, options = {}) {
39
+ this.command = command;
40
+ this.options = options;
41
+ }
42
+ get isRunning() {
43
+ return this.child !== null && !this.child.killed && this.child.exitCode === null;
44
+ }
45
+ get pid() {
46
+ return this.child?.pid;
47
+ }
48
+ /** Last chunk of captured stdout+stderr (for "server failed to start" errors). */
49
+ get outputTail() {
50
+ return this.output.slice(-2_000);
51
+ }
52
+ start() {
53
+ if (this.child)
54
+ throw new Error(`Dev server already started: ${this.command}`);
55
+ const bufferLimit = this.options.outputBufferChars ?? 20_000;
56
+ this.child = spawn(this.command, {
57
+ cwd: this.options.cwd ?? process.cwd(),
58
+ env: { ...process.env, ...(this.options.env ?? {}) },
59
+ shell: true,
60
+ // Own process group on POSIX so stop() can kill the whole tree
61
+ // (shell -> npm -> node) instead of just the shell wrapper.
62
+ detached: process.platform !== 'win32',
63
+ stdio: ['ignore', 'pipe', 'pipe'],
64
+ });
65
+ const capture = (chunk) => {
66
+ this.output = (this.output + chunk.toString()).slice(-bufferLimit);
67
+ };
68
+ this.child.stdout?.on('data', capture);
69
+ this.child.stderr?.on('data', capture);
70
+ }
71
+ /** Resolves once the URL responds; rejects with the server output on timeout/early exit. */
72
+ async waitUntilReady(url, timeoutMs = 30_000) {
73
+ if (!this.child)
74
+ this.start();
75
+ let exited = null;
76
+ const onExit = (code) => {
77
+ exited = new Error(`Dev server exited before ${url} became ready (exit code ${code ?? 'unknown'}).\n` +
78
+ `Command: ${this.command}\n--- server output ---\n${this.outputTail || '(no output captured)'}`);
79
+ };
80
+ this.child.once('exit', onExit);
81
+ try {
82
+ await waitForUrl(url, timeoutMs);
83
+ if (exited)
84
+ throw exited;
85
+ }
86
+ catch (error) {
87
+ if (exited)
88
+ throw exited;
89
+ throw new Error(`${error instanceof Error ? error.message : String(error)}\n` +
90
+ `Command: ${this.command}\n--- server output ---\n${this.outputTail || '(no output captured)'}`);
91
+ }
92
+ finally {
93
+ this.child?.removeListener('exit', onExit);
94
+ }
95
+ }
96
+ /** Terminates the spawned process tree. Safe to call multiple times. */
97
+ async stop(graceMs = 3_000) {
98
+ const child = this.child;
99
+ if (!child || child.exitCode !== null) {
100
+ this.child = null;
101
+ return;
102
+ }
103
+ const exited = new Promise((resolvePromise) => {
104
+ child.once('exit', () => resolvePromise());
105
+ });
106
+ this.signalTree(child, 'SIGTERM');
107
+ const graceful = await Promise.race([
108
+ exited.then(() => true),
109
+ new Promise((resolvePromise) => setTimeout(() => resolvePromise(false), graceMs)),
110
+ ]);
111
+ if (!graceful) {
112
+ this.signalTree(child, 'SIGKILL');
113
+ await Promise.race([
114
+ exited,
115
+ new Promise((resolvePromise) => setTimeout(resolvePromise, 2_000)),
116
+ ]);
117
+ }
118
+ this.child = null;
119
+ }
120
+ signalTree(child, signal) {
121
+ try {
122
+ if (process.platform !== 'win32' && child.pid) {
123
+ // Negative pid = the whole process group created by `detached: true`.
124
+ process.kill(-child.pid, signal);
125
+ return;
126
+ }
127
+ }
128
+ catch {
129
+ /* group already gone — fall through to direct kill */
130
+ }
131
+ try {
132
+ child.kill(signal);
133
+ }
134
+ catch {
135
+ /* already exited */
136
+ }
137
+ }
138
+ }
139
+ /**
140
+ * Convenience wrapper: spawn `command`, wait for `url`, run `fn`, and always
141
+ * tear the server down afterwards — even when `fn` throws.
142
+ */
143
+ export async function withManagedDevServer(command, url, fn, options = {}) {
144
+ const server = new ManagedDevServer(command, options);
145
+ server.start();
146
+ try {
147
+ await server.waitUntilReady(url, options.readyTimeoutMs ?? 30_000);
148
+ return await fn();
149
+ }
150
+ finally {
151
+ await server.stop();
152
+ }
153
+ }
154
+ //# sourceMappingURL=server-lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-lifecycle.js","sourceRoot":"","sources":["../../../src/engine/server-lifecycle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export * from './types.js';
2
+ export * from './traps/console-trap.js';
3
+ export * from './traps/network-trap.js';
4
+ export * from './traps/layout-trap.js';
5
+ export * from './traps/a11y-trap.js';
6
+ export * from './traps/perf-trap.js';
7
+ export * from './engine/browser-session.js';
8
+ export * from './engine/route-crawler.js';
9
+ export * from './engine/interaction-runner.js';
10
+ export * from './engine/audit-runner.js';
11
+ export * from './engine/server-lifecycle.js';
12
+ export * from './reporter/terminal-summary.js';
13
+ export * from './reporter/agent-diagnostic.js';
14
+ export * from './reporter/html-report.js';
15
+ export * from './mcp/server.js';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,16 @@
1
+ export * from './types.js';
2
+ export * from './traps/console-trap.js';
3
+ export * from './traps/network-trap.js';
4
+ export * from './traps/layout-trap.js';
5
+ export * from './traps/a11y-trap.js';
6
+ export * from './traps/perf-trap.js';
7
+ export * from './engine/browser-session.js';
8
+ export * from './engine/route-crawler.js';
9
+ export * from './engine/interaction-runner.js';
10
+ export * from './engine/audit-runner.js';
11
+ export * from './engine/server-lifecycle.js';
12
+ export * from './reporter/terminal-summary.js';
13
+ export * from './reporter/agent-diagnostic.js';
14
+ export * from './reporter/html-report.js';
15
+ export * from './mcp/server.js';
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,111 @@
1
+ import { type GhostQAOptions, type GhostQAReport } from '../types.js';
2
+ /**
3
+ * Native MCP (Model Context Protocol) server for ghost-qa.
4
+ *
5
+ * Standard JSON-RPC 2.0 over stdio, implemented with zero external SDKs:
6
+ * newline-delimited JSON in, newline-delimited JSON out, diagnostics on
7
+ * stderr only (stdout is the protocol channel). Compatible with Claude Code,
8
+ * Claude Desktop, Cursor, Codex and any other MCP host:
9
+ *
10
+ * { "mcpServers": { "ghost-qa": { "command": "npx", "args": ["-y", "github:avivgerz-hue/ghost-qa", "mcp"] } } }
11
+ */
12
+ export declare const MCP_PROTOCOL_VERSION = "2024-11-05";
13
+ export declare const MCP_SERVER_INFO: {
14
+ readonly name: "ghost-qa";
15
+ readonly version: "1.3.0";
16
+ };
17
+ export interface JsonRpcRequest {
18
+ jsonrpc: '2.0';
19
+ id?: string | number | null;
20
+ method: string;
21
+ params?: Record<string, unknown>;
22
+ }
23
+ export interface JsonRpcResponse {
24
+ jsonrpc: '2.0';
25
+ id: string | number | null;
26
+ result?: unknown;
27
+ error?: {
28
+ code: number;
29
+ message: string;
30
+ data?: unknown;
31
+ };
32
+ }
33
+ export declare const JSON_RPC_ERRORS: {
34
+ readonly parseError: -32700;
35
+ readonly invalidRequest: -32600;
36
+ readonly methodNotFound: -32601;
37
+ readonly invalidParams: -32602;
38
+ readonly internalError: -32603;
39
+ };
40
+ export interface DoctorResult {
41
+ ready: boolean;
42
+ node: string;
43
+ nodeOk: boolean;
44
+ chromiumPath: string;
45
+ chromiumFound: boolean;
46
+ smokeTest: string;
47
+ }
48
+ export declare function runDoctorCheck(): Promise<DoctorResult>;
49
+ export declare const MCP_TOOLS: readonly [{
50
+ readonly name: "ghost_qa_audit_url";
51
+ readonly description: "Run the full ghost-qa headless browser audit against a running localhost app: crawls internal routes on Desktop 1440x900 and Mobile 390x844, safely exercises interactive controls, and traps console/hydration errors, failed network requests, layout overflow, accessibility bugs and performance problems. Returns the Self-Healing Bug Report — fix every critical/major issue it reports before declaring the task done.";
52
+ readonly inputSchema: {
53
+ readonly type: "object";
54
+ readonly properties: {
55
+ readonly url: {
56
+ readonly type: "string";
57
+ readonly description: "Target URL of the running app, e.g. http://localhost:3000";
58
+ };
59
+ readonly maxDepth: {
60
+ readonly type: "number";
61
+ readonly description: "Link-following depth (default 2)";
62
+ };
63
+ readonly maxRoutes: {
64
+ readonly type: "number";
65
+ readonly description: "Maximum routes to visit (default 25)";
66
+ };
67
+ readonly viewport: {
68
+ readonly type: "string";
69
+ readonly enum: readonly ["both", "desktop", "mobile"];
70
+ readonly description: "Viewports to test (default both)";
71
+ };
72
+ };
73
+ readonly required: readonly ["url"];
74
+ readonly additionalProperties: false;
75
+ };
76
+ }, {
77
+ readonly name: "ghost_qa_doctor";
78
+ readonly description: "Verify ghost-qa environment readiness: Node.js version, Chromium binary availability, and a live headless-browser smoke test. Run this first when an audit fails to start.";
79
+ readonly inputSchema: {
80
+ readonly type: "object";
81
+ readonly properties: {};
82
+ readonly additionalProperties: false;
83
+ };
84
+ }];
85
+ export type McpToolName = (typeof MCP_TOOLS)[number]['name'];
86
+ export interface McpHandlers {
87
+ audit: (target: string, options: GhostQAOptions) => Promise<GhostQAReport>;
88
+ doctor: () => Promise<DoctorResult>;
89
+ }
90
+ export declare const defaultHandlers: McpHandlers;
91
+ /**
92
+ * Pure JSON-RPC dispatcher — one parsed request in, one response object (or
93
+ * `null` for notifications) out. Fully unit-testable without stdio or a
94
+ * browser when handlers are injected.
95
+ */
96
+ export declare function handleJsonRpcRequest(request: JsonRpcRequest, handlers?: McpHandlers): Promise<JsonRpcResponse | null>;
97
+ /** Parses one raw line of stdio input into a response line (or null). */
98
+ export declare function handleJsonRpcLine(line: string, handlers?: McpHandlers): Promise<string | null>;
99
+ /** The ready-to-paste MCP host configuration installed by `ghost-qa init`. */
100
+ export declare function mcpServerConfig(): {
101
+ mcpServers: Record<string, {
102
+ command: string;
103
+ args: string[];
104
+ }>;
105
+ };
106
+ /**
107
+ * Serves MCP over stdio until stdin closes. All human diagnostics go to
108
+ * stderr — stdout carries protocol frames only.
109
+ */
110
+ export declare function startMcpServer(input?: NodeJS.ReadableStream, output?: NodeJS.WritableStream, handlers?: McpHandlers): Promise<void>;
111
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/mcp/server.ts"],"names":[],"mappings":"AAMA,OAAO,EAAmB,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEvF;;;;;;;;;GASG;AAEH,eAAO,MAAM,oBAAoB,eAAe,CAAC;AACjD,eAAO,MAAM,eAAe;;;CAA2D,CAAC;AAExF,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAC3D;AAED,eAAO,MAAM,eAAe;;;;;;CAMlB,CAAC;AAEX,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC,CAmB5D;AAUD,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8BZ,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;IAC3E,MAAM,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;CACrC;AAED,eAAO,MAAM,eAAe,EAAE,WAG7B,CAAC;AAqFF;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,cAAc,EACvB,QAAQ,GAAE,WAA6B,GACtC,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAmDjC;AAED,yEAAyE;AACzE,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE,WAA6B,GACtC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwBxB;AAED,8EAA8E;AAC9E,wBAAgB,eAAe,IAAI;IAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAA;CAAE,CAMrG;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,KAAK,GAAE,MAAM,CAAC,cAA8B,EAC5C,MAAM,GAAE,MAAM,CAAC,cAA+B,EAC9C,QAAQ,GAAE,WAA6B,GACtC,OAAO,CAAC,IAAI,CAAC,CAiBf"}
@@ -0,0 +1,267 @@
1
+ import { createInterface } from 'node:readline';
2
+ import { existsSync } from 'node:fs';
3
+ import { chromium } from 'playwright';
4
+ import { runGhostQAAudit, GHOST_QA_VERSION } from '../engine/audit-runner.js';
5
+ import { smokeTestBrowser } from '../engine/browser-session.js';
6
+ import { formatAgentDiagnostic } from '../reporter/agent-diagnostic.js';
7
+ import { DEFAULT_OPTIONS } from '../types.js';
8
+ /**
9
+ * Native MCP (Model Context Protocol) server for ghost-qa.
10
+ *
11
+ * Standard JSON-RPC 2.0 over stdio, implemented with zero external SDKs:
12
+ * newline-delimited JSON in, newline-delimited JSON out, diagnostics on
13
+ * stderr only (stdout is the protocol channel). Compatible with Claude Code,
14
+ * Claude Desktop, Cursor, Codex and any other MCP host:
15
+ *
16
+ * { "mcpServers": { "ghost-qa": { "command": "npx", "args": ["-y", "github:avivgerz-hue/ghost-qa", "mcp"] } } }
17
+ */
18
+ export const MCP_PROTOCOL_VERSION = '2024-11-05';
19
+ export const MCP_SERVER_INFO = { name: 'ghost-qa', version: GHOST_QA_VERSION };
20
+ export const JSON_RPC_ERRORS = {
21
+ parseError: -32700,
22
+ invalidRequest: -32600,
23
+ methodNotFound: -32601,
24
+ invalidParams: -32602,
25
+ internalError: -32603,
26
+ };
27
+ export async function runDoctorCheck() {
28
+ const nodeMajor = Number.parseInt(process.versions.node.split('.')[0] ?? '0', 10);
29
+ const chromiumPath = process.env.GHOST_QA_CHROMIUM_PATH ?? safeExecutablePath();
30
+ const chromiumFound = chromiumPath !== '' && existsSync(chromiumPath);
31
+ let smokeTest = 'not run (Chromium binary not found)';
32
+ let smokeOk = false;
33
+ if (chromiumFound) {
34
+ const smoke = await smokeTestBrowser();
35
+ smokeOk = smoke.ok;
36
+ smokeTest = smoke.detail.replace(/\s+/g, ' ').slice(0, 400);
37
+ }
38
+ return {
39
+ ready: nodeMajor >= 20 && chromiumFound && smokeOk,
40
+ node: process.versions.node,
41
+ nodeOk: nodeMajor >= 20,
42
+ chromiumPath,
43
+ chromiumFound,
44
+ smokeTest,
45
+ };
46
+ }
47
+ function safeExecutablePath() {
48
+ try {
49
+ return chromium.executablePath();
50
+ }
51
+ catch {
52
+ return '';
53
+ }
54
+ }
55
+ export const MCP_TOOLS = [
56
+ {
57
+ name: 'ghost_qa_audit_url',
58
+ description: 'Run the full ghost-qa headless browser audit against a running localhost app: crawls internal routes on Desktop 1440x900 and Mobile 390x844, safely exercises interactive controls, and traps console/hydration errors, failed network requests, layout overflow, accessibility bugs and performance problems. Returns the Self-Healing Bug Report — fix every critical/major issue it reports before declaring the task done.',
59
+ inputSchema: {
60
+ type: 'object',
61
+ properties: {
62
+ url: {
63
+ type: 'string',
64
+ description: 'Target URL of the running app, e.g. http://localhost:3000',
65
+ },
66
+ maxDepth: { type: 'number', description: 'Link-following depth (default 2)' },
67
+ maxRoutes: { type: 'number', description: 'Maximum routes to visit (default 25)' },
68
+ viewport: {
69
+ type: 'string',
70
+ enum: ['both', 'desktop', 'mobile'],
71
+ description: 'Viewports to test (default both)',
72
+ },
73
+ },
74
+ required: ['url'],
75
+ additionalProperties: false,
76
+ },
77
+ },
78
+ {
79
+ name: 'ghost_qa_doctor',
80
+ description: 'Verify ghost-qa environment readiness: Node.js version, Chromium binary availability, and a live headless-browser smoke test. Run this first when an audit fails to start.',
81
+ inputSchema: { type: 'object', properties: {}, additionalProperties: false },
82
+ },
83
+ ];
84
+ export const defaultHandlers = {
85
+ audit: (target, options) => runGhostQAAudit(target, options),
86
+ doctor: () => runDoctorCheck(),
87
+ };
88
+ function toolResult(text, structured, isError = false) {
89
+ return {
90
+ content: [{ type: 'text', text }],
91
+ ...(structured ? { structuredContent: structured } : {}),
92
+ isError,
93
+ };
94
+ }
95
+ function optionsFromArgs(args) {
96
+ const options = { ...DEFAULT_OPTIONS, viewports: [...DEFAULT_OPTIONS.viewports] };
97
+ if (typeof args.maxDepth === 'number' && Number.isFinite(args.maxDepth) && args.maxDepth >= 0) {
98
+ options.maxDepth = Math.floor(args.maxDepth);
99
+ }
100
+ if (typeof args.maxRoutes === 'number' && Number.isFinite(args.maxRoutes) && args.maxRoutes > 0) {
101
+ options.maxRoutes = Math.floor(args.maxRoutes);
102
+ }
103
+ if (args.viewport === 'desktop' || args.viewport === 'mobile') {
104
+ options.viewports = [args.viewport];
105
+ }
106
+ else if (args.viewport === 'both') {
107
+ options.viewports = ['desktop', 'mobile'];
108
+ }
109
+ return options;
110
+ }
111
+ async function callTool(name, args, handlers) {
112
+ switch (name) {
113
+ case 'ghost_qa_audit_url': {
114
+ const url = args.url;
115
+ if (typeof url !== 'string' || !/^https?:\/\//i.test(url)) {
116
+ return toolResult('Invalid argument: "url" must be an http(s) URL of a running app, e.g. http://localhost:3000', undefined, true);
117
+ }
118
+ try {
119
+ const report = await handlers.audit(url, optionsFromArgs(args));
120
+ return toolResult(formatAgentDiagnostic(report), {
121
+ passed: report.passed,
122
+ targetUrl: report.targetUrl,
123
+ routesCrawled: report.summary.routesCrawled,
124
+ interactionsTested: report.summary.interactionsTested,
125
+ totalIssues: report.summary.totalIssues,
126
+ bySeverity: report.summary.bySeverity,
127
+ byCategory: report.summary.byCategory,
128
+ issues: report.issues.map((issue) => ({
129
+ id: issue.id,
130
+ severity: issue.severity,
131
+ category: issue.category,
132
+ type: issue.type,
133
+ route: issue.route,
134
+ viewport: issue.viewport,
135
+ message: issue.message,
136
+ })),
137
+ });
138
+ }
139
+ catch (error) {
140
+ return toolResult(`ghost-qa audit failed to run: ${error instanceof Error ? error.message : String(error)}\n` +
141
+ 'Check that the dev server is running and Chromium is installed (npx playwright install chromium), or call ghost_qa_doctor.', undefined, true);
142
+ }
143
+ }
144
+ case 'ghost_qa_doctor': {
145
+ const result = await handlers.doctor();
146
+ const lines = [
147
+ `ghost-qa doctor — ${result.ready ? 'READY ✔' : 'NOT READY ✖'}`,
148
+ `Node.js: ${result.node} ${result.nodeOk ? '(ok)' : '(requires >= 20)'}`,
149
+ `Chromium: ${result.chromiumFound ? result.chromiumPath : 'not found — run: npx playwright install chromium'}`,
150
+ `Smoke test: ${result.smokeTest}`,
151
+ ];
152
+ return toolResult(lines.join('\n'), { ...result });
153
+ }
154
+ default:
155
+ return null;
156
+ }
157
+ }
158
+ /**
159
+ * Pure JSON-RPC dispatcher — one parsed request in, one response object (or
160
+ * `null` for notifications) out. Fully unit-testable without stdio or a
161
+ * browser when handlers are injected.
162
+ */
163
+ export async function handleJsonRpcRequest(request, handlers = defaultHandlers) {
164
+ const id = request.id ?? null;
165
+ const isNotification = request.id === undefined;
166
+ const respond = (result) => isNotification ? null : { jsonrpc: '2.0', id, result };
167
+ const fail = (code, message) => isNotification ? null : { jsonrpc: '2.0', id, error: { code, message } };
168
+ if (!request || typeof request.method !== 'string') {
169
+ return fail(JSON_RPC_ERRORS.invalidRequest, 'Invalid Request: "method" must be a string.');
170
+ }
171
+ switch (request.method) {
172
+ case 'initialize': {
173
+ const requested = request.params?.protocolVersion;
174
+ return respond({
175
+ protocolVersion: typeof requested === 'string' && requested ? requested : MCP_PROTOCOL_VERSION,
176
+ capabilities: { tools: { listChanged: false } },
177
+ serverInfo: { ...MCP_SERVER_INFO },
178
+ instructions: 'Use ghost_qa_audit_url to verify any frontend change in a real browser before reporting a task complete. Fix every critical/major issue it returns and re-run until it passes.',
179
+ });
180
+ }
181
+ case 'ping':
182
+ return respond({});
183
+ case 'tools/list':
184
+ return respond({ tools: MCP_TOOLS });
185
+ case 'tools/call': {
186
+ const name = request.params?.name;
187
+ const args = (request.params?.arguments ?? {});
188
+ if (typeof name !== 'string') {
189
+ return fail(JSON_RPC_ERRORS.invalidParams, 'tools/call requires params.name (string).');
190
+ }
191
+ const result = await callTool(name, args, handlers);
192
+ if (result === null) {
193
+ return fail(JSON_RPC_ERRORS.invalidParams, `Unknown tool: ${name}`);
194
+ }
195
+ return respond(result);
196
+ }
197
+ case 'resources/list':
198
+ return respond({ resources: [] });
199
+ case 'prompts/list':
200
+ return respond({ prompts: [] });
201
+ default:
202
+ // Notifications (notifications/initialized, notifications/cancelled…)
203
+ // never get a response; unknown requests get Method Not Found.
204
+ if (isNotification)
205
+ return null;
206
+ return fail(JSON_RPC_ERRORS.methodNotFound, `Method not found: ${request.method}`);
207
+ }
208
+ }
209
+ /** Parses one raw line of stdio input into a response line (or null). */
210
+ export async function handleJsonRpcLine(line, handlers = defaultHandlers) {
211
+ const trimmed = line.trim();
212
+ if (!trimmed)
213
+ return null;
214
+ let parsed;
215
+ try {
216
+ parsed = JSON.parse(trimmed);
217
+ }
218
+ catch {
219
+ return JSON.stringify({
220
+ jsonrpc: '2.0',
221
+ id: null,
222
+ error: { code: JSON_RPC_ERRORS.parseError, message: 'Parse error: invalid JSON.' },
223
+ });
224
+ }
225
+ // Batch requests are answered as a batch, per JSON-RPC 2.0.
226
+ if (Array.isArray(parsed)) {
227
+ const responses = [];
228
+ for (const item of parsed) {
229
+ const response = await handleJsonRpcRequest(item, handlers);
230
+ if (response)
231
+ responses.push(response);
232
+ }
233
+ return responses.length > 0 ? JSON.stringify(responses) : null;
234
+ }
235
+ const response = await handleJsonRpcRequest(parsed, handlers);
236
+ return response ? JSON.stringify(response) : null;
237
+ }
238
+ /** The ready-to-paste MCP host configuration installed by `ghost-qa init`. */
239
+ export function mcpServerConfig() {
240
+ return {
241
+ mcpServers: {
242
+ 'ghost-qa': { command: 'npx', args: ['-y', 'github:avivgerz-hue/ghost-qa', 'mcp'] },
243
+ },
244
+ };
245
+ }
246
+ /**
247
+ * Serves MCP over stdio until stdin closes. All human diagnostics go to
248
+ * stderr — stdout carries protocol frames only.
249
+ */
250
+ export function startMcpServer(input = process.stdin, output = process.stdout, handlers = defaultHandlers) {
251
+ process.stderr.write(`ghost-qa MCP server v${GHOST_QA_VERSION} listening on stdio\n`);
252
+ const rl = createInterface({ input, crlfDelay: Infinity });
253
+ return new Promise((resolvePromise) => {
254
+ rl.on('line', (line) => {
255
+ void handleJsonRpcLine(line, handlers)
256
+ .then((responseLine) => {
257
+ if (responseLine)
258
+ output.write(`${responseLine}\n`);
259
+ })
260
+ .catch((error) => {
261
+ process.stderr.write(`ghost-qa MCP handler error: ${error instanceof Error ? error.message : String(error)}\n`);
262
+ });
263
+ });
264
+ rl.on('close', () => resolvePromise());
265
+ });
266
+ }
267
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/mcp/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { GhostQAReport, IssueCategory } from '../types.js';
2
+ /**
3
+ * Token-efficient fix guidance per category. The agent reading the diagnostic
4
+ * should be able to act without re-discovering first principles each run.
5
+ */
6
+ export declare const FIX_PLAYBOOK: Record<IssueCategory, string>;
7
+ /**
8
+ * The Self-Healing Bug Report: deliberately compact Markdown an agent can
9
+ * paste into its own context — verdict first, issues grouped by route, one
10
+ * fix playbook line per category, then the re-verify command.
11
+ */
12
+ export declare function formatAgentDiagnostic(report: GhostQAReport): string;
13
+ /** Structured JSON for CI gates and programmatic agent tooling. */
14
+ export declare function formatAgentDiagnosticJson(report: GhostQAReport): string;
15
+ export type DiagnosticFormat = 'markdown' | 'json';
16
+ export declare function formatDiagnostic(report: GhostQAReport, format: DiagnosticFormat): string;
17
+ //# sourceMappingURL=agent-diagnostic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-diagnostic.d.ts","sourceRoot":"","sources":["../../../src/reporter/agent-diagnostic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAW,MAAM,aAAa,CAAC;AAEzE;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAetD,CAAC;AAsBF;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CA2CnE;AAED,mEAAmE;AACnE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAEvE;AAED,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,MAAM,CAAC;AAEnD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAExF"}