• src/syncterm/Wren.adoc src/syncterm/scripts/console.wren syncterm.wren

    From Deuc¨@VERT to Git commit to main/sbbs/master on Tuesday, April 28, 2026 04:20:01
    https://gitlab.synchro.net/main/sbbs/-/commit/e2a8307110280f8f5bef30e7
    Modified Files:
    src/syncterm/Wren.adoc src/syncterm/scripts/console.wren syncterm.wren src/syncterm/wren_bind.c
    Log Message:
    SyncTERM: Wren console Ä /mods command + REPL.modules

    Adds REPL.modules, a foreign static getter that walks
    modules->entries directly to enumerate every module currently
    loaded into the VM (including core, every embedded module, every
    user script, and anything pulled in via import). Skips empty
    slots and tombstones (key is UNDEFINED_VAL for both); non-string
    keys are filtered defensively.

    console.wren grows a /mods command that calls REPL.modules,
    sorts via a byte-wise stringLT_ helper, and prints the result.
    Wren's String doesn't implement <, so List.sort()'s default
    {|a, b| a < b} comparator aborts on string lists; the helper does
    ASCII-safe byte comparison and is reusable for other string sorts
    that come up later.

    Wren.adoc refreshed: documents the new Hook.dispatch_ contract
    ("hooks must run synchronously; wrap parking work in
    Fiber.new {...}.call()"), corrects the Modal Input section's
    description of nextEvent-from-a-hook (now detected and reported,
    not silently hung), describes REPL.eval's actual statement-keyword pre-classifier (was still describing the old try-expression-first
    flow), and adds REPL.modules + /mods + /? + /q to the command
    tables.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Deuc¨@VERT to Git commit to main/sbbs/master on Tuesday, April 28, 2026 04:20:01
    https://gitlab.synchro.net/main/sbbs/-/commit/e2528de46b9d76fdceb6ea0d
    Modified Files:
    src/syncterm/Wren.adoc src/syncterm/scripts/console.wren syncterm.wren src/syncterm/term.c wren_bind.c wren_host.c wren_host.h wren_host_internal.h
    Log Message:
    SyncTERM: Wren API audit + Directory rework + doc completeness pass

    Three threads, committed together because they overlap in the same files:

    API shape audit
    ---------------
    * Input.next, Input.poll, Input.nextEvent Ä converted from getters
    to methods (Input.next(), Input.poll(), Input.nextEvent()). The
    rule "getters are for things that feel like variable access, not
    things that feel like they're doing something" Ä these block,
    poll, or park a fiber, so they're actions.
    * Directory.list Ä converted from method to a foreign Map getter.
    The directory's contents read like a property; indexing
    `Cache.list["RIP"]` returns the File or Directory handle for that
    name (or null), which composes naturally for tree traversal:
    `Cache.list["RIP"].list["icons.dat"]`.

    Directory rework
    ----------------
    * Directory.create(name) Ä now actually creates the file (was a
    no-op File-object factory). Uses C11 exclusive-create
    (fopen("wbx")) for race-free atomic creation. Returns null on
    any failure (file exists, invalid name, path too long, OS reject).
    * Directory.createDir(name) Ä added. Mirrors create() for
    subdirectories via MKDIR (which is naturally exclusive).
    * Directory.delete(name) Ä added. Parent-acts-on-child shape:
    removes the named entry (regular file or empty directory only;
    refuses symlinks, devices, FIFOs). Returns bool.
    * File.delete() Ä removed. The instance-method-that-zombies-its-
    receiver shape was awkward; Directory.delete(name) covers the
    case from the parent.
    * Directory.list now returns Files AND Directories Ä the C
    implementation always built a Map keyed by name with File values
    for regular files; this extends it to also emit Directory values
    for subdirectories, matching the documented intent.

    Live-handle registry
    --------------------
    A successful Directory.delete shouldn't leave outstanding handles
    to the removed entry quietly operating on stale paths. Each
    wren_file and wren_directory now self-registers on a doubly-linked
    list rooted on wren_host_state. Helpers fs_register_*,
    fs_unregister_*, fs_kill_*, fs_invalidate_subtree.

    Two layers of staleness protection on every File / Directory
    operation:

    1. dead flag Ä set by fs_invalidate_subtree when a parent's
    delete removes the entry (or marks an ancestor). file_check /
    dir_check (called at the top of every method) abort the fiber
    on dead.
    2. Per-call fexist() / isdir() Ä catches deletions that bypassed
    Directory.delete (other process, the user, another script).
    On miss: fs_kill_*(handle) (mark dead + unregister) + throw.

    Open-file exemption: a File between open() and close() skips
    the fexist() check (its fd is authoritative Ä Unix lets reads/
    writes continue past unlink, and Windows refuses to delete
    open files at all). fs_invalidate_subtree skips fp != NULL
    entries on the same logic. fn_File_close re-runs fexist()
    after fclose; if the path is gone, the handle becomes dead.

    Wren.adoc completeness pass
    ---------------------------
    Stale "see ciolib.h" references replaced with full reference
    content:
    * Codepage Ä every entry described, _b suffix explained.
    * Key Ä full grouped tables (ASCII / cursor / modified Insert-
    Delete / modified arrows / function keys with all four modifier
    columns / synthetic markers).
    * Font Ä full 46-row table including the 1-31 unnamed-in-Wren
    slots that are still reachable numerically; "thin"/"swiss"
    font-style annotations explained.
    * Screen.supports, Screen.videoFlags Ä every flag described.
    * ConnType, Emulation, BBSListType, ScreenMode, AddressFamily,
    MusicMode, RipVersion, Parity, FlowControl, LogLevel, ExtAttr,
    LastColumnFlag, LogMode, StatusDisplay Ä all converted from
    bare name lists to descriptive tables.

    Corrections to wrong descriptions:
    * sxScroll Ä SIXEL scroll mode (not "smooth scroll" / DECSCLM).
    * blinkAltChars Ä repurposes attribute bit 7 to select the alt
    character set (not "animate alt-char-set on blink interval").
    * StatusDisplay Ä VT320 DECSSDT semantics (host-writable status
    line, not "verbose status showing connected host").

    Worked example replaced. The "auto-respond to a prompt" example
    was using onInput + manual line buffering with a logic bug that
    only checked for prompts on LF (so "Logon: " Ä which has no
    trailing LF Ä never matched). Replaced with a Hook.onMatch
    two-liner; added a smaller per-byte BEL-counter example that
    demonstrates onInput correctly without the broken pattern.

    Anchors added: [[hook-events]], [[modal-input]], [[codepage]], [[filename-policy]], [[directory-handle-staleness]] so the
    existing <<...>> cross-refs resolve.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net