@burdenoff/microfe-vibecontrols 2026.626.2 → 2026.709.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"AgentCard.js","names":[],"sources":["../../../src/components/agents/AgentCard.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { Server, Clock, Cpu, Play, Square, Settings, Globe, Link, RefreshCw } from 'lucide-react';\nimport { Checkbox } from '@burdenoff/fe-libs/ui';\nimport { AgentStatusBadge } from './AgentStatusBadge';\nimport type { Agent } from './types';\nimport { getAgentStatus } from './agentStatus';\nimport { classifyAgentHealth } from '../../utils/agentHealth';\nimport { ActionMenu, type ActionMenuItem } from '../shared/ActionMenu';\nimport { PlatformIcon } from '../shared/PlatformIcon';\nimport { useTr } from '../../shared/hooks/useTr';\n\nexport interface AgentCardProps {\n agent: Agent;\n onSelect?: (agent: Agent) => void;\n onConfigure?: (agent: Agent) => void;\n onSettings?: (agent: Agent) => void;\n onStart?: (agent: Agent) => void;\n onStop?: (agent: Agent) => void;\n onDisconnect?: (agent: Agent) => void;\n onEditTunnelUrl?: (agent: Agent) => void;\n selected?: boolean;\n onToggleSelect?: () => void;\n className?: string;\n /**\n * Last error from /health/ready or the live probe — shown in the badge\n * tooltip when the agent is degraded so users know WHY without curling\n * the tunnel themselves.\n */\n healthErrorMessage?: string | null;\n}\n\n/**\n * AgentCard - Display agent information in a card format\n *\n * @example\n * ```tsx\n * <AgentCard\n * agent={myAgent}\n * onSelect={handleSelect}\n * onConfigure={handleConfigure}\n * />\n * ```\n */\nexport const AgentCard: FC<AgentCardProps> = ({\n agent,\n onSelect,\n onConfigure,\n onSettings,\n onStart,\n onStop,\n onDisconnect,\n onEditTunnelUrl,\n selected = false,\n onToggleSelect,\n className = '',\n healthErrorMessage,\n}) => {\n const tr = useTr();\n // Support both onConfigure and onSettings\n const handleConfigure = onConfigure || onSettings;\n\n const status = getAgentStatus(agent);\n\n const formatLastHeartbeat = (timestamp: string | null | undefined) => {\n if (!timestamp) return tr('agentsPage.never', 'Never');\n const diff = Date.now() - new Date(timestamp).getTime();\n if (diff < 60000) return tr('agentsPage.justNow', 'Just now');\n if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`;\n if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago`;\n return `${Math.floor(diff / 86400000)}d ago`;\n };\n\n const menuItems: ActionMenuItem[] = [];\n if (status === 'ACTIVE' && onStop) {\n menuItems.push({\n key: 'stop',\n label: tr('agentsPage.stopAgent', 'Stop Agent'),\n icon: Square,\n onSelect: () => onStop(agent),\n });\n }\n if ((status === 'STOPPED' || status === 'OFFLINE') && onStart) {\n menuItems.push({\n key: 'start',\n label: tr('agentsPage.startAgent', 'Start Agent'),\n icon: Play,\n onSelect: () => onStart(agent),\n });\n }\n if (status === 'DEGRADED' && onStart) {\n // Reconnect on a degraded agent fires the same startVibecontrolsAgent\n // mutation as a fresh start — svc-side that POSTs lifecycle/start to the\n // agent's tunnel, which usually clears transient failures (tunnel hiccup,\n // finalize retry). Labelled \"Reconnect\" not \"Start\" so the user knows\n // it's a recovery action, not creating a new instance.\n menuItems.push({\n key: 'reconnect',\n label: tr('agentsPage.reconnectAgent', 'Reconnect'),\n icon: RefreshCw,\n onSelect: () => onStart(agent),\n });\n }\n if (\n (status === 'ACTIVE' ||\n status === 'STOPPED' ||\n status === 'OFFLINE' ||\n status === 'DEGRADED') &&\n onDisconnect\n ) {\n menuItems.push({\n key: 'disconnect',\n label:\n status === 'OFFLINE'\n ? tr('agentsPage.clearConnection', 'Clear Connection')\n : tr('agentsPage.disconnect', 'Disconnect'),\n icon: Square,\n onSelect: () => onDisconnect(agent),\n variant: 'danger',\n });\n }\n if (onEditTunnelUrl) {\n menuItems.push({\n key: 'edit-tunnel',\n label: tr('agentsPage.editTunnel', 'Edit Tunnel'),\n icon: Link,\n onSelect: () => onEditTunnelUrl(agent),\n });\n }\n if (handleConfigure) {\n menuItems.push({\n key: 'settings',\n label: tr('agentsPage.settings', 'Settings'),\n icon: Settings,\n onSelect: () => handleConfigure(agent),\n });\n }\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n className={`bg-bg-surface border rounded-card shadow-elevation-1 p-5 h-full hover:border-border-strong hover:shadow-elevation-2 transition-all duration-200 ease-[var(--motion-easing-out)] cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:ring-offset-2 focus-visible:ring-offset-bg-canvas ${\n selected\n ? 'border-transparent ring-1 ring-[var(--color-focus-ring)] bg-[var(--color-accent-soft)]'\n : 'border-border-subtle'\n } ${className}`}\n onClick={() => onSelect?.(agent)}\n onKeyDown={(e) => {\n if (e.target !== e.currentTarget) return; // children (menu, checkbox, links) handle their own keys\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onSelect?.(agent);\n }\n }}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex items-start gap-2 sm:gap-3 min-w-0 flex-1\">\n {/* Selection Checkbox */}\n {onToggleSelect && (\n <span\n className=\"flex flex-shrink-0 items-center justify-center max-md:min-h-11 max-md:min-w-11 max-md:-m-2 md:mt-0.5\"\n onClick={(e) => {\n e.stopPropagation();\n if (e.target === e.currentTarget) onToggleSelect();\n }}\n >\n <Checkbox\n checked={selected}\n onCheckedChange={() => onToggleSelect()}\n onClick={(e) => e.stopPropagation()}\n aria-label={tr('agentsPage.selectAgent', 'Select {{name}}', { name: agent.name })}\n />\n </span>\n )}\n <div className=\"flex-shrink-0 size-9 sm:size-10 rounded-lg bg-[var(--color-accent-soft)] flex items-center justify-center\">\n <Server className=\"size-4 sm:size-5 text-action-primary-bg\" aria-hidden=\"true\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-1.5 sm:gap-2 min-w-0\">\n <h3 className=\"font-semibold text-text-primary truncate min-w-0 text-sm sm:text-base tracking-tight\">\n {agent.name}\n </h3>\n <PlatformIcon\n platform={agent.platform}\n className=\"size-4 flex-shrink-0 text-text-secondary\"\n />\n </div>\n <p className=\"text-xs sm:text-sm text-text-secondary truncate\">\n {agent.hostname || `ID: ${agent.id}`}\n </p>\n </div>\n </div>\n {/* Status and Actions - always visible */}\n <div className=\"flex items-center gap-1 sm:gap-2 flex-shrink-0\">\n <AgentStatusBadge\n status={status}\n reason={healthErrorMessage ?? null}\n linkTo={`/vibecontrols/agents/${agent.id}?tab=connection`}\n onClick={(event) => {\n // The card itself has a `onSelect` click target that\n // routes to the agent detail. Stop propagation so a\n // badge click doesn't *also* fire that handler — the\n // anchor's href already routes to the right tab and\n // React Router picks it up via the surrounding shell.\n event.stopPropagation();\n }}\n />\n {(handleConfigure || onStart || onStop) && menuItems.length > 0 && (\n <ActionMenu\n ariaLabel={tr('agentsPage.agentActionsMenu', 'Agent actions menu')}\n title={tr('agentsPage.agentActions', 'Agent actions')}\n align=\"end\"\n items={menuItems}\n />\n )}\n </div>\n </div>\n\n {(() => {\n // Full-width status guidance row (below the header) so the degraded /\n // recovering copy gets the whole card width to wrap on narrow screens,\n // instead of being crushed into the narrow name column next to the\n // status badge + actions menu.\n const health = classifyAgentHealth(status, healthErrorMessage ?? null);\n if (health.phase === 'none') return null;\n return (\n <div\n className={`mt-3 flex items-start gap-1.5 text-xs ${\n health.phase === 'attention' ? 'text-status-warning-text' : 'text-content-tertiary'\n }`}\n >\n {health.inProgress && (\n <RefreshCw className=\"size-3.5 mt-0.5 flex-shrink-0 animate-spin\" aria-hidden=\"true\" />\n )}\n <p className=\"min-w-0 flex-1 break-words leading-relaxed\">\n <span className=\"font-medium\">{health.label}.</span> {health.actionHint}\n </p>\n </div>\n );\n })()}\n\n <div className=\"mt-5 grid grid-cols-2 gap-3 text-sm\">\n <div className=\"flex items-center gap-2 text-text-secondary\">\n <Clock className=\"size-4\" aria-hidden=\"true\" />\n <span className=\"tabular-nums\">{formatLastHeartbeat(agent.lastHeartbeat)}</span>\n </div>\n {agent.architecture && (\n <div className=\"flex items-center gap-2 text-text-secondary\">\n <Cpu className=\"size-4\" aria-hidden=\"true\" />\n <span>{agent.architecture}</span>\n </div>\n )}\n </div>\n\n {agent.tunnelUrl && (\n // Plain \"Tunnel: <link>\" row. The colored status chip that used\n // to sit here was a redundant second status surface — the\n // canonical state lives in the <AgentStatusBadge> top-right.\n // The Globe glyph stays as a neutral icon (no status color).\n <div className=\"mt-4 flex items-center gap-2 text-sm\">\n <Globe className=\"size-4 flex-shrink-0 text-text-secondary\" aria-hidden=\"true\" />\n <span className=\"text-text-secondary flex-shrink-0\">Tunnel:</span>\n <a\n href={agent.tunnelUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={(e) => e.stopPropagation()}\n aria-label={tr('agentsPage.tunnelOpensInNewTab', '{{url}} (opens in new tab)', {\n url: agent.tunnelUrl,\n })}\n className=\"min-w-0 truncate font-mono text-xs text-text-link hover:text-text-linkHover hover:underline\"\n >\n {agent.tunnelUrl}\n </a>\n </div>\n )}\n\n {agent.capabilities && agent.capabilities.length > 0 && (\n <div className=\"mt-4 flex flex-wrap gap-1.5\">\n {agent.capabilities.slice(0, 4).map((cap) => (\n <span\n key={cap}\n className=\"px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded-full\"\n >\n {cap}\n </span>\n ))}\n {agent.capabilities.length > 4 && (\n <span className=\"px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded-full\">\n +{agent.capabilities.length - 4}\n </span>\n )}\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"AgentCard.js","names":[],"sources":["../../../src/components/agents/AgentCard.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { Server, Clock, Cpu, Play, Square, Settings, Globe, Link, RefreshCw } from 'lucide-react';\nimport { Checkbox } from '@burdenoff/fe-libs/ui';\nimport { AgentStatusBadge } from './AgentStatusBadge';\nimport type { Agent } from './types';\nimport { getAgentStatus } from './agentStatus';\nimport { classifyAgentHealth } from '../../utils/agentHealth';\nimport { ActionMenu, type ActionMenuItem } from '../shared/ActionMenu';\nimport { PlatformIcon } from '../shared/PlatformIcon';\nimport { useTr } from '../../shared/hooks/useTr';\n\nexport interface AgentCardProps {\n agent: Agent;\n onSelect?: (agent: Agent) => void;\n onConfigure?: (agent: Agent) => void;\n onSettings?: (agent: Agent) => void;\n onStart?: (agent: Agent) => void;\n onStop?: (agent: Agent) => void;\n onDisconnect?: (agent: Agent) => void;\n onEditTunnelUrl?: (agent: Agent) => void;\n selected?: boolean;\n onToggleSelect?: () => void;\n className?: string;\n /**\n * Last error from /health/ready or the live probe — shown in the badge\n * tooltip when the agent is degraded so users know WHY without curling\n * the tunnel themselves.\n */\n healthErrorMessage?: string | null;\n}\n\n/**\n * AgentCard - Display agent information in a card format\n *\n * @example\n * ```tsx\n * <AgentCard\n * agent={myAgent}\n * onSelect={handleSelect}\n * onConfigure={handleConfigure}\n * />\n * ```\n */\nexport const AgentCard: FC<AgentCardProps> = ({\n agent,\n onSelect,\n onConfigure,\n onSettings,\n onStart,\n onStop,\n onDisconnect,\n onEditTunnelUrl,\n selected = false,\n onToggleSelect,\n className = '',\n healthErrorMessage,\n}) => {\n const tr = useTr();\n // Support both onConfigure and onSettings\n const handleConfigure = onConfigure || onSettings;\n\n const status = getAgentStatus(agent);\n\n const formatLastHeartbeat = (timestamp: string | null | undefined) => {\n if (!timestamp) return tr('agentsPage.never', 'Never');\n const diff = Date.now() - new Date(timestamp).getTime();\n if (diff < 60000) return tr('agentsPage.justNow', 'Just now');\n if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`;\n if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago`;\n return `${Math.floor(diff / 86400000)}d ago`;\n };\n\n const menuItems: ActionMenuItem[] = [];\n if (status === 'ACTIVE' && onStop) {\n menuItems.push({\n key: 'stop',\n label: tr('agentsPage.stopAgent', 'Stop Agent'),\n icon: Square,\n onSelect: () => onStop(agent),\n });\n }\n if ((status === 'STOPPED' || status === 'OFFLINE') && onStart) {\n menuItems.push({\n key: 'start',\n label: tr('agentsPage.startAgent', 'Start Agent'),\n icon: Play,\n onSelect: () => onStart(agent),\n });\n }\n if (status === 'DEGRADED' && onStart) {\n // Reconnect on a degraded agent fires the same startVibecontrolsAgent\n // mutation as a fresh start — svc-side that POSTs lifecycle/start to the\n // agent's tunnel, which usually clears transient failures (tunnel hiccup,\n // finalize retry). Labelled \"Reconnect\" not \"Start\" so the user knows\n // it's a recovery action, not creating a new instance.\n menuItems.push({\n key: 'reconnect',\n label: tr('agentsPage.reconnectAgent', 'Reconnect'),\n icon: RefreshCw,\n onSelect: () => onStart(agent),\n });\n }\n if (\n (status === 'ACTIVE' ||\n status === 'STOPPED' ||\n status === 'OFFLINE' ||\n status === 'DEGRADED') &&\n onDisconnect\n ) {\n menuItems.push({\n key: 'disconnect',\n label:\n status === 'OFFLINE'\n ? tr('agentsPage.clearConnection', 'Clear Connection')\n : tr('agentsPage.disconnect', 'Disconnect'),\n icon: Square,\n onSelect: () => onDisconnect(agent),\n variant: 'danger',\n });\n }\n if (onEditTunnelUrl) {\n menuItems.push({\n key: 'edit-tunnel',\n label: tr('agentsPage.editTunnel', 'Edit Tunnel'),\n icon: Link,\n onSelect: () => onEditTunnelUrl(agent),\n });\n }\n if (handleConfigure) {\n menuItems.push({\n key: 'settings',\n label: tr('agentsPage.settings', 'Settings'),\n icon: Settings,\n onSelect: () => handleConfigure(agent),\n });\n }\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n className={`bg-bg-surface border rounded-card shadow-elevation-1 p-5 h-full hover:border-border-strong hover:shadow-elevation-2 transition-all duration-200 ease-[var(--motion-easing-out)] cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:ring-offset-2 focus-visible:ring-offset-bg-canvas ${\n selected\n ? 'border-transparent ring-1 ring-[var(--color-focus-ring)] bg-[var(--color-accent-soft)]'\n : 'border-border-subtle'\n } ${className}`}\n onClick={() => onSelect?.(agent)}\n onKeyDown={(e) => {\n if (e.target !== e.currentTarget) return; // children (menu, checkbox, links) handle their own keys\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onSelect?.(agent);\n }\n }}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex items-start gap-2 sm:gap-3 min-w-0 flex-1\">\n {/* Selection Checkbox */}\n {onToggleSelect && (\n <span\n className=\"flex flex-shrink-0 items-center justify-center max-md:min-h-11 max-md:min-w-11 max-md:-m-2 md:mt-0.5\"\n onClick={(e) => {\n e.stopPropagation();\n if (e.target === e.currentTarget) onToggleSelect();\n }}\n >\n <Checkbox\n checked={selected}\n onCheckedChange={() => onToggleSelect()}\n onClick={(e) => e.stopPropagation()}\n aria-label={tr('agentsPage.selectAgent', 'Select {{name}}', { name: agent.name })}\n />\n </span>\n )}\n <div className=\"flex-shrink-0 size-9 sm:size-10 rounded-lg bg-[var(--color-accent-soft)] flex items-center justify-center\">\n <Server className=\"size-4 sm:size-5 text-action-primary-bg\" aria-hidden=\"true\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-1.5 sm:gap-2 min-w-0\">\n <h3 className=\"font-semibold text-text-primary truncate min-w-0 text-sm sm:text-base tracking-tight\">\n {agent.name}\n </h3>\n <PlatformIcon\n platform={agent.platform}\n className=\"size-4 flex-shrink-0 text-text-secondary\"\n />\n </div>\n <p className=\"text-xs sm:text-sm text-text-secondary truncate\">\n {agent.hostname || `ID: ${agent.id}`}\n </p>\n </div>\n </div>\n {/* Status and Actions - always visible */}\n <div className=\"flex items-center gap-1 sm:gap-2 flex-shrink-0\">\n <AgentStatusBadge\n status={status}\n reason={healthErrorMessage ?? null}\n linkTo={`/vibecontrols/agents/${agent.id}?tab=connection`}\n onClick={(event) => {\n // The card itself has a `onSelect` click target that\n // routes to the agent detail. Stop propagation so a\n // badge click doesn't *also* fire that handler — the\n // anchor's href already routes to the right tab and\n // React Router picks it up via the surrounding shell.\n event.stopPropagation();\n }}\n />\n {(handleConfigure || onStart || onStop) && menuItems.length > 0 && (\n <ActionMenu\n ariaLabel={tr('agentsPage.agentActionsMenu', 'Agent actions menu')}\n title={tr('agentsPage.agentActions', 'Agent actions')}\n align=\"end\"\n items={menuItems}\n />\n )}\n </div>\n </div>\n\n {(() => {\n // Full-width status guidance row (below the header) so the degraded /\n // recovering copy gets the whole card width to wrap on narrow screens,\n // instead of being crushed into the narrow name column next to the\n // status badge + actions menu.\n const health = classifyAgentHealth(status, healthErrorMessage ?? null);\n if (health.phase === 'none') return null;\n return (\n <div\n className={`mt-3 flex items-start gap-1.5 text-xs ${\n health.phase === 'attention' ? 'text-status-warning-text' : 'text-content-tertiary'\n }`}\n >\n {health.inProgress && (\n <RefreshCw\n className=\"size-3.5 mt-0.5 flex-shrink-0 animate-spin\"\n aria-hidden=\"true\"\n />\n )}\n <p className=\"min-w-0 flex-1 break-words leading-relaxed\">\n <span className=\"font-medium\">{health.label}.</span> {health.actionHint}\n </p>\n </div>\n );\n })()}\n\n <div className=\"mt-5 grid grid-cols-2 gap-3 text-sm\">\n <div className=\"flex items-center gap-2 text-text-secondary\">\n <Clock className=\"size-4\" aria-hidden=\"true\" />\n <span className=\"tabular-nums\">{formatLastHeartbeat(agent.lastHeartbeat)}</span>\n </div>\n {agent.architecture && (\n <div className=\"flex items-center gap-2 text-text-secondary\">\n <Cpu className=\"size-4\" aria-hidden=\"true\" />\n <span>{agent.architecture}</span>\n </div>\n )}\n </div>\n\n {agent.tunnelUrl && (\n // Plain \"Tunnel: <link>\" row. The colored status chip that used\n // to sit here was a redundant second status surface — the\n // canonical state lives in the <AgentStatusBadge> top-right.\n // The Globe glyph stays as a neutral icon (no status color).\n <div className=\"mt-4 flex items-center gap-2 text-sm\">\n <Globe className=\"size-4 flex-shrink-0 text-text-secondary\" aria-hidden=\"true\" />\n <span className=\"text-text-secondary flex-shrink-0\">Tunnel:</span>\n <a\n href={agent.tunnelUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={(e) => e.stopPropagation()}\n aria-label={tr('agentsPage.tunnelOpensInNewTab', '{{url}} (opens in new tab)', {\n url: agent.tunnelUrl,\n })}\n className=\"min-w-0 truncate font-mono text-xs text-text-link hover:text-text-linkHover hover:underline\"\n >\n {agent.tunnelUrl}\n </a>\n </div>\n )}\n\n {agent.capabilities && agent.capabilities.length > 0 && (\n <div className=\"mt-4 flex flex-wrap gap-1.5\">\n {agent.capabilities.slice(0, 4).map((cap) => (\n <span\n key={cap}\n className=\"px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded-full\"\n >\n {cap}\n </span>\n ))}\n {agent.capabilities.length > 4 && (\n <span className=\"px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded-full\">\n +{agent.capabilities.length - 4}\n </span>\n )}\n </div>\n )}\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;AA2CA,IAAa,KAAiC,EAC5C,UACA,aACA,gBACA,eACA,YACA,WACA,iBACA,oBACA,cAAW,IACX,mBACA,eAAY,IACZ,4BACI;CACJ,IAAM,IAAK,GAAO,EAEZ,IAAkB,KAAe,GAEjC,IAAS,EAAe,EAAM,EAE9B,KAAuB,MAAyC;AACpE,MAAI,CAAC,EAAW,QAAO,EAAG,oBAAoB,QAAQ;EACtD,IAAM,IAAO,KAAK,KAAK,GAAG,IAAI,KAAK,EAAU,CAAC,SAAS;AAIvD,SAHI,IAAO,MAAc,EAAG,sBAAsB,WAAW,GACzD,IAAO,OAAgB,GAAG,KAAK,MAAM,IAAO,IAAM,CAAC,SACnD,IAAO,QAAiB,GAAG,KAAK,MAAM,IAAO,KAAQ,CAAC,SACnD,GAAG,KAAK,MAAM,IAAO,MAAS,CAAC;IAGlC,IAA8B,EAAE;AAiEtC,QAhEI,MAAW,YAAY,KACzB,EAAU,KAAK;EACb,KAAK;EACL,OAAO,EAAG,wBAAwB,aAAa;EAC/C,MAAM;EACN,gBAAgB,EAAO,EAAM;EAC9B,CAAC,GAEC,MAAW,aAAa,MAAW,cAAc,KACpD,EAAU,KAAK;EACb,KAAK;EACL,OAAO,EAAG,yBAAyB,cAAc;EACjD,MAAM;EACN,gBAAgB,EAAQ,EAAM;EAC/B,CAAC,EAEA,MAAW,cAAc,KAM3B,EAAU,KAAK;EACb,KAAK;EACL,OAAO,EAAG,6BAA6B,YAAY;EACnD,MAAM;EACN,gBAAgB,EAAQ,EAAM;EAC/B,CAAC,GAGD,MAAW,YACV,MAAW,aACX,MAAW,aACX,MAAW,eACb,KAEA,EAAU,KAAK;EACb,KAAK;EACL,OACE,MAAW,YACP,EAAG,8BAA8B,mBAAmB,GACpD,EAAG,yBAAyB,aAAa;EAC/C,MAAM;EACN,gBAAgB,EAAa,EAAM;EACnC,SAAS;EACV,CAAC,EAEA,KACF,EAAU,KAAK;EACb,KAAK;EACL,OAAO,EAAG,yBAAyB,cAAc;EACjD,MAAM;EACN,gBAAgB,EAAgB,EAAM;EACvC,CAAC,EAEA,KACF,EAAU,KAAK;EACb,KAAK;EACL,OAAO,EAAG,uBAAuB,WAAW;EAC5C,MAAM;EACN,gBAAgB,EAAgB,EAAM;EACvC,CAAC,EAIF,kBAAC,OAAD;EACE,MAAK;EACL,UAAU;EACV,WAAW,kVACT,IACI,2FACA,uBACL,GAAG;EACJ,eAAe,IAAW,EAAM;EAChC,YAAY,MAAM;AACZ,KAAE,WAAW,EAAE,kBACf,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,gBAAgB,EAClB,IAAW,EAAM;;YAbvB;GAiBE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf;MAEG,KACC,kBAAC,QAAD;OACE,WAAU;OACV,UAAU,MAAM;AAEd,QADA,EAAE,iBAAiB,EACf,EAAE,WAAW,EAAE,iBAAe,GAAgB;;iBAGpD,kBAAC,GAAD;QACE,SAAS;QACT,uBAAuB,GAAgB;QACvC,UAAU,MAAM,EAAE,iBAAiB;QACnC,cAAY,EAAG,0BAA0B,mBAAmB,EAAE,MAAM,EAAM,MAAM,CAAC;QACjF,CAAA;OACG,CAAA;MAET,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,GAAD;QAAQ,WAAU;QAA0C,eAAY;QAAS,CAAA;OAC7E,CAAA;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAM;SACJ,CAAA,EACL,kBAAC,GAAD;SACE,UAAU,EAAM;SAChB,WAAU;SACV,CAAA,CACE;WACN,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAM,YAAY,OAAO,EAAM;QAC9B,CAAA,CACA;;MACF;QAEN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MACU;MACR,QAAQ,KAAsB;MAC9B,QAAQ,wBAAwB,EAAM,GAAG;MACzC,UAAU,MAAU;AAMlB,SAAM,iBAAiB;;MAEzB,CAAA,GACA,KAAmB,KAAW,MAAW,EAAU,SAAS,KAC5D,kBAAC,GAAD;MACE,WAAW,EAAG,+BAA+B,qBAAqB;MAClE,OAAO,EAAG,2BAA2B,gBAAgB;MACrD,OAAM;MACN,OAAO;MACP,CAAA,CAEA;OACF;;UAEE;IAKN,IAAM,IAAS,EAAoB,GAAQ,KAAsB,KAAK;AAEtE,WADI,EAAO,UAAU,SAAe,OAElC,kBAAC,OAAD;KACE,WAAW,yCACT,EAAO,UAAU,cAAc,6BAA6B;eAFhE,CAKG,EAAO,cACN,kBAAC,GAAD;MACE,WAAU;MACV,eAAY;MACZ,CAAA,EAEJ,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACE,kBAAC,QAAD;QAAM,WAAU;kBAAhB,CAA+B,EAAO,OAAM,IAAQ;;;OAAE,EAAO;OAC3D;QACA;;OAEN;GAEJ,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAO,WAAU;MAAS,eAAY;MAAS,CAAA,EAC/C,kBAAC,QAAD;MAAM,WAAU;gBAAgB,EAAoB,EAAM,cAAc;MAAQ,CAAA,CAC5E;QACL,EAAM,gBACL,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAK,WAAU;MAAS,eAAY;MAAS,CAAA,EAC7C,kBAAC,QAAD,EAAA,UAAO,EAAM,cAAoB,CAAA,CAC7B;OAEJ;;GAEL,EAAM,aAKL,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAO,WAAU;MAA2C,eAAY;MAAS,CAAA;KACjF,kBAAC,QAAD;MAAM,WAAU;gBAAoC;MAAc,CAAA;KAClE,kBAAC,KAAD;MACE,MAAM,EAAM;MACZ,QAAO;MACP,KAAI;MACJ,UAAU,MAAM,EAAE,iBAAiB;MACnC,cAAY,EAAG,kCAAkC,8BAA8B,EAC7E,KAAK,EAAM,WACZ,CAAC;MACF,WAAU;gBAET,EAAM;MACL,CAAA;KACA;;GAGP,EAAM,gBAAgB,EAAM,aAAa,SAAS,KACjD,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,EAAM,aAAa,MAAM,GAAG,EAAE,CAAC,KAAK,MACnC,kBAAC,QAAD;KAEE,WAAU;eAET;KACI,EAJA,EAIA,CACP,EACD,EAAM,aAAa,SAAS,KAC3B,kBAAC,QAAD;KAAM,WAAU;eAAhB,CAAoF,KAChF,EAAM,aAAa,SAAS,EACzB;OAEL;;GAEJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"EmptyState.js","names":[],"sources":["../../../src/components/shared/EmptyState.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport {\n EmptyState as CanonicalEmptyState,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\n\ninterface EmptyStateProps {\n icon?: ReactNode;\n title: string;\n description?: string;\n action?: ReactNode;\n /**\n * Boff UI 2.0 — when set, the empty state renders the on-brand illustration\n * (served by the host shell at `/illustrations/<name>.webp`) instead of the\n * plain icon. Falls back to the icon path when omitted so existing call sites\n * stay visually unchanged.\n */\n illustration?: string;\n /** Optional alt text for the illustration (defaults to the title). */\n illustrationAlt?: string;\n}\n\n/**\n * Local wrapper around `EmptyState` from `@burdenoff/fe-libs/ui`.\n *\n * Keeps the existing microfe-vibecontrols call sites stable while routing all\n * empty-state rendering through the canonical primitive. When an `illustration`\n * is supplied it routes through the richer `IllustratedEmptyState` primitive.\n */\nexport function EmptyState({\n icon,\n title,\n description,\n action,\n illustration,\n illustrationAlt,\n}: EmptyStateProps) {\n if (illustration) {\n return (\n <IllustratedEmptyState\n illustration={illustration}\n alt={illustrationAlt ?? title}\n title={title}\n description={description}\n action={action}\n />\n );\n }\n return (\n <CanonicalEmptyState icon={icon} title={title} description={description} action={action} />\n );\n}\n"],"mappings":";;;AA6BA,SAAgB,EAAW,EACzB,SACA,UACA,gBACA,WACA,iBACA,sBACkB;AAYlB,QAXI,IAEA,kBAAC,GAAD;EACgB;EACd,KAAK,KAAmB;EACjB;EACM;EACL;EACR,CAAA,GAIJ,kBAAC,GAAD;EAA2B;EAAa;EAAoB;EAAqB;EAAU,CAAA"}
1
+ {"version":3,"file":"EmptyState.js","names":[],"sources":["../../../src/components/shared/EmptyState.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { EmptyState as CanonicalEmptyState, IllustratedEmptyState } from '@burdenoff/fe-libs/ui';\n\ninterface EmptyStateProps {\n icon?: ReactNode;\n title: string;\n description?: string;\n action?: ReactNode;\n /**\n * Boff UI 2.0 — when set, the empty state renders the on-brand illustration\n * (served by the host shell at `/illustrations/<name>.webp`) instead of the\n * plain icon. Falls back to the icon path when omitted so existing call sites\n * stay visually unchanged.\n */\n illustration?: string;\n /** Optional alt text for the illustration (defaults to the title). */\n illustrationAlt?: string;\n}\n\n/**\n * Local wrapper around `EmptyState` from `@burdenoff/fe-libs/ui`.\n *\n * Keeps the existing microfe-vibecontrols call sites stable while routing all\n * empty-state rendering through the canonical primitive. When an `illustration`\n * is supplied it routes through the richer `IllustratedEmptyState` primitive.\n */\nexport function EmptyState({\n icon,\n title,\n description,\n action,\n illustration,\n illustrationAlt,\n}: EmptyStateProps) {\n if (illustration) {\n return (\n <IllustratedEmptyState\n illustration={illustration}\n alt={illustrationAlt ?? title}\n title={title}\n description={description}\n action={action}\n />\n );\n }\n return (\n <CanonicalEmptyState icon={icon} title={title} description={description} action={action} />\n );\n}\n"],"mappings":";;;AA0BA,SAAgB,EAAW,EACzB,SACA,UACA,gBACA,WACA,iBACA,sBACkB;AAYlB,QAXI,IAEA,kBAAC,GAAD;EACgB;EACd,KAAK,KAAmB;EACjB;EACM;EACL;EACR,CAAA,GAIJ,kBAAC,GAAD;EAA2B;EAAa;EAAoB;EAAqB;EAAU,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"GettingStartedPage.js","names":[],"sources":["../../src/pages/GettingStartedPage.tsx"],"sourcesContent":["import { useCallback, useMemo, useState } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { Terminal, ExternalLink, Download, Info } from 'lucide-react';\nimport { PageHeader, Card, InstallTabs } from '@/components/shared';\nimport { EmphasisPanel, ShowMore } from '@burdenoff/fe-libs/ui';\nimport { MotionPage, MotionList, MotionItem } from '@burdenoff/fe-libs/shared/motion';\nimport { Tabs, type TabItem } from '@burdenoff/fe-libs/chrome';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\nconst AGENT_NPM_URL = 'https://www.npmjs.com/package/@vibecontrols/agent';\nconst INSTALL_DOCS_URL = 'https://docs.vibecontrols.com/users/installing-the-agent';\n\n/**\n * Getting Started page — a tabbed guide to installing and running the\n * VibeControls Agent. Two top-level tabs:\n *\n * • Install — shows the global bun / npm install commands via the shared\n * `InstallTabs` component, plus the real connect-and-run flow.\n * • CLI Reference — a compact reference of the agent's `vibe` commands.\n *\n * Bun (or Node >= 18 for npm) is the only machine prerequisite. On first run\n * `vibe start` sets up a Cloudflare tunnel, generates an agentApiKey, and\n * waits for the platform to push OAuth credentials once the agent is\n * connected here.\n *\n * Official docs: https://docs.vibecontrols.com/users/installing-the-agent\n */\nexport function GettingStartedPage() {\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n const [params, setParams] = useSearchParams();\n const tabs: TabItem[] = useMemo(\n () => [\n { id: 'install', label: tr('gettingStarted.installTab', 'Install') },\n { id: 'cli', label: tr('gettingStarted.cliTab', 'CLI Reference') },\n ],\n [tr]\n );\n const activeId = params.get('tab') ?? tabs[0].id;\n const handleTabChange = (id: string) => {\n const next = new URLSearchParams(params);\n if (id === tabs[0].id) next.delete('tab');\n else next.set('tab', id);\n setParams(next, { replace: true });\n };\n\n const [pinnedVersion, setPinnedVersion] = useState('');\n\n return (\n <MotionPage className=\"space-y-8 px-6 lg:px-8 py-6 bg-bg-canvas min-h-screen\">\n <PageHeader\n title={tr('gettingStarted.title', 'Getting Started')}\n description={tr(\n 'gettingStarted.description',\n 'Install and configure the VibeControls Agent CLI'\n )}\n />\n\n <div className=\"border-b border-border-subtle\">\n <Tabs\n items={tabs}\n activeTabId={activeId}\n onTabChange={handleTabChange}\n variant=\"underline\"\n />\n </div>\n\n {activeId === 'install' && (\n <div className=\"space-y-6\">\n {/* Hero — the single emphasised zone on this page */}\n <EmphasisPanel className=\"sm:p-8\">\n <div className=\"flex items-start gap-4\">\n <div className=\"flex-shrink-0 size-12 rounded-xl bg-[var(--color-accent-soft)] flex items-center justify-center\">\n <Download className=\"size-6 text-accent-purple\" />\n </div>\n <div className=\"flex-1\">\n <h2 className=\"text-lg sm:text-xl font-semibold text-text-primary mb-1\">\n {tr('gettingStarted.installAgent', 'Install the Agent')}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'gettingStarted.installAgentDesc',\n 'Install the agent globally with bun or npm on the machine you want to manage, then run vibe start. Bun (or Node >= 18 for npm) is the only prerequisite.'\n )}\n </p>\n <a\n href={INSTALL_DOCS_URL}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mt-3 inline-flex items-center gap-1.5 text-sm text-text-link hover:text-text-linkHover hover:underline\"\n >\n {tr('gettingStarted.viewInstallDocs', 'View the full install docs')}\n <ExternalLink className=\"size-3.5\" />\n </a>\n </div>\n </div>\n </EmphasisPanel>\n\n {/* Install tabs */}\n <Card padding=\"none\">\n <div className=\"p-5 sm:p-6\">\n <InstallTabs pinnedAgentVersion={pinnedVersion || undefined} />\n\n <div className=\"mt-6 pt-4 border-t border-border-subtle\">\n <label\n htmlFor=\"pinned-version\"\n className=\"text-xs font-medium text-text-secondary flex items-center gap-1.5 mb-1.5\"\n >\n <Info className=\"size-3.5\" />{' '}\n {tr('gettingStarted.pinVersion', 'Pin a specific agent version (optional)')}\n </label>\n <input\n aria-label=\"pinned-version\"\n id=\"pinned-version\"\n type=\"text\"\n placeholder={tr(\n 'gettingStarted.pinVersionPlaceholder',\n 'e.g. 2026.408.1 (leave blank for latest)'\n )}\n value={pinnedVersion}\n onChange={(e) => setPinnedVersion(e.target.value)}\n className=\"w-full max-w-xs px-3 py-2 rounded-input border border-border-default bg-bg-elevated text-sm text-text-primary focus-visible:outline-none focus-visible:border-border-strong focus-visible:shadow-[var(--shadow-focus)]\"\n />\n </div>\n </div>\n </Card>\n\n {/* Next steps */}\n <Card padding=\"none\">\n <div className=\"p-5 sm:p-6\">\n <h3 className=\"text-base font-semibold text-text-primary mb-3\">\n {tr('gettingStarted.nextSteps', 'Next steps')}\n </h3>\n <ol className=\"list-decimal list-inside space-y-2 text-sm text-text-secondary\">\n <li>\n {tr('gettingStarted.nextStep1Prefix', 'Start the agent:')}{' '}\n <code className=\"font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded\">\n vibe start\n </code>{' '}\n {tr(\n 'gettingStarted.nextStep1Suffix',\n '— on first run it establishes a Cloudflare tunnel, generates an agentApiKey, and waits in pre-config mode for the platform.'\n )}\n </li>\n <li>\n {tr('gettingStarted.nextStep2Prefix', 'In this UI, go to')}{' '}\n <strong>\n {tr('gettingStarted.targetsAndAgents', 'Targets & Agents')} →{' '}\n {tr('gettingStarted.addAgent', 'Add Agent')}\n </strong>\n {tr(\n 'gettingStarted.nextStep2Suffix',\n ', create or pick a target, and paste the tunnel URL and agentApiKey that vibe start printed. The platform then pushes OAuth credentials automatically and the agent activates.'\n )}\n </li>\n <li>\n {tr('gettingStarted.nextStep3Prefix', 'Run it as a background service:')}{' '}\n <code className=\"font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded\">\n vibe autostart install\n </code>{' '}\n {tr('gettingStarted.nextStep3Suffix', '(remove later with')}{' '}\n <code className=\"font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded\">\n vibe autostart uninstall\n </code>\n {tr('gettingStarted.nextStep3End', ').')}\n </li>\n <li>\n {tr('gettingStarted.nextStep4Prefix', 'Verify it is running with')}{' '}\n <code className=\"font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded\">\n vibe health\n </code>{' '}\n {tr('gettingStarted.nextStep4And', 'and')}{' '}\n <code className=\"font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded\">\n vibe status\n </code>\n .\n </li>\n </ol>\n <a\n href={INSTALL_DOCS_URL}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mt-4 inline-flex items-center gap-1.5 text-sm text-text-link hover:text-text-linkHover hover:underline\"\n >\n {tr('gettingStarted.viewInstallDocs', 'View the full install docs')}\n <ExternalLink className=\"size-3.5\" />\n </a>\n </div>\n </Card>\n </div>\n )}\n\n {activeId === 'cli' && (\n <Card padding=\"none\">\n <div className=\"p-5 sm:p-6\">\n <h3 className=\"text-base font-semibold text-text-primary mb-4 flex items-center gap-2\">\n <Terminal className=\"size-5 text-accent-purple\" />\n {tr('gettingStarted.cliQuickRef', 'CLI Quick Reference')}\n </h3>\n <ShowMore collapsedHeight={172} label={tr('gettingStarted.showAllCommands', 'Show all commands')}>\n <MotionList stagger={0.04} className=\"space-y-2\">\n {[\n {\n cmd: 'vibe start',\n desc: tr(\n 'gettingStarted.cmdVibeStart',\n 'First run: auto-detects deps, picks a port (default 3005), establishes a Cloudflare tunnel, generates an agentApiKey, then waits for the platform'\n ),\n },\n {\n cmd: 'vibe start --profile <name>',\n desc: tr(\n 'gettingStarted.cmdVibeStartProfile',\n 'Run a named profile (e.g. alpha, default) for multiple agent instances'\n ),\n },\n {\n cmd: 'vibe setup',\n desc: tr(\n 'gettingStarted.cmdVibeSetup',\n 'Install missing dependencies (tmux, ttyd, cloudflared)'\n ),\n },\n {\n cmd: 'vibe health',\n desc: tr('gettingStarted.cmdVibeHealth', 'Run an HTTP health check on the agent'),\n },\n {\n cmd: 'vibe status',\n desc: tr('gettingStarted.cmdVibeStatus', 'Show all running agent instances'),\n },\n {\n cmd: 'vibe autostart install',\n desc: tr(\n 'gettingStarted.cmdVibeAutostartInstall',\n 'Run the agent as a background service (daemonize)'\n ),\n },\n {\n cmd: 'vibe autostart uninstall',\n desc: tr(\n 'gettingStarted.cmdVibeAutostartUninstall',\n 'Remove the background service'\n ),\n },\n {\n cmd: 'vibecontrols agents list --active',\n desc: tr(\n 'gettingStarted.cmdAgentsListActive',\n 'Platform CLI — see the connected agent on the backend'\n ),\n },\n ].map((item) => (\n <MotionItem\n key={item.cmd}\n className=\"flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-3 px-3 py-2 rounded-button hover:bg-bg-sunken transition-colors\"\n >\n <code className=\"text-xs font-mono text-text-primary sm:w-72 flex-shrink-0\">\n $ {item.cmd}\n </code>\n <span className=\"text-xs text-text-muted\">{item.desc}</span>\n </MotionItem>\n ))}\n </MotionList>\n </ShowMore>\n <div className=\"mt-4 pt-4 border-t border-border-seam flex flex-wrap items-center gap-3\">\n <a\n href={AGENT_NPM_URL}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-2 px-3 py-1.5 text-xs border border-border-default text-text-secondary rounded-button hover:bg-bg-sunken hover:border-border-strong transition-colors\"\n >\n {tr('gettingStarted.agentNpmPackage', 'Agent npm package')}{' '}\n <ExternalLink className=\"size-3\" />\n </a>\n <span className=\"text-xs text-text-muted\">\n {tr('gettingStarted.agentNpmLatest', '@vibecontrols/agent (latest)')}\n </span>\n </div>\n </div>\n </Card>\n )}\n </MotionPage>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"GettingStartedPage.js","names":[],"sources":["../../src/pages/GettingStartedPage.tsx"],"sourcesContent":["import { useCallback, useMemo, useState } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { Terminal, ExternalLink, Download, Info } from 'lucide-react';\nimport { PageHeader, Card, InstallTabs } from '@/components/shared';\nimport { EmphasisPanel, ShowMore } from '@burdenoff/fe-libs/ui';\nimport { MotionPage, MotionList, MotionItem } from '@burdenoff/fe-libs/shared/motion';\nimport { Tabs, type TabItem } from '@burdenoff/fe-libs/chrome';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\nconst AGENT_NPM_URL = 'https://www.npmjs.com/package/@vibecontrols/agent';\nconst INSTALL_DOCS_URL = 'https://docs.vibecontrols.com/users/installing-the-agent';\n\n/**\n * Getting Started page — a tabbed guide to installing and running the\n * VibeControls Agent. Two top-level tabs:\n *\n * • Install — shows the global bun / npm install commands via the shared\n * `InstallTabs` component, plus the real connect-and-run flow.\n * • CLI Reference — a compact reference of the agent's `vibe` commands.\n *\n * Bun (or Node >= 18 for npm) is the only machine prerequisite. On first run\n * `vibe start` sets up a Cloudflare tunnel, generates an agentApiKey, and\n * waits for the platform to push OAuth credentials once the agent is\n * connected here.\n *\n * Official docs: https://docs.vibecontrols.com/users/installing-the-agent\n */\nexport function GettingStartedPage() {\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n const [params, setParams] = useSearchParams();\n const tabs: TabItem[] = useMemo(\n () => [\n { id: 'install', label: tr('gettingStarted.installTab', 'Install') },\n { id: 'cli', label: tr('gettingStarted.cliTab', 'CLI Reference') },\n ],\n [tr]\n );\n const activeId = params.get('tab') ?? tabs[0].id;\n const handleTabChange = (id: string) => {\n const next = new URLSearchParams(params);\n if (id === tabs[0].id) next.delete('tab');\n else next.set('tab', id);\n setParams(next, { replace: true });\n };\n\n const [pinnedVersion, setPinnedVersion] = useState('');\n\n return (\n <MotionPage className=\"space-y-8 px-6 lg:px-8 py-6 bg-bg-canvas min-h-screen\">\n <PageHeader\n title={tr('gettingStarted.title', 'Getting Started')}\n description={tr(\n 'gettingStarted.description',\n 'Install and configure the VibeControls Agent CLI'\n )}\n />\n\n <div className=\"border-b border-border-subtle\">\n <Tabs\n items={tabs}\n activeTabId={activeId}\n onTabChange={handleTabChange}\n variant=\"underline\"\n />\n </div>\n\n {activeId === 'install' && (\n <div className=\"space-y-6\">\n {/* Hero — the single emphasised zone on this page */}\n <EmphasisPanel className=\"sm:p-8\">\n <div className=\"flex items-start gap-4\">\n <div className=\"flex-shrink-0 size-12 rounded-xl bg-[var(--color-accent-soft)] flex items-center justify-center\">\n <Download className=\"size-6 text-accent-purple\" />\n </div>\n <div className=\"flex-1\">\n <h2 className=\"text-lg sm:text-xl font-semibold text-text-primary mb-1\">\n {tr('gettingStarted.installAgent', 'Install the Agent')}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'gettingStarted.installAgentDesc',\n 'Install the agent globally with bun or npm on the machine you want to manage, then run vibe start. Bun (or Node >= 18 for npm) is the only prerequisite.'\n )}\n </p>\n <a\n href={INSTALL_DOCS_URL}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mt-3 inline-flex items-center gap-1.5 text-sm text-text-link hover:text-text-linkHover hover:underline\"\n >\n {tr('gettingStarted.viewInstallDocs', 'View the full install docs')}\n <ExternalLink className=\"size-3.5\" />\n </a>\n </div>\n </div>\n </EmphasisPanel>\n\n {/* Install tabs */}\n <Card padding=\"none\">\n <div className=\"p-5 sm:p-6\">\n <InstallTabs pinnedAgentVersion={pinnedVersion || undefined} />\n\n <div className=\"mt-6 pt-4 border-t border-border-subtle\">\n <label\n htmlFor=\"pinned-version\"\n className=\"text-xs font-medium text-text-secondary flex items-center gap-1.5 mb-1.5\"\n >\n <Info className=\"size-3.5\" />{' '}\n {tr('gettingStarted.pinVersion', 'Pin a specific agent version (optional)')}\n </label>\n <input\n aria-label=\"pinned-version\"\n id=\"pinned-version\"\n type=\"text\"\n placeholder={tr(\n 'gettingStarted.pinVersionPlaceholder',\n 'e.g. 2026.408.1 (leave blank for latest)'\n )}\n value={pinnedVersion}\n onChange={(e) => setPinnedVersion(e.target.value)}\n className=\"w-full max-w-xs px-3 py-2 rounded-input border border-border-default bg-bg-elevated text-sm text-text-primary focus-visible:outline-none focus-visible:border-border-strong focus-visible:shadow-[var(--shadow-focus)]\"\n />\n </div>\n </div>\n </Card>\n\n {/* Next steps */}\n <Card padding=\"none\">\n <div className=\"p-5 sm:p-6\">\n <h3 className=\"text-base font-semibold text-text-primary mb-3\">\n {tr('gettingStarted.nextSteps', 'Next steps')}\n </h3>\n <ol className=\"list-decimal list-inside space-y-2 text-sm text-text-secondary\">\n <li>\n {tr('gettingStarted.nextStep1Prefix', 'Start the agent:')}{' '}\n <code className=\"font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded\">\n vibe start\n </code>{' '}\n {tr(\n 'gettingStarted.nextStep1Suffix',\n '— on first run it establishes a Cloudflare tunnel, generates an agentApiKey, and waits in pre-config mode for the platform.'\n )}\n </li>\n <li>\n {tr('gettingStarted.nextStep2Prefix', 'In this UI, go to')}{' '}\n <strong>\n {tr('gettingStarted.targetsAndAgents', 'Targets & Agents')} →{' '}\n {tr('gettingStarted.addAgent', 'Add Agent')}\n </strong>\n {tr(\n 'gettingStarted.nextStep2Suffix',\n ', create or pick a target, and paste the tunnel URL and agentApiKey that vibe start printed. The platform then pushes OAuth credentials automatically and the agent activates.'\n )}\n </li>\n <li>\n {tr('gettingStarted.nextStep3Prefix', 'Run it as a background service:')}{' '}\n <code className=\"font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded\">\n vibe autostart install\n </code>{' '}\n {tr('gettingStarted.nextStep3Suffix', '(remove later with')}{' '}\n <code className=\"font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded\">\n vibe autostart uninstall\n </code>\n {tr('gettingStarted.nextStep3End', ').')}\n </li>\n <li>\n {tr('gettingStarted.nextStep4Prefix', 'Verify it is running with')}{' '}\n <code className=\"font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded\">\n vibe health\n </code>{' '}\n {tr('gettingStarted.nextStep4And', 'and')}{' '}\n <code className=\"font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded\">\n vibe status\n </code>\n .\n </li>\n </ol>\n <a\n href={INSTALL_DOCS_URL}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mt-4 inline-flex items-center gap-1.5 text-sm text-text-link hover:text-text-linkHover hover:underline\"\n >\n {tr('gettingStarted.viewInstallDocs', 'View the full install docs')}\n <ExternalLink className=\"size-3.5\" />\n </a>\n </div>\n </Card>\n </div>\n )}\n\n {activeId === 'cli' && (\n <Card padding=\"none\">\n <div className=\"p-5 sm:p-6\">\n <h3 className=\"text-base font-semibold text-text-primary mb-4 flex items-center gap-2\">\n <Terminal className=\"size-5 text-accent-purple\" />\n {tr('gettingStarted.cliQuickRef', 'CLI Quick Reference')}\n </h3>\n <ShowMore\n collapsedHeight={172}\n label={tr('gettingStarted.showAllCommands', 'Show all commands')}\n >\n <MotionList stagger={0.04} className=\"space-y-2\">\n {[\n {\n cmd: 'vibe start',\n desc: tr(\n 'gettingStarted.cmdVibeStart',\n 'First run: auto-detects deps, picks a port (default 3005), establishes a Cloudflare tunnel, generates an agentApiKey, then waits for the platform'\n ),\n },\n {\n cmd: 'vibe start --profile <name>',\n desc: tr(\n 'gettingStarted.cmdVibeStartProfile',\n 'Run a named profile (e.g. alpha, default) for multiple agent instances'\n ),\n },\n {\n cmd: 'vibe setup',\n desc: tr(\n 'gettingStarted.cmdVibeSetup',\n 'Install missing dependencies (tmux, ttyd, cloudflared)'\n ),\n },\n {\n cmd: 'vibe health',\n desc: tr(\n 'gettingStarted.cmdVibeHealth',\n 'Run an HTTP health check on the agent'\n ),\n },\n {\n cmd: 'vibe status',\n desc: tr('gettingStarted.cmdVibeStatus', 'Show all running agent instances'),\n },\n {\n cmd: 'vibe autostart install',\n desc: tr(\n 'gettingStarted.cmdVibeAutostartInstall',\n 'Run the agent as a background service (daemonize)'\n ),\n },\n {\n cmd: 'vibe autostart uninstall',\n desc: tr(\n 'gettingStarted.cmdVibeAutostartUninstall',\n 'Remove the background service'\n ),\n },\n {\n cmd: 'vibecontrols agents list --active',\n desc: tr(\n 'gettingStarted.cmdAgentsListActive',\n 'Platform CLI — see the connected agent on the backend'\n ),\n },\n ].map((item) => (\n <MotionItem\n key={item.cmd}\n className=\"flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-3 px-3 py-2 rounded-button hover:bg-bg-sunken transition-colors\"\n >\n <code className=\"text-xs font-mono text-text-primary sm:w-72 flex-shrink-0\">\n $ {item.cmd}\n </code>\n <span className=\"text-xs text-text-muted\">{item.desc}</span>\n </MotionItem>\n ))}\n </MotionList>\n </ShowMore>\n <div className=\"mt-4 pt-4 border-t border-border-seam flex flex-wrap items-center gap-3\">\n <a\n href={AGENT_NPM_URL}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-2 px-3 py-1.5 text-xs border border-border-default text-text-secondary rounded-button hover:bg-bg-sunken hover:border-border-strong transition-colors\"\n >\n {tr('gettingStarted.agentNpmPackage', 'Agent npm package')}{' '}\n <ExternalLink className=\"size-3\" />\n </a>\n <span className=\"text-xs text-text-muted\">\n {tr('gettingStarted.agentNpmLatest', '@vibecontrols/agent (latest)')}\n </span>\n </div>\n </div>\n </Card>\n )}\n </MotionPage>\n );\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-vibecontrols",
3
- "version": "2026.626.2",
3
+ "version": "2026.709.1",
4
4
  "description": "VibeControls microfrontend for Burdenoff products",
5
5
  "type": "module",
6
6
  "files": [