Commit Graph

2432 Commits

Author SHA1 Message Date
rcourtman 3cdc5ec6c5 feat(frontend): Update AI chat for native streaming architecture
Adapts frontend to work with the new native chat service:

Model selector improvements:
- Extract ModelSelector to reusable component
- Add notable model filtering (shows recent models by default)
- Add "Show older models" toggle for legacy model access
- Add notable badge indicator for recommended models

Chat flow changes:
- Simplify approval handling - backend agentic loop executes commands
- Tool results now come via stream events, not approval response
- Session model selection preserved when switching sessions

Type updates:
- Add 'notable' field to ModelInfo interface
- Add 'notable' to API response types
2026-01-19 19:19:13 +00:00
rcourtman 0f5807d0f9 refactor(ai): Remove deprecated opencode sidecar package
The opencode package implemented the old architecture where:
- Pulse ran an OpenCode subprocess as a sidecar
- AI messages were proxied through OpenCode
- OpenCode connected back to Pulse's MCP server for tool access

This is now replaced by the native chat service (internal/ai/chat)
which calls AI providers directly and executes tools inline.

Removed files:
- sidecar.go: OpenCode process management
- service.go: Message proxying and session management
- client.go: HTTP client for OpenCode API
- bridge.go: MCP tool bridging
- patrol.go: Patrol context extraction
- *_test.go: Associated tests

Benefits of new architecture:
- No external subprocess dependency
- Direct streaming from AI providers
- Lower latency (no proxy hop)
- Simpler deployment
2026-01-19 19:18:14 +00:00
rcourtman 17ca31a557 refactor(ai): Replace mcp package with tools package for direct tool execution
This refactoring removes the MCP (Model Context Protocol) server layer and
converts AI tools to be called directly by the chat service.

Key changes:
- Rename package from internal/ai/mcp to internal/ai/tools
- Remove server.go - tools no longer exposed via MCP server
- Tools are now called directly by the chat service via ExecuteTool()

New tools added:
- Kubernetes: clusters, nodes, pods, deployments (4 tools)
- PMG: mail gateway status, mail stats, queues, spam stats (4 tools)
- Infrastructure: snapshots, PBS jobs, backup tasks, network stats,
  disk I/O, cluster status, swarm, services, tasks, recent tasks,
  physical disks, RAID status, host Ceph, resource disks (14 tools)
- Patrol: connection health, resolved alerts (2 tools)

Test coverage:
- Added comprehensive test files for adapters, infrastructure,
  patrol, profiles, and query tools

Total tools: 50 (was ~25)
2026-01-19 19:17:24 +00:00
rcourtman 5ff4f97a0d feat(ai): Add native chat service with streaming and tool execution
Replace the OpenCode sidecar with a native chat service that handles:
- Real-time streaming responses from AI providers
- Multi-turn conversation sessions with history
- Tool execution with automatic function calling
- Agentic workflows for autonomous task completion
- Patrol integration for automated health analysis

The chat service directly communicates with AI providers using the
new StreamingProvider interface, eliminating the need for an external
sidecar process. Sessions are managed in-memory with configurable
history limits.

Key components:
- service.go: Main chat service with provider integration
- session.go: Session management and message history
- agentic.go: Agentic loop for autonomous tool execution
- patrol.go: Patrol-specific chat context and analysis
- tools.go: Tool execution bridge to tools package
- types.go: Chat message and event type definitions
2026-01-19 19:12:04 +00:00
rcourtman 4fe3d7df77 feat(ai): Add streaming support and notable models to AI providers
- Add ChatStream method to all providers (Anthropic, OpenAI, Gemini, Ollama)
  for real-time streaming of AI responses with tool call support
- Add StreamingProvider interface with StreamEvent types for content,
  thinking, tool_start, tool_end, done, and error events
- Add notable models feature that fetches model metadata from models.dev
  to identify recent/recommended models (within last 3 months)
- Add Notable field to ModelInfo struct to flag "latest and greatest" models
- Add SupportsThinking method to check for extended reasoning capability

The streaming support enables real-time AI chat responses instead of
waiting for complete responses. The notable models feature helps users
identify which models are current and recommended.
2026-01-19 19:10:58 +00:00
rcourtman 17dec929a0 feat: Add mention support for webhook alerts. Related to #1118
Adds a Mention field to webhook configurations that allows users to tag
individuals or groups when alerts are sent. This works with:

- Discord: @everyone, <@USER_ID>, <@&ROLE_ID>
- Microsoft Teams: @General, user email
- Mattermost: @channel, @all, @username

The mention is included in the webhook payload via the {{.Mention}} template
variable. Built-in templates for Discord, Slack, and Teams now conditionally
include mentions when configured.

Backend changes:
- Add Mention field to WebhookConfig struct
- Add Mention field to WebhookPayloadData for template access
- Pass mention through sendGroupedWebhook

Frontend changes:
- Add mention field to Webhook interface
- Add Mention input to webhook configuration form
- Show service-specific help text for mention formats
2026-01-18 15:16:37 +00:00
rcourtman 71bcc570ad fix: Add nil checks in findDuplicate() to prevent crash. Related to #1119
When a resource exists in the hostname or IP index but has been removed from
the main resources map, looking up and accessing .Type would cause a nil
pointer dereference panic.

The MachineID lookup already had this check, but hostname and IP lookups
were missing it. This adds consistent nil checking across all three lookup
paths.
2026-01-18 13:41:00 +00:00
rcourtman 7d2e002caa fix: add sudo to mv command in deploy 2026-01-18 09:46:50 +00:00
rcourtman a40be03963 fix: use sudo for systemctl commands in deploy 2026-01-18 09:43:47 +00:00
rcourtman 3114775aa9 fix: clean up stale files before deploy 2026-01-18 09:40:42 +00:00
rcourtman bfe621eeb9 fix: use FRONTEND_PORT env var for health check port 2026-01-18 09:37:45 +00:00
rcourtman 4fbc08daba fix: use SSH key secret for demo server deployment 2026-01-18 09:32:19 +00:00
rcourtman 66fa6d45a7 chore: disable nightly demo deploys and switch to authkey 2026-01-18 09:26:12 +00:00
rcourtman 204a9fe084 perf: Cache agent profiles to prevent disk I/O on every report. Related to #1094
GetHostAgentConfig was loading profiles and assignments from disk on
every agent report (every 10-30 seconds per host). With multiple hosts,
this caused disk I/O contention that eventually led to request timeouts.

Added in-memory caching with 60-second TTL:
- Fast path reads from cache without locks when valid
- Double-checked locking pattern for cache refresh
- Cache auto-invalidates after TTL, no manual invalidation needed
2026-01-17 22:31:02 +00:00
rcourtman d2fb5d2e5e chore: ignore measure_sessions.sh 2026-01-17 18:56:16 +00:00
rcourtman 227d791afa feat: Dynamic precision for byte formatting. Closes #1116
formatBytes now uses 'auto' precision by default:
- Values < 10: 2 decimals (e.g., "5.94 GB")
- Values 10-100: 1 decimal (e.g., "45.2 GB")
- Values >= 100: 0 decimals (e.g., "256 GB")

Explicit decimal places still work: formatBytes(value, 2)
2026-01-17 16:39:32 +00:00
rcourtman f1b5f06702 fix: Docker update button stuck on 'Loading settings'. Related to #1114
When system settings API fails, the catch blocks in App.tsx now call
markSystemSettingsLoadedWithDefaults() to ensure the UI doesn't stay
permanently in a loading state with disabled update buttons.
2026-01-17 15:55:52 +00:00
rcourtman 432f13b6f5 feat(ai): add Docker update management MCP tools
Add three new MCP tools for Docker container update management:
- pulse_list_docker_updates: list containers with pending updates
- pulse_check_docker_updates: trigger update check on a host
- pulse_update_docker_container: apply update with approval workflow

Changes:
- Add UpdatesProvider interface to executor.go
- Add response types to data_types.go
- Add UpdatesMCPAdapter to adapters.go
- Register tools and handlers in tools_infrastructure.go
- Add SetUpdatesProvider() to service.go
- Wire provider in router.go wireOpenCodeProviders()
2026-01-17 15:47:36 +00:00
rcourtman 70102db985 fix(ui): AI chat panel collapse and session actions
Chat panel fixes:
- Fix collapse button not working (use store's isOpenSignal)
- Add isOpenSignal accessor for proper SolidJS reactivity
- Click-outside handler to close dropdowns

Session management UI:
- Session actions menu (summarize, diff, revert)
- Better tool result handling with exit codes
- Continuation messages after command execution
- Session title generation from first message

OpenCode API additions:
- Session summarize/diff/revert endpoints
- Better model format handling
2026-01-17 14:49:11 +00:00
rcourtman 4cea85ec97 feat(mcp): expand MCP tools and add session management APIs
New API endpoints:
- POST /api/ai/sessions/{id}/summarize - Compress context
- GET /api/ai/sessions/{id}/diff - Get file changes
- POST /api/ai/sessions/{id}/fork - Branch conversation
- POST /api/ai/sessions/{id}/revert - Undo changes
- POST /api/ai/sessions/{id}/unrevert - Restore reverted changes

MCP provider wiring:
- Storage, backup, disk health providers
- Metrics history, baseline, pattern detection
- Findings manager and metadata updater

Tool improvements:
- pulse_get_topology: Unified infrastructure view
- Improved tool descriptions with usage examples
- Better license checking with logging
2026-01-17 14:43:58 +00:00
rcourtman c26f0e6e6c feat(ai): improve OpenCode integration and control level handling
OpenCode client improvements:
- Fix session listing with proper timestamp parsing
- Model selection with provider inference (anthropic, google, etc)
- Add session management APIs (summarize, diff, fork, revert)
- Generated session titles from first user message

Control level refactoring:
- IsAutonomous() helper for cleaner checks
- Legacy autonomous_mode maps to control_level for backwards compat
- Simplified system instructions (rely on tool descriptions instead)

Includes tests for model provider inference.
2026-01-17 14:43:28 +00:00
rcourtman 103eb9c3e0 feat(monitoring): auto-detect Docker inside LXC containers
Adds automatic Docker detection for Proxmox LXC containers:
- New HasDocker and DockerCheckedAt fields on Container model
- Docker socket check via connected agents on first run, restart, or start
- Parallel checking with timeouts for efficiency
- Caches results and only re-checks after state transitions

This enables the AI to know which LXC containers are Docker hosts
for better infrastructure guidance.
2026-01-17 14:42:52 +00:00
rcourtman 3512069965 feat(license): grant Pro features in dev mode
Extends the demo mode behavior to also apply when PULSE_DEV=true,
allowing developers to test Pro features during development without
requiring a license key.
2026-01-17 14:42:27 +00:00
rcourtman 2c4d7edf58 feat(install): add watchdog restart loop for Unraid agents
Implements exponential backoff restart loop in the wrapper script
for Unraid/Slackware installations. When the agent exits unexpectedly,
it will automatically restart with increasing delays (5s -> 60s max).

This improves reliability for users who don't have systemd for
automatic service restarts.
2026-01-17 14:41:59 +00:00
rcourtman a9f342c09e fix(pre-commit): only re-stage files that were already staged
Prevents accidentally staging unrelated work-in-progress files when
the formatter modifies files during pre-commit hook.
2026-01-17 14:41:32 +00:00
rcourtman 3096ec53b5 fix: preserve alert activation state when saving config. Related to #1096 2026-01-16 14:24:02 +00:00
rcourtman 884ede22f1 fix: persist setup credentials for first-run wizard. Related to #1110 2026-01-16 13:58:06 +00:00
rcourtman 5507525ee4 fix: resolve TypeScript errors in AISettings and UnifiedAgents
- Add control_level and protected_guests to AISettings interface
- Add control_level and protected_guests to AISettingsUpdateRequest
- Fix type error in filteredRows by casting filterType as UnifiedAgentType
- Make formatRelativeTime and formatAbsoluteTime accept undefined
2026-01-15 21:26:39 +00:00
rcourtman e31b12a82b fix: avoid shell syntax error in uninstall command when no token is set
The uninstall command was including '--token <api-token>' as a literal
string when no token was configured, causing a shell syntax error when
users copied and ran it. The angle brackets are interpreted as shell
redirects.

The uninstall script works without a token (it's primarily a local
cleanup operation), so we now only include the token parameter when
a real token is available.

Related to #1099
2026-01-15 21:21:55 +00:00
rcourtman 56a126dbc2 fix: silence unused variable warnings in aiChat.ts 2026-01-15 21:18:55 +00:00
rcourtman 035436ad6e fix: add mutex to prevent concurrent map writes in Docker agent CPU tracking
The agent was crashing with 'fatal error: concurrent map writes' when
handleCheckUpdatesCommand spawned a goroutine that called collectOnce
concurrently with the main collection loop. Both code paths access
a.prevContainerCPU without synchronization.

Added a.cpuMu mutex to protect all accesses to prevContainerCPU in:
- pruneStaleCPUSamples()
- collectContainer() delete operation
- calculateContainerCPUPercent()

Related to #1063
2026-01-15 21:10:55 +00:00
rcourtman a7de907c35 chore: remove internal planning doc, add gitignore patterns
- Remove docs/AGENTS_AI_SCOPE_PLAN.md (internal dev doc)
- Add gitignore patterns for *_PLAN.md, *_ROADMAP.md, *IMPLEMENTATION*.md in docs/
2026-01-15 13:53:42 +00:00
rcourtman 8c7581d32c feat(profiles): add AI-assisted profile suggestions
Add ability for users to describe what kind of agent profile they need
in natural language, and have AI generate a suggestion with name,
description, config values, and rationale.

- Add ProfileSuggestionHandler with schema-aware prompting
- Add SuggestProfileModal component with example prompts
- Update AgentProfilesPanel with suggest button and description field
- Streamline ValidConfigKeys to only agent-supported settings
- Update profile validation tests for simplified schema
2026-01-15 13:24:18 +00:00
rcourtman 404f49959d fix(ui): preserve user preferences across logout sessions
Previously, logout cleared all localStorage, wiping user preferences
like column visibility, view modes, temperature units, and filters.
Now only auth and session-specific caches are cleared.

Fixes #1107
2026-01-14 23:38:28 +00:00
rcourtman 9b49d3171d feat(pbs): add datastore exclusion to reduce PBS log noise
Users with removable/unmounted datastores (e.g., external HDDs for
offline backup) experienced excessive PBS log entries because Pulse
was querying all datastores including unavailable ones.

Added `excludeDatastores` field to PBS node configuration that accepts
patterns to exclude specific datastores from monitoring:
- Exact names: "exthdd1500gb"
- Prefix patterns: "ext*"
- Suffix patterns: "*hdd"
- Contains patterns: "*removable*"

Pattern matching is case-insensitive.

Fixes #1105
2026-01-14 12:26:18 +00:00
rcourtman 3e74e689cd fix(api): increase Docker agent report size limit from 512KB to 2MB
Users with 100+ containers were hitting the payload size limit,
causing "Failed to decode request body" 400 errors. This aligns
the Docker agent limit with the Kubernetes agent limit (2MB).

Fixes #1104
2026-01-14 12:20:39 +00:00
rcourtman 038b57ee43 feat(ai): proxy OpenCode API paths for iframe embedding
OpenCode's frontend uses window.location.origin for API calls. When
embedded in Pulse's iframe, this points to Pulse instead of OpenCode.

This commit proxies OpenCode's API paths through Pulse:
- /global/, /session/, /tui/, /config/, /file/, /find/, /instance/,
  /mcp/, /permission/, /project/, /provider/, /pty/, /question/,
  /experimental/

Changes:
- router.go: Add OpenCode API paths to route check and register handlers
- ai_handler.go: Add HandleOpenCodeAPI to proxy requests to OpenCode
- vite.config.ts: Add proxy entries for OpenCode API paths
- AIChat.tsx: Revert to iframe approach now that proxying works
- ThinkingBlock.tsx: Make collapsible for better UX
2026-01-14 10:52:33 +00:00
rcourtman 67b9b5c0f8 fix(ai): use custom Chat component instead of OpenCode iframe
The iframe approach doesn't work because OpenCode's frontend tries to
connect to its backend at the page origin, which is Pulse instead of
OpenCode. The API/WebSocket calls fail.

Switch to using the custom Chat component which communicates with
OpenCode through Pulse's backend API (/api/ai/...), providing a
native Pulse experience with proper streaming and tool execution.
2026-01-14 10:39:34 +00:00
rcourtman 7f9995adf3 fix(ai): rewrite OpenCode asset paths for iframe embedding
OpenCode's HTML uses absolute paths like /assets/... for static files.
When embedded in Pulse's iframe, these paths don't go through the
/opencode/ proxy and fail to load.

Modified the proxy's ModifyResponse to rewrite src="/" and href="/"
attributes in HTML responses to include the /opencode/ prefix, ensuring
all assets load correctly through the proxy.
2026-01-14 10:35:37 +00:00
rcourtman 875d244b66 fix(ai): allow OpenCode UI to be embedded in iframe
The OpenCode reverse proxy now properly modifies response headers to
allow iframe embedding within Pulse's AI panel:

- ai_handler.go: Add ModifyResponse to strip X-Frame-Options and modify
  CSP frame-ancestors from OpenCode's responses
- security.go: Skip frame-related security headers for /opencode/ paths
  since the proxy manages its own headers

This fixes the "refused to connect" error when opening the AI sidebar.
2026-01-14 10:28:30 +00:00
rcourtman 668f00a905 fix(ai): disable session sync in favor of OpenCode
OpenCode handles session management internally through its embedded UI.
Disable the Pulse-side session sync to prevent 404 errors from calling
non-existent endpoints.

The aiChatStore still handles:
- Panel open/close state
- Context management for investigate buttons
- Initial prompt handling
2026-01-14 10:06:04 +00:00
rcourtman 316c3cbb6f feat(ai): embed OpenCode web UI in Pulse AI panel
Replace custom Chat components with an iframe that embeds OpenCode's
native web UI. This provides a more polished experience and automatically
benefits from OpenCode improvements.

Changes:
- Add reverse proxy for /opencode/ route to OpenCode's web server
- Simplify AIChat component to iframe wrapper with header
- Add GetBaseURL() method to OpenCode service
- Configure Vite proxy for development

The Pulse Pro value proposition is now: managed OpenCode deployment
with rich MCP tools that provide infrastructure context.
2026-01-14 09:53:02 +00:00
rcourtman e6a658a04d docs(ui): clarify kiosk mode usage in token preset description
Update the "Kiosk / Dashboard" token preset description to mention
the ?kiosk=1 URL parameter that hides navigation and filter panels,
making it clearer how to set up a wall display.

Addresses feedback from #1102
2026-01-13 23:46:34 +00:00
rcourtman 9cd53814a3 feat(alerts): add per-volume disk thresholds for host agents
Allow users to set custom disk usage thresholds per mounted filesystem
on host agents, rather than applying a single threshold to all volumes.

This addresses NAS/NVR use cases where some volumes (e.g., NVR storage)
intentionally run at 99% while others need strict monitoring.

Backend:
- Check for disk-specific overrides before using HostDefaults.Disk
- Override key format: host:<hostId>/disk:<mountpoint>
- Support both custom thresholds and disable per-disk

Frontend:
- Add 'hostDisk' resource type
- Add "Host Disks" collapsible section in Thresholds → Hosts tab
- Group disks by host for easier navigation

Closes #1103
2026-01-13 23:38:20 +00:00
rcourtman d73e57af86 Initialize SQLite audit logger for Pro license with audit_logging feature
The audit logging feature was showing the UI for Pro users but the
SQLiteLogger was never actually initialized - it fell back to the
ConsoleLogger which only writes to console and returns empty arrays
for queries.

This fix:
- Adds initAuditLoggerIfLicensed() helper to license_handlers.go
- Calls it when loading a persisted license at startup
- Calls it when activating a new license via API
- Creates SQLiteLogger with 90-day default retention when audit_logging
  feature is enabled

The audit.db will be created in {dataDir}/audit/ when Pro is licensed.
2026-01-13 10:06:48 +00:00
rcourtman d73f1c16ff fix: wait for license to load before showing upgrade CTAs
The upgrade banners were showing briefly even for Pro users because
hasFeature() returned false before the license status was loaded.

Now we check licenseLoaded() before showing the upgrade CTA.
2026-01-13 09:35:31 +00:00
rcourtman b177812fd3 revert: remove accidentally committed WIP OpenCode changes
Reverts unintended changes from 4e064aa0 that broke the frontend build.
The workflow fix for cmd/pulse package build remains intact.
2026-01-13 09:15:42 +00:00
rcourtman 4e064aa0cc fix: build entire cmd/pulse package, not just main.go
The static binary build was only compiling main.go, missing bootstrap.go
and config.go which define osExit, bootstrapTokenCmd, and configCmd.
2026-01-13 09:06:21 +00:00
rcourtman d389345153 fix(hosts): calculate Used memory from Total-Free for host agents in LXC
The previous fix (4090d981) addressed memory reporting for Docker agents
running in LXC containers, but the same issue also affects host agents.
When gopsutil runs inside an LXC, it can read Total and Free memory
from cgroup limits, but reports 0 for Used memory.

Added the same Total - Free fallback calculation to the host agent
processing path, which populates the Hosts tab.

Fixes #1075
2026-01-12 21:19:40 +00:00
rcourtman 0cc295066c fix(alerts): allow configuration access when alerts are disabled
Users should be able to configure alert thresholds, notifications, and
schedules regardless of whether alert notifications are enabled. The
enable/disable toggle only controls whether notifications are sent,
not whether users can access the configuration.

Previously, when alerts were in 'pending_review' or 'snoozed' state,
all configuration tabs were disabled, forcing users to the Overview
tab only.

Fixes #1101
2026-01-12 21:19:40 +00:00