feat(native): harden launcher bridge and implement presentation-aware handover
- Upgraded LauncherBackgroundSync to force-hydrate OS metadata (home/tmp) on mount. - Hardened electron_relay.ts with robust placeholder resolution and global regex. - Restored safe handover by making native.launch_from_cache presentation-aware. - Integrated heartbeat and sync status into the formal Launcher Config UI. - Added comprehensive technical documentation for the 2026 native architecture.
This commit is contained in:
@@ -43,6 +43,12 @@
|
||||
if (info) {
|
||||
$ae_loc.home_directory = info.home_directory;
|
||||
$ae_loc.tmp_directory = info.tmp_directory;
|
||||
|
||||
// Also sync into native_device for redundancy
|
||||
if (!$ae_loc.native_device) $ae_loc.native_device = {};
|
||||
$ae_loc.native_device.home_directory = info.home_directory;
|
||||
$ae_loc.native_device.tmp_directory = info.tmp_directory;
|
||||
|
||||
if (log_lvl) console.log('Sync: Native OS metadata hydrated.', { home: info.home_directory });
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
@@ -140,85 +140,295 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Sync Loop Timers Section -->
|
||||
<section
|
||||
class:preset-outlined-warning-300-700={$events_loc.launcher.show_section__sync_timers}
|
||||
class="sync_timers w-full preset-outlined-surface-300-700 transition-all mb-2"
|
||||
>
|
||||
<h3 class="text-center mb-2 text-sm font-semibold w-full">
|
||||
<button
|
||||
onclick={() => {
|
||||
$events_loc.launcher.show_section__sync_timers =
|
||||
!$events_loc.launcher.show_section__sync_timers;
|
||||
}}
|
||||
class="btn btn-sm w-full justify-between"
|
||||
>
|
||||
<span>
|
||||
{#if $events_loc.launcher.show_section__sync_timers}
|
||||
<span class="fas fa-chevron-down"></span>
|
||||
{:else}
|
||||
<span class="fas fa-chevron-right"></span>
|
||||
{/if}
|
||||
Native Sync Timers
|
||||
</span>
|
||||
</button>
|
||||
</h3>
|
||||
<!-- Sync Loop Timers Section -->
|
||||
|
||||
<section
|
||||
|
||||
class:preset-outlined-warning-300-700={$events_loc.launcher.show_section__sync_timers}
|
||||
|
||||
class="sync_timers w-full preset-outlined-surface-300-700 transition-all mb-2"
|
||||
|
||||
<div
|
||||
class="flex flex-col gap-1 items-center justify-start w-full p-2"
|
||||
class:hidden={!$events_loc.launcher.show_section__sync_timers}
|
||||
>
|
||||
{#if $ae_loc.native_device}
|
||||
<label class="flex flex-row gap-1 items-center justify-start text-xs w-full">
|
||||
<span class="grow opacity-70">Event Sync (ms):</span>
|
||||
<input
|
||||
type="number"
|
||||
bind:value={$ae_loc.native_device.check_event_loop_period}
|
||||
class="input input-sm w-24 text-right preset-tonal-surface"
|
||||
/>
|
||||
</label>
|
||||
<label class="flex flex-row gap-1 items-center justify-start text-xs w-full">
|
||||
<span class="grow opacity-70">Device Heartbeat (ms):</span>
|
||||
<input
|
||||
type="number"
|
||||
bind:value={$ae_loc.native_device.check_event_device_loop_period}
|
||||
class="input input-sm w-24 text-right preset-tonal-surface"
|
||||
/>
|
||||
</label>
|
||||
<label class="flex flex-row gap-1 items-center justify-start text-xs w-full">
|
||||
<span class="grow opacity-70">Location Refresh (ms):</span>
|
||||
<input
|
||||
type="number"
|
||||
bind:value={$ae_loc.native_device.check_event_location_loop_period}
|
||||
class="input input-sm w-24 text-right preset-tonal-surface"
|
||||
/>
|
||||
</label>
|
||||
<label class="flex flex-row gap-1 items-center justify-start text-xs w-full">
|
||||
<span class="grow opacity-70">Session Scan (ms):</span>
|
||||
<input
|
||||
type="number"
|
||||
bind:value={$ae_loc.native_device.check_event_session_loop_period}
|
||||
class="input input-sm w-24 text-right preset-tonal-surface"
|
||||
/>
|
||||
</label>
|
||||
<label class="flex flex-row gap-1 items-center justify-start text-xs w-full border-t border-surface-500/20 pt-1 mt-1">
|
||||
<span class="grow font-semibold text-primary-500">Hash Prefix Length:</span>
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
max="8"
|
||||
bind:value={$ae_loc.native_device.hash_prefix_length}
|
||||
class="input input-sm w-24 text-right preset-tonal-surface font-bold"
|
||||
/>
|
||||
</label>
|
||||
<div class="text-[9px] text-gray-500 mt-1 italic w-full text-right">
|
||||
* Prefix: {($ae_loc.native_device.hash_prefix_length || 2)} chars. Reload required.
|
||||
|
||||
<h3 class="text-center mb-2 text-sm font-semibold w-full">
|
||||
|
||||
<button
|
||||
|
||||
onclick={() => {
|
||||
|
||||
$events_loc.launcher.show_section__sync_timers =
|
||||
|
||||
!$events_loc.launcher.show_section__sync_timers;
|
||||
|
||||
}}
|
||||
|
||||
class="btn btn-sm w-full justify-between"
|
||||
|
||||
>
|
||||
|
||||
<span>
|
||||
|
||||
{#if $events_loc.launcher.show_section__sync_timers}
|
||||
|
||||
<span class="fas fa-chevron-down"></span>
|
||||
|
||||
{:else}
|
||||
|
||||
<span class="fas fa-chevron-right"></span>
|
||||
|
||||
{/if}
|
||||
|
||||
Native Sync Timers
|
||||
|
||||
</span>
|
||||
|
||||
</button>
|
||||
|
||||
</h3>
|
||||
|
||||
|
||||
|
||||
<div
|
||||
|
||||
class="flex flex-col gap-1 items-center justify-start w-full p-2"
|
||||
|
||||
class:hidden={!$events_loc.launcher.show_section__sync_timers}
|
||||
|
||||
>
|
||||
|
||||
{#if $ae_loc.native_device}
|
||||
|
||||
<label class="flex flex-row gap-1 items-center justify-start text-xs w-full">
|
||||
|
||||
<span class="grow opacity-70">Event Sync (ms):</span>
|
||||
|
||||
<input
|
||||
|
||||
type="number"
|
||||
|
||||
bind:value={$ae_loc.native_device.check_event_loop_period}
|
||||
|
||||
class="input input-sm w-24 text-right preset-tonal-surface"
|
||||
|
||||
/>
|
||||
|
||||
</label>
|
||||
|
||||
<label class="flex flex-row gap-1 items-center justify-start text-xs w-full">
|
||||
|
||||
<span class="grow opacity-70">Device Heartbeat (ms):</span>
|
||||
|
||||
<input
|
||||
|
||||
type="number"
|
||||
|
||||
bind:value={$ae_loc.native_device.check_event_device_loop_period}
|
||||
|
||||
class="input input-sm w-24 text-right preset-tonal-surface"
|
||||
|
||||
/>
|
||||
|
||||
</label>
|
||||
|
||||
<label class="flex flex-row gap-1 items-center justify-start text-xs w-full">
|
||||
|
||||
<span class="grow opacity-70">Location Refresh (ms):</span>
|
||||
|
||||
<input
|
||||
|
||||
type="number"
|
||||
|
||||
bind:value={$ae_loc.native_device.check_event_location_loop_period}
|
||||
|
||||
class="input input-sm w-24 text-right preset-tonal-surface"
|
||||
|
||||
/>
|
||||
|
||||
</label>
|
||||
|
||||
<label class="flex flex-row gap-1 items-center justify-start text-xs w-full">
|
||||
|
||||
<span class="grow opacity-70">Session Scan (ms):</span>
|
||||
|
||||
<input
|
||||
|
||||
type="number"
|
||||
|
||||
bind:value={$ae_loc.native_device.check_event_session_loop_period}
|
||||
|
||||
class="input input-sm w-24 text-right preset-tonal-surface"
|
||||
|
||||
/>
|
||||
|
||||
</label>
|
||||
|
||||
<label class="flex flex-row gap-1 items-center justify-start text-xs w-full border-t border-surface-500/20 pt-1 mt-1">
|
||||
|
||||
<span class="grow font-semibold text-primary-500">Hash Prefix Length:</span>
|
||||
|
||||
<input
|
||||
|
||||
type="number"
|
||||
|
||||
min="1"
|
||||
|
||||
max="8"
|
||||
|
||||
bind:value={$ae_loc.native_device.hash_prefix_length}
|
||||
|
||||
class="input input-sm w-24 text-right preset-tonal-surface font-bold"
|
||||
|
||||
/>
|
||||
|
||||
</label>
|
||||
|
||||
<div class="text-[9px] text-gray-500 mt-1 italic w-full text-right">
|
||||
|
||||
* Prefix: {($ae_loc.native_device.hash_prefix_length || 2)} chars. Reload required.
|
||||
|
||||
</div>
|
||||
|
||||
{:else}
|
||||
|
||||
<div class="text-xs text-error-500 italic">No device config hydrated.</div>
|
||||
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<!-- System Health Section -->
|
||||
|
||||
<section
|
||||
|
||||
class:preset-outlined-primary-300-700={$events_loc.launcher.show_section__health}
|
||||
|
||||
class="system_health w-full preset-outlined-surface-300-700 transition-all mb-2"
|
||||
|
||||
>
|
||||
|
||||
<h3 class="text-center mb-2 text-sm font-semibold w-full">
|
||||
|
||||
<button
|
||||
|
||||
onclick={() => {
|
||||
|
||||
$events_loc.launcher.show_section__health =
|
||||
|
||||
!$events_loc.launcher.show_section__health;
|
||||
|
||||
}}
|
||||
|
||||
class="btn btn-sm w-full justify-between"
|
||||
|
||||
>
|
||||
|
||||
<span>
|
||||
|
||||
{#if $events_loc.launcher.show_section__health}
|
||||
|
||||
<span class="fas fa-chevron-down"></span>
|
||||
|
||||
{:else}
|
||||
|
||||
<span class="fas fa-chevron-right"></span>
|
||||
|
||||
{/if}
|
||||
|
||||
System & Sync Health
|
||||
|
||||
</span>
|
||||
|
||||
<span class="flex gap-1 items-center">
|
||||
|
||||
{#if $events_sess.launcher.heartbeat_info.status === 'success'}
|
||||
|
||||
<span class="w-2 h-2 rounded-full bg-success-500 animate-pulse"></span>
|
||||
|
||||
{:else}
|
||||
|
||||
<span class="w-2 h-2 rounded-full bg-error-500"></span>
|
||||
|
||||
{/if}
|
||||
|
||||
</span>
|
||||
|
||||
</button>
|
||||
|
||||
</h3>
|
||||
|
||||
|
||||
|
||||
<div
|
||||
|
||||
class="flex flex-col gap-2 p-2 items-center justify-start w-full"
|
||||
|
||||
class:hidden={!$events_loc.launcher.show_section__health}
|
||||
|
||||
>
|
||||
|
||||
<!-- Heartbeat Info -->
|
||||
|
||||
<div class="grid grid-cols-2 gap-x-2 gap-y-1 w-full text-[10px] bg-surface-500/5 p-2 rounded border border-surface-500/10">
|
||||
|
||||
<span class="opacity-70">Last Heartbeat:</span>
|
||||
|
||||
<span class="text-right font-mono {$events_sess.launcher.heartbeat_info.status === 'success' ? 'text-success-500' : 'text-error-500'}">
|
||||
|
||||
{$events_sess.launcher.heartbeat_info.last_timestamp || 'Pending...'}
|
||||
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
<span class="opacity-70">Room Sync Status:</span>
|
||||
|
||||
<span class="text-right font-mono">
|
||||
|
||||
{$events_sess.launcher.sync_stats.cached} / {$events_sess.launcher.sync_stats.total} Files
|
||||
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
{#if $events_sess.launcher.sync_stats.currently_syncing}
|
||||
|
||||
<span class="col-span-2 text-center text-primary-500 animate-pulse mt-1 border-t border-primary-500/20 pt-1">
|
||||
|
||||
<span class="fas fa-sync fa-spin mr-1"></span>
|
||||
|
||||
Syncing: {$events_sess.launcher.sync_stats.currently_syncing}
|
||||
|
||||
</span>
|
||||
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
{:else}
|
||||
<div class="text-xs text-error-500 italic">No device config hydrated.</div>
|
||||
{/if}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<!-- Basic Native Info -->
|
||||
|
||||
{#if $ae_loc.is_native && $ae_loc.native_device}
|
||||
|
||||
<div class="w-full mt-1 flex flex-col gap-1 text-[10px] opacity-80 pl-1 italic">
|
||||
|
||||
<div>Host: {$ae_loc.native_device.info_hostname || 'Loading...'}</div>
|
||||
|
||||
<div class="truncate">IPs: {$ae_loc.native_device.info_ip_list || '...'}</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
{/if}
|
||||
|
||||
<!-- <hr class="w-full my-2 border-1 border-gray-200 dark:border-gray-800 " /> -->
|
||||
|
||||
Reference in New Issue
Block a user