sketchy remove

This commit is contained in:
Shawn Morreau
2025-11-20 14:04:47 -05:00
parent 96055edda7
commit ed39bda62a
6 changed files with 90 additions and 14 deletions
+1 -10
View File
@@ -21,24 +21,18 @@ export const cursor = agent({
configureCursorMcpServers({ mcpServers, cliPath }); configureCursorMcpServers({ mcpServers, cliPath });
try { try {
// Run cursor-agent in non-interactive mode with the prompt
// Using -p flag for prompt, --output-format text for plain text output
// and --approve-mcps to automatically approve all MCP servers
const fullPrompt = addInstructions(payload); const fullPrompt = addInstructions(payload);
// Find temp directory from cliPath to set HOME for MCP config lookup
const tempDir = cliPath.split("/.local/bin/")[0]; const tempDir = cliPath.split("/.local/bin/")[0];
log.info("Running Cursor CLI..."); log.info("Running Cursor CLI...");
// Use spawn to handle streaming output
// Use --print flag explicitly for non-interactive mode
return new Promise((resolve) => { return new Promise((resolve) => {
const child = spawn( const child = spawn(
cliPath, cliPath,
["--print", fullPrompt, "--output-format", "text", "--approve-mcps", "--force"], ["--print", fullPrompt, "--output-format", "text", "--approve-mcps", "--force"],
{ {
cwd: process.cwd(), // Run in current working directory cwd: process.cwd(),
env: { env: {
...process.env, ...process.env,
CURSOR_API_KEY: apiKey, CURSOR_API_KEY: apiKey,
@@ -52,7 +46,6 @@ export const cursor = agent({
let stdout = ""; let stdout = "";
let stderr = ""; let stderr = "";
// Log when process starts
child.on("spawn", () => { child.on("spawn", () => {
log.debug("Cursor CLI process spawned"); log.debug("Cursor CLI process spawned");
}); });
@@ -67,12 +60,10 @@ export const cursor = agent({
child.stderr?.on("data", (data) => { child.stderr?.on("data", (data) => {
const text = data.toString(); const text = data.toString();
stderr += text; stderr += text;
// Log errors as they come - but also write to stdout so we can see it
process.stderr.write(text); process.stderr.write(text);
log.warning(text); log.warning(text);
}); });
// Handle process exit
child.on("close", (code, signal) => { child.on("close", (code, signal) => {
if (signal) { if (signal) {
log.warning(`Cursor CLI terminated by signal: ${signal}`); log.warning(`Cursor CLI terminated by signal: ${signal}`);
+2 -2
View File
@@ -32,10 +32,11 @@ export const gemini = agent({
try { try {
const result = await spawn({ const result = await spawn({
cmd: "node", cmd: "node",
args: [cliPath, "--yolo", "--output-format", "text", "-p", sessionPrompt], args: [cliPath, "--yolo", "--output-format=text", "-p", sessionPrompt],
env: { env: {
GEMINI_API_KEY: apiKey, GEMINI_API_KEY: apiKey,
GITHUB_INSTALLATION_TOKEN: githubInstallationToken, GITHUB_INSTALLATION_TOKEN: githubInstallationToken,
GEMINI_CLI_DISABLE_SCHEMA_VALIDATION: "1",
}, },
onStdout: (chunk) => { onStdout: (chunk) => {
const trimmed = chunk.trim(); const trimmed = chunk.trim();
@@ -94,7 +95,6 @@ function configureGeminiMcpServers({ mcpServers, cliPath }: ConfigureMcpServersP
const addArgs = ["mcp", "add", serverName, command, ...args]; const addArgs = ["mcp", "add", serverName, command, ...args];
// Add environment variables as --env flags
for (const [key, value] of Object.entries(envVars)) { for (const [key, value] of Object.entries(envVars)) {
addArgs.push("--env", `${key}=${value}`); addArgs.push("--env", `${key}=${value}`);
} }
+2
View File
@@ -1,5 +1,7 @@
import { spawnSync } from "node:child_process"; import { spawnSync } from "node:child_process";
import { chmodSync, createWriteStream, existsSync } from "node:fs"; import { chmodSync, createWriteStream, existsSync } from "node:fs";
import { mkdtemp } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import { pipeline } from "node:stream/promises"; import { pipeline } from "node:stream/promises";
import type { McpStdioServerConfig } from "@anthropic-ai/claude-agent-sdk"; import type { McpStdioServerConfig } from "@anthropic-ai/claude-agent-sdk";
+1 -1
View File
@@ -1 +1 @@
create a comment on https://github.com/pullfrogai/scratch/pull/29 that says Things just got out of hand comment on https://github.com/pullfrogai/scratch/pull/29 that writes a really funny joke about Arktype
+56
View File
@@ -36,4 +36,60 @@ addTools(server, [
GetCheckSuiteLogsTool, GetCheckSuiteLogsTool,
]); ]);
// intercept stdout to remove $schema fields from JSON-RPC messages
// FastMCP uses stdout for JSON-RPC communication, so we intercept here
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
process.stdout.write = function (chunk: any, encoding?: any, cb?: any): boolean {
if (typeof chunk === "string" || Buffer.isBuffer(chunk)) {
try {
const text = typeof chunk === "string" ? chunk : chunk.toString("utf-8");
// MCP uses JSON-RPC over stdio, messages are JSON objects on single lines
const lines = text.split("\n");
const modifiedLines = lines.map((line) => {
const trimmed = line.trim();
// only process lines that look like JSON-RPC messages
if (trimmed.startsWith("{") && trimmed.includes('"jsonrpc"')) {
try {
const parsed = JSON.parse(trimmed);
// recursively remove $schema fields from the message
const cleaned = removeSchemaFields(parsed);
return JSON.stringify(cleaned) + "\n";
} catch {
// if parsing fails, return original line
return line + (line.endsWith("\n") ? "" : "\n");
}
}
return line + (line.endsWith("\n") ? "" : "\n");
});
const result = modifiedLines.join("");
return originalStdoutWrite(result, encoding, cb);
} catch {
// if anything fails, just pass through
}
}
return originalStdoutWrite(chunk, encoding, cb);
};
// recursively remove $schema fields from JSON objects
function removeSchemaFields(obj: any): any {
if (obj === null || typeof obj !== "object") {
return obj;
}
if (Array.isArray(obj)) {
return obj.map(removeSchemaFields);
}
const result: any = {};
for (const [key, value] of Object.entries(obj)) {
// skip $schema fields
if (key === "$schema") {
continue;
}
result[key] = removeSchemaFields(value);
}
return result;
}
server.start(); server.start();
+28 -1
View File
@@ -65,9 +65,36 @@ export const tool = <const params>(toolDef: Tool<any, StandardSchemaV1<params>>)
return toolDef; return toolDef;
}; };
// recursively remove $schema fields from JSON Schema objects
function removeSchemaFields(obj: any): any {
if (obj === null || typeof obj !== "object") {
return obj;
}
if (Array.isArray(obj)) {
return obj.map(removeSchemaFields);
}
const result: any = {};
for (const [key, value] of Object.entries(obj)) {
// skip $schema fields
if (key === "$schema") {
continue;
}
result[key] = removeSchemaFields(value);
}
return result;
}
export const addTools = (server: FastMCP, tools: Tool<any, any>[]) => { export const addTools = (server: FastMCP, tools: Tool<any, any>[]) => {
for (const tool of tools) { for (const tool of tools) {
server.addTool(tool); // clone tool and remove $schema from parameters schema
const cleanedTool = {
...tool,
parameters: tool.parameters ? removeSchemaFields(tool.parameters) : undefined,
};
server.addTool(cleanedTool);
} }
return server; return server;
}; };