feat(tui,server,config): live config editor + artifact viewer

Two operator features over the existing WebSocket protocol, plus a tui-go nav fix.

Config editor (g / palette "config"):
- core:config gains a thin registry stack: OrchestrationKnobs ([orchestration]
  block), CorrexConfigWriter (round-trip TOML serializer; parseToml(write(c))==c),
  ConfigHolder (AtomicReference live config), and EditableConfig (allowlist of
  editable fields + patch applier; security fields are absent so they can never
  be patched).
- ConfigService validates -> persists (atomic temp+move) -> swaps the holder ->
  rebuilds config-derived services. Live-apply is scoped to safe seams: stage
  timeout, compaction threshold (now a supplier), router knobs (routerFacade
  rebuild), and personalization/project toggles all take effect on the next
  session/turn; in-flight sessions keep the config they started with.
  server.host/port are persisted + badged "restart required", not hot-swapped.
- Protocol: GetConfig / UpdateConfig / ConfigSnapshot; TUI overlay with
  type-aware editing (bool toggle, enum cycle, inline int/string edit) and save.

Artifact viewer (v / palette "artifacts"):
- Server assembles a session's artifacts from the event log and resolves bytes
  from the CAS store (StreamQueries.listArtifacts) — a replay-neutral snapshot
  read. TUI overlay lists artifacts and shows scrollable content.

tui-go fix: workflow failure no longer clears selectedID (which yanked the user
to the list); listNav lands on the first session when nothing is selected
instead of wrapping to a random one.

Config is not event-sourced (it lives in TOML); editing stays outside the log.
This commit is contained in:
2026-06-09 10:18:35 +04:00
parent 89487db72a
commit a92b5a3531
27 changed files with 1629 additions and 72 deletions
+20
View File
@@ -47,6 +47,8 @@ const (
OverlayDiff
OverlayToolPalette
OverlayModels
OverlayArtifacts
OverlayConfig
)
// RouterEntry is one line in a session's conversation transcript.
@@ -188,6 +190,23 @@ type Model struct {
diffScrollOffset int
eventStripShown bool
// artifact viewer (OverlayArtifacts) — populated by the artifact.list response
artifacts []protocol.ArtifactDto
artifactsFor string // sessionId the current listing belongs to
artifactsIndex int
artifactScroll int
artifactsLoading bool
// config editor (OverlayConfig) — populated by the config.snapshot response
configFields []protocol.ConfigFieldDto
configIndex int
configStaged map[string]string // key -> edited value, pending save
configEditing bool // true while typing a value into configEditBuf
configEditBuf string
configError string
configRestart []string // keys from the last save that need a restart
configLoading bool
// command palette
paletteFilter string
paletteIndex int
@@ -214,6 +233,7 @@ func NewModel(client *ws.Client) Model {
history: map[string][]string{},
historyIndex: -1,
routerMessages: map[string][]RouterEntry{},
configStaged: map[string]string{},
chatMode: ChatModeChat,
providerType: "LOCAL",
snapshotPhase: true,