Commit graph

493 commits

Author SHA1 Message Date
rcourtman
0b717bfa44 Improve test coverage 2025-12-17 12:00:59 +00:00
rcourtman
307bb9f6cc feat: add Linux agent archives to releases and improve version mismatch detection
Release improvements:
- Add standalone Linux agent archives (amd64, arm64, armv7, armv6, 386) to releases
- Previously only Darwin/Windows had standalone agent downloads

Agent version mismatch detection:
- New agentVersion.ts utility compares agent versions against server version
- DockerHostSummaryTable now shows accurate 'outdated' warnings when
  agent version is older than the connected Pulse server
- Better tooltips explain version status and upgrade instructions
2025-12-16 22:51:10 +00:00
rcourtman
6bfa8a3837 fix: AI model selector dropdown overflow on small screens
Add max-height and overflow-y-auto to the model selector dropdown in
the AI chat panel to prevent it from extending past the screen when
there are many models available (e.g., with Ollama).

Fixes feedback from discussion #845
2025-12-16 20:59:42 +00:00
rcourtman
a9c0a4d682 feat: configurable backup freshness thresholds for dashboard indicator
Adds FreshHours and StaleHours settings to control when the dashboard
backup indicator shows green (fresh), amber (stale), or red (critical).

- Backend: Added FreshHours/StaleHours to BackupAlertConfig (default 24/72 hours)
- Frontend: getBackupInfo() now accepts optional thresholds parameter
- Dashboard/GuestRow components use thresholds from alert config
- Settings saved/loaded with alert configuration

Closes #839
2025-12-16 16:36:08 +00:00
rcourtman
a8957a2e7b feat(ui): make AI settings page more compact and user-friendly
- Replace verbose info banner with streamlined layout
- Add collapsible 'Advanced Model Selection' accordion for Chat/Patrol models
- Make AI Patrol Settings section collapsible with inline summary badges
- Compact Cost Controls into single-row inline layout
- Reduce form spacing for tighter presentation
- Remove unused formHelpText import

Also includes:
- OpenAI provider fixes for max_tokens parameters
- Security setup CSRF and 401 fixes
- Minor UI tweaks
2025-12-16 09:20:09 +00:00
rcourtman
101fa62997 fix(security): show actual backend error instead of misleading DISABLE_AUTH message
The frontend was incorrectly assuming any 401/403 response from the
quick-setup endpoint meant the legacy DISABLE_AUTH flag was present.

This was wrong - the real causes are typically:
- Missing bootstrap token (for first-run setup)
- Invalid bootstrap token
- Authentication required for existing setups

Now the frontend properly displays the actual error message from the
backend, which includes helpful instructions for retrieving the
bootstrap token.
2025-12-15 22:30:24 +00:00
rcourtman
a3909f1b39 fix: strip provider prefix from all AI provider models and instant URL refresh
Backend fixes:
- Strip provider prefix (anthropic:, openai:, deepseek:, ollama:) in all
  provider Chat methods and constructors for robust handling
- Models are now correctly parsed regardless of caller format

Frontend fixes:
- Tool cards now persist in AI chat after approval execution by adding
  to streamEvents array
- Dashboard now listens for pulse:metadata-changed custom event
- AI Chat emits this event when set_resource_url tool completes
- Guest URL icons now update instantly when AI sets them
2025-12-15 19:18:09 +00:00
rcourtman
43d658556b feat(ai): improve AI settings first-time setup UX
- Add setup modal that appears when enabling AI without configured provider
- Modal allows selecting provider (Anthropic, OpenAI, DeepSeek, Ollama)
- Enter API key/URL and enable AI in one smooth flow
- Reorder backend to apply API keys before enabled check
- Fix Ollama to strip 'ollama:' prefix from model names
- Simplify backend error message for unconfigured providers
2025-12-15 18:59:19 +00:00
rcourtman
06ae5295b3 fix(ai): send Ollama URL when using default localhost address
The form pre-fills the Ollama URL field with http://localhost:11434 but
compared it against that same default value to detect changes. This meant
users configuring Ollama with the default URL never actually saved it.

Also shows actual backend error messages instead of generic "Failed to update"
when toggling the AI enable switch.

Related to #847
2025-12-15 10:03:15 +00:00
rcourtman
3b4c77de28 fix(ui): add CPU tooltip to Proxmox Overview. Related to #816 2025-12-15 02:06:12 +00:00
rcourtman
9e7240042f fix(ui): apply threshold-based coloring to memory bars
Fixes #828

Memory bars were always showing green regardless of usage percentage.
Added getMemoryColor() function that applies threshold-based coloring:
- Green: Below 70%
- Yellow/Orange: 70-90%
- Red: Above 90%

This matches the existing disk bar behavior and restores the expected
visual warning for high memory usage.
2025-12-14 22:11:07 +00:00
rcourtman
3948652a21 fix(docker): truncate long image names in container table
Fixes #825

Long Docker image names (like Immich postgres containers) were expanding
the entire table row, requiring horizontal scrolling to see CPU/Memory.

Changed the image cell to use:
- Inline style max-width (more reliable in table layouts)
- Block span with truncate class
- overflow-hidden on parent container

Images now truncate with ellipsis at 200px, with full name in tooltip.
2025-12-14 22:05:38 +00:00
rcourtman
b004f6d017 fix(ui): stabilize type badge order in unified agents table
Fixes #773

The type badge order was flapping between 'Host Docker' and 'Docker Host'
because Array.from(new Set([...])) doesn't preserve insertion order reliably.

Added a sortTypes helper that ensures types are always displayed in a
consistent order: 'host' before 'docker'. This prevents visual flapping
even when the underlying data sources update at slightly different times.
2025-12-14 21:51:06 +00:00
rcourtman
aca2534a1a fix: Quick tips banner incorrectly states 0 disables alerts, should be -1
The Quick tips banner on the Alerts page said "Set any threshold to 0" but
the actual code uses -1 to disable alerts. The tooltips on individual fields
were correct; only the top-of-page banner was wrong.

Related to #843
2025-12-14 19:08:24 +00:00
rcourtman
49c30ea412 fix: update UnifiedAgents test for 'Force Docker' label change 2025-12-14 18:11:13 +00:00
rcourtman
6795f83e63 feat: auto-detect platforms during agent install and allow multi-host tokens
- Install script now auto-detects Docker, Kubernetes, and Proxmox
- Platform monitoring is enabled automatically when detected
- Users can override with --disable-* or --enable-* flags
- Allow same token to register multiple hosts (one per hostname)
- Update tests to reflect new multi-host token behavior
- Improve CompleteStep and UnifiedAgents UI components
- Update UNIFIED_AGENT.md documentation
2025-12-14 16:21:59 +00:00
rcourtman
eb59faaa4a fix: cluster-aware guest deduplication and multi-agent token binding
- Add cluster-aware guest ID generation (clusterName-VMID instead of instanceName-VMID)
  to prevent duplicate VMs/containers when multiple cluster nodes are monitored

- Add cluster deduplication at registration time - when a node is added that belongs
  to an already-configured cluster, merge as endpoint instead of creating duplicate

- Add startup consolidation to automatically merge duplicate cluster instances

- Change host agent token binding from agent GUID to hostname, allowing:
  - Multiple host agents to share a token (each bound by hostname)
  - Agent reinstalls on same host without token conflicts

- Remove 12-character password minimum requirement

- Remove emoji from auto-registration success message

- Fix grouped view node lookup to support both cluster-aware node IDs
  (clusterName-nodeName) and legacy guest grouping keys (instance-nodeName)

Fixes duplicate guests appearing when agents are installed on multiple
cluster nodes. Also improves multi-agent UX by allowing shared tokens.
2025-12-14 10:16:17 +00:00
rcourtman
1b8a310f2e feat: display linked host agent badge on PVE nodes
- NodeGroupHeader shows '+ Host Agent' badge when node has linked agent
- NodeSummaryTable shows '+Agent' badge in the node row
- Filter out linked hosts from Managed Agents list (prevents duplication)

This provides visual feedback when a PVE node has enhanced monitoring
via an installed host agent.
2025-12-13 23:18:31 +00:00
rcourtman
db8afeea18 feat: frontend support for linked host agents and PVE nodes
- Added linkedHostAgentId to Node interface
- Added linkedNodeId/linkedVmId/linkedContainerId to Host interface
- Filter out linked hosts from 'Managed Agents' list (they show merged with nodes)

Next: Update Dashboard to display linked entity badges
2025-12-13 23:16:48 +00:00
rcourtman
cc5586c5c0 feat: auto-generate new token after each install command copy
Users no longer need to manually click 'New Token' - a fresh token is
automatically generated after each copy. The command shown is always
ready for the next host.
2025-12-13 23:00:58 +00:00
rcourtman
893d3d5c79 fix: clarify one-token-per-host requirement and improve stale agent cleanup
- Setup wizard now clearly states 'Use a different token for each host'
- New Token button is always visible and more prominent (blue styling)
- WebSocket store now clears stale agents (>60s since lastSeen) immediately
  when receiving empty host arrays, instead of waiting for 3 consecutive updates
2025-12-13 22:57:00 +00:00
rcourtman
68456763f9 fix: apply empty agent updates immediately when existing agents are stale
The anti-flapping logic previously required 3 consecutive empty updates
before clearing stale agents from the UI. Now if all existing hosts/dockerHosts
have lastSeen > 60 seconds ago, empty updates are applied immediately.

This fixes the issue where removed agents stayed visible for too long.
2025-12-13 22:41:15 +00:00
rcourtman
122bd49700 fix: clarify that one token works on multiple hosts
Changed misleading 'Each copy uses a unique token' to 'Use the same
command on multiple servers'. Also toned down the 'Different Token'
button since it's rarely needed.
2025-12-13 22:22:25 +00:00
rcourtman
9aa1000bdb feat: make uninstall command always visible in Agents settings
Previously the uninstall command was hidden behind the token generation step.
Now it's always visible at the bottom of the 'Add a unified agent' card.
2025-12-13 21:41:27 +00:00
rcourtman
1a9973461e chore: update lockfiles 2025-12-13 21:30:57 +00:00
rcourtman
7891027d55 style: replace emojis with text indicators in UI components
- SecurityWarning: replace emoji icons with text-based indicators
- NodeModal: minor formatting cleanup
2025-12-13 21:30:44 +00:00
rcourtman
7eb6d33dad fix: add null safety checks for resources() in useResourcesAsLegacy
Prevents errors when resources array is undefined during initial load.
2025-12-13 21:30:36 +00:00
rcourtman
4ad8235f7a feat: add API token to WebSocket URL for authentication
WebSocket connections can't send custom headers, so the token is passed
as a query parameter. Works with the backend change to support ?token= auth.
2025-12-13 21:30:27 +00:00
rcourtman
a5893bba21 perf: debounce search and optimize filter parsing in Backups and Storage
- UnifiedBackups: memoize parsed search filters, debounce search input
- Storage: debounce search input to prevent jank during rapid typing
2025-12-13 21:29:45 +00:00
rcourtman
d5638c7c14 perf: debounce search input in Kubernetes clusters view
Prevents UI jank during rapid typing by using a 200ms debounced search term.
2025-12-13 21:28:19 +00:00
rcourtman
8abcc93aac perf: optimize Dashboard guest sorting and parent node lookups
- Pre-compute guest-to-parent-node mapping to avoid repeated lookups during render
- Memoize sort comparator to avoid duplicating sorting logic
- Reduces computational overhead when rendering large guest lists
2025-12-13 21:27:50 +00:00
rcourtman
8ed0851fb9 feat: simplify setup wizard to 3 steps (welcome, security, complete)
Removed Connect and Features steps that were adding friction without much value.
The wizard now focuses on:
1. Welcome - introduction and bootstrap token entry
2. Security - credential setup
3. Complete - shows install command and connected agents

Agent polling now happens in CompleteStep instead of relying on WebSockets
which aren't available during the pre-login setup phase.
2025-12-13 21:27:21 +00:00
rcourtman
7ae0b5cafd fix: Hide AI sidebar button when AI is disabled
The button was showing when aiChatStore.enabled was undefined.
Changed condition from 'enabled !== false' to 'enabled === true'
to only show when AI is explicitly enabled.
2025-12-13 16:13:25 +00:00
rcourtman
ae3e3a64f0 fix: Make OIDC toggle auto-save when disabling
- Disabling OIDC now saves immediately (safe operation)
- Enabling requires Save button press (prevents lockout without config)
- Shows helpful hint when enabling: configure first, then save
2025-12-13 16:09:48 +00:00
rcourtman
e4fa231ad3 fix: Make AI Assistant toggle auto-save immediately
The toggle was only updating local state without persisting.
Now it saves and shows confirmation feedback on toggle.
2025-12-13 16:01:03 +00:00
rcourtman
5a52913a90 fix: Resolve TypeScript errors and add ARIA accessibility
- Fixed type mismatches in ProxmoxAgentNodesPanel (prop signatures)
- Fixed temperatureTransports type (array vs single object)
- Added ARIA attributes to SetupWizard for screen reader support
- All tsc --noEmit checks pass
2025-12-13 15:49:37 +00:00
rcourtman
414574739b chore: Use proper logger in WelcomeStep instead of console.error 2025-12-13 15:43:13 +00:00
rcourtman
c1d9c1bb95 fix: Correct NodeConfig import path in ProxmoxAgentNodesPanel 2025-12-13 15:39:28 +00:00
rcourtman
e470fbec83 chore: Fix lint warnings in SetupWizard and add AI API docs
- Fixed unused variables in wizard components
- Fixed invalid aiEnabled field in FeaturesStep (AI uses separate API)
- Added AI endpoints section to API.md
2025-12-13 15:36:40 +00:00
rcourtman
e27b6f2657 Merge main into ai-features: incorporate latest bugfixes
Resolved conflicts:
- pkg/fsfilters/filters.go: Keep both TrueNAS and EnhanceCP filter fixes
- DockerUnifiedTable.tsx: Use main's resource column overlap fix
2025-12-13 15:18:51 +00:00
rcourtman
cb06077fab feat: Add multi-step Setup Wizard for Pulse 5.0 onboarding
- New SetupWizard component with 5-step flow:
  1. Welcome: Bootstrap token unlock, platform showcase
  2. Security: Admin account + API token creation
  3. Connect: Multi-platform infrastructure (Proxmox, Docker, K8s)
  4. Features: AI and auto-updates toggles
  5. Complete: Credentials display with copy/download

- Replaced FirstRunSetup with SetupWizard in Login.tsx
- Added Install Update button to UpdatesSettingsPanel
- Enhanced UpdatesSettingsPanel with update plan integration
- Added UpdateConfirmationModal to Settings for inline updates

Positions Pulse as a unified infrastructure monitoring platform,
not just a Proxmox-specific tool.
2025-12-13 15:08:47 +00:00
rcourtman
dbac8632b7 feat: add persistent metrics history API endpoint
- Add GET /api/metrics-store/history endpoint for querying SQLite-backed metrics
- Support flexible time ranges: 1h, 6h, 12h, 24h, 7d, 30d, 90d
- Return aggregated data with min/max values for longer time ranges
- Add TypeScript types and ChartsAPI.getMetricsHistory() client method

This enables frontend charts to visualize long-term trends using the
tiered retention system (raw → minute → hourly → daily averages).
2025-12-13 14:18:16 +00:00
rcourtman
17aaf6d603 Enhance settings panels with improved UI/UX
General Settings:
- Add animated sun/moon icon to dark mode toggle with gradient backgrounds
- Dynamic label showing current theme state (Light mode/Dark mode)
- Smooth CSS transitions for icon rotation and scaling

Updates Settings:
- Redesign version display with visual card layout
- Add build type badges (Development, Docker, Source) as colorful pills
- Show 3-column layout with arrow indicator when updates available
- Move Check Now button to footer with refresh icon
- Display auto-check status indicator

Security Overview:
- Add loading skeleton during data fetch
- Enhance proxy auth notice with gradient header and admin badge
- Style logout/guide links as proper buttons
- Add Security Best Practices tips card with recommendations
2025-12-13 13:41:43 +00:00
rcourtman
c5ac33e8c6 feat(backups): Add time format toggle to BackupsFilter
- Added toggle button to switch between relative and absolute time display
- Time preference is persisted to localStorage
- Toggle shows clock icon with 'Relative' or 'Absolute' label
- Implements the TODO from UnifiedBackups.tsx
2025-12-13 13:17:35 +00:00
rcourtman
75874687fb chore: Fix all remaining lint warnings
- Prefix unused catch error variables with underscore in AIChat.tsx and Alerts.tsx
- Reduced lint warnings from 8 to 0
- Clean lint output with no warnings or errors
2025-12-13 11:05:08 +00:00
rcourtman
3c0f4aa576 chore(settings): Remove unused diagnostics code and cleanup
- Removed unused helper functions (formatIsoDateTime, formatIsoRelativeTime, etc.)
- Removed unused handler functions (handleRegisterProxyNodes, handleDockerPrepareToken, handleCopy)
- Removed unused type interfaces (ProxyRegisterNode, DockerMigrationResult)
- Removed unused imports (copyToClipboard, showTokenReveal, APITokenRecord)
- Removed unused state signals for diagnostics actions
- Reduced lint warnings from 26 to 8
- Settings.tsx reduced from 5955 to 5740 lines
2025-12-13 10:53:18 +00:00
rcourtman
529daf58f8 chore(settings): Prefix unused variables to suppress lint warnings
- Prefix unused destructured variables with underscore
- Reduces lint warnings from 26 to 18
- Remaining warnings are for legacy helper functions
2025-12-13 08:02:24 +00:00
rcourtman
065cbe46cf chore(settings): Clean up unused imports and optimize polling
- Removed unused getPulsePort/getPulseWebSocketUrl imports
- Optimized polling to only run on proxmox tab (DiagnosticsPanel handles its own fetching)
- Remaining lint warnings are for legacy code that may need future refactoring
2025-12-13 07:59:52 +00:00
rcourtman
de2f6e0edb enhance(settings): Improve SecurityPostureSummary with score indicator
- Added dynamic security score calculation (0-100%)
- Added gradient header that changes color based on score:
  - Green (>=80%): Strong security
  - Amber (50-79%): Moderate security
  - Red (<50%): Weak security
- Improved visual hierarchy with color-coded status cards
- Added 'Critical' labels for important missing features
- Changed icons to lucide-solid for consistency
2025-12-13 07:54:09 +00:00
rcourtman
6a3c143740 refactor(settings): Extract DiagnosticsPanel and improve AI Settings UX
- Created standalone DiagnosticsPanel component with modern visual design
  - Gradient header with system health indicator
  - Card-based layout for System Runtime, PVE Nodes, PBS, Discovery
  - Status badges and improved visual hierarchy
  - Export functionality (full and GitHub-sanitized)

- Reduced Settings.tsx from 8,035 to 5,956 lines (26% reduction)
  - Removed ~2,079 lines of inline diagnostics code
  - Improved maintainability by encapsulating diagnostics logic

- Improved AI Settings UX:
  - Cost Controls: Gradient design, RECOMMENDED badge, $ prefix
  - Shows daily/weekly budget equivalents when value is entered
  - Auto-Fix: Streamlined acknowledgment with clear button instead of checkbox
  - Better visual hierarchy throughout
2025-12-13 07:51:49 +00:00
rcourtman
0074e49792 fix(frontend): hide unconfigured navigation tabs 2025-12-13 00:21:00 +00:00
rcourtman
0ddc30c1e1 Redesign Ceph, Replication, and Mail Gateway pages for UI consistency
- Ceph: Complete rework with summary cards (storage, clusters, services, pools),
  search with type-to-search, proper loading/disconnected/empty states, cluster
  overview table, pools table with filtering, health badges with tooltips

- Replication: Add summary cards (total/healthy/issues/next sync), status filter
  buttons (All/Healthy/Warning/Error), search with type-to-search, countdown timers
  for next sync with overdue/imminent highlighting, row highlighting for problem jobs,
  error tooltips, loading state

- Mail Gateway: Add aggregate summary cards across all instances (mail/spam/virus/
  quarantine/queue), visual threat rate progress bars, status badges with health
  indicators, queue depth tooltips with breakdown, streamlined stats grid with
  color-coded threat categories, improved cluster nodes table

All three pages now follow the same design patterns as Dashboard, Hosts, Docker,
and Storage using Card, EmptyState, and consistent styling.
2025-12-13 00:08:29 +00:00
rcourtman
c48c5b8861 fix(hosts): Merge filter sections into single row 2025-12-12 23:43:13 +00:00
rcourtman
ca8cd0e3b4 style(hosts,docker): Move search bar to its own row above filters
- Consistent with Kubernetes page layout
- Search bar now takes full width on top row
- Filter toggles on second row below search
2025-12-12 23:41:37 +00:00
rcourtman
fa5fde56e6 style(kubernetes): Move search bar to its own row above filters 2025-12-12 23:37:49 +00:00
rcourtman
9725849d77 feat(kubernetes): Add keyboard focus for search input
- Typing anywhere on the page auto-focuses the search input
- Escape key clears search and blurs input
- Matches Dashboard behavior for consistent UX
- Fixed missing createEffect import
2025-12-12 23:36:31 +00:00
rcourtman
91f8b81547 feat(kubernetes): Add column picker and sorting for all views
- Add sortable headers to Clusters and Nodes views
- Add ColumnPicker dropdown for Pods view (toggle Namespace, Cluster, Ready, Restarts, Image, Age columns)
- Column visibility persists to localStorage
- Sorting persists across sessions for all views
2025-12-12 23:31:46 +00:00
rcourtman
987f7a3822 feat(kubernetes): Add sorting and namespace filter to K8s UI
- Add sortable table headers for Pod and Deployment views
- Click column headers to toggle sort direction
- Sort state persists across sessions
- Add namespace dropdown filter for Pods/Deployments views
- Auto-populates from available namespaces
- Include namespace filter in reset and active filters check
2025-12-12 23:24:04 +00:00
rcourtman
0cd16b29cc feat(kubernetes): Add Kubernetes mock data and UI
Backend:
- Add K8s cluster, node, pod, deployment mock data generation
- Configurable via PULSE_MOCK_K8S_CLUSTERS, PULSE_MOCK_K8S_NODES,
  PULSE_MOCK_K8S_PODS, PULSE_MOCK_K8S_DEPLOYMENTS env vars
- Generate realistic cluster data with versions, namespaces, pod phases
- Add dynamic metric updates for K8s resources
- Deep copy K8s data in cloneState to prevent race conditions

Frontend:
- Add KubernetesClusters component with 4 view modes:
  Clusters, Nodes, Pods, Deployments
- Filter bar with search, status filter, show hidden toggle
- Nodes view: status, roles, CPU/memory/pod capacity, kubelet version
- Pods view: namespace, status, ready containers, restarts, image, age
- Deployments view: replicas, ready/up-to-date status
- Matches Docker/Dashboard table styling patterns
2025-12-12 23:13:40 +00:00
rcourtman
d96942596f feat: add Kubernetes platform support 2025-12-12 21:31:11 +00:00
rcourtman
bf43d448cf fix: Robust OCI container detection with state persistence
Backend:
- Seed OCI classification from previous state so containers never
  'downgrade' to LXC if config fetching intermittently fails
- Prevent type regression in recordGuestSnapshot when OCI was previously detected
- Move metrics zeroing before snapshot recording for cleaner flow

Frontend:
- Add isOCIContainer() memo that checks both type and isOci flag
- Use isOCI helper in Dashboard.tsx for AI context building
- Include oci-container type in useResources container conversion
- Preserve isOci and osTemplate fields through legacy conversion

This ensures OCI containers retain their classification even when
Proxmox API permissions or transient errors prevent config reads.
2025-12-12 20:06:39 +00:00
rcourtman
a20760f527 fix: Preserve OCI container type through unified resource conversion
The useResources.ts hook was hardcoding type: 'lxc' when converting
unified resources to legacy container format, causing OCI containers
to intermittently display as LXC when WebSocket updates occurred.

Now preserves the actual type from platformData (oci/lxc).
2025-12-12 19:18:36 +00:00
rcourtman
e82cf7eaaf feat: Enhance OCI container display and AI context
- Frontend: Add ociImage memo to extract clean image name from osTemplate
- Frontend: Show OCI image name in type badge tooltip
- Frontend: Display OCI image in OS column when no guest agent info available
- Frontend: Include ociImage in AI context data for selected OCI containers
- Backend: Differentiate OCI containers as 'oci_container' type in AI context
- Backend: Add Metadata field to ResourceContext for extensibility
- Backend: Include oci_image in container metadata for AI analysis
- Backend: Update section heading to 'LXC/OCI Containers' in AI context

This follows Docker container patterns to avoid duplicating work.
2025-12-12 18:00:09 +00:00
rcourtman
dfb5d50f73 feat: Add Proxmox 9.1+ OCI container support
- Backend: Add IsOCI and OSTemplate fields to Container model
- Backend: Add extractContainerOSTemplate() and isOCITemplate() detection functions
- Backend: Detect OCI containers via ostemplate config and set type to 'oci'
- Frontend: Add isOci and osTemplate to Container interface
- Frontend: Add 'oci-container' to ResourceType with distinct purple badge
- Frontend: Update Dashboard filters to include OCI containers with LXC
- Tests: Add comprehensive unit tests for OCI detection logic

OCI containers are detected by checking the ostemplate for patterns like:
- oci: prefix (e.g., oci:docker.io/library/alpine:latest)
- docker: prefix (e.g., docker:nginx:latest)
- Known registry URLs (docker.io, ghcr.io, gcr.io, quay.io, etc.)
- Local templates with oci- or oci_ filename patterns
2025-12-12 17:51:43 +00:00
rcourtman
7f057432ed feat: AI security and policy improvements for 5.0
- Add DOMPurify sanitization for AI chat markdown rendering (XSS fix)
- Configure DOMPurify to add target=_blank and rel=noopener to links
- Update system prompt to align with command approval policy
- Clarify safe vs destructive commands in prompt
- Improve patrol auto-fix mode guidance with safe operation list
- Add verification requirements for auto-fix actions
- Update observe-only mode to be clearer about read-only restrictions
2025-12-12 17:38:55 +00:00
rcourtman
2381631df0 fix(ui): Move Auto-Fix Model selector next to Auto-Fix toggle
UX improvement: The Auto-Fix Model dropdown was too far from the
Patrol Auto-Fix toggle, making it hard to find.

Now the flow is:
1. Scroll to 'AI Patrol Behavior' section
2. Check the acknowledgement checkbox
3. Enable 'Patrol Auto-Fix' toggle
4. Model selector appears RIGHT BELOW the toggle

The model dropdown only appears when auto-fix is enabled (since
it's irrelevant otherwise).
2025-12-12 15:17:44 +00:00
rcourtman
878eb937f3 feat(ui): Add AI Insights Panel component
Add collapsible panel to display AI-learned intelligence:

Features:
- Failure predictions with time estimates
- Color-coded severity (overdue=red, <3 days=amber, etc.)
- Human-readable event types and confidence percentages
- Resource dependency/correlation display
- Shows source → target relationships with avg delay
- Expandable/collapsible design to save space

Styling:
- Purple gradient theme consistent with AI branding
- Responsive with dark mode support
- Clean card-based layout for predictions
- Badge showing total insight count

Ready to integrate into Alerts page or resource details.
2025-12-12 14:55:08 +00:00
rcourtman
119f6ecc51 feat(frontend): Add AI intelligence API types and methods
Add TypeScript types and API methods for AI intelligence data:

Types (aiIntelligence.ts):
- FailurePattern - Detected recurring patterns
- FailurePrediction - Predicted failures with confidence
- ResourceCorrelation - Detected resource dependencies
- InfrastructureChange - Recent config/state changes
- ResourceBaseline - Learned normal behavior baselines

API Methods (ai.ts):
- getPatterns(resourceId?) - Fetch failure patterns
- getPredictions(resourceId?) - Fetch failure predictions
- getCorrelations(resourceId?) - Fetch resource correlations
- getRecentChanges(hours?) - Fetch infrastructure changes
- getBaselines(resourceId?) - Fetch learned baselines

All methods support optional resource_id filtering.
2025-12-12 14:53:53 +00:00
rcourtman
de8b36d65d feat(settings): Add separate Auto-Fix Model setting for remediation
Add configurable model specifically for automatic remediation actions:

Backend (internal/config/ai.go):
- Add AutoFixModel field to AIConfig
- Add GetAutoFixModel() getter with fallback chain:
  AutoFixModel -> PatrolModel -> Model

Frontend (AISettings.tsx, types/ai.ts):
- Add auto_fix_model to AISettings types
- Add Auto-Fix Model dropdown (only shows when patrol_auto_fix enabled)
- Falls back to patrol model if not set

API (ai_handlers.go):
- Add auto_fix_model to response and update request
- Handle saving/loading the new field

Rationale:
- Auto-fix takes real actions, may warrant a more capable model
- Patrol observation can use cheaper models for cost savings
- Gives users granular control over model costs vs reliability
- Model hierarchy: Chat > AutoFix > Patrol > Default
2025-12-12 14:35:28 +00:00
rcourtman
ec8f306ad1 Make AI cost sparklines more informative 2025-12-12 13:37:30 +00:00
rcourtman
a0d2e46510 fix(ui): Show single-point sparkline as horizontal line
When there's only 1 day of AI usage data, the sparkline was invisible
because a single point draws at x=0 with no width. Now draws a
horizontal line across the full width so users can see the value.

This happens when AI has just been enabled and there's only one
day of recorded usage so far.
2025-12-12 13:21:54 +00:00
rcourtman
5f2c240480 Clarify AI cost estimates with pricing coverage 2025-12-12 13:19:03 +00:00
rcourtman
5c9ebf8d3a Add AI cost export and top target rollups 2025-12-12 12:55:39 +00:00
rcourtman
9c78cf7f84 Move AI cost budget setting into AI settings 2025-12-12 12:23:06 +00:00
rcourtman
1294a66f56 Backup AI usage history on reset 2025-12-12 12:14:13 +00:00
rcourtman
4df04970ea Persist AI cost budget and allow history reset 2025-12-12 12:10:58 +00:00
rcourtman
5ba4e6a84c Improve AI cost dashboard ranges and breakdowns 2025-12-12 11:35:41 +00:00
rcourtman
f3e95c24ae feat(ai): Add baseline learning and anomaly detection (Phase 2)
Phase 2 of Pulse AI differentiation:

- Create internal/ai/baseline package for learned baselines
- Implement statistical baseline learning with mean, stddev, percentiles
- Add z-score based anomaly detection with severity classification
  (low, medium, high, critical based on standard deviations)
- Integrate baseline provider into context builder
- Wire baseline store into patrol service with adapters
- Add anomaly enrichment to resource contexts

Key features:
- Learn computes baseline from historical metric data points
- IsAnomaly and CheckAnomaly detect deviations from normal
- Persists baselines to disk as JSON for durability
- Formatted anomaly descriptions for AI consumption
  Example: 'Memory is high above normal (85.2% vs typical 42.1% ± 8.3%)'

The baseline store needs to be initialized and triggered to learn
from metrics history. Next step is adding the learning loop.

All tests passing.
2025-12-12 11:26:31 +00:00
rcourtman
64dad395a2 Add 1d range to AI cost dashboard 2025-12-12 11:09:44 +00:00
rcourtman
3ea6c1be5d Show AI cost refresh errors and harden log redaction 2025-12-12 11:05:24 +00:00
rcourtman
71b6a2ae12 Add estimated USD to AI cost dashboard 2025-12-12 10:43:07 +00:00
rcourtman
935b4da7ac Add AI usage dashboard 2025-12-12 09:59:59 +00:00
rcourtman
f57e45ed5f feat: Docker agent retry, UI column improvements, and IP tooltip enhancements
- Add exponential backoff retry for Docker agent startup (main.go)
- Fix Docker resource/image column widths with proper truncation
- Unify IP tooltip styling across hosts and guests with detailed network info
- Improve column visibility defaults and sticky column handling
- Various component refinements for Dashboard, Storage, and Backups views
2025-12-12 08:26:36 +00:00
rcourtman
1a78e8846a feat(ai): Replace patrol frequency dropdown with custom minutes input
- Changed patrol schedule from preset dropdown to freeform number input
- Users can now set any interval (min 10 minutes, max 7 days, or 0 to disable)
- Added patrol_interval_minutes to API request/response (preset is now deprecated)
- Backend validates: min 10 minutes when enabled, max 10080 (7 days)
- Frontend shows human-readable duration next to input (e.g., '6h', '2h 30m')

Also improved Auto-Fix Mode safety:
- Removed '(recommended)' from preset options (was subjective)
- Added 'I understand the risks' acknowledgement checkbox
- Toggle is disabled until user explicitly acknowledges the risks
- Shows prominent warning when Auto-Fix is enabled
- Acknowledgement is session-based (must re-acknowledge on page reload)
2025-12-11 23:24:33 +00:00
rcourtman
d03b3d644c fix(ai-chat): Display messages chronologically in AI chatbot
- Add 'content' type to StreamDisplayEvent for tracking text chunks
- Track content events in streamEvents array for chronological display
- Update render to use Switch/Match for cleaner conditional rendering
- Interleave thinking, tool calls, and content as they stream in
- Add fallback for old messages without streamEvents for backwards compat

Previously, tool/command outputs stayed at top while AI text responses
accumulated at the bottom. Now all events appear in order like a
normal chatbot.
2025-12-11 23:02:59 +00:00
rcourtman
a082fd3fc1 fix: Remove hardcoded model names from UI to prevent staleness
- Remove model references from provider labels ('OpenAI' not 'OpenAI (GPT-4)')
- Remove DEFAULT_MODELS usage in form initialization
- Use generic placeholders instead of specific model names
- Models are now fetched dynamically from each provider's API
- UI won't become outdated when new models are released
2025-12-11 18:38:59 +00:00
rcourtman
6e19232b02 feat: Improve AI settings status indicator
- Show number of configured providers and available models
- Display friendly model name (without provider prefix)
- Better status message: 'Ready • 1  10 models'provider
2025-12-11 18:30:04 +00:00
rcourtman
cdf722b45d feat: Add refresh models button to AI settings
- Adds 'Refresh Models' button next to Default Model label
- Spinning icon animation during loading
- Allows manual refresh after configuring new providers
2025-12-11 18:28:33 +00:00
rcourtman
bf92c0510a feat: Add clear credentials button for each AI provider
- Add clear_anthropic_key, clear_openai_key, clear_deepseek_key, clear_ollama_url flags to API
- Backend handles clearing with confirmation prompt
- Each provider accordion shows Test and Clear buttons when configured
- Clear button requires confirmation before removing credentials
- Frontend automatically refreshes settings after clearing
2025-12-11 18:24:25 +00:00
rcourtman
597527fc04 feat: Add per-provider test buttons and documentation links
- Add /api/ai/test/{provider} endpoint for testing individual providers
- Add 'Test' button to each provider accordion (visible when configured)
- Shows test result inline (success/error message)
- Update help links with direct URLs to API key pages:
  - Anthropic: console.anthropic.com/settings/keys
  - OpenAI: platform.openai.com/api-keys
  - DeepSeek: platform.deepseek.com/api_keys
  - Ollama: ollama.ai
2025-12-11 18:11:31 +00:00
rcourtman
0c3dcf353a feat: Implement multi-provider AI support
Backend:
- Add per-provider API key fields to AIConfig (AnthropicAPIKey, OpenAIAPIKey, DeepSeekAPIKey, OllamaBaseURL, OpenAIBaseURL)
- Add NewForProvider() and NewForModel() factory functions for multi-provider instantiation
- Update ListModels() to aggregate models from all configured providers with provider:model format
- Update Execute/ExecuteStream to dynamically create provider based on selected model
- Update TestConnection to use multi-provider aware provider creation
- Add helper functions: HasProvider(), GetConfiguredProviders(), GetAPIKeyForProvider(), GetBaseURLForProvider(), ParseModelString(), FormatModelString()

Frontend:
- Remove legacy single-provider UI (provider grid, single API key input, single base URL)
- Add accordion-style UI for configuring all providers independently
- Add model grouping by provider in selectors using optgroup
- Update AIChat model dropdown with grouped provider sections
- Add helper functions for parsing provider from model ID and grouping models

API:
- Add multi-provider fields to AISettingsResponse and AISettingsUpdateRequest
- Add /api/ai/models endpoint for dynamic model listing
- Update settings handlers for per-provider credential management
2025-12-11 16:00:45 +00:00
rcourtman
29404d4e81 feat(ai): Add Suppression Rules UI to Alerts page
Users can now:
1. View all active suppression rules in a collapsible section
2. Add new rules manually with resource ID, category, and description
3. Delete rules to re-enable alerts
4. See whether rules came from dismissed findings or were manually created

The UI shows:
- 🔇 Suppression Rules (N active) header with expand/collapse
- + Add Rule button to open the form
- Each rule shows resource, category, origin (Manual/From Finding), and description
- Delete button to remove rules
2025-12-11 00:15:35 +00:00
rcourtman
a8d0b15346 feat(ai): Add suppression rules management API and UI
Users can now:
1. View all suppression rules (both from dismissed findings and manually created)
2. Create manual rules like 'ignore performance issues on debian-go'
3. Delete rules when they want alerts to come back

Backend:
- Added SuppressionRule type for user-defined rules
- Added suppressionRules storage to FindingsStore
- Added AddSuppressionRule/GetSuppressionRules/DeleteSuppressionRule methods
- Added isSuppressedInternal check for manual rules
- Added API handlers and routes for /api/ai/patrol/suppressions

Frontend:
- Added SuppressionRule interface
- Added getSuppressionRules/addSuppressionRule/deleteSuppressionRule API functions
- Added getDismissedFindings for viewing dismissed findings

Example usage:
POST /api/ai/patrol/suppressions
{
  'resource_id': 'debian-go',
  'category': 'performance',
  'description': 'Dev container runs hot - expected'
}
2025-12-11 00:12:18 +00:00
rcourtman
b1199b3cbf fix(ai): Use context.Background() for forced patrol runs
The ForcePatrol() function was using the HTTP request context, which gets
cancelled immediately when the API response is sent. This caused LLM analysis
to fail with 'context canceled' before it could complete.

Now uses context.Background() so the goroutine runs independently of the
HTTP request lifecycle.

Also fixed dropdown hover gap issue in the dismiss menu.
2025-12-10 23:31:21 +00:00
rcourtman
a3d953172c feat(ai): Add LLM memory system for patrol findings
Implements a comprehensive feedback system that allows the LLM to 'remember'
user decisions about findings, preventing repetitive/annoying alerts.

Backend changes:
- Extended Finding struct with dismissed_reason, user_note, times_raised, suppressed
- Added Dismiss(), Suppress(), SetUserNote(), IsSuppressed() methods to FindingsStore
- Added GetDismissedForContext() to format dismissed findings for LLM context
- Enhanced buildPatrolPrompt() to inject user feedback context
- Added POST /api/ai/patrol/dismiss and /api/ai/patrol/suppress endpoints
- Updated IsActive() to exclude suppressed findings

Frontend changes:
- Added Dismiss dropdown with options: Not an Issue, Expected Behavior, Will Fix Later
- Added Never Alert Again option for permanent suppression
- Expected Behavior prompts for optional note to help LLM understand context
- Added visual badges: recurrence count (×N), dismissed status, suppressed indicator
- Display user notes in expanded finding view

Also fixes:
- Fixed 403 error on Run Patrol (compilation errors from partial refactoring)
- Removed non-LLM patrol checks - patrol now uses LLM analysis only
- Fixed function signature mismatches in alert_triggered.go

The LLM now receives context about previously dismissed findings and is
instructed not to re-raise them unless severity has significantly worsened.
2025-12-10 22:55:34 +00:00
rcourtman
c88e2db7b4 feat(ai): Enhanced AI patrol system with alert triggers and history persistence
- Add alert-triggered AI analysis for real-time incident response
- Implement patrol history persistence across restarts
- Add patrol schedule configuration UI in AI Settings
- Enhance AIChat with patrol status and manual trigger controls
- Add resource store improvements for AI context building
- Expand Alerts page with AI-powered analysis integration
- Add Vite proxy config for AI API endpoints
- Support both Anthropic and OpenAI providers with streaming
2025-12-10 21:08:22 +00:00
rcourtman
d2330cf405 refactor(ai): Remove over-engineered URL discovery service
Keep only the simple AI-powered approach:
- set_resource_url tool lets AI save discovered URLs
- Users ask AI directly: 'Find URLs for my containers'
- AI uses its intelligence to discover and set URLs

Removed:
- URLDiscoveryService (rigid port scanning)
- Bulk discovery API endpoints
- Frontend discovery button

The AI itself is smart enough to iterate through resources
and discover URLs when asked.
2025-12-10 08:35:24 +00:00
rcourtman
a6656381c8 Add AI monitoring enhancements and host metadata features
- Add host metadata API for custom URL editing on hosts page
- Enhance AI routing with unified resource provider lookup
- Add encryption key watcher script for debugging key issues
- Improve AI service with better command timeout handling
- Update dev environment workflow with key monitoring docs
- Fix resource store deduplication logic
2025-12-09 16:27:46 +00:00
rcourtman
67351bf58c feat: AI integration, Docker metrics, RAID display, and infrastructure improvements
- Add Claude OAuth authentication support with hybrid API key/OAuth flow
- Implement Docker container historical metrics in backend and charts API
- Add CEPH cluster data collection and new Ceph page
- Enhance RAID status display with detailed tooltips and visual indicators
- Fix host deduplication logic with Docker bridge IP filtering
- Fix NVMe temperature collection in host agent
- Add comprehensive test coverage for new features
- Improve frontend sparklines and metrics history handling
- Fix navigation issues and frontend reload loops
2025-12-09 09:29:27 +00:00
rcourtman
b284bd10fa fix: correct property names in AIChat availableResources memo
Fixed type mismatches where code was using old property names:
- vm/ct.mem → vm/ct.memory.used
- vm/ct.maxmem → vm/ct.memory.total
- vm/ct.maxdisk → vm/ct.disk.total
- node.node → node.name
- node.mem/maxmem/maxdisk → node.memory/disk properties
- host.connected → host.status === 'online'
- host.version → host.agentVersion

This fixes 15 TypeScript errors in the AI context picker.
2025-12-08 09:53:07 +00:00