• .claude/skills/javascript/SKILL.md

    From Rob Swindell (on Windows 11)@VERT to Git commit to main/sbbs/master on Sun May 24 15:52:35 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/f27b2e8270997abb2ada9598
    Modified Files:
    .claude/skills/javascript/SKILL.md
    Log Message:
    .claude/skills/javascript: document constant namespaces and terminal-capability checks

    Two new subsections after load()/require(): one breaks down where
    constants come from (host-injected globals like LOG_*/INVALID_SOCKET, class-static properties like FileBase.DETAIL/SORT and CryptContext.ALGO_*,
    and JS-library files under exec/load/ that need load()/require()); the
    other distinguishes console.term_supports(USER_UTF8) (live connection capability) from user.settings & USER_UTF8 (stored preference) and
    explains when to use which.

    Triggered by C-vs-JS namespace confusion (bare UTF8 in sbbsdefs.h vs
    USER_UTF8 in exec/load/userdefs.js, same (1<<29) value) hit during
    LLM-guru language-output work.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Windows 11)@VERT to Git commit to main/sbbs/master on Fri May 29 15:31:38 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/30e601ade1688cc1a957bb92
    Modified Files:
    .claude/skills/javascript/SKILL.md
    Log Message:
    skills/javascript: note the chat_llm LLM-Guru module family

    Add the chat_llm engine, chat_llm_irc adapter, llm_tools, and llm_index to
    the stock exec/*.js inventory, plus wiki links to the new module/config/
    howto pages now published on wiki.synchro.net.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Fri May 29 23:59:56 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/d4613a65265ef3fe028b36a7
    Modified Files:
    .claude/skills/javascript/SKILL.md
    Log Message:
    javascript skill: how to syntax-check/test a side-effecting module

    Document the guard-and-load() idiom: gate a module's load-time entry
    point (server loop, socket connect, greeting) behind a NO_MAIN-style
    sentinel so it can be load()ed under jsexec for syntax-checking and unit-testing its helpers without running the side effect. Cites the
    stock CHAT_LLM_NO_STANDALONE / CHAT_LLM_IRC_NO_MAIN guards. Notes that syncjslint.js is a style linter (jslint) with false positives on valid SpiderMonkey regex, not a reliable syntax gate.

    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Fri May 29 23:59:57 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/a923481d60d196ea331efafd
    Modified Files:
    .claude/skills/javascript/SKILL.md
    Log Message:
    skills/javascript: document INI trailing-comment type-dependency

    Synchronet .ini value parsing strips a trailing "; comment" only for single-token value types (boolean via isTrue, enum via parseEnum, and integer/float/datetime via the numeric parse). STRING values keep the
    whole post-'=' text (truncsp only), so an inline comment after a
    string-valued key becomes part of the value -- the trap that corrupts URL/path/name settings. File.iniGetObject() reads every value as a raw
    string and thus never strips inline comments.

    Add a "Reading INI files (and the trailing-comment trap)" section with
    the per-type table, the rationale (single-token values have no
    delimiter ambiguity; strings do), and the history behind the
    single-token support (cceb1fbb8 isTrue after FozzTexx's sexpots.ini
    report; 7346893d6 enum-after-comment).

    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Thu Jun 4 19:01:13 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/ee6689ca9a399aa3c5ad1cc6
    Modified Files:
    .claude/skills/javascript/SKILL.md
    Log Message:
    javascript skill: document js.on_exit() scope + forced-termination semantics

    js.on_exit() evaluates its handler string in the script's GLOBAL scope (it compiles the string against the global object), so a handler function nested in another function is unreachable and throws silently at exit. It also fires on forced termination (operator-terminate / SIGTERM), which -- unlike a thrown exception -- does NOT run catch/finally (verified empirically via SIGTERM + file markers). New 'Script lifecycle: exit handlers' section covers the global-scope requirement, the finally-vs-on_exit distinction, and the out-of-process testing caveat.

    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Thu Jun 4 19:01:13 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/a915d2d944ed7b316e36e030
    Modified Files:
    .claude/skills/javascript/SKILL.md
    Log Message:
    javascript skill: correct js.on_exit scope (door child-scope vs jsexec)

    The earlier note said on_exit evaluates "in the GLOBAL scope" -- true only for jsexec/login/timed-event modules (host evaluates against js_glob and recurses child scopes). Doors and most bbs.exec/;exec/js.exec invocations run in a fresh child js_scope (exec.cpp:595) and the host evaluates on_exit against THAT scope (exec.cpp:701) with no recursion. Registration captures the scope where js.on_exit is called -- top level = js_scope, inside a function = that function's call object -- so a handler registered inside main() is filed where a
    door's EvalOnExit(js_scope) never looks and silently never runs, even though the
    same code passes under jsexec (which recurses). This shipped as a live bug.

    Rewrite: register on_exit at top level (not inside a function); prefer try/finally for clean-unwind cleanup (a door disconnect is a clean unwind) and use on_exit only as the forced-terminate backstop; note that a jsexec wrapper does not reproduce a door's on_exit scope, so finally is the dependable path.

    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Sat Jun 6 15:23:28 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/90570a43c9e774e639c3ab04
    Modified Files:
    .claude/skills/javascript/SKILL.md
    Log Message:
    skills/javascript: document inkey timed input + inactivity model

    Add a "Timed / non-blocking key input, and the inactivity model"
    subsection to the input/output coverage: console.inkey(mode, timeout)
    semantics (timeout in ms; K_NONE returns "" vs K_NUL returns null on
    timeout; 1-char string on a key), the getkey-enforces-idle /
    inkey-doesn't trap, and the live console inactivity properties (max_getkey_inactivity, getkey_inactivity_warning, last_getkey_activity). Verified against inkey.cpp, getkey.cpp, js_console.cpp, scfglib1.c (NOINP=0x0100, default max_getkey_inactivity=300).

    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Sun Jun 7 18:41:23 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/e9e5884dba659e4eec2e8ee0
    Modified Files:
    .claude/skills/javascript/SKILL.md
    Log Message:
    skills/javascript: load() caller-scope trap + uselect/printfile/directory gotchas

    Lessons captured from Synchronet door work:
    - load('file') runs in the CALLER's scope, so its top-level vars become locals of
    whatever function called load() -- a top-level / on_exit handler can't see a
    value load()ed inside main(); capture it into a reachable scope (the silent
    "quetzal is not defined" ReferenceError).
    - console.uselect: the title is auto-prefixed with "Select " (pass "a Game", not
    "Select a Game"); the display call's number argument is the DEFAULT item index.
    console.line_counter = 0 discards a pending auto-pager prompt before a clear. - console.printfile renders Ctrl-A codes + ANSI/CP437 by default; P_PCBOARD is
    only for PCBoard @X codes (it would misread a literal @).
    - directory() defaults to GLOB_MARK, so directory entries come back with a trailing
    '/' (self-identifying). The CWD is process-global (always ctrl/, since sbbs is
    multi-threaded) -- which is why no chdir is exposed to BBS JS; build absolute
    paths from js.exec_dir / system.*_dir.

    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net