diff --git a/fedac/native/ac-os b/fedac/native/ac-os index 2d9e2e7bd2..a879862d67 100755 --- a/fedac/native/ac-os +++ b/fedac/native/ac-os @@ -977,8 +977,10 @@ pull_ota() { fi log "SHA256 verified: ${ACTUAL_HASH:0:16}..." - # Override VMLINUZ so flash_usb uses the downloaded kernel + # Override VMLINUZ and build name so flash_usb uses the downloaded kernel + # (not the locally-generated name from scripts/build-name.sh) VMLINUZ="${PULLED_KERNEL}" + export AC_BUILD_NAME="${BUILD_NAME}" log "Ready to flash: ${BUILD_NAME}" } diff --git a/fedac/native/pieces/prompt.mjs b/fedac/native/pieces/prompt.mjs index 35a03300eb..433d129f01 100644 --- a/fedac/native/pieces/prompt.mjs +++ b/fedac/native/pieces/prompt.mjs @@ -333,6 +333,27 @@ function execute(cmd, system) { return; } + // Set default boot piece + if (baseWord === "boot") { + if (spaceIdx > 0) { + const pieceName = cmd.slice(spaceIdx + 1).trim(); + if (pieceName) { + system?.saveConfig?.("piece", pieceName); + message = "boot → " + pieceName; + } else { + message = "usage: boot "; + } + } else { + // Show current boot piece + const raw = system?.readFile?.("/mnt/config.json"); + let cur = "notepat"; + if (raw) try { cur = JSON.parse(raw).piece || cur; } catch (_) {} + message = "boot piece: " + cur; + } + messageFrame = 0; + return; + } + // Dark/light mode override if (lower === "dark") { __theme._forceDark = true; diff --git a/fedac/native/src/ac-native.c b/fedac/native/src/ac-native.c index 89c3e1c662..4661c158f5 100644 --- a/fedac/native/src/ac-native.c +++ b/fedac/native/src/ac-native.c @@ -2074,6 +2074,27 @@ int main(int argc, char *argv[]) { } } + // Check for previous crash (written by signal handler) + { + FILE *cf = fopen("/mnt/crash.json", "r"); + if (cf) { + char cbuf[512] = {0}; + fread(cbuf, 1, sizeof(cbuf) - 1, cf); + fclose(cf); + char sig[32] = {0}; + parse_config_string(cbuf, "\"signal\"", sig, sizeof(sig)); + if (sig[0]) { + rt->crash_active = 1; + rt->crash_frame = 0; + snprintf(rt->crash_msg, sizeof(rt->crash_msg), + "previous crash: %s", sig); + ac_log("[ac-native] Previous crash detected: %s\n", sig); + } + // Remove crash file so we don't re-show it + remove("/mnt/crash.json"); + } + } + // Override piece_path from config.json boot piece (pieces bundled at /pieces/) // Resolve aliases: "claude" and "cc" → terminal (with param "claude") if (strcmp(rt->piece, "claude") == 0 || strcmp(rt->piece, "cc") == 0) { @@ -2844,9 +2865,13 @@ int main(int argc, char *argv[]) { } JS_FreeValue(rt->ctx, global); - // Reset counters + // Reset counters and crash state rt->paint_count = 0; rt->sim_count = 0; + rt->crash_active = 0; + rt->crash_count = 0; + rt->crash_frame = 0; + rt->crash_msg[0] = 0; // NOTE: "claude" and "cc" aliases removed — claude.mjs handles auth curtain // before jumping to terminal:claude itself. @@ -2884,6 +2909,26 @@ int main(int argc, char *argv[]) { clock_gettime(CLOCK_MONOTONIC, &_pf_paint1); + // Crash overlay — red bar with error message when JS throws + if (rt->crash_active) { + rt->crash_frame++; + int bar_h = 24; + int flash = (rt->crash_frame < 30) ? (rt->crash_frame % 6 < 3 ? 255 : 180) : 200; + graph_ink(&graph, (ACColor){flash, 0, 0, 240}); + graph_box(&graph, 0, 0, screen->width, bar_h, 1); + graph_ink(&graph, (ACColor){255, 255, 255, 255}); + font_draw_matrix(&graph, "CRASH", 4, 4, 2); + // Truncate message to fit screen + char crash_display[128]; + snprintf(crash_display, sizeof(crash_display), "%s", rt->crash_msg); + graph_ink(&graph, (ACColor){255, 200, 200, 255}); + font_draw_matrix(&graph, crash_display, 60, 8, 1); + // Auto-dismiss after 5 seconds (300 frames at 60fps) + if (rt->crash_frame > 300) { + rt->crash_active = 0; + } + } + // Software cursor on its own overlay buffer (unaffected by KidLisp effects) if (cursor_fb && input && (input->pointer_x || input->pointer_y)) { fb_clear(cursor_fb, 0x00000000); // transparent diff --git a/fedac/native/src/js-bindings.c b/fedac/native/src/js-bindings.c index b5c49b8f2d..a69c830191 100644 --- a/fedac/native/src/js-bindings.c +++ b/fedac/native/src/js-bindings.c @@ -5316,6 +5316,14 @@ void js_call_boot(ACRuntime *rt) { } } +// Helper: record a JS crash for the overlay +static void js_record_crash(ACRuntime *rt, const char *fn_name, const char *msg) { + rt->crash_active = 1; + rt->crash_count++; + rt->crash_frame = 0; + snprintf(rt->crash_msg, sizeof(rt->crash_msg), "%s(): %s", fn_name, msg ? msg : "unknown"); +} + void js_call_paint(ACRuntime *rt) { if (!JS_IsFunction(rt->ctx, rt->paint_fn)) return; current_rt = rt; @@ -5328,6 +5336,7 @@ void js_call_paint(ACRuntime *rt) { JSValue stack = JS_GetPropertyStr(rt->ctx, exc, "stack"); const char *stack_str = JS_ToCString(rt->ctx, stack); fprintf(stderr, "[js] paint() error: %s\n%s\n", str, stack_str ? stack_str : ""); + js_record_crash(rt, "paint", str); if (stack_str) JS_FreeCString(rt->ctx, stack_str); JS_FreeValue(rt->ctx, stack); JS_FreeCString(rt->ctx, str); @@ -5387,6 +5396,7 @@ void js_call_act(ACRuntime *rt) { const char *stack_str = JS_ToCString(rt->ctx, stack); fprintf(stderr, "[js] act() error: %s\n%s\n", str, stack_str ? stack_str : ""); ac_log("[js] act() error: %s\n%s\n", str, stack_str ? stack_str : ""); + js_record_crash(rt, "act", str); if (stack_str) JS_FreeCString(rt->ctx, stack_str); JS_FreeValue(rt->ctx, stack); JS_FreeCString(rt->ctx, str); @@ -5425,6 +5435,7 @@ void js_call_sim(ACRuntime *rt) { JSValue stack = JS_GetPropertyStr(rt->ctx, exc, "stack"); const char *stack_str = JS_ToCString(rt->ctx, stack); fprintf(stderr, "[js] sim() error: %s\n%s\n", str, stack_str ? stack_str : ""); + js_record_crash(rt, "sim", str); if (stack_str) JS_FreeCString(rt->ctx, stack_str); JS_FreeValue(rt->ctx, stack); JS_FreeCString(rt->ctx, str); diff --git a/fedac/native/src/js-bindings.h b/fedac/native/src/js-bindings.h index 171bc539b0..d98f9ce6cd 100644 --- a/fedac/native/src/js-bindings.h +++ b/fedac/native/src/js-bindings.h @@ -100,6 +100,13 @@ typedef struct { // User config (read from /mnt/config.json on EFI partition) char handle[64]; // e.g. "jeffrey" (without @) char piece[64]; // default piece name, e.g. "notepat" + + // JS crash overlay — set when paint/act/sim throws an unhandled exception + int crash_active; // 1 = crash bar visible + int crash_count; // total JS exceptions since piece load + char crash_msg[256]; // last error message + char crash_piece[64]; // piece that crashed + int crash_frame; // frame counter for animation } ACRuntime; // Initialize QuickJS and register all AC API bindings