Run the managed/persistent GuruConnect agent as a LocalSystem Windows
service so it is reachable at the login screen and across reboots, and
so the SPEC-016 per-machine cak_ store (ACL-restricted to SYSTEM +
Administrators) is finally readable in-context.
Phase 1 scope (host + lifecycle only):
- New agent/src/service/mod.rs: registers "GuruConnectAgent" with the
SCM via the windows-service dispatcher, reports a correct lifecycle
(StartPending -> Running -> StopPending -> Stopped), handles
Stop/Shutdown via an AtomicBool the agent loop polls (graceful WS
close), and provides install/uninstall/start (LocalSystem, AutoStart,
sc-failure crash recovery). Idempotent install/uninstall.
- main.rs: hidden `service-run` subcommand routes the SCM-launched
process into the dispatcher; new run_managed_agent_service() runs the
existing RunMode::PermanentAgent logic (resolve/enroll cak_, hold the
relay) as SYSTEM. run_agent() now takes an optional SCM shutdown flag,
skips the HKCU Run autostart and the tray when run as the service, and
interrupts the reconnect backoff promptly on stop. An interactive
launch of a managed binary now installs+starts the service and exits
instead of double-running.
- install.rs: a managed install (embedded config present) installs the
LocalSystem service as the single autostart and removes the legacy
HKCU Run entry; uninstall stops+deletes the service (idempotent).
Attended/viewer installs are untouched.
- Kept the SPEC-016 Phase B fail-fast guard as a harmless safety net for
any non-SYSTEM invocation; updated its comment to name this service as
the managed run context.
Phase 2 NOT built (seams documented): session broker, per-session
capture/input worker, CreateProcessAsUserW token handoff, service/worker
IPC, and SERVICE_CONTROL_SESSIONCHANGE. Phase 1 enrolls/connects as
SYSTEM but does not capture a desktop (a Session-0 process cannot).
No service is installed/started on the dev host; that is a VM/admin
integration step. fmt + clippy -D warnings + release build + 55 tests
all pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The SPEC-016 Phase B credential-store guard referenced "SPEC-017" for the
forthcoming SYSTEM service host, but 017 is now Mike's end-user-access
spec; the service host is SPEC-018. Comment + error-string text only, no
logic change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
H1: derive machine_uid from the durable hardware salt ALONE (SMBIOS UUID, or
board+disk serial) plus a fixed namespace, so it survives an OS re-image (which
regenerates MachineGuid). MachineGuid is demoted to a last-resort signal used
only when no hardware salt is readable (volatile, reboot-only floor). Re-image
stability proven by salted_uid_is_reimage_stable_independent_of_machine_guid.
H2: in store_cak, lock the directory ACL BEFORE any secret bytes are written;
the temp file is created inside the already-locked dir, then renamed. No
ciphertext ever exists at an inherited/world-readable path. Ordering made an
explicit precondition, not an unstated inheritance assumption.
M1: load_cak now returns a LoadCakError enum distinguishing Io (incl.
PermissionDenied — operational) from Decrypt (the real tamper/wrong-machine
signal). Only a successful READ whose DPAPI decrypt fails hard-stops.
M2: the PowerShell SMBIOS/board/disk shell-out is spawned and waited on with a
10s wall-clock bound; on timeout the child is killed and the signal is treated
as missing (falls back through the chain), never panics. Keeps
CREATE_NO_WINDOW -NonInteractive -NoProfile.
L1: warn! breadcrumb when the salted derivation degrades to MachineGuid-only,
so the server-side collision-gate operator has a clue. No secret values logged.
C1: keep the SYSTEM+Administrators ACL (Option A target). store_cak now does a
read-back verification immediately after writing and fails at ENROLL time if
this context cannot read its own store; resolve_agent_credential fails fast with
an actionable SPEC-017 message on an access-denied store instead of silently
re-enrolling/bricking. Guarded comment notes this is satisfied once the SYSTEM
service host lands.
Deferred items (clear_cak placeholder, legacy api_key path) left as-is.
Verification on x86_64-pc-windows-msvc: cargo fmt --check clean, clippy
-D warnings clean, release build OK, 52 tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New enroll module: on a managed agent with no stored cak_ but with
enrollment_key + site_code, POST machine_uid + hostname + labels to
<https-base>/api/enroll and persist the minted cak_. Handles every Phase A
status code distinctly:
- 201 new / 200 reuse -> persist cak_ (DPAPI store) and connect
- 202 collision_pending -> log "pending operator confirmation", slow
re-check loop (no key issued; cannot connect until confirmed)
- 401 ENROLL_REJECTED / 409 ENROLL_SITE_CONFLICT -> distinct actionable
errors, long backoff (won't fix without operator action, but recovers
automatically once it does) — no tight loop
- 429 -> honor Retry-After, short backoff
- network / 5xx / decode -> short backoff
The enrollment_key and cak_ are never logged. Uses the existing reqwest
client and the update path's TLS posture (rustls; dev-insecure only in
debug + opt-in). Wire-contract unit tests pin the request shape against
the server's EnrollRequest/EnrollLabels and decode active + pending bodies.
main.rs run-mode wiring: before a managed agent connects, resolve the
operating credential by precedence — stored cak_ (steady state, no
network) -> first-run enrollment -> DEPRECATED legacy api_key (transition
only, logged at WARNING) -> error. The relay already accepts the cak_ as
the api_key query param, so the persistent transport authenticates with it
unchanged. Attended/support-code and viewer paths are untouched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Store the per-machine cak_ with BOTH layers Mike locked: DPAPI-machine
encryption (CryptProtectData with CRYPTPROTECT_LOCAL_MACHINE — a copied
blob is inert off the box) inside a SYSTEM/Administrators-only ACL'd file
at %ProgramData%\GuruConnect\credentials\agent.cak. The directory + file
ACL is hardened via icacls (/inheritance:r + grant to the well-known SIDs
*S-1-5-18 and *S-1-5-32-544, locale-independent) — auditable, with far
less unsafe FFI than building a registry-key security descriptor by hand.
Co-locates with the existing %ProgramData%\GuruConnect config/seed dir.
Provides store_cak / load_cak / clear_cak. store_cak writes atomically
(temp file + rename in the locked dir). load_cak treats a present-but-
undecryptable blob as a hard error (tamper / cross-machine copy) rather
than silently re-enrolling over it. The plaintext is never logged; the
transient plaintext copy is scrubbed after encryption. DPAPI output blobs
are LocalFree'd. Enables the Win32_Security_Cryptography windows feature.
Round-trip unit tests cover encrypt/decrypt recovery across lengths and
that a tampered blob fails to decrypt (DPAPI authenticates its blobs).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add enrollment_key + site_code to EmbeddedConfig and the resolved Config
alongside the existing labels, and add department/device_type label fields
(SPEC-007 AgentStatus parity). The legacy api_key is retained but made
optional/defaulted so a SPEC-016 site installer can carry only the
enrollment credentials; existing pre-enrollment installers still parse.
The enrollment fields are #[serde(skip)] on Config so they are never
written to the on-disk TOML (install-time material only); apply_enrollment_env
layers them from GURUCONNECT_ENROLLMENT_KEY / GURUCONNECT_SITE_CODE on the
file and env load paths. The embedded path carries them from the install
blob. Config delivery itself (signed wrapper) is Phase C and unchanged here.
Add Config::https_base() deriving the REST API base (https://host[:port])
from the wss:// server_url so the enroll client and the persistent
transport share one authority.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extend the SPEC-004 machine_uid derivation with the locked SPEC-016
hardware salt: combine the Windows MachineGuid with the SMBIOS system
UUID (Win32_ComputerSystemProduct.UUID), falling back to motherboard
serial (Win32_BaseBoard.SerialNumber) + primary disk serial when the
SMBIOS UUID is absent or a degenerate placeholder (all-zeros / all-FFs,
emitted by some OEMs and hypervisor templates).
Signals are read via narrow PowerShell CIM queries (hidden window, no
profile) rather than adding a WMI crate or hand-rolling COM IWbemServices
for two scalar reads. Values are normalized (trim + upper-case) so vendor
case/space drift never perturbs the digest. The combined string is
SHA-256'd into the existing opaque muid_<hex> shape, preserving the wire
identity the relay connect path already reports while making it survive an
OS re-image on the same hardware. Which signal set fed the result is
logged (source label only, never the secret values).
Adds unit tests for derivation determinism + signal-sensitivity,
degenerate-SMBIOS rejection, and signal normalization.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The native viewer's H.264 path (Task 7 first-cut, compile-verified only)
never rendered a frame. Three stacked bugs, all confirmed via live loopback:
1. decoder: MF_E_NOTACCEPTING (0xC00D36B5) was treated as fatal and only
one output was drained per call, so once the MFT filled it rejected
every subsequent frame. decode() now returns Vec<DecodedFrame>, drains
on back-pressure and retries the unconsumed sample, then drains all
ready outputs.
2. decoder: the NV12 output type was hand-built and rejected by the MS
H.264 decoder MFT (MF_E_TRANSFORM_TYPE_NOT_SET, 0xC00D6D60). It is now
negotiated by enumerating GetOutputAvailableType on STREAM_CHANGE /
TYPE_NOT_SET.
3. render: a manual pump_messages() in about_to_wait stole winit's own
thread messages and froze the event loop after one iteration, so frames
were never drained from the channel. Removed; winit's run_app pump
already services the WH_KEYBOARD_LL hook.
Validated on a 5070 loopback: 0 decode errors, frames decode/paint/present
(present count 0 -> 1740). Reviewed (APPROVE-WITH-NITS); diagnostics stripped.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Agent now derives a recomputable, opaque machine_uid (Windows: SHA-256 of the OS
MachineGuid at HKLM\SOFTWARE\Microsoft\Cryptography\MachineGuid -> muid_<hex>;
non-Windows / registry-failure: persisted random UUID, warn-logged). Raw GUID
never exposed; OnceLock-cached. Reported ALONGSIDE agent_id (unchanged) on
AgentStatus (new additive proto field 12) and in the connect handshake query.
This is the stable identity that fixes config-loss duplicate registrations
(DESKTOP-I66IM5Q x9); server-side dedup keying that consumes it is SPEC-004
Task 2. Non-breaking, isolated. 5 unit tests; cargo fmt/clippy(-D warnings)/test
green on GURU-5070.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The auto-update path built both reqwest clients with an unconditional
danger_accept_invalid_certs(true), so a network MITM could serve an arbitrary
update .exe (checksum is no defense — same unverified channel) and gain RCE on
every managed endpoint. Replace with dev_insecure_tls() = cfg!(debug_assertions)
&& env GURUCONNECT_DEV_INSECURE_TLS: the cfg gate compiles out of release builds,
so a shipped agent ALWAYS verifies certs; dev keeps a self-signed escape hatch.
Loud warn when the insecure path is taken; verify_checksum kept + documented as
transport-integrity (not tamper) defense; TODO + follow-up for embedded-key
update signing (defense-in-depth). Release-invariant unit test added.
cargo fmt/clippy(-D warnings)/test green on GURU-5070 (90 tests). Closes the
2026-05-30 security-audit HIGH (reports/2026-05-30-gc-audit.md).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
From the secure-session-core Tasks 3-5 code review (APPROVE-WITH-FIXES):
- MEDIUM-2: delete the dead `validate_agent_key` "accept-any-key" placeholder +
its AuthenticatedAgent/AuthState scaffolding (zero callers; the real agent
auth is validate_agent_api_key + per-agent cak_ keys). Removes an auth landmine.
- LOW-3: stop interpolating support-code values into 3 relay log lines (bearer
credentials).
- LOW-1: document the X-Real-IP trust requirement in ip_extract.rs (NPM must set
it from $remote_addr); behavior unchanged.
- LOW-2: correct the consent/heartbeat comment in agent session loop (the loop
awaits the dialog; safe because CONSENT_TIMEOUT 60s < HEARTBEAT_TIMEOUT 90s).
cargo fmt/clippy(-D warnings)/test all green on GURU-5070 (89 tests, 0 warnings).
MEDIUM-1 (viewer-token logout revocation) remains a tracked follow-up.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SPEC-002 Phase 1 Task 7 (the last), code-reviewed APPROVED, locally verified
(cargo fmt + clippy -D warnings exit 0 + cargo test --workspace 89 pass + build).
- Encoder trait + factory: RawEncoder (salvaged, UNCHANGED) and H264Encoder,
selected by negotiation; factory falls back to raw on H.264 init failure.
- Negotiation: agent advertises supports_h264 (MFTEnumEx HW probe, cached) in
AgentStatus; server picks the codec via select_video_codec(supports, prefer)
and stamps StartStream.video_codec; agent re-guards on local HW. Policy
constant DEFAULT_PREFER_H264 = false, so RAW is negotiated for every session
today - H.264 stays dormant until live hardware validation (Task 8).
- MF H.264 encoder (h264.rs, FIRST-CUT / compile-verified-only): HW encoder MFT,
BGRA->NV12 (color.rs, unit-tested), sync drain, fall-back-to-raw on any failure.
- Viewer H.264 decoder (decoder.rs, FIRST-CUT): MF decoder on a dedicated COM
thread; drops+logs on failure, raw render path untouched.
- proto additive: VideoCodec enum, StartStream.video_codec=3,
SessionResponse.video_codec=5, AgentStatus.supports_h264=11.
- Raw+Zstd path byte-for-byte unchanged; remains the guaranteed default/fallback.
Review confirmed unsafe impl Send for H264Encoder is sound (single-owned &mut on
the block_on thread; session future never spawned) and every MF failure degrades
to raw. H.264 is NOT claimed functional - compile/clippy/build-verified only;
live validation + force-IDR + the no-spawn-invariant doc are Task 8 go-live gates.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SPEC-002 Phase 1 Task 6, code-reviewed APPROVED (2 rounds), locally verified
(cargo fmt + clippy -D warnings exit 0 + cargo test --workspace 70 pass + build).
- Viewer WH_KEYBOARD_LL hook diverts system combos (Win/Win+R, Alt+Tab, Alt+Esc,
Ctrl+Esc) to the remote as a full KeyEvent (vk + scan + is_extended + modifiers)
and suppresses local handling - GATED on the viewer window having focus AND a
"send system keys" toggle (default on; Pause/Break host-key), so it never bricks
the technician's local keyboard when unfocused.
- Agent injection via SendInput KEYEVENTF_SCANCODE + correct KEYEVENTF_EXTENDEDKEY
(right Ctrl/Alt, arrows, nav, Win, NumLock, numpad Divide) - layout-independent,
extended-key-correct.
- Ctrl+Alt+Del completes through the SAS helper (SYSTEM SendSAS); installer sets
the SoftwareSASGeneration policy; 3-tier fail-loud (no false success). SAS named
pipe DACL tightened from NULL/Everyone to Authenticated Users.
- Modifier hygiene: viewer emits key-ups for held Ctrl/Alt/Shift/Win on focus loss
/ close so modifiers never stick on the remote.
- proto: KeyEvent.is_extended = 7 (additive; older agents derive the flag).
Closes Win+R / Ctrl+C-V / Ctrl+Alt+Del / arrows-vs-numpad fidelity. Live on-device
testing is plan Task 8.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CI never ran clippy on the agent crate (the build-server clippy job is
Linux-only and can't compile the Windows agent; build-agent only runs cargo
build), so 77 clippy -D-warnings errors had accumulated. Behavior-preserving
cleanup, code-reviewed APPROVED, locally verified (cargo clippy --workspace
--all-targets --all-features -- -D warnings exits 0; cargo test --workspace =
57 passed).
- let _ = on Win32 resource-teardown BOOL returns (gdi.rs); fallible
BitBlt/GetDIBits stay error-handled
- removed unused imports/vars; idiom fixes (div_ceil, is_null, transmute
annotations, match collapsing, useless_conversion)
- #[allow(dead_code)] + comment on genuine Task-6/7 scaffolding (vk consts,
SpecialKey emission, SAS mgmt API, modifier tracking, GDI frame-diff fields)
- Cargo.lock: cargo pruned ~147 stale transitive entries (no version changes)
Follow-up: add cargo clippy -D warnings to the build-agent CI job so the agent
crate stays clippy-clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
9082e11 compiles + passes all 50 server tests on the build host; only blocked
CI on cargo fmt (4 files) and one clippy -D dead-code denial:
- cargo fmt --all (relay/mod.rs, session/mod.rs, agent consent/mod.rs + session/mod.rs)
- #[cfg_attr(not(test), allow(dead_code))] on session::get_consent_state (a
read accessor currently exercised only by tests)
No logic change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SPEC-002 Phase 1 Task 5, code-reviewed APPROVED. An attended (support-code)
session is invisible and inert to the technician until the end user accepts a
consent prompt on their own machine.
- proto: ConsentRequest / ConsentResponse + ConsentAccessMode enum (oneof
fields 80/81; no existing field renumbered).
- server: ConsentState on Session; attended -> Pending, managed -> NotRequired;
join_session refuses viewers unless Granted/NotRequired (single chokepoint -
StartStream only fires from join_session, so no frames or input flow pre-
consent); run_consent_handshake sends ConsentRequest, 60s timeout, granted ->
proceed, denied/timeout/disconnect -> teardown (end_session denied, machine
offline, support code released). consent_state persisted; consent_requested/
granted/denied audited.
- agent: Windows MessageBox (topmost/system-modal) on spawn_blocking; anything
but an explicit Yes = deny; non-Windows build is a fail-closed stub.
Not cargo-check-verified locally (no toolchain). Server verified on the build
host; the Windows agent half is verified by CI build-agent (Pluto).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
First run of the build-and-test CI gate (cargo fmt --all -- --check) surfaced
pre-existing formatting drift across the agent and server crates. Apply rustfmt
across the workspace so the codebase meets its own CI gate. Pure formatting; no
logic changes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Brings azcomputerguru/guru-connect up to the authoritative working copy that
had been maintained in the claudetools monorepo: Phase 1 security and
infrastructure (middleware, metrics, utils, token blacklist, deployment
scripts, security audits) plus the native-remote-control integration spec.
Preserves the repo .gitignore, .cargo, and server/static/downloads.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Added organization, site, tags columns to connect_machines table
- Agent now sends org/site/tags from embedded config in AgentStatus
- Server stores org/site/tags metadata in database
- Enables grouping machines by client/site/tag in dashboard
Previously, any installation with the protocol handler registered
would default to running as an agent. This caused admin/technician
machines (viewer-only) to appear in the sessions list.
Changes:
- Add Config::has_agent_config() to check for explicit agent config
- Only run as agent when: explicit 'agent' command, support code
provided, OR agent config file exists
- Viewer-only installs (protocol handler but no config) now exit
silently when launched without arguments
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Features:
- Agent checks for updates periodically (hourly) during idle
- Admin can trigger immediate updates via dashboard "Update Agent" button
- Silent updates with in-place binary replacement (no reboot required)
- SHA-256 checksum verification before installation
- Semantic version comparison
Server changes:
- New releases table for tracking available versions
- GET /api/version endpoint for agent polling (unauthenticated)
- POST /api/machines/:id/update endpoint for admin push updates
- Release management API (/api/releases CRUD)
- Track agent_version in machine status
Agent changes:
- New update.rs module with download/verify/install/restart logic
- Handle ADMIN_UPDATE WebSocket command for push updates
- --post-update flag for cleanup after successful update
- Periodic update check in idle loop (persistent agents only)
- agent_version included in AgentStatus messages
Dashboard changes:
- Version display in machine detail panel
- "Update Agent" button for each connected machine
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add git hash (short and full), branch, commit date
- Add build timestamp and dirty/clean state
- Add build profile (debug/release) and target triple
- New `version-info` command shows all build details
- `--version` now shows version-hash format (e.g., 0.1.0-4614df04)
- Startup logs now include version hash and build info
Example output:
GuruConnect v0.1.0
Git: 4614df04 (clean)
Branch: main
Commit: 2025-12-30 06:30:28 -0700
Built: 2025-12-30 15:25:20 UTC
Profile: release
Target: x86_64-pc-windows-msvc
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- REST API: All session/code/machine endpoints now require AuthenticatedUser
- Viewer WebSocket: Requires JWT token in query params (token=...)
- Agent WebSocket: Requires either valid support code OR API key
- Dashboard: Passes JWT token when connecting to viewer WS
- Native viewer: Passes token in protocol URL and WebSocket connection
- Added AGENT_API_KEY env var support for persistent agents
- Added get_status() to SupportCodeManager for auth validation
This fixes the security vulnerability where unauthenticated agents
could connect and appear in the dashboard without any credentials.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add AdminCommand message to protobuf (uninstall, restart, update)
- Add DELETE /api/machines/:agent_id endpoint with options:
- ?uninstall=true - send uninstall command to online agent
- ?export=true - return session history before deletion
- Add GET /api/machines/:agent_id/history endpoint for history export
- Add GET /api/machines endpoint to list all machines
- Handle AdminCommand in agent session handler
- Handle ADMIN_UNINSTALL error in agent main loop to trigger uninstall
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use raw FFI for named pipe operations instead of windows crate APIs
- Add Win32_System_IO feature to Cargo.toml
- Define pipe constants manually to avoid missing exports
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- New guruconnect-sas-service binary (runs as SYSTEM)
- Named pipe IPC for agent-to-service communication
- Multi-tier SAS approach: service > sas.dll > fallback
- Service auto-install/uninstall helpers in startup.rs
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add StartStream/StopStream/AgentStatus messages to protobuf
- Agent now starts in idle mode (heartbeat only, no capture)
- Agent enters streaming mode when viewer connects (StartStream)
- Agent returns to idle when all viewers disconnect (StopStream)
- Server tracks viewer IDs and sends start/stop commands
- Heartbeat mechanism with 90 second timeout detection
- Session API now includes streaming status and agent info
This allows 2000+ agents to connect with minimal bandwidth.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Hide console window by default (windows_subsystem = "windows")
- Add "Show Debug Window" menu item to tray
- AllocConsole when debug window requested
- Console shows logs for troubleshooting
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Persistent agents: No "End Session" menu, shows "Managed by Administrator"
- Persistent agents: Always reconnect, can only be removed via admin disconnect
- Support sessions: User can end via tray icon
- Tray icon still shows for persistent agents (status display only)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Persistent agents (no code) now add to startup on launch
- All agents add to startup, cleanup removes it on explicit exit
- Persistent agents reconnect automatically on disconnect
- Support sessions still exit without reconnecting
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ChatMessage to protobuf definitions
- Server relays chat messages between agent and viewer
- Agent chat module shows messages via MessageBox
- Dashboard chat modal with WebSocket connection
- Simplified protobuf encoder/decoder in JavaScript
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Added startup.rs module for Windows registry operations
- Agent adds itself to HKCU\...\Run on session start
- Agent removes itself from startup on session end
- Works with user-level registry (no admin required)
- Added Win32_System_Registry feature to windows crate
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Added guruconnect.manifest requesting highestAvailable privileges
- Using winres to embed manifest in executable
- Added is_elevated() function to detect admin status
- Logs elevation status on startup
- Manifest includes Windows 7-11 compatibility
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Windows message queue pumping in process_events()
- PeekMessageW/TranslateMessage/DispatchMessageW for event delivery
- Menu clicks and tray events now work properly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Added tray-icon and muda crates for tray functionality
- Tray icon shows green circle when connected
- Menu displays: session code, machine name, End Session option
- End Session menu item cleanly terminates the agent
- Tray events processed in session main loop
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Server changes:
- Allow cancelling connected codes (not just pending)
- Reject agent connections with cancelled codes
- Periodic cancellation check during active sessions
- Send Disconnect message when code is cancelled
Agent changes:
- Detect cancellation via Disconnect message
- Show Windows MessageBox to notify user
- Exit cleanly without reconnecting for support sessions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Agent now reads its own filename to extract the 6-digit code.
User just downloads GuruConnect-123456.exe and double-clicks - no
command line arguments or prompts needed.
Supports patterns:
- GuruConnect-123456.exe
- GuruConnect_123456.exe
- GuruConnect123456.exe
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Server: Accept support_code param in WebSocket connection
- Server: Link code to session when agent connects, mark as connected
- Server: Mark code as completed when agent disconnects
- Agent: Accept support code from command line argument
- Agent: Send hostname and support_code in WebSocket params
- Portal: Trigger agent download with code in filename
- Portal: Show code reminder in download instructions
- Dashboard: Add machines list fetching (Access tab)
- Add TODO.md for feature tracking
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add UUID-based agent_id field to Config struct
- Auto-generate and persist agent_id on first run
- Include agent_id in WebSocket query parameters
- Update production server URL to connect.azcomputerguru.com
Fixes WebSocket connection failure where server expected agent_id parameter.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- GetDesc now returns value instead of mutable param
- CPUAccessFlags is u32, not flag wrapper
- SetEvictionPriority takes enum directly
- Fix encode_utf16 iteration
- Rename display variable to avoid tracing conflict
- Fix borrow issue in websocket receive