Desktop: dev loop (desktop-dev.sh, auto-restart on source edits), SHONAR_DEV engine --reload, build stamp in window title, detail screen reloads report rewrites + surfaces fetch errors
This commit is contained in:
parent
67b1eb65c7
commit
31e03262fd
3 changed files with 77 additions and 4 deletions
|
|
@ -328,7 +328,12 @@ class DesktopState(private val appDir: File = defaultAppDir()) {
|
|||
}
|
||||
stopEngine()
|
||||
apiProc = spawn(backend, File(venv, "uvicorn").absolutePath,
|
||||
listOf("shonar.main:app", "--port", "8000"), env)
|
||||
listOf("shonar.main:app", "--port", "8000") +
|
||||
// Dev mode: engine hot-reloads on backend source edits.
|
||||
(if (System.getenv("SHONAR_DEV") == "1")
|
||||
listOf("--reload", "--reload-dir", "shonar")
|
||||
else emptyList()),
|
||||
env)
|
||||
var up = false
|
||||
var waited = 0.0
|
||||
while (waited < 120.0) {
|
||||
|
|
@ -746,9 +751,23 @@ class DesktopState(private val appDir: File = defaultAppDir()) {
|
|||
// If the file is mid-pipeline (pump running, or reprocess started
|
||||
// elsewhere), show live stage/progress instead of a stale report.
|
||||
while (true) {
|
||||
val jobs = runCatching { parseJobs(provider.fetchJobs(remoteId)) }
|
||||
.getOrNull().orEmpty()
|
||||
val fetched = runCatching { parseJobs(provider.fetchJobs(remoteId)) }
|
||||
if (fetched.isFailure && d.jobs.isEmpty()) {
|
||||
// Don't fail silently: a dead session used to render as
|
||||
// an idle screen, indistinguishable from "never started".
|
||||
d.error = "Couldn't read job status from the engine: " +
|
||||
(fetched.exceptionOrNull()?.message ?: "unknown error")
|
||||
} else if (fetched.isSuccess) {
|
||||
d.error = null
|
||||
}
|
||||
val jobs = fetched.getOrNull().orEmpty()
|
||||
if (_detail.value?.file != file) break
|
||||
// Pick up report rewrites made by the pump/completion paths
|
||||
// while this screen sits open (they write the file, not us).
|
||||
if (d.transcript == null) {
|
||||
val fresh = runCatching { reportFile(file).readText() }.getOrNull()
|
||||
if (fresh != null && fresh != d.reportText) d.reportText = fresh
|
||||
}
|
||||
d.jobs = jobs
|
||||
jobLabel(jobs)?.let { d.busy = it } ?: run { d.busy = null }
|
||||
_detail.value = d.copy()
|
||||
|
|
|
|||
|
|
@ -37,7 +37,17 @@ fun main() = application {
|
|||
var zoom by remember { mutableStateOf(1f) }
|
||||
Window(
|
||||
onCloseRequest = ::exitApplication,
|
||||
title = "SHONAR Desktop",
|
||||
title = "SHONAR Desktop" + run {
|
||||
// Build stamp so "which window is this?" is answerable at a glance.
|
||||
val jar = java.io.File(
|
||||
System.getProperty("java.class.path", "").split(":")
|
||||
.firstOrNull { it.endsWith(".jar") } ?: "")
|
||||
if (jar.exists()) {
|
||||
val fmt = java.time.format.DateTimeFormatter.ofPattern("HH:mm")
|
||||
.withZone(java.time.ZoneId.systemDefault())
|
||||
" · build " + fmt.format(java.time.Instant.ofEpochMilli(jar.lastModified()))
|
||||
} else ""
|
||||
},
|
||||
state = rememberWindowState(width = 1100.dp, height = 800.dp),
|
||||
) {
|
||||
val baseDensity = LocalDensity.current
|
||||
|
|
|
|||
44
desktop/desktop-dev.sh
Executable file
44
desktop/desktop-dev.sh
Executable file
|
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/env bash
|
||||
# SHONAR desktop dev loop: runs the app and auto-restarts it when any
|
||||
# Kotlin/Gradle source changes (inotifywait). Engine runs in dev mode
|
||||
# (SHONAR_DEV=1 -> uvicorn --reload), so backend edits apply live too.
|
||||
#
|
||||
# Stop with Ctrl-C (or pkill -f desktop-dev.sh).
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
export SHONAR_DEV=1
|
||||
export DISPLAY="${DISPLAY:-:0}"
|
||||
|
||||
WATCH_DIRS=(
|
||||
"app/src/main/kotlin"
|
||||
"../../android/app/src/main/java/com/shonar"
|
||||
)
|
||||
FLAG="$(pwd)/.dev-restart-flag"
|
||||
|
||||
pkill -f "com.shonar.desktop.MainKt" 2>/dev/null || true
|
||||
rm -f "$FLAG"
|
||||
sleep 1
|
||||
|
||||
(
|
||||
while inotifywait -qq -e close_write,move \
|
||||
--include '\.kt$|\.kts$' "${WATCH_DIRS[@]}" 2>/dev/null; do
|
||||
echo "[dev] source change -> restarting app…"
|
||||
touch "$FLAG"
|
||||
pkill -f "com.shonar.desktop.MainKt" 2>/dev/null || true
|
||||
done
|
||||
) &
|
||||
WATCHER=$!
|
||||
trap 'kill $WATCHER 2>/dev/null || true; rm -f "$FLAG"' EXIT
|
||||
|
||||
while true; do
|
||||
rm -f "$FLAG"
|
||||
./gradlew run --offline
|
||||
if [ -f "$FLAG" ]; then
|
||||
continue # killed by a source edit: rebuild now
|
||||
fi
|
||||
rm -f "$FLAG"
|
||||
# App closed cleanly or build failed — wait for the next edit.
|
||||
# (Build failure: gradlew prints the error; the loop idles until you fix it.)
|
||||
inotifywait -qq -e close_write,move --include '\.kt$|\.kts$' "${WATCH_DIRS[@]}"
|
||||
done
|
||||
Loading…
Add table
Add a link
Reference in a new issue