@@ -305,18 +305,25 @@ platform detection at the top of the script.
305305
306306=== Required Format
307307
308+ Every `.desktop` file's primary `Exec=` line MUST go through `keepopen.sh`
309+ (see §Fallback Ladder below). This ensures that a user who double-clicks
310+ a desktop icon always lands somewhere useful — even when every upstream
311+ hook is broken — instead of seeing a terminal flash on-and-off with no
312+ feedback.
313+
308314[source,ini]
309315----
310316[Desktop Entry]
311317Type=Application
312318Name=Application Name
313- Exec=/path/to/launcher. sh --auto
314- Terminal=false # Critical for web/GUI apps
319+ Exec=/var/mnt/eclipse/repos/.desktop-tools/keepopen. sh "AppName" "/path/to/repo" "GUI_CMD" "TUI_CMD" "/tmp/app.log"
320+ Terminal=true # keepopen needs a terminal for its loud banners and shell fallback
315321Icon=/path/to/icon.png
316322Categories=Category;
317323StartupNotify=true
318324
319- # Actions for additional functionality
325+ # Actions for additional functionality — these can bypass keepopen because
326+ # they are invoked from an already-open context menu; no fallback needed.
320327Actions=stop;status;
321328
322329[Desktop Action stop]
@@ -328,19 +335,112 @@ Name=Server Status
328335Exec=/path/to/launcher.sh --status
329336----
330337
331- === Forbidden Patterns
338+ NOTE: The old "pure-GUI apps use `Terminal=false`" advice is superseded by
339+ `keepopen.sh`. A pure-GUI `Exec=` still flashes a terminal for ~1 second
340+ when the GUI launch succeeds, but in exchange every failure mode becomes
341+ *visible* instead of silent. The tradeoff favours debuggability.
342+
343+ == Fallback Ladder (`keepopen.sh`)
344+
345+ === Why this exists
346+
347+ Desktop launchers fail in three predictable ways, and users must be able
348+ to see which one happened:
349+
350+ 1. The GUI binary is missing, broken, or the URL is unreachable.
351+ 2. The TUI/CLI fallback is also broken.
352+ 3. The repo itself is missing or unbuildable.
353+
354+ Without a visible fallback ladder, all three failures look identical to
355+ the user: a terminal flashes for half a second, then the desktop is quiet.
356+ `keepopen.sh` turns each failure into a LOUD, labelled banner and, when
357+ all else fails, drops the user into an interactive shell at the repo
358+ root so they can fix whatever is broken.
359+
360+ === Canonical location
361+
362+ The single source of truth is:
363+
364+ developer-ecosystem/standards/launcher/keepopen.sh
365+
366+ For desktop files to reference a stable absolute path, a symlink is
367+ deployed at:
368+
369+ /var/mnt/eclipse/repos/.desktop-tools/keepopen.sh → ↑
370+
371+ `launch-scaffolder` copies the same script into its baked-in standards
372+ so regenerated launchers stay in sync.
373+
374+ === Calling convention
375+
376+ [source,bash]
377+ ----
378+ keepopen.sh APP_NAME REPO_DIR "GUI_CMD" "TUI_CMD" [LOG_FILE]
379+ ----
380+
381+ * `APP_NAME`: short label; used in banners and the `[keepopen:${APP_NAME}]` prefix.
382+ * `REPO_DIR`: absolute path to the app's repository root — where the final shell fallback lands.
383+ * `GUI_CMD`: shell command for the primary GUI path. Pass `""` to skip this stage.
384+ * `TUI_CMD`: shell command for the TUI fallback. Pass `""` to skip this stage.
385+ * `LOG_FILE` (optional): log file path, shown in banners so the user knows where to look.
386+
387+ Each `*_CMD` is executed via `bash -c`, so pipelines and shell quoting work.
388+ For launchers that daemonise their payload and exit 0 immediately, chain
389+ a `tail -f LOG` after the launcher so the terminal stays open:
390+
391+ [source,bash]
392+ ----
393+ "aerie-launcher.sh --auto && tail -f /tmp/aerie.log"
394+ ----
395+
396+ === The three stages
397+
398+ [cols="1,3,3"]
399+ |===
400+ | Stage | On success | On failure
401+
402+ | **1. GUI**
403+ | `keepopen` exits 0 silently.
404+ | Yellow banner titled `FALLBACK 1/2 — GUI FAILED (exit N)` listing the
405+ GUI cmd, log file, and a human-readable hint. Proceeds to stage 2.
406+
407+ | **2. TUI**
408+ | `keepopen` exits 0 silently.
409+ | Red banner titled `FALLBACK 2/2 — TUI ALSO FAILED (exit N)` listing
410+ both commands and the repo path. Proceeds to stage 3.
411+
412+ | **3. Shell at repo root**
413+ | `exec bash -l` inside `REPO_DIR` — user can investigate, run `just --list`, etc.
414+ | If `REPO_DIR` does not exist, a red warning prints and the shell starts in `$PWD`.
415+ |===
416+
417+ The banners are intentionally loud and ugly. Visibility beats aesthetics —
418+ the point is that a broken launcher should *look* broken, not silently fail.
419+
420+ === Forbidden patterns
421+
422+ * Do **not** use `read -rp 'Press Enter to close...'` as a terminal-keepalive.
423+ It loses the user's context. Use `keepopen.sh`'s shell fallback instead,
424+ which drops them into the repo root where they can actually debug.
425+ * Do **not** wrap `Exec=` in `konsole --hold` — the `--hold` terminal has
426+ no working directory and no login-shell environment, so the user can't
427+ easily switch to investigating.
428+ * Do **not** skip `keepopen.sh` for "simple" apps. Simple apps break too,
429+ and the symptom is identical to the flashy ones without the wrapper.
430+
431+ === Forbidden (legacy) patterns
332432
333433[source,ini]
334434----
335- # BAD: Terminal wrapping
435+ # BAD: konsole wrapping (pre-keepopen era)
336436Exec=konsole -e /path/to/launcher.sh --auto
337437Terminal=true
338438
339- # BAD: Complex wrapping
439+ # BAD: konsole --hold with no cwd / no login shell
340440Exec=konsole --background-mode --hold --qwindowtitle Title -e wrapper.sh launcher.sh
341441
342- # BAD: No error handling
343- Exec=launcher.sh
442+ # BAD: launcher without keepopen — flashes a terminal on failure with no feedback
443+ Exec=launcher.sh --auto
344444----
345445
346446== Troubleshooting Guide
@@ -418,8 +518,12 @@ APP_NAME="AppName"
418518
419519== Compliance Checklist
420520
421- [ ] Remove all terminal wrapping from desktop files
422- [ ] Set `Terminal=false` for GUI/web applications
521+ [ ] Primary `Exec=` goes through `keepopen.sh` with non-empty GUI and/or TUI commands
522+ [ ] `GUI_CMD` for daemon-style launchers chains `&& tail -f LOG` so the terminal stays open on success
523+ [ ] `REPO_DIR` argument points to a real, existing repository root
524+ [ ] `LOG_FILE` argument is passed when the launcher writes one, so banners can cite it
525+ [ ] Remove all pre-keepopen konsole wrapping from desktop files
526+ [ ] `Terminal=true` on the primary Exec (keepopen needs a terminal for banners + shell fallback)
423527[ ] Implement `nohup` for background processes
424528[ ] Add PID file tracking and cleanup
425529[ ] Implement `wait_for_server()` with reasonable timeout
0 commit comments