feat(launcher): harden native caching and telemetry; consolidate documentation
- Implemented SHA-256 integrity checks and stale temp purge in native download logic.\n- Enabled strict hash verification in background sync cycle.\n- Made CPU load gauge dynamic using real-time loadavg metadata.\n- Consolidated native app documentation into single master manual.\n- Marked legacy electron_native.js as deprecated.\n- Updated roadmap with temp cleanup and launch protection tasks.
This commit is contained in:
13
TODO.md
13
TODO.md
@@ -29,7 +29,18 @@ This is a list of tasks to be completed before the next event/show/conference.
|
||||
- [x] **Session Search:** Modernized logic, fixed layout bugs and icon exports. (Completed 2026-01-27)
|
||||
- [x] **Exhibit Search:** Standardized Exhibitor and Lead Tracking reactive search. (Completed 2026-01-28)
|
||||
|
||||
## Urgent Tasks (Feb 9, 2026)
|
||||
## Urgent Tasks (Feb 10, 2026)
|
||||
|
||||
1. **AE Events Launcher Hardening:**
|
||||
- [ ] **Temp Cleanup:** Implement auto/manual removal of `[tmp]` files older than 24 hours.
|
||||
- [ ] **Recording Access:** Add button to open `[recording]` directory in Finder (macOS).
|
||||
- [ ] **JWT Lifecycle:** Implement silent auto-refresh for long-running podium sessions.
|
||||
- [ ] **Launch Protection:** Prevent "Duplicate Launch" via UI locking and status messaging.
|
||||
- [ ] **Cache Reliability:** Implement `.tmp -> .file` rename pattern with post-download checksum verification.
|
||||
- [ ] **Native Actuators:** Plan macOS-specific commands for window focus and system orientation.
|
||||
- [ ] **Self-Update:** Implement simple directory/URL-based auto-update mechanism.
|
||||
- [x] **Audit:** Marked `electron_native.js` as `[DEPRECATED]` in favor of active native repo logic.
|
||||
- [x] **Telemetry:** Made CPU Load gauge dynamic using real-time `loadavg` data.
|
||||
|
||||
1. **IDAA Module Verification:**
|
||||
- [ ] **Bulletin Board (BB):** 90-95% Ready for Beta Test.
|
||||
|
||||
146
documentation/AE_EVENTS_LAUNCHER_NATIVE_INTEGRATION.md
Normal file
146
documentation/AE_EVENTS_LAUNCHER_NATIVE_INTEGRATION.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# Aether Events Launcher: Native Electron Integration
|
||||
|
||||
> **Status:** Operational / Phase 5 Implementation
|
||||
> **Last Updated:** February 10, 2026
|
||||
> **Primary Platform:** macOS (Darwin)
|
||||
> **Fallback Platform:** Linux / Windows
|
||||
|
||||
## 1. Overview
|
||||
The Aether Events Launcher utilizes an Electron-based "Native Shell" to provide OS-level capabilities that are normally restricted by browser sandboxing. This enables persistent file caching, direct control of presentation software (Keynote, PowerPoint), and hardware telemetry.
|
||||
|
||||
### Operational Modes
|
||||
| Mode | Purpose | File Handling |
|
||||
| :--- | :--- | :--- |
|
||||
| **Default** | Standard web browser access. | Direct downloads; no local caching. |
|
||||
| **Onsite** | Web access on event networks. | Faster polling; browser-based file management. |
|
||||
| **Native** | Dedicated Podium Kiosk (Electron). | Full background pre-caching; atomic safe-handover. |
|
||||
|
||||
---
|
||||
|
||||
## 2. Architecture: The Three-Layer Bridge
|
||||
|
||||
The integration is built on a decoupled three-layer communication model to ensure security and cross-platform flexibility.
|
||||
|
||||
### 2.1 Layer 1: The Engine (Main Process)
|
||||
- **File:** `aether_app_native/src/main/*.ts`
|
||||
- **Role:** Performs the heavy lifting (Filesystem, Shell, AppleScript).
|
||||
- **Responsibilities:**
|
||||
- Managing the **Hashed Cache** directory.
|
||||
- Executing `osascript` intents for presentation control.
|
||||
- Spawn/Kill process management.
|
||||
|
||||
### 2.2 Layer 2: The Gatekeeper (Preload Script)
|
||||
- **Namespace:** `window.aetherNative`
|
||||
- **Role:** Securely exposes whitelisted IPC channels to the Renderer.
|
||||
- **Standards:** Uses `contextBridge.exposeInMainWorld` to prevent arbitrary code execution.
|
||||
|
||||
### 2.3 Layer 3: The Messenger (SvelteKit Relay)
|
||||
- **File:** `src/lib/electron/electron_relay.ts`
|
||||
- **Role:** Provides a clean, typed API for Svelte components.
|
||||
- **Responsibilities:**
|
||||
- Mapping `camelCase` UI triggers to `snake_case` IPC calls.
|
||||
- Implementing "Smart Fallbacks" (e.g., resolving `[home]` placeholders if the bridge is partially hydrated).
|
||||
|
||||
---
|
||||
|
||||
## 3. The "Zero-Config" Lifecycle
|
||||
|
||||
To support rapid onsite deployment, the native app requires zero manual setup.
|
||||
|
||||
1. **Seed:** On launch, the Main process reads a local `seed.json` (Device ID + API Key).
|
||||
2. **Identity:** Calls `GET /v3/data_store/code/{device_code}` or `GET /v3/crud/event_device/{id}` to pull operational context.
|
||||
3. **Hydrate:** Authenticates with the Aether V3 API and injects the **JWT** and **Device Config** into the UI environment.
|
||||
4. **Launch:** Navigates the SvelteKit frontend directly to the assigned Event Launcher route.
|
||||
|
||||
---
|
||||
|
||||
## 4. Podium Reliability Protocol
|
||||
|
||||
The system is designed to ensure that a presentation never fails due to network instability.
|
||||
|
||||
### 4.1 Hashed Cache Pattern
|
||||
Files are stored persistently using their SHA-256 hash to prevent filename collisions and handle versioning.
|
||||
- **Root:** `~/Library/Caches/OSIT/file_cache/`
|
||||
- **Subdirectory:** First 2 characters of hash (e.g., `ab/`)
|
||||
- **Filename:** `{hash}.file`
|
||||
|
||||
### 4.2 Background Sync (File Warming)
|
||||
When a user navigates to a session in the Launcher UI, the `LauncherBackgroundSync` component:
|
||||
1. Extracts all `event_file_id` values for that session.
|
||||
2. Checks the native cache via `aetherNative.check_cache`.
|
||||
3. Triggers background downloads for missing files via `aetherNative.download_to_cache`.
|
||||
|
||||
### 4.3 Safe Handover (Launch Sequence)
|
||||
When a user clicks "Open", the system follows a non-destructive sequence:
|
||||
1. **Verify:** Confirm hash exists in the permanent cache.
|
||||
2. **Copy:** Create an atomic copy in the system `[tmp]` directory.
|
||||
3. **Restore:** Rename the copy to its original filename (e.g., `Abstract_101.pptx`).
|
||||
4. **Execute:** Launch the file via the OS.
|
||||
|
||||
---
|
||||
|
||||
## 5. Automation & Actuators (Phase 5)
|
||||
|
||||
The native shell provides specialized handlers for controlling the "Podium Experience."
|
||||
|
||||
### 5.1 Presentation Acts
|
||||
| Action | Handler | Actuator (macOS) |
|
||||
| :--- | :--- | :--- |
|
||||
| **Launch** | `launch_presentation` | `open` or `osascript` (slideshow start) |
|
||||
| **Control** | `control_presentation` | `osascript` (next/prev slide) |
|
||||
| **Clean Up**| `kill_processes` | `killall -INT` (graceful exit) |
|
||||
|
||||
### 5.2 System Management
|
||||
- **Telemetry:** Pushes `cpu_usage`, `memory_free_gb`, and `foreground_app` via heartbeats using the `get_device_info` relay.
|
||||
- **Self-Update (Roadmap):** Plan to monitor Syncthing `admin_share` for newer `.app` versions and perform atomic swaps.
|
||||
|
||||
### 5.3 Planned Actuators (Future Phases)
|
||||
- **Recording:** Control for `aperture` session capture (`start`, `stop`).
|
||||
- **Display Layouts:** Toggling between Mirror and Extended modes via `displayplacer`.
|
||||
|
||||
---
|
||||
|
||||
## 6. Launcher Configuration & Management
|
||||
|
||||
The Launcher features a standardized, responsive configuration interface designed for onsite technical management.
|
||||
|
||||
### 6.1 UI Architecture
|
||||
- **Tabbed Navigation:** Categorized into System, Sync, and General settings.
|
||||
- **Section Wrapper (`Launcher_Cfg_Section`):** A shared component providing a consistent header, icon, and responsive grid container.
|
||||
|
||||
### 6.2 3-Way State Logic
|
||||
To manage screen real estate on varying laptop resolutions, all configuration sections utilize a 3-way visibility state:
|
||||
- **`collapsed`**: Content is hidden.
|
||||
- **`auto`**: Expanded by default, but automatically closes if another "auto" section is opened.
|
||||
- **`pinned`**: Expanded and remains open regardless of other section interactions.
|
||||
|
||||
### 6.3 Technical Mode (`edit_mode`)
|
||||
The UI dynamically filters fields based on the user's focus. Enabling Technical Mode (`$ae_loc.edit_mode`) reveals advanced diagnostic and writeable fields.
|
||||
|
||||
| Category | Standard View (Read-Only) | Technical Mode (Read/Write) |
|
||||
| :--- | :--- | :--- |
|
||||
| **Health** | Heartbeat, RAM Usage, Sync Stats | Hostname, IP List, Raw Device JSON |
|
||||
| **OS Bridge** | Folder Buttons, Recording Toggle | Manual Terminal Commands, Reset Wallpaper |
|
||||
| **Sync** | Sync Completion Status | Millisecond Timers, Cache Prefix Logic |
|
||||
| **Update** | Current Version Status | Manual Update Paths, URL Overrides |
|
||||
|
||||
---
|
||||
|
||||
## 7. Implementation Reference (IPC Whitelist)
|
||||
|
||||
### Core Functions (`electron_relay.ts`)
|
||||
- `get_device_config()`: Returns hydrated device settings from the native shell.
|
||||
- `get_device_info()`: Returns OS metadata, IP list, and path placeholders (`[home]`, `[tmp]`).
|
||||
- `check_hash_file_cache({cache_root, hash})`: Local filesystem hash check.
|
||||
- `download_to_cache({url, cache_root, hash, ...})`: Authorized background download to the hashed cache.
|
||||
- `launch_from_cache({cache_root, hash, temp_root, filename})`: Atomic "Safe Handover" trigger.
|
||||
- `launch_presentation({path, app})`: Phase 5 specialized launcher with slideshow activation.
|
||||
- `control_presentation({app, action})`: Remote navigation (next/prev) for active decks.
|
||||
- `kill_processes({process_name_li})`: Graceful application termination.
|
||||
- `manage_recording({action})`: Presentation session capture control (Aperture).
|
||||
- `list_tools()`: Manifest of all available native bridge functions.
|
||||
|
||||
### Path Placeholders
|
||||
To ensure cross-platform compatibility, all paths should use:
|
||||
- `[home]`: User home directory.
|
||||
- `[tmp]`: System temporary directory.
|
||||
76
documentation/history/AETHER_NATIVE_APP_ELECTRON_NEW_2026.md
Normal file
76
documentation/history/AETHER_NATIVE_APP_ELECTRON_NEW_2026.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Aether Native Electron App - V3 Architecture (2026)
|
||||
|
||||
## 1. Overview
|
||||
The Aether Native App serves as the OS-level bridge for the SvelteKit frontend. It enables functionality that is normally restricted by browser sandboxing, such as local filesystem management, hardware telemetry, and direct control of third-party presentation software (PowerPoint, Keynote, LibreOffice).
|
||||
|
||||
**Core Tasks (Completed Jan 2026):**
|
||||
* **[Infrastructure]**: Restore AE Events Presentation Launcher (Electron) (ID: 221513945)
|
||||
* **[Frontend]**: V3 File Caching: Implement Launcher CRUD Migration (ID: 173518010)
|
||||
* **[Frontend]**: Native App Bridge: Standardize Electron IPC (ID: 173448078)
|
||||
|
||||
---
|
||||
|
||||
## 2. The Three-Layer Architecture
|
||||
|
||||
### 2.1 The Engine (`src/main/*.ts`)
|
||||
* **Process:** Main Process (Node.js/TypeScript)
|
||||
* **Role:** Performs the actual OS-level operations.
|
||||
* **Key Responsibilities:**
|
||||
* **Shell Handlers (`shell_handlers.ts`)**: Executing shell commands, AppleScripts, and process management.
|
||||
* **File Handlers (`file_handlers.ts`)**: Managing the permanent Hashed Cache (`file_cache/`) and atomic Safe Handover.
|
||||
* Resolving global path placeholders like `[home]` and `[tmp]` via `file_utils.ts`.
|
||||
|
||||
### 2.2 The Bridge (`src/preload/index.ts`)
|
||||
* **Process:** Preload Script
|
||||
* **Role:** The security gatekeeper.
|
||||
* **Key Responsibilities:**
|
||||
* Uses Electron's `contextBridge` to securely expose Main Process functions to the UI.
|
||||
* Exposes the `window.aetherNative` object.
|
||||
* Ensures that only whitelisted IPC channels can be triggered by the renderer.
|
||||
|
||||
### 2.3 The Messenger (`src/lib/electron/electron_relay.ts`)
|
||||
* **Process:** Renderer Process (SvelteKit)
|
||||
* **Role:** The TypeScript API used by Svelte components.
|
||||
* **Key Responsibilities:**
|
||||
* Standardizing IPC calls to snake_case.
|
||||
* Implementing "Smart Fallbacks" (e.g., UI-side placeholder resolution if the bridge is inactive).
|
||||
|
||||
---
|
||||
|
||||
## 3. Core Lifecycle
|
||||
|
||||
1. **Seed Phase:** The Electron shell reads `resources/seed_config.json` to identify the device.
|
||||
2. **Hydration Phase:** The shell authenticates with the Aether V3 API to pull device-specific settings.
|
||||
3. **Injection Phase:** The shell injects the **JWT** and **Native Config** into the SvelteKit environment.
|
||||
4. **Observation Phase:** Background sync loops manage file warming and heartbeat telemetry.
|
||||
|
||||
---
|
||||
|
||||
## 4. Native Tool Library (`window.aetherNative`)
|
||||
|
||||
### File & Cache Management
|
||||
- `check_cache({hash})`: Verify if a file exists in the hidden hashed storage.
|
||||
- `download_to_cache({url, hash})`: Secure background download using the native API key.
|
||||
- `launch_from_cache({hash, filename})`: **Safe Handover** — copies from cache to temp with the original name and triggers the specialized launcher.
|
||||
|
||||
### OS Execution (The "Actuators")
|
||||
- `launch_presentation({path, app})`: Phase 5 specialized launcher with auto-focus (`activate`) and slideshow start.
|
||||
- **Linux:** Triggers `libreoffice --impress`.
|
||||
- **macOS:** Triggers AppleScript for Keynote or PowerPoint.
|
||||
- `control_presentation({app, action})`: Remote navigation for active decks.
|
||||
- **Actions:** `next`, `prev`, `start`, `stop`.
|
||||
- `run_cmd({cmd})`: Executes raw shell commands with automatic path resolution.
|
||||
- `kill_processes([names])`: Force-closes apps to clean the podium.
|
||||
|
||||
### Metadata & Discovery
|
||||
- `get_device_info()`: Provides CPU/RAM stats and absolute system paths.
|
||||
- `list_tools()`: Returns a JSON manifest of all available native functions for self-documentation.
|
||||
|
||||
---
|
||||
|
||||
## 5. Path Placeholder System
|
||||
To maintain cross-platform compatibility, the system uses a placeholder syntax for all paths:
|
||||
- `[home]`: Resolves to the user's home directory (e.g., `/home/scott` or `/Users/scott`).
|
||||
- `[tmp]`: Resolves to the system temporary directory.
|
||||
|
||||
**Resolution Logic:** All native handlers utilize a global regex (`/\[home\]/g`) to ensure these are converted to absolute paths before any disk or shell operation occurs.
|
||||
146
documentation/history/NATIVE_APP_AUTOMATION_SCRIPTS.md
Normal file
146
documentation/history/NATIVE_APP_AUTOMATION_SCRIPTS.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# Specification: Aether Native Host Automation & Scripting
|
||||
|
||||
**Target OS:** macOS (Primary), Linux/Windows (Secondary)
|
||||
**Languages:** AppleScript (`osascript`), Bash (`sh`), Node.js `child_process`
|
||||
**Implementation:** `src/main/shell_handlers.ts` (Electron App)
|
||||
|
||||
## 1. Presentation Launch & Control (AppleScript)
|
||||
To provide a seamless "Podium Experience," the app uses AppleScript to control third-party presentation software.
|
||||
|
||||
### 1.1 Microsoft PowerPoint
|
||||
* **Launch:** `powerpoint:launch`
|
||||
```applescript
|
||||
tell application "Microsoft PowerPoint"
|
||||
activate
|
||||
open (POSIX file "[FILE_PATH]")
|
||||
delay 1
|
||||
run slide show of active presentation
|
||||
end tell
|
||||
```
|
||||
* **Control:**
|
||||
* **Next:** `tell application "Microsoft PowerPoint" to next slide of slide show view of active presentation`
|
||||
* **Prev:** `tell application "Microsoft PowerPoint" to previous slide of slide show view of active presentation`
|
||||
* **Start:** `tell application "Microsoft PowerPoint" to run slide show of active presentation`
|
||||
* **Stop:** `tell application "Microsoft PowerPoint" to stop slide show of active presentation`
|
||||
* **Quit:** `quit application "Microsoft PowerPoint" saving no`
|
||||
|
||||
### 1.2 Apple Keynote
|
||||
* **Launch:** `keynote:launch`
|
||||
```applescript
|
||||
tell application "Keynote"
|
||||
activate
|
||||
open (POSIX file "[FILE_PATH]")
|
||||
delay 1
|
||||
start (front document)
|
||||
end tell
|
||||
```
|
||||
* **Control:**
|
||||
* **Next:** `tell application "Keynote" to show next`
|
||||
* **Prev:** `tell application "Keynote" to show previous`
|
||||
* **Start:** `tell application "Keynote" to start (front document)`
|
||||
* **Stop:** `tell application "Keynote" to stop`
|
||||
|
||||
### 1.3 Adobe Acrobat (PDF)
|
||||
* **Launch:** `acrobat:fullscreen`
|
||||
```applescript
|
||||
tell application "Adobe Acrobat Reader"
|
||||
activate
|
||||
-- Acrobat doesn't have a direct "Start Slideshow" AppleScript command
|
||||
-- We use system events to trigger Cmd+L (Full Screen)
|
||||
tell application "System Events" to keystroke "l" using {command down}
|
||||
end tell
|
||||
```
|
||||
|
||||
### 1.4 LibreOffice (Linux Testing)
|
||||
* **Launch:** `libreoffice:launch`
|
||||
```bash
|
||||
libreoffice --impress "[FILE_PATH]"
|
||||
```
|
||||
* **Note:** LibreOffice control on Linux is currently limited to launch-only.
|
||||
|
||||
## 2. Process Management (Bash/Node)
|
||||
The app must ensure that only one presentation is "Active" to prevent audio overlap or confusion.
|
||||
|
||||
| Action | macOS Command | Linux/Windows Mock |
|
||||
| --- | --- | --- |
|
||||
| **Kill Office** | `killall -INT "Microsoft PowerPoint"` | `pkill -f powerpnt` |
|
||||
| **Kill Keynote**| `killall -INT "Keynote"` | `echo "Keynote Not Supported"` |
|
||||
| **Kill Acrobat**| `killall -9 "Acrobat Reader"` | `pkill -f acroread` |
|
||||
| **Kill Parallels**| `pkill -i -f '(Parallels).*(PowerPoint)'` | `N/A` |
|
||||
|
||||
## 3. Recording Lifecycle (`aperture_wrapper`)
|
||||
The app manages high-quality screen and audio recording using the `aperture` CLI or a custom wrapper.
|
||||
|
||||
### 3.1 Start Recording
|
||||
* **Intent:** `record:start`
|
||||
* **Action:** Launch `aperture` as a child process.
|
||||
* **Command Pattern:**
|
||||
```bash
|
||||
aperture --fps 30 --highlight-clicks --audio-device "[DEVICE_ID]" --output "[PATH]/[SESSION_ID].mp4"
|
||||
```
|
||||
* **Telemetry:** Push `record_status: "Recording"` and the PID to the V3 API.
|
||||
|
||||
### 3.2 Stop Recording
|
||||
* **Intent:** `record:stop`
|
||||
* **Action:**
|
||||
1. Send `SIGINT` (Interrupt) to the recorded process.
|
||||
2. Wait for file finalization.
|
||||
3. Verify file existence and minimum size.
|
||||
4. Push `record_status: "Idle"` to the V3 API.
|
||||
|
||||
## 4. Host Hardening & "Odd Stuff"
|
||||
Specialized scripts to ensure the Mac laptop behaves as a dedicated podium.
|
||||
|
||||
### 4.1 Podium Lockdown (macOS)
|
||||
* **Prevent Sleep:** `caffeinate -dis &` (Stores PID).
|
||||
* **Volume Enforce:** `osascript -e "set volume output volume 100"`
|
||||
* **Timezone Sync:** Force `America/New_York` (ET) for all device status pushes to ensure dashboard consistency.
|
||||
* **Hide Menu Bar/Dock:** (Optional) Use `System Events` AppleScript to toggle auto-hide.
|
||||
|
||||
### 4.2 Digital Poster Screen Saver
|
||||
To prevent screen burn-in and provide branding when the podium is idle:
|
||||
* **Idle Detection:** Uses `svelte-idle` to track user activity.
|
||||
* **Action:** Automatically rotates through a random list of `event_file` objects marked as "poster".
|
||||
* **Override:** Any mouse movement or click immediately kills the screen saver modal.
|
||||
|
||||
### 4.3 WebSocket Remote Control (The "Tech Bridge")
|
||||
Allows onsite staff to manage the podium without physical access.
|
||||
* **Intents:**
|
||||
* `ae_refresh:now`: Triggers a full page reload.
|
||||
* `ae_native:cmd`: Executes a whitelisted shell command.
|
||||
* `ae_open:event_file`: Remotely opens a specific presentation or image.
|
||||
* `ae_record:start/stop`: Remotely toggles the Aperture wrapper.
|
||||
|
||||
## 5. Accessibility & Permissions (macOS TCC)
|
||||
Since this is a specialized app, we must handle Apple's TCC (Transparency, Consent, and Control) layer:
|
||||
- **AV Access:** Use `systemPreferences.askForMediaAccess('camera')` and `microphone`.
|
||||
- **Accessibility:** For remote control/automation, check `systemPreferences.isTrustedAccessibilityClient(true)`.
|
||||
- **Screen Recording:** Triggered by the first `aperture` call; the app should provide a UI guide to help the user enable it in System Settings.
|
||||
- **Check Command:** `osascript -e 'tell application "System Events" to get UI elements enabled'`
|
||||
|
||||
## 6. Automation Strategy (The "Intent" Pattern)
|
||||
To keep the bridge secure, we do **not** send raw scripts from the UI. Instead, we send an "Intent."
|
||||
|
||||
**Renderer Call:**
|
||||
```javascript
|
||||
window.aetherNative.launch_presentation({ path: '/tmp/my_deck.pptx', app: 'powerpoint' });
|
||||
window.aetherNative.control_presentation({ app: 'powerpoint', action: 'next' });
|
||||
```
|
||||
|
||||
**Main Process Handler (`src/main/shell_handlers.ts`):**
|
||||
1. Verify the file path is within the allowed `[tmp]` directory.
|
||||
2. Select the corresponding AppleScript template based on `app` and `action`.
|
||||
3. Replace `[FILE_PATH]` and execute via `child_process.exec`.
|
||||
|
||||
## 7. Linux Development Mocking
|
||||
Since development happens on Arch Linux, the `execIntent` handler will check `process.platform`:
|
||||
- If `darwin`: Execute `osascript`.
|
||||
- If `linux`: Use `libreoffice` for launch, or log intent for control commands.
|
||||
- **Recording Mock:** Use `ffmpeg` or generate a fake `.mp4` file to test the sync/upload logic.
|
||||
|
||||
## 8. Refresh & Sync Loops
|
||||
Decoupled polling to balance performance and responsiveness:
|
||||
- **Session Loop (30s):** High frequency for active podium changes.
|
||||
- **Location Loop (2m):** Medium frequency for room configuration.
|
||||
- **Device Loop (5m):** Low frequency for background heartbeat and telemetry.
|
||||
- **Sync Loop (15m):** Background file warming for upcoming presentations.
|
||||
52
documentation/history/NATIVE_APP_DEPLOYMENT_PLAN.md
Normal file
52
documentation/history/NATIVE_APP_DEPLOYMENT_PLAN.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# Deployment & Update Plan: Aether Native V3
|
||||
|
||||
**Mechanism:** Syncthing + Admin Share
|
||||
**Target:** macOS Fleet
|
||||
**Primary Controller:** `admin_share` directory
|
||||
|
||||
## 1. Distribution via Syncthing
|
||||
We will leverage the existing Syncthing mesh to distribute binaries and configurations.
|
||||
|
||||
### 1.1 Directory Structure (Admin Share)
|
||||
```text
|
||||
admin_share/
|
||||
├── configs/
|
||||
│ └── seed_[DEVICE_ID].json # Specific seed files for auto-provisioning
|
||||
├── binaries/
|
||||
│ └── native_app/
|
||||
│ ├── version.json # Latest version metadata
|
||||
│ └── Aether_Native.app/ # The macOS App Bundle (or .zip)
|
||||
└── scripts/
|
||||
└── update_helper.sh # macOS script to swap binaries
|
||||
```
|
||||
|
||||
## 2. Self-Update Protocol
|
||||
The V3 app will monitor for updates without relying on external internet access (perfect for isolated event networks).
|
||||
|
||||
### 2.1 The Update Flow
|
||||
1. **Check:** On launch (and periodically), the app reads `admin_share/binaries/native_app/version.json`.
|
||||
2. **Compare:** If `version.json > package.json`, the app signals the user: "Update Available".
|
||||
3. **Stage:** The app copies the new `.app` bundle from the sync folder to a local `~/Library/Caches/Aether/updates/` directory.
|
||||
4. **Swap:** The app launches `update_helper.sh` and exits. The script moves the new version into `/Applications/` and restarts the app.
|
||||
|
||||
## 3. Provisioning (The "Seed" Strategy)
|
||||
To set up a new laptop:
|
||||
1. Install Syncthing and link the `admin_share`.
|
||||
2. The Electron app looks for `admin_share/configs/seed_$(hostname).json`.
|
||||
3. If found, it copies it to its local config path and bootstraps itself.
|
||||
4. **Result:** Zero manual configuration for the onsite tech.
|
||||
|
||||
## 4. macOS Specific Lifecycle
|
||||
- **Gatekeeper:** Since these are distributed via Syncthing, we must handle the "App is damaged or from an unidentified developer" prompt.
|
||||
- **Plan:** Include a `post-sync` script that runs `xattr -rd com.apple.quarantine` on the binary folder within the admin share (if permissions allow) or instructs the user on the first run.
|
||||
|
||||
## 5. Development Workflow (Arch Linux -> Mac)
|
||||
1. **Build:** On Arch Linux, run `npm run build:mac`.
|
||||
2. **Package:** Use `electron-packager` to create the macOS `.app` bundle.
|
||||
3. **Distribute:** Move the built `.app` into the local Syncthing `admin_share` folder.
|
||||
4. **Verify:** Watch the fleet of Macs automatically pull the update via Syncthing.
|
||||
|
||||
## 6. Project Document Updates
|
||||
The following files have been updated to reflect this deployment strategy:
|
||||
- `NATIVE_APP_V3_REWRITE_PLAN.md`: Added self-update logic requirements.
|
||||
- `NATIVE_BRIDGE_INTERFACE_SPEC.md`: Added `ae_sys.checkForUpdates()` method.
|
||||
75
documentation/history/NATIVE_APP_FUNCTIONAL_SPEC.md
Normal file
75
documentation/history/NATIVE_APP_FUNCTIONAL_SPEC.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Functional Specification: Aether Native App (Electron)
|
||||
|
||||
**Date:** 2026-01-30
|
||||
**Status:** V5 / Phase 5 Specification
|
||||
**Target OS:** macOS (Primary), Linux/Windows (Secondary)
|
||||
|
||||
## 1. Core Objectives
|
||||
The Native App acts as a "Privileged Shell" for the Aether SvelteKit UI, providing capabilities that standard web browsers block for security reasons. It turns a standard laptop into a managed "Podium Kiosk."
|
||||
|
||||
## 2. macOS Permission Matrix (TCC)
|
||||
To function as a podium controller, the Electron app requires specific entitlements.
|
||||
|
||||
| Permission | Reason | Criticality |
|
||||
| :--- | :--- | :--- |
|
||||
| **Accessibility** | Required to send AppleScript commands (Next/Prev) to Keynote and PowerPoint. | **CRITICAL** |
|
||||
| **Screen Recording** | Required by the `aperture` utility to record the presentation session. | **CRITICAL** |
|
||||
| **Microphone** | Required to capture room audio/presenter voice during recording. | **CRITICAL** |
|
||||
| **Camera** | Optional, only if "Presenter View" (PiP) recording is enabled. | Low |
|
||||
| **Automation** | Allows the app to control "System Events", "Finder", "Keynote", and "Microsoft PowerPoint". | **CRITICAL** |
|
||||
| **Full Disk Access** | Recommended to ensure access to `~/OSIT` and `~/Downloads` without nagging prompts. | High |
|
||||
|
||||
## 3. Handler Registry (V5)
|
||||
The following IPC handlers are exposed via `window.aetherNative`.
|
||||
|
||||
### 3.1 File & Cache System
|
||||
| Handler | Description |
|
||||
| :--- | :--- |
|
||||
| `native:check-cache` | Verifies file existence in the sharded local cache (`~/OSIT/native_app/cache/xx/hash.file`). |
|
||||
| `native:download-to-cache` | Streams a file from the API to the local cache with SHA-256 verification. |
|
||||
| `native:launch-from-cache` | **Atomic Launch:** Copies file from cache -> temp with original filename -> launches app. |
|
||||
|
||||
### 3.2 Automation & Control (Phase 5)
|
||||
| Handler | Description |
|
||||
| :--- | :--- |
|
||||
| `native:launch-presentation` | Opens a file using the specific app (Keynote/PPT) with "Slide Show" mode enabled immediately. |
|
||||
| `native:control-presentation` | Sends navigation commands: `next`, `prev`, `start`, `stop`. |
|
||||
| `native:kill-processes` | Force quits applications by name (e.g., "Microsoft PowerPoint") to resolve freezes. |
|
||||
|
||||
### 3.3 System Management (New Requirements)
|
||||
These handlers are required for full "Kiosk" management.
|
||||
|
||||
| Handler | Description | Implementation Note |
|
||||
| :--- | :--- | :--- |
|
||||
| `native:set-wallpaper` | Resets desktop background to a specific image. | AppleScript: `tell application "System Events" to set picture of every desktop...` |
|
||||
| `native:update-app` | Checks `~/OSIT/admin_share/...` for newer versions and self-updates. | Requires specific logic to swap the `.app` bundle and restart. |
|
||||
| `native:window-control` | Controls the Electron window: `maximize`, `minimize`, `kiosk`, `devtools`. | Direct Electron `BrowserWindow` API calls. |
|
||||
| `native:manage-recording` | Controls `aperture` process: `start`, `stop`, `status`. | Must track the PID of the spawned recording process. |
|
||||
| `native:set-display-layout` | Toggles between **Mirror** and **Extended** modes. | Use bundled `displayplacer` binary (AppleScript is unreliable for this). |
|
||||
| `native:power-control` | Initiates `shutdown` or `restart`. | Command: `shutdown -h now` (may require admin/sudo setup or user-level fallback). |
|
||||
| `native:open-external` | Opens a URL in a specific browser (Chrome/Firefox). | `spawn('open', ['-a', 'Google Chrome', url])`. |
|
||||
|
||||
## 4. Feature Specifications
|
||||
|
||||
### 4.1 Self-Update Strategy
|
||||
1. **Path:** `~/OSIT/Speaker Ready System/Admin Share/Custom Applications/osit_binaries/`
|
||||
2. **Logic:**
|
||||
* Compare `package.json` version in running app vs. remote path.
|
||||
* If remote > local:
|
||||
* Display "Updating..." splash.
|
||||
* Copy new `.app` to `/Applications` (or current location).
|
||||
* Relaunch.
|
||||
|
||||
### 4.2 Web Page Handling
|
||||
The Launcher avoids Safari.
|
||||
* **Strategy A (Simple):** `native:open-external` -> Opens in Google Chrome Kiosk Mode (`--kiosk`).
|
||||
* **Strategy B (Integrated):** Use an Electron `BrowserView` (not `iframe`) to render the website *inside* the Aether window, ensuring we keep the "Back" button overlay visible.
|
||||
|
||||
### 4.3 Display Layouts
|
||||
To reliably switch between Mirroring (for setup) and Extended (for presentation):
|
||||
* **Tool:** Bundle **`displayplacer`** (Homebrew utility) inside `resources/bin`.
|
||||
* **Command:** `displayplacer "id:<main> res:1920x1080" "id:<proj> res:1920x1080 origin:(1920,0)"` (Example).
|
||||
|
||||
## 5. Security Guardrails
|
||||
* **IPC Whitelisting:** All `run-cmd` calls are deprecated in favor of specific named handlers (e.g., `set-wallpaper`) to prevent arbitrary command execution.
|
||||
* **Path Validation:** All file operations must be restricted to `~/OSIT` or `~/tmp` directories.
|
||||
91
documentation/history/NATIVE_APP_V3_API_PAYLOAD.md
Normal file
91
documentation/history/NATIVE_APP_V3_API_PAYLOAD.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# Specification: Aether V3 API Device Config Payload
|
||||
|
||||
**Endpoint:** `GET /v3/crud/event_device/{id_random}?view=native_bootstrap`
|
||||
**Goal:** Provide full operational context to an Electron instance with zero local configuration.
|
||||
|
||||
## 1. Response Structure (Draft)
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"identity": {
|
||||
"device_id_random": "GZvFjgIIZQg",
|
||||
"device_code": "macbook_air_scott_idem",
|
||||
"account_id_random": "xFP7AhU8Zlc",
|
||||
"event_id_random": "UFu-gF-rZ-ws",
|
||||
"location_id_random": "PFGP-37-81-80"
|
||||
},
|
||||
"network": {
|
||||
"api_base_url": "https://api.oneskyit.com",
|
||||
"file_server_url": "https://files.oneskyit.com",
|
||||
"heartbeat_interval_ms": 30000
|
||||
},
|
||||
"filesystem": {
|
||||
"cache_path": "[home]/Library/Caches/OSIT/file_cache",
|
||||
"temp_path": "[home]/tmp/OSIT/temp",
|
||||
"use_sharding": true,
|
||||
"verify_on_launch": true
|
||||
},
|
||||
"launcher": {
|
||||
"app_mode": "native",
|
||||
"auto_start_slideshow": true,
|
||||
"prevent_sleep": true,
|
||||
"whitelisted_apps": ["PowerPoint", "Keynote", "Acrobat Reader"]
|
||||
},
|
||||
"ui_prefs": {
|
||||
"theme_name": "cerberus",
|
||||
"theme_mode": "dark",
|
||||
"show_clock": true,
|
||||
"show_admin_tools": false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Key Payload Fields
|
||||
|
||||
### 2.1 Identity & Scoping
|
||||
- `account_id_random`: Automatically scopes all subsequent V3 API calls for the SvelteKit UI.
|
||||
- `location_id_random`: Locks the UI to a specific room/podium.
|
||||
|
||||
### 2.2 Filesystem Strategy
|
||||
- `cache_path`: Uses the `[home]` placeholder. The Electron Main process will resolve this to the local user profile.
|
||||
- `use_sharding`: Tells the Sync Engine to use the `/ab/abcdef...` directory structure.
|
||||
|
||||
### 2.3 Automation Whitelist
|
||||
- To prevent security risks, the `launcher` object defines exactly which applications the native shell is allowed to "Kill" or "Open".
|
||||
|
||||
## 3. Telemetry & Heartbeat (Push Strategy)
|
||||
To support the onsite dashboard (`src/routes/events/.../device`), the Electron app must push its status back to the server.
|
||||
|
||||
### 3.1 Heartbeat Payload (`PATCH /v3/crud/event_device/{id}`)
|
||||
```json
|
||||
{
|
||||
"heartbeat": "2026-01-20T14:30:00Z",
|
||||
"status": "Online",
|
||||
"status_msg": "Presentation: 'Introduction to AE.pptx' (Slide 4/20)",
|
||||
"record_status": "Idle",
|
||||
"info_ip_list": "192.168.1.10, 10.0.0.5",
|
||||
"meta_json": {
|
||||
"cpu_usage": 12,
|
||||
"memory_free_gb": 4.2,
|
||||
"sync_progress": 100,
|
||||
"foreground_app": "PowerPoint",
|
||||
"is_fullscreen": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 4. The "Bootstrap Paradox" Resolution
|
||||
To allow unauthenticated config fetching for new devices:
|
||||
1. **Device API Key:** Each device record in the DB has an `api_secret_key`.
|
||||
2. **Initial Header:** The Electron app sends `x-aether-device-key: <key>` in the bootstrap request.
|
||||
3. **JWT Hand-off:** The response `meta` will contain a short-lived JWT that the app uses to authenticate its first "Real" V3 requests.
|
||||
|
||||
## 5. Database Mapping (V3 Enriched View)
|
||||
The `v_event_device` SQL view must be updated to include:
|
||||
- `account_id_random` (joined from `account`)
|
||||
- `event_id_random` (joined from `event`)
|
||||
- `location_id_random` (joined from `event_location`)
|
||||
- `theme_name` (joined from `site_cfg_json` via `account`)
|
||||
166
documentation/history/NATIVE_APP_V3_REWRITE_PLAN.md
Normal file
166
documentation/history/NATIVE_APP_V3_REWRITE_PLAN.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# Project Plan: Aether Native V3 Rewrite
|
||||
|
||||
**Target:** Electron 33+
|
||||
**Primary Platform:** macOS (Production)
|
||||
**Development Platform:** Arch Linux
|
||||
**API Version:** Aether V3 (REST + JWT)
|
||||
|
||||
## 0. Project Purpose
|
||||
The sole purpose of this Native App is to serve as the **AE Events Launcher**. It provides the SvelteKit frontend with the ability to:
|
||||
- Persistently cache files in the local filesystem.
|
||||
- Execute OS-level shell commands and scripts (e.g., launching presentation software).
|
||||
- Provide a "Zero-Config" experience for onsite event laptops.
|
||||
|
||||
### 0.1 Application Modes
|
||||
The system must support three distinct operational modes:
|
||||
|
||||
| Mode | Refresh Logic | File Handling |
|
||||
| --- | --- | --- |
|
||||
| **Default** | Slower auto-refresh timers. | Standard browser downloads. No local caching. |
|
||||
| **Onsite** | Faster auto-refresh timers. | Downloads files with modified extensions (e.g., .pptxwin). |
|
||||
| **Native** | Fastest auto-refresh timers. | Full background pre-caching. Launching from local temp directory with original names. |
|
||||
|
||||
---
|
||||
|
||||
## 1. Minimalist Configuration Strategy
|
||||
To simplify laptop deployment, we will move away from large local JSON files.
|
||||
|
||||
### 1.1 The "Seed" Config
|
||||
Each laptop will contain a `seed.json`. For development, this is located at `~/seed.json`. In production, it will move to standard OS config paths (e.g., `~/.config/aether/seed.json` or `~/Library/Application Support/Aether/`).
|
||||
|
||||
```json
|
||||
{
|
||||
"event_device_id": "dbgMWS3KEHE",
|
||||
"primary_api_base_url": "https://dev-api.oneskyit.com",
|
||||
"backup_api_base_url": null,
|
||||
"onsite_api_base_url": null,
|
||||
"aether_api_key": "INSdG85ANwsEIru3nUttMw"
|
||||
}
|
||||
```
|
||||
*Note: only `event_device_id` is strictly required for the bootstrapper to start.*
|
||||
|
||||
### 1.2 The Bootstrap Flow
|
||||
1. **Launch:** Electron reads the `seed.json`.
|
||||
2. **Identity:** App calls `GET /v3/crud/event_device/{id}`.
|
||||
3. **Hydrate:** App uses `app_base_url` from the device record to search for the corresponding `site_domain`.
|
||||
4. **Target URL:** Electron constructs the launcher URL:
|
||||
`http://[app_base_url]/events/[event_id]/launcher/[event_location_id]`
|
||||
5. **Inject:** Config and JWT are injected into the SvelteKit frontend via the Preload script.
|
||||
|
||||
### 1.3 Technical Flow: Startup & Background Caching
|
||||
The system utilizes a multi-layered hydration and synchronization strategy to ensure files are available instantly.
|
||||
|
||||
#### Step 1: Zero-Config Initialization (Main Process)
|
||||
- **Seed Discovery:** Main process reads `seed.json`.
|
||||
- **Identity Exchange:** Main process authenticates with the API using the `aether_api_key`.
|
||||
- **Global Injections:** Once hydrated, the Main process provides the SvelteKit frontend with:
|
||||
- `native_device`: Full record from `event_device` table (contains timers).
|
||||
- `aether_api_key`: For authorized background downloads.
|
||||
- `local_file_cache_path`: Root for the permanent hashed cache.
|
||||
- `host_file_temp_path`: Root for the operational launch directory.
|
||||
|
||||
#### Step 2: Session-Driven Caching (Renderer Process)
|
||||
- **View Trigger:** When a user navigates to a session or location, the SvelteKit frontend populates the `event_file_obj_li` store.
|
||||
- **Sync Cycle:** The `LauncherBackgroundSync` component detects the new file list and:
|
||||
1. Extracts all `event_file_id` values.
|
||||
2. Fetches full metadata (hashes) from the local Dexie IndexedDB.
|
||||
3. Asynchronously checks the Native Cache for each hash.
|
||||
- **Background Download:** Missing files are downloaded directly to the hashed cache using the authorized Native API Key.
|
||||
- **Timer Loop:** A background loop runs every `check_event_loop_period` (configurable via API) to ensure the cache stays in sync with server-side changes.
|
||||
|
||||
#### Step 3: Hashed Cache Pattern (Filesystem)
|
||||
To prevent filename collisions and handle versioning, the permanent cache follows the server's structure:
|
||||
- **Root:** `[local_file_cache_path]`
|
||||
- **Subdirectory:** First 2 characters of SHA256 (e.g., `ab/`)
|
||||
- **Filename:** Full SHA256 with `.file` extension (e.g., `abc123...file`)
|
||||
|
||||
#### Step 4: Safe Handover (Launch Sequence)
|
||||
When a user clicks "Open", the system follows a non-destructive handover:
|
||||
1. **Verify:** Confirm hash exists in `local_file_cache_path`.
|
||||
2. **Prepare:** Copy the hashed file to `host_file_temp_path`.
|
||||
3. **Restore:** Rename the copy back to its original filename (e.g., `Presentation.pptx`).
|
||||
4. **Execute:** Trigger OS-level `shell.openPath()` on the temp file.
|
||||
*This ensures the permanent cache remains clean while the third-party app (PowerPoint, etc.) can operate on a file with a familiar name.*
|
||||
|
||||
### 1.3 Technical Flow: Startup & Background Caching
|
||||
The system utilizes a multi-layered hydration and synchronization strategy to ensure files are available instantly.
|
||||
|
||||
#### Step 1: Zero-Config Initialization (Main Process)
|
||||
- **Seed Discovery:** Main process reads `seed.json`.
|
||||
- **Identity Exchange:** Main process authenticates with the API using the `aether_api_key`.
|
||||
- **Global Injections:** Once hydrated, the Main process provides the SvelteKit frontend with:
|
||||
- `native_device`: Full record from `event_device` table (contains timers).
|
||||
- `aether_api_key`: For authorized background downloads.
|
||||
- `local_file_cache_path`: Root for the permanent hashed cache.
|
||||
- `host_file_temp_path`: Root for the operational launch directory.
|
||||
|
||||
#### Step 2: Session-Driven Caching (Renderer Process)
|
||||
- **View Trigger:** When a user navigates to a session or location, the SvelteKit frontend populates the `event_file_obj_li` store.
|
||||
- **Sync Cycle:** The `LauncherBackgroundSync` component detects the new file list and:
|
||||
1. Extracts all `event_file_id` values.
|
||||
2. Fetches full metadata (hashes) from the local Dexie IndexedDB.
|
||||
3. Asynchronously checks the Native Cache for each hash.
|
||||
- **Background Download:** Missing files are downloaded directly to the hashed cache using the authorized Native API Key.
|
||||
- **Timer Loop:** A background loop runs every `check_event_loop_period` (configurable via API) to ensure the cache stays in sync with server-side changes.
|
||||
|
||||
#### Step 3: Hashed Cache Pattern (Filesystem)
|
||||
To prevent filename collisions and handle versioning, the permanent cache follows the server's structure:
|
||||
- **Root:** `[local_file_cache_path]`
|
||||
- **Subdirectory:** First 2 characters of SHA256 (e.g., `ab/`)
|
||||
- **Filename:** Full SHA256 with `.file` extension (e.g., `abc123...file`)
|
||||
|
||||
#### Step 4: Safe Handover (Launch Sequence)
|
||||
When a user clicks "Open", the system follows a non-destructive handover:
|
||||
1. **Verify:** Confirm hash exists in `local_file_cache_path`.
|
||||
2. **Prepare:** Copy the hashed file to `host_file_temp_path`.
|
||||
3. **Restore:** Rename the copy back to its original filename (e.g., `Presentation.pptx`).
|
||||
4. **Execute:** Trigger OS-level `shell.openPath()` on the temp file.
|
||||
*This ensures the permanent cache remains clean while the third-party app (PowerPoint, etc.) can operate on a file with a familiar name.*
|
||||
|
||||
## 2. macOS Hardening (Permissions)
|
||||
...
|
||||
macOS requires explicit user consent for several features. The new app will handle these during the "Splash Screen" phase.
|
||||
|
||||
- **AV Access:** Use `systemPreferences.askForMediaAccess('camera')` and `microphone`.
|
||||
- **Accessibility:** For remote control/automation, check `systemPreferences.isTrustedAccessibilityClient(true)`.
|
||||
- **Screen Recording:** Required for the presentation tracker. We will use a "Check and Prompt" loop.
|
||||
|
||||
## 3. Cross-Platform Handling
|
||||
| Feature | macOS (Production) | Linux/Windows (Dev/Comp) |
|
||||
| --- | --- | --- |
|
||||
| **Process Kill** | `killall -INT "PowerPoint"` | `pkill -f "powerpnt.exe"` |
|
||||
| **Automation** | AppleScript (`osascript`) | Mocked via logs or Shell commands. |
|
||||
| **Paths** | `~/Library/Caches/Aether` | `~/.cache/aether` |
|
||||
| **Window** | Frameless, Transparent support. | Standard decorated window. |
|
||||
|
||||
## 4. Proposed Directory Structure
|
||||
```text
|
||||
aether_app_native_v3/
|
||||
├── src/
|
||||
│ ├── main/
|
||||
│ │ ├── index.ts # Window lifecycle
|
||||
│ │ ├── ipc_handlers.ts # Whitelisted OS commands
|
||||
│ │ ├── macos_perms.ts # Mic/Cam/Accessibility logic
|
||||
│ │ └── api_client.ts # V3 Auth & Config sync
|
||||
│ ├── preload/
|
||||
│ │ └── index.ts # Secure ContextBridge
|
||||
│ └── shared/
|
||||
│ └── types.ts # TS Interfaces for the bridge
|
||||
├── resources/ # Icons and splash screens
|
||||
└── electron-builder.yml # Multi-platform build config
|
||||
```
|
||||
|
||||
## 5. Security Upgrades
|
||||
1. **JWT Storage:** Store the session token in Electron's `safeStorage` (OS-level encryption) rather than simple `localStorage`.
|
||||
2. **Navigation Lock:** Prevent the SvelteKit UI from navigating away from the Aether domain.
|
||||
3. **Command Whitelisting:** Instead of a generic `run_cmd`, implement specific handlers like `native:launch-presentation` which only accepts a file hash.
|
||||
|
||||
## 6. Deployment & Self-Update
|
||||
To support onsite deployment via Syncthing:
|
||||
1. **Version Watcher:** Main process monitors `admin_share/binaries/native_app/version.json`.
|
||||
2. **Atomic Swap:** Use a dedicated `update_helper.sh` to swap the `.app` bundle while the app is closed.
|
||||
3. **Zero-Touch Provisioning:** Auto-copy `seed_[hostname].json` from the sync share if local config is missing.
|
||||
|
||||
## 7. Development Tools (Arch Linux)
|
||||
- Use `fakeroot` and `binutils` to package for macOS on Linux.
|
||||
- Use `Xvfb` for headless testing of Electron windows in CI/CD.
|
||||
74
documentation/history/NATIVE_BRIDGE_INTERFACE_SPEC.md
Normal file
74
documentation/history/NATIVE_BRIDGE_INTERFACE_SPEC.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# Specification: Aether Native V3 Bridge Interface
|
||||
|
||||
**Namespace:** `window.native_app`
|
||||
**Security:** Context Isolated, Sandboxed IPC
|
||||
|
||||
## 1. Device & Identity (`ae_device`)
|
||||
Functions for bootstrapping the app from the `seed.json`.
|
||||
|
||||
| Method | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `getSeed()` | `() => Promise<SeedConfig>` | Returns the local `event_device_id` and `api_base_url`. |
|
||||
| `getDeviceInfo()` | `() => Promise<DeviceInfo>` | Returns OS, Arch, and unique hardware UUID. |
|
||||
| `getPermissions()`| `() => Promise<PermStatus>` | Returns status of Mic, Camera, and Accessibility. |
|
||||
| `requestAccess()` | `(type: string) => Promise<boolean>` | Triggers macOS TCC permission prompts. |
|
||||
|
||||
## 2. Sync Engine (`ae_sync`)
|
||||
The Sync Engine manages the "Cold Cache" (`~/Library/Caches/Aether/`). It handles atomic downloads and hash verification.
|
||||
|
||||
| Method | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `getCacheStatus()` | `(file_hash: string) => Promise<CacheInfo>` | Checks if a file exists and is valid. |
|
||||
| `startSync()` | `(task: SyncRequest) => Promise<void>` | Begins background download of a presentation. |
|
||||
| `cancelSync()` | `(file_hash: string) => Promise<void>` | Aborts an active download. |
|
||||
| `clearCache()` | `() => Promise<void>` | Wipes the cold cache (Maintenance). |
|
||||
|
||||
### Events (Main -> Renderer)
|
||||
- `sync:progress`: `{ hash, percent, speed, bytesLoaded }`
|
||||
- `sync:complete`: `{ hash, success, error }`
|
||||
|
||||
## 3. Launcher (`ae_launcher`)
|
||||
The "Big Red Button" logic. Handles the hand-off to the OS.
|
||||
|
||||
| Method | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `launch()` | `(req: LaunchRequest) => Promise<void>` | 1. Moves file to Temp. 2. Opens with default app. 3. Starts slideshow. |
|
||||
| `killApp()` | `(appName: string) => Promise<void>` | Closes PowerPoint/Keynote/Acrobat gracefully. |
|
||||
| `preventSleep()` | `(enable: boolean) => Promise<void>` | Prevents the laptop from sleeping during a session. |
|
||||
|
||||
## 4. System Control (`ae_sys`)
|
||||
Low-level macOS/Windows/Linux wrappers.
|
||||
|
||||
| Method | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `setVolume()` | `(level: number) => Promise<void>` | Sets system master volume (0-100). |
|
||||
| `checkForUpdates()`| `() => Promise<UpdateStatus>` | Checks the Syncthing share for a newer version. |
|
||||
| `applyUpdate()` | `() => Promise<void>` | Triggers the `update_helper.sh` and exits. |
|
||||
| `execIntent()` | `(intent: string, args: any) => Promise<any>` | Executes a whitelisted command (e.g. `open-logs-folder`). |
|
||||
|
||||
---
|
||||
|
||||
## 5. TypeScript Interface (Draft)
|
||||
|
||||
```typescript
|
||||
export interface AE_Native_Bridge {
|
||||
device: {
|
||||
getSeed: () => Promise<{ device_id: string; api_url: string }>;
|
||||
requestPermissions: () => Promise<void>;
|
||||
};
|
||||
sync: {
|
||||
getStatus: (hash: string) => Promise<{ exists: boolean; verified: boolean }>;
|
||||
queueDownload: (payload: { url: string; hash: string; jwt: string }) => void;
|
||||
};
|
||||
launcher: {
|
||||
launch: (file: { hash: string; name: string; type: 'pptx'|'key'|'pdf' }) => Promise<boolean>;
|
||||
killAll: () => Promise<void>;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## 6. Podium Reliability Protocol
|
||||
To ensure the podium never fails:
|
||||
1. **Pre-Flight Check:** The SvelteKit UI will call `sync.getStatus` for every file in the session as soon as the page loads.
|
||||
2. **Auto-Warmup:** If a file is missing, the UI automatically calls `sync.queueDownload` in the background.
|
||||
3. **Verification:** The `launcher.launch` command will perform a final `sha256` check on the temp file *before* executing `shell.openPath`.
|
||||
37
documentation/history/PROJECT_LAUNCHER_CONFIG_OVERHAUL.md
Normal file
37
documentation/history/PROJECT_LAUNCHER_CONFIG_OVERHAUL.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Project: Launcher Configuration UI/UX Overhaul
|
||||
|
||||
**Status:** IN-PROGRESS
|
||||
**Goal:** Create a standardized, responsive, and categorized configuration interface for the AE Events Launcher.
|
||||
|
||||
## 1. Objectives
|
||||
- **Standardization**: Use consistent naming (`snake_case`), styling, and layout across all config pieces.
|
||||
- **Flexibility**: Support mobile, tablet, and high-res Macbook displays using responsive widths.
|
||||
- **Intelligent Collapsing**: Implement a 3-way state logic: `collapsed`, `auto_collapse`, `pinned`.
|
||||
- **Contextual Fields**: Hide technical/editable fields unless `$ae_loc.edit_mode` is enabled.
|
||||
|
||||
## 2. 3-Way State Logic
|
||||
- **`collapsed`**: Section content is hidden.
|
||||
- **`auto`**: Section is expanded by default, but closes if another "auto" section is opened.
|
||||
- **`pinned`**: Section is expanded and *ignores* the auto-collapse signals from other sections.
|
||||
|
||||
## 3. Component Architecture
|
||||
- **`Launcher_Cfg`**: The main container with Tabbed Navigation (System, Sync, General).
|
||||
- **`Launcher_Cfg_Section`**: Shared wrapper component providing the header, 3-way toggle, and responsive container.
|
||||
- **Sub-components**: Individual sections (Health, Native OS, Timers, etc.) refactored to use the shared wrapper.
|
||||
|
||||
## 4. Feature Matrix & `edit_mode`
|
||||
| Component | Always Visible (Read-Only) | Edit Mode Only (Write/Technical) |
|
||||
| :--- | :--- | :--- |
|
||||
| **Health** | Heartbeat Status, RAM/CPU Gauges | Raw Metadata JSON, Hostname, IPs |
|
||||
| **Native OS** | Folder Open Buttons, Recording Toggle | Manual Terminal CMD, Reset Wallpaper |
|
||||
| **Sync** | Sync Stats (Total/Cached) | Millisecond Timers, Hash Prefix Length |
|
||||
| **Updates** | Current Version, Check Button | Update Path/URL inputs |
|
||||
|
||||
## 5. Progress Tracker
|
||||
- [ ] Migrate `events_loc.launcher` visibility flags to 3-way states.
|
||||
- [ ] Implement `Launcher_Cfg_Section` wrapper component.
|
||||
- [ ] Refactor `Launcher_Cfg_Health`.
|
||||
- [ ] Refactor `Launcher_Cfg_Native_OS`.
|
||||
- [ ] Refactor `Launcher_Cfg_Sync_Timers`.
|
||||
- [ ] Refactor `Launcher_Cfg_Updates`.
|
||||
- [ ] Final UI/UX Polish.
|
||||
62
documentation/history/PROJECT_NATIVE_ELECTRON_INTEGRATION.md
Normal file
62
documentation/history/PROJECT_NATIVE_ELECTRON_INTEGRATION.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Project: Aether Native Electron Integration
|
||||
|
||||
**Status:** Planning / Documentation
|
||||
**Date:** 2026-01-20
|
||||
**Target Platform:** macOS (Production), Arch Linux (Development)
|
||||
|
||||
## 1. Overview
|
||||
This project aims to integrate the modern SvelteKit-based Aether UI into the established Electron native shell (`aether_app_native`). This enables "Native Mode" functionality, such as local file system access, presentation management, and hardware integration, which are restricted in standard web browsers.
|
||||
|
||||
## 2. Component Mapping
|
||||
|
||||
### 2.1 The Shell (`aether_app_native`)
|
||||
- **Main Process:** Handles window creation, lifecycle, and IPC handlers.
|
||||
- **Config:** Uses `ae_native_app_sk_config.json` located in `~/OSIT/native_app/` or `~/.config/OSIT/`.
|
||||
- **Preload Script:** (To be standardized) The bridge that injects functionality into the UI.
|
||||
|
||||
### 2.2 The UI (`aether_app_sveltekit`)
|
||||
- **Framework:** Svelte 5 / SvelteKit.
|
||||
- **Detection:** Uses `+layout.svelte` to check for `window.native_app`.
|
||||
- **Relay:** `src/lib/electron/electron_relay.js` acts as the frontend-side API for the native bridge.
|
||||
|
||||
## 3. Development Strategy (Arch Linux)
|
||||
Since production targets macOS but development happens on Linux:
|
||||
1. **Mocking macOS APIs:** Any calls to `osascript` or macOS-specific shell commands must be wrapped in a platform check.
|
||||
2. **Path Handling:** Use `[home]` placeholders in config files to ensure paths resolve correctly on both `/home/scott/` (Linux) and `/Users/scott/` (Mac).
|
||||
3. **Packaging:** Use `electron-packager` with macOS target flags to verify build integrity on Linux.
|
||||
|
||||
## 4. Implementation Plan
|
||||
|
||||
### Phase 1: Bridge Standardization
|
||||
- Move existing logic from `aether_app_native/app/js/aether_app_native_v4.js` into a formal `preload.js`.
|
||||
- Use `contextBridge.exposeInMainWorld` to provide a secure `native_app` object.
|
||||
- Standardize return types (Promises) for all IPC calls.
|
||||
|
||||
### Phase 2: SvelteKit Build Integration
|
||||
- Transition SvelteKit build to support relative asset paths (required for `file://` protocol).
|
||||
- Update the native app's `index.js` to load the built SvelteKit `index.html` instead of a remote URL.
|
||||
|
||||
### Phase 3: Feature Parity (Events Module)
|
||||
- Port the "Event Launcher" logic to the new bridge.
|
||||
- Implement robust file caching using the `local_file_cache_path` from the native config.
|
||||
- Ensure `kill_processes` works for both `pkill` (Linux) and `killall` (Mac).
|
||||
|
||||
## 5. Security Protocols
|
||||
- **Context Isolation:** Must remain enabled.
|
||||
- **Sandbox:** Enabled where possible.
|
||||
- **IPC Whitelisting:** Only specific, pre-defined commands can be executed via `run_cmd`.
|
||||
|
||||
## 6. Project Documentation Index
|
||||
The following documents provide detailed specifications for the V3 Native App rebuild:
|
||||
|
||||
- **[NATIVE_APP_FUNCTIONAL_SPEC.md](NATIVE_APP_FUNCTIONAL_SPEC.md)**: Detailed audit of legacy features (process management, file caching, automation) to be preserved in the rewrite.
|
||||
- **[NATIVE_APP_V3_REWRITE_PLAN.md](NATIVE_APP_V3_REWRITE_PLAN.md)**: Technical strategy for Electron 33+, including the Zero-Config hydration flow and macOS permission handling.
|
||||
- **[NATIVE_APP_V3_API_PAYLOAD.md](NATIVE_APP_V3_API_PAYLOAD.md)**: JSON schema definitions for the V3 bootstrap payload and the push-telemetry heartbeat logic.
|
||||
- **[NATIVE_BRIDGE_INTERFACE_SPEC.md](NATIVE_BRIDGE_INTERFACE_SPEC.md)**: Definition of the `window.native_app` IPC contract and the "Podium Reliability Protocol."
|
||||
- **[NATIVE_APP_DEPLOYMENT_PLAN.md](NATIVE_APP_DEPLOYMENT_PLAN.md)**: Strategy for binary distribution and self-updates using the existing Syncthing `admin_share` infrastructure.
|
||||
- **[NATIVE_APP_AUTOMATION_SCRIPTS.md](NATIVE_APP_AUTOMATION_SCRIPTS.md)**: Specifications for AppleScript intents, recording lifecycle (Aperture), and Arch Linux mocking logic.
|
||||
|
||||
## 7. References
|
||||
- Existing Native Docs: `aether_app_native/Aether App Native setup documentation.txt`
|
||||
- Electron Integration: `src/lib/electron/README.md`
|
||||
- Svelte 5 Runes: `documentation/ARCHITECTURE.md`
|
||||
@@ -1,48 +1,34 @@
|
||||
# Electron Integration (Events - Launcher)
|
||||
# Aether Native Integration (Electron)
|
||||
|
||||
This document describes the Electron integration for the Aether Svelte application, which provides native capabilities for the Events module, specifically for the **Event Launcher** functionality.
|
||||
This directory contains the SvelteKit-side bridge for the Aether Native App (Electron). It provides the UI with access to OS-level capabilities required for the **Event Launcher**.
|
||||
|
||||
## Overview
|
||||
## 📖 Technical Manual
|
||||
For detailed architecture, lifecycle, and IPC specifications, see:
|
||||
👉 **[AE_EVENTS_LAUNCHER_NATIVE_INTEGRATION.md](../../../documentation/AE_EVENTS_LAUNCHER_NATIVE_INTEGRATION.md)**
|
||||
|
||||
The Event Launcher is not a standalone module but rather a set of native functions and UI elements integrated into the Events module. It is designed to be used in a hybrid event scenario where a local application (the Electron app) is used to control presentations and other event-related content on a local machine.
|
||||
## 📂 File Manifest
|
||||
|
||||
## Architecture
|
||||
| File | Role | Description |
|
||||
| :--- | :--- | :--- |
|
||||
| `electron_relay.ts` | **Messenger** | The TypeScript API used by Svelte components. Standardizes calls to `snake_case`. |
|
||||
| `electron_native.js` | **Bridge Logic** | (Internal) Logic often used in the Preload or Renderer to facilitate IPC. |
|
||||
|
||||
The Electron integration is composed of three main parts:
|
||||
## 🚀 Usage Example
|
||||
|
||||
1. **Electron Main Process (`electron.js`):** The main process of the Electron application. It is responsible for creating the browser window and handling communication with the renderer process.
|
||||
2. **Native Functions (`src/lib/electron/electron_native.js`):** A set of functions that are executed in the Electron main process and have access to the operating system's native APIs. These functions provide the core functionality for the Event Launcher, such as opening files, running commands, and managing processes.
|
||||
3. **Relay/Bridge (`src/lib/electron/electron_relay.js`):** A bridge that exposes the native functions to the Svelte application running in the renderer process. This allows the Svelte components to call the native functions.
|
||||
```typescript
|
||||
import { is_native, launch_from_cache } from '$lib/electron/electron_relay';
|
||||
|
||||
## Key Functionality
|
||||
if (is_native) {
|
||||
await launch_from_cache({
|
||||
cache_root: $ae_loc.native_device.local_file_cache_path,
|
||||
hash: file_obj.hash_sha256,
|
||||
temp_root: $ae_loc.native_device.host_file_temp_path,
|
||||
filename: file_obj.filename
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
The native functions in `electron_native.js` provide the following key functionalities for the Event Launcher:
|
||||
|
||||
- **File Caching:**
|
||||
- `check_hash_file_cache()`: Checks if a file with a specific hash exists in the local cache.
|
||||
- `download_hash_file_to_cache()`: Downloads a file from the API and stores it in the local cache.
|
||||
- **File Operations:**
|
||||
- `open_hash_file_to_temp()`: Copies a file from the cache to a temporary directory and opens it.
|
||||
- `open_local_file()`: Opens a local file.
|
||||
- **Process Management:**
|
||||
- `kill_processes()`: Kills processes by name or ID. This is used to close presentation applications after a presentation is finished.
|
||||
- **Command Execution:**
|
||||
- `run_osascript()`: Runs an AppleScript command (macOS only).
|
||||
- `run_cmd()`: Runs a shell command.
|
||||
- **Device Information:**
|
||||
- `get_device_info()`: Gets information about the device, which can be used for logging and debugging.
|
||||
|
||||
## UI Integration
|
||||
|
||||
The Event Launcher functionality is integrated into the Events module's UI as follows:
|
||||
|
||||
- **Launcher Links:** In the list of event sessions, there are "launcher" links that, when clicked, trigger the native launcher functionality.
|
||||
- **Configuration:** The visibility and behavior of the launcher links are controlled by the `mod_pres_mgmt_json` configuration in the `Event` object. This allows for fine-grained control over the launcher functionality on a per-event basis.
|
||||
|
||||
## How it Works
|
||||
|
||||
1. The Svelte application, running in the Electron renderer process, displays a list of event sessions.
|
||||
2. For each session, a "launcher" link is displayed if the configuration allows it.
|
||||
3. When the user clicks on a launcher link, a function in `electron_relay.js` is called.
|
||||
4. The relay function then calls the corresponding native function in `electron_native.js` via the Electron context bridge.
|
||||
5. The native function performs the requested action, such as downloading a file, opening a presentation, or running a command.
|
||||
## 🔐 Security Standards
|
||||
- **Namespace:** All native functions are exposed via `window.aetherNative`.
|
||||
- **Whitelisting:** Only specific intents (e.g., `launch_presentation`) are allowed.
|
||||
- **Path Isolation:** All file operations are restricted to `[home]` and `[tmp]` via placeholder resolution.
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// [DEPRECATED] 2026-02-10: This file is a legacy reference from Aether V2/V4.
|
||||
// Do NOT import this into the SvelteKit frontend.
|
||||
// The active native logic resides in the 'aether_app_native_electron' repository.
|
||||
|
||||
// @ts-nocheck
|
||||
'use strict';
|
||||
/* This should only contain functions that can not be pulled easily into Svelte */
|
||||
|
||||
@@ -23,9 +23,9 @@ export async function get_device_info() {
|
||||
}
|
||||
|
||||
// 2. File & Cache Management
|
||||
export async function check_hash_file_cache({ cache_root, hash, hash_prefix_length = 2 }: any) {
|
||||
export async function check_hash_file_cache({ cache_root, hash, hash_prefix_length = 2, verify_hash = false }: any) {
|
||||
if (!native) return false;
|
||||
return await native.check_cache({ cache_root, hash, hash_prefix_length });
|
||||
return await native.check_cache({ cache_root, hash, hash_prefix_length, verify_hash });
|
||||
}
|
||||
|
||||
export async function download_to_cache({ url, cache_root, hash, api_key, account_id, hash_prefix_length = 2 }: any) {
|
||||
|
||||
@@ -9,6 +9,18 @@
|
||||
let { on_expand }: Props = $props();
|
||||
|
||||
// Derived Usage Percentage for Visuals
|
||||
let cpu_load_pct = $derived.by(() => {
|
||||
const meta = $ae_loc.native_device?.meta_json;
|
||||
// loadavg is [1m, 5m, 15m] - use 1m load
|
||||
if (!meta?.loadavg || !Array.isArray(meta.loadavg)) return 15;
|
||||
|
||||
// Load average is usually 0.0 to N (cores). Normalize to 0-100 based on cores if available.
|
||||
const load = meta.loadavg[0];
|
||||
const cores = (meta.cpus || []).length || 1;
|
||||
const pct = Math.round((load / cores) * 100);
|
||||
return Math.min(Math.max(pct, 5), 100); // Clamp 5-100
|
||||
});
|
||||
|
||||
let ram_usage_pct = $derived.by(() => {
|
||||
const meta = $ae_loc.native_device?.meta_json;
|
||||
if (!meta?.total_mem || !meta?.free_mem) return 0;
|
||||
@@ -51,14 +63,14 @@
|
||||
>CPU Architecture: {$ae_loc.native_device?.meta_json
|
||||
?.arch || '...'}</span
|
||||
>
|
||||
<span>Load: Healthy</span>
|
||||
<span>Load: {cpu_load_pct}%</span>
|
||||
</div>
|
||||
<div
|
||||
class="w-full h-1.5 bg-surface-500/20 rounded-full overflow-hidden"
|
||||
>
|
||||
<div
|
||||
class="h-full bg-primary-500 transition-all duration-1000"
|
||||
style="width: 15%"
|
||||
class="h-full transition-all duration-1000 {get_usage_color(cpu_load_pct)}"
|
||||
style="width: {cpu_load_pct}%"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -150,7 +150,8 @@
|
||||
const exists = await native.check_hash_file_cache({
|
||||
cache_root,
|
||||
hash: file_obj.hash_sha256,
|
||||
hash_prefix_length: prefix_len
|
||||
hash_prefix_length: prefix_len,
|
||||
verify_hash: true // Hardened check: Perform full SHA-256 verify if file exists
|
||||
});
|
||||
|
||||
if (exists) {
|
||||
@@ -238,7 +239,10 @@
|
||||
|
||||
if (info) {
|
||||
update_payload.info_hostname = info.hostname;
|
||||
update_payload.info_ip_list = info.ip_addresses.join(', ');
|
||||
// Safely handle IP list (bridge may return ip_addresses or networkInterfaces)
|
||||
const ips = info.ip_addresses || [];
|
||||
update_payload.info_ip_list = Array.isArray(ips) ? ips.join(', ') : 'Unknown';
|
||||
|
||||
update_payload.meta_json = {
|
||||
platform: info.platform,
|
||||
release: info.release,
|
||||
|
||||
Reference in New Issue
Block a user