Dashboard freeze + Gemini 0.39.0 JSONL support#21
Merged
Conversation
isEditingName() in the poll() guard blocked all fetches indefinitely whenever any .name contenteditable held focus. The intent was to protect a focused element from being ripped out by a structural rebuild, but the side effect was that every card's pill froze the moment a user clicked + New group (which auto-focuses the new name span) and walked away. Move the gate from poll() entry to render()'s structural-rebuild branch only. The fast-path updateCardInPlace loop still runs during edits, so pills + 'synced Xs ago' keep updating; only group-header rebuilds defer until blur. Add a global pointerdown blur-on-outside handler so an abandoned focus auto-clears.
Per google-gemini/gemini-cli#23749, Gemini 0.39.0 migrated from atomic .json full-file rewrites to append-only .jsonl streaming. Adapter only matched .json in _locate and used a single JSON.parse in scanActivity, so 0.39.0+ users silently got null pills. Add parseJsonl() that replays the documented record types — header, MessageRecord, MetadataUpdateRecord ($set), RewindRecord ($rewindTo) — into the same ConversationRecord shape the legacy .json path produces. _deriveSnapshot stays unchanged; it consumes either format through one entry point. scanActivity dispatches on file extension. Both formats coexist in the chats/ dir because Gemini preserves history rather than migrating across the version bump.
Adds four edge-case tests covering \$set metadata merge, \$rewindTo truncation, malformed-line skip-and-continue, and partial-trailing- line survival. Brings the GeminiAdapter test count to 7. Rewrites the file-header comment to describe both .json (Gemini <=0.38 atomic) and .jsonl (Gemini >=0.39 append-only, per PR #23749) format paths, since the previous wording asserted Gemini 'is NOT an append- only JSONL' which became false in 0.39. Also flips the _parsedCache field comment from 'cached parsed JSON' to 'cached parsed ConversationRecord' (format-neutral).
probeGeminiDir's mtime tie-break scan filtered chat files by .json only, so a fresh Gemini ≥0.39 install (which only writes .jsonl) fell back to the less accurate tmp-dir mtime when computing cross-host detection ties against Claude/Codex. One-line filter widened to match both extensions, mirroring the gemini.mjs adapter fix. Also refreshes the activity-watch comment in index.mjs whose 'rewritten-JSON re-read for Gemini' phrasing became half-true after the dual-format dispatch landed.
channyzf6
added a commit
that referenced
this pull request
Apr 26, 2026
#38) gemini-cli 0.39.0 broke our installer's gemini registration with "Not enough non-option arguments: got 1, need at least 2." Root cause: gemini's mcp add subcommand uses yargs, which treats '--' as the "end of options" marker and shoves the post-'--' content into a SEPARATE bucket (argv['--']) -- not into the positional args list. So <commandOrUrl> + [args...] never get populated. Claude (Commander.js) and codex (custom parser) both treat '--' as a command boundary and propagate post-'--' content as positional args, so they keep working. Fix: per-CLI dashSeparator flag in FLAG_PROFILES. claude/codex stay on '--', gemini drops it and passes command + args inline as positionals. Verified live with dummy registrations against all three CLIs; only gemini's behavior changes. Also updated docs/INSTALL.md gemini snippet to match. This used to work in gemini-cli 0.38.x; 0.39.0 made the parser stricter (likely yargs upgrade with populate-- enabled). Two breaking changes from 0.39.0 in our codebase: this one and the JSONL chat-log format change fixed in PR #21.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two independent bugs surfaced by a user report. Bundled because they shipped together from the same investigation.
Phase A — dashboard edit-freeze
isEditingName()in thepoll()guard wedged the entire dashboard whenever any group-name contenteditable held focus. A user clicking+ New group(which auto-focuses the new name span) and walking away froze every card's pill across all hosts indefinitely.Fix: move the gate to
render()'s structural-rebuild branch only — the in-place pill-update fast-path keeps running during edits, so pills + "synced Xs ago" stay live; only group-header rebuilds defer until blur. Adds a globalpointerdownblur-on-outside handler so abandoned focus auto-clears.Phase B — Gemini 0.39.0 JSONL support
Per google-gemini/gemini-cli#23749, Gemini CLI 0.39.0 migrated from atomic
.jsonfull-file rewrites to append-only.jsonlstreaming. OurGeminiAdapteronly matched.jsonin_locateand used a singleJSON.parseinscanActivity, so 0.39.0+ users silently got null pills — the adapter found nothing to read.Fix:
parseJsonl()walks the documented record types (header,MessageRecord,MetadataUpdateRecord$set,RewindRecord$rewindTo) and materializes the sameConversationRecordshape the existing_deriveSnapshot()consumes.scanActivity()dispatches by file extension;_locate()accepts both.registry.mjs probeGeminiDirgot the same extension-filter fix so cross-host detection tie-breaks remain accurate.Adds a
node:testscaffold (zero new deps) with 7 fixture-driven tests: legacy regression, JSONL basic,$setmerge,$rewindTotruncation, malformed-line skip, partial-trailing-line survival.Test plan
+ New group, walk away. DevTools → Network:/sessionspolls continue every 2s. Pills stay live. Click outside the focused name span → focus auto-clears.node --test lib/host/gemini.test.mjs— 7 pass / 0 fail.activityState(legacy.jsonpath).activityState(new.jsonlpath) — pending a 0.39.0 user to verify if the dev machine isn't on 0.39 yet.