sketchy remove
This commit is contained in:
+1
-10
@@ -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
@@ -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}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
@@ -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
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user