Append &hideMenu=true to the circuitjs.html iframe src used by
renderCircuitEmbeds so lesson content embeds render clean without
the toolbar and menu bar. The embed path in CircuitEditor.svelte
is untouched, so the editor keeps its full toolbar.
Verified:
- Bundle contains embed URL (with hideMenu=true) and editor URL
(without) as separate variants
- svelte-check: 0 errors
- /lesson/rangkaian_dasar returns 200 on the running stack
- add @types/node for hooks.server process/env types
- fix katex auto-render import path (contrib/auto-render)
- declare global Web Bluetooth API types in ble-deployer
- guard simApi null in CircuitEditor autosave interval
- default-type imports for CodeEditor/CircuitEditor
- make lesson slug getter non-nullable
- add expected_flowchart to LessonContent type
- key lesson workspace by slug; drop phantom onReset prop
- guard CodeTab render when lesson data is null
- Export siswa terpilih/seluruh + progress ke CSV round-trip (token tidak
pernah diekspor; teacher tidak ikut; urutan deterministik)
- Import preview all-or-nothing: siswa existing di-restore (nama+progress,
token lama dipertahankan), siswa baru dibuat dari student_id kosong +
token; conflict tidak menyebut raw token/digest
- Bulk delete multi-seleksi dengan validasi ketat (teacher terlindungi,
zero-delete bila ada ID bermasalah)
- fix(import): deteksi delimiter berbasis schema — menerima titik koma
(;) maupun koma (,), ekspor tetap ';' + BOM; header tab/campuran ditolak
dengan pesan jelas (regresi: file Excel/Sheets kini bisa diimpor)
- refactor: progress_status.py — kontrak status legacy tunggal dipakai
storage PG, export, dan import; report siswa hanya role student
- UI /progress: dialog import/export + bulk delete, selection store,
respon import tanpa raw token; APP_VERSION 22 -> 26
- ops: ORIGIN env var di podman-compose.yml
- docs: README section 9 (workflow round-trip + delimiter) dan
docs/11-database-migration (kelola siswa via round-trip CSV)
- test: parser round-trip (45), repositories, route management (24,
PostgreSQL), frontend 91, fixtures CSV valid/invalid
- FileTree menerima prop language ('c' | 'python', default 'c')
- hanya merender file dengan ekstensi yang cocok (.c atau .py)
- tombol + buat file dengan ekstensi bahasa aktif
- header menampilkan nama bahasa (C/Python), bukan generik 'File'
- runActiveFile() memanggil consumeStdin() (antrean + draft, digabung, dikosongkan)
- pesan info jika stdin kosong: program yang membaca input akan mendapat EOF
- hapus pembacaan consoleInput langsung yang menyebabkan baris hilang
- playground route: velxio/flowchart/circuit/code tabs with auto-save
- FileTree + ConsolePanel for C/Python code tab
- compileCode() forwards stdin through routes/compile.py to compiler_worker
- compiler_worker run_c_code/run_python_code accept stdin, pass via subprocess.run(input=)
- known issue: Console UI does not queue stdin properly → fix in next cycle
Update velxio submodule pointer to the new integration branch that contains:
- EmbedBridge.ts PostMessage bridge for iframe integration
- DeployProgress UI for compile/transfer/flash status
- BASE_URL customization for /velxio/ path
- Backend auth, project, and database endpoints for Elemes LMS
- SerialMonitor BLE/Hardware toggle support
Restructure quiz flow into QuizSession primitive + atomic quiz state in
LessonManager, and extract QuizQuestionView for split-view display.
Tab-safety fix: add lesson-tabs.ts with pickDefaultTab(), getAvailableTabs()
mirroring the exact {#if} conditions in +page.svelte, and ensureActiveTab()
safety-net that falls back to pickDefaultTab() when the desired tab is not
rendered. A reactive $effect in lesson/[slug]/+page.svelte validates
activeTab against lesson data on every change, preventing the "tab quiz
kosong" (empty workspace) regression for quiz-only lessons and phantom-tab
state after data changes.
Files:
- lib/services/lesson-tabs.ts (+test): pure helpers, 18 tests pass
- lesson/[slug]/+page.svelte: ensureActiveTab reactive guard + QuizQuestionView
- lesson/[slug]/lesson.svelte.ts: atomic startQuiz, getExitStatus, idempotent
submit on navigate/exit
- lib/services/quiz-session.ts (+test), lib/types/quiz.ts, QuizTab.svelte
(mgr-driven), QuizQuestionView.svelte, lesson.css
- services/lesson_service.py, services/tests/test_lesson_service_quiz.py
(test_lesson_service_quiz.py), requirements.txt (+pytest)
- docs/07-quiz-authoring.md
- version.ts APP_VERSION 21 -> 22 (forces SW update for the fix)
- examples/content/dasar/quiz_test.md synced to live content root
- Generalize _read_md_cached() for generic file caching
- Add find_sub_home_for_lesson() and get_sub_home_data() helpers
- Add /api/bab/<folder> endpoint
- Detect sub-home in api_lesson for nav context
- Skip sub-home.md in find_lesson_file() and _parse_lesson_links()
- Add title to bab frontend page data
- Update generate_tokens.py & content_parser.py to skip sub-home.md
Consolidates all dev work including the orphaned-read race fix:
- Single read-pump feeds a FIFO ByteStreamBuffer; readExact/drain/
serial monitor consume from buffer (no orphaned reader.read()).
- DTR timing 50ms+100ms, port reuse, pre-sync drain.
- Vitest + ByteStreamBuffer unit tests (7 pass).
- APP_VERSION 18 for SW cache-bust.
Verified on CH340 (1a86:7523): INSYNC 0x14 + STK_OK 0x10
received cleanly, deploy succeeds.
WARN-1: pumpRunning now reset to false when the pump loop exits via
{done} or error, so future startPump() isn't a silent no-op.
WARN-3: readExact clears rxBuffer on timeout to avoid stale bytes
leaking into the next non-retried STK500 command.
readExact and drainStray now consume the FIFO buffer fed by the pump
instead of calling reader.read() directly. No orphaned reader.read()
promise can swallow optiboot INSYNC/OK replies anymore. This is the
core fix for "get_sync failed after N attempts".
Single pump loop becomes the only reader.read() caller, feeding
rxBuffer. Serial monitor + readExact/drain will consume from the
buffer (next tasks). Build passes.
Test runner setup (vitest) plus deadline-based FIFO buffer that
becomes the single sink for serial bytes. readExact keeps
partial bytes buffered on timeout — the exact case that dropped
optiboot INSYNC/OK replies under the orphaned-reader race.
7 unit tests pass.