diff --git a/package.json b/package.json index d2ca2ac..fb2b1da 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@farhoodliquor/paperclip-adapter-claude-k8s", - "version": "0.1.8", + "version": "0.1.9", "description": "Paperclip adapter plugin that runs Claude Code agents as Kubernetes Jobs", "license": "MIT", "repository": { diff --git a/src/server/config-schema.ts b/src/server/config-schema.ts index e9ce2a7..1a80bf6 100644 --- a/src/server/config-schema.ts +++ b/src/server/config-schema.ts @@ -1,173 +1,116 @@ -export interface AdapterConfigSchema { - sections?: AdapterConfigSection[]; +// NOTE: These types must match what Paperclip's SchemaConfigFields component +// expects. Paperclip's server at GET /api/adapters/:type/config-schema +// calls adapter.getConfigSchema() and the UI reads the JSON — types are only +// used at build time here. The Paperclip types in @paperclipai/adapter-utils +// may lag behind; these locals are the source of truth for this adapter. + +interface ConfigFieldOption { + label: string; + value: string; + group?: string; } -export interface AdapterConfigSection { - title: string; +type ConfigFieldSchema = + | { type: "text"; key: string; label: string; hint?: string; default?: unknown; meta?: Record } + | { type: "number"; key: string; label: string; hint?: string; default?: unknown; meta?: Record } + | { type: "toggle"; key: string; label: string; hint?: string; default?: unknown; meta?: Record } + | { type: "select"; key: string; label: string; hint?: string; options: ConfigFieldOption[]; default?: unknown; meta?: Record } + | { type: "textarea"; key: string; label: string; hint?: string; default?: unknown; meta?: Record } + | { type: "combobox"; key: string; label: string; hint?: string; options?: ConfigFieldOption[]; default?: unknown; meta?: Record }; + +interface AdapterConfigSchema { fields: ConfigFieldSchema[]; } -export type ConfigFieldSchema = - | TextFieldSchema - | NumberFieldSchema - | ToggleFieldSchema - | SelectFieldSchema - | TextareaFieldSchema; - -export interface TextFieldSchema { - type: "text"; - key: string; - label: string; - description?: string; - placeholder?: string; - helpLink?: string; -} - -export interface NumberFieldSchema { - type: "number"; - key: string; - label: string; - description?: string; - placeholder?: string; - helpLink?: string; -} - -export interface ToggleFieldSchema { - type: "toggle"; - key: string; - label: string; - description?: string; - helpLink?: string; -} - -export interface SelectFieldSchema { - type: "select"; - key: string; - label: string; - description?: string; - options: { value: string; label: string }[]; - helpLink?: string; -} - -export interface TextareaFieldSchema { - type: "textarea"; - key: string; - label: string; - description?: string; - placeholder?: string; - helpLink?: string; -} - export function getConfigSchema(): AdapterConfigSchema { - return { - sections: [ - { - title: "Kubernetes", - fields: [ - { - type: "text", - key: "namespace", - label: "Namespace", - description: "Kubernetes namespace for Jobs. Defaults to the Deployment namespace.", - }, - { - type: "text", - key: "image", - label: "Container Image", - description: "Override the container image used for Job pods. Defaults to the running Deployment image.", - placeholder: "registry/image:tag", - }, - { - type: "select", - key: "imagePullPolicy", - label: "Image Pull Policy", - description: "Image pull policy for the container image.", - options: [ - { value: "IfNotPresent", label: "IfNotPresent" }, - { value: "Always", label: "Always" }, - { value: "Never", label: "Never" }, - ], - }, - { - type: "text", - key: "kubeconfig", - label: "Kubeconfig Path", - description: "Absolute path to a kubeconfig file on disk. Defaults to in-cluster service account auth.", - placeholder: "/path/to/kubeconfig", - }, - { - type: "number", - key: "ttlSecondsAfterFinished", - label: "TTL Seconds After Finished", - description: "Auto-cleanup delay for completed Jobs in seconds. Default: 300.", - }, - { - type: "toggle", - key: "retainJobs", - label: "Retain Jobs", - description: "Skip cleanup of completed Jobs for debugging purposes.", - }, - ], - }, - { - title: "Resource Limits", - fields: [ - { - type: "text", - key: "resources.requests.cpu", - label: "CPU Request", - description: "CPU request for Job pods (e.g. 100m, 0.5, 1).", - placeholder: "100m", - }, - { - type: "text", - key: "resources.requests.memory", - label: "Memory Request", - description: "Memory request for Job pods (e.g. 128Mi, 512Mi, 1Gi).", - placeholder: "512Mi", - }, - { - type: "text", - key: "resources.limits.cpu", - label: "CPU Limit", - description: "CPU limit for Job pods (e.g. 100m, 0.5, 1).", - placeholder: "1000m", - }, - { - type: "text", - key: "resources.limits.memory", - label: "Memory Limit", - description: "Memory limit for Job pods (e.g. 128Mi, 512Mi, 1Gi).", - placeholder: "1Gi", - }, - ], - }, - { - title: "Scheduling", - fields: [ - { - type: "textarea", - key: "nodeSelector", - label: "Node Selector", - description: "Node selector for Job pods. One key=value per line (e.g. disktype=ssd).", - placeholder: "disktype=ssd\ngpu=true", - }, - { - type: "textarea", - key: "tolerations", - label: "Tolerations", - description: "Tolerations for Job pods as JSON array.", - placeholder: '[{"key":"node-type","operator":"Equal","value":"gpu","effect":"NoSchedule"}]', - }, - { - type: "textarea", - key: "labels", - label: "Labels", - description: "Extra labels added to Job metadata. One key=value per line.", - placeholder: "team=ai\nenv=prod", - }, - ], - }, - ], - }; + const fields: ConfigFieldSchema[] = [ + // Kubernetes + { + type: "text", + key: "namespace", + label: "Namespace", + hint: "Kubernetes namespace for Jobs. Defaults to the Deployment namespace.", + }, + { + type: "text", + key: "image", + label: "Container Image", + hint: "Override the container image used for Job pods. Defaults to the running Deployment image.", + }, + { + type: "select", + key: "imagePullPolicy", + label: "Image Pull Policy", + hint: "Image pull policy for the container image.", + options: [ + { value: "IfNotPresent", label: "IfNotPresent" }, + { value: "Always", label: "Always" }, + { value: "Never", label: "Never" }, + ], + }, + { + type: "text", + key: "kubeconfig", + label: "Kubeconfig Path", + hint: "Absolute path to a kubeconfig file on disk. Defaults to in-cluster service account auth.", + }, + { + type: "number", + key: "ttlSecondsAfterFinished", + label: "TTL Seconds After Finished", + hint: "Auto-cleanup delay for completed Jobs in seconds. Default: 300.", + }, + { + type: "toggle", + key: "retainJobs", + label: "Retain Jobs", + hint: "Skip cleanup of completed Jobs for debugging purposes.", + }, + // Resource Limits + { + type: "text", + key: "resources.requests.cpu", + label: "CPU Request", + hint: "CPU request for Job pods (e.g. 100m, 0.5, 1).", + }, + { + type: "text", + key: "resources.requests.memory", + label: "Memory Request", + hint: "Memory request for Job pods (e.g. 128Mi, 512Mi, 1Gi).", + }, + { + type: "text", + key: "resources.limits.cpu", + label: "CPU Limit", + hint: "CPU limit for Job pods (e.g. 100m, 0.5, 1).", + }, + { + type: "text", + key: "resources.limits.memory", + label: "Memory Limit", + hint: "Memory limit for Job pods (e.g. 128Mi, 512Mi, 1Gi).", + }, + // Scheduling + { + type: "textarea", + key: "nodeSelector", + label: "Node Selector", + hint: "Node selector for Job pods. One key=value per line (e.g. disktype=ssd).", + }, + { + type: "textarea", + key: "tolerations", + label: "Tolerations", + hint: "Tolerations for Job pods as JSON array.", + }, + { + type: "textarea", + key: "labels", + label: "Labels", + hint: "Extra labels added to Job metadata. One key=value per line.", + }, + ]; + + return { fields }; }