Fix 1 (stale error_detail):
open_file_error_detail is now cleared at the start of every mode's
branch (native, onsite, default) alongside open_file_clicked=true.
Previously it was cleared mid-way through the native flow (Step 1),
so a stale error from a previous failed run could flash briefly.
Fix 2 (stuck 'Opening...' during post_script sleep):
After the Step 4 open call returns (run_cmd or open_local_file_v2),
update the status message immediately to 'App opened — running setup...'
so the button doesn't appear frozen for the full post_delay_ms wait.
Fix 3 (safety valve for hanging native calls):
A 60s setTimeout is registered at the start of the native branch.
If any native IPC call hangs indefinitely and the existing per-path
reset timeouts never fire, this force-resets open_file_clicked after
60s. All normal paths complete within ~8s so this only triggers on
true hangs. ERR_NETWORK_CHANGED cannot re-enter the download path
because the open_file_clicked guard blocks re-entry.
shell.openPath always resolves on the Electron side, but if the Svelte
renderer navigates before the IPC reply arrives, the promise rejects
with 'reply was never sent'. The file is already open at that point.
Catch the rejection and treat it as success on both call sites (Step 4
primary path and Step 7 fallback). This eliminates the unhandled
promise error without masking real failures.
URL files: event_file.filename = 'https://...' is now a first-class
file type in the launcher.
- is_url derived rune detects https/http filename prefix
- URL branch in handle_open_file() runs before cache/native branches
(no download, no temp copy, no hash)
- Offline guard: warns and blocks click if navigator.onLine is false;
online/offline listeners registered only for URL rows (no-op on files)
- Native mode: opens via native.open_external({ url, app: 'chrome' })
with silent fallback to default browser
- Browser mode: window.open() with noopener
- display_mode default: 'mirror' (URLs typically just need the screen
mirrored, not extended presenter view)
- Button badge shows Link2 icon + WifiOff warning when offline
- Button text uses event_file.title as label (falls back to URL)
- Test mode popup: skips Steps 1-2 (N/A), shows open_external call
DEFAULT_LAUNCH_PROFILES: add 'url' key (display_mode: 'mirror')
Electron TODO: added set_display_layout / displayplacer per-device
config task to aether_app_native_electron/documentation/TODO_AGENTS.md
with full contract details and resources
The sleep step was running unconditionally, meaning files that open
with the 'default' catch-all profile (zip, unknown ext, etc.) would
wait 2 seconds for no reason — there's no AppleScript to prepare for.
Gate the sleep inside the post_script check so it only delays when
there's actually automation to run after app launch.
Also update the test mode popup to show '0ms — skipped (no post_script)'
and display post_delay_ms as '(default: 2000ms)' when unset.
Enables testing the LaunchProfile system from any device (no Mac/Electron
needed). When active, the Open button simulates the full native flow and
shows a debug popup with everything that WOULD be sent to Electron.
- ae_events_stores__launcher_defaults.ts: add native_test_mode boolean
(persisted, default false) to LauncherLocState and launcher_loc_defaults.
- launcher_cfg_app_modes.svelte: add Native Test Mode checkbox toggle in
the Advanced Toggles (Edit Mode Only) section with active-state warning.
- launcher_file_cont.svelte:
- Add test_mode_popup_open/test_mode_popup_data state vars.
- Add branch 0 in handle_open_file(): when native_test_mode + app_mode=native,
skip all Electron calls; resolve the real LaunchProfile, build a data
snapshot, open the debug popup.
- Debug popup shows: file info, simulated temp path, cache/copy pass,
resolved LaunchProfile fields, set_display_layout call, open command
(run_cmd or open_local_file_v2 fallback), sleep delay, post-script
(AppleScript or shell: prefix). Click backdrop or Close to dismiss.
- Add ae_launcher__default_launch_profiles.ts with LaunchProfile interface,
DEFAULT_LAUNCH_PROFILES constant, and resolve_launch_profile() helper.
Covers pptx/ppt/key/odp/pdf, all VLC media formats, Windows/Parallels
variants (pptxwin/pptwin/odpwin/pdfwin), and a catch-all 'default'.
- Replace get_launch_script_template() with get_launch_profile() in
launcher_file_cont.svelte. Override priority: device API config >
local persistent config > built-in defaults > 'default' catch-all.
- Rewrite handle_open_file() native branch with 9-step profile-driven flow:
copy_from_cache_to_temp → resolve profile → set_display_layout (silent fail)
→ open (run_cmd or OS default) → sleep(post_delay_ms) → run post_script
→ fallback to OS default on open failure → surface status/error detail.
- Add open_file_error_detail state var; show error pre block in status
alert for native error state, show fallback note for fallback state.
- Add display override toggle button in event_file_meta (visible when
trusted_access + is_native): cycles null → extend → mirror → null,
PATCHes event_file.cfg_json.display_override via V3 CRUD.
- TODO__Agents: expand CMSC Charlotte launcher task into done/remaining
sections; enumerate Svelte-side migration items (default templates,
composable open flow, error fallback, slide control config, kill list
config, Launcher config UI editor, end-to-end Mac test gate)
- PROJECT__AE_Events_Launcher_Native_integration: update Last Updated to 2026-05-11
- Bootstrap lifecycle now reflects actual two-step flow (event_device → site_domain/search).
Removes stale /v3/data_store/code reference and corrects the JWT claim — auth is
x-aether-api-key + x-account-id throughout; no JWT is issued or used.
- check_hash_file_cache corrected to check_cache (actual method name in preload bridge).
- cleanup_tmp_files removed from relay list — stale .tmp cleanup is handled inline inside
download_to_cache, not via a standalone IPC channel.
- Known Issue section replaced: all AppleScript handlers are now hardened (launch_presentation
converted to temp-.scpt approach in the companion Electron commit ca4fddd).
- Markdown lint fixes: blank lines around tables, table pipe spacing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Drop the _random key copy loop from _process_generic_props in both files —
V3 API returns {obj_type}_id directly as the random string ID, so copying
from {obj_type}_id_random is a no-op. Simplify .id assignment to use
baseIdKey only. Remove commented-out _random entries from properties_to_save.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix download button to use hosted_file_id instead of id (which resolved
to event_file_id via _process_generic_props, hitting the wrong endpoint)
- Fix Dexie file table query in event_file_obj_tbl_wrapper to use _id
fields (the indexed ones) instead of _id_random variants
- Remove _random fields from properties_to_save in event, event_session
- Drop _id_random fallbacks from launcher device ID resolution and
background sync heartbeat
- Clean up dead comments and old FA anchor in post edit component
- Update TODO__Agents.md: BGH section removed, CMSC/Axonius shows added,
download button fix marked complete
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Hide AI tools panel when entry is not in edit mode
- Clicking AI button when a summary already exists opens it directly
instead of triggering a new API call; Re-run still available in modal
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add hover titles to all save buttons
- Match warning color scheme across floating, inline, and header save buttons
- Fix floating save button visibility (Tailwind v4 hidden/md:inline-flex conflict)
- Hide floating save when no unsaved changes using {#if}
- Hide Config button when not in admin edit mode
- Remove the mobile/backup explicit Save button from header (redundant)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The auto-save $effect wrapped has_unsaved_changes in untrack(), which meant it
was never tracked when save_status was 'saved' (JS short-circuit in the else-if
branch). After every successful save the effect lost its reactive dependency on
user edits and never re-fired until something else changed save_status first.
Fix: track tmp_entry_obj.content and tmp_entry_obj.name directly (void reads)
so the effect re-runs on every keystroke and the debounce timer resets correctly
(fires 2 s after the last change, not the first). has_unsaved_changes is also
tracked directly so the status indicator resets cleanly when changes are cleared.
All side-effects remain in untrack() to prevent reactive loops.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Entry: 50 chars for entry name, 30 for journal name
Journal: 60 chars for journal name
Appends ellipsis (…) when truncated.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Wire indentWithTab into keymap (Tab=indent, Shift-Tab=dedent, 4 spaces)
- Set indentUnit to 4 spaces
- Wrap lineNumbers() in a Compartment for live toggle without editor rebuild
- Add Hash toolbar button to toggle line numbers; respects show_line_numbers prop as initial value
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Chromium's native audio player shadow DOM collapses when max-height is
applied to the <audio> element — audio plays but controls are invisible.
Remove the inline style (carried over from video context) and use w-full
max-w-lg instead.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Expose archive_content.code in edit form (trusted + edit_mode only)
- Add code to properties_to_save so it persists on every API load/save
- Add code field + index to Archive_Content Dexie interface (schema v2)
- Minor: center "Add" button rows in archive and content list components
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
XHR upload % in the button + disabled states now communicate
upload/save progress; the top Saving.../Finished saving block
is no longer needed (and its out:fade was broken on re-entry).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The outer bordered div was always in the DOM; only the label and input
inside were hidden during upload, leaving a visible empty dashed box.
Apply the same hidden guard to the container div.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pass track_progress: true to post_object so the XHR path fires live
percent_completed events, making the upload % display functional.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New track_progress param (default false) switches to XMLHttpRequest for
form_data uploads so xhr.upload.onprogress can fire percent_completed
postMessages into api_upload_kv. fetch() has no upload progress events.
No retry loop on XHR path — silently retrying a large video upload is
bad UX; caller re-submits on failure.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Restrict upload to one file (each archive content item maps to one file);
contextual toggle button text (Switch to Select / Switch to Upload);
swap FontAwesome upload icon for Lucide.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Guard task_id effect against resetting mid-upload; add prevent_default
wrapper; add 20-min timeout for large video/audio files; add null result
guard before result[0]; fix for= attribute to use variable; console.error
on failure; remove dead params/comments.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
archive_obj.archive_id_random → .archive_id in load function and post-create
assignment; remove archive_id_random and hosted_file_id_random from editable
fields list — V3 returns the random string as the primary ID field directly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ArchiveContentForm interface + factory for controlled input bindings
- obj_changed bindable prop wired to Cancel button visibility in parent page
- Split Save button: edit mode disables when clean, create mode always enabled
- Post-upload/select/remove syncs orig snapshot so file ops do not dirty the form
- Fix archive_content_id_random / archive_id_random → V3 field names in edit component
- Add missing file_extension field to ae_ArchiveContent type
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Svelte 4 store nested property mutations don't call set()/update(), so
$effect on $idaa_slct never fired after upload. Replaced store property
binds with local $state variables that Svelte 5 proxies track natively.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>