Extract adapter registry across CLI, server, and UI
Refactor monolithic heartbeat service, AgentConfigForm, and CLI heartbeat-run into a proper adapter registry pattern. Each adapter type (process, claude-local, codex-local, http) gets its own module with server-side execution logic, CLI invocation, and UI config form. Significantly reduces file sizes and enables adding new adapters without touching core code. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
77
server/src/adapters/process/execute.ts
Normal file
77
server/src/adapters/process/execute.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import type { AdapterExecutionContext, AdapterExecutionResult } from "../types.js";
|
||||
import {
|
||||
asString,
|
||||
asNumber,
|
||||
asStringArray,
|
||||
parseObject,
|
||||
buildPaperclipEnv,
|
||||
redactEnvForLogs,
|
||||
runChildProcess,
|
||||
} from "../utils.js";
|
||||
|
||||
export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExecutionResult> {
|
||||
const { runId, agent, config, onLog, onMeta } = ctx;
|
||||
const command = asString(config.command, "");
|
||||
if (!command) throw new Error("Process adapter missing command");
|
||||
|
||||
const args = asStringArray(config.args);
|
||||
const cwd = asString(config.cwd, process.cwd());
|
||||
const envConfig = parseObject(config.env);
|
||||
const env: Record<string, string> = { ...buildPaperclipEnv(agent) };
|
||||
for (const [k, v] of Object.entries(envConfig)) {
|
||||
if (typeof v === "string") env[k] = v;
|
||||
}
|
||||
|
||||
const timeoutSec = asNumber(config.timeoutSec, 900);
|
||||
const graceSec = asNumber(config.graceSec, 15);
|
||||
|
||||
if (onMeta) {
|
||||
await onMeta({
|
||||
adapterType: "process",
|
||||
command,
|
||||
cwd,
|
||||
commandArgs: args,
|
||||
env: redactEnvForLogs(env),
|
||||
});
|
||||
}
|
||||
|
||||
const proc = await runChildProcess(runId, command, args, {
|
||||
cwd,
|
||||
env,
|
||||
timeoutSec,
|
||||
graceSec,
|
||||
onLog,
|
||||
});
|
||||
|
||||
if (proc.timedOut) {
|
||||
return {
|
||||
exitCode: proc.exitCode,
|
||||
signal: proc.signal,
|
||||
timedOut: true,
|
||||
errorMessage: `Timed out after ${timeoutSec}s`,
|
||||
};
|
||||
}
|
||||
|
||||
if ((proc.exitCode ?? 0) !== 0) {
|
||||
return {
|
||||
exitCode: proc.exitCode,
|
||||
signal: proc.signal,
|
||||
timedOut: false,
|
||||
errorMessage: `Process exited with code ${proc.exitCode ?? -1}`,
|
||||
resultJson: {
|
||||
stdout: proc.stdout,
|
||||
stderr: proc.stderr,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
exitCode: proc.exitCode,
|
||||
signal: proc.signal,
|
||||
timedOut: false,
|
||||
resultJson: {
|
||||
stdout: proc.stdout,
|
||||
stderr: proc.stderr,
|
||||
},
|
||||
};
|
||||
}
|
||||
8
server/src/adapters/process/index.ts
Normal file
8
server/src/adapters/process/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import type { ServerAdapterModule } from "../types.js";
|
||||
import { execute } from "./execute.js";
|
||||
|
||||
export const processAdapter: ServerAdapterModule = {
|
||||
type: "process",
|
||||
execute,
|
||||
models: [],
|
||||
};
|
||||
Reference in New Issue
Block a user