@permissionbrick/auto-review-mcp 0.1.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/dist/server.js ADDED
@@ -0,0 +1,289 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Auto-review MCP orchestrator server.
4
+ *
5
+ * One long-running process serves the MCP over Streamable HTTP on two
6
+ * role-scoped endpoints:
7
+ * - http://<host>:<port>/developer/mcp → developer tools
8
+ * - http://<host>:<port>/reviewer/mcp → reviewer tools
9
+ *
10
+ * Both Claude Code instances connect at the same time; all sessions share one
11
+ * Orchestrator. Role is fixed by the URL path, so no role parameter is needed
12
+ * on the tool calls.
13
+ */
14
+ import http from "node:http";
15
+ import { randomUUID } from "node:crypto";
16
+ import { fileURLToPath } from "node:url";
17
+ import { z } from "zod";
18
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
19
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
20
+ import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
21
+ import { Orchestrator } from "./orchestrator.js";
22
+ import { GET_NEXT_REVIEW_DESC, INITIALIZE_SESSION_DESC, REQUEST_REVIEW_DESC, SIGNAL_COMPLETE_DESC, SUBMIT_REVIEW_DESC, WORKFLOW_STATUS_DESC, timeoutFallbackNote, } from "./descriptions.js";
23
+ const CLI_PATH = fileURLToPath(new URL("./cli.js", import.meta.url));
24
+ function parseArgs(argv) {
25
+ const opts = new Map();
26
+ for (let i = 0; i < argv.length; i++) {
27
+ const a = argv[i];
28
+ if (a.startsWith("--")) {
29
+ const key = a.slice(2);
30
+ const eq = key.indexOf("=");
31
+ if (eq >= 0)
32
+ opts.set(key.slice(0, eq), key.slice(eq + 1));
33
+ else if (i + 1 < argv.length && !argv[i + 1].startsWith("--"))
34
+ opts.set(key, argv[++i]);
35
+ else
36
+ opts.set(key, "true");
37
+ }
38
+ }
39
+ const get = (k, env, dflt) => opts.get(k) ?? process.env[env] ?? dflt;
40
+ const repo = get("repo", "AUTO_REVIEW_REPO");
41
+ const pollSeconds = Number(get("poll-seconds", "AUTO_REVIEW_POLL_SECONDS", "1500"));
42
+ return {
43
+ repo,
44
+ host: get("host", "AUTO_REVIEW_HOST", "0.0.0.0"),
45
+ port: Number(get("port", "AUTO_REVIEW_PORT", "8765")),
46
+ pollMs: Math.max(1, pollSeconds) * 1000,
47
+ maxDiffBytes: Number(get("max-diff-bytes", "AUTO_REVIEW_MAX_DIFF_BYTES", "200000")),
48
+ };
49
+ }
50
+ function log(msg) {
51
+ process.stderr.write(`[${new Date().toISOString()}] ${msg}\n`);
52
+ }
53
+ // ---------------------------------------------------------------------------
54
+ // MCP server (per session) — registers the tools for one role
55
+ // ---------------------------------------------------------------------------
56
+ function jsonResult(payload) {
57
+ return {
58
+ content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
59
+ };
60
+ }
61
+ function buildMcpServer(role, orch, pollCmds) {
62
+ const server = new McpServer({ name: `auto-review-${role}`, version: "0.1.0" });
63
+ if (role === "developer") {
64
+ server.registerTool("initialize_review_session", {
65
+ description: INITIALIZE_SESSION_DESC,
66
+ inputSchema: {
67
+ repo_path: z
68
+ .string()
69
+ .min(1)
70
+ .describe("Absolute path to the root of the git repository you are working in (usually your cwd)."),
71
+ },
72
+ }, async ({ repo_path }) => jsonResult(await orch.initializeSession(repo_path)));
73
+ server.registerTool("request_review", {
74
+ description: `${REQUEST_REVIEW_DESC}\n\n${timeoutFallbackNote(pollCmds.developer, "the reviewer's verdict on the batch you just submitted")}`,
75
+ inputSchema: {
76
+ summary: z
77
+ .string()
78
+ .min(1)
79
+ .describe("What you changed and why, detailed enough for a reviewer to judge it."),
80
+ commit_message: z
81
+ .string()
82
+ .min(1)
83
+ .describe("Commit message for this batch; used verbatim for the commit on approval."),
84
+ },
85
+ }, async ({ summary, commit_message }) => jsonResult(await orch.requestReview(summary, commit_message)));
86
+ server.registerTool("signal_complete", {
87
+ description: SIGNAL_COMPLETE_DESC,
88
+ inputSchema: { note: z.string().optional().describe("Optional closing note.") },
89
+ }, async ({ note }) => jsonResult(await orch.signalComplete(note)));
90
+ }
91
+ else {
92
+ server.registerTool("get_next_review", {
93
+ description: `${GET_NEXT_REVIEW_DESC}\n\n${timeoutFallbackNote(pollCmds.reviewer, "the next batch to review")}`,
94
+ inputSchema: {},
95
+ }, async () => jsonResult(await orch.getNextReview()));
96
+ server.registerTool("submit_review", {
97
+ description: SUBMIT_REVIEW_DESC,
98
+ inputSchema: {
99
+ batch_id: z.string().min(1).describe("The batch_id returned by get_next_review."),
100
+ verdict: z.enum(["approved", "changes_requested"]),
101
+ issue: z
102
+ .string()
103
+ .optional()
104
+ .describe("Required for changes_requested: what is wrong and what to change."),
105
+ category: z
106
+ .enum(["spec", "code"])
107
+ .optional()
108
+ .describe("Required for changes_requested: 'spec' (fails the requirement) or 'code'."),
109
+ },
110
+ }, async ({ batch_id, verdict, issue, category }) => jsonResult(await orch.submitReview(batch_id, verdict, issue, category)));
111
+ }
112
+ // Shared read-only status tool, available to both roles.
113
+ server.registerTool("workflow_status", { description: WORKFLOW_STATUS_DESC, inputSchema: {} }, async () => jsonResult(orch.status()));
114
+ return server;
115
+ }
116
+ function roleForPath(pathname) {
117
+ if (pathname === "/developer" || pathname === "/developer/mcp")
118
+ return "developer";
119
+ if (pathname === "/reviewer" || pathname === "/reviewer/mcp")
120
+ return "reviewer";
121
+ return null;
122
+ }
123
+ function readBody(req) {
124
+ return new Promise((resolve, reject) => {
125
+ const chunks = [];
126
+ req.on("data", (c) => chunks.push(c));
127
+ req.on("end", () => {
128
+ const raw = Buffer.concat(chunks).toString("utf8");
129
+ if (raw.trim() === "")
130
+ return resolve(undefined);
131
+ try {
132
+ resolve(JSON.parse(raw));
133
+ }
134
+ catch (e) {
135
+ reject(e);
136
+ }
137
+ });
138
+ req.on("error", reject);
139
+ });
140
+ }
141
+ function sendJson(res, code, body) {
142
+ res.writeHead(code, { "content-type": "application/json" });
143
+ res.end(JSON.stringify(body));
144
+ }
145
+ function jsonRpcError(res, code, message) {
146
+ sendJson(res, code, { jsonrpc: "2.0", error: { code: -32000, message }, id: null });
147
+ }
148
+ async function main() {
149
+ const cfg = parseArgs(process.argv.slice(2));
150
+ const orch = new Orchestrator({
151
+ pollMs: cfg.pollMs,
152
+ maxDiffBytes: cfg.maxDiffBytes,
153
+ log,
154
+ });
155
+ // --repo is optional: if given, pre-initialize; otherwise the developer agent
156
+ // sets it at runtime via initialize_review_session.
157
+ if (cfg.repo) {
158
+ const init = await orch.initializeSession(cfg.repo);
159
+ if (init.status === "error") {
160
+ log(`WARNING: --repo '${cfg.repo}' could not be used (${init.message}). ` +
161
+ `Awaiting initialize_review_session from the developer agent.`);
162
+ }
163
+ }
164
+ // Shell commands the agent runs as a client-timeout fallback (see descriptions).
165
+ // Quoted so paths with spaces survive copy-paste into a shell.
166
+ const node = JSON.stringify(process.execPath);
167
+ const cli = JSON.stringify(CLI_PATH);
168
+ const pollCmds = {
169
+ developer: `${node} ${cli} await-verdict --port ${cfg.port} --timeout 3600`,
170
+ reviewer: `${node} ${cli} next-review --port ${cfg.port} --timeout 3600`,
171
+ };
172
+ const sessions = new Map();
173
+ const httpServer = http.createServer(async (req, res) => {
174
+ try {
175
+ const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
176
+ const pathname = url.pathname;
177
+ if (pathname === "/healthz" || pathname === "/") {
178
+ sendJson(res, 200, { ok: true, service: "auto-review", status: orch.status() });
179
+ return;
180
+ }
181
+ // Plain-HTTP long-poll endpoints used by the `cli.js` poll command (no MCP
182
+ // session). Each blocks up to the poll window, then returns JSON; the CLI
183
+ // re-polls internally so the agent sees one long-blocking shell command.
184
+ if (req.method === "GET" && pathname === "/reviewer/next-review") {
185
+ sendJson(res, 200, await orch.getNextReview());
186
+ return;
187
+ }
188
+ if (req.method === "GET" && pathname === "/developer/await-verdict") {
189
+ sendJson(res, 200, await orch.awaitVerdict());
190
+ return;
191
+ }
192
+ const role = roleForPath(pathname);
193
+ if (!role) {
194
+ sendJson(res, 404, {
195
+ error: "Unknown path. Use /developer/mcp or /reviewer/mcp.",
196
+ });
197
+ return;
198
+ }
199
+ const sidHeader = req.headers["mcp-session-id"];
200
+ const sessionId = Array.isArray(sidHeader) ? sidHeader[0] : sidHeader;
201
+ if (req.method === "POST") {
202
+ const body = await readBody(req).catch(() => undefined);
203
+ const existing = sessionId ? sessions.get(sessionId) : undefined;
204
+ if (existing) {
205
+ if (existing.role !== role) {
206
+ jsonRpcError(res, 400, `Session belongs to the '${existing.role}' endpoint.`);
207
+ return;
208
+ }
209
+ await existing.transport.handleRequest(req, res, body);
210
+ return;
211
+ }
212
+ if (sessionId) {
213
+ jsonRpcError(res, 404, "Unknown or expired session id. Re-initialize.");
214
+ return;
215
+ }
216
+ if (!isInitializeRequest(body)) {
217
+ jsonRpcError(res, 400, "No session id and not an initialize request.");
218
+ return;
219
+ }
220
+ // New session for this role.
221
+ const transport = new StreamableHTTPServerTransport({
222
+ sessionIdGenerator: () => randomUUID(),
223
+ enableJsonResponse: true,
224
+ onsessioninitialized: (id) => {
225
+ sessions.set(id, { transport, role });
226
+ log(`${role} session initialised: ${id}`);
227
+ },
228
+ });
229
+ transport.onclose = () => {
230
+ if (transport.sessionId) {
231
+ sessions.delete(transport.sessionId);
232
+ log(`${role} session closed: ${transport.sessionId}`);
233
+ }
234
+ };
235
+ const mcp = buildMcpServer(role, orch, pollCmds);
236
+ await mcp.connect(transport);
237
+ await transport.handleRequest(req, res, body);
238
+ return;
239
+ }
240
+ if (req.method === "GET" || req.method === "DELETE") {
241
+ const existing = sessionId ? sessions.get(sessionId) : undefined;
242
+ if (!existing || existing.role !== role) {
243
+ jsonRpcError(res, 400, "Invalid or missing session id for this endpoint.");
244
+ return;
245
+ }
246
+ await existing.transport.handleRequest(req, res);
247
+ return;
248
+ }
249
+ res.writeHead(405, { allow: "GET, POST, DELETE" });
250
+ res.end();
251
+ }
252
+ catch (err) {
253
+ log(`request error: ${err.stack ?? String(err)}`);
254
+ if (!res.headersSent)
255
+ jsonRpcError(res, 500, "Internal server error.");
256
+ else
257
+ res.end();
258
+ }
259
+ });
260
+ // No socket-level timeout: tool calls may legitimately be held open for the
261
+ // full poll window. Keep TCP alive for long-held connections.
262
+ httpServer.requestTimeout = 0;
263
+ httpServer.headersTimeout = 0;
264
+ httpServer.keepAliveTimeout = 0;
265
+ httpServer.timeout = 0;
266
+ httpServer.on("error", (err) => {
267
+ if (err.code === "EADDRINUSE") {
268
+ // Another coordinator already owns the port (e.g. the other agent started
269
+ // it first). That one serves both agents; this one is redundant.
270
+ log(`port ${cfg.port} already in use — assuming another coordinator is running. Exiting.`);
271
+ process.exit(0);
272
+ }
273
+ log(`FATAL: HTTP server error: ${err.stack ?? String(err)}`);
274
+ process.exit(1);
275
+ });
276
+ httpServer.listen(cfg.port, cfg.host, () => {
277
+ log(`auto-review MCP server listening on http://${cfg.host}:${cfg.port}`);
278
+ log(` repo under review : ${orch.status().repo ?? "(awaiting initialize_review_session)"}`);
279
+ log(` developer endpoint: http://${cfg.host}:${cfg.port}/developer/mcp`);
280
+ log(` reviewer endpoint : http://${cfg.host}:${cfg.port}/reviewer/mcp`);
281
+ log(` poll window : ${cfg.pollMs / 1000}s max diff: ${cfg.maxDiffBytes} bytes`);
282
+ log(` set MCP_TOOL_TIMEOUT >= ${cfg.pollMs}ms in each agent instance`);
283
+ });
284
+ }
285
+ main().catch((err) => {
286
+ log(`FATAL: ${err?.stack ?? String(err)}`);
287
+ process.exit(1);
288
+ });
289
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/dist/stdio.js ADDED
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Stdio entrypoint for the `command: "node"` MCP config type.
4
+ *
5
+ * Claude Code / Codex spawns ONE of these per agent (developer / reviewer) over
6
+ * stdio. Because the two agents are separate processes, the shared review state
7
+ * can't live inside them — so this is a thin PROXY:
8
+ *
9
+ * client ──stdio──▶ this proxy ──HTTP──▶ shared coordinator (singleton)
10
+ *
11
+ * It ensures one background coordinator is running, connects to that
12
+ * coordinator's role endpoint as an MCP client, and transparently forwards
13
+ * tools/list and tools/call.
14
+ *
15
+ * Usage (via .mcp.json / config.toml):
16
+ * command: node
17
+ * args: [".../dist/stdio.js", "--role", "developer"]
18
+ */
19
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
20
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
21
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
22
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
23
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
24
+ import { ensureCoordinator } from "./launch.js";
25
+ function err(msg) {
26
+ process.stderr.write(`[auto-review stdio] ${msg}\n`);
27
+ }
28
+ function parseConfig(argv) {
29
+ const opts = new Map();
30
+ for (let i = 0; i < argv.length; i++) {
31
+ const a = argv[i];
32
+ if (!a.startsWith("--"))
33
+ continue;
34
+ const key = a.slice(2);
35
+ const eq = key.indexOf("=");
36
+ if (eq >= 0)
37
+ opts.set(key.slice(0, eq), key.slice(eq + 1));
38
+ else if (i + 1 < argv.length && !argv[i + 1].startsWith("--"))
39
+ opts.set(key, argv[++i]);
40
+ else
41
+ opts.set(key, "true");
42
+ }
43
+ const get = (k, env, dflt) => opts.get(k) ?? process.env[env] ?? dflt;
44
+ const role = get("role", "AUTO_REVIEW_ROLE");
45
+ if (role !== "developer" && role !== "reviewer") {
46
+ err(`--role must be 'developer' or 'reviewer' (got: ${role ?? "unset"})`);
47
+ process.exit(1);
48
+ }
49
+ return {
50
+ role,
51
+ repo: get("repo", "AUTO_REVIEW_REPO"),
52
+ host: get("host", "AUTO_REVIEW_HOST", "127.0.0.1"),
53
+ port: Number(get("port", "AUTO_REVIEW_PORT", "8765")),
54
+ pollSeconds: Number(get("poll-seconds", "AUTO_REVIEW_POLL_SECONDS", "40")),
55
+ maxDiffBytes: Number(get("max-diff-bytes", "AUTO_REVIEW_MAX_DIFF_BYTES", "200000")),
56
+ };
57
+ }
58
+ async function main() {
59
+ const cfg = parseConfig(process.argv.slice(2));
60
+ await ensureCoordinator({ ...cfg, log: err });
61
+ // Connect to the coordinator as an MCP client on this agent's role endpoint.
62
+ const endpoint = `http://${cfg.host}:${cfg.port}/${cfg.role}/mcp`;
63
+ const client = new Client({ name: `auto-review-proxy-${cfg.role}`, version: "0.1.0" });
64
+ await client.connect(new StreamableHTTPClientTransport(new URL(endpoint)));
65
+ // Generous timeout for forwarded blocking calls; the coordinator returns
66
+ // keep_waiting within its poll window, so this only needs headroom.
67
+ const callTimeoutMs = (cfg.pollSeconds + 30) * 1000;
68
+ // Expose a stdio MCP server that transparently mirrors the coordinator's
69
+ // tools (single source of truth = the coordinator).
70
+ const server = new Server({ name: `auto-review-${cfg.role}`, version: "0.1.0" }, { capabilities: { tools: {} } });
71
+ server.setRequestHandler(ListToolsRequestSchema, async () => client.listTools());
72
+ server.setRequestHandler(CallToolRequestSchema, async (req) => client.callTool(req.params, undefined, { timeout: callTimeoutMs }));
73
+ const shutdown = async () => {
74
+ try {
75
+ await client.close();
76
+ }
77
+ catch {
78
+ /* ignore */
79
+ }
80
+ process.exit(0);
81
+ };
82
+ process.on("SIGINT", shutdown);
83
+ process.on("SIGTERM", shutdown);
84
+ await server.connect(new StdioServerTransport());
85
+ err(`ready: proxying ${cfg.role} → ${endpoint}`);
86
+ }
87
+ main().catch((e) => {
88
+ err(`FATAL: ${e?.stack ?? String(e)}`);
89
+ process.exit(1);
90
+ });
91
+ //# sourceMappingURL=stdio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio.js","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAYhD,SAAS,GAAG,CAAC,GAAW;IACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,WAAW,CAAC,IAAc;IACjC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QAClC,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,EAAE,IAAI,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;aACtD,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;;YACnF,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC7B,CAAC;IACD,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,GAAW,EAAE,IAAa,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;IAE/F,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAqB,CAAC;IACjE,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;QAChD,GAAG,CAAC,kDAAkD,IAAI,IAAI,OAAO,GAAG,CAAC,CAAC;QAC1E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO;QACL,IAAI;QACJ,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC;QACrC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,EAAE,WAAW,CAAE;QACnD,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,kBAAkB,EAAE,MAAM,CAAC,CAAC;QACrD,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,0BAA0B,EAAE,IAAI,CAAC,CAAC;QAC1E,YAAY,EAAE,MAAM,CAAC,GAAG,CAAC,gBAAgB,EAAE,4BAA4B,EAAE,QAAQ,CAAC,CAAC;KACpF,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,GAAG,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,MAAM,iBAAiB,CAAC,EAAE,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;IAE9C,6EAA6E;IAC7E,MAAM,QAAQ,GAAG,UAAU,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,MAAM,CAAC;IAClE,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,IAAI,EAAE,qBAAqB,GAAG,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IACvF,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,6BAA6B,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAE3E,yEAAyE;IACzE,oEAAoE;IACpE,MAAM,aAAa,GAAG,CAAC,GAAG,CAAC,WAAW,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;IAEpD,yEAAyE;IACzE,oDAAoD;IACpD,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,EAAE,IAAI,EAAE,eAAe,GAAG,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EACrD,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAChC,CAAC;IACF,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;IACjF,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,CAC5D,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CACnE,CAAC;IAEF,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,YAAY;QACd,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAEhC,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;IACjD,GAAG,CAAC,mBAAmB,GAAG,CAAC,IAAI,MAAM,QAAQ,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;IACjB,GAAG,CAAC,UAAU,CAAC,EAAE,KAAK,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Shared types for the auto-review orchestrator.
3
+ *
4
+ * The wire shapes returned to the agents are plain JSON objects (serialised as
5
+ * the text content of each tool result). They are intentionally small and
6
+ * self-describing so an agent can act on them with no extra context.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@permissionbrick/auto-review-mcp",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Local MCP server that orchestrates an auto-review loop between a developer agent and a reviewer agent.",
6
+ "keywords": [
7
+ "mcp",
8
+ "model-context-protocol",
9
+ "code-review",
10
+ "ai-agents",
11
+ "claude-code",
12
+ "codex",
13
+ "developer-tools"
14
+ ],
15
+ "license": "MIT",
16
+ "author": "permissionBRICK",
17
+ "homepage": "https://github.com/permissionBRICK/auto-review#readme",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/permissionBRICK/auto-review.git"
21
+ },
22
+ "bugs": {
23
+ "url": "https://github.com/permissionBRICK/auto-review/issues"
24
+ },
25
+ "engines": {
26
+ "node": ">=18"
27
+ },
28
+ "bin": {
29
+ "auto-review-mcp": "dist/stdio.js",
30
+ "auto-review-server": "dist/server.js",
31
+ "auto-review-cli": "dist/cli.js"
32
+ },
33
+ "files": [
34
+ "dist"
35
+ ],
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "scripts": {
40
+ "build": "tsc -p tsconfig.json",
41
+ "start": "node dist/server.js",
42
+ "dev": "tsx src/server.ts",
43
+ "demo": "tsx scripts/demo.ts",
44
+ "demo:stdio": "tsx scripts/demo-stdio.ts",
45
+ "demo:cli": "tsx scripts/demo-cli.ts",
46
+ "prepare": "npm run build"
47
+ },
48
+ "dependencies": {
49
+ "@modelcontextprotocol/sdk": "^1.12.0",
50
+ "zod": "^3.23.8"
51
+ },
52
+ "devDependencies": {
53
+ "@types/node": "^22.0.0",
54
+ "tsx": "^4.19.0",
55
+ "typescript": "^5.5.0"
56
+ }
57
+ }