feat(runtime): share chat commands and run login sequence

This commit is contained in:
Erik 2026-08-14 20:27:45 +02:00
parent 5535d0adac
commit 41b15efd4d
57 changed files with 1739 additions and 345 deletions

View file

@ -168,13 +168,21 @@ line, writer opens `FileShare.Read`, tailer opens
`Read/FileShare.ReadWrite|Delete`): events `started`, `connected`,
`characterList{accountName,slotCount,characters[{id,name,secondsGreyedOut}]}`,
`enteredWorld{characterId,characterName}`, `pluginLoaded{plugin}`,
`pluginFailed{plugin,error}`, `disconnected{reason}`,
`pluginFailed{plugin,error}`,
`loginCommandFailed{commandIndex,command,error}`,
`disconnected{reason}`,
`exited{code,reason}` — every line carries `"v":1`, `"e"`, `"t"`
(ISO-8601 UTC), `"sessionId"`. `secondsGreyedOut` is a uint on BOTH
sides. Unknown `e` values must parse to a typed Unknown event, never
throw; a known `e` with a wrong payload shape should be distinguishable
from an unknown `e` (LA3 review finding 12).
`loginCommandFailed.commandIndex` is the zero-based index in the configured
`loginCommands` array. `command` is the exact configured line and `error` is
the isolated parser/router/handler failure. The event is observational: the
host continues with the next configured line and never converts the command
failure into a login, plugin, session, or process failure.
**Known LA1 status limitation:** the stream has no independent mid-play
wire-drop detector. If a transport becomes silent without raising through the
host's tick/teardown path, no immediate `disconnected` line can be promised;
@ -203,9 +211,10 @@ Three pieces, one slice, because they share the session-config/status seam:
`RuntimeOptions.LivePass` is a bare string — the config path must not
widen that exposure).
2. **Status stream both hosts:** per-session `status.jsonl` (path given in
config; absent → no writer constructed, zero cost). Versioned event
config; absent → permanent no-op sink). Versioned event
vocabulary (`"v":1`): `started`, `connected`, `characterList`,
`enteredWorld`, `pluginLoaded`/`pluginFailed`, `disconnected`, `exited`.
`enteredWorld`, `pluginLoaded`/`pluginFailed`,
`loginCommandFailed`, `disconnected`, `exited`.
Recon: today's `HeadlessDiagnosticWriter` is a single shared-stdout JSONL
sink with four kinds (lifecycle/failure/event/resources) and NO per-session
file — the status writer is a second, separate sink, not a rework of the