Repository navigation
emrg: ask the daemon where a GUI session lives before opening it - #2485
Conversation
|
CI cause for the Windows leg, measured from job 119765557482 (no verdict — this head is parked for a later cycle).
The subject body is delimited by The Windows runner checks out with CRLF, so that sentinel does not occur, A fix that does not depend on the line ending: normalise once in the test's |
…e/gui-ask-daemon-session-cwd
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20261022-183149
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20261022-185533
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20261022-190957
The diff is the GUI open path only (main.js, daemon_client.js) plus its two test files and the
Agent.md GUI test-count line, whose parts add up to its total (161 → 166, the five new tests).
pickSessionCwd treats a non-empty index answer as a fact and returns the caller's candidate for
anything else — an unknown, an empty or non-string cwd, a frame it cannot read — so a guess never
acquires the authority of the daemon's answer, and the home directory is never a return value.
No assertion was removed or weakened: the only pre-existing line replaced in boot-contract.test.js
is the test helper's getter (read), which now normalises CRLF; every assert.match in that file
still reads the text it read before. Both CI legs pass (test 2m7s, test-windows 5m17s).
Closes #2484
The GUI never asked the daemon where a session lives.
emrg:switchSessionworked it out locally from~/.emrg/sessions_index.json(resolveSessionCwdinmain.js), and when that lookup returned nothing every caller fell back toresolveSessionCwd(sid) || os.homedir().emrg:sendMessagethen opened its connection withresume: false, so the daemon's ghost-session check — compare the requested cwd against the global index whenmeta.jsonis missing ormessage_count == 0, in_handle_resume_session— never ran, and the task's cwd reached the daemon's open-or-create path as it stood.What changed
daemon_client.js:resolve_session_cwdjoins the command→response map (session_cwd_result), andpickSessionCwd(frame, fallback)states the reading the daemon's two answers deserve —indexis a fact,unknownis not, and a frame that cannot be read is neither.main.js:askSessionCwd(sessionId, candidateCwd)asks the daemon on its own connection (3 s bound; an error or a timeout answersnull, the same reading asunknown) and returnsnullrather than a directory.emrg:switchSessionopens atasked || projectPath || resolveSessionCwd(sid)— the daemon's answer, then the caller's project, then the local guess, and nothing at all when none of the three can place the session (the daemon answersnot_found, which the existing fallback already handles).emrg:sendMessage's pre-open asks before opening and sends the answered cwd with the task, so theresume: falsewindow no longer decides where a session is created.Not in this change
The other dozen
resolveSessionCwd(sid) || DEFAULT_CWDcall sites (delete, rename, clear, compact, history, memory, sandbox, images) run against a session the host already has open, whereopenSessionsholds its project andresolveSessionCwdreturns that first. The window this closes is the pre-open one.Verification
cd emrg/gui && npm test— 167 tests, 159 pass, 8 skipped (the integration legs skip without an isolated daemon).uv run pytest tests/ -q— 5587 passed, 34 skipped (this tree carries master837fad4f, which added one).DEFAULT_CWDfrom the failure branch each redden exactly one guard, and the tree is green again once restored.scripts/check-node-test-count.py --writemoved the documented GUI count 161 → 166; its per-file breakdown (daemon_client98 → 100,boot-contract6 → 9) is synced in the same commit, andtests/test_doc_counts.pypasses.The Windows leg, and why it was red
test-windowsfailed on the previous head, in this file's own caseissue #2484: askSessionCwd asks, judges, and never falls back to the home directory:AssertionError: it must send the daemon's own command,operator: match,actual: ''.The cause was the reader, not the assertion. That case slices a function body out of
main.jswithsrc.slice(start, src.indexOf("\n }\n", start) + 4). A Windows runner checks out CRLF, so the sentinel never occurs,indexOfanswers-1, andslice(start, 3)is the empty string — everyassert.matchover the body then read''.read()now normalises\r\nto\nonce, the shapedaemon_client.test.jsalready uses for the source it reads, and no assertion was weakened.Verified on both line endings, because a local green proves nothing about this class. A script ran this test's own extractor over
main.jsas LF (a 557-character body), over the same file forced to CRLF (0 characters — the reported failure, reproduced) and over the CRLF copy after normalisation (557 characters, the LF slice exactly), with the three assertions of the failing case holding on that text.npm teston this tree: 167 tests, 159 pass, 0 fail, 8 skipped.No sibling newline sentinel exists in
emrg/gui/test/(measured by grep over that directory), so nothing else carries this shape.The head also carries master (
837fad4f), which the previous one did not: it was one commit behind, so a green run there would have described a tree that could no longer be merged. The branch had no standing votes, so this refresh spent none.CI: pending.