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:
18
ui/src/adapters/process/build-config.ts
Normal file
18
ui/src/adapters/process/build-config.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import type { CreateConfigValues } from "../../components/AgentConfigForm";
|
||||
|
||||
function parseCommaArgs(value: string): string[] {
|
||||
return value
|
||||
.split(",")
|
||||
.map((item) => item.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
export function buildProcessConfig(v: CreateConfigValues): Record<string, unknown> {
|
||||
const ac: Record<string, unknown> = {};
|
||||
if (v.cwd) ac.cwd = v.cwd;
|
||||
ac.timeoutSec = 0;
|
||||
ac.graceSec = 15;
|
||||
if (v.command) ac.command = v.command;
|
||||
if (v.args) ac.args = parseCommaArgs(v.args);
|
||||
return ac;
|
||||
}
|
||||
77
ui/src/adapters/process/config-fields.tsx
Normal file
77
ui/src/adapters/process/config-fields.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
import type { AdapterConfigFieldsProps } from "../types";
|
||||
import {
|
||||
Field,
|
||||
DraftInput,
|
||||
help,
|
||||
} from "../../components/agent-config-primitives";
|
||||
|
||||
const inputClass =
|
||||
"w-full rounded-md border border-border px-2.5 py-1.5 bg-transparent outline-none text-sm font-mono placeholder:text-muted-foreground/40";
|
||||
|
||||
function formatArgList(value: unknown): string {
|
||||
if (Array.isArray(value)) {
|
||||
return value
|
||||
.filter((item): item is string => typeof item === "string")
|
||||
.join(", ");
|
||||
}
|
||||
return typeof value === "string" ? value : "";
|
||||
}
|
||||
|
||||
function parseCommaArgs(value: string): string[] {
|
||||
return value
|
||||
.split(",")
|
||||
.map((item) => item.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
export function ProcessConfigFields({
|
||||
isCreate,
|
||||
values,
|
||||
set,
|
||||
config,
|
||||
eff,
|
||||
mark,
|
||||
}: AdapterConfigFieldsProps) {
|
||||
return (
|
||||
<>
|
||||
<Field label="Command" hint={help.command}>
|
||||
<DraftInput
|
||||
value={
|
||||
isCreate
|
||||
? values!.command
|
||||
: eff("adapterConfig", "command", String(config.command ?? ""))
|
||||
}
|
||||
onCommit={(v) =>
|
||||
isCreate
|
||||
? set!({ command: v })
|
||||
: mark("adapterConfig", "command", v || undefined)
|
||||
}
|
||||
immediate
|
||||
className={inputClass}
|
||||
placeholder="e.g. node, python"
|
||||
/>
|
||||
</Field>
|
||||
<Field label="Args (comma-separated)" hint={help.args}>
|
||||
<DraftInput
|
||||
value={
|
||||
isCreate
|
||||
? values!.args
|
||||
: eff("adapterConfig", "args", formatArgList(config.args))
|
||||
}
|
||||
onCommit={(v) =>
|
||||
isCreate
|
||||
? set!({ args: v })
|
||||
: mark(
|
||||
"adapterConfig",
|
||||
"args",
|
||||
v ? parseCommaArgs(v) : undefined,
|
||||
)
|
||||
}
|
||||
immediate
|
||||
className={inputClass}
|
||||
placeholder="e.g. script.js, --flag"
|
||||
/>
|
||||
</Field>
|
||||
</>
|
||||
);
|
||||
}
|
||||
12
ui/src/adapters/process/index.ts
Normal file
12
ui/src/adapters/process/index.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import type { UIAdapterModule } from "../types";
|
||||
import { parseProcessStdoutLine } from "./parse-stdout";
|
||||
import { ProcessConfigFields } from "./config-fields";
|
||||
import { buildProcessConfig } from "./build-config";
|
||||
|
||||
export const processUIAdapter: UIAdapterModule = {
|
||||
type: "process",
|
||||
label: "Shell Process",
|
||||
parseStdoutLine: parseProcessStdoutLine,
|
||||
ConfigFields: ProcessConfigFields,
|
||||
buildAdapterConfig: buildProcessConfig,
|
||||
};
|
||||
5
ui/src/adapters/process/parse-stdout.ts
Normal file
5
ui/src/adapters/process/parse-stdout.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import type { TranscriptEntry } from "../types";
|
||||
|
||||
export function parseProcessStdoutLine(line: string, ts: string): TranscriptEntry[] {
|
||||
return [{ kind: "stdout", ts, text: line }];
|
||||
}
|
||||
Reference in New Issue
Block a user