@skyhook-io/radar-app 0.2.2 → 0.3.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.
Files changed (177) hide show
  1. package/README.md +7 -1
  2. package/package.json +33 -25
  3. package/src/App.tsx +1449 -382
  4. package/src/RadarApp.tsx +132 -19
  5. package/src/api/apiResources.ts +1 -1
  6. package/src/api/client.argoResourceSync.test.ts +69 -0
  7. package/src/api/client.delta.test.ts +89 -0
  8. package/src/api/client.deltaSync.test.ts +216 -0
  9. package/src/api/client.metrics.test.ts +106 -0
  10. package/src/api/client.rightsizing.test.ts +32 -0
  11. package/src/api/client.ts +2730 -271
  12. package/src/api/client.yaml.test.ts +45 -0
  13. package/src/api/diagnose.ts +289 -0
  14. package/src/api/quotas.ts +16 -0
  15. package/src/api/rbac.ts +57 -0
  16. package/src/api/timelineSource.test.ts +217 -0
  17. package/src/api/timelineSource.ts +582 -0
  18. package/src/components/ConnectionErrorView.tsx +186 -70
  19. package/src/components/ContextSwitcher.tsx +63 -18
  20. package/src/components/DebugOverlay.tsx +5 -3
  21. package/src/components/NamespaceSwitcher.tsx +41 -0
  22. package/src/components/UserMenu.tsx +69 -21
  23. package/src/components/applications/ApplicationsView.tsx +936 -0
  24. package/src/components/audit/AuditSettingsDialog.tsx +79 -17
  25. package/src/components/audit/AuditView.tsx +65 -62
  26. package/src/components/compare/CompareViewRoute.tsx +124 -0
  27. package/src/components/compare/useCompareCandidates.ts +27 -0
  28. package/src/components/compare/useCompareLauncher.tsx +79 -0
  29. package/src/components/cost/ApplicationCostTab.test.ts +204 -0
  30. package/src/components/cost/ApplicationCostTab.tsx +571 -0
  31. package/src/components/cost/CostTrendChart.tsx +106 -75
  32. package/src/components/cost/CostView.test.ts +12 -0
  33. package/src/components/cost/CostView.tsx +507 -223
  34. package/src/components/cost/CostViewTabs.test.tsx +21 -0
  35. package/src/components/cost/CostViewTabs.tsx +40 -0
  36. package/src/components/cost/CurrentAllocationUse.test.ts +21 -0
  37. package/src/components/cost/CurrentAllocationUse.tsx +126 -0
  38. package/src/components/cost/WorkloadCostTab.test.ts +153 -0
  39. package/src/components/cost/WorkloadCostTab.tsx +372 -0
  40. package/src/components/cost/cloud-console.test.ts +39 -0
  41. package/src/components/cost/cloud-console.ts +81 -0
  42. package/src/components/cost/errors.ts +8 -0
  43. package/src/components/cost/format.test.ts +27 -0
  44. package/src/components/cost/format.ts +46 -0
  45. package/src/components/cost/kinds.ts +5 -0
  46. package/src/components/curl/ServiceCurlButton.tsx +445 -0
  47. package/src/components/diagnose/AISettings.tsx +147 -0
  48. package/src/components/diagnose/DiagnoseContext.tsx +495 -0
  49. package/src/components/diagnose/DiagnoseSurface.tsx +394 -0
  50. package/src/components/diagnose/Home.tsx +163 -0
  51. package/src/components/diagnose/InvestigationView.tsx +622 -0
  52. package/src/components/diagnose/LocalDiagnoseAction.tsx +162 -0
  53. package/src/components/diagnose/launch.ts +65 -0
  54. package/src/components/diagnose/parts.tsx +1756 -0
  55. package/src/components/dock/BottomDock.tsx +2 -3
  56. package/src/components/dock/DockContext.tsx +1 -0
  57. package/src/components/dock/TerminalTab.tsx +1 -1
  58. package/src/components/dock/WorkloadLogsTab.tsx +21 -5
  59. package/src/components/dock/index.ts +1 -1
  60. package/src/components/execution/BatchExecutionView.test.ts +170 -0
  61. package/src/components/execution/BatchExecutionView.tsx +1329 -0
  62. package/src/components/execution/batch-run-actions.test.ts +48 -0
  63. package/src/components/execution/batch-run-actions.ts +24 -0
  64. package/src/components/execution/batch-timeline.test.ts +57 -0
  65. package/src/components/execution/batch-timeline.ts +46 -0
  66. package/src/components/execution/execution-definition.test.ts +208 -0
  67. package/src/components/execution/execution-definition.ts +245 -0
  68. package/src/components/gitops/ArgoResourceDiffLoader.tsx +23 -0
  69. package/src/components/gitops/GitOpsView.tsx +1042 -0
  70. package/src/components/gitops/RevisionMetaChip.tsx +63 -0
  71. package/src/components/helm/ChartBrowser.tsx +87 -31
  72. package/src/components/helm/HelmCompareRoute.tsx +1341 -0
  73. package/src/components/helm/HelmReleaseDrawer.test.ts +17 -0
  74. package/src/components/helm/HelmReleaseDrawer.tsx +1073 -102
  75. package/src/components/helm/HelmView.tsx +237 -96
  76. package/src/components/helm/InstallWizard.tsx +94 -38
  77. package/src/components/helm/ManifestDiffViewer.tsx +8 -27
  78. package/src/components/helm/OwnedResources.tsx +34 -59
  79. package/src/components/helm/RevisionHistory.tsx +52 -3
  80. package/src/components/helm/RoleGatedPanel.tsx +3 -3
  81. package/src/components/helm/TrackChartSourceDialog.tsx +185 -0
  82. package/src/components/helm/ValuesDiffPreview.tsx +17 -7
  83. package/src/components/helm/ValuesViewer.tsx +49 -53
  84. package/src/components/helm/helm-utils.ts +4 -0
  85. package/src/components/home/ActivitySummary.tsx +4 -1
  86. package/src/components/home/ClusterHealthCard.tsx +56 -42
  87. package/src/components/home/CostCard.tsx +21 -36
  88. package/src/components/home/GitOpsControllersCard.tsx +110 -0
  89. package/src/components/home/HelmSummary.tsx +3 -1
  90. package/src/components/home/HomeView.tsx +339 -105
  91. package/src/components/home/MCPSetupDialog.tsx +29 -87
  92. package/src/components/home/TrafficSummary.tsx +2 -2
  93. package/src/components/home/mcpToolCatalog.ts +333 -0
  94. package/src/components/issues/IssuesPane.tsx +151 -0
  95. package/src/components/logs/LogsViewer.tsx +4 -1
  96. package/src/components/logs/ScheduledWorkloadLogsViewer.tsx +135 -0
  97. package/src/components/logs/WorkloadLogsViewer.tsx +4 -1
  98. package/src/components/nav/PrimaryNavRail.tsx +285 -0
  99. package/src/components/portforward/PortForwardButton.tsx +118 -47
  100. package/src/components/portforward/PortForwardManager.tsx +253 -131
  101. package/src/components/resource/HPACharts.tsx +237 -0
  102. package/src/components/resource/PVCUsageBar.tsx +59 -0
  103. package/src/components/resource/PrometheusCharts.tsx +160 -584
  104. package/src/components/resource/PrometheusChartsGrid.tsx +270 -0
  105. package/src/components/resource/RestartChart.tsx +133 -0
  106. package/src/components/resource/RightsizingStrip.test.ts +109 -0
  107. package/src/components/resource/RightsizingStrip.tsx +363 -0
  108. package/src/components/resource-drawer/ResourceDrawer.tsx +3 -1
  109. package/src/components/resources/CompositeRenderer.tsx +101 -0
  110. package/src/components/resources/ImageFilesystemModal.tsx +19 -12
  111. package/src/components/resources/PodFilesystemModal.tsx +6 -5
  112. package/src/components/resources/ResourceDetailDrawer.tsx +13 -3
  113. package/src/components/resources/ResourcesView.tsx +194 -17
  114. package/src/components/resources/renderers/CronWorkflowRenderer.tsx +1 -0
  115. package/src/components/resources/renderers/HPARenderer.tsx +20 -1
  116. package/src/components/resources/renderers/NamespaceRenderer.tsx +31 -0
  117. package/src/components/resources/renderers/NodeRenderer.tsx +10 -4
  118. package/src/components/resources/renderers/PVCRenderer.tsx +19 -1
  119. package/src/components/resources/renderers/PodRenderer.tsx +30 -6
  120. package/src/components/resources/renderers/RoleBindingRenderer.tsx +45 -1
  121. package/src/components/resources/renderers/RoleRenderer.tsx +27 -1
  122. package/src/components/resources/renderers/ServiceAccountRenderer.tsx +28 -1
  123. package/src/components/resources/renderers/ServiceRenderer.tsx +81 -8
  124. package/src/components/resources/renderers/WorkloadRenderer.tsx +51 -4
  125. package/src/components/resources/renderers/index.ts +2 -0
  126. package/src/components/resources/resource-utils.ts +2 -1
  127. package/src/components/rightsizing/RightsizingScanView.tsx +938 -0
  128. package/src/components/rightsizing/copy.test.ts +56 -0
  129. package/src/components/rightsizing/model.test.ts +227 -0
  130. package/src/components/rightsizing/model.ts +158 -0
  131. package/src/components/rightsizing/presentation.test.ts +104 -0
  132. package/src/components/rightsizing/presentation.ts +94 -0
  133. package/src/components/settings/MyPermissionsDialog.tsx +241 -0
  134. package/src/components/settings/SettingsDialog.tsx +1505 -165
  135. package/src/components/shared/CreateResourceDialog.tsx +9 -2
  136. package/src/components/shared/LargeClusterNamespacePicker.tsx +3 -3
  137. package/src/components/timeline/LocalTimelineScrubber.tsx +212 -0
  138. package/src/components/timeline/RetainedTimelineScrubber.tsx +311 -0
  139. package/src/components/timeline/TimelineList.tsx +86 -13
  140. package/src/components/timeline/TimelineSwimlanes.tsx +9 -1299
  141. package/src/components/timeline/TimelineView.tsx +873 -24
  142. package/src/components/timeline/TimelineView.urlparams.test.ts +335 -0
  143. package/src/components/traffic/TrafficFilterSidebar.tsx +10 -45
  144. package/src/components/traffic/TrafficFlowList.tsx +29 -15
  145. package/src/components/traffic/TrafficGraph.tsx +42 -24
  146. package/src/components/traffic/TrafficView.tsx +32 -19
  147. package/src/components/ui/CommandPalette.tsx +8 -215
  148. package/src/components/ui/DiagnosticsOverlay.tsx +219 -9
  149. package/src/components/ui/Markdown.tsx +3 -3
  150. package/src/components/ui/Omnibar.tsx +602 -0
  151. package/src/components/ui/RadarOmnibar.tsx +52 -0
  152. package/src/components/ui/SearchSyntaxHelp.tsx +89 -0
  153. package/src/components/ui/ShortcutHelpOverlay.tsx +3 -2
  154. package/src/components/ui/UpdateNotification.tsx +48 -36
  155. package/src/components/ui/command-items.ts +178 -0
  156. package/src/components/workload/WorkloadView.tsx +1342 -158
  157. package/src/context/ConnectionContext.tsx +146 -21
  158. package/src/context/DiagnoseCustomization.tsx +93 -0
  159. package/src/context/NavCustomization.tsx +75 -0
  160. package/src/context/TimelineSource.tsx +50 -0
  161. package/src/contexts/CapabilitiesContext.tsx +32 -8
  162. package/src/filter/FilterLocationBridge.tsx +30 -0
  163. package/src/hooks/useClusterLoadState.ts +73 -0
  164. package/src/hooks/useDocumentTitle.ts +25 -0
  165. package/src/hooks/useEventSource.ts +6 -0
  166. package/src/hooks/useKeyboardShortcuts.tsx +1 -0
  167. package/src/hooks/useMediaQuery.ts +21 -0
  168. package/src/hooks/useNavRailPinned.ts +46 -0
  169. package/src/hooks/useRecentResources.ts +49 -0
  170. package/src/index.css +162 -1
  171. package/src/index.ts +73 -1
  172. package/src/main.tsx +7 -5
  173. package/src/types/clusterLoadState.ts +33 -0
  174. package/src/types.ts +2 -0
  175. package/src/utils/auditBadges.ts +53 -0
  176. package/src/utils/navigation.ts +64 -1
  177. package/src/components/ui/NamespaceSelector.tsx +0 -436
@@ -1,6 +1,8 @@
1
1
  import { useRef, useEffect, useState, useCallback } from 'react'
2
2
  import { X, Copy, Check, Radio, Terminal, MessageSquare, Code2, ChevronRight, Pin } from 'lucide-react'
3
3
  import { apiUrl, getAuthHeaders, getCredentialsMode } from '../../api/config'
4
+ import { MCP_TOOL_CATALOG } from './mcpToolCatalog'
5
+ import { Tooltip } from '../ui/Tooltip'
4
6
 
5
7
  interface MCPSetupDialogProps {
6
8
  open: boolean
@@ -18,13 +20,14 @@ function CopyButton({ text }: { text: string }) {
18
20
  }
19
21
 
20
22
  return (
23
+ <Tooltip content="Copy to clipboard" position="left" wrapperClassName="absolute top-2 right-2">
21
24
  <button
22
25
  onClick={handleCopy}
23
- className="absolute top-2 right-2 p-1.5 rounded-md bg-theme-elevated/50 hover:bg-theme-elevated text-theme-text-tertiary hover:text-theme-text-secondary transition-colors"
24
- title="Copy to clipboard"
26
+ className="p-1.5 rounded-md bg-theme-elevated/50 hover:bg-theme-elevated text-theme-text-tertiary hover:text-theme-text-secondary transition-colors"
25
27
  >
26
28
  {copied ? <Check className="w-3.5 h-3.5 text-green-500" /> : <Copy className="w-3.5 h-3.5" />}
27
29
  </button>
30
+ </Tooltip>
28
31
  )
29
32
  }
30
33
 
@@ -201,15 +204,16 @@ export function MCPSetupDialog({ open, onClose, mcpUrl }: MCPSetupDialogProps) {
201
204
  <a href="https://modelcontextprotocol.io" target="_blank" rel="noopener noreferrer" className="text-purple-400 hover:text-purple-300 underline underline-offset-2">
202
205
  Model Context Protocol
203
206
  </a>{' '}
204
- (MCP) server that lets AI assistants query your cluster through Radar.
207
+ (MCP) server that lets AI agents query your cluster through Radar.
205
208
  Unlike raw kubectl access, Radar gives your AI pre-processed, enriched data —
206
209
  topology graphs, health assessments, deduplicated events, filtered logs — so it
207
210
  can understand your cluster state quickly without burning through context on
208
211
  verbose YAML output.
209
212
  </p>
210
213
  <p className="text-sm text-theme-text-secondary leading-relaxed">
211
- Read tools are strictly read-only. Write tools (restart, scale, sync) are
212
- non-destructive and annotated so your AI client can distinguish them.
214
+ Read tools are strictly read-only. Write tools (restart, scale, sync, apply,
215
+ node drain) are annotated as destructive so your AI client can flag them and
216
+ prompt before running.
213
217
  </p>
214
218
  </div>
215
219
 
@@ -219,7 +223,7 @@ export function MCPSetupDialog({ open, onClose, mcpUrl }: MCPSetupDialogProps) {
219
223
  <div className="relative">
220
224
  <div className="flex items-center gap-3 bg-theme-base rounded-md px-3 py-2.5">
221
225
  <span className="badge text-purple-400 bg-purple-500/10">HTTP</span>
222
- <code className="text-sm font-mono text-theme-text-primary">{mcpUrl}</code>
226
+ <code className="inline-code text-sm">{mcpUrl}</code>
223
227
  </div>
224
228
  <CopyButton text={mcpUrl} />
225
229
  </div>
@@ -296,95 +300,33 @@ export function MCPSetupDialog({ open, onClose, mcpUrl }: MCPSetupDialogProps) {
296
300
 
297
301
  {/* Available tools */}
298
302
  <div className="space-y-2">
299
- <h4 className="text-sm font-semibold text-theme-text-primary">Tools</h4>
303
+ <div className="flex items-baseline justify-between">
304
+ <h4 className="text-sm font-semibold text-theme-text-primary">Tools</h4>
305
+ <span className="text-[11px] text-theme-text-tertiary">{MCP_TOOL_CATALOG.length} tools</span>
306
+ </div>
300
307
  <div className="grid grid-cols-1 gap-1.5">
301
- {[
302
- { name: 'get_dashboard', desc: 'Get cluster health overview including resource counts, problems (failing pods, unhealthy deployments), recent warning events, and Helm release status. Start here to understand cluster state before drilling into specific resources.', params: [
303
- { name: 'namespace', required: false, desc: 'filter to a specific namespace' },
304
- ]},
305
- { name: 'list_resources', desc: 'List Kubernetes resources of a given kind with minified summaries. Supports all built-in kinds (pods, deployments, services, etc.) and CRDs. Use to discover what\'s running before inspecting individual resources.', params: [
306
- { name: 'kind', required: true, desc: 'resource kind, e.g. pods, deployments, services' },
307
- { name: 'namespace', required: false, desc: 'filter to a specific namespace' },
308
- ]},
309
- { name: 'get_resource', desc: 'Get detailed information about a single Kubernetes resource. Returns minified spec, status, and metadata. Optionally include related context (events, relationships, metrics, logs) to avoid extra tool calls.', params: [
310
- { name: 'kind', required: true, desc: 'resource kind, e.g. pod, deployment, service' },
311
- { name: 'namespace', required: true, desc: 'resource namespace' },
312
- { name: 'name', required: true, desc: 'resource name' },
313
- { name: 'include', required: false, desc: 'events, relationships, metrics, logs' },
314
- ]},
315
- { name: 'get_topology', desc: 'Get the topology graph showing relationships between Kubernetes resources. Returns nodes and edges representing Deployments, Services, Ingresses, Pods, etc. Use \'traffic\' view for network flow or \'resources\' view for ownership hierarchy. Use \'summary\' format for LLM-friendly text descriptions.', params: [
316
- { name: 'namespace', required: false, desc: 'filter to a specific namespace' },
317
- { name: 'view', required: false, desc: 'traffic or resources' },
318
- { name: 'format', required: false, desc: 'graph (default) or summary (text)' },
319
- ]},
320
- { name: 'get_events', desc: 'Get recent Kubernetes warning events, deduplicated and sorted by recency. Useful for diagnosing issues — shows event reason, message, and occurrence count. Filter by resource kind/name to scope to a specific resource.', params: [
321
- { name: 'namespace', required: false, desc: 'filter to a specific namespace' },
322
- { name: 'limit', required: false, desc: 'max events to return (default 20)' },
323
- { name: 'kind', required: false, desc: 'filter to events for this resource kind' },
324
- { name: 'name', required: false, desc: 'filter to events for this resource name' },
325
- ]},
326
- { name: 'get_pod_logs', desc: 'Get filtered log lines from a pod, prioritizing errors and warnings. Returns diagnostically relevant lines (errors, panics, stack traces) or falls back to the last 20 lines if no error patterns match.', params: [
327
- { name: 'namespace', required: true, desc: 'pod namespace' },
328
- { name: 'name', required: true, desc: 'pod name' },
329
- { name: 'container', required: false, desc: 'container name (defaults to first)' },
330
- { name: 'tail_lines', required: false, desc: 'lines from end (default 200)' },
331
- ]},
332
- { name: 'list_namespaces', desc: 'List all Kubernetes namespaces with their status. Use to discover available namespaces before filtering other queries.', params: [] },
333
- { name: 'get_changes', desc: 'Get recent resource changes (creates, updates, deletes) from the cluster timeline. Use to investigate what changed before an incident. Filter by namespace, resource kind, or specific resource name.', params: [
334
- { name: 'namespace', required: false, desc: 'filter to a specific namespace' },
335
- { name: 'kind', required: false, desc: 'filter to a resource kind (e.g. Deployment)' },
336
- { name: 'name', required: false, desc: 'filter to a specific resource name' },
337
- { name: 'since', required: false, desc: 'lookback duration, e.g. 1h, 30m (default 1h)' },
338
- { name: 'limit', required: false, desc: 'max changes to return (default 20, max 50)' },
339
- ]},
340
- { name: 'list_helm_releases', desc: 'List all Helm releases in the cluster with their status and health. Returns release name, namespace, chart, version, status, and resource health.', params: [
341
- { name: 'namespace', required: false, desc: 'filter to a specific namespace' },
342
- ]},
343
- { name: 'get_helm_release', desc: 'Get detailed information about a specific Helm release including owned resources and their status. Optionally include values, revision history, or manifest diff between revisions.', params: [
344
- { name: 'namespace', required: true, desc: 'release namespace' },
345
- { name: 'name', required: true, desc: 'release name' },
346
- { name: 'include', required: false, desc: 'values, history, diff' },
347
- { name: 'diff_revision_1', required: false, desc: 'first revision for diff' },
348
- { name: 'diff_revision_2', required: false, desc: 'second revision for diff (defaults to current)' },
349
- ]},
350
- { name: 'get_workload_logs', desc: 'Get aggregated, AI-filtered logs from all pods of a workload (Deployment, StatefulSet, or DaemonSet). Logs are collected from all matching pods, filtered for errors/warnings, and deduplicated.', params: [
351
- { name: 'kind', required: true, desc: 'deployment, statefulset, or daemonset' },
352
- { name: 'namespace', required: true, desc: 'workload namespace' },
353
- { name: 'name', required: true, desc: 'workload name' },
354
- { name: 'container', required: false, desc: 'specific container name' },
355
- { name: 'tail_lines', required: false, desc: 'lines per pod (default 100)' },
356
- ]},
357
- { name: 'manage_workload', desc: 'Perform operations on a workload. \'restart\' triggers a rolling restart, \'scale\' changes the replica count, \'rollback\' reverts to a previous revision.', params: [
358
- { name: 'action', required: true, desc: 'restart, scale, or rollback' },
359
- { name: 'kind', required: true, desc: 'deployment, statefulset, or daemonset' },
360
- { name: 'namespace', required: true, desc: 'workload namespace' },
361
- { name: 'name', required: true, desc: 'workload name' },
362
- { name: 'replicas', required: false, desc: 'target replica count (for scale)' },
363
- { name: 'revision', required: false, desc: 'target revision (for rollback)' },
364
- ]},
365
- { name: 'manage_cronjob', desc: 'Perform operations on a CronJob. \'trigger\' creates a manual Job run, \'suspend\' pauses the schedule, \'resume\' re-enables it.', params: [
366
- { name: 'action', required: true, desc: 'trigger, suspend, or resume' },
367
- { name: 'namespace', required: true, desc: 'cronjob namespace' },
368
- { name: 'name', required: true, desc: 'cronjob name' },
369
- ]},
370
- { name: 'manage_gitops', desc: 'Perform operations on GitOps resources. ArgoCD: sync, suspend, resume. FluxCD: reconcile, suspend, resume.', params: [
371
- { name: 'action', required: true, desc: 'sync/reconcile, suspend, or resume' },
372
- { name: 'tool', required: true, desc: 'argocd or fluxcd' },
373
- { name: 'namespace', required: true, desc: 'resource namespace' },
374
- { name: 'name', required: true, desc: 'resource name' },
375
- { name: 'kind', required: false, desc: 'FluxCD resource kind (e.g. kustomization, helmrelease)' },
376
- ]},
377
- ].map((tool) => (
308
+ {MCP_TOOL_CATALOG.map((tool) => (
378
309
  <div key={tool.name} className="card-inner space-y-1.5">
379
- <code className="text-[11px] font-mono text-purple-400">{tool.name}</code>
310
+ <div className="flex items-center gap-2">
311
+ <code className="inline-code text-[11px]">{tool.name}</code>
312
+ {tool.write && (
313
+ <Tooltip content="Write tool — annotated as destructive">
314
+ <span className="badge-sm bg-amber-500/10 text-amber-600 dark:text-amber-400">
315
+ write
316
+ </span>
317
+ </Tooltip>
318
+ )}
319
+ </div>
380
320
  <p className="text-[11px] text-theme-text-tertiary leading-relaxed">{tool.desc}</p>
381
321
  {tool.params.length > 0 && (
382
322
  <div className="flex flex-wrap gap-1.5 pt-0.5">
383
323
  {tool.params.map((p) => (
384
- <span key={p.name} className="badge-sm font-mono bg-theme-elevated text-theme-text-secondary" title={p.desc}>
385
- <span className="text-theme-text-secondary">{p.name}</span>
324
+ <Tooltip key={p.arg} content={p.desc}>
325
+ <span className="inline-code text-[11px]">
326
+ <span>{p.arg}</span>
386
327
  {p.required && <span className="text-red-400">*</span>}
387
328
  </span>
329
+ </Tooltip>
388
330
  ))}
389
331
  </div>
390
332
  )}
@@ -100,7 +100,7 @@ export function TrafficSummary({ data, onNavigate }: TrafficSummaryProps) {
100
100
  <div className="flex items-center justify-between px-5 py-3 border-b border-theme-border/50">
101
101
  <div className="flex items-center gap-2">
102
102
  <Activity className="w-4 h-4 text-theme-text-tertiary" />
103
- <span className="text-xs font-semibold uppercase tracking-wider text-theme-text-secondary">Traffic</span>
103
+ <span className="text-xs font-semibold uppercase tracking-wider text-theme-text-secondary">Live Traffic</span>
104
104
  </div>
105
105
  {hasFlows && (
106
106
  <span className="text-[11px] text-theme-text-tertiary">
@@ -145,7 +145,7 @@ export function TrafficSummary({ data, onNavigate }: TrafficSummaryProps) {
145
145
  </div>
146
146
 
147
147
  <div className="px-4 py-1.5 border-t border-theme-border/50 flex items-center justify-end gap-1.5 text-[10px] font-semibold uppercase tracking-wider text-theme-text-secondary group-hover:text-theme-text-primary transition-colors">
148
- Open Traffic
148
+ Open Live Traffic
149
149
  <ArrowRight className="w-3.5 h-3.5 transition-transform group-hover:translate-x-0.5" />
150
150
  </div>
151
151
  </div>
@@ -0,0 +1,333 @@
1
+ // Human-facing catalog for the MCP setup dialog (MCPSetupDialog.tsx).
2
+ //
3
+ // Source of truth for the *set* of tools is the backend registration in
4
+ // internal/mcp/tools.go. This list must stay in sync with it — the Go test
5
+ // TestSetupDialogCoversAllTools (internal/mcp/tools_catalog_test.go) parses
6
+ // this file and fails CI if the tool names here don't exactly match the
7
+ // registered tools. When you add or remove an MCP tool there, update this
8
+ // catalog too.
9
+ //
10
+ // Descriptions here are intentionally shorter and more human-facing than the
11
+ // LLM-oriented routing descriptions in tools.go — different audience, so they
12
+ // are not shared verbatim.
13
+
14
+ export interface MCPToolParam {
15
+ arg: string
16
+ required?: boolean
17
+ desc: string
18
+ }
19
+
20
+ export interface MCPToolInfo {
21
+ name: string
22
+ write?: boolean
23
+ desc: string
24
+ params: MCPToolParam[]
25
+ }
26
+
27
+ export const MCP_TOOL_CATALOG: MCPToolInfo[] = [
28
+ {
29
+ name: 'get_dashboard',
30
+ desc: 'Cluster or namespace health overview: resource counts, failing pods, unhealthy workloads, recent warning events, and Helm status. Start here before drilling into specific resources.',
31
+ params: [{ arg: 'namespace', desc: 'filter to a specific namespace' }],
32
+ },
33
+ {
34
+ name: 'top_resources',
35
+ desc: 'Live CPU/memory ranking (like `kubectl top`) joined with Kubernetes context — pod status, restarts, owner workload, requests, and limits. Ranks pods, workloads, or nodes.',
36
+ params: [
37
+ { arg: 'kind', desc: 'pods (default), workloads, or nodes' },
38
+ { arg: 'namespace', desc: 'filter pods/workloads to a namespace' },
39
+ { arg: 'sort', desc: 'cpu (default) or memory' },
40
+ { arg: 'limit', desc: 'max rows (default 20, max 100)' },
41
+ ],
42
+ },
43
+ {
44
+ name: 'list_resources',
45
+ desc: 'List Kubernetes resources of a given kind with compact summaries plus per-row health, managedBy, and issue counts. Supports built-in kinds and CRDs.',
46
+ params: [
47
+ { arg: 'kind', required: true, desc: 'resource kind, e.g. pods, deployments, services' },
48
+ { arg: 'group', desc: 'API group when the kind is ambiguous (e.g. serving.knative.dev)' },
49
+ { arg: 'namespace', desc: 'filter to a specific namespace' },
50
+ { arg: 'context', desc: 'per-row context: default (summaryContext) or none' },
51
+ ],
52
+ },
53
+ {
54
+ name: 'get_resource',
55
+ desc: 'A single resource: minified spec/status/metadata plus resourceContext (relationships, refs, issue/audit/policy rollups). Optionally include heavier event/metrics data.',
56
+ params: [
57
+ { arg: 'kind', required: true, desc: 'resource kind, e.g. pod, deployment, service' },
58
+ { arg: 'name', required: true, desc: 'resource name' },
59
+ { arg: 'namespace', desc: 'omit for cluster-scoped kinds (Node, ClusterRole, IngressClass, etc.)' },
60
+ { arg: 'group', desc: 'API group when the kind is ambiguous (e.g. serving.knative.dev for Knative Service vs core Service)' },
61
+ { arg: 'include', desc: 'events, metrics' },
62
+ { arg: 'context', desc: 'resourceContext tier: basic (default) or none' },
63
+ ],
64
+ },
65
+ {
66
+ name: 'get_topology',
67
+ desc: 'Topology graph of relationships between resources — Services, workloads, Pods, Ingresses, owners. Use traffic view for network flow or resources view for ownership hierarchy.',
68
+ params: [
69
+ { arg: 'namespace', desc: 'filter to a specific namespace' },
70
+ { arg: 'view', desc: 'traffic or resources' },
71
+ { arg: 'format', desc: 'graph (default) or summary (text)' },
72
+ ],
73
+ },
74
+ {
75
+ name: 'get_neighborhood',
76
+ desc: 'BFS-expanded topology around one resource — its upstream/downstream Services, workloads, Pods, refs, and owners. Cheaper and more focused than full topology once you have a suspect.',
77
+ params: [
78
+ { arg: 'kind', required: true, desc: 'resource kind, e.g. pod, deployment, service, application' },
79
+ { arg: 'name', required: true, desc: 'resource name' },
80
+ { arg: 'namespace', desc: 'resource namespace; omit for cluster-scoped kinds' },
81
+ { arg: 'group', desc: 'API group to disambiguate colliding kinds' },
82
+ { arg: 'profile', desc: 'auto (default) or all (every edge type, heavier)' },
83
+ { arg: 'hops', desc: 'BFS depth (default 1, max 2)' },
84
+ { arg: 'max_nodes', desc: 'node budget (default 25)' },
85
+ ],
86
+ },
87
+ {
88
+ name: 'get_events',
89
+ desc: 'Recent Kubernetes warning events, deduplicated and sorted by recency. Shows reason, message, and occurrence count. Filter to a specific resource by kind/name.',
90
+ params: [
91
+ { arg: 'namespace', desc: 'filter to a specific namespace' },
92
+ { arg: 'limit', desc: 'max events (default 20, max 100)' },
93
+ { arg: 'kind', desc: 'filter to events for this resource kind' },
94
+ { arg: 'name', desc: 'filter to events for this resource name' },
95
+ ],
96
+ },
97
+ {
98
+ name: 'get_pod_logs',
99
+ desc: 'Pod logs with secret redaction. Without grep, prioritizes errors and warnings and falls back to recent tail lines; grep returns only regex matches instead.',
100
+ params: [
101
+ { arg: 'namespace', required: true, desc: 'pod namespace' },
102
+ { arg: 'name', required: true, desc: 'pod name' },
103
+ { arg: 'container', desc: 'container name (defaults to first)' },
104
+ { arg: 'tail_lines', desc: 'lines from end (default 200)' },
105
+ { arg: 'grep', desc: 'regex matches to return instead of diagnostic auto-filtering' },
106
+ { arg: 'since', desc: 'only logs newer than this duration (e.g. 30s, 10m, 1h)' },
107
+ { arg: 'previous', desc: 'logs from the previous terminated container (CrashLoopBackOff)' },
108
+ ],
109
+ },
110
+ {
111
+ name: 'diagnose',
112
+ desc: 'One-call root-cause bundle. Workloads get spec + resourceContext + current AND previous logs across pods + warning events + startup blockers; GitOps reconcilers, including Flux HelmRelease, get status summary + parsed related issues.',
113
+ params: [
114
+ { arg: 'kind', required: true, desc: 'pod, deployment, statefulset, daemonset, application, kustomization, or Flux HelmRelease' },
115
+ { arg: 'namespace', required: true, desc: 'resource namespace' },
116
+ { arg: 'name', required: true, desc: 'resource name' },
117
+ { arg: 'container', desc: 'specific container (defaults to all)' },
118
+ { arg: 'tail_lines', desc: 'lines per pod/stream (default 100)' },
119
+ { arg: 'since', desc: 'only logs newer than this duration' },
120
+ ],
121
+ },
122
+ {
123
+ name: 'list_namespaces',
124
+ desc: 'List all Kubernetes namespaces with their status. Use to discover available namespaces before filtering other queries.',
125
+ params: [],
126
+ },
127
+ {
128
+ name: 'get_changes',
129
+ desc: 'Recent meaningful changes from the Kubernetes timeline plus native Helm deployment history (source=helm). Includes failed upgrades, rollbacks, and current Helm revisions; sourcesErrored marks partial source failures.',
130
+ params: [
131
+ { arg: 'namespace', desc: 'filter to a specific namespace' },
132
+ { arg: 'kind', desc: 'filter to a resource kind (e.g. Deployment)' },
133
+ { arg: 'name', desc: 'filter to a specific resource name' },
134
+ { arg: 'since', desc: 'lookback duration, e.g. 1h, 30m (default 1h)' },
135
+ { arg: 'limit', desc: 'max changes (default 20, max 50)' },
136
+ ],
137
+ },
138
+ {
139
+ name: 'get_cluster_audit',
140
+ desc: 'Best-practice and security posture findings — Security, Reliability, Efficiency — each with remediation guidance. Static config posture, independent of live operational health.',
141
+ params: [
142
+ { arg: 'namespace', desc: 'filter to a specific namespace' },
143
+ { arg: 'category', desc: 'Security, Reliability, or Efficiency' },
144
+ { arg: 'severity', desc: 'danger or warning' },
145
+ { arg: 'limit', desc: 'max findings (default 30, max 100)' },
146
+ ],
147
+ },
148
+ {
149
+ name: 'list_helm_releases',
150
+ desc: 'All Helm releases with status, resource health, storage namespace, Flux ownership, current lastOperation, and capped operation trails for failed upgrades, rollbacks, or stuck pending operations.',
151
+ params: [{ arg: 'namespace', desc: 'filter to a specific namespace' }],
152
+ },
153
+ {
154
+ name: 'get_helm_release',
155
+ desc: 'Detailed Helm release info with owned resources, health, Flux ownership, current lastOperation, operationInsight, hooks, and failed/running hook diagnostics with live Job/Pod/Event/redacted-log evidence when available.',
156
+ params: [
157
+ { arg: 'namespace', required: true, desc: 'Helm storage namespace; use storageNamespace from list_helm_releases when present' },
158
+ { arg: 'name', required: true, desc: 'release name' },
159
+ { arg: 'include', desc: 'values, history, operations, diff, values_diff, notes_diff, resource_diff' },
160
+ { arg: 'diff_revision_1', desc: 'first revision for any diff include' },
161
+ { arg: 'diff_revision_2', desc: 'second revision for any diff include (defaults to current)' },
162
+ ],
163
+ },
164
+ {
165
+ name: 'list_packages',
166
+ desc: 'Unified "what\'s installed" view across Helm releases, workload labels, CRD registrations, and GitOps declarations (Argo + Flux), with sources, versions, health, and a sourceLegend for the stable source codes.',
167
+ params: [
168
+ { arg: 'namespace', desc: 'filter to a specific namespace' },
169
+ { arg: 'source', desc: 'H/helm, L/labels, C/crds, A/argocd, F/fluxcd' },
170
+ { arg: 'chart', desc: 'case-insensitive chart-name substring' },
171
+ ],
172
+ },
173
+ {
174
+ name: 'issues',
175
+ desc: 'Ranked list of what is broken right now — failing workloads, active native Helm release failures or stuck pending operations, dangling references, scheduling blockers, and false CRD conditions. Native Helm rows use group=helm.sh.',
176
+ params: [
177
+ { arg: 'namespace', desc: 'filter to one namespace' },
178
+ { arg: 'severity', desc: 'comma-separated: critical, warning' },
179
+ { arg: 'kind', desc: 'comma-separated kind filter' },
180
+ { arg: 'limit', desc: 'max issues (default 200, max 1000)' },
181
+ { arg: 'filter', desc: 'optional CEL boolean expression' },
182
+ ],
183
+ },
184
+ {
185
+ name: 'search',
186
+ desc: 'Find resources by content/term match — config keys, env refs, images, label values, ConfigMap data, CRD fields, status messages. Secret values are never indexed.',
187
+ params: [
188
+ { arg: 'query', required: true, desc: 'tokens AND\'d; modifiers kind:, ns:, label:, image:' },
189
+ { arg: 'limit', desc: 'max hits (default 50, max 500)' },
190
+ { arg: 'include', desc: 'summary (default), raw, or none' },
191
+ { arg: 'filter', desc: 'optional CEL boolean expression' },
192
+ { arg: 'context', desc: 'per-hit context: default (summaryContext) or none' },
193
+ ],
194
+ },
195
+ {
196
+ name: 'get_subject_permissions',
197
+ desc: 'Effective RBAC for a ServiceAccount, User, or Group. Returns the full bindings/rules dump by default, or an authoritative SubjectAccessReview answer when verb and resource are supplied for a ServiceAccount.',
198
+ params: [
199
+ { arg: 'kind', required: true, desc: 'ServiceAccount, User, or Group' },
200
+ { arg: 'name', required: true, desc: 'subject name' },
201
+ { arg: 'namespace', desc: 'required for ServiceAccount; omit for User/Group' },
202
+ { arg: 'verb', desc: 'access check: Kubernetes API verb; requires resource' },
203
+ { arg: 'resource', desc: 'access check: plural API resource; requires verb' },
204
+ { arg: 'group', desc: 'access check: API group; omit for core/v1' },
205
+ { arg: 'resource_namespace', desc: 'access check target; defaults to subject namespace' },
206
+ { arg: 'subresource', desc: 'access check subresource, e.g. log for pods/log' },
207
+ { arg: 'resource_name', desc: 'access check target resource name' },
208
+ ],
209
+ },
210
+ {
211
+ name: 'query_prometheus',
212
+ desc: "Run PromQL against the cluster's Prometheus (auto-discovered or configured; works with Thanos, VictoriaMetrics, Mimir). Instant queries return current values; range queries return time-series history with automatic step adjustment. Oversized results return a cardinality summary with a suggested topk rewrite instead of raw data.",
213
+ params: [
214
+ { arg: 'query', required: true, desc: 'PromQL query to execute' },
215
+ { arg: 'type', desc: 'instant (default) or range' },
216
+ { arg: 'since', desc: 'range lookback, e.g. 30m, 1h, 24h, 7d (default 1h)' },
217
+ { arg: 'start', desc: 'range RFC3339 start time; overrides since' },
218
+ { arg: 'end', desc: 'range RFC3339 end time (default now)' },
219
+ { arg: 'step', desc: 'range resolution, e.g. 30s, 5m (auto-calculated when omitted)' },
220
+ { arg: 'max_points', desc: 'max data points per series (default 300, max 600)' },
221
+ { arg: 'timeout', desc: 'query timeout in seconds (default 30, max 180)' },
222
+ ],
223
+ },
224
+ {
225
+ name: 'discover_metrics',
226
+ desc: 'Discover exact Prometheus metric names (with type and help text) or values of one label before writing PromQL. Lists active series from the last hour; flags truncation so the selector can be narrowed.',
227
+ params: [
228
+ { arg: 'match', desc: 'PromQL series selector filter, e.g. {__name__=~"node_cpu.*"}; required when label is empty' },
229
+ { arg: 'label', desc: 'discover values of this label instead of metric names, e.g. namespace, pod' },
230
+ { arg: 'limit', desc: 'max values returned (default 100, max 500)' },
231
+ ],
232
+ },
233
+ {
234
+ name: 'get_prometheus_rules',
235
+ desc: 'List Prometheus alerting and recording rules with their PromQL definitions, state (firing/pending/inactive), and active alert instances. The starting point for alert investigation: fetch the rule, then query its expression.',
236
+ params: [
237
+ { arg: 'type', desc: 'alert or record (omit for both)' },
238
+ { arg: 'name', desc: 'substring filter on rule name' },
239
+ { arg: 'group', desc: 'substring filter on rule group name' },
240
+ { arg: 'state', desc: 'alerting rules only: firing, pending, or inactive' },
241
+ { arg: 'limit', desc: 'max rules returned (default 50, max 200)' },
242
+ ],
243
+ },
244
+ {
245
+ name: 'get_workload_logs',
246
+ desc: 'Aggregated logs across all pods of a workload. Without grep, filters for diagnostic relevance; grep returns only matching timestamp-prefixed lines instead.',
247
+ params: [
248
+ { arg: 'kind', desc: 'deployment (default), statefulset, daemonset, job, or workflow' },
249
+ { arg: 'namespace', required: true, desc: 'workload namespace' },
250
+ { arg: 'name', required: true, desc: 'workload name' },
251
+ { arg: 'container', desc: 'specific container (defaults to all)' },
252
+ { arg: 'tail_lines', desc: 'lines per pod (default 100)' },
253
+ { arg: 'grep', desc: 'regex matches to return instead of diagnostic auto-filtering' },
254
+ { arg: 'since', desc: 'only logs newer than this duration' },
255
+ { arg: 'previous', desc: 'logs from the previous terminated container' },
256
+ ],
257
+ },
258
+ {
259
+ name: 'manage_workload',
260
+ write: true,
261
+ desc: 'Operate on a workload: restart triggers a rolling restart, scale changes the replica count, rollback reverts to a previous revision.',
262
+ params: [
263
+ { arg: 'action', required: true, desc: 'restart, scale, or rollback' },
264
+ { arg: 'kind', required: true, desc: 'deployment, statefulset, or daemonset' },
265
+ { arg: 'namespace', required: true, desc: 'workload namespace' },
266
+ { arg: 'name', required: true, desc: 'workload name' },
267
+ { arg: 'replicas', desc: 'target replica count (for scale)' },
268
+ { arg: 'revision', desc: 'target revision (for rollback)' },
269
+ ],
270
+ },
271
+ {
272
+ name: 'manage_cronjob',
273
+ write: true,
274
+ desc: 'Operate on a CronJob: trigger creates a manual Job run, suspend pauses the schedule, resume re-enables it.',
275
+ params: [
276
+ { arg: 'action', required: true, desc: 'trigger, suspend, or resume' },
277
+ { arg: 'namespace', required: true, desc: 'cronjob namespace' },
278
+ { arg: 'name', required: true, desc: 'cronjob name' },
279
+ ],
280
+ },
281
+ {
282
+ name: 'manage_gitops',
283
+ write: true,
284
+ desc: 'Operate on GitOps resources. ArgoCD: sync, refresh, terminate, rollback, suspend, resume. FluxCD: reconcile, sync-with-source, suspend, resume.',
285
+ params: [
286
+ { arg: 'action', required: true, desc: 'sync/reconcile, refresh, terminate, rollback, suspend, or resume' },
287
+ { arg: 'tool', required: true, desc: 'argocd or fluxcd' },
288
+ { arg: 'namespace', required: true, desc: 'resource namespace' },
289
+ { arg: 'name', required: true, desc: 'resource name' },
290
+ { arg: 'kind', desc: 'FluxCD resource kind (e.g. kustomization, helmrelease)' },
291
+ ],
292
+ },
293
+ {
294
+ name: 'apply_resource',
295
+ write: true,
296
+ desc: 'Create or update a resource from YAML. apply mode is server-side apply and reports field ownership conflicts by default; create mode fails if it exists. Multi-document YAML returns per-document status on partial failure.',
297
+ params: [
298
+ { arg: 'yaml', required: true, desc: 'YAML manifest (multi-document with --- supported)' },
299
+ { arg: 'mode', desc: 'apply (default) or create' },
300
+ { arg: 'dry_run', desc: 'validate and preview without persisting' },
301
+ { arg: 'namespace', desc: 'override namespace for the resource' },
302
+ { arg: 'verify', desc: 'return post-mutation state; on dry_run return preview diff (default true)' },
303
+ { arg: 'force', desc: 'force SSA field ownership conflicts and take ownership from other managers (default false)' },
304
+ ],
305
+ },
306
+ {
307
+ name: 'patch_resource',
308
+ write: true,
309
+ desc: 'Patch one existing resource with JSON Patch, JSON Merge Patch, or built-in-kind strategic merge patch for precise edits without rewriting the full manifest.',
310
+ params: [
311
+ { arg: 'kind', required: true, desc: 'resource kind, e.g. Deployment, Service, ConfigMap' },
312
+ { arg: 'name', required: true, desc: 'resource name' },
313
+ { arg: 'namespace', desc: 'resource namespace; omit for cluster-scoped resources' },
314
+ { arg: 'group', desc: 'API group when the kind is ambiguous' },
315
+ { arg: 'patch_type', desc: 'json (default), merge, or strategic' },
316
+ { arg: 'patch', required: true, desc: 'JSON patch body' },
317
+ { arg: 'dry_run', desc: 'validate and preview without persisting' },
318
+ { arg: 'verify', desc: 'return post-patch state; on dry_run return preview diff (default true)' },
319
+ ],
320
+ },
321
+ {
322
+ name: 'manage_node',
323
+ write: true,
324
+ desc: 'Operate on a node: cordon marks it unschedulable, uncordon reverses that, drain cordons then evicts all non-DaemonSet pods.',
325
+ params: [
326
+ { arg: 'action', required: true, desc: 'cordon, uncordon, or drain' },
327
+ { arg: 'name', required: true, desc: 'node name' },
328
+ { arg: 'delete_empty_dir_data', desc: 'evict pods with emptyDir volumes (default true)' },
329
+ { arg: 'force', desc: 'evict pods not managed by a controller (default false)' },
330
+ { arg: 'timeout', desc: 'drain timeout in seconds (default 60)' },
331
+ ],
332
+ },
333
+ ]