@burdenoff/microfe-vibecontrols 2026.514.1 → 2026.514.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/agents/AgentForm.js.map +1 -1
- package/dist/generated/wspace-operations.js +886 -869
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/generated/wspace-types.js.map +1 -1
- package/dist/index.js +10 -10
- package/dist/pages/SessionsPage.js +651 -613
- package/dist/pages/SessionsPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentForm.js","names":[],"sources":["../../../src/components/agents/AgentForm.tsx"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n X,\n Eye,\n EyeOff,\n CheckCircle2,\n XCircle,\n Loader2,\n ChevronRight,\n ChevronLeft,\n ChevronDown,\n Copy,\n Check,\n Terminal,\n Download,\n RefreshCw,\n Plus,\n Settings2,\n} from 'lucide-react';\n// useProbeAgentTunnelLazyQuery removed: validate now hits the agent's tunnel\n// URL directly from the browser (see validateAgent below).\nimport { SearchableSelect } from '@/components/shared';\nimport type { SearchableSelectOption } from '@/components/shared';\n\ntype WizardStage = 'details' | 'validate';\n\ninterface TargetOption {\n id: string;\n name: string;\n type: string;\n status: string;\n}\n\ninterface AgentFormProps {\n onSubmit: (data: Record<string, unknown>) => Promise<{ id: string } | void>;\n onCancel: () => void;\n isLoading?: boolean;\n /** Navigate to a path (used to go to agent details after creation) */\n onNavigate?: (path: string) => void;\n /** Available targets for the agent to be installed on */\n targets?: TargetOption[];\n /** Whether targets are still loading */\n targetsLoading?: boolean;\n /**\n * Create a new target inline. When provided, the form shows a\n * \"+ Create new target\" affordance that lets users create a DIRECT\n * target on the fly without leaving the dialog. Must return the new\n * target so the form can auto-select it.\n */\n onCreateTarget?: (name: string) => Promise<TargetOption | null>;\n}\n\nexport function AgentForm({\n onSubmit,\n onCancel,\n isLoading,\n onNavigate,\n targets,\n targetsLoading,\n onCreateTarget,\n}: AgentFormProps) {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n const [stage, setStage] = useState<WizardStage>('details');\n const [showApiKey, setShowApiKey] = useState(false);\n const [showInstallInstructions, setShowInstallInstructions] = useState(false);\n const [copiedCommand, setCopiedCommand] = useState<string | null>(null);\n\n // Stage 1: Basic details\n const [name, setName] = useState('');\n const [tunnelUrl, setTunnelUrl] = useState('');\n const [agentApiKey, setAgentApiKey] = useState('');\n const [selectedTargetId, setSelectedTargetId] = useState('');\n\n // Inline target creation state\n const [showInlineTarget, setShowInlineTarget] = useState(false);\n const [inlineTargetName, setInlineTargetName] = useState('');\n const [creatingTarget, setCreatingTarget] = useState(false);\n const [inlineTargetError, setInlineTargetError] = useState<string | null>(null);\n\n // Stage 2: Validation (via backend-proxied GraphQL query)\n const [validating, setValidating] = useState(false);\n const [healthResult, setHealthResult] = useState<{\n ok: boolean;\n data?: { status: string; version: string; uptime: number };\n error?: string;\n } | null>(null);\n const [identityResult, setIdentityResult] = useState<{\n ok: boolean;\n data?: { hostname: string; platform: string; arch: string };\n error?: string;\n } | null>(null);\n\n // Auto-detected fields (editable overrides)\n const [detectedHostname, setDetectedHostname] = useState('');\n const [detectedPlatform, setDetectedPlatform] = useState('linux');\n const [detectedArch, setDetectedArch] = useState('x86_64');\n const [detectedVersion, setDetectedVersion] = useState('1.0.0');\n\n // Error state for creation failures\n const [createError, setCreateError] = useState<string | null>(null);\n\n // Advanced options (Phase 5B: per-daemon profile name).\n // Defaults to \"default\" (autofilled but editable). Disclosure is closed\n // by default — users only need to touch this for multi-profile setups.\n const [showAdvanced, setShowAdvanced] = useState(false);\n const [profile, setProfile] = useState('default');\n\n const copyToClipboard = useCallback((text: string, id: string) => {\n navigator.clipboard.writeText(text);\n setCopiedCommand(id);\n setTimeout(() => setCopiedCommand(null), 2000);\n }, []);\n\n const normalizeUrl = (url: string) => {\n let u = url.trim();\n if (u.endsWith('/')) u = u.slice(0, -1);\n return u;\n };\n\n // Validate the agent by probing /health and /api/profiles/default/agent/identity\n // directly from the browser. The agent exposes CORS-allowed endpoints for\n // app.vibecontrols.com (see agent's createApp() — `@elysiajs/cors` is wired\n // for the host origin), so the browser can reach the tunnel URL without a\n // backend proxy. The earlier backend-proxy approach (probeAgentTunnel query)\n // is still wired into the schema, but in production we observed the proxy\n // hanging at the ACA egress layer regardless of timeout, so we bypass it for\n // the wizard validate step. Each fetch is bounded by a 10s AbortSignal so a\n // dead tunnel surfaces a real error instead of an infinite spinner.\n const validateAgent = async () => {\n const baseUrl = normalizeUrl(tunnelUrl);\n if (!baseUrl) return;\n\n setValidating(true);\n setHealthResult(null);\n setIdentityResult(null);\n\n const probeHealth = async (): Promise<void> => {\n try {\n const res = await fetch(`${baseUrl}/health`, {\n signal: AbortSignal.timeout(10_000),\n });\n if (!res.ok) {\n setHealthResult({ ok: false, error: `HTTP ${String(res.status)}: ${res.statusText}` });\n return;\n }\n const data = (await res.json()) as {\n status?: string;\n version?: string;\n uptime?: number;\n };\n setHealthResult({\n ok: true,\n data: {\n status: data.status || 'healthy',\n version: data.version || 'unknown',\n uptime: data.uptime || 0,\n },\n });\n if (data.version) setDetectedVersion(data.version);\n } catch (err) {\n const isTimeout = err instanceof DOMException && err.name === 'AbortError';\n setHealthResult({\n ok: false,\n error: isTimeout ? 'Health check timed out after 10s' :\n (err instanceof Error ? err.message : 'Health check failed'),\n });\n }\n };\n\n const probeIdentity = async (): Promise<void> => {\n try {\n const headers: Record<string, string> = {};\n if (agentApiKey) headers['x-agent-api-key'] = agentApiKey;\n const res = await fetch(`${baseUrl}/api/profiles/default/agent/identity`, {\n headers,\n signal: AbortSignal.timeout(10_000),\n });\n if (!res.ok) {\n setIdentityResult({\n ok: false,\n error: res.status === 401 ? 'Invalid API key' : `HTTP ${String(res.status)}: ${res.statusText}`,\n });\n return;\n }\n const data = (await res.json()) as {\n hostname?: string;\n platform?: string;\n arch?: string;\n };\n const hostname = data.hostname || '';\n const platform = data.platform || 'linux';\n const arch = data.arch || 'x86_64';\n setIdentityResult({ ok: true, data: { hostname, platform, arch } });\n if (hostname) setDetectedHostname(hostname);\n if (platform) setDetectedPlatform(platform);\n if (arch) setDetectedArch(arch);\n if (!name && hostname) setName(hostname);\n } catch (err) {\n const isTimeout = err instanceof DOMException && err.name === 'AbortError';\n setIdentityResult({\n ok: false,\n error: isTimeout ? 'Identity check timed out after 10s' :\n (err instanceof Error ? err.message : 'Identity check failed'),\n });\n }\n };\n\n // Run both probes in parallel so the user sees results as fast as the\n // slower of the two — instead of stacking 20s in series on failure paths.\n await Promise.all([probeHealth(), probeIdentity()]);\n\n setValidating(false);\n };\n\n // Create the agent and close the modal\n const handleCreateAgent = async () => {\n setCreateError(null);\n\n // Pipe the chosen profile through `metadata.profile`. Phase 5A (svc) is\n // adding first-class AgentProfile rows; in the meantime the backend\n // also reads `metadata.profile` so the create path keeps working\n // regardless of which side of the cut-over the cluster is on.\n const trimmedProfile = profile.trim() || 'default';\n const data: Record<string, unknown> = {\n name: name || detectedHostname || 'Unnamed Agent',\n hostname: detectedHostname || 'unknown',\n platform: detectedPlatform,\n architecture: detectedArch,\n version: detectedVersion,\n tunnelUrl: normalizeUrl(tunnelUrl),\n tunnelStatus: 'ACTIVE',\n agentApiKey,\n metadata: { profile: trimmedProfile },\n ...(selectedTargetId ? { targetId: selectedTargetId } : {}),\n };\n\n try {\n const result = await onSubmit(data);\n const newAgentId = result?.id || null;\n\n if (!newAgentId) {\n // Mutation succeeded but returned no agent ID — treat as failure\n setCreateError('Agent creation returned no ID. The agent may already exist.');\n return;\n }\n\n // Close the modal — the agent list will refetch automatically\n if (onNavigate) {\n onNavigate(`/agents/${newAgentId}`);\n } else {\n onCancel();\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Failed to create agent';\n setCreateError(message);\n }\n };\n\n const isValidationPassed = healthResult?.ok && identityResult?.ok;\n const hasTargets = targets && targets.length > 0;\n // The user must either pick or inline-create a target if inline creation\n // is enabled; otherwise we only require it when targets already exist.\n const targetRequiredButMissing = onCreateTarget\n ? selectedTargetId.length === 0\n : hasTargets && selectedTargetId.length === 0;\n const canProceedToValidate = tunnelUrl.trim().length > 0 && !targetRequiredButMissing;\n\n const handleInlineCreateTarget = useCallback(async () => {\n if (!onCreateTarget || !inlineTargetName.trim()) return;\n setCreatingTarget(true);\n setInlineTargetError(null);\n try {\n const created = await onCreateTarget(inlineTargetName.trim());\n if (created) {\n setSelectedTargetId(created.id);\n setShowInlineTarget(false);\n setInlineTargetName('');\n } else {\n setInlineTargetError(\n tr('agentsPage.inlineTargetFailed', 'Failed to create target. Please try again.')\n );\n }\n } catch (err) {\n setInlineTargetError(err instanceof Error ? err.message : 'Failed to create target');\n } finally {\n setCreatingTarget(false);\n }\n }, [onCreateTarget, inlineTargetName, tr]);\n\n const CopyButton = ({ text, id }: { text: string; id: string }) => (\n <button\n type=\"button\"\n onClick={() => copyToClipboard(text, id)}\n className=\"p-1 rounded hover:bg-bg-elevated transition-colors\"\n title={tr('agentsPage.copy', 'Copy')}\n >\n {copiedCommand === id ? (\n <Check className=\"w-3.5 h-3.5 text-status-success-text\" />\n ) : (\n <Copy className=\"w-3.5 h-3.5 text-text-secondary\" />\n )}\n </button>\n );\n\n // Stepper\n const steps = [\n { key: 'details', label: 'Setup' },\n { key: 'validate', label: 'Validate' },\n ];\n\n const currentStepIndex = steps.findIndex((s) => s.key === stage);\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-bg-overlay\">\n <div className=\"w-full max-w-xl bg-bg-surface rounded-lg shadow-xl max-h-[90vh] overflow-y-auto\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default sticky top-0 bg-bg-surface z-10\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('agentsPage.addNewAgent', 'Add New Agent')}\n </h2>\n <button onClick={onCancel} className=\"p-1 rounded hover:bg-bg-sunken transition-colors\">\n <X className=\"w-5 h-5 text-text-secondary\" />\n </button>\n </div>\n\n {/* Stepper */}\n <div className=\"flex items-center gap-2 px-6 pt-4 pb-2\">\n {steps.map((step, i) => (\n <div key={step.key} className=\"flex items-center gap-2\">\n <div\n className={`flex items-center justify-center w-7 h-7 rounded-full text-xs font-semibold transition-colors ${\n i < currentStepIndex\n ? 'bg-status-success-bg text-status-success-text'\n : i === currentStepIndex\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary'\n }`}\n >\n {i < currentStepIndex ? <CheckCircle2 className=\"w-4 h-4\" /> : i + 1}\n </div>\n <span\n className={`text-sm ${i === currentStepIndex ? 'font-medium text-text-primary' : 'text-text-secondary'}`}\n >\n {step.label}\n </span>\n {i < steps.length - 1 && <ChevronRight className=\"w-4 h-4 text-text-muted\" />}\n </div>\n ))}\n </div>\n\n <div className=\"p-6\">\n {/* Stage 1: Setup */}\n {stage === 'details' && (\n <div className=\"space-y-4\">\n {/* Install instructions (collapsible) */}\n <div className=\"border border-border-default rounded-lg overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setShowInstallInstructions(!showInstallInstructions)}\n className=\"w-full flex items-center justify-between px-4 py-3 bg-bg-sunken hover:bg-bg-sunken/80 transition-colors\"\n >\n <div className=\"flex items-center gap-2\">\n <Download className=\"w-4 h-4 text-action-primary-bg\" />\n <span className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.installInstructions', 'Agent Install Instructions')}\n </span>\n </div>\n <ChevronRight\n className={`w-4 h-4 text-text-secondary transition-transform ${showInstallInstructions ? 'rotate-90' : ''}`}\n />\n </button>\n {showInstallInstructions && (\n <div className=\"px-4 py-3 space-y-3 border-t border-border-default\">\n <div className=\"space-y-2\">\n {[\n {\n label: tr('agentsPage.installStep1', '1. Install the agent CLI'),\n cmd: 'npm install -g @vibecontrols/agent@latest',\n },\n {\n label: tr('agentsPage.installStep2', '2. Start the agent'),\n cmd: 'vibe start',\n },\n {\n label: tr('agentsPage.installStep3', '3. Get the API key'),\n cmd: 'vibe key',\n },\n {\n label: tr('agentsPage.installStep4', '4. Start the tunnel'),\n cmd: 'vibe tunnel agent --start',\n },\n ].map((step) => (\n <div key={step.cmd}>\n <p className=\"text-xs text-text-secondary mb-1\">{step.label}</p>\n <div className=\"flex items-center gap-2 bg-bg-sunken rounded-md px-3 py-1.5 font-mono text-xs text-text-primary\">\n <Terminal className=\"w-3 h-3 text-text-muted flex-shrink-0\" />\n <code className=\"flex-1\">{step.cmd}</code>\n <CopyButton text={step.cmd} id={step.cmd} />\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n\n {/* Target Selection — with inline creation */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('agentsPage.target', 'Target')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </label>\n\n {hasTargets && !showInlineTarget && (\n <>\n <SearchableSelect\n placeholder={tr('agentsPage.selectTarget', 'Select a target...')}\n searchPlaceholder={tr('agentsPage.searchTargets', 'Search targets...')}\n options={(targets ?? []).map(\n (tgt): SearchableSelectOption => ({\n value: tgt.id,\n label: tgt.name,\n description: `${tgt.type}${tgt.status ? ` · ${tgt.status}` : ''}`,\n })\n )}\n value={selectedTargetId}\n onChange={setSelectedTargetId}\n clearable\n />\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr(\n 'agentsPage.targetDescription',\n 'The target machine this agent will be installed on.'\n )}{' '}\n {onCreateTarget && (\n <button\n type=\"button\"\n onClick={() => {\n setShowInlineTarget(true);\n setInlineTargetName(name.trim() || '');\n }}\n className=\"text-action-primary-bg hover:underline inline-flex items-center gap-1\"\n >\n <Plus className=\"w-3 h-3\" />\n {tr('agentsPage.createNewTarget', 'Create a new target')}\n </button>\n )}\n </p>\n </>\n )}\n\n {/* Empty state prompt (no targets exist yet) */}\n {!hasTargets && !targetsLoading && onCreateTarget && !showInlineTarget && (\n <div className=\"p-3 bg-bg-sunken border border-border-default rounded-lg\">\n <p className=\"text-sm text-text-secondary mb-2\">\n {tr(\n 'agentsPage.noTargetsInlinePrompt',\n \"You don't have any targets yet. Create one now to install this agent on it.\"\n )}\n </p>\n <button\n type=\"button\"\n onClick={() => {\n setShowInlineTarget(true);\n setInlineTargetName(name.trim() || '');\n }}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:opacity-90\"\n >\n <Plus className=\"w-4 h-4\" />\n {tr('agentsPage.createFirstTarget', 'Create first target')}\n </button>\n </div>\n )}\n\n {/* Inline creation form */}\n {showInlineTarget && onCreateTarget && (\n <div className=\"p-3 bg-bg-sunken border border-border-default rounded-lg space-y-2\">\n <p className=\"text-xs font-medium text-text-secondary\">\n {tr(\n 'agentsPage.newDirectTarget',\n 'New target (Direct — you can change the type later)'\n )}\n </p>\n <input\n type=\"text\"\n value={inlineTargetName}\n onChange={(e) => setInlineTargetName(e.target.value)}\n placeholder={tr('agentsPage.targetName', 'Target name')}\n className=\"w-full px-3 py-2 text-sm bg-bg-elevated border border-border-default rounded-md text-text-primary placeholder-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n autoFocus\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n void handleInlineCreateTarget();\n }\n }}\n />\n {inlineTargetError && (\n <p className=\"text-xs text-status-error-text\">{inlineTargetError}</p>\n )}\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => void handleInlineCreateTarget()}\n disabled={!inlineTargetName.trim() || creatingTarget}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:opacity-90 disabled:opacity-50\"\n >\n {creatingTarget ? (\n <Loader2 className=\"w-3.5 h-3.5 animate-spin\" />\n ) : (\n <Check className=\"w-3.5 h-3.5\" />\n )}\n {tr('agentsPage.create', 'Create')}\n </button>\n <button\n type=\"button\"\n onClick={() => {\n setShowInlineTarget(false);\n setInlineTargetName('');\n setInlineTargetError(null);\n }}\n className=\"px-3 py-1.5 text-sm text-text-secondary hover:text-text-primary\"\n >\n {tr('agentsPage.cancel', 'Cancel')}\n </button>\n </div>\n </div>\n )}\n\n {/* Loading placeholder */}\n {targetsLoading && !hasTargets && (\n <div className=\"p-3 bg-bg-sunken border border-border-default rounded-lg flex items-center gap-2 text-sm text-text-secondary\">\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n {tr('agentsPage.loadingTargets', 'Loading targets...')}\n </div>\n )}\n </div>\n\n {/* API/Tunnel URL */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('agentsPage.apiTunnelUrl', 'API / Tunnel URL')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n type=\"url\"\n value={tunnelUrl}\n onChange={(e) => setTunnelUrl(e.target.value)}\n placeholder=\"https://your-tunnel.trycloudflare.com\"\n required\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono\"\n />\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr(\n 'agentsPage.tunnelUrlHint',\n \"The agent's tunnel URL or local API URL (e.g. http://localhost:3005)\"\n )}\n </p>\n </div>\n\n {/* Agent API Key */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('agentsPage.agentApiKey', 'Agent API Key')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <div className=\"relative\">\n <input\n type={showApiKey ? 'text' : 'password'}\n value={agentApiKey}\n onChange={(e) => setAgentApiKey(e.target.value)}\n placeholder=\"vcak_...\"\n required\n className=\"w-full px-3 py-2 pr-10 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono\"\n />\n <button\n type=\"button\"\n onClick={() => setShowApiKey(!showApiKey)}\n className=\"absolute right-2 top-1/2 -translate-y-1/2 p-1 rounded hover:bg-bg-elevated transition-colors\"\n >\n {showApiKey ? (\n <EyeOff className=\"w-4 h-4 text-text-secondary\" />\n ) : (\n <Eye className=\"w-4 h-4 text-text-secondary\" />\n )}\n </button>\n </div>\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr('agentsPage.apiKeyHint', 'Run')}{' '}\n <code className=\"bg-bg-sunken px-1 rounded\">vibe key</code>{' '}\n {tr(\n 'agentsPage.apiKeyHintSuffix',\n 'on the agent to get this. Changes on restart.'\n )}\n </p>\n </div>\n\n {/* Advanced options — per-daemon profile name (Phase 5B) */}\n <div className=\"border border-border-default rounded-lg overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setShowAdvanced((v) => !v)}\n className=\"w-full flex items-center justify-between px-4 py-2.5 bg-bg-sunken hover:bg-bg-sunken/80 transition-colors\"\n aria-expanded={showAdvanced}\n data-testid=\"agent-form-advanced-toggle\"\n >\n <div className=\"flex items-center gap-2\">\n <Settings2 className=\"w-4 h-4 text-text-secondary\" />\n <span className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.advancedOptions', 'Advanced options')}\n </span>\n </div>\n <ChevronDown\n className={`w-4 h-4 text-text-secondary transition-transform ${showAdvanced ? 'rotate-180' : ''}`}\n />\n </button>\n {showAdvanced && (\n <div className=\"px-4 py-3 space-y-3 border-t border-border-default\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('agentsPage.profileName', 'Profile name')}\n </label>\n <input\n type=\"text\"\n value={profile}\n onChange={(e) => setProfile(e.target.value)}\n placeholder=\"default\"\n className=\"w-full px-3 py-2 text-sm bg-bg-surface border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono\"\n data-testid=\"agent-form-profile-input\"\n />\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr(\n 'agentsPage.profileNameHint',\n 'Each profile runs an isolated CLI on the daemon. Leave as \"default\" unless you want this agent to host multiple parallel profiles.'\n )}\n </p>\n </div>\n </div>\n )}\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center justify-between pt-4\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-4 py-2 text-sm font-medium text-text-primary bg-bg-sunken border border-border-default rounded-md hover:bg-bg-elevated transition-colors\"\n >\n {tr('agentsPage.cancel', 'Cancel')}\n </button>\n <button\n type=\"button\"\n disabled={!canProceedToValidate}\n onClick={() => {\n setStage('validate');\n validateAgent();\n }}\n className=\"flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {tr('agentsPage.nextValidate', 'Next: Validate')}\n <ChevronRight className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n )}\n\n {/* Stage 2: Validate */}\n {stage === 'validate' && (\n <div className=\"space-y-4\">\n {/* Validation Results */}\n <div className=\"space-y-3\">\n {/* Health Check */}\n <div\n className={`flex items-center gap-3 p-3 rounded-lg border ${\n healthResult === null\n ? 'border-border-default bg-bg-sunken'\n : healthResult.ok\n ? 'border-status-success-text/20 bg-status-success-bg/30'\n : 'border-status-error-text/20 bg-status-error-bg/30'\n }`}\n >\n {validating && !healthResult ? (\n <Loader2 className=\"w-5 h-5 text-text-secondary animate-spin\" />\n ) : healthResult?.ok ? (\n <CheckCircle2 className=\"w-5 h-5 text-status-success-text\" />\n ) : healthResult ? (\n <XCircle className=\"w-5 h-5 text-status-error-text\" />\n ) : (\n <div className=\"w-5 h-5 rounded-full border-2 border-border-default\" />\n )}\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.healthCheck', 'Health Check')}\n </p>\n {healthResult?.ok && healthResult.data && (\n <p className=\"text-xs text-text-secondary\">\n Status: {healthResult.data.status} | Version: {healthResult.data.version} |\n Uptime: {Math.round(healthResult.data.uptime)}s\n </p>\n )}\n {healthResult && !healthResult.ok && (\n <p className=\"text-xs text-status-error-text\">{healthResult.error}</p>\n )}\n </div>\n </div>\n\n {/* API Access Check */}\n <div\n className={`flex items-center gap-3 p-3 rounded-lg border ${\n identityResult === null\n ? 'border-border-default bg-bg-sunken'\n : identityResult.ok\n ? 'border-status-success-text/20 bg-status-success-bg/30'\n : 'border-status-error-text/20 bg-status-error-bg/30'\n }`}\n >\n {validating && !identityResult ? (\n <Loader2 className=\"w-5 h-5 text-text-secondary animate-spin\" />\n ) : identityResult?.ok ? (\n <CheckCircle2 className=\"w-5 h-5 text-status-success-text\" />\n ) : identityResult ? (\n <XCircle className=\"w-5 h-5 text-status-error-text\" />\n ) : (\n <div className=\"w-5 h-5 rounded-full border-2 border-border-default\" />\n )}\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.apiAccess', 'API Access')}\n </p>\n {identityResult?.ok && identityResult.data && (\n <p className=\"text-xs text-text-secondary\">\n Host: {identityResult.data.hostname} | {identityResult.data.platform} /{' '}\n {identityResult.data.arch}\n </p>\n )}\n {identityResult && !identityResult.ok && (\n <p className=\"text-xs text-status-error-text\">{identityResult.error}</p>\n )}\n </div>\n </div>\n </div>\n\n {/* Retry button */}\n {!validating && (!healthResult?.ok || !identityResult?.ok) && (\n <button\n type=\"button\"\n onClick={validateAgent}\n className=\"flex items-center gap-2 px-3 py-1.5 text-sm text-text-secondary hover:text-text-primary hover:bg-bg-sunken rounded-md transition-colors\"\n >\n <RefreshCw className=\"w-3.5 h-3.5\" />\n {tr('agentsPage.retryValidation', 'Retry validation')}\n </button>\n )}\n\n {/* Detected info (editable overrides) */}\n {isValidationPassed && (\n <div className=\"space-y-3 pt-2\">\n <p className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.detectedAgentInfo', 'Detected Agent Info')}\n </p>\n\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n {tr('agentsPage.name', 'Name')}\n </label>\n <input\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={detectedHostname}\n className=\"w-full px-3 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n {tr('agentsPage.platform', 'Platform')}\n </label>\n <select\n value={detectedPlatform}\n onChange={(e) => setDetectedPlatform(e.target.value)}\n className=\"w-full px-3 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value=\"linux\">Linux</option>\n <option value=\"darwin\">macOS</option>\n <option value=\"windows\">Windows</option>\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n {tr('agentsPage.architecture', 'Architecture')}\n </label>\n <select\n value={detectedArch}\n onChange={(e) => setDetectedArch(e.target.value)}\n className=\"w-full px-3 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value=\"x86_64\">x86_64</option>\n <option value=\"arm64\">arm64</option>\n <option value=\"aarch64\">aarch64</option>\n </select>\n </div>\n </div>\n </div>\n )}\n\n {/* Creation error */}\n {createError && (\n <div className=\"p-3 bg-status-error-bg/30 border border-status-error-text/20 rounded-lg\">\n <div className=\"flex items-center gap-2\">\n <XCircle className=\"w-5 h-5 text-status-error-text flex-shrink-0\" />\n <p className=\"text-sm text-status-error-text\">{createError}</p>\n </div>\n <div className=\"flex items-center gap-2 mt-3\">\n <button\n type=\"button\"\n onClick={() => {\n setCreateError(null);\n // Reset form to allow entering different credentials\n setStage('details');\n setTunnelUrl('');\n setAgentApiKey('');\n setHealthResult(null);\n setIdentityResult(null);\n }}\n className=\"flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-text-primary bg-bg-sunken border border-border-default rounded-md hover:bg-bg-elevated transition-colors\"\n >\n <RefreshCw className=\"w-3.5 h-3.5\" />\n {tr('agentsPage.tryDifferentAgent', 'Try Different Agent')}\n </button>\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-3 py-1.5 text-sm font-medium text-text-secondary hover:text-text-primary transition-colors\"\n >\n {tr('agentsPage.close', 'Close')}\n </button>\n </div>\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex items-center justify-between pt-4\">\n <button\n type=\"button\"\n onClick={() => setStage('details')}\n className=\"flex items-center gap-1 px-4 py-2 text-sm font-medium text-text-primary bg-bg-sunken border border-border-default rounded-md hover:bg-bg-elevated transition-colors\"\n >\n <ChevronLeft className=\"w-4 h-4\" />\n {tr('agentsPage.back', 'Back')}\n </button>\n <button\n type=\"button\"\n disabled={!isValidationPassed || isLoading || validating}\n onClick={handleCreateAgent}\n className=\"flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {isLoading ? (\n <>\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n {tr('agentsPage.adding', 'Adding...')}\n </>\n ) : (\n <>\n {tr('agentsPage.addAgent', 'Add Agent')}\n <ChevronRight className=\"w-4 h-4\" />\n </>\n )}\n </button>\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AgentForm.js","names":[],"sources":["../../../src/components/agents/AgentForm.tsx"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n X,\n Eye,\n EyeOff,\n CheckCircle2,\n XCircle,\n Loader2,\n ChevronRight,\n ChevronLeft,\n ChevronDown,\n Copy,\n Check,\n Terminal,\n Download,\n RefreshCw,\n Plus,\n Settings2,\n} from 'lucide-react';\n// useProbeAgentTunnelLazyQuery removed: validate now hits the agent's tunnel\n// URL directly from the browser (see validateAgent below).\nimport { SearchableSelect } from '@/components/shared';\nimport type { SearchableSelectOption } from '@/components/shared';\n\ntype WizardStage = 'details' | 'validate';\n\ninterface TargetOption {\n id: string;\n name: string;\n type: string;\n status: string;\n}\n\ninterface AgentFormProps {\n onSubmit: (data: Record<string, unknown>) => Promise<{ id: string } | void>;\n onCancel: () => void;\n isLoading?: boolean;\n /** Navigate to a path (used to go to agent details after creation) */\n onNavigate?: (path: string) => void;\n /** Available targets for the agent to be installed on */\n targets?: TargetOption[];\n /** Whether targets are still loading */\n targetsLoading?: boolean;\n /**\n * Create a new target inline. When provided, the form shows a\n * \"+ Create new target\" affordance that lets users create a DIRECT\n * target on the fly without leaving the dialog. Must return the new\n * target so the form can auto-select it.\n */\n onCreateTarget?: (name: string) => Promise<TargetOption | null>;\n}\n\nexport function AgentForm({\n onSubmit,\n onCancel,\n isLoading,\n onNavigate,\n targets,\n targetsLoading,\n onCreateTarget,\n}: AgentFormProps) {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n const [stage, setStage] = useState<WizardStage>('details');\n const [showApiKey, setShowApiKey] = useState(false);\n const [showInstallInstructions, setShowInstallInstructions] = useState(false);\n const [copiedCommand, setCopiedCommand] = useState<string | null>(null);\n\n // Stage 1: Basic details\n const [name, setName] = useState('');\n const [tunnelUrl, setTunnelUrl] = useState('');\n const [agentApiKey, setAgentApiKey] = useState('');\n const [selectedTargetId, setSelectedTargetId] = useState('');\n\n // Inline target creation state\n const [showInlineTarget, setShowInlineTarget] = useState(false);\n const [inlineTargetName, setInlineTargetName] = useState('');\n const [creatingTarget, setCreatingTarget] = useState(false);\n const [inlineTargetError, setInlineTargetError] = useState<string | null>(null);\n\n // Stage 2: Validation (via backend-proxied GraphQL query)\n const [validating, setValidating] = useState(false);\n const [healthResult, setHealthResult] = useState<{\n ok: boolean;\n data?: { status: string; version: string; uptime: number };\n error?: string;\n } | null>(null);\n const [identityResult, setIdentityResult] = useState<{\n ok: boolean;\n data?: { hostname: string; platform: string; arch: string };\n error?: string;\n } | null>(null);\n\n // Auto-detected fields (editable overrides)\n const [detectedHostname, setDetectedHostname] = useState('');\n const [detectedPlatform, setDetectedPlatform] = useState('linux');\n const [detectedArch, setDetectedArch] = useState('x86_64');\n const [detectedVersion, setDetectedVersion] = useState('1.0.0');\n\n // Error state for creation failures\n const [createError, setCreateError] = useState<string | null>(null);\n\n // Advanced options (Phase 5B: per-daemon profile name).\n // Defaults to \"default\" (autofilled but editable). Disclosure is closed\n // by default — users only need to touch this for multi-profile setups.\n const [showAdvanced, setShowAdvanced] = useState(false);\n const [profile, setProfile] = useState('default');\n\n const copyToClipboard = useCallback((text: string, id: string) => {\n navigator.clipboard.writeText(text);\n setCopiedCommand(id);\n setTimeout(() => setCopiedCommand(null), 2000);\n }, []);\n\n const normalizeUrl = (url: string) => {\n let u = url.trim();\n if (u.endsWith('/')) u = u.slice(0, -1);\n return u;\n };\n\n // Validate the agent by probing /health and /api/profiles/default/agent/identity\n // directly from the browser. The agent exposes CORS-allowed endpoints for\n // app.vibecontrols.com (see agent's createApp() — `@elysiajs/cors` is wired\n // for the host origin), so the browser can reach the tunnel URL without a\n // backend proxy. The earlier backend-proxy approach (probeAgentTunnel query)\n // is still wired into the schema, but in production we observed the proxy\n // hanging at the ACA egress layer regardless of timeout, so we bypass it for\n // the wizard validate step. Each fetch is bounded by a 10s AbortSignal so a\n // dead tunnel surfaces a real error instead of an infinite spinner.\n const validateAgent = async () => {\n const baseUrl = normalizeUrl(tunnelUrl);\n if (!baseUrl) return;\n\n setValidating(true);\n setHealthResult(null);\n setIdentityResult(null);\n\n const probeHealth = async (): Promise<void> => {\n try {\n const res = await fetch(`${baseUrl}/health`, {\n signal: AbortSignal.timeout(10_000),\n });\n if (!res.ok) {\n setHealthResult({ ok: false, error: `HTTP ${String(res.status)}: ${res.statusText}` });\n return;\n }\n const data = (await res.json()) as {\n status?: string;\n version?: string;\n uptime?: number;\n };\n setHealthResult({\n ok: true,\n data: {\n status: data.status || 'healthy',\n version: data.version || 'unknown',\n uptime: data.uptime || 0,\n },\n });\n if (data.version) setDetectedVersion(data.version);\n } catch (err) {\n const isTimeout = err instanceof DOMException && err.name === 'AbortError';\n setHealthResult({\n ok: false,\n error: isTimeout\n ? 'Health check timed out after 10s'\n : err instanceof Error\n ? err.message\n : 'Health check failed',\n });\n }\n };\n\n const probeIdentity = async (): Promise<void> => {\n try {\n const headers: Record<string, string> = {};\n if (agentApiKey) headers['x-agent-api-key'] = agentApiKey;\n const res = await fetch(`${baseUrl}/api/profiles/default/agent/identity`, {\n headers,\n signal: AbortSignal.timeout(10_000),\n });\n if (!res.ok) {\n setIdentityResult({\n ok: false,\n error:\n res.status === 401\n ? 'Invalid API key'\n : `HTTP ${String(res.status)}: ${res.statusText}`,\n });\n return;\n }\n const data = (await res.json()) as {\n hostname?: string;\n platform?: string;\n arch?: string;\n };\n const hostname = data.hostname || '';\n const platform = data.platform || 'linux';\n const arch = data.arch || 'x86_64';\n setIdentityResult({ ok: true, data: { hostname, platform, arch } });\n if (hostname) setDetectedHostname(hostname);\n if (platform) setDetectedPlatform(platform);\n if (arch) setDetectedArch(arch);\n if (!name && hostname) setName(hostname);\n } catch (err) {\n const isTimeout = err instanceof DOMException && err.name === 'AbortError';\n setIdentityResult({\n ok: false,\n error: isTimeout\n ? 'Identity check timed out after 10s'\n : err instanceof Error\n ? err.message\n : 'Identity check failed',\n });\n }\n };\n\n // Run both probes in parallel so the user sees results as fast as the\n // slower of the two — instead of stacking 20s in series on failure paths.\n await Promise.all([probeHealth(), probeIdentity()]);\n\n setValidating(false);\n };\n\n // Create the agent and close the modal\n const handleCreateAgent = async () => {\n setCreateError(null);\n\n // Pipe the chosen profile through `metadata.profile`. Phase 5A (svc) is\n // adding first-class AgentProfile rows; in the meantime the backend\n // also reads `metadata.profile` so the create path keeps working\n // regardless of which side of the cut-over the cluster is on.\n const trimmedProfile = profile.trim() || 'default';\n const data: Record<string, unknown> = {\n name: name || detectedHostname || 'Unnamed Agent',\n hostname: detectedHostname || 'unknown',\n platform: detectedPlatform,\n architecture: detectedArch,\n version: detectedVersion,\n tunnelUrl: normalizeUrl(tunnelUrl),\n tunnelStatus: 'ACTIVE',\n agentApiKey,\n metadata: { profile: trimmedProfile },\n ...(selectedTargetId ? { targetId: selectedTargetId } : {}),\n };\n\n try {\n const result = await onSubmit(data);\n const newAgentId = result?.id || null;\n\n if (!newAgentId) {\n // Mutation succeeded but returned no agent ID — treat as failure\n setCreateError('Agent creation returned no ID. The agent may already exist.');\n return;\n }\n\n // Close the modal — the agent list will refetch automatically\n if (onNavigate) {\n onNavigate(`/agents/${newAgentId}`);\n } else {\n onCancel();\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Failed to create agent';\n setCreateError(message);\n }\n };\n\n const isValidationPassed = healthResult?.ok && identityResult?.ok;\n const hasTargets = targets && targets.length > 0;\n // The user must either pick or inline-create a target if inline creation\n // is enabled; otherwise we only require it when targets already exist.\n const targetRequiredButMissing = onCreateTarget\n ? selectedTargetId.length === 0\n : hasTargets && selectedTargetId.length === 0;\n const canProceedToValidate = tunnelUrl.trim().length > 0 && !targetRequiredButMissing;\n\n const handleInlineCreateTarget = useCallback(async () => {\n if (!onCreateTarget || !inlineTargetName.trim()) return;\n setCreatingTarget(true);\n setInlineTargetError(null);\n try {\n const created = await onCreateTarget(inlineTargetName.trim());\n if (created) {\n setSelectedTargetId(created.id);\n setShowInlineTarget(false);\n setInlineTargetName('');\n } else {\n setInlineTargetError(\n tr('agentsPage.inlineTargetFailed', 'Failed to create target. Please try again.')\n );\n }\n } catch (err) {\n setInlineTargetError(err instanceof Error ? err.message : 'Failed to create target');\n } finally {\n setCreatingTarget(false);\n }\n }, [onCreateTarget, inlineTargetName, tr]);\n\n const CopyButton = ({ text, id }: { text: string; id: string }) => (\n <button\n type=\"button\"\n onClick={() => copyToClipboard(text, id)}\n className=\"p-1 rounded hover:bg-bg-elevated transition-colors\"\n title={tr('agentsPage.copy', 'Copy')}\n >\n {copiedCommand === id ? (\n <Check className=\"w-3.5 h-3.5 text-status-success-text\" />\n ) : (\n <Copy className=\"w-3.5 h-3.5 text-text-secondary\" />\n )}\n </button>\n );\n\n // Stepper\n const steps = [\n { key: 'details', label: 'Setup' },\n { key: 'validate', label: 'Validate' },\n ];\n\n const currentStepIndex = steps.findIndex((s) => s.key === stage);\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-bg-overlay\">\n <div className=\"w-full max-w-xl bg-bg-surface rounded-lg shadow-xl max-h-[90vh] overflow-y-auto\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default sticky top-0 bg-bg-surface z-10\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('agentsPage.addNewAgent', 'Add New Agent')}\n </h2>\n <button onClick={onCancel} className=\"p-1 rounded hover:bg-bg-sunken transition-colors\">\n <X className=\"w-5 h-5 text-text-secondary\" />\n </button>\n </div>\n\n {/* Stepper */}\n <div className=\"flex items-center gap-2 px-6 pt-4 pb-2\">\n {steps.map((step, i) => (\n <div key={step.key} className=\"flex items-center gap-2\">\n <div\n className={`flex items-center justify-center w-7 h-7 rounded-full text-xs font-semibold transition-colors ${\n i < currentStepIndex\n ? 'bg-status-success-bg text-status-success-text'\n : i === currentStepIndex\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary'\n }`}\n >\n {i < currentStepIndex ? <CheckCircle2 className=\"w-4 h-4\" /> : i + 1}\n </div>\n <span\n className={`text-sm ${i === currentStepIndex ? 'font-medium text-text-primary' : 'text-text-secondary'}`}\n >\n {step.label}\n </span>\n {i < steps.length - 1 && <ChevronRight className=\"w-4 h-4 text-text-muted\" />}\n </div>\n ))}\n </div>\n\n <div className=\"p-6\">\n {/* Stage 1: Setup */}\n {stage === 'details' && (\n <div className=\"space-y-4\">\n {/* Install instructions (collapsible) */}\n <div className=\"border border-border-default rounded-lg overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setShowInstallInstructions(!showInstallInstructions)}\n className=\"w-full flex items-center justify-between px-4 py-3 bg-bg-sunken hover:bg-bg-sunken/80 transition-colors\"\n >\n <div className=\"flex items-center gap-2\">\n <Download className=\"w-4 h-4 text-action-primary-bg\" />\n <span className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.installInstructions', 'Agent Install Instructions')}\n </span>\n </div>\n <ChevronRight\n className={`w-4 h-4 text-text-secondary transition-transform ${showInstallInstructions ? 'rotate-90' : ''}`}\n />\n </button>\n {showInstallInstructions && (\n <div className=\"px-4 py-3 space-y-3 border-t border-border-default\">\n <div className=\"space-y-2\">\n {[\n {\n label: tr('agentsPage.installStep1', '1. Install the agent CLI'),\n cmd: 'npm install -g @vibecontrols/agent@latest',\n },\n {\n label: tr('agentsPage.installStep2', '2. Start the agent'),\n cmd: 'vibe start',\n },\n {\n label: tr('agentsPage.installStep3', '3. Get the API key'),\n cmd: 'vibe key',\n },\n {\n label: tr('agentsPage.installStep4', '4. Start the tunnel'),\n cmd: 'vibe tunnel agent --start',\n },\n ].map((step) => (\n <div key={step.cmd}>\n <p className=\"text-xs text-text-secondary mb-1\">{step.label}</p>\n <div className=\"flex items-center gap-2 bg-bg-sunken rounded-md px-3 py-1.5 font-mono text-xs text-text-primary\">\n <Terminal className=\"w-3 h-3 text-text-muted flex-shrink-0\" />\n <code className=\"flex-1\">{step.cmd}</code>\n <CopyButton text={step.cmd} id={step.cmd} />\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n\n {/* Target Selection — with inline creation */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('agentsPage.target', 'Target')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </label>\n\n {hasTargets && !showInlineTarget && (\n <>\n <SearchableSelect\n placeholder={tr('agentsPage.selectTarget', 'Select a target...')}\n searchPlaceholder={tr('agentsPage.searchTargets', 'Search targets...')}\n options={(targets ?? []).map(\n (tgt): SearchableSelectOption => ({\n value: tgt.id,\n label: tgt.name,\n description: `${tgt.type}${tgt.status ? ` · ${tgt.status}` : ''}`,\n })\n )}\n value={selectedTargetId}\n onChange={setSelectedTargetId}\n clearable\n />\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr(\n 'agentsPage.targetDescription',\n 'The target machine this agent will be installed on.'\n )}{' '}\n {onCreateTarget && (\n <button\n type=\"button\"\n onClick={() => {\n setShowInlineTarget(true);\n setInlineTargetName(name.trim() || '');\n }}\n className=\"text-action-primary-bg hover:underline inline-flex items-center gap-1\"\n >\n <Plus className=\"w-3 h-3\" />\n {tr('agentsPage.createNewTarget', 'Create a new target')}\n </button>\n )}\n </p>\n </>\n )}\n\n {/* Empty state prompt (no targets exist yet) */}\n {!hasTargets && !targetsLoading && onCreateTarget && !showInlineTarget && (\n <div className=\"p-3 bg-bg-sunken border border-border-default rounded-lg\">\n <p className=\"text-sm text-text-secondary mb-2\">\n {tr(\n 'agentsPage.noTargetsInlinePrompt',\n \"You don't have any targets yet. Create one now to install this agent on it.\"\n )}\n </p>\n <button\n type=\"button\"\n onClick={() => {\n setShowInlineTarget(true);\n setInlineTargetName(name.trim() || '');\n }}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:opacity-90\"\n >\n <Plus className=\"w-4 h-4\" />\n {tr('agentsPage.createFirstTarget', 'Create first target')}\n </button>\n </div>\n )}\n\n {/* Inline creation form */}\n {showInlineTarget && onCreateTarget && (\n <div className=\"p-3 bg-bg-sunken border border-border-default rounded-lg space-y-2\">\n <p className=\"text-xs font-medium text-text-secondary\">\n {tr(\n 'agentsPage.newDirectTarget',\n 'New target (Direct — you can change the type later)'\n )}\n </p>\n <input\n type=\"text\"\n value={inlineTargetName}\n onChange={(e) => setInlineTargetName(e.target.value)}\n placeholder={tr('agentsPage.targetName', 'Target name')}\n className=\"w-full px-3 py-2 text-sm bg-bg-elevated border border-border-default rounded-md text-text-primary placeholder-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n autoFocus\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n void handleInlineCreateTarget();\n }\n }}\n />\n {inlineTargetError && (\n <p className=\"text-xs text-status-error-text\">{inlineTargetError}</p>\n )}\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => void handleInlineCreateTarget()}\n disabled={!inlineTargetName.trim() || creatingTarget}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:opacity-90 disabled:opacity-50\"\n >\n {creatingTarget ? (\n <Loader2 className=\"w-3.5 h-3.5 animate-spin\" />\n ) : (\n <Check className=\"w-3.5 h-3.5\" />\n )}\n {tr('agentsPage.create', 'Create')}\n </button>\n <button\n type=\"button\"\n onClick={() => {\n setShowInlineTarget(false);\n setInlineTargetName('');\n setInlineTargetError(null);\n }}\n className=\"px-3 py-1.5 text-sm text-text-secondary hover:text-text-primary\"\n >\n {tr('agentsPage.cancel', 'Cancel')}\n </button>\n </div>\n </div>\n )}\n\n {/* Loading placeholder */}\n {targetsLoading && !hasTargets && (\n <div className=\"p-3 bg-bg-sunken border border-border-default rounded-lg flex items-center gap-2 text-sm text-text-secondary\">\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n {tr('agentsPage.loadingTargets', 'Loading targets...')}\n </div>\n )}\n </div>\n\n {/* API/Tunnel URL */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('agentsPage.apiTunnelUrl', 'API / Tunnel URL')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n type=\"url\"\n value={tunnelUrl}\n onChange={(e) => setTunnelUrl(e.target.value)}\n placeholder=\"https://your-tunnel.trycloudflare.com\"\n required\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono\"\n />\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr(\n 'agentsPage.tunnelUrlHint',\n \"The agent's tunnel URL or local API URL (e.g. http://localhost:3005)\"\n )}\n </p>\n </div>\n\n {/* Agent API Key */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('agentsPage.agentApiKey', 'Agent API Key')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <div className=\"relative\">\n <input\n type={showApiKey ? 'text' : 'password'}\n value={agentApiKey}\n onChange={(e) => setAgentApiKey(e.target.value)}\n placeholder=\"vcak_...\"\n required\n className=\"w-full px-3 py-2 pr-10 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono\"\n />\n <button\n type=\"button\"\n onClick={() => setShowApiKey(!showApiKey)}\n className=\"absolute right-2 top-1/2 -translate-y-1/2 p-1 rounded hover:bg-bg-elevated transition-colors\"\n >\n {showApiKey ? (\n <EyeOff className=\"w-4 h-4 text-text-secondary\" />\n ) : (\n <Eye className=\"w-4 h-4 text-text-secondary\" />\n )}\n </button>\n </div>\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr('agentsPage.apiKeyHint', 'Run')}{' '}\n <code className=\"bg-bg-sunken px-1 rounded\">vibe key</code>{' '}\n {tr(\n 'agentsPage.apiKeyHintSuffix',\n 'on the agent to get this. Changes on restart.'\n )}\n </p>\n </div>\n\n {/* Advanced options — per-daemon profile name (Phase 5B) */}\n <div className=\"border border-border-default rounded-lg overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setShowAdvanced((v) => !v)}\n className=\"w-full flex items-center justify-between px-4 py-2.5 bg-bg-sunken hover:bg-bg-sunken/80 transition-colors\"\n aria-expanded={showAdvanced}\n data-testid=\"agent-form-advanced-toggle\"\n >\n <div className=\"flex items-center gap-2\">\n <Settings2 className=\"w-4 h-4 text-text-secondary\" />\n <span className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.advancedOptions', 'Advanced options')}\n </span>\n </div>\n <ChevronDown\n className={`w-4 h-4 text-text-secondary transition-transform ${showAdvanced ? 'rotate-180' : ''}`}\n />\n </button>\n {showAdvanced && (\n <div className=\"px-4 py-3 space-y-3 border-t border-border-default\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('agentsPage.profileName', 'Profile name')}\n </label>\n <input\n type=\"text\"\n value={profile}\n onChange={(e) => setProfile(e.target.value)}\n placeholder=\"default\"\n className=\"w-full px-3 py-2 text-sm bg-bg-surface border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono\"\n data-testid=\"agent-form-profile-input\"\n />\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr(\n 'agentsPage.profileNameHint',\n 'Each profile runs an isolated CLI on the daemon. Leave as \"default\" unless you want this agent to host multiple parallel profiles.'\n )}\n </p>\n </div>\n </div>\n )}\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center justify-between pt-4\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-4 py-2 text-sm font-medium text-text-primary bg-bg-sunken border border-border-default rounded-md hover:bg-bg-elevated transition-colors\"\n >\n {tr('agentsPage.cancel', 'Cancel')}\n </button>\n <button\n type=\"button\"\n disabled={!canProceedToValidate}\n onClick={() => {\n setStage('validate');\n validateAgent();\n }}\n className=\"flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {tr('agentsPage.nextValidate', 'Next: Validate')}\n <ChevronRight className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n )}\n\n {/* Stage 2: Validate */}\n {stage === 'validate' && (\n <div className=\"space-y-4\">\n {/* Validation Results */}\n <div className=\"space-y-3\">\n {/* Health Check */}\n <div\n className={`flex items-center gap-3 p-3 rounded-lg border ${\n healthResult === null\n ? 'border-border-default bg-bg-sunken'\n : healthResult.ok\n ? 'border-status-success-text/20 bg-status-success-bg/30'\n : 'border-status-error-text/20 bg-status-error-bg/30'\n }`}\n >\n {validating && !healthResult ? (\n <Loader2 className=\"w-5 h-5 text-text-secondary animate-spin\" />\n ) : healthResult?.ok ? (\n <CheckCircle2 className=\"w-5 h-5 text-status-success-text\" />\n ) : healthResult ? (\n <XCircle className=\"w-5 h-5 text-status-error-text\" />\n ) : (\n <div className=\"w-5 h-5 rounded-full border-2 border-border-default\" />\n )}\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.healthCheck', 'Health Check')}\n </p>\n {healthResult?.ok && healthResult.data && (\n <p className=\"text-xs text-text-secondary\">\n Status: {healthResult.data.status} | Version: {healthResult.data.version} |\n Uptime: {Math.round(healthResult.data.uptime)}s\n </p>\n )}\n {healthResult && !healthResult.ok && (\n <p className=\"text-xs text-status-error-text\">{healthResult.error}</p>\n )}\n </div>\n </div>\n\n {/* API Access Check */}\n <div\n className={`flex items-center gap-3 p-3 rounded-lg border ${\n identityResult === null\n ? 'border-border-default bg-bg-sunken'\n : identityResult.ok\n ? 'border-status-success-text/20 bg-status-success-bg/30'\n : 'border-status-error-text/20 bg-status-error-bg/30'\n }`}\n >\n {validating && !identityResult ? (\n <Loader2 className=\"w-5 h-5 text-text-secondary animate-spin\" />\n ) : identityResult?.ok ? (\n <CheckCircle2 className=\"w-5 h-5 text-status-success-text\" />\n ) : identityResult ? (\n <XCircle className=\"w-5 h-5 text-status-error-text\" />\n ) : (\n <div className=\"w-5 h-5 rounded-full border-2 border-border-default\" />\n )}\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.apiAccess', 'API Access')}\n </p>\n {identityResult?.ok && identityResult.data && (\n <p className=\"text-xs text-text-secondary\">\n Host: {identityResult.data.hostname} | {identityResult.data.platform} /{' '}\n {identityResult.data.arch}\n </p>\n )}\n {identityResult && !identityResult.ok && (\n <p className=\"text-xs text-status-error-text\">{identityResult.error}</p>\n )}\n </div>\n </div>\n </div>\n\n {/* Retry button */}\n {!validating && (!healthResult?.ok || !identityResult?.ok) && (\n <button\n type=\"button\"\n onClick={validateAgent}\n className=\"flex items-center gap-2 px-3 py-1.5 text-sm text-text-secondary hover:text-text-primary hover:bg-bg-sunken rounded-md transition-colors\"\n >\n <RefreshCw className=\"w-3.5 h-3.5\" />\n {tr('agentsPage.retryValidation', 'Retry validation')}\n </button>\n )}\n\n {/* Detected info (editable overrides) */}\n {isValidationPassed && (\n <div className=\"space-y-3 pt-2\">\n <p className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.detectedAgentInfo', 'Detected Agent Info')}\n </p>\n\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n {tr('agentsPage.name', 'Name')}\n </label>\n <input\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={detectedHostname}\n className=\"w-full px-3 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n {tr('agentsPage.platform', 'Platform')}\n </label>\n <select\n value={detectedPlatform}\n onChange={(e) => setDetectedPlatform(e.target.value)}\n className=\"w-full px-3 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value=\"linux\">Linux</option>\n <option value=\"darwin\">macOS</option>\n <option value=\"windows\">Windows</option>\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n {tr('agentsPage.architecture', 'Architecture')}\n </label>\n <select\n value={detectedArch}\n onChange={(e) => setDetectedArch(e.target.value)}\n className=\"w-full px-3 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value=\"x86_64\">x86_64</option>\n <option value=\"arm64\">arm64</option>\n <option value=\"aarch64\">aarch64</option>\n </select>\n </div>\n </div>\n </div>\n )}\n\n {/* Creation error */}\n {createError && (\n <div className=\"p-3 bg-status-error-bg/30 border border-status-error-text/20 rounded-lg\">\n <div className=\"flex items-center gap-2\">\n <XCircle className=\"w-5 h-5 text-status-error-text flex-shrink-0\" />\n <p className=\"text-sm text-status-error-text\">{createError}</p>\n </div>\n <div className=\"flex items-center gap-2 mt-3\">\n <button\n type=\"button\"\n onClick={() => {\n setCreateError(null);\n // Reset form to allow entering different credentials\n setStage('details');\n setTunnelUrl('');\n setAgentApiKey('');\n setHealthResult(null);\n setIdentityResult(null);\n }}\n className=\"flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-text-primary bg-bg-sunken border border-border-default rounded-md hover:bg-bg-elevated transition-colors\"\n >\n <RefreshCw className=\"w-3.5 h-3.5\" />\n {tr('agentsPage.tryDifferentAgent', 'Try Different Agent')}\n </button>\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-3 py-1.5 text-sm font-medium text-text-secondary hover:text-text-primary transition-colors\"\n >\n {tr('agentsPage.close', 'Close')}\n </button>\n </div>\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex items-center justify-between pt-4\">\n <button\n type=\"button\"\n onClick={() => setStage('details')}\n className=\"flex items-center gap-1 px-4 py-2 text-sm font-medium text-text-primary bg-bg-sunken border border-border-default rounded-md hover:bg-bg-elevated transition-colors\"\n >\n <ChevronLeft className=\"w-4 h-4\" />\n {tr('agentsPage.back', 'Back')}\n </button>\n <button\n type=\"button\"\n disabled={!isValidationPassed || isLoading || validating}\n onClick={handleCreateAgent}\n className=\"flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {isLoading ? (\n <>\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n {tr('agentsPage.adding', 'Adding...')}\n </>\n ) : (\n <>\n {tr('agentsPage.addAgent', 'Add Agent')}\n <ChevronRight className=\"w-4 h-4\" />\n </>\n )}\n </button>\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|