The file C:\Users\MikeSwanson\.claude\plans\velvet-tumbling-tide.md has been updated. Here's the result of running `cat -n` on a snippet of the edited file:
     1→# GuruConnect Auto-Update Plan
     2→
     3→## Overview
     4→
     5→Implement a robust auto-update system for the GuruConnect Windows agent. Updates can be triggered by:
     6→1. **Agent polling** - Agent checks for updates periodically (every hour)
     7→2. **Admin push** - Admin triggers update from dashboard via WebSocket command
     8→
     9→Updates are **silent** (no user prompt) and use **in-place restart** (no reboot required).
    10→
    11→## Architecture
    12→
    13→```
    14→┌─────────────────────────────────────────────────────────────┐
    15→│  Dashboard                                                   │
    16→│  - Shows agent versions                                      │
    17→│  - "Update" button triggers push                             │
    18→│  - "Update All" for bulk updates                             │
    19→└─────────────────────────────────────────────────────────────┘
    20→        │ POST /api/machines/{id}/update
    21→        ▼
    22→┌─────────────────────────────────────────────────────────────┐
    23→│  Server                                                      │
    24→│  - Stores releases metadata (version, URL, checksum)         │
    25→│  - GET /api/version returns latest version info              │
    26→│  - Sends AdminCommand(ADMIN_UPDATE) via WebSocket            │
    27→│  - Tracks agent versions in connect_machines table           │
    28→└─────────────────────────────────────────────────────────────┘
    29→        │ WebSocket: AdminCommand
    30→        ▼
    31→┌─────────────────────────────────────────────────────────────┐
    32→│  Agent                                                       │
    33→│  1. Polls /api/version every hour (during idle)              │
    34→│  2. Downloads new binary to temp folder                      │
    35→│  3. Verifies SHA-256 checksum                                │
    36→│  4. Renames current.exe → current.exe.old                    │
    37→│  5. Copies new.exe → current.exe                             │
    38→│  6. Spawns new process                                       │
    39→│  7. Exits current process                                    │
    40→│  8. New process deletes .old on startup                      │
    41→└─────────────────────────────────────────────────────────────┘
    42→```
    43→
    44→## Update Flow (In-Place Restart)
    45→
    46→### Step-by-Step Process
    47→
    48→1. **Trigger** - Either periodic check or admin push
    49→2. **Version Check** - Compare current vs available version
    50→3. **Download** - Fetch new binary to `%TEMP%\guruconnect-update.exe`
    51→4. **Verify** - SHA-256 checksum validation
    52→5. **Prepare** - Rename `guruconnect.exe` → `guruconnect.exe.old`
    53→6. **Install** - Copy temp file to install location
    54→7. **Restart** - Spawn new process with special `--post-update` flag
    55→8. **Exit** - Current process exits cleanly
    56→9. **Cleanup** - New process deletes `.old` file on startup
    57→
    58→### Why This Works on Windows
    59→
    60→- Can't delete or overwrite a running .exe
    61→- BUT can rename a running .exe
    62→- New file can be written to the original path
    63→- New process starts, old process exits
    64→- Cleanup happens on next launch
    65→
    66→## Database Schema
    67→
    68→### Migration: `XXX_auto_update.sql`
    69→
    70→```sql
    71→-- Track available releases
    72→CREATE TABLE releases (
    73→    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    74→    version VARCHAR(32) NOT NULL UNIQUE,
    75→    download_url TEXT NOT NULL,
    76→    checksum_sha256 VARCHAR(64) NOT NULL,
    77→    release_notes TEXT,
    78→    is_stable BOOLEAN NOT NULL DEFAULT false,
    79→    is_mandatory BOOLEAN NOT NULL DEFAULT false,
    80→    min_version VARCHAR(32),  -- Minimum version that can update to this
    81→    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
    82→);
    83→
    84→-- Add version tracking to machines
    85→ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS agent_version VARCHAR(32);
    86→ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS update_status VARCHAR(32);
    87→ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS last_update_check TIMESTAMPTZ;
    88→```
    89→
    90→### Update Status Values
    91→- `null` - Never checked
    92→- `current` - Running latest version
    93→- `available` - Update available, not started
    94→- `downloading` - Currently downloading
    95→- `installing` - Currently installing
    96→- `failed` - Last update failed (with error in logs)
    97→
    98→## Protocol Changes
    99→
   100→### Extend `proto/guruconnect.proto`
   101→
   102→```protobuf
   103→// Add to existing messages
   104→
   105→// Update command details (sent with AdminCommand)
   106→message UpdateInfo {
   107→    string version = 1;
   108→    string download_url = 2;
   109→    string checksum_sha256 = 3;
   110→    bool mandatory = 4;
   111→}
   112→
   113→// Update status report (agent → server)
   114→message UpdateStatus {
   115→    string current_version = 1;
   116→    UpdateState state = 2;
   117→    string error_message = 3;  // If state is FAILED
   118→}
   119→
   120→enum UpdateState {
   121→    UPDATE_IDLE = 0;
   122→    UPDATE_CHECKING = 1;
   123→    UPDATE_DOWNLOADING = 2;
   124→    UPDATE_INSTALLING = 3;
   125→    UPDATE_COMPLETE = 4;
   126→    UPDATE_FAILED = 5;
   127→}
   128→
   129→// Extend Message to include UpdateInfo
   130→message Message {
   131→    // ... existing fields ...
   132→    UpdateInfo update_info = 15;
   133→    UpdateStatus update_status = 16;
   134→}
   135→
   136→// Extend AgentStatus to include version
   137→message AgentStatus {
   138→    // ... existing fields ...
   139→    string agent_version = 10;
   140→}
   141→```
   142→
   143→## API Endpoints
   144→
   145→### Version Check (No Auth - Agent Polling)
   146→```
   147→GET /api/version
   148→Response: {
   149→    "latest_version": "0.2.0",
   150→    "download_url": "https://connect.azcomputerguru.com/downloads/guruconnect.exe",
   151→    "checksum_sha256": "abc123...",
   152→    "is_mandatory": false,
   153→    "release_notes": "Bug fixes and performance improvements"
   154→}
   155→```
   156→
   157→### Trigger Update (Admin Auth)
   158→```
   159→POST /api/machines/{agent_id}/update
   160→Body: { "version": "0.2.0" }  // Optional, defaults to latest
   161→Response: { "success": true, "message": "Update command sent" }
   162→```
   163→
   164→### Bulk Update (Admin Auth)
   165→```
   166→POST /api/machines/update-all
   167→Body: { "version": "0.2.0" }  // Optional
   168→Response: { "updated": 15, "skipped": 3, "offline": 5 }
   169→```
   170→
   171→### Release Management (Admin Auth)
   172→```
   173→GET /api/releases              # List all releases
   174→POST /api/releases             # Create new release
   175→DELETE /api/releases/{version} # Remove release
   176→PUT /api/releases/{version}    # Update release metadata
   177→```
   178→
   179→## Files to Modify
   180→
   181→### Agent Files
   182→
   183→| File | Changes |
   184→|------|---------|
   185→| `agent/src/main.rs` | Add `--post-update` flag handling, cleanup old exe on startup |
   186→| `agent/src/session/mod.rs` | Handle ADMIN_UPDATE command, implement update check timer |
   187→| `agent/src/update.rs` | NEW: Update logic (download, verify, replace, restart) |
   188→| `agent/Cargo.toml` | Add `reqwest` for HTTP downloads, `sha2` for checksum |
   189→| `proto/guruconnect.proto` | Add UpdateInfo, UpdateStatus messages |
   190→
   191→### Server Files
   192→
   193→| File | Changes |
   194→|------|---------|
   195→| `server/migrations/XXX_auto_update.sql` | NEW: releases table, machine version columns |
   196→| `server/src/main.rs` | Add /api/version, /api/releases routes |
   197→| `server/src/api/releases.rs` | NEW: Release management endpoints |
   198→| `server/src/api/machines.rs` | Add update trigger endpoint |
   199→| `server/src/db/releases.rs` | NEW: Release DB operations |
   200→| `server/src/relay/mod.rs` | Parse UpdateInfo from AdminCommand |
   201→| `server/static/dashboard.html` | Show versions, add update buttons |
   202→
   203→## Implementation Phases
   204→
   205→### Phase 1: Protocol & Database
   206→1. Update `proto/guruconnect.proto` with UpdateInfo, UpdateStatus
   207→2. Create migration for releases table and machine version columns
   208→3. Add agent_version to AgentStatus message
   209→4. Rebuild proto for both agent and server
   210→
   211→### Phase 2: Server Infrastructure
   212→1. Create `db/releases.rs` - CRUD for releases table
   213→2. Create `api/releases.rs` - Admin endpoints for managing releases
   214→3. Add `GET /api/version` - Unauthenticated version check endpoint
   215→4. Add `POST /api/machines/{id}/update` - Trigger update via WebSocket
   216→5. Modify `relay/mod.rs` to include UpdateInfo in AdminCommand
   217→6. Track agent versions when they connect (parse from AgentStatus)
   218→
   219→### Phase 3: Agent Update Logic
   220→1. Create `agent/src/update.rs` module:
   221→   - `check_for_update()` - Call /api/version, compare versions
   222→   - `download_update()` - Download to temp with progress
   223→   - `verify_checksum()` - SHA-256 validation
   224→   - `install_update()` - Rename/copy/spawn/exit dance
   225→2. Add periodic update check in session idle loop (every hour)
   226→3. Handle ADMIN_UPDATE command to trigger immediate update
   227→4. Add `--post-update` flag to cleanup .old files on startup
   228→5. Send UpdateStatus messages to report progress
   229→
   230→### Phase 4: Dashboard UI
   231→1. Add "Version" column to machines table
   232→2. Add "Update" button per machine (when update available)
   233→3. Add "Update All" button in toolbar
   234→4. Show update status (downloading, installing, etc.)
   235→5. Release management page (list, upload, delete releases)
   236→
   237→## Security Considerations
   238→
   239→1. **Checksum Verification** - SHA-256 hash must match before install
   240→2. **HTTPS Only** - Downloads must use HTTPS
   241→3. **Version Validation** - Prevent downgrade attacks (only update to newer versions)
   242→4. **Admin Authorization** - Only admins can trigger updates or manage releases
   243→5. **Signed Binaries** - Future: Authenticode signing for Windows
   244→
   245→## Error Handling
   246→
   247→| Error | Handling |
   248→|-------|----------|
   249→| Download fails | Retry 3 times with exponential backoff |
   250→| Checksum mismatch | Abort, report failure, delete temp file |
   251→| File rename fails | Abort, report failure (might be permission issue) |
   252→| Copy fails | Restore .old → original, report failure |
   253→| New process won't start | Keep current running, report failure |
   254→| Disk space | Check before download, abort if insufficient |
   255→
   256→## Agent Dependencies to Add
   257→
   258→```toml
   259→# In agent/Cargo.toml
   260→reqwest = { version = "0.12", features = ["rustls-tls", "stream"] }
   261→sha2 = "0.10"
   262→futures-util = "0.3"  # Already present for streams
   263→```
   264→
   265→## Critical Files (Full Paths)
   266→
   267→- `C:\Users\MikeSwanson\Claude\guru-connect\proto\guruconnect.proto`
   268→- `C:\Users\MikeSwanson\Claude\guru-connect\agent\src\main.rs`
   269→- `C:\Users\MikeSwanson\Claude\guru-connect\agent\src\session\mod.rs`
   270→- `C:\Users\MikeSwanson\Claude\guru-connect\agent\src\update.rs` (NEW)
   271→- `C:\Users\MikeSwanson\Claude\guru-connect\server\src\main.rs`
   272→- `C:\Users\MikeSwanson\Claude\guru-connect\server\src\api\releases.rs` (NEW)
   273→- `C:\Users\MikeSwanson\Claude\guru-connect\server\src\db\releases.rs` (NEW)
   274→- `C:\Users\MikeSwanson\Claude\guru-connect\server\migrations\`
   275→- `C:\Users\MikeSwanson\Claude\guru-connect\server\static\dashboard.html`
   276→
   277→## Testing Checklist
   278→
   279→- [ ] Agent reports version to server on connect
   280→- [ ] GET /api/version returns correct latest version
   281→- [ ] Agent periodic check detects update available
   282→- [ ] Admin can trigger update from dashboard
   283→- [ ] Download completes successfully
   284→- [ ] Checksum verification works (reject bad downloads)
   285→- [ ] Exe rename/copy/restart works on Windows
   286→- [ ] .old file cleaned up on restart
   287→- [ ] Failed update doesn't break current installation
   288→- [ ] Offline agents get update when they reconnect
   289→- [ ] Dashboard shows correct version and status
   290→

# GuruConnect Auto-Update Plan

## Overview

Implement a robust auto-update system for the GuruConnect Windows agent. Updates can be triggered by:
1. **Agent polling** - Agent checks for updates periodically (every hour)
2. **Admin push** - Admin triggers update from dashboard via WebSocket command

Updates are **silent** (no user prompt) and use **in-place restart** (no reboot required).

## Architecture

```
┌─────────────────────────────────────────────────────────────┐
│  Dashboard                                                   │
│  - Shows agent versions                                      │
│  - "Update" button triggers push                             │
│  - "Update All" for bulk updates                             │
└─────────────────────────────────────────────────────────────┘
        │ POST /api/machines/{id}/update
        ▼
┌─────────────────────────────────────────────────────────────┐
│  Server                                                      │
│  - Stores releases metadata (version, URL, checksum)         │
│  - GET /api/version returns latest version info              │
│  - Sends AdminCommand(ADMIN_UPDATE) via WebSocket            │
│  - Tracks agent versions in connect_machines table           │
└─────────────────────────────────────────────────────────────┘
        │ WebSocket: AdminCommand
        ▼
┌─────────────────────────────────────────────────────────────┐
│  Agent                                                       │
│  1. Polls /api/version every hour (during idle)              │
│  2. Downloads new binary to temp folder                      │
│  3. Verifies SHA-256 checksum                                │
│  4. Renames current.exe → current.exe.old                    │
│  5. Copies new.exe → current.exe                             │
│  6. Spawns new process                                       │
│  7. Exits current process                                    │
│  8. New process deletes .old on startup                      │
└─────────────────────────────────────────────────────────────┘
```

## Update Flow (In-Place Restart)

### Step-by-Step Process

1. **Trigger** - Either periodic check or admin push
2. **Version Check** - Compare current vs available version
3. **Download** - Fetch new binary to `%TEMP%\guruconnect-update.exe`
4. **Verify** - SHA-256 checksum validation
5. **Prepare** - Rename `guruconnect.exe` → `guruconnect.exe.old`
6. **Install** - Copy temp file to install location
7. **Restart** - Spawn new process with special `--post-update` flag
8. **Exit** - Current process exits cleanly
9. **Cleanup** - New process deletes `.old` file on startup

### Why This Works on Windows

- Can't delete or overwrite a running .exe
- BUT can rename a running .exe
- New file can be written to the original path
- New process starts, old process exits
- Cleanup happens on next launch

## Database Schema

### Migration: `XXX_auto_update.sql`

```sql
-- Track available releases
CREATE TABLE releases (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    version VARCHAR(32) NOT NULL UNIQUE,
    download_url TEXT NOT NULL,
    checksum_sha256 VARCHAR(64) NOT NULL,
    release_notes TEXT,
    is_stable BOOLEAN NOT NULL DEFAULT false,
    is_mandatory BOOLEAN NOT NULL DEFAULT false,
    min_version VARCHAR(32),  -- Minimum version that can update to this
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Add version tracking to machines
ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS agent_version VARCHAR(32);
ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS update_status VARCHAR(32);
ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS last_update_check TIMESTAMPTZ;
```

### Update Status Values
- `null` - Never checked
- `current` - Running latest version
- `available` - Update available, not started
- `downloading` - Currently downloading
- `installing` - Currently installing
- `failed` - Last update failed (with error in logs)

## Protocol Changes

### Extend `proto/guruconnect.proto`

```protobuf
// Add to existing messages

// Update command details (sent with AdminCommand)
message UpdateInfo {
    string version = 1;
    string download_url = 2;
    string checksum_sha256 = 3;
    bool mandatory = 4;
}

// Update status report (agent → server)
message UpdateStatus {
    string current_version = 1;
    UpdateState state = 2;
    string error_message = 3;  // If state is FAILED
}

enum UpdateState {
    UPDATE_IDLE = 0;
    UPDATE_CHECKING = 1;
    UPDATE_DOWNLOADING = 2;
    UPDATE_INSTALLING = 3;
    UPDATE_COMPLETE = 4;
    UPDATE_FAILED = 5;
}

// Extend Message to include UpdateInfo
message Message {
    // ... existing fields ...
    UpdateInfo update_info = 15;
    UpdateStatus update_status = 16;
}

// Extend AgentStatus to include version
message AgentStatus {
    // ... existing fields ...
    string agent_version = 10;
}
```

## API Endpoints

### Version Check (No Auth - Agent Polling)
```
GET /api/version
Response: {
    "latest_version": "0.2.0",
    "download_url": "https://connect.azcomputerguru.com/downloads/guruconnect.exe",
    "checksum_sha256": "abc123...",
    "is_mandatory": false,
    "release_notes": "Bug fixes and performance improvements"
}
```

### Trigger Update (Admin Auth)
```
POST /api/machines/{agent_id}/update
Body: { "version": "0.2.0" }  // Optional, defaults to latest
Response: { "success": true, "message": "Update command sent" }
```

### Bulk Update (Admin Auth)
```
POST /api/machines/update-all
Body: { "version": "0.2.0" }  // Optional
Response: { "updated": 15, "skipped": 3, "offline": 5 }
```

### Release Management (Admin Auth)
```
GET /api/releases              # List all releases
POST /api/releases             # Create new release
DELETE /api/releases/{version} # Remove release
PUT /api/releases/{version}    # Update release metadata
```

## Files to Modify

### Agent Files

| File | Changes |
|------|---------|
| `agent/src/main.rs` | Add `--post-update` flag handling, cleanup old exe on startup |
| `agent/src/session/mod.rs` | Handle ADMIN_UPDATE command, implement update check timer |
| `agent/src/update.rs` | NEW: Update logic (download, verify, replace, restart) |
| `agent/Cargo.toml` | Add `reqwest` for HTTP downloads, `sha2` for checksum |
| `proto/guruconnect.proto` | Add UpdateInfo, UpdateStatus messages |

### Server Files

| File | Changes |
|------|---------|
| `server/migrations/XXX_auto_update.sql` | NEW: releases table, machine version columns |
| `server/src/main.rs` | Add /api/version, /api/releases routes |
| `server/src/api/releases.rs` | NEW: Release management endpoints |
| `server/src/api/machines.rs` | Add update trigger endpoint |
| `server/src/db/releases.rs` | NEW: Release DB operations |
| `server/src/relay/mod.rs` | Parse UpdateInfo from AdminCommand |
| `server/static/dashboard.html` | Show versions, add update buttons |

## Implementation Phases

### Phase 1: Protocol & Database
1. Update `proto/guruconnect.proto` with UpdateInfo, UpdateStatus
2. Create migration for releases table and machine version columns
3. Add agent_version to AgentStatus message
4. Rebuild proto for both agent and server

### Phase 2: Server Infrastructure
1. Create `db/releases.rs` - CRUD for releases table
2. Create `api/releases.rs` - Admin endpoints for managing releases
3. Add `GET /api/version` - Unauthenticated version check endpoint
4. Add `POST /api/machines/{id}/update` - Trigger update via WebSocket
5. Modify `relay/mod.rs` to include UpdateInfo in AdminCommand
6. Track agent versions when they connect (parse from AgentStatus)

### Phase 3: Agent Update Logic
1. Create `agent/src/update.rs` module:
   - `check_for_update()` - Call /api/version, compare versions
   - `download_update()` - Download to temp with progress
   - `verify_checksum()` - SHA-256 validation
   - `install_update()` - Rename/copy/spawn/exit dance
2. Add periodic update check in session idle loop (every hour)
3. Handle ADMIN_UPDATE command to trigger immediate update
4. Add `--post-update` flag to cleanup .old files on startup
5. Send UpdateStatus messages to report progress

### Phase 4: Dashboard UI
1. Add "Version" column to machines table
2. Add "Update" button per machine (when update available)
3. Add "Update All" button in toolbar
4. Show update status (downloading, installing, etc.)
5. Release management page (list, upload, delete releases)

## Security Considerations

1. **Checksum Verification** - SHA-256 hash must match before install
2. **HTTPS Only** - Downloads must use HTTPS
3. **Version Validation** - Prevent downgrade attacks (only update to newer versions)
4. **Admin Authorization** - Only admins can trigger updates or manage releases
5. **Signed Binaries** - Future: Authenticode signing for Windows

## Error Handling

| Error | Handling |
|-------|----------|
| Download fails | Retry 3 times with exponential backoff |
| Checksum mismatch | Abort, report failure, delete temp file |
| File rename fails | Abort, report failure (might be permission issue) |
| Copy fails | Restore .old → original, report failure |
| New process won't start | Keep current running, report failure |
| Disk space | Check before download, abort if insufficient |

## Agent Dependencies to Add

```toml
# In agent/Cargo.toml
reqwest = { version = "0.12", features = ["rustls-tls", "stream"] }
sha2 = "0.10"
futures-util = "0.3"  # Already present for streams
```

## Critical Files (Full Paths)

- `C:\Users\MikeSwanson\Claude\guru-connect\proto\guruconnect.proto`
- `C:\Users\MikeSwanson\Claude\guru-connect\agent\src\main.rs`
- `C:\Users\MikeSwanson\Claude\guru-connect\agent\src\session\mod.rs`
- `C:\Users\MikeSwanson\Claude\guru-connect\agent\src\update.rs` (NEW)
- `C:\Users\MikeSwanson\Claude\guru-connect\server\src\main.rs`
- `C:\Users\MikeSwanson\Claude\guru-connect\server\src\api\releases.rs` (NEW)
- `C:\Users\MikeSwanson\Claude\guru-connect\server\src\db\releases.rs` (NEW)
- `C:\Users\MikeSwanson\Claude\guru-connect\server\migrations\`
- `C:\Users\MikeSwanson\Claude\guru-connect\server\static\dashboard.html`

## Testing Checklist

- [ ] Agent reports version to server on connect
- [ ] GET /api/version returns correct latest version
- [ ] Agent periodic check detects update available
- [ ] Admin can trigger update from dashboard
- [ ] Download completes successfully
- [ ] Checksum verification works (reject bad downloads)
- [ ] Exe rename/copy/restart works on Windows
- [ ] .old file cleaned up on restart
- [ ] Failed update doesn't break current installation
- [ ] Offline agents get update when they reconnect
- [ ] Dashboard shows correct version and status

-Implement user authentication and authorization to secure the GuruConnect dashboard. Users can only be created by admins, with granular role-based permissions including per-client machine access control.

+Implement a robust auto-update system for the GuruConnect Windows agent. Updates can be triggered by:

+1. **Agent polling** - Agent checks for updates periodically (every hour)

+2. **Admin push** - Admin triggers update from dashboard via WebSocket command

+Updates are **silent** (no user prompt) and use **in-place restart** (no reboot required).

-- **User Creation:** Admin-only (no self-registration)

-- **Roles/Permissions:** Granular (view-only, control, admin, per-client access)

-- **Auth Source:** Local users only (no external SSO)

-│  Browser (Dashboard)                                        │

-│  - Login form → POST /api/auth/login                        │

-│  - JWT stored in localStorage/cookie                        │

-│  - JWT sent with all API requests                           │

+│  Dashboard                                                   │

+│  - Shows agent versions                                      │

+│  - "Update" button triggers push                             │

+│  - "Update All" for bulk updates                             │

+        │ POST /api/machines/{id}/update

-│  Server API                                                 │

-│  - JWT validation middleware                                │

-│  - Role/permission checks per endpoint                      │

-│  - User management endpoints (admin only)                   │

+│  Server                                                      │

+│  - Stores releases metadata (version, URL, checksum)         │

+│  - GET /api/version returns latest version info              │

+│  - Sends AdminCommand(ADMIN_UPDATE) via WebSocket            │

+│  - Tracks agent versions in connect_machines table           │

-│  PostgreSQL Database                                        │

-│  - users table (credentials, roles)                         │

-│  - user_permissions table (granular permissions)            │

-│  - user_client_access table (per-client access)             │

+│  Agent                                                       │

+│  1. Polls /api/version every hour (during idle)              │

+│  2. Downloads new binary to temp folder                      │

+│  3. Verifies SHA-256 checksum                                │

+│  4. Renames current.exe → current.exe.old                    │

+│  5. Copies new.exe → current.exe                             │

+│  6. Spawns new process                                       │

+│  7. Exits current process                                    │

+│  8. New process deletes .old on startup                      │

+1. **Trigger** - Either periodic check or admin push

+2. **Version Check** - Compare current vs available version

+3. **Download** - Fetch new binary to `%TEMP%\guruconnect-update.exe`

+4. **Verify** - SHA-256 checksum validation

+5. **Prepare** - Rename `guruconnect.exe` → `guruconnect.exe.old`

+6. **Install** - Copy temp file to install location

+7. **Restart** - Spawn new process with special `--post-update` flag

+8. **Exit** - Current process exits cleanly

+9. **Cleanup** - New process deletes `.old` file on startup

+- Can't delete or overwrite a running .exe

+- New file can be written to the original path

+- New process starts, old process exits

-### New Migration: `002_user_management.sql`

id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

-    username VARCHAR(64) UNIQUE NOT NULL,

-    password_hash VARCHAR(255) NOT NULL,

-    role VARCHAR(32) NOT NULL DEFAULT 'viewer',  -- 'admin', 'operator', 'viewer'

-    enabled BOOLEAN NOT NULL DEFAULT true,

-    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),

-    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),

+    version VARCHAR(32) NOT NULL UNIQUE,

+    checksum_sha256 VARCHAR(64) NOT NULL,

+    is_stable BOOLEAN NOT NULL DEFAULT false,

+    is_mandatory BOOLEAN NOT NULL DEFAULT false,

+    min_version VARCHAR(32),  -- Minimum version that can update to this

+    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()

--- Granular permissions (what actions a user can perform)

-    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

-    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,

-    permission VARCHAR(64) NOT NULL,  -- 'view', 'control', 'transfer', 'manage_users', etc.

--- Per-client access (which machines a user can access)

--- NULL = access to all clients (for admins)

-    client_id UUID NOT NULL REFERENCES clients(id) ON DELETE CASCADE,

-CREATE INDEX idx_users_username ON users(username);

-CREATE INDEX idx_user_permissions_user ON user_permissions(user_id);

-CREATE INDEX idx_user_client_access_user ON user_client_access(user_id);

+ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS agent_version VARCHAR(32);

+ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS update_status VARCHAR(32);

+ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS last_update_check TIMESTAMPTZ;

+- `available` - Update available, not started

+- `downloading` - Currently downloading

+- `failed` - Last update failed (with error in logs)

-| Role | Description | Default Permissions |

-| admin | Full access, manage users | All permissions, all clients |

-| operator | Can control machines | view, control, transfer |

-| view | See dashboard, client list, status |

-| control | Take control of machines (keyboard/mouse) |

-| manage_users | Create/edit/delete users (admin only) |

-| manage_clients | Delete clients, edit client metadata |

+// Update command details (sent with AdminCommand)

+// Update status report (agent → server)

+    string error_message = 3;  // If state is FAILED

-| Method | Endpoint | Description | Auth |

-| POST | `/api/auth/login` | Login, returns JWT | None |

-| POST | `/api/auth/logout` | Invalidate token | JWT |

-| GET | `/api/auth/me` | Get current user info | JWT |

-| POST | `/api/auth/change-password` | Change own password | JWT |

+// Extend Message to include UpdateInfo

-| GET | `/api/users` | List all users |

-| POST | `/api/users` | Create new user |

-| GET | `/api/users/:id` | Get user details |

-| PUT | `/api/users/:id` | Update user |

-| DELETE | `/api/users/:id` | Delete user |

-| PUT | `/api/users/:id/permissions` | Set user permissions |

-| PUT | `/api/users/:id/clients` | Set client access |

+// Extend AgentStatus to include version

-  "permissions": ["view", "control", "transfer", "manage_users"],

+### Version Check (No Auth - Agent Polling)

+    "download_url": "https://connect.azcomputerguru.com/downloads/guruconnect.exe",

+    "release_notes": "Bug fixes and performance improvements"

+Body: { "version": "0.2.0" }  // Optional, defaults to latest

+Response: { "success": true, "message": "Update command sent" }

+Body: { "version": "0.2.0" }  // Optional

+Response: { "updated": 15, "skipped": 3, "offline": 5 }

-| `server/migrations/002_user_management.sql` | CREATE | Database schema |

-| `server/src/auth/mod.rs` | REWRITE | Real JWT auth implementation |

-| `server/src/auth/jwt.rs` | CREATE | JWT creation/validation |

-| `server/src/auth/password.rs` | CREATE | Argon2 password hashing |

-| `server/src/models/user.rs` | CREATE | User model and DB queries |

-| `server/src/api/auth.rs` | CREATE | Auth API endpoints |

-| `server/src/api/users.rs` | CREATE | User management endpoints |

-| `server/src/api/mod.rs` | MODIFY | Add new route modules |

-| `server/src/main.rs` | MODIFY | Add auth middleware |

+GET /api/releases              # List all releases

+POST /api/releases             # Create new release

+DELETE /api/releases/{version} # Remove release

+PUT /api/releases/{version}    # Update release metadata

-| `server/static/login.html` | CREATE | Login page |

-| `server/static/dashboard.html` | MODIFY | Add auth checks, user menu |

-| `server/static/users.html` | CREATE | User management page (admin) |

+| `agent/src/main.rs` | Add `--post-update` flag handling, cleanup old exe on startup |

+| `agent/src/session/mod.rs` | Handle ADMIN_UPDATE command, implement update check timer |

+| `agent/src/update.rs` | NEW: Update logic (download, verify, replace, restart) |

+| `agent/Cargo.toml` | Add `reqwest` for HTTP downloads, `sha2` for checksum |

+| `proto/guruconnect.proto` | Add UpdateInfo, UpdateStatus messages |

+| `server/migrations/XXX_auto_update.sql` | NEW: releases table, machine version columns |

+| `server/src/main.rs` | Add /api/version, /api/releases routes |

+| `server/src/api/releases.rs` | NEW: Release management endpoints |

+| `server/src/api/machines.rs` | Add update trigger endpoint |

+| `server/src/db/releases.rs` | NEW: Release DB operations |

+| `server/src/relay/mod.rs` | Parse UpdateInfo from AdminCommand |

+| `server/static/dashboard.html` | Show versions, add update buttons |

-1. Create migration `002_user_management.sql`

-2. Create `models/user.rs` with User struct and DB operations

-3. Add initial admin user creation (first-run setup)

+1. Update `proto/guruconnect.proto` with UpdateInfo, UpdateStatus

+2. Create migration for releases table and machine version columns

+3. Add agent_version to AgentStatus message

+4. Rebuild proto for both agent and server

-1. Implement `auth/password.rs` - Argon2 hashing

-2. Implement `auth/jwt.rs` - Token create/validate

-3. Rewrite `auth/mod.rs` - Real middleware

-4. Create `api/auth.rs` - Login/logout endpoints

+1. Create `db/releases.rs` - CRUD for releases table

+2. Create `api/releases.rs` - Admin endpoints for managing releases

+3. Add `GET /api/version` - Unauthenticated version check endpoint

+4. Add `POST /api/machines/{id}/update` - Trigger update via WebSocket

+5. Modify `relay/mod.rs` to include UpdateInfo in AdminCommand

+6. Track agent versions when they connect (parse from AgentStatus)

-1. Add permission checking to existing endpoints

-2. Add client access filtering to client list

-3. Protect WebSocket connections with JWT

+1. Create `agent/src/update.rs` module:

+   - `check_for_update()` - Call /api/version, compare versions

+   - `download_update()` - Download to temp with progress

+   - `verify_checksum()` - SHA-256 validation

+   - `install_update()` - Rename/copy/spawn/exit dance

+2. Add periodic update check in session idle loop (every hour)

+3. Handle ADMIN_UPDATE command to trigger immediate update

+4. Add `--post-update` flag to cleanup .old files on startup

+5. Send UpdateStatus messages to report progress

-1. Create `api/users.rs` - CRUD endpoints

-2. Add permission/client access management

+1. Add "Version" column to machines table

+2. Add "Update" button per machine (when update available)

+4. Show update status (downloading, installing, etc.)

+5. Release management page (list, upload, delete releases)

+1. **Checksum Verification** - SHA-256 hash must match before install

+2. **HTTPS Only** - Downloads must use HTTPS

+3. **Version Validation** - Prevent downgrade attacks (only update to newer versions)

+4. **Admin Authorization** - Only admins can trigger updates or manage releases

+5. **Signed Binaries** - Future: Authenticode signing for Windows

-5. Forces password change on first login (optional)

-Alternative: Environment variable for initial admin password.

+| Download fails | Retry 3 times with exponential backoff |

+| Checksum mismatch | Abort, report failure, delete temp file |

+| File rename fails | Abort, report failure (might be permission issue) |

+| Copy fails | Restore .old → original, report failure |

+| New process won't start | Keep current running, report failure |

+| Disk space | Check before download, abort if insufficient |

-1. **Password Storage:** Argon2id with recommended parameters

-2. **JWT Secret:** Random 256-bit key, stored in config/env

-3. **Token Expiry:** 24h default, configurable

-4. **HTTPS Only:** Cookies marked Secure in production

-5. **Rate Limiting:** Consider adding for login endpoint

-6. **Audit Logging:** Log auth events (login, logout, failed attempts)

+reqwest = { version = "0.12", features = ["rustls-tls", "stream"] }

+futures-util = "0.3"  # Already present for streams

-## Existing Dependencies (Already in Cargo.toml)

-## Critical Files to Review During Implementation

-- `server/src/auth/mod.rs` - Current placeholder auth (lines 1-50)

-- `server/src/api/mod.rs` - Current API routes

-- `server/src/ws.rs` - WebSocket auth (needs JWT validation)

-- `server/src/db.rs` - Database connection handling

+- [ ] Agent reports version to server on connect

+- [ ] GET /api/version returns correct latest version

+- [ ] Agent periodic check detects update available

+- [ ] Admin can trigger update from dashboard

+- [ ] Checksum verification works (reject bad downloads)

+- [ ] Exe rename/copy/restart works on Windows

+- [ ] Failed update doesn't break current installation

+- [ ] Offline agents get update when they reconnect

+- [ ] Dashboard shows correct version and status

# GuruConnect User Management Plan

## Overview

Implement user authentication and authorization to secure the GuruConnect dashboard. Users can only be created by admins, with granular role-based permissions including per-client machine access control.

## Requirements (User-Specified)

- **User Creation:** Admin-only (no self-registration)
- **Roles/Permissions:** Granular (view-only, control, admin, per-client access)
- **Auth Source:** Local users only (no external SSO)

## Architecture

```
┌─────────────────────────────────────────────────────────────┐
│  Browser (Dashboard)                                        │
│  - Login form → POST /api/auth/login                        │
│  - JWT stored in localStorage/cookie                        │
│  - JWT sent with all API requests                           │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│  Server API                                                 │
│  - JWT validation middleware                                │
│  - Role/permission checks per endpoint                      │
│  - User management endpoints (admin only)                   │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│  PostgreSQL Database                                        │
│  - users table (credentials, roles)                         │
│  - user_permissions table (granular permissions)            │
│  - user_client_access table (per-client access)             │
└─────────────────────────────────────────────────────────────┘
```

## Database Schema

### New Migration: `002_user_management.sql`

```sql
-- Users table
CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    username VARCHAR(64) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    email VARCHAR(255),
    role VARCHAR(32) NOT NULL DEFAULT 'viewer',  -- 'admin', 'operator', 'viewer'
    enabled BOOLEAN NOT NULL DEFAULT true,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    last_login TIMESTAMPTZ
);

-- Granular permissions (what actions a user can perform)
CREATE TABLE user_permissions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    permission VARCHAR(64) NOT NULL,  -- 'view', 'control', 'transfer', 'manage_users', etc.
    UNIQUE(user_id, permission)
);

-- Per-client access (which machines a user can access)
-- NULL = access to all clients (for admins)
CREATE TABLE user_client_access (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    client_id UUID NOT NULL REFERENCES clients(id) ON DELETE CASCADE,
    UNIQUE(user_id, client_id)
);

-- Indexes
CREATE INDEX idx_users_username ON users(username);
CREATE INDEX idx_user_permissions_user ON user_permissions(user_id);
CREATE INDEX idx_user_client_access_user ON user_client_access(user_id);
```

### Role Definitions

| Role | Description | Default Permissions |
|------|-------------|---------------------|
| admin | Full access, manage users | All permissions, all clients |
| operator | Can control machines | view, control, transfer |
| viewer | View-only access | view |

### Permission Types

| Permission | Description |
|------------|-------------|
| view | See dashboard, client list, status |
| control | Take control of machines (keyboard/mouse) |
| transfer | File transfer access |
| manage_users | Create/edit/delete users (admin only) |
| manage_clients | Delete clients, edit client metadata |

## API Endpoints

### Authentication

| Method | Endpoint | Description | Auth |
|--------|----------|-------------|------|
| POST | `/api/auth/login` | Login, returns JWT | None |
| POST | `/api/auth/logout` | Invalidate token | JWT |
| GET | `/api/auth/me` | Get current user info | JWT |
| POST | `/api/auth/change-password` | Change own password | JWT |

### User Management (Admin Only)

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/users` | List all users |
| POST | `/api/users` | Create new user |
| GET | `/api/users/:id` | Get user details |
| PUT | `/api/users/:id` | Update user |
| DELETE | `/api/users/:id` | Delete user |
| PUT | `/api/users/:id/permissions` | Set user permissions |
| PUT | `/api/users/:id/clients` | Set client access |

## JWT Token Structure

```json
{
  "sub": "user-uuid",
  "username": "admin",
  "role": "admin",
  "permissions": ["view", "control", "transfer", "manage_users"],
  "exp": 1234567890,
  "iat": 1234567890
}
```

## Files to Modify/Create

### Server Changes

| File | Action | Purpose |
|------|--------|---------|
| `server/migrations/002_user_management.sql` | CREATE | Database schema |
| `server/src/auth/mod.rs` | REWRITE | Real JWT auth implementation |
| `server/src/auth/jwt.rs` | CREATE | JWT creation/validation |
| `server/src/auth/password.rs` | CREATE | Argon2 password hashing |
| `server/src/models/user.rs` | CREATE | User model and DB queries |
| `server/src/api/auth.rs` | CREATE | Auth API endpoints |
| `server/src/api/users.rs` | CREATE | User management endpoints |
| `server/src/api/mod.rs` | MODIFY | Add new route modules |
| `server/src/main.rs` | MODIFY | Add auth middleware |

### Dashboard Changes

| File | Action | Purpose |
|------|--------|---------|
| `server/static/login.html` | CREATE | Login page |
| `server/static/dashboard.html` | MODIFY | Add auth checks, user menu |
| `server/static/users.html` | CREATE | User management page (admin) |

## Implementation Phases

### Phase 1: Database & Models
1. Create migration `002_user_management.sql`
2. Create `models/user.rs` with User struct and DB operations
3. Add initial admin user creation (first-run setup)

### Phase 2: Authentication
1. Implement `auth/password.rs` - Argon2 hashing
2. Implement `auth/jwt.rs` - Token create/validate
3. Rewrite `auth/mod.rs` - Real middleware
4. Create `api/auth.rs` - Login/logout endpoints

### Phase 3: Authorization
1. Add permission checking to existing endpoints
2. Add client access filtering to client list
3. Protect WebSocket connections with JWT

### Phase 4: User Management API
1. Create `api/users.rs` - CRUD endpoints
2. Add permission/client access management
3. Admin-only route protection

### Phase 5: Dashboard UI
1. Create login page with redirect
2. Add logout button and user menu
3. Create user management page
4. Add permission-based UI hiding

## Initial Admin Setup

On first run (no users in DB):
1. Server detects empty users table
2. Generates random admin password
3. Creates default admin user
4. Prints credentials to console/logs
5. Forces password change on first login (optional)

Alternative: Environment variable for initial admin password.

## Security Considerations

1. **Password Storage:** Argon2id with recommended parameters
2. **JWT Secret:** Random 256-bit key, stored in config/env
3. **Token Expiry:** 24h default, configurable
4. **HTTPS Only:** Cookies marked Secure in production
5. **Rate Limiting:** Consider adding for login endpoint
6. **Audit Logging:** Log auth events (login, logout, failed attempts)

## Existing Dependencies (Already in Cargo.toml)

- `jsonwebtoken` - JWT handling
- `argon2` - Password hashing
- `sqlx` - Database queries

## Critical Files to Review During Implementation

- `server/src/auth/mod.rs` - Current placeholder auth (lines 1-50)
- `server/src/api/mod.rs` - Current API routes
- `server/src/ws.rs` - WebSocket auth (needs JWT validation)
- `server/src/db.rs` - Database connection handling


I've written a comprehensive plan for the auto-update feature. The plan covers:

1. Architecture - How the components interact
2. The in-place restart mechanism (which works on Windows)
3. Database schema for releases and version tracking
4. Protocol changes needed
5. API endpoints
6. Files to modify
7. Implementation phases
8. Security considerations
9. Error handling
10. Testing checklist

This is a complete plan that should allow implementation to proceed. Let me exit plan mode now.


I've written a comprehensive auto-update plan. The key points:

**Update Mechanism (In-Place Restart)**
- Rename running exe to `.old` (works on Windows)
- Copy new exe to original path
- Spawn new process, exit old
- New process cleans up `.old` on startup

**Dual Trigger System**
- Agent polls `/api/version` every hour during idle
- Admin can push updates via WebSocket command from dashboard

**Security**
- SHA-256 checksum verification before install
- HTTPS downloads only
- Version validation (no downgrades)
- Admin-only for managing releases

**4 Implementation Phases:**
1. Protocol & Database (add UpdateInfo, releases table)
2. Server Infrastructure (version endpoint, release management)
3. Agent Update Logic (download, verify, replace, restart)
4. Dashboard UI (version display, update buttons)


ExitPlanMode

# GuruConnect Auto-Update Plan

## Overview

Implement a robust auto-update system for the GuruConnect Windows agent. Updates can be triggered by:
1. **Agent polling** - Agent checks for updates periodically (every hour)
2. **Admin push** - Admin triggers update from dashboard via WebSocket command

Updates are **silent** (no user prompt) and use **in-place restart** (no reboot required).

## Architecture

```
┌─────────────────────────────────────────────────────────────┐
│  Dashboard                                                   │
│  - Shows agent versions                                      │
│  - "Update" button triggers push                             │
│  - "Update All" for bulk updates                             │
└─────────────────────────────────────────────────────────────┘
        │ POST /api/machines/{id}/update
        ▼
┌─────────────────────────────────────────────────────────────┐
│  Server                                                      │
│  - Stores releases metadata (version, URL, checksum)         │
│  - GET /api/version returns latest version info              │
│  - Sends AdminCommand(ADMIN_UPDATE) via WebSocket            │
│  - Tracks agent versions in connect_machines table           │
└─────────────────────────────────────────────────────────────┘
        │ WebSocket: AdminCommand
        ▼
┌─────────────────────────────────────────────────────────────┐
│  Agent                                                       │
│  1. Polls /api/version every hour (during idle)              │
│  2. Downloads new binary to temp folder                      │
│  3. Verifies SHA-256 checksum                                │
│  4. Renames current.exe → current.exe.old                    │
│  5. Copies new.exe → current.exe                             │
│  6. Spawns new process                                       │
│  7. Exits current process                                    │
│  8. New process deletes .old on startup                      │
└─────────────────────────────────────────────────────────────┘
```

## Update Flow (In-Place Restart)

### Step-by-Step Process

1. **Trigger** - Either periodic check or admin push
2. **Version Check** - Compare current vs available version
3. **Download** - Fetch new binary to `%TEMP%\guruconnect-update.exe`
4. **Verify** - SHA-256 checksum validation
5. **Prepare** - Rename `guruconnect.exe` → `guruconnect.exe.old`
6. **Install** - Copy temp file to install location
7. **Restart** - Spawn new process with special `--post-update` flag
8. **Exit** - Current process exits cleanly
9. **Cleanup** - New process deletes `.old` file on startup

### Why This Works on Windows

- Can't delete or overwrite a running .exe
- BUT can rename a running .exe
- New file can be written to the original path
- New process starts, old process exits
- Cleanup happens on next launch

## Database Schema

### Migration: `XXX_auto_update.sql`

```sql
-- Track available releases
CREATE TABLE releases (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    version VARCHAR(32) NOT NULL UNIQUE,
    download_url TEXT NOT NULL,
    checksum_sha256 VARCHAR(64) NOT NULL,
    release_notes TEXT,
    is_stable BOOLEAN NOT NULL DEFAULT false,
    is_mandatory BOOLEAN NOT NULL DEFAULT false,
    min_version VARCHAR(32),  -- Minimum version that can update to this
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Add version tracking to machines
ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS agent_version VARCHAR(32);
ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS update_status VARCHAR(32);
ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS last_update_check TIMESTAMPTZ;
```

### Update Status Values
- `null` - Never checked
- `current` - Running latest version
- `available` - Update available, not started
- `downloading` - Currently downloading
- `installing` - Currently installing
- `failed` - Last update failed (with error in logs)

## Protocol Changes

### Extend `proto/guruconnect.proto`

```protobuf
// Add to existing messages

// Update command details (sent with AdminCommand)
message UpdateInfo {
    string version = 1;
    string download_url = 2;
    string checksum_sha256 = 3;
    bool mandatory = 4;
}

// Update status report (agent → server)
message UpdateStatus {
    string current_version = 1;
    UpdateState state = 2;
    string error_message = 3;  // If state is FAILED
}

enum UpdateState {
    UPDATE_IDLE = 0;
    UPDATE_CHECKING = 1;
    UPDATE_DOWNLOADING = 2;
    UPDATE_INSTALLING = 3;
    UPDATE_COMPLETE = 4;
    UPDATE_FAILED = 5;
}

// Extend Message to include UpdateInfo
message Message {
    // ... existing fields ...
    UpdateInfo update_info = 15;
    UpdateStatus update_status = 16;
}

// Extend AgentStatus to include version
message AgentStatus {
    // ... existing fields ...
    string agent_version = 10;
}
```

## API Endpoints

### Version Check (No Auth - Agent Polling)
```
GET /api/version
Response: {
    "latest_version": "0.2.0",
    "download_url": "https://connect.azcomputerguru.com/downloads/guruconnect.exe",
    "checksum_sha256": "abc123...",
    "is_mandatory": false,
    "release_notes": "Bug fixes and performance improvements"
}
```

### Trigger Update (Admin Auth)
```
POST /api/machines/{agent_id}/update
Body: { "version": "0.2.0" }  // Optional, defaults to latest
Response: { "success": true, "message": "Update command sent" }
```

### Bulk Update (Admin Auth)
```
POST /api/machines/update-all
Body: { "version": "0.2.0" }  // Optional
Response: { "updated": 15, "skipped": 3, "offline": 5 }
```

### Release Management (Admin Auth)
```
GET /api/releases              # List all releases
POST /api/releases             # Create new release
DELETE /api/releases/{version} # Remove release
PUT /api/releases/{version}    # Update release metadata
```

## Files to Modify

### Agent Files

| File | Changes |
|------|---------|
| `agent/src/main.rs` | Add `--post-update` flag handling, cleanup old exe on startup |
| `agent/src/session/mod.rs` | Handle ADMIN_UPDATE command, implement update check timer |
| `agent/src/update.rs` | NEW: Update logic (download, verify, replace, restart) |
| `agent/Cargo.toml` | Add `reqwest` for HTTP downloads, `sha2` for checksum |
| `proto/guruconnect.proto` | Add UpdateInfo, UpdateStatus messages |

### Server Files

| File | Changes |
|------|---------|
| `server/migrations/XXX_auto_update.sql` | NEW: releases table, machine version columns |
| `server/src/main.rs` | Add /api/version, /api/releases routes |
| `server/src/api/releases.rs` | NEW: Release management endpoints |
| `server/src/api/machines.rs` | Add update trigger endpoint |
| `server/src/db/releases.rs` | NEW: Release DB operations |
| `server/src/relay/mod.rs` | Parse UpdateInfo from AdminCommand |
| `server/static/dashboard.html` | Show versions, add update buttons |

## Implementation Phases

### Phase 1: Protocol & Database
1. Update `proto/guruconnect.proto` with UpdateInfo, UpdateStatus
2. Create migration for releases table and machine version columns
3. Add agent_version to AgentStatus message
4. Rebuild proto for both agent and server

### Phase 2: Server Infrastructure
1. Create `db/releases.rs` - CRUD for releases table
2. Create `api/releases.rs` - Admin endpoints for managing releases
3. Add `GET /api/version` - Unauthenticated version check endpoint
4. Add `POST /api/machines/{id}/update` - Trigger update via WebSocket
5. Modify `relay/mod.rs` to include UpdateInfo in AdminCommand
6. Track agent versions when they connect (parse from AgentStatus)

### Phase 3: Agent Update Logic
1. Create `agent/src/update.rs` module:
   - `check_for_update()` - Call /api/version, compare versions
   - `download_update()` - Download to temp with progress
   - `verify_checksum()` - SHA-256 validation
   - `install_update()` - Rename/copy/spawn/exit dance
2. Add periodic update check in session idle loop (every hour)
3. Handle ADMIN_UPDATE command to trigger immediate update
4. Add `--post-update` flag to cleanup .old files on startup
5. Send UpdateStatus messages to report progress

### Phase 4: Dashboard UI
1. Add "Version" column to machines table
2. Add "Update" button per machine (when update available)
3. Add "Update All" button in toolbar
4. Show update status (downloading, installing, etc.)
5. Release management page (list, upload, delete releases)

## Security Considerations

1. **Checksum Verification** - SHA-256 hash must match before install
2. **HTTPS Only** - Downloads must use HTTPS
3. **Version Validation** - Prevent downgrade attacks (only update to newer versions)
4. **Admin Authorization** - Only admins can trigger updates or manage releases
5. **Signed Binaries** - Future: Authenticode signing for Windows

## Error Handling

| Error | Handling |
|-------|----------|
| Download fails | Retry 3 times with exponential backoff |
| Checksum mismatch | Abort, report failure, delete temp file |
| File rename fails | Abort, report failure (might be permission issue) |
| Copy fails | Restore .old → original, report failure |
| New process won't start | Keep current running, report failure |
| Disk space | Check before download, abort if insufficient |

## Agent Dependencies to Add

```toml
# In agent/Cargo.toml
reqwest = { version = "0.12", features = ["rustls-tls", "stream"] }
sha2 = "0.10"
futures-util = "0.3"  # Already present for streams
```

## Critical Files (Full Paths)

- `C:\Users\MikeSwanson\Claude\guru-connect\proto\guruconnect.proto`
- `C:\Users\MikeSwanson\Claude\guru-connect\agent\src\main.rs`
- `C:\Users\MikeSwanson\Claude\guru-connect\agent\src\session\mod.rs`
- `C:\Users\MikeSwanson\Claude\guru-connect\agent\src\update.rs` (NEW)
- `C:\Users\MikeSwanson\Claude\guru-connect\server\src\main.rs`
- `C:\Users\MikeSwanson\Claude\guru-connect\server\src\api\releases.rs` (NEW)
- `C:\Users\MikeSwanson\Claude\guru-connect\server\src\db\releases.rs` (NEW)
- `C:\Users\MikeSwanson\Claude\guru-connect\server\migrations\`
- `C:\Users\MikeSwanson\Claude\guru-connect\server\static\dashboard.html`

## Testing Checklist

- [ ] Agent reports version to server on connect
- [ ] GET /api/version returns correct latest version
- [ ] Agent periodic check detects update available
- [ ] Admin can trigger update from dashboard
- [ ] Download completes successfully
- [ ] Checksum verification works (reject bad downloads)
- [ ] Exe rename/copy/restart works on Windows
- [ ] .old file cleaned up on restart
- [ ] Failed update doesn't break current installation
- [ ] Offline agents get update when they reconnect
- [ ] Dashboard shows correct version and status


User has approved your plan. You can now start coding. Start with updating your todo list if applicable

Your plan has been saved to: C:\Users\MikeSwanson\.claude\plans\velvet-tumbling-tide.md
You can refer back to it if needed during implementation.

## Approved Plan:
# GuruConnect Auto-Update Plan

## Overview

Implement a robust auto-update system for the GuruConnect Windows agent. Updates can be triggered by:
1. **Agent polling** - Agent checks for updates periodically (every hour)
2. **Admin push** - Admin triggers update from dashboard via WebSocket command

Updates are **silent** (no user prompt) and use **in-place restart** (no reboot required).

## Architecture

```
┌─────────────────────────────────────────────────────────────┐
│  Dashboard                                                   │
│  - Shows agent versions                                      │
│  - "Update" button triggers push                             │
│  - "Update All" for bulk updates                             │
└─────────────────────────────────────────────────────────────┘
        │ POST /api/machines/{id}/update
        ▼
┌─────────────────────────────────────────────────────────────┐
│  Server                                                      │
│  - Stores releases metadata (version, URL, checksum)         │
│  - GET /api/version returns latest version info              │
│  - Sends AdminCommand(ADMIN_UPDATE) via WebSocket            │
│  - Tracks agent versions in connect_machines table           │
└─────────────────────────────────────────────────────────────┘
        │ WebSocket: AdminCommand
        ▼
┌─────────────────────────────────────────────────────────────┐
│  Agent                                                       │
│  1. Polls /api/version every hour (during idle)              │
│  2. Downloads new binary to temp folder                      │
│  3. Verifies SHA-256 checksum                                │
│  4. Renames current.exe → current.exe.old                    │
│  5. Copies new.exe → current.exe                             │
│  6. Spawns new process                                       │
│  7. Exits current process                                    │
│  8. New process deletes .old on startup                      │
└─────────────────────────────────────────────────────────────┘
```

## Update Flow (In-Place Restart)

### Step-by-Step Process

1. **Trigger** - Either periodic check or admin push
2. **Version Check** - Compare current vs available version
3. **Download** - Fetch new binary to `%TEMP%\guruconnect-update.exe`
4. **Verify** - SHA-256 checksum validation
5. **Prepare** - Rename `guruconnect.exe` → `guruconnect.exe.old`
6. **Install** - Copy temp file to install location
7. **Restart** - Spawn new process with special `--post-update` flag
8. **Exit** - Current process exits cleanly
9. **Cleanup** - New process deletes `.old` file on startup

### Why This Works on Windows

- Can't delete or overwrite a running .exe
- BUT can rename a running .exe
- New file can be written to the original path
- New process starts, old process exits
- Cleanup happens on next launch

## Database Schema

### Migration: `XXX_auto_update.sql`

```sql
-- Track available releases
CREATE TABLE releases (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    version VARCHAR(32) NOT NULL UNIQUE,
    download_url TEXT NOT NULL,
    checksum_sha256 VARCHAR(64) NOT NULL,
    release_notes TEXT,
    is_stable BOOLEAN NOT NULL DEFAULT false,
    is_mandatory BOOLEAN NOT NULL DEFAULT false,
    min_version VARCHAR(32),  -- Minimum version that can update to this
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Add version tracking to machines
ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS agent_version VARCHAR(32);
ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS update_status VARCHAR(32);
ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS last_update_check TIMESTAMPTZ;
```

### Update Status Values
- `null` - Never checked
- `current` - Running latest version
- `available` - Update available, not started
- `downloading` - Currently downloading
- `installing` - Currently installing
- `failed` - Last update failed (with error in logs)

## Protocol Changes

### Extend `proto/guruconnect.proto`

```protobuf
// Add to existing messages

// Update command details (sent with AdminCommand)
message UpdateInfo {
    string version = 1;
    string download_url = 2;
    string checksum_sha256 = 3;
    bool mandatory = 4;
}

// Update status report (agent → server)
message UpdateStatus {
    string current_version = 1;
    UpdateState state = 2;
    string error_message = 3;  // If state is FAILED
}

enum UpdateState {
    UPDATE_IDLE = 0;
    UPDATE_CHECKING = 1;
    UPDATE_DOWNLOADING = 2;
    UPDATE_INSTALLING = 3;
    UPDATE_COMPLETE = 4;
    UPDATE_FAILED = 5;
}

// Extend Message to include UpdateInfo
message Message {
    // ... existing fields ...
    UpdateInfo update_info = 15;
    UpdateStatus update_status = 16;
}

// Extend AgentStatus to include version
message AgentStatus {
    // ... existing fields ...
    string agent_version = 10;
}
```

## API Endpoints

### Version Check (No Auth - Agent Polling)
```
GET /api/version
Response: {
    "latest_version": "0.2.0",
    "download_url": "https://connect.azcomputerguru.com/downloads/guruconnect.exe",
    "checksum_sha256": "abc123...",
    "is_mandatory": false,
    "release_notes": "Bug fixes and performance improvements"
}
```

### Trigger Update (Admin Auth)
```
POST /api/machines/{agent_id}/update
Body: { "version": "0.2.0" }  // Optional, defaults to latest
Response: { "success": true, "message": "Update command sent" }
```

### Bulk Update (Admin Auth)
```
POST /api/machines/update-all
Body: { "version": "0.2.0" }  // Optional
Response: { "updated": 15, "skipped": 3, "offline": 5 }
```

### Release Management (Admin Auth)
```
GET /api/releases              # List all releases
POST /api/releases             # Create new release
DELETE /api/releases/{version} # Remove release
PUT /api/releases/{version}    # Update release metadata
```

## Files to Modify

### Agent Files

| File | Changes |
|------|---------|
| `agent/src/main.rs` | Add `--post-update` flag handling, cleanup old exe on startup |
| `agent/src/session/mod.rs` | Handle ADMIN_UPDATE command, implement update check timer |
| `agent/src/update.rs` | NEW: Update logic (download, verify, replace, restart) |
| `agent/Cargo.toml` | Add `reqwest` for HTTP downloads, `sha2` for checksum |
| `proto/guruconnect.proto` | Add UpdateInfo, UpdateStatus messages |

### Server Files

| File | Changes |
|------|---------|
| `server/migrations/XXX_auto_update.sql` | NEW: releases table, machine version columns |
| `server/src/main.rs` | Add /api/version, /api/releases routes |
| `server/src/api/releases.rs` | NEW: Release management endpoints |
| `server/src/api/machines.rs` | Add update trigger endpoint |
| `server/src/db/releases.rs` | NEW: Release DB operations |
| `server/src/relay/mod.rs` | Parse UpdateInfo from AdminCommand |
| `server/static/dashboard.html` | Show versions, add update buttons |

## Implementation Phases

### Phase 1: Protocol & Database
1. Update `proto/guruconnect.proto` with UpdateInfo, UpdateStatus
2. Create migration for releases table and machine version columns
3. Add agent_version to AgentStatus message
4. Rebuild proto for both agent and server

### Phase 2: Server Infrastructure
1. Create `db/releases.rs` - CRUD for releases table
2. Create `api/releases.rs` - Admin endpoints for managing releases
3. Add `GET /api/version` - Unauthenticated version check endpoint
4. Add `POST /api/machines/{id}/update` - Trigger update via WebSocket
5. Modify `relay/mod.rs` to include UpdateInfo in AdminCommand
6. Track agent versions when they connect (parse from AgentStatus)

### Phase 3: Agent Update Logic
1. Create `agent/src/update.rs` module:
   - `check_for_update()` - Call /api/version, compare versions
   - `download_update()` - Download to temp with progress
   - `verify_checksum()` - SHA-256 validation
   - `install_update()` - Rename/copy/spawn/exit dance
2. Add periodic update check in session idle loop (every hour)
3. Handle ADMIN_UPDATE command to trigger immediate update
4. Add `--post-update` flag to cleanup .old files on startup
5. Send UpdateStatus messages to report progress

### Phase 4: Dashboard UI
1. Add "Version" column to machines table
2. Add "Update" button per machine (when update available)
3. Add "Update All" button in toolbar
4. Show update status (downloading, installing, etc.)
5. Release management page (list, upload, delete releases)

## Security Considerations

1. **Checksum Verification** - SHA-256 hash must match before install
2. **HTTPS Only** - Downloads must use HTTPS
3. **Version Validation** - Prevent downgrade attacks (only update to newer versions)
4. **Admin Authorization** - Only admins can trigger updates or manage releases
5. **Signed Binaries** - Future: Authenticode signing for Windows

## Error Handling

| Error | Handling |
|-------|----------|
| Download fails | Retry 3 times with exponential backoff |
| Checksum mismatch | Abort, report failure, delete temp file |
| File rename fails | Abort, report failure (might be permission issue) |
| Copy fails | Restore .old → original, report failure |
| New process won't start | Keep current running, report failure |
| Disk space | Check before download, abort if insufficient |

## Agent Dependencies to Add

```toml
# In agent/Cargo.toml
reqwest = { version = "0.12", features = ["rustls-tls", "stream"] }
sha2 = "0.10"
futures-util = "0.3"  # Already present for streams
```

## Critical Files (Full Paths)

- `C:\Users\MikeSwanson\Claude\guru-connect\proto\guruconnect.proto`
- `C:\Users\MikeSwanson\Claude\guru-connect\agent\src\main.rs`
- `C:\Users\MikeSwanson\Claude\guru-connect\agent\src\session\mod.rs`
- `C:\Users\MikeSwanson\Claude\guru-connect\agent\src\update.rs` (NEW)
- `C:\Users\MikeSwanson\Claude\guru-connect\server\src\main.rs`
- `C:\Users\MikeSwanson\Claude\guru-connect\server\src\api\releases.rs` (NEW)
- `C:\Users\MikeSwanson\Claude\guru-connect\server\src\db\releases.rs` (NEW)
- `C:\Users\MikeSwanson\Claude\guru-connect\server\migrations\`
- `C:\Users\MikeSwanson\Claude\guru-connect\server\static\dashboard.html`

## Testing Checklist

- [ ] Agent reports version to server on connect
- [ ] GET /api/version returns correct latest version
- [ ] Agent periodic check detects update available
- [ ] Admin can trigger update from dashboard
- [ ] Download completes successfully
- [ ] Checksum verification works (reject bad downloads)
- [ ] Exe rename/copy/restart works on Windows
- [ ] .old file cleaned up on restart
- [ ] Failed update doesn't break current installation
- [ ] Offline agents get update when they reconnect
- [ ] Dashboard shows correct version and status


The plan is approved. Now I need to start implementing it. Let me create a todo list and begin with Phase 1: Protocol & Database.


Let me set up the task tracking and begin implementation.


TodoWrite

Phase 1: Update proto/guruconnect.proto with UpdateInfo, UpdateStatus, UpdateState

Phase 1: Create database migration for releases table and machine version columns

Phase 2: Create server db/releases.rs - CRUD for releases table

Phase 2: Create server api/releases.rs - Admin endpoints

Phase 2: Add GET /api/version endpoint (unauthenticated)

Phase 2: Add POST /api/machines/{id}/update endpoint

Phase 2: Track agent versions when they connect

Phase 3: Create agent/src/update.rs module

Phase 3: Add periodic update check in session idle loop

Phase 3: Handle ADMIN_UPDATE command in session

Phase 3: Add --post-update flag and cleanup logic

Phase 4: Update dashboard.html with version display and update buttons


Todos have been modified successfully. Ensure that you continue to use the todo list to track your progress. Please proceed with the current tasks if applicable

Phase 1: Update proto/guruconnect.proto with UpdateInfo, UpdateStatus, UpdateState

Phase 1: Create database migration for releases table and machine version columns

Phase 2: Create server db/releases.rs - CRUD for releases table

Phase 2: Create server api/releases.rs - Admin endpoints

Phase 2: Add GET /api/version endpoint (unauthenticated)

Phase 2: Add POST /api/machines/{id}/update endpoint

Phase 2: Track agent versions when they connect

Phase 3: Create agent/src/update.rs module

Phase 3: Add periodic update check in session idle loop

Phase 3: Handle ADMIN_UPDATE command in session

Phase 3: Add --post-update flag and cleanup logic

Phase 4: Update dashboard.html with version display and update buttons


Now let me start with Phase 1. First, I need to read the current proto file to understand its structure and add the new messages.


     1→syntax = "proto3";
     2→package guruconnect;
     3→
     4→// ============================================================================
     5→// Session Management
     6→// ============================================================================
     7→
     8→message SessionRequest {
     9→    string agent_id = 1;
    10→    string session_token = 2;
    11→    SessionType session_type = 3;
    12→    string client_version = 4;
    13→}
    14→
    15→message SessionResponse {
    16→    bool success = 1;
    17→    string session_id = 2;
    18→    string error = 3;
    19→    DisplayInfo display_info = 4;
    20→}
    21→
    22→enum SessionType {
    23→    SCREEN_CONTROL = 0;
    24→    VIEW_ONLY = 1;
    25→    BACKSTAGE = 2;
    26→    FILE_TRANSFER = 3;
    27→}
    28→
    29→// ============================================================================
    30→// Display Information
    31→// ============================================================================
    32→
    33→message DisplayInfo {
    34→    repeated Display displays = 1;
    35→    int32 primary_display = 2;
    36→}
    37→
    38→message Display {
    39→    int32 id = 1;
    40→    string name = 2;
    41→    int32 x = 3;
    42→    int32 y = 4;
    43→    int32 width = 5;
    44→    int32 height = 6;
    45→    bool is_primary = 7;
    46→}
    47→
    48→message SwitchDisplay {
    49→    int32 display_id = 1;
    50→}
    51→
    52→// ============================================================================
    53→// Video Frames
    54→// ============================================================================
    55→
    56→message VideoFrame {
    57→    int64 timestamp = 1;
    58→    int32 display_id = 2;
    59→    int32 sequence = 3;
    60→
    61→    oneof encoding {
    62→        RawFrame raw = 10;
    63→        EncodedFrame vp9 = 11;
    64→        EncodedFrame h264 = 12;
    65→        EncodedFrame h265 = 13;
    66→    }
    67→}
    68→
    69→message RawFrame {
    70→    int32 width = 1;
    71→    int32 height = 2;
    72→    bytes data = 3;             // Zstd compressed BGRA
    73→    bool compressed = 4;
    74→    repeated DirtyRect dirty_rects = 5;
    75→    bool is_keyframe = 6;       // Full frame vs incremental
    76→}
    77→
    78→message DirtyRect {
    79→    int32 x = 1;
    80→    int32 y = 2;
    81→    int32 width = 3;
    82→    int32 height = 4;
    83→}
    84→
    85→message EncodedFrame {
    86→    bytes data = 1;
    87→    bool keyframe = 2;
    88→    int64 pts = 3;
    89→    int64 dts = 4;
    90→}
    91→
    92→message VideoAck {
    93→    int32 sequence = 1;
    94→    int64 timestamp = 2;
    95→}
    96→
    97→// ============================================================================
    98→// Cursor
    99→// ============================================================================
   100→
   101→message CursorShape {
   102→    uint64 id = 1;
   103→    int32 hotspot_x = 2;
   104→    int32 hotspot_y = 3;
   105→    int32 width = 4;
   106→    int32 height = 5;
   107→    bytes data = 6;             // BGRA bitmap
   108→}
   109→
   110→message CursorPosition {
   111→    int32 x = 1;
   112→    int32 y = 2;
   113→    bool visible = 3;
   114→}
   115→
   116→// ============================================================================
   117→// Input Events
   118→// ============================================================================
   119→
   120→message MouseEvent {
   121→    int32 x = 1;
   122→    int32 y = 2;
   123→    MouseButtons buttons = 3;
   124→    int32 wheel_delta_x = 4;
   125→    int32 wheel_delta_y = 5;
   126→    MouseEventType event_type = 6;
   127→}
   128→
   129→enum MouseEventType {
   130→    MOUSE_MOVE = 0;
   131→    MOUSE_DOWN = 1;
   132→    MOUSE_UP = 2;
   133→    MOUSE_WHEEL = 3;
   134→}
   135→
   136→message MouseButtons {
   137→    bool left = 1;
   138→    bool right = 2;
   139→    bool middle = 3;
   140→    bool x1 = 4;
   141→    bool x2 = 5;
   142→}
   143→
   144→message KeyEvent {
   145→    bool down = 1;              // true = key down, false = key up
   146→    KeyEventType key_type = 2;
   147→    uint32 vk_code = 3;         // Virtual key code (Windows VK_*)
   148→    uint32 scan_code = 4;       // Hardware scan code
   149→    string unicode = 5;         // Unicode character (for text input)
   150→    Modifiers modifiers = 6;
   151→}
   152→
   153→enum KeyEventType {
   154→    KEY_VK = 0;                 // Virtual key code
   155→    KEY_SCAN = 1;               // Scan code
   156→    KEY_UNICODE = 2;            // Unicode character
   157→}
   158→
   159→message Modifiers {
   160→    bool ctrl = 1;
   161→    bool alt = 2;
   162→    bool shift = 3;
   163→    bool meta = 4;              // Windows key
   164→    bool caps_lock = 5;
   165→    bool num_lock = 6;
   166→}
   167→
   168→message SpecialKeyEvent {
   169→    SpecialKey key = 1;
   170→}
   171→
   172→enum SpecialKey {
   173→    CTRL_ALT_DEL = 0;
   174→    LOCK_SCREEN = 1;
   175→    PRINT_SCREEN = 2;
   176→}
   177→
   178→// ============================================================================
   179→// Clipboard
   180→// ============================================================================
   181→
   182→message ClipboardData {
   183→    ClipboardFormat format = 1;
   184→    bytes data = 2;
   185→    string mime_type = 3;
   186→}
   187→
   188→enum ClipboardFormat {
   189→    CLIPBOARD_TEXT = 0;
   190→    CLIPBOARD_HTML = 1;
   191→    CLIPBOARD_RTF = 2;
   192→    CLIPBOARD_IMAGE = 3;
   193→    CLIPBOARD_FILES = 4;
   194→}
   195→
   196→message ClipboardRequest {
   197→    // Request current clipboard content
   198→}
   199→
   200→// ============================================================================
   201→// Quality Control
   202→// ============================================================================
   203→
   204→message QualitySettings {
   205→    QualityPreset preset = 1;
   206→    int32 custom_fps = 2;       // 1-60
   207→    int32 custom_bitrate = 3;   // kbps
   208→    CodecPreference codec = 4;
   209→}
   210→
   211→enum QualityPreset {
   212→    QUALITY_AUTO = 0;
   213→    QUALITY_LOW = 1;            // Low bandwidth
   214→    QUALITY_BALANCED = 2;
   215→    QUALITY_HIGH = 3;           // Best quality
   216→}
   217→
   218→enum CodecPreference {
   219→    CODEC_AUTO = 0;
   220→    CODEC_RAW = 1;              // Raw + Zstd (LAN)
   221→    CODEC_VP9 = 2;
   222→    CODEC_H264 = 3;
   223→    CODEC_H265 = 4;
   224→}
   225→
   226→message LatencyReport {
   227→    int64 rtt_ms = 1;
   228→    int32 fps = 2;
   229→    int32 bitrate_kbps = 3;
   230→}
   231→
   232→// ============================================================================
   233→// Chat Messages
   234→// ============================================================================
   235→
   236→message ChatMessage {
   237→    string id = 1;              // Unique message ID
   238→    string sender = 2;          // "technician" or "client"
   239→    string content = 3;         // Message text
   240→    int64 timestamp = 4;        // Unix timestamp
   241→}
   242→
   243→// ============================================================================
   244→// Control Messages
   245→// ============================================================================
   246→
   247→message Heartbeat {
   248→    int64 timestamp = 1;
   249→}
   250→
   251→message HeartbeatAck {
   252→    int64 client_timestamp = 1;
   253→    int64 server_timestamp = 2;
   254→}
   255→
   256→message Disconnect {
   257→    string reason = 1;
   258→}
   259→
   260→// Server commands agent to start streaming video
   261→message StartStream {
   262→    string viewer_id = 1;           // ID of viewer requesting stream
   263→    int32 display_id = 2;           // Which display to stream (0 = primary)
   264→}
   265→
   266→// Server commands agent to stop streaming
   267→message StopStream {
   268→    string viewer_id = 1;           // Which viewer disconnected
   269→}
   270→
   271→// Agent reports its status periodically when idle
   272→message AgentStatus {
   273→    string hostname = 1;
   274→    string os_version = 2;
   275→    bool is_elevated = 3;
   276→    int64 uptime_secs = 4;
   277→    int32 display_count = 5;
   278→    bool is_streaming = 6;
   279→}
   280→
   281→// Server commands agent to uninstall itself
   282→message AdminCommand {
   283→    AdminCommandType command = 1;
   284→    string reason = 2;              // Why the command was issued
   285→}
   286→
   287→enum AdminCommandType {
   288→    ADMIN_UNINSTALL = 0;            // Uninstall agent and remove from startup
   289→    ADMIN_RESTART = 1;              // Restart the agent process
   290→    ADMIN_UPDATE = 2;               // Download and install update (future)
   291→}
   292→
   293→// ============================================================================
   294→// Top-Level Message Wrapper
   295→// ============================================================================
   296→
   297→message Message {
   298→    oneof payload {
   299→        // Session
   300→        SessionRequest session_request = 1;
   301→        SessionResponse session_response = 2;
   302→
   303→        // Video
   304→        VideoFrame video_frame = 10;
   305→        VideoAck video_ack = 11;
   306→        SwitchDisplay switch_display = 12;
   307→
   308→        // Cursor
   309→        CursorShape cursor_shape = 15;
   310→        CursorPosition cursor_position = 16;
   311→
   312→        // Input
   313→        MouseEvent mouse_event = 20;
   314→        KeyEvent key_event = 21;
   315→        SpecialKeyEvent special_key = 22;
   316→
   317→        // Clipboard
   318→        ClipboardData clipboard_data = 30;
   319→        ClipboardRequest clipboard_request = 31;
   320→
   321→        // Quality
   322→        QualitySettings quality_settings = 40;
   323→        LatencyReport latency_report = 41;
   324→
   325→        // Control
   326→        Heartbeat heartbeat = 50;
   327→        HeartbeatAck heartbeat_ack = 51;
   328→        Disconnect disconnect = 52;
   329→        StartStream start_stream = 53;
   330→        StopStream stop_stream = 54;
   331→        AgentStatus agent_status = 55;
   332→
   333→        // Chat
   334→        ChatMessage chat_message = 60;
   335→
   336→        // Admin commands (server -> agent)
   337→        AdminCommand admin_command = 70;
   338→    }
   339→}
   340→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

syntax = "proto3";
package guruconnect;

// ============================================================================
// Session Management
// ============================================================================

message SessionRequest {
    string agent_id = 1;
    string session_token = 2;
    SessionType session_type = 3;
    string client_version = 4;
}

message SessionResponse {
    bool success = 1;
    string session_id = 2;
    string error = 3;
    DisplayInfo display_info = 4;
}

enum SessionType {
    SCREEN_CONTROL = 0;
    VIEW_ONLY = 1;
    BACKSTAGE = 2;
    FILE_TRANSFER = 3;
}

// ============================================================================
// Display Information
// ============================================================================

message DisplayInfo {
    repeated Display displays = 1;
    int32 primary_display = 2;
}

message Display {
    int32 id = 1;
    string name = 2;
    int32 x = 3;
    int32 y = 4;
    int32 width = 5;
    int32 height = 6;
    bool is_primary = 7;
}

message SwitchDisplay {
    int32 display_id = 1;
}

// ============================================================================
// Video Frames
// ============================================================================

message VideoFrame {
    int64 timestamp = 1;
    int32 display_id = 2;
    int32 sequence = 3;

    oneof encoding {
        RawFrame raw = 10;
        EncodedFrame vp9 = 11;
        EncodedFrame h264 = 12;
        EncodedFrame h265 = 13;
    }
}

message RawFrame {
    int32 width = 1;
    int32 height = 2;
    bytes data = 3;             // Zstd compressed BGRA
    bool compressed = 4;
    repeated DirtyRect dirty_rects = 5;
    bool is_keyframe = 6;       // Full frame vs incremental
}

message DirtyRect {
    int32 x = 1;
    int32 y = 2;
    int32 width = 3;
    int32 height = 4;
}

message EncodedFrame {
    bytes data = 1;
    bool keyframe = 2;
    int64 pts = 3;
    int64 dts = 4;
}

message VideoAck {
    int32 sequence = 1;
    int64 timestamp = 2;
}

// ============================================================================
// Cursor
// ============================================================================

message CursorShape {
    uint64 id = 1;
    int32 hotspot_x = 2;
    int32 hotspot_y = 3;
    int32 width = 4;
    int32 height = 5;
    bytes data = 6;             // BGRA bitmap
}

message CursorPosition {
    int32 x = 1;
    int32 y = 2;
    bool visible = 3;
}

// ============================================================================
// Input Events
// ============================================================================

message MouseEvent {
    int32 x = 1;
    int32 y = 2;
    MouseButtons buttons = 3;
    int32 wheel_delta_x = 4;
    int32 wheel_delta_y = 5;
    MouseEventType event_type = 6;
}

enum MouseEventType {
    MOUSE_MOVE = 0;
    MOUSE_DOWN = 1;
    MOUSE_UP = 2;
    MOUSE_WHEEL = 3;
}

message MouseButtons {
    bool left = 1;
    bool right = 2;
    bool middle = 3;
    bool x1 = 4;
    bool x2 = 5;
}

message KeyEvent {
    bool down = 1;              // true = key down, false = key up
    KeyEventType key_type = 2;
    uint32 vk_code = 3;         // Virtual key code (Windows VK_*)
    uint32 scan_code = 4;       // Hardware scan code
    string unicode = 5;         // Unicode character (for text input)
    Modifiers modifiers = 6;
}

enum KeyEventType {
    KEY_VK = 0;                 // Virtual key code
    KEY_SCAN = 1;               // Scan code
    KEY_UNICODE = 2;            // Unicode character
}

message Modifiers {
    bool ctrl = 1;
    bool alt = 2;
    bool shift = 3;
    bool meta = 4;              // Windows key
    bool caps_lock = 5;
    bool num_lock = 6;
}

message SpecialKeyEvent {
    SpecialKey key = 1;
}

enum SpecialKey {
    CTRL_ALT_DEL = 0;
    LOCK_SCREEN = 1;
    PRINT_SCREEN = 2;
}

// ============================================================================
// Clipboard
// ============================================================================

message ClipboardData {
    ClipboardFormat format = 1;
    bytes data = 2;
    string mime_type = 3;
}

enum ClipboardFormat {
    CLIPBOARD_TEXT = 0;
    CLIPBOARD_HTML = 1;
    CLIPBOARD_RTF = 2;
    CLIPBOARD_IMAGE = 3;
    CLIPBOARD_FILES = 4;
}

message ClipboardRequest {
    // Request current clipboard content
}

// ============================================================================
// Quality Control
// ============================================================================

message QualitySettings {
    QualityPreset preset = 1;
    int32 custom_fps = 2;       // 1-60
    int32 custom_bitrate = 3;   // kbps
    CodecPreference codec = 4;
}

enum QualityPreset {
    QUALITY_AUTO = 0;
    QUALITY_LOW = 1;            // Low bandwidth
    QUALITY_BALANCED = 2;
    QUALITY_HIGH = 3;           // Best quality
}

enum CodecPreference {
    CODEC_AUTO = 0;
    CODEC_RAW = 1;              // Raw + Zstd (LAN)
    CODEC_VP9 = 2;
    CODEC_H264 = 3;
    CODEC_H265 = 4;
}

message LatencyReport {
    int64 rtt_ms = 1;
    int32 fps = 2;
    int32 bitrate_kbps = 3;
}

// ============================================================================
// Chat Messages
// ============================================================================

message ChatMessage {
    string id = 1;              // Unique message ID
    string sender = 2;          // "technician" or "client"
    string content = 3;         // Message text
    int64 timestamp = 4;        // Unix timestamp
}

// ============================================================================
// Control Messages
// ============================================================================

message Heartbeat {
    int64 timestamp = 1;
}

message HeartbeatAck {
    int64 client_timestamp = 1;
    int64 server_timestamp = 2;
}

message Disconnect {
    string reason = 1;
}

// Server commands agent to start streaming video
message StartStream {
    string viewer_id = 1;           // ID of viewer requesting stream
    int32 display_id = 2;           // Which display to stream (0 = primary)
}

// Server commands agent to stop streaming
message StopStream {
    string viewer_id = 1;           // Which viewer disconnected
}

// Agent reports its status periodically when idle
message AgentStatus {
    string hostname = 1;
    string os_version = 2;
    bool is_elevated = 3;
    int64 uptime_secs = 4;
    int32 display_count = 5;
    bool is_streaming = 6;
}

// Server commands agent to uninstall itself
message AdminCommand {
    AdminCommandType command = 1;
    string reason = 2;              // Why the command was issued
}

enum AdminCommandType {
    ADMIN_UNINSTALL = 0;            // Uninstall agent and remove from startup
    ADMIN_RESTART = 1;              // Restart the agent process
    ADMIN_UPDATE = 2;               // Download and install update (future)
}

// ============================================================================
// Top-Level Message Wrapper
// ============================================================================

message Message {
    oneof payload {
        // Session
        SessionRequest session_request = 1;
        SessionResponse session_response = 2;

        // Video
        VideoFrame video_frame = 10;
        VideoAck video_ack = 11;
        SwitchDisplay switch_display = 12;

        // Cursor
        CursorShape cursor_shape = 15;
        CursorPosition cursor_position = 16;

        // Input
        MouseEvent mouse_event = 20;
        KeyEvent key_event = 21;
        SpecialKeyEvent special_key = 22;

        // Clipboard
        ClipboardData clipboard_data = 30;
        ClipboardRequest clipboard_request = 31;

        // Quality
        QualitySettings quality_settings = 40;
        LatencyReport latency_report = 41;

        // Control
        Heartbeat heartbeat = 50;
        HeartbeatAck heartbeat_ack = 51;
        Disconnect disconnect = 52;
        StartStream start_stream = 53;
        StopStream stop_stream = 54;
        AgentStatus agent_status = 55;

        // Chat
        ChatMessage chat_message = 60;

        // Admin commands (server -> agent)
        AdminCommand admin_command = 70;
    }
}


Now I need to add:
1. UpdateInfo message
2. UpdateStatus message
3. UpdateState enum
4. Add agent_version to AgentStatus
5. Add update_info and update_status to Message

Let me add these new messages and fields.


Now I'll add the update-related messages to the protobuf file:


Edit

// Agent reports its status periodically when idle
message AgentStatus {
    string hostname = 1;
    string os_version = 2;
    bool is_elevated = 3;
    int64 uptime_secs = 4;
    int32 display_count = 5;
    bool is_streaming = 6;
}

// Agent reports its status periodically when idle
message AgentStatus {
    string hostname = 1;
    string os_version = 2;
    bool is_elevated = 3;
    int64 uptime_secs = 4;
    int32 display_count = 5;
    bool is_streaming = 6;
    string agent_version = 7;           // Agent version (e.g., "0.1.0-abc123")
}


The file C:\Users\MikeSwanson\Claude\guru-connect\proto\guruconnect.proto has been updated. Here's the result of running `cat -n` on a snippet of the edited file:
   267→message StopStream {
   268→    string viewer_id = 1;           // Which viewer disconnected
   269→}
   270→
   271→// Agent reports its status periodically when idle
   272→message AgentStatus {
   273→    string hostname = 1;
   274→    string os_version = 2;
   275→    bool is_elevated = 3;
   276→    int64 uptime_secs = 4;
   277→    int32 display_count = 5;
   278→    bool is_streaming = 6;
   279→    string agent_version = 7;           // Agent version (e.g., "0.1.0-abc123")
   280→}
   281→
   282→// Server commands agent to uninstall itself
   283→message AdminCommand {
   284→    AdminCommandType command = 1;

// Agent reports its status periodically when idle
message AgentStatus {
    string hostname = 1;
    string os_version = 2;
    bool is_elevated = 3;
    int64 uptime_secs = 4;
    int32 display_count = 5;
    bool is_streaming = 6;
    string agent_version = 7;           // Agent version (e.g., "0.1.0-abc123")
}

syntax = "proto3";
package guruconnect;

// ============================================================================
// Session Management
// ============================================================================

message SessionRequest {
    string agent_id = 1;
    string session_token = 2;
    SessionType session_type = 3;
    string client_version = 4;
}

message SessionResponse {
    bool success = 1;
    string session_id = 2;
    string error = 3;
    DisplayInfo display_info = 4;
}

enum SessionType {
    SCREEN_CONTROL = 0;
    VIEW_ONLY = 1;
    BACKSTAGE = 2;
    FILE_TRANSFER = 3;
}

// ============================================================================
// Display Information
// ============================================================================

message DisplayInfo {
    repeated Display displays = 1;
    int32 primary_display = 2;
}

message Display {
    int32 id = 1;
    string name = 2;
    int32 x = 3;
    int32 y = 4;
    int32 width = 5;
    int32 height = 6;
    bool is_primary = 7;
}

message SwitchDisplay {
    int32 display_id = 1;
}

// ============================================================================
// Video Frames
// ============================================================================

message VideoFrame {
    int64 timestamp = 1;
    int32 display_id = 2;
    int32 sequence = 3;

    oneof encoding {
        RawFrame raw = 10;
        EncodedFrame vp9 = 11;
        EncodedFrame h264 = 12;
        EncodedFrame h265 = 13;
    }
}

message RawFrame {
    int32 width = 1;
    int32 height = 2;
    bytes data = 3;             // Zstd compressed BGRA
    bool compressed = 4;
    repeated DirtyRect dirty_rects = 5;
    bool is_keyframe = 6;       // Full frame vs incremental
}

message DirtyRect {
    int32 x = 1;
    int32 y = 2;
    int32 width = 3;
    int32 height = 4;
}

message EncodedFrame {
    bytes data = 1;
    bool keyframe = 2;
    int64 pts = 3;
    int64 dts = 4;
}

message VideoAck {
    int32 sequence = 1;
    int64 timestamp = 2;
}

// ============================================================================
// Cursor
// ============================================================================

message CursorShape {
    uint64 id = 1;
    int32 hotspot_x = 2;
    int32 hotspot_y = 3;
    int32 width = 4;
    int32 height = 5;
    bytes data = 6;             // BGRA bitmap
}

message CursorPosition {
    int32 x = 1;
    int32 y = 2;
    bool visible = 3;
}

// ============================================================================
// Input Events
// ============================================================================

message MouseEvent {
    int32 x = 1;
    int32 y = 2;
    MouseButtons buttons = 3;
    int32 wheel_delta_x = 4;
    int32 wheel_delta_y = 5;
    MouseEventType event_type = 6;
}

enum MouseEventType {
    MOUSE_MOVE = 0;
    MOUSE_DOWN = 1;
    MOUSE_UP = 2;
    MOUSE_WHEEL = 3;
}

message MouseButtons {
    bool left = 1;
    bool right = 2;
    bool middle = 3;
    bool x1 = 4;
    bool x2 = 5;
}

message KeyEvent {
    bool down = 1;              // true = key down, false = key up
    KeyEventType key_type = 2;
    uint32 vk_code = 3;         // Virtual key code (Windows VK_*)
    uint32 scan_code = 4;       // Hardware scan code
    string unicode = 5;         // Unicode character (for text input)
    Modifiers modifiers = 6;
}

enum KeyEventType {
    KEY_VK = 0;                 // Virtual key code
    KEY_SCAN = 1;               // Scan code
    KEY_UNICODE = 2;            // Unicode character
}

message Modifiers {
    bool ctrl = 1;
    bool alt = 2;
    bool shift = 3;
    bool meta = 4;              // Windows key
    bool caps_lock = 5;
    bool num_lock = 6;
}

message SpecialKeyEvent {
    SpecialKey key = 1;
}

enum SpecialKey {
    CTRL_ALT_DEL = 0;
    LOCK_SCREEN = 1;
    PRINT_SCREEN = 2;
}

// ============================================================================
// Clipboard
// ============================================================================

message ClipboardData {
    ClipboardFormat format = 1;
    bytes data = 2;
    string mime_type = 3;
}

enum ClipboardFormat {
    CLIPBOARD_TEXT = 0;
    CLIPBOARD_HTML = 1;
    CLIPBOARD_RTF = 2;
    CLIPBOARD_IMAGE = 3;
    CLIPBOARD_FILES = 4;
}

message ClipboardRequest {
    // Request current clipboard content
}

// ============================================================================
// Quality Control
// ============================================================================

message QualitySettings {
    QualityPreset preset = 1;
    int32 custom_fps = 2;       // 1-60
    int32 custom_bitrate = 3;   // kbps
    CodecPreference codec = 4;
}

enum QualityPreset {
    QUALITY_AUTO = 0;
    QUALITY_LOW = 1;            // Low bandwidth
    QUALITY_BALANCED = 2;
    QUALITY_HIGH = 3;           // Best quality
}

enum CodecPreference {
    CODEC_AUTO = 0;
    CODEC_RAW = 1;              // Raw + Zstd (LAN)
    CODEC_VP9 = 2;
    CODEC_H264 = 3;
    CODEC_H265 = 4;
}

message LatencyReport {
    int64 rtt_ms = 1;
    int32 fps = 2;
    int32 bitrate_kbps = 3;
}

// ============================================================================
// Chat Messages
// ============================================================================

message ChatMessage {
    string id = 1;              // Unique message ID
    string sender = 2;          // "technician" or "client"
    string content = 3;         // Message text
    int64 timestamp = 4;        // Unix timestamp
}

// ============================================================================
// Control Messages
// ============================================================================

message Heartbeat {
    int64 timestamp = 1;
}

message HeartbeatAck {
    int64 client_timestamp = 1;
    int64 server_timestamp = 2;
}

message Disconnect {
    string reason = 1;
}

// Server commands agent to start streaming video
message StartStream {
    string viewer_id = 1;           // ID of viewer requesting stream
    int32 display_id = 2;           // Which display to stream (0 = primary)
}

// Server commands agent to stop streaming
message StopStream {
    string viewer_id = 1;           // Which viewer disconnected
}

// Agent reports its status periodically when idle
message AgentStatus {
    string hostname = 1;
    string os_version = 2;
    bool is_elevated = 3;
    int64 uptime_secs = 4;
    int32 display_count = 5;
    bool is_streaming = 6;
}

// Server commands agent to uninstall itself
message AdminCommand {
    AdminCommandType command = 1;
    string reason = 2;              // Why the command was issued
}

enum AdminCommandType {
    ADMIN_UNINSTALL = 0;            // Uninstall agent and remove from startup
    ADMIN_RESTART = 1;              // Restart the agent process
    ADMIN_UPDATE = 2;               // Download and install update (future)
}

// ============================================================================
// Top-Level Message Wrapper
// ============================================================================

message Message {
    oneof payload {
        // Session
        SessionRequest session_request = 1;
        SessionResponse session_response = 2;

        // Video
        VideoFrame video_frame = 10;
        VideoAck video_ack = 11;
        SwitchDisplay switch_display = 12;

        // Cursor
        CursorShape cursor_shape = 15;
        CursorPosition cursor_position = 16;

        // Input
        MouseEvent mouse_event = 20;
        KeyEvent key_event = 21;
        SpecialKeyEvent special_key = 22;

        // Clipboard
        ClipboardData clipboard_data = 30;
        ClipboardRequest clipboard_request = 31;

        // Quality
        QualitySettings quality_settings = 40;
        LatencyReport latency_report = 41;

        // Control
        Heartbeat heartbeat = 50;
        HeartbeatAck heartbeat_ack = 51;
        Disconnect disconnect = 52;
        StartStream start_stream = 53;
        StopStream stop_stream = 54;
        AgentStatus agent_status = 55;

        // Chat
        ChatMessage chat_message = 60;

        // Admin commands (server -> agent)
        AdminCommand admin_command = 70;
    }
}

+    string agent_version = 7;           // Agent version (e.g., "0.1.0-abc123")


Good, now let me add the UpdateInfo message and UpdateStatus message after AdminCommand. I'll also add UpdateState enum.