@burdenoff/microfe-vibecontrols 2026.623.3 → 2026.623.5

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.
Files changed (29) hide show
  1. package/dist/VibeControlsRoutes.js +161 -149
  2. package/dist/VibeControlsRoutes.js.map +1 -1
  3. package/dist/components/agents/AgentCard.js +1 -1
  4. package/dist/components/agents/AgentCard.js.map +1 -1
  5. package/dist/components/agents/AgentForm.js +2 -2
  6. package/dist/components/agents/AgentForm.js.map +1 -1
  7. package/dist/components/catalog/CatalogCard.js +9 -12
  8. package/dist/components/catalog/CatalogCard.js.map +1 -1
  9. package/dist/components/idp-components/ComponentCard.js +9 -12
  10. package/dist/components/idp-components/ComponentCard.js.map +1 -1
  11. package/dist/components/notes/NoteCard.js +9 -12
  12. package/dist/components/notes/NoteCard.js.map +1 -1
  13. package/dist/components/sessions/SessionCard.js +9 -12
  14. package/dist/components/sessions/SessionCard.js.map +1 -1
  15. package/dist/components/shared/AgentSetupBanner.js +2 -2
  16. package/dist/components/shared/AgentSetupBanner.js.map +1 -1
  17. package/dist/components/shared/Card.js +1 -1
  18. package/dist/components/shared/Card.js.map +1 -1
  19. package/dist/components/shared/InstallTabs.js +17 -56
  20. package/dist/components/shared/InstallTabs.js.map +1 -1
  21. package/dist/components/shared/StatCard.js +1 -1
  22. package/dist/components/shared/StatCard.js.map +1 -1
  23. package/dist/components/tunnels/TunnelCard.js +1 -1
  24. package/dist/components/tunnels/TunnelCard.js.map +1 -1
  25. package/dist/pages/GettingStartedPage.js +130 -114
  26. package/dist/pages/GettingStartedPage.js.map +1 -1
  27. package/dist/translations/en.js +27 -52
  28. package/dist/translations/en.js.map +1 -1
  29. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"InstallTabs.js","names":[],"sources":["../../../src/components/shared/InstallTabs.tsx"],"sourcesContent":["import { useMemo, useState, useCallback } from 'react';\nimport { Copy, Check, Terminal } from 'lucide-react';\nimport { Tabs, type TabItem } from '@burdenoff/fe-libs/chrome';\nimport { useTr } from '../../shared/hooks/useTr';\n\ntype InstallMethod = 'curl' | 'npm';\ntype InstallOs = 'linux' | 'macos' | 'windows';\n\n/**\n * Resolves the current host for the curl install URL so the instructions\n * always match the environment the user is looking at (local / alpha / prod).\n * The `VIBECONTROLS_HOST` global can be set by the shell if it needs to\n * override (e.g. for previews), otherwise we read from `window.location`.\n */\nfunction resolveHost(): string {\n if (typeof window === 'undefined') return 'vibecontrols.local.burdenoff.com';\n const injected = (window as unknown as { __VIBECONTROLS_HOST__?: string }).__VIBECONTROLS_HOST__;\n return injected ?? window.location.host;\n}\n\nfunction CopyableCommand({ command }: { command: string }) {\n const tr = useTr();\n const [copied, setCopied] = useState(false);\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(command);\n } catch {\n const el = document.createElement('textarea');\n el.value = command;\n document.body.appendChild(el);\n el.select();\n document.execCommand('copy');\n document.body.removeChild(el);\n }\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }, [command]);\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={handleCopy}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') handleCopy();\n }}\n className=\"flex items-center gap-2 px-3 py-2.5 bg-bg-sunken border border-border-default rounded-md cursor-pointer hover:bg-bg-elevated transition-colors group\"\n title={tr('vibecontrols.shared.installTabs.clickToCopy', 'Click to copy')}\n >\n <Terminal className=\"size-4 text-text-muted flex-shrink-0\" />\n <code className=\"text-sm font-mono text-text-primary flex-1 break-all\">{command}</code>\n {copied ? (\n <Check className=\"size-4 text-status-success-text flex-shrink-0\" />\n ) : (\n <Copy className=\"size-4 text-text-muted group-hover:text-text-secondary flex-shrink-0\" />\n )}\n </div>\n );\n}\n\nexport interface InstallTabsProps {\n /** Optional pinned agent version to embed in instructions */\n pinnedAgentVersion?: string;\n /** Optional compact layout when rendered inside a narrow callout card */\n compact?: boolean;\n}\n\n/**\n * Unified install instructions widget used by the Getting Started page and\n * the Agents \"Get started\" callout. Two top tabs — Curl (preferred) and\n * NPM — each with Linux/macOS/Windows sub-tabs, so the user always sees a\n * single command they can copy.\n *\n * The curl install script is served by the app shell at `/install` (bash)\n * and `/install.ps1` (PowerShell). The only prerequisite is bun, which the\n * script installs automatically at a pinned version.\n */\nexport function InstallTabs({ pinnedAgentVersion, compact = false }: InstallTabsProps) {\n const tr = useTr();\n const host = resolveHost();\n const [method, setMethod] = useState<InstallMethod>('curl');\n const [os, setOs] = useState<InstallOs>('linux');\n\n const methodTabs: TabItem[] = useMemo(\n () => [\n {\n id: 'curl',\n label: tr('vibecontrols.shared.installTabs.curlRecommended', 'Curl (Recommended)'),\n },\n { id: 'npm', label: tr('vibecontrols.shared.installTabs.npm', 'NPM') },\n ],\n [tr]\n );\n\n const osTabs: TabItem[] = useMemo(\n () => [\n { id: 'linux', label: tr('vibecontrols.shared.installTabs.linux', 'Linux') },\n { id: 'macos', label: tr('vibecontrols.shared.installTabs.macos', 'macOS') },\n { id: 'windows', label: tr('vibecontrols.shared.installTabs.windows', 'Windows') },\n ],\n [tr]\n );\n\n // Resolve the actual command string per (method, os).\n const command = useMemo(() => {\n const agentSuffix = pinnedAgentVersion ? `@${pinnedAgentVersion}` : '@latest';\n if (method === 'curl') {\n if (os === 'windows') {\n return `powershell -c \"irm ${host}/install.ps1 | iex\"`;\n }\n // The trailing `&& hash -r` runs in the user's shell (right of the pipe),\n // flushing any stale cached `vibe` path so the freshly-installed binary\n // resolves immediately — no manual `hash -r` / new terminal. The install\n // script also rebinds a stale path on disk, so this is belt-and-braces\n // (and a harmless no-op when nothing is cached). fish users: drop it.\n return `curl -fsSL https://${host}/install | bash && hash -r 2>/dev/null`;\n }\n // npm\n return `npm install -g @vibecontrols/agent${agentSuffix}`;\n }, [method, os, host, pinnedAgentVersion]);\n\n const scriptUrl =\n method === 'curl'\n ? os === 'windows'\n ? `https://${host}/install.ps1`\n : `https://${host}/install`\n : null;\n\n return (\n <div className={compact ? 'space-y-3' : 'space-y-4'}>\n <Tabs\n items={methodTabs}\n activeTabId={method}\n onTabChange={(id) => setMethod(id as InstallMethod)}\n variant=\"underline\"\n />\n\n <Tabs\n items={osTabs}\n activeTabId={os}\n onTabChange={(id) => setOs(id as InstallOs)}\n variant=\"pills\"\n size=\"sm\"\n />\n\n <CopyableCommand command={command} />\n\n {method === 'curl' && scriptUrl && (\n <p className=\"text-xs text-text-muted\">\n {tr(\n 'vibecontrols.shared.installTabs.curlDescription',\n 'The script installs bun (pinned, v1.3.10) then installs @vibecontrols/agent and core plugins. Only bun is required on your machine — no other prerequisites. The trailing “&& hash -r” refreshes your shell so “vibe” works immediately (using fish? drop it — fish auto-rehashes).'\n )}{' '}\n <a\n href={scriptUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"text-text-link hover:text-text-linkHover hover:underline\"\n >\n {tr('vibecontrols.shared.installTabs.viewInstallScript', 'View the install script')}\n </a>\n .\n </p>\n )}\n {method === 'npm' && (\n <p className=\"text-xs text-text-muted\">\n {tr(\n 'vibecontrols.shared.installTabs.npmDescription',\n 'Requires Node.js >= 18. You can also pass @<version> to pin a specific release.'\n )}\n </p>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;AAcA,SAAS,IAAsB;AAG7B,QAFI,OAAO,SAAW,MAAoB,qCACxB,OAAyD,yBACxD,OAAO,SAAS;;AAGrC,SAAS,EAAgB,EAAE,cAAgC;CACzD,IAAM,IAAK,GAAO,EACZ,CAAC,GAAQ,KAAa,EAAS,GAAM,EACrC,IAAa,EAAY,YAAY;AACzC,MAAI;AACF,SAAM,UAAU,UAAU,UAAU,EAAQ;UACtC;GACN,IAAM,IAAK,SAAS,cAAc,WAAW;AAK7C,GAJA,EAAG,QAAQ,GACX,SAAS,KAAK,YAAY,EAAG,EAC7B,EAAG,QAAQ,EACX,SAAS,YAAY,OAAO,EAC5B,SAAS,KAAK,YAAY,EAAG;;AAG/B,EADA,EAAU,GAAK,EACf,iBAAiB,EAAU,GAAM,EAAE,IAAK;IACvC,CAAC,EAAQ,CAAC;AAEb,QACE,kBAAC,OAAD;EACE,MAAK;EACL,UAAU;EACV,SAAS;EACT,YAAY,MAAM;AAChB,IAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,QAAK,GAAY;;EAEtD,WAAU;EACV,OAAO,EAAG,+CAA+C,gBAAgB;YAR3E;GAUE,kBAAC,GAAD,EAAU,WAAU,wCAAyC,CAAA;GAC7D,kBAAC,QAAD;IAAM,WAAU;cAAwD;IAAe,CAAA;GACtF,IACC,kBAAC,GAAD,EAAO,WAAU,iDAAkD,CAAA,GAEnE,kBAAC,GAAD,EAAM,WAAU,wEAAyE,CAAA;GAEvF;;;AAqBV,SAAgB,EAAY,EAAE,uBAAoB,aAAU,MAA2B;CACrF,IAAM,IAAK,GAAO,EACZ,IAAO,GAAa,EACpB,CAAC,GAAQ,KAAa,EAAwB,OAAO,EACrD,CAAC,GAAI,KAAS,EAAoB,QAAQ,EAE1C,IAAwB,QACtB,CACJ;EACE,IAAI;EACJ,OAAO,EAAG,mDAAmD,qBAAqB;EACnF,EACD;EAAE,IAAI;EAAO,OAAO,EAAG,uCAAuC,MAAM;EAAE,CACvE,EACD,CAAC,EAAG,CACL,EAEK,IAAoB,QAClB;EACJ;GAAE,IAAI;GAAS,OAAO,EAAG,yCAAyC,QAAQ;GAAE;EAC5E;GAAE,IAAI;GAAS,OAAO,EAAG,yCAAyC,QAAQ;GAAE;EAC5E;GAAE,IAAI;GAAW,OAAO,EAAG,2CAA2C,UAAU;GAAE;EACnF,EACD,CAAC,EAAG,CACL,EAGK,IAAU,QAAc;EAC5B,IAAM,IAAc,IAAqB,IAAI,MAAuB;AAapE,SAZI,MAAW,SACT,MAAO,YACF,sBAAsB,EAAK,uBAO7B,sBAAsB,EAAK,0CAG7B,qCAAqC;IAC3C;EAAC;EAAQ;EAAI;EAAM;EAAmB,CAAC,EAEpC,IACJ,MAAW,SACP,MAAO,YACL,WAAW,EAAK,gBAChB,WAAW,EAAK,YAClB;AAEN,QACE,kBAAC,OAAD;EAAK,WAAW,IAAU,cAAc;YAAxC;GACE,kBAAC,GAAD;IACE,OAAO;IACP,aAAa;IACb,cAAc,MAAO,EAAU,EAAoB;IACnD,SAAQ;IACR,CAAA;GAEF,kBAAC,GAAD;IACE,OAAO;IACP,aAAa;IACb,cAAc,MAAO,EAAM,EAAgB;IAC3C,SAAQ;IACR,MAAK;IACL,CAAA;GAEF,kBAAC,GAAD,EAA0B,YAAW,CAAA;GAEpC,MAAW,UAAU,KACpB,kBAAC,KAAD;IAAG,WAAU;cAAb;KACG,EACC,mDACA,sRACD;KAAE;KACH,kBAAC,KAAD;MACE,MAAM;MACN,QAAO;MACP,KAAI;MACJ,WAAU;gBAET,EAAG,qDAAqD,0BAA0B;MACjF,CAAA;;KAEF;;GAEL,MAAW,SACV,kBAAC,KAAD;IAAG,WAAU;cACV,EACC,kDACA,kFACD;IACC,CAAA;GAEF"}
1
+ {"version":3,"file":"InstallTabs.js","names":[],"sources":["../../../src/components/shared/InstallTabs.tsx"],"sourcesContent":["import { useMemo, useState, useCallback } from 'react';\nimport { Copy, Check, Terminal } from 'lucide-react';\nimport { Tabs, type TabItem } from '@burdenoff/fe-libs/chrome';\nimport { useTr } from '../../shared/hooks/useTr';\n\ntype InstallMethod = 'bun' | 'npm';\n\nfunction CopyableCommand({ command }: { command: string }) {\n const tr = useTr();\n const [copied, setCopied] = useState(false);\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(command);\n } catch {\n const el = document.createElement('textarea');\n el.value = command;\n document.body.appendChild(el);\n el.select();\n document.execCommand('copy');\n document.body.removeChild(el);\n }\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }, [command]);\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={handleCopy}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') handleCopy();\n }}\n className=\"flex items-center gap-2 px-3 py-2.5 bg-bg-sunken border border-border-default rounded-md cursor-pointer hover:bg-bg-elevated transition-colors group\"\n title={tr('vibecontrols.shared.installTabs.clickToCopy', 'Click to copy')}\n >\n <Terminal className=\"size-4 text-text-muted flex-shrink-0\" />\n <code className=\"text-sm font-mono text-text-primary flex-1 break-all\">{command}</code>\n {copied ? (\n <Check className=\"size-4 text-status-success-text flex-shrink-0\" />\n ) : (\n <Copy className=\"size-4 text-text-muted group-hover:text-text-secondary flex-shrink-0\" />\n )}\n </div>\n );\n}\n\nexport interface InstallTabsProps {\n /** Optional pinned agent version to embed in instructions */\n pinnedAgentVersion?: string;\n /** Optional compact layout when rendered inside a narrow callout card */\n compact?: boolean;\n}\n\n/**\n * Unified install instructions widget used by the Getting Started page and\n * the Agents \"Get started\" callout. Two tabs — Bun (recommended, the platform\n * default) and NPM — each showing a single global install command the user\n * can copy. Bun (or Node >= 18 for npm) is the only prerequisite; an\n * optional `@<version>` suffix pins a specific release.\n *\n * Official docs: https://docs.vibecontrols.com/users/installing-the-agent\n */\nexport function InstallTabs({ pinnedAgentVersion, compact = false }: InstallTabsProps) {\n const tr = useTr();\n const [method, setMethod] = useState<InstallMethod>('bun');\n\n const methodTabs: TabItem[] = useMemo(\n () => [\n {\n id: 'bun',\n label: tr('vibecontrols.shared.installTabs.bunRecommended', 'Bun (Recommended)'),\n },\n { id: 'npm', label: tr('vibecontrols.shared.installTabs.npm', 'NPM') },\n ],\n [tr]\n );\n\n // Resolve the global install command for the selected package manager.\n // The `@<version>` suffix pins a release; default is `@latest`.\n const command = useMemo(() => {\n const ver = pinnedAgentVersion ? `@${pinnedAgentVersion}` : '@latest';\n if (method === 'bun') {\n return `bun install -g @vibecontrols/agent${ver}`;\n }\n return `npm install -g @vibecontrols/agent${ver}`;\n }, [method, pinnedAgentVersion]);\n\n return (\n <div className={compact ? 'space-y-3' : 'space-y-4'}>\n <Tabs\n items={methodTabs}\n activeTabId={method}\n onTabChange={(id) => setMethod(id as InstallMethod)}\n variant=\"underline\"\n />\n\n <CopyableCommand command={command} />\n\n {method === 'bun' && (\n <p className=\"text-xs text-text-muted\">\n {tr(\n 'vibecontrols.shared.installTabs.bunDescription',\n 'Bun is the platform default and the only prerequisite. You can pin a specific release with @<version> (defaults to the latest).'\n )}\n </p>\n )}\n {method === 'npm' && (\n <p className=\"text-xs text-text-muted\">\n {tr(\n 'vibecontrols.shared.installTabs.npmDescription',\n 'Requires Node.js >= 18. You can pin a specific release with @<version> (defaults to the latest).'\n )}\n </p>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;AAOA,SAAS,EAAgB,EAAE,cAAgC;CACzD,IAAM,IAAK,GAAO,EACZ,CAAC,GAAQ,KAAa,EAAS,GAAM,EACrC,IAAa,EAAY,YAAY;AACzC,MAAI;AACF,SAAM,UAAU,UAAU,UAAU,EAAQ;UACtC;GACN,IAAM,IAAK,SAAS,cAAc,WAAW;AAK7C,GAJA,EAAG,QAAQ,GACX,SAAS,KAAK,YAAY,EAAG,EAC7B,EAAG,QAAQ,EACX,SAAS,YAAY,OAAO,EAC5B,SAAS,KAAK,YAAY,EAAG;;AAG/B,EADA,EAAU,GAAK,EACf,iBAAiB,EAAU,GAAM,EAAE,IAAK;IACvC,CAAC,EAAQ,CAAC;AAEb,QACE,kBAAC,OAAD;EACE,MAAK;EACL,UAAU;EACV,SAAS;EACT,YAAY,MAAM;AAChB,IAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,QAAK,GAAY;;EAEtD,WAAU;EACV,OAAO,EAAG,+CAA+C,gBAAgB;YAR3E;GAUE,kBAAC,GAAD,EAAU,WAAU,wCAAyC,CAAA;GAC7D,kBAAC,QAAD;IAAM,WAAU;cAAwD;IAAe,CAAA;GACtF,IACC,kBAAC,GAAD,EAAO,WAAU,iDAAkD,CAAA,GAEnE,kBAAC,GAAD,EAAM,WAAU,wEAAyE,CAAA;GAEvF;;;AAoBV,SAAgB,EAAY,EAAE,uBAAoB,aAAU,MAA2B;CACrF,IAAM,IAAK,GAAO,EACZ,CAAC,GAAQ,KAAa,EAAwB,MAAM,EAEpD,IAAwB,QACtB,CACJ;EACE,IAAI;EACJ,OAAO,EAAG,kDAAkD,oBAAoB;EACjF,EACD;EAAE,IAAI;EAAO,OAAO,EAAG,uCAAuC,MAAM;EAAE,CACvE,EACD,CAAC,EAAG,CACL,EAIK,IAAU,QAAc;EAC5B,IAAM,IAAM,IAAqB,IAAI,MAAuB;AAI5D,SAHI,MAAW,QACN,qCAAqC,MAEvC,qCAAqC;IAC3C,CAAC,GAAQ,EAAmB,CAAC;AAEhC,QACE,kBAAC,OAAD;EAAK,WAAW,IAAU,cAAc;YAAxC;GACE,kBAAC,GAAD;IACE,OAAO;IACP,aAAa;IACb,cAAc,MAAO,EAAU,EAAoB;IACnD,SAAQ;IACR,CAAA;GAEF,kBAAC,GAAD,EAA0B,YAAW,CAAA;GAEpC,MAAW,SACV,kBAAC,KAAD;IAAG,WAAU;cACV,EACC,kDACA,kIACD;IACC,CAAA;GAEL,MAAW,SACV,kBAAC,KAAD;IAAG,WAAU;cACV,EACC,kDACA,mGACD;IACC,CAAA;GAEF"}
@@ -10,7 +10,7 @@ function o({ title: o, value: s, subtitle: c, icon: l, trend: u, variant: d = "d
10
10
  success: "bg-status-success-bg-subtle",
11
11
  warning: "bg-status-warning-bg-subtle",
12
12
  error: "bg-status-error-bg-subtle"
13
- }[d]} ${f ? "hover:border-border-strong hover:shadow-elevation-2 hover:-translate-y-0.5 transition-all duration-200 ease-[var(--motion-easing-out)] cursor-pointer w-full text-left" : ""}`,
13
+ }[d]} ${f ? "hover:border-border-strong hover:shadow-elevation-2 transition-all duration-200 ease-[var(--motion-easing-out)] cursor-pointer w-full text-left" : ""}`,
14
14
  children: /* @__PURE__ */ i("div", {
15
15
  className: "flex flex-col gap-2.5",
16
16
  children: [
@@ -1 +1 @@
1
- {"version":3,"file":"StatCard.js","names":[],"sources":["../../../src/components/shared/StatCard.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { TrendingUp, TrendingDown, Minus } from 'lucide-react';\nimport { AnimatedCounter } from '@burdenoff/fe-libs/shared/motion';\n\ninterface StatCardProps {\n title: string;\n value: string | number;\n subtitle?: string;\n icon?: ReactNode;\n trend?: {\n value: number;\n label?: string;\n };\n variant?: 'default' | 'success' | 'warning' | 'error';\n onClick?: () => void;\n}\n\nexport function StatCard({\n title,\n value,\n subtitle,\n icon,\n trend,\n variant = 'default',\n onClick,\n}: StatCardProps) {\n const variantStyles = {\n default: 'bg-bg-surface',\n success: 'bg-status-success-bg-subtle',\n warning: 'bg-status-warning-bg-subtle',\n error: 'bg-status-error-bg-subtle',\n };\n\n // Subtle tint + same-hue saturated text (passes AA in both themes); the old\n // solid `bg-status-X-bg` + `text-status-X-text` was same-hue low-contrast.\n // The neutral/default tile uses the brand accent wash so metric cards lead\n // with the theme accent rather than a flat grey.\n const iconVariantStyles = {\n default: 'bg-[var(--color-accent-soft)] text-text-primary',\n success: 'bg-status-success-bg-subtle text-status-success-text',\n warning: 'bg-status-warning-bg-subtle text-status-warning-text',\n error: 'bg-status-error-bg-subtle text-status-error-text',\n };\n\n const Component = onClick ? 'button' : 'div';\n\n return (\n <Component\n onClick={onClick}\n className={`p-5 rounded-card border border-border-subtle shadow-elevation-1 ${variantStyles[variant]} ${onClick ? 'hover:border-border-strong hover:shadow-elevation-2 hover:-translate-y-0.5 transition-all duration-200 ease-[var(--motion-easing-out)] cursor-pointer w-full text-left' : ''}`}\n >\n <div className=\"flex flex-col gap-2.5\">\n <div className=\"flex items-center justify-between\">\n <p className=\"text-sm font-medium text-text-secondary\">{title}</p>\n {icon && (\n <div\n className={`flex-shrink-0 size-9 rounded-lg flex items-center justify-center ${iconVariantStyles[variant]} [&>svg]:w-4 [&>svg]:h-4`}\n >\n {icon}\n </div>\n )}\n </div>\n <div className=\"text-2xl font-semibold text-text-primary tabular-nums\">\n {typeof value === 'number' ? <AnimatedCounter value={value} /> : value}\n </div>\n {subtitle && <p className=\"text-xs text-text-secondary\">{subtitle}</p>}\n {trend && (\n <div className=\"flex items-center gap-1\">\n {trend.value > 0 ? (\n <TrendingUp className=\"size-4 text-status-success-text\" />\n ) : trend.value < 0 ? (\n <TrendingDown className=\"size-4 text-status-error-text\" />\n ) : (\n <Minus className=\"size-4 text-text-secondary\" />\n )}\n <span\n className={`text-xs font-medium tabular-nums ${\n trend.value > 0\n ? 'text-status-success-text'\n : trend.value < 0\n ? 'text-status-error-text'\n : 'text-text-secondary'\n }`}\n >\n {trend.value > 0 ? '+' : ''}\n {trend.value}%\n </span>\n {trend.label && <span className=\"text-xs text-text-secondary\">{trend.label}</span>}\n </div>\n )}\n </div>\n </Component>\n );\n}\n"],"mappings":";;;;AAiBA,SAAgB,EAAS,EACvB,UACA,UACA,aACA,SACA,UACA,aAAU,WACV,cACgB;AAqBhB,QACE,kBAHgB,IAAU,WAAW,OAGrC;EACW;EACT,WAAW,mEAvBO;GACpB,SAAS;GACT,SAAS;GACT,SAAS;GACT,OAAO;GACR,CAkB+F,GAAS,GAAG,IAAU,2KAA2K;YAE7R,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBAA2C;MAAU,CAAA,EACjE,KACC,kBAAC,OAAD;MACE,WAAW,oEAnBG;OACxB,SAAS;OACT,SAAS;OACT,SAAS;OACT,OAAO;OACR,CAc4G,GAAS;gBAEzG;MACG,CAAA,CAEJ;;IACN,kBAAC,OAAD;KAAK,WAAU;eACZ,OAAO,KAAU,WAAW,kBAAC,GAAD,EAAwB,UAAS,CAAA,GAAG;KAC7D,CAAA;IACL,KAAY,kBAAC,KAAD;KAAG,WAAU;eAA+B;KAAa,CAAA;IACrE,KACC,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,EAAM,QAAQ,IACb,kBAAC,GAAD,EAAY,WAAU,mCAAoC,CAAA,GACxD,EAAM,QAAQ,IAChB,kBAAC,GAAD,EAAc,WAAU,iCAAkC,CAAA,GAE1D,kBAAC,GAAD,EAAO,WAAU,8BAA+B,CAAA;MAElD,kBAAC,QAAD;OACE,WAAW,oCACT,EAAM,QAAQ,IACV,6BACA,EAAM,QAAQ,IACZ,2BACA;iBANV;QASG,EAAM,QAAQ,IAAI,MAAM;QACxB,EAAM;QAAM;QACR;;MACN,EAAM,SAAS,kBAAC,QAAD;OAAM,WAAU;iBAA+B,EAAM;OAAa,CAAA;MAC9E;;IAEJ;;EACI,CAAA"}
1
+ {"version":3,"file":"StatCard.js","names":[],"sources":["../../../src/components/shared/StatCard.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { TrendingUp, TrendingDown, Minus } from 'lucide-react';\nimport { AnimatedCounter } from '@burdenoff/fe-libs/shared/motion';\n\ninterface StatCardProps {\n title: string;\n value: string | number;\n subtitle?: string;\n icon?: ReactNode;\n trend?: {\n value: number;\n label?: string;\n };\n variant?: 'default' | 'success' | 'warning' | 'error';\n onClick?: () => void;\n}\n\nexport function StatCard({\n title,\n value,\n subtitle,\n icon,\n trend,\n variant = 'default',\n onClick,\n}: StatCardProps) {\n const variantStyles = {\n default: 'bg-bg-surface',\n success: 'bg-status-success-bg-subtle',\n warning: 'bg-status-warning-bg-subtle',\n error: 'bg-status-error-bg-subtle',\n };\n\n // Subtle tint + same-hue saturated text (passes AA in both themes); the old\n // solid `bg-status-X-bg` + `text-status-X-text` was same-hue low-contrast.\n // The neutral/default tile uses the brand accent wash so metric cards lead\n // with the theme accent rather than a flat grey.\n const iconVariantStyles = {\n default: 'bg-[var(--color-accent-soft)] text-text-primary',\n success: 'bg-status-success-bg-subtle text-status-success-text',\n warning: 'bg-status-warning-bg-subtle text-status-warning-text',\n error: 'bg-status-error-bg-subtle text-status-error-text',\n };\n\n const Component = onClick ? 'button' : 'div';\n\n return (\n <Component\n onClick={onClick}\n className={`p-5 rounded-card border border-border-subtle shadow-elevation-1 ${variantStyles[variant]} ${onClick ? 'hover:border-border-strong hover:shadow-elevation-2 transition-all duration-200 ease-[var(--motion-easing-out)] cursor-pointer w-full text-left' : ''}`}\n >\n <div className=\"flex flex-col gap-2.5\">\n <div className=\"flex items-center justify-between\">\n <p className=\"text-sm font-medium text-text-secondary\">{title}</p>\n {icon && (\n <div\n className={`flex-shrink-0 size-9 rounded-lg flex items-center justify-center ${iconVariantStyles[variant]} [&>svg]:w-4 [&>svg]:h-4`}\n >\n {icon}\n </div>\n )}\n </div>\n <div className=\"text-2xl font-semibold text-text-primary tabular-nums\">\n {typeof value === 'number' ? <AnimatedCounter value={value} /> : value}\n </div>\n {subtitle && <p className=\"text-xs text-text-secondary\">{subtitle}</p>}\n {trend && (\n <div className=\"flex items-center gap-1\">\n {trend.value > 0 ? (\n <TrendingUp className=\"size-4 text-status-success-text\" />\n ) : trend.value < 0 ? (\n <TrendingDown className=\"size-4 text-status-error-text\" />\n ) : (\n <Minus className=\"size-4 text-text-secondary\" />\n )}\n <span\n className={`text-xs font-medium tabular-nums ${\n trend.value > 0\n ? 'text-status-success-text'\n : trend.value < 0\n ? 'text-status-error-text'\n : 'text-text-secondary'\n }`}\n >\n {trend.value > 0 ? '+' : ''}\n {trend.value}%\n </span>\n {trend.label && <span className=\"text-xs text-text-secondary\">{trend.label}</span>}\n </div>\n )}\n </div>\n </Component>\n );\n}\n"],"mappings":";;;;AAiBA,SAAgB,EAAS,EACvB,UACA,UACA,aACA,SACA,UACA,aAAU,WACV,cACgB;AAqBhB,QACE,kBAHgB,IAAU,WAAW,OAGrC;EACW;EACT,WAAW,mEAvBO;GACpB,SAAS;GACT,SAAS;GACT,SAAS;GACT,OAAO;GACR,CAkB+F,GAAS,GAAG,IAAU,oJAAoJ;YAEtQ,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBAA2C;MAAU,CAAA,EACjE,KACC,kBAAC,OAAD;MACE,WAAW,oEAnBG;OACxB,SAAS;OACT,SAAS;OACT,SAAS;OACT,OAAO;OACR,CAc4G,GAAS;gBAEzG;MACG,CAAA,CAEJ;;IACN,kBAAC,OAAD;KAAK,WAAU;eACZ,OAAO,KAAU,WAAW,kBAAC,GAAD,EAAwB,UAAS,CAAA,GAAG;KAC7D,CAAA;IACL,KAAY,kBAAC,KAAD;KAAG,WAAU;eAA+B;KAAa,CAAA;IACrE,KACC,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,EAAM,QAAQ,IACb,kBAAC,GAAD,EAAY,WAAU,mCAAoC,CAAA,GACxD,EAAM,QAAQ,IAChB,kBAAC,GAAD,EAAc,WAAU,iCAAkC,CAAA,GAE1D,kBAAC,GAAD,EAAO,WAAU,8BAA+B,CAAA;MAElD,kBAAC,QAAD;OACE,WAAW,oCACT,EAAM,QAAQ,IACV,6BACA,EAAM,QAAQ,IACZ,2BACA;iBANV;QASG,EAAM,QAAQ,IAAI,MAAM;QACxB,EAAM;QAAM;QACR;;MACN,EAAM,SAAS,kBAAC,QAAD;OAAM,WAAU;iBAA+B,EAAM;OAAa,CAAA;MAC9E;;IAEJ;;EACI,CAAA"}
@@ -18,7 +18,7 @@ function m({ tunnel: m, isPending: h = !1, onOpen: g, onStart: _, onStop: v, onD
18
18
  opacity: 1,
19
19
  y: 0
20
20
  },
21
- className: "rounded-card border border-border-subtle bg-bg-surface shadow-elevation-1 p-5 hover:border-border-strong hover:shadow-elevation-2 hover:-translate-y-0.5 transition-all duration-200 ease-[var(--motion-easing-out)]",
21
+ className: "rounded-card border border-border-subtle bg-bg-surface shadow-elevation-1 p-5 hover:border-border-strong hover:shadow-elevation-2 transition-all duration-200 ease-[var(--motion-easing-out)]",
22
22
  children: [/* @__PURE__ */ p("div", {
23
23
  className: "flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4",
24
24
  children: [/* @__PURE__ */ p("button", {
@@ -1 +1 @@
1
- {"version":3,"file":"TunnelCard.js","names":[],"sources":["../../../src/components/tunnels/TunnelCard.tsx"],"sourcesContent":["import { motion } from 'framer-motion';\nimport { Loader2, Play, Square, Trash2, ExternalLink } from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\n\nimport type { ListTunnelsQuery } from '@/generated/wspace-operations';\nimport { TunnelStatus, VibeEntityType } from '@/generated/wspace-types';\nimport { TunnelStatusBadge } from './TunnelStatusBadge';\nimport { ProviderBadge } from './ProviderBadge';\nimport { EntityVibeLinkControl } from '../shared/EntityVibeLinkControl';\n\ntype TunnelRow = NonNullable<ListTunnelsQuery['tunnels']>['items'][number];\n\ninterface TunnelCardProps {\n tunnel: TunnelRow;\n isPending?: boolean;\n onOpen: (id: string) => void;\n // Mutation callbacks are optional: the parent omits them when the actor\n // lacks the permission (tunnel:execute for start/stop, tunnel:delete), so\n // the corresponding control is hidden rather than 403-ing on click.\n onStart?: (id: string) => void;\n onStop?: (id: string) => void;\n onDelete?: (id: string, name: string) => void;\n}\n\nexport function TunnelCard({\n tunnel,\n isPending = false,\n onOpen,\n onStart,\n onStop,\n onDelete,\n}: TunnelCardProps) {\n const tr = useTr();\n const canStart =\n !isPending &&\n tunnel.status !== TunnelStatus.Active &&\n tunnel.status !== TunnelStatus.Provisioning;\n const canStop = !isPending && tunnel.status === TunnelStatus.Active;\n const hostname = tunnel.primaryDomain?.hostname;\n const publicUrl = hostname\n ? `${tunnel.protocol.toLowerCase() === 'tcp' ? 'tcp' : 'https'}://${hostname}`\n : null;\n\n return (\n <motion.div\n initial={{ opacity: 0, y: 4 }}\n animate={{ opacity: 1, y: 0 }}\n className=\"rounded-card border border-border-subtle bg-bg-surface shadow-elevation-1 p-5 hover:border-border-strong hover:shadow-elevation-2 hover:-translate-y-0.5 transition-all duration-200 ease-[var(--motion-easing-out)]\"\n >\n <div className=\"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4\">\n <button\n type=\"button\"\n onClick={() => onOpen(tunnel.id)}\n className=\"flex-1 text-left min-w-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus rounded-button\"\n >\n <div className=\"flex flex-wrap items-center gap-2 mb-1.5\">\n <h3 className=\"text-base font-semibold text-text-primary truncate tracking-tight\">\n {tunnel.name}\n </h3>\n <TunnelStatusBadge status={tunnel.status} />\n <ProviderBadge providerKey={tunnel.providerKey} />\n </div>\n {publicUrl ? (\n <p className=\"text-sm text-text-secondary truncate\">{publicUrl}</p>\n ) : (\n <p className=\"text-sm text-text-muted\">\n {tr('vibecontrols.tunnels.noDomain', 'No domain attached')}\n </p>\n )}\n <p className=\"text-xs font-mono text-text-muted mt-1 tabular-nums\">\n {tunnel.protocol}:{tunnel.localPort} on {tunnel.localHost}\n </p>\n </button>\n\n <div className=\"flex items-center gap-2 flex-shrink-0 flex-wrap\">\n {publicUrl && (\n <a\n href={publicUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center rounded-button border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken hover:border-border-strong transition-colors\"\n onClick={(e) => e.stopPropagation()}\n >\n <ExternalLink className=\"size-3.5 mr-1.5\" />\n {tr('vibecontrols.tunnels.open', 'Open')}\n </a>\n )}\n {isPending && (\n <span className=\"inline-flex items-center rounded-button border border-border-subtle bg-bg-sunken px-3 py-1.5 text-xs text-text-muted\">\n <Loader2 className=\"size-3.5 mr-1.5 animate-spin\" />\n {tunnel.status === 'ACTIVE'\n ? tr('vibecontrols.tunnels.stopping', 'Stopping…')\n : tr('vibecontrols.tunnels.starting', 'Starting…')}\n </span>\n )}\n {canStart && onStart && (\n <button\n type=\"button\"\n onClick={() => onStart(tunnel.id)}\n className=\"inline-flex items-center rounded-button bg-action-primary-bg px-3 py-1.5 text-xs font-medium text-action-primary-text hover:bg-action-primary-bgHover transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus\"\n >\n <Play className=\"size-3.5 mr-1.5\" />\n {tr('vibecontrols.tunnels.start', 'Start')}\n </button>\n )}\n {canStop && onStop && (\n <button\n type=\"button\"\n onClick={() => onStop(tunnel.id)}\n className=\"inline-flex items-center rounded-button border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken hover:border-border-strong transition-colors\"\n >\n <Square className=\"size-3.5 mr-1.5\" />\n {tr('vibecontrols.tunnels.stop', 'Stop')}\n </button>\n )}\n <EntityVibeLinkControl\n entityType={VibeEntityType.Tunnel}\n entityId={tunnel.id}\n currentVibeId={tunnel.vibeId ?? null}\n currentVisibility={tunnel.visibility ?? null}\n refetchQueries={['ListTunnels']}\n />\n {onDelete && (\n <button\n type=\"button\"\n onClick={() => onDelete(tunnel.id, tunnel.name)}\n className=\"inline-flex items-center rounded-button border border-border-subtle px-2 py-1.5 text-xs text-status-error-text hover:bg-status-error-bg-subtle hover:border-status-error-border transition-colors\"\n aria-label=\"Delete tunnel\"\n >\n <Trash2 className=\"size-3.5\" />\n </button>\n )}\n </div>\n </div>\n {tunnel.lastError && (\n <div className=\"mt-4 rounded-button border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text\">\n {tunnel.lastError}\n </div>\n )}\n </motion.div>\n );\n}\n"],"mappings":";;;;;;;;;AAwBA,SAAgB,EAAW,EACzB,WACA,eAAY,IACZ,WACA,YACA,WACA,eACkB;CAClB,IAAM,IAAK,GAAO,EACZ,IACJ,CAAC,KACD,EAAO,WAAW,EAAa,UAC/B,EAAO,WAAW,EAAa,cAC3B,IAAU,CAAC,KAAa,EAAO,WAAW,EAAa,QACvD,IAAW,EAAO,eAAe,UACjC,IAAY,IACd,GAAG,EAAO,SAAS,aAAa,KAAK,QAAQ,QAAQ,QAAQ,KAAK,MAClE;AAEJ,QACE,kBAAC,EAAO,KAAR;EACE,SAAS;GAAE,SAAS;GAAG,GAAG;GAAG;EAC7B,SAAS;GAAE,SAAS;GAAG,GAAG;GAAG;EAC7B,WAAU;YAHZ,CAKE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAO,EAAO,GAAG;IAChC,WAAU;cAHZ;KAKE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAO;QACL,CAAA;OACL,kBAAC,GAAD,EAAmB,QAAQ,EAAO,QAAU,CAAA;OAC5C,kBAAC,GAAD,EAAe,aAAa,EAAO,aAAe,CAAA;OAC9C;;KACL,IACC,kBAAC,KAAD;MAAG,WAAU;gBAAwC;MAAc,CAAA,GAEnE,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAG,iCAAiC,qBAAqB;MACxD,CAAA;KAEN,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACG,EAAO;OAAS;OAAE,EAAO;OAAU;OAAK,EAAO;OAC9C;;KACG;OAET,kBAAC,OAAD;IAAK,WAAU;cAAf;KACG,KACC,kBAAC,KAAD;MACE,MAAM;MACN,QAAO;MACP,KAAI;MACJ,WAAU;MACV,UAAU,MAAM,EAAE,iBAAiB;gBALrC,CAOE,kBAAC,GAAD,EAAc,WAAU,mBAAoB,CAAA,EAC3C,EAAG,6BAA6B,OAAO,CACtC;;KAEL,KACC,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CACE,kBAAC,GAAD,EAAS,WAAU,gCAAiC,CAAA,EACnD,EAAO,WAAW,WACf,EAAG,iCAAiC,YAAY,GAChD,EAAG,iCAAiC,YAAY,CAC/C;;KAER,KAAY,KACX,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAQ,EAAO,GAAG;MACjC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,mBAAoB,CAAA,EACnC,EAAG,8BAA8B,QAAQ,CACnC;;KAEV,KAAW,KACV,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAO,EAAO,GAAG;MAChC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAQ,WAAU,mBAAoB,CAAA,EACrC,EAAG,6BAA6B,OAAO,CACjC;;KAEX,kBAAC,GAAD;MACE,YAAY,EAAe;MAC3B,UAAU,EAAO;MACjB,eAAe,EAAO,UAAU;MAChC,mBAAmB,EAAO,cAAc;MACxC,gBAAgB,CAAC,cAAc;MAC/B,CAAA;KACD,KACC,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAS,EAAO,IAAI,EAAO,KAAK;MAC/C,WAAU;MACV,cAAW;gBAEX,kBAAC,GAAD,EAAQ,WAAU,YAAa,CAAA;MACxB,CAAA;KAEP;MACF;MACL,EAAO,aACN,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAO;GACJ,CAAA,CAEG"}
1
+ {"version":3,"file":"TunnelCard.js","names":[],"sources":["../../../src/components/tunnels/TunnelCard.tsx"],"sourcesContent":["import { motion } from 'framer-motion';\nimport { Loader2, Play, Square, Trash2, ExternalLink } from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\n\nimport type { ListTunnelsQuery } from '@/generated/wspace-operations';\nimport { TunnelStatus, VibeEntityType } from '@/generated/wspace-types';\nimport { TunnelStatusBadge } from './TunnelStatusBadge';\nimport { ProviderBadge } from './ProviderBadge';\nimport { EntityVibeLinkControl } from '../shared/EntityVibeLinkControl';\n\ntype TunnelRow = NonNullable<ListTunnelsQuery['tunnels']>['items'][number];\n\ninterface TunnelCardProps {\n tunnel: TunnelRow;\n isPending?: boolean;\n onOpen: (id: string) => void;\n // Mutation callbacks are optional: the parent omits them when the actor\n // lacks the permission (tunnel:execute for start/stop, tunnel:delete), so\n // the corresponding control is hidden rather than 403-ing on click.\n onStart?: (id: string) => void;\n onStop?: (id: string) => void;\n onDelete?: (id: string, name: string) => void;\n}\n\nexport function TunnelCard({\n tunnel,\n isPending = false,\n onOpen,\n onStart,\n onStop,\n onDelete,\n}: TunnelCardProps) {\n const tr = useTr();\n const canStart =\n !isPending &&\n tunnel.status !== TunnelStatus.Active &&\n tunnel.status !== TunnelStatus.Provisioning;\n const canStop = !isPending && tunnel.status === TunnelStatus.Active;\n const hostname = tunnel.primaryDomain?.hostname;\n const publicUrl = hostname\n ? `${tunnel.protocol.toLowerCase() === 'tcp' ? 'tcp' : 'https'}://${hostname}`\n : null;\n\n return (\n <motion.div\n initial={{ opacity: 0, y: 4 }}\n animate={{ opacity: 1, y: 0 }}\n className=\"rounded-card border border-border-subtle bg-bg-surface shadow-elevation-1 p-5 hover:border-border-strong hover:shadow-elevation-2 transition-all duration-200 ease-[var(--motion-easing-out)]\"\n >\n <div className=\"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4\">\n <button\n type=\"button\"\n onClick={() => onOpen(tunnel.id)}\n className=\"flex-1 text-left min-w-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus rounded-button\"\n >\n <div className=\"flex flex-wrap items-center gap-2 mb-1.5\">\n <h3 className=\"text-base font-semibold text-text-primary truncate tracking-tight\">\n {tunnel.name}\n </h3>\n <TunnelStatusBadge status={tunnel.status} />\n <ProviderBadge providerKey={tunnel.providerKey} />\n </div>\n {publicUrl ? (\n <p className=\"text-sm text-text-secondary truncate\">{publicUrl}</p>\n ) : (\n <p className=\"text-sm text-text-muted\">\n {tr('vibecontrols.tunnels.noDomain', 'No domain attached')}\n </p>\n )}\n <p className=\"text-xs font-mono text-text-muted mt-1 tabular-nums\">\n {tunnel.protocol}:{tunnel.localPort} on {tunnel.localHost}\n </p>\n </button>\n\n <div className=\"flex items-center gap-2 flex-shrink-0 flex-wrap\">\n {publicUrl && (\n <a\n href={publicUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center rounded-button border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken hover:border-border-strong transition-colors\"\n onClick={(e) => e.stopPropagation()}\n >\n <ExternalLink className=\"size-3.5 mr-1.5\" />\n {tr('vibecontrols.tunnels.open', 'Open')}\n </a>\n )}\n {isPending && (\n <span className=\"inline-flex items-center rounded-button border border-border-subtle bg-bg-sunken px-3 py-1.5 text-xs text-text-muted\">\n <Loader2 className=\"size-3.5 mr-1.5 animate-spin\" />\n {tunnel.status === 'ACTIVE'\n ? tr('vibecontrols.tunnels.stopping', 'Stopping…')\n : tr('vibecontrols.tunnels.starting', 'Starting…')}\n </span>\n )}\n {canStart && onStart && (\n <button\n type=\"button\"\n onClick={() => onStart(tunnel.id)}\n className=\"inline-flex items-center rounded-button bg-action-primary-bg px-3 py-1.5 text-xs font-medium text-action-primary-text hover:bg-action-primary-bgHover transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus\"\n >\n <Play className=\"size-3.5 mr-1.5\" />\n {tr('vibecontrols.tunnels.start', 'Start')}\n </button>\n )}\n {canStop && onStop && (\n <button\n type=\"button\"\n onClick={() => onStop(tunnel.id)}\n className=\"inline-flex items-center rounded-button border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken hover:border-border-strong transition-colors\"\n >\n <Square className=\"size-3.5 mr-1.5\" />\n {tr('vibecontrols.tunnels.stop', 'Stop')}\n </button>\n )}\n <EntityVibeLinkControl\n entityType={VibeEntityType.Tunnel}\n entityId={tunnel.id}\n currentVibeId={tunnel.vibeId ?? null}\n currentVisibility={tunnel.visibility ?? null}\n refetchQueries={['ListTunnels']}\n />\n {onDelete && (\n <button\n type=\"button\"\n onClick={() => onDelete(tunnel.id, tunnel.name)}\n className=\"inline-flex items-center rounded-button border border-border-subtle px-2 py-1.5 text-xs text-status-error-text hover:bg-status-error-bg-subtle hover:border-status-error-border transition-colors\"\n aria-label=\"Delete tunnel\"\n >\n <Trash2 className=\"size-3.5\" />\n </button>\n )}\n </div>\n </div>\n {tunnel.lastError && (\n <div className=\"mt-4 rounded-button border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text\">\n {tunnel.lastError}\n </div>\n )}\n </motion.div>\n );\n}\n"],"mappings":";;;;;;;;;AAwBA,SAAgB,EAAW,EACzB,WACA,eAAY,IACZ,WACA,YACA,WACA,eACkB;CAClB,IAAM,IAAK,GAAO,EACZ,IACJ,CAAC,KACD,EAAO,WAAW,EAAa,UAC/B,EAAO,WAAW,EAAa,cAC3B,IAAU,CAAC,KAAa,EAAO,WAAW,EAAa,QACvD,IAAW,EAAO,eAAe,UACjC,IAAY,IACd,GAAG,EAAO,SAAS,aAAa,KAAK,QAAQ,QAAQ,QAAQ,KAAK,MAClE;AAEJ,QACE,kBAAC,EAAO,KAAR;EACE,SAAS;GAAE,SAAS;GAAG,GAAG;GAAG;EAC7B,SAAS;GAAE,SAAS;GAAG,GAAG;GAAG;EAC7B,WAAU;YAHZ,CAKE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAO,EAAO,GAAG;IAChC,WAAU;cAHZ;KAKE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAO;QACL,CAAA;OACL,kBAAC,GAAD,EAAmB,QAAQ,EAAO,QAAU,CAAA;OAC5C,kBAAC,GAAD,EAAe,aAAa,EAAO,aAAe,CAAA;OAC9C;;KACL,IACC,kBAAC,KAAD;MAAG,WAAU;gBAAwC;MAAc,CAAA,GAEnE,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAG,iCAAiC,qBAAqB;MACxD,CAAA;KAEN,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACG,EAAO;OAAS;OAAE,EAAO;OAAU;OAAK,EAAO;OAC9C;;KACG;OAET,kBAAC,OAAD;IAAK,WAAU;cAAf;KACG,KACC,kBAAC,KAAD;MACE,MAAM;MACN,QAAO;MACP,KAAI;MACJ,WAAU;MACV,UAAU,MAAM,EAAE,iBAAiB;gBALrC,CAOE,kBAAC,GAAD,EAAc,WAAU,mBAAoB,CAAA,EAC3C,EAAG,6BAA6B,OAAO,CACtC;;KAEL,KACC,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CACE,kBAAC,GAAD,EAAS,WAAU,gCAAiC,CAAA,EACnD,EAAO,WAAW,WACf,EAAG,iCAAiC,YAAY,GAChD,EAAG,iCAAiC,YAAY,CAC/C;;KAER,KAAY,KACX,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAQ,EAAO,GAAG;MACjC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,mBAAoB,CAAA,EACnC,EAAG,8BAA8B,QAAQ,CACnC;;KAEV,KAAW,KACV,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAO,EAAO,GAAG;MAChC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAQ,WAAU,mBAAoB,CAAA,EACrC,EAAG,6BAA6B,OAAO,CACjC;;KAEX,kBAAC,GAAD;MACE,YAAY,EAAe;MAC3B,UAAU,EAAO;MACjB,eAAe,EAAO,UAAU;MAChC,mBAAmB,EAAO,cAAc;MACxC,gBAAgB,CAAC,cAAc;MAC/B,CAAA;KACD,KACC,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAS,EAAO,IAAI,EAAO,KAAK;MAC/C,WAAU;MACV,cAAW;gBAEX,kBAAC,GAAD,EAAQ,WAAU,YAAa,CAAA;MACxB,CAAA;KAEP;MACF;MACL,EAAO,aACN,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAO;GACJ,CAAA,CAEG"}
@@ -10,42 +10,42 @@ import { jsx as f, jsxs as p } from "react/jsx-runtime";
10
10
  import { Tabs as m } from "@burdenoff/fe-libs/chrome";
11
11
  import { MotionItem as h, MotionList as g, MotionPage as _ } from "@burdenoff/fe-libs/shared/motion";
12
12
  //#region src/pages/GettingStartedPage.tsx
13
- var v = "https://www.npmjs.com/package/@vibecontrols/cli";
14
- function y() {
15
- let { t: y } = o(), b = r((e, t) => {
16
- let n = y(e);
13
+ var v = "https://www.npmjs.com/package/@vibecontrols/agent", y = "https://docs.vibecontrols.com/users/installing-the-agent";
14
+ function b() {
15
+ let { t: b } = o(), x = r((e, t) => {
16
+ let n = b(e);
17
17
  return n === e ? t : n;
18
- }, [y]), [x, S] = d(), C = i(() => [{
18
+ }, [b]), [S, C] = d(), w = i(() => [{
19
19
  id: "install",
20
- label: b("gettingStarted.installTab", "Install")
20
+ label: x("gettingStarted.installTab", "Install")
21
21
  }, {
22
22
  id: "cli",
23
- label: b("gettingStarted.cliTab", "CLI Reference")
24
- }], [b]), w = x.get("tab") ?? C[0].id, T = (e) => {
25
- let t = new URLSearchParams(x);
26
- e === C[0].id ? t.delete("tab") : t.set("tab", e), S(t, { replace: !0 });
27
- }, [E, D] = a("");
23
+ label: x("gettingStarted.cliTab", "CLI Reference")
24
+ }], [x]), T = S.get("tab") ?? w[0].id, E = (e) => {
25
+ let t = new URLSearchParams(S);
26
+ e === w[0].id ? t.delete("tab") : t.set("tab", e), C(t, { replace: !0 });
27
+ }, [D, O] = a("");
28
28
  return /* @__PURE__ */ p(_, {
29
29
  className: "space-y-8 px-6 lg:px-8 py-6 bg-bg-canvas min-h-screen",
30
30
  children: [
31
31
  /* @__PURE__ */ f(e, {
32
- title: b("gettingStarted.title", "Getting Started"),
33
- description: b("gettingStarted.description", "Install and configure the VibeControls Agent CLI")
32
+ title: x("gettingStarted.title", "Getting Started"),
33
+ description: x("gettingStarted.description", "Install and configure the VibeControls Agent CLI")
34
34
  }),
35
35
  /* @__PURE__ */ f("div", {
36
36
  className: "border-b border-border-subtle",
37
37
  children: /* @__PURE__ */ f(m, {
38
- items: C,
39
- activeTabId: w,
40
- onTabChange: T,
38
+ items: w,
39
+ activeTabId: T,
40
+ onTabChange: E,
41
41
  variant: "underline"
42
42
  })
43
43
  }),
44
- w === "install" && /* @__PURE__ */ p("div", {
44
+ T === "install" && /* @__PURE__ */ p("div", {
45
45
  className: "space-y-6",
46
46
  children: [
47
47
  /* @__PURE__ */ f("div", {
48
- className: "relative border border-border-subtle bg-accent-purple-subtle rounded-card p-6 sm:p-8 shadow-elevation-1",
48
+ className: "relative border border-border-subtle bg-bg-elevated rounded-card p-6 sm:p-8 shadow-elevation-1",
49
49
  children: /* @__PURE__ */ p("div", {
50
50
  className: "flex items-start gap-4",
51
51
  children: [/* @__PURE__ */ f("div", {
@@ -53,13 +53,23 @@ function y() {
53
53
  children: /* @__PURE__ */ f(s, { className: "size-6 text-accent-purple" })
54
54
  }), /* @__PURE__ */ p("div", {
55
55
  className: "flex-1",
56
- children: [/* @__PURE__ */ f("h2", {
57
- className: "text-lg sm:text-xl font-semibold text-text-primary mb-1",
58
- children: b("gettingStarted.installAgent", "Install the Agent")
59
- }), /* @__PURE__ */ f("p", {
60
- className: "text-sm text-text-secondary",
61
- children: b("gettingStarted.installAgentDesc", "Run a single command on the machine you want to manage. The recommended curl script installs bun (pinned) and the agent automatically — no other prerequisites.")
62
- })]
56
+ children: [
57
+ /* @__PURE__ */ f("h2", {
58
+ className: "text-lg sm:text-xl font-semibold text-text-primary mb-1",
59
+ children: x("gettingStarted.installAgent", "Install the Agent")
60
+ }),
61
+ /* @__PURE__ */ f("p", {
62
+ className: "text-sm text-text-secondary",
63
+ children: x("gettingStarted.installAgentDesc", "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.")
64
+ }),
65
+ /* @__PURE__ */ p("a", {
66
+ href: y,
67
+ target: "_blank",
68
+ rel: "noopener noreferrer",
69
+ className: "mt-3 inline-flex items-center gap-1.5 text-sm text-text-link hover:text-text-linkHover hover:underline",
70
+ children: [x("gettingStarted.viewInstallDocs", "View the full install docs"), /* @__PURE__ */ f(c, { className: "size-3.5" })]
71
+ })
72
+ ]
63
73
  })]
64
74
  })
65
75
  }),
@@ -67,7 +77,7 @@ function y() {
67
77
  padding: "none",
68
78
  children: /* @__PURE__ */ p("div", {
69
79
  className: "p-5 sm:p-6",
70
- children: [/* @__PURE__ */ f(n, { pinnedAgentVersion: E || void 0 }), /* @__PURE__ */ p("div", {
80
+ children: [/* @__PURE__ */ f(n, { pinnedAgentVersion: D || void 0 }), /* @__PURE__ */ p("div", {
71
81
  className: "mt-6 pt-4 border-t border-border-subtle",
72
82
  children: [/* @__PURE__ */ p("label", {
73
83
  htmlFor: "pinned-version",
@@ -75,15 +85,15 @@ function y() {
75
85
  children: [
76
86
  /* @__PURE__ */ f(l, { className: "size-3.5" }),
77
87
  " ",
78
- b("gettingStarted.pinVersion", "Pin a specific agent version (optional)")
88
+ x("gettingStarted.pinVersion", "Pin a specific agent version (optional)")
79
89
  ]
80
90
  }), /* @__PURE__ */ f("input", {
81
91
  "aria-label": "pinned-version",
82
92
  id: "pinned-version",
83
93
  type: "text",
84
- placeholder: b("gettingStarted.pinVersionPlaceholder", "e.g. 2026.408.1 (leave blank for latest)"),
85
- value: E,
86
- onChange: (e) => D(e.target.value),
94
+ placeholder: x("gettingStarted.pinVersionPlaceholder", "e.g. 2026.408.1 (leave blank for latest)"),
95
+ value: D,
96
+ onChange: (e) => O(e.target.value),
87
97
  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)]"
88
98
  })]
89
99
  })]
@@ -93,119 +103,125 @@ function y() {
93
103
  padding: "none",
94
104
  children: /* @__PURE__ */ p("div", {
95
105
  className: "p-5 sm:p-6",
96
- children: [/* @__PURE__ */ f("h3", {
97
- className: "text-base font-semibold text-text-primary mb-3",
98
- children: b("gettingStarted.nextSteps", "Next steps")
99
- }), /* @__PURE__ */ p("ol", {
100
- className: "list-decimal list-inside space-y-2 text-sm text-text-secondary",
101
- children: [
102
- /* @__PURE__ */ p("li", { children: [
103
- b("gettingStarted.nextStep1Prefix", "Start the agent:"),
104
- " ",
105
- /* @__PURE__ */ f("code", {
106
- className: "font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded",
107
- children: "vibecontrols auth login"
108
- }),
109
- " ",
110
- b("gettingStarted.nextStep1Suffix", "to authenticate the CLI before running workspace commands.")
111
- ] }),
112
- /* @__PURE__ */ p("li", { children: [
113
- b("gettingStarted.nextStep2Prefix", "Select a workspace and inspect agents:"),
114
- " ",
115
- /* @__PURE__ */ f("code", {
116
- className: "font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded",
117
- children: "vibecontrols workspace set <id>"
118
- }),
119
- " ",
120
- b("gettingStarted.nextStep2And", "then"),
121
- " ",
122
- /* @__PURE__ */ f("code", {
123
- className: "font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded",
124
- children: "vibecontrols agents list"
125
- }),
126
- "."
127
- ] }),
128
- /* @__PURE__ */ p("li", { children: [
129
- b("gettingStarted.nextStep3Prefix", "In this UI, go to"),
130
- " ",
131
- /* @__PURE__ */ p("strong", { children: [
132
- b("gettingStarted.targetsAndAgents", "Targets & Agents"),
133
- " →",
106
+ children: [
107
+ /* @__PURE__ */ f("h3", {
108
+ className: "text-base font-semibold text-text-primary mb-3",
109
+ children: x("gettingStarted.nextSteps", "Next steps")
110
+ }),
111
+ /* @__PURE__ */ p("ol", {
112
+ className: "list-decimal list-inside space-y-2 text-sm text-text-secondary",
113
+ children: [
114
+ /* @__PURE__ */ p("li", { children: [
115
+ x("gettingStarted.nextStep1Prefix", "Start the agent:"),
134
116
  " ",
135
- b("gettingStarted.addAgent", "Add Agent")
117
+ /* @__PURE__ */ f("code", {
118
+ className: "font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded",
119
+ children: "vibe start"
120
+ }),
121
+ " ",
122
+ x("gettingStarted.nextStep1Suffix", "— on first run it establishes a Cloudflare tunnel, generates an agentApiKey, and waits in pre-config mode for the platform.")
136
123
  ] }),
137
- b("gettingStarted.nextStep3Suffix", ", pick or create a target, and paste the URL and key from step 2.")
138
- ] })
139
- ]
140
- })]
124
+ /* @__PURE__ */ p("li", { children: [
125
+ x("gettingStarted.nextStep2Prefix", "In this UI, go to"),
126
+ " ",
127
+ /* @__PURE__ */ p("strong", { children: [
128
+ x("gettingStarted.targetsAndAgents", "Targets & Agents"),
129
+ " →",
130
+ " ",
131
+ x("gettingStarted.addAgent", "Add Agent")
132
+ ] }),
133
+ x("gettingStarted.nextStep2Suffix", ", 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.")
134
+ ] }),
135
+ /* @__PURE__ */ p("li", { children: [
136
+ x("gettingStarted.nextStep3Prefix", "Run it as a background service:"),
137
+ " ",
138
+ /* @__PURE__ */ f("code", {
139
+ className: "font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded",
140
+ children: "vibe autostart install"
141
+ }),
142
+ " ",
143
+ x("gettingStarted.nextStep3Suffix", "(remove later with"),
144
+ " ",
145
+ /* @__PURE__ */ f("code", {
146
+ className: "font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded",
147
+ children: "vibe autostart uninstall"
148
+ }),
149
+ x("gettingStarted.nextStep3End", ").")
150
+ ] }),
151
+ /* @__PURE__ */ p("li", { children: [
152
+ x("gettingStarted.nextStep4Prefix", "Verify it is running with"),
153
+ " ",
154
+ /* @__PURE__ */ f("code", {
155
+ className: "font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded",
156
+ children: "vibe health"
157
+ }),
158
+ " ",
159
+ x("gettingStarted.nextStep4And", "and"),
160
+ " ",
161
+ /* @__PURE__ */ f("code", {
162
+ className: "font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded",
163
+ children: "vibe status"
164
+ }),
165
+ "."
166
+ ] })
167
+ ]
168
+ }),
169
+ /* @__PURE__ */ p("a", {
170
+ href: y,
171
+ target: "_blank",
172
+ rel: "noopener noreferrer",
173
+ className: "mt-4 inline-flex items-center gap-1.5 text-sm text-text-link hover:text-text-linkHover hover:underline",
174
+ children: [x("gettingStarted.viewInstallDocs", "View the full install docs"), /* @__PURE__ */ f(c, { className: "size-3.5" })]
175
+ })
176
+ ]
141
177
  })
142
178
  })
143
179
  ]
144
180
  }),
145
- w === "cli" && /* @__PURE__ */ f(t, {
181
+ T === "cli" && /* @__PURE__ */ f(t, {
146
182
  padding: "none",
147
183
  children: /* @__PURE__ */ p("div", {
148
184
  className: "p-5 sm:p-6",
149
185
  children: [
150
186
  /* @__PURE__ */ p("h3", {
151
187
  className: "text-base font-semibold text-text-primary mb-4 flex items-center gap-2",
152
- children: [/* @__PURE__ */ f(u, { className: "size-5 text-accent-purple" }), b("gettingStarted.cliQuickRef", "CLI Quick Reference")]
188
+ children: [/* @__PURE__ */ f(u, { className: "size-5 text-accent-purple" }), x("gettingStarted.cliQuickRef", "CLI Quick Reference")]
153
189
  }),
154
190
  /* @__PURE__ */ f(g, {
155
191
  stagger: .04,
156
192
  className: "space-y-2",
157
193
  children: [
158
194
  {
159
- cmd: "vibecontrols auth login",
160
- desc: b("gettingStarted.cmdAuthLogin", "Sign in with OAuth2 Device Code")
161
- },
162
- {
163
- cmd: "vibecontrols auth whoami",
164
- desc: b("gettingStarted.cmdAuthWhoami", "Show the active signed-in identity")
165
- },
166
- {
167
- cmd: "vibecontrols workspace set <id>",
168
- desc: b("gettingStarted.cmdWorkspaceSet", "Choose the workspace context")
169
- },
170
- {
171
- cmd: "vibecontrols vibes list",
172
- desc: b("gettingStarted.cmdVibesList", "List VibeControls vibes")
173
- },
174
- {
175
- cmd: "vibecontrols agents list",
176
- desc: b("gettingStarted.cmdAgentsList", "List registered agents")
177
- },
178
- {
179
- cmd: "vibecontrols sessions list",
180
- desc: b("gettingStarted.cmdSessionsList", "List workspace sessions")
195
+ cmd: "vibe start",
196
+ desc: x("gettingStarted.cmdVibeStart", "First run: auto-detects deps, picks a port (default 3005), establishes a Cloudflare tunnel, generates an agentApiKey, then waits for the platform")
181
197
  },
182
198
  {
183
- cmd: "vibecontrols tags create --key bug --label Bug",
184
- desc: b("gettingStarted.cmdTagsCreate", "Create a workspace tag")
199
+ cmd: "vibe start --profile <name>",
200
+ desc: x("gettingStarted.cmdVibeStartProfile", "Run a named profile (e.g. alpha, default) for multiple agent instances")
185
201
  },
186
202
  {
187
- cmd: "vibecontrols rbac check <user> read project",
188
- desc: b("gettingStarted.cmdRbacCheck", "Check RBAC access")
203
+ cmd: "vibe setup",
204
+ desc: x("gettingStarted.cmdVibeSetup", "Install missing dependencies (tmux, ttyd, cloudflared)")
189
205
  },
190
206
  {
191
- cmd: "vibecontrols products feature-flags list",
192
- desc: b("gettingStarted.cmdFeatureFlagsList", "List product feature flags")
207
+ cmd: "vibe health",
208
+ desc: x("gettingStarted.cmdVibeHealth", "Run an HTTP health check on the agent")
193
209
  },
194
210
  {
195
- cmd: "vibecontrols devportal apps list --status PUBLISHED",
196
- desc: b("gettingStarted.cmdDevportalApps", "List published Developer Portal apps")
211
+ cmd: "vibe status",
212
+ desc: x("gettingStarted.cmdVibeStatus", "Show all running agent instances")
197
213
  },
198
214
  {
199
- cmd: "vibecontrols billing subscriptions list",
200
- desc: b("gettingStarted.cmdBillingSubscriptions", "List billing subscriptions")
215
+ cmd: "vibe autostart install",
216
+ desc: x("gettingStarted.cmdVibeAutostartInstall", "Run the agent as a background service (daemonize)")
201
217
  },
202
218
  {
203
- cmd: "vibecontrols health check",
204
- desc: b("gettingStarted.cmdHealthCheck", "Run platform health checks")
219
+ cmd: "vibe autostart uninstall",
220
+ desc: x("gettingStarted.cmdVibeAutostartUninstall", "Remove the background service")
205
221
  },
206
222
  {
207
- cmd: "vibecontrols auth logout",
208
- desc: b("gettingStarted.cmdAuthLogout", "Sign out of the CLI")
223
+ cmd: "vibecontrols agents list --active",
224
+ desc: x("gettingStarted.cmdAgentsListActive", "Platform CLI — see the connected agent on the backend")
209
225
  }
210
226
  ].map((e) => /* @__PURE__ */ p(h, {
211
227
  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",
@@ -226,13 +242,13 @@ function y() {
226
242
  rel: "noopener noreferrer",
227
243
  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",
228
244
  children: [
229
- b("gettingStarted.cliNpmPackage", "CLI npm package"),
245
+ x("gettingStarted.agentNpmPackage", "Agent npm package"),
230
246
  " ",
231
247
  /* @__PURE__ */ f(c, { className: "size-3" })
232
248
  ]
233
249
  }), /* @__PURE__ */ f("span", {
234
250
  className: "text-xs text-text-muted",
235
- children: b("gettingStarted.cliNpmLatest", "@vibecontrols/cli (latest)")
251
+ children: x("gettingStarted.agentNpmLatest", "@vibecontrols/agent (latest)")
236
252
  })]
237
253
  })
238
254
  ]
@@ -242,6 +258,6 @@ function y() {
242
258
  });
243
259
  }
244
260
  //#endregion
245
- export { y as GettingStartedPage };
261
+ export { b as GettingStartedPage };
246
262
 
247
263
  //# sourceMappingURL=GettingStartedPage.js.map
@@ -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 { 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 CLI_NPM_URL = 'https://www.npmjs.com/package/@vibecontrols/cli';\n\n/**\n * Getting Started page — a tabbed guide to installing and using the\n * VibeControls Agent CLI. Two top-level tabs:\n *\n * • Install — shows curl / npm commands for Linux, macOS, Windows via\n * the shared `InstallTabs` component.\n * • CLI Reference — a compact reference of the most common commands.\n *\n * Bun is the only machine prerequisite — the curl install script installs\n * it automatically at a pinned version (v1.3.10). OAuth2 is always enabled\n * in the gateway so no manual configuration is needed.\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 */}\n <div className=\"relative border border-border-subtle bg-accent-purple-subtle rounded-card p-6 sm:p-8 shadow-elevation-1\">\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 'Run a single command on the machine you want to manage. The recommended curl script installs bun (pinned) and the agent automatically — no other prerequisites.'\n )}\n </p>\n </div>\n </div>\n </div>\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 vibecontrols auth login\n </code>{' '}\n {tr(\n 'gettingStarted.nextStep1Suffix',\n 'to authenticate the CLI before running workspace commands.'\n )}\n </li>\n <li>\n {tr('gettingStarted.nextStep2Prefix', 'Select a workspace and inspect agents:')}{' '}\n <code className=\"font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded\">\n vibecontrols workspace set &lt;id&gt;\n </code>{' '}\n {tr('gettingStarted.nextStep2And', 'then')}{' '}\n <code className=\"font-mono text-xs bg-bg-sunken/60 text-text-secondary px-1.5 py-0.5 rounded\">\n vibecontrols agents list\n </code>\n .\n </li>\n <li>\n {tr('gettingStarted.nextStep3Prefix', '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.nextStep3Suffix',\n ', pick or create a target, and paste the URL and key from step 2.'\n )}\n </li>\n </ol>\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 <MotionList stagger={0.04} className=\"space-y-2\">\n {[\n {\n cmd: 'vibecontrols auth login',\n desc: tr('gettingStarted.cmdAuthLogin', 'Sign in with OAuth2 Device Code'),\n },\n {\n cmd: 'vibecontrols auth whoami',\n desc: tr('gettingStarted.cmdAuthWhoami', 'Show the active signed-in identity'),\n },\n {\n cmd: 'vibecontrols workspace set <id>',\n desc: tr('gettingStarted.cmdWorkspaceSet', 'Choose the workspace context'),\n },\n {\n cmd: 'vibecontrols vibes list',\n desc: tr('gettingStarted.cmdVibesList', 'List VibeControls vibes'),\n },\n {\n cmd: 'vibecontrols agents list',\n desc: tr('gettingStarted.cmdAgentsList', 'List registered agents'),\n },\n {\n cmd: 'vibecontrols sessions list',\n desc: tr('gettingStarted.cmdSessionsList', 'List workspace sessions'),\n },\n {\n cmd: 'vibecontrols tags create --key bug --label Bug',\n desc: tr('gettingStarted.cmdTagsCreate', 'Create a workspace tag'),\n },\n {\n cmd: 'vibecontrols rbac check <user> read project',\n desc: tr('gettingStarted.cmdRbacCheck', 'Check RBAC access'),\n },\n {\n cmd: 'vibecontrols products feature-flags list',\n desc: tr('gettingStarted.cmdFeatureFlagsList', 'List product feature flags'),\n },\n {\n cmd: 'vibecontrols devportal apps list --status PUBLISHED',\n desc: tr(\n 'gettingStarted.cmdDevportalApps',\n 'List published Developer Portal apps'\n ),\n },\n {\n cmd: 'vibecontrols billing subscriptions list',\n desc: tr('gettingStarted.cmdBillingSubscriptions', 'List billing subscriptions'),\n },\n {\n cmd: 'vibecontrols health check',\n desc: tr('gettingStarted.cmdHealthCheck', 'Run platform health checks'),\n },\n {\n cmd: 'vibecontrols auth logout',\n desc: tr('gettingStarted.cmdAuthLogout', 'Sign out of the CLI'),\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 <div className=\"mt-4 pt-4 border-t border-border-subtle flex flex-wrap items-center gap-3\">\n <a\n href={CLI_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.cliNpmPackage', 'CLI npm package')}{' '}\n <ExternalLink className=\"size-3\" />\n </a>\n <span className=\"text-xs text-text-muted\">\n {tr('gettingStarted.cliNpmLatest', '@vibecontrols/cli (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 { 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 */}\n <div className=\"relative border border-border-subtle bg-bg-elevated rounded-card p-6 sm:p-8 shadow-elevation-1\">\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 </div>\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 <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 <div className=\"mt-4 pt-4 border-t border-border-subtle 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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"}