Skip to content

Fix Ctrl+] attach controls on Windows - #4

Closed
JeremiahM37 wants to merge 58 commits into
mainfrom
win-attach-fix
Closed

JeremiahM37 wants to merge 58 commits into
mainfrom
win-attach-fix

Conversation

@JeremiahM37

Copy link
Copy Markdown
Owner

CI iteration for the Windows attach test

A message sent to a session is staged at /tmp/… by Go and pasted by a
command line. On Windows Go wrote C:\tmp\… while Git Bash, and the
lectern it runs, read the user's temp directory, where Git mounts /tmp.
Local file reads and writes now map /tmp to that directory and other
root paths into Git's installation, as Git Bash does.

The local runtime's PATH merge treats Windows directories case-insensitively,
and its test uses paths that are absolute on each OS.
Windows cannot delete a running executable, and the test's PTY host and
terminal server are still exiting when t.TempDir is removed.
…ity test

CI's python3 is 3.12, which words them differently from 3.13; the Go port
follows 3.13, and callers only see that the document is invalid.
… standing in, own-folder commit warning and a real message, chat keeps its last line, sessions named by project and topic with inline rename, a calm Sessions page, three-item navigation
…ion, and let the demo ask once

Starting an agent whose program is not on the machine now fails before a
session exists (422 agent_not_installed, naming the agents that are
installed and how to install this one) instead of reporting Started and then
Idle over "command not found".

A pending approval expires once its session has ended or its agent has
exited, swept on the scheduler tick so every way a session ends is covered.
A real-process test proves an agent that dies while asking reads Ended ·
agent exited on both the pty and tmux backends.

In ask mode the demo agent asks for approval before its first write, through
the same PermissionRequest hook a real agent uses, and points at Review &
merge.
…s and controls readable without a terminal

With no LECTERN_DB, a server (lectern serve, or bare lectern with no
terminal) now uses ~/.local/state/lectern/server/lectern.db instead of the
folder it was started in; an existing ./lectern.db is still used, so no
install loses its data, and the startup log names the file.

local status is a sentence by default and JSON with --json. controls with no
terminal says to use lectern api instead of failing inside the TUI. up names
an installed agent, or the demo, rather than always lectern claude.
The private runtime can now also listen on this computer's Wi-Fi address,
on request, serving the same sessions and database. Settings → Connect your
phone gets a "Let phones on this Wi-Fi connect" button, and lectern phone
does the same from the terminal, printing a QR code for a one-time pairing
link (5 minutes), a warning that the LAN connection is unencrypted, and the
Tailscale and relay alternatives; lectern phone --off stops it.

Only paired devices get in from the network: the app is in token mode, the
LAN gate refuses other host names and origins, never accepts the runtime
token, and keeps the runtime's own controls off the network. The device
cookie drops Secure only for plain HTTP from the network, where a browser
would otherwise discard it. The wizard no longer tells people to run lectern
serve, which listens on localhost and keeps its own database.
docs/getting-started.md is three steps per OS (install, lectern up, start an
agent) with the phone, doctor and update next. quickstart.md becomes "Run a
shared server" (install, a token, lectern serve), local.md drops the tmux and
Python requirements, the WSL-only Windows story and the macOS-experimental
note, and README, guide and terminal-client link to the new page. install.ps1
and the MCP example use a neutral server address.
…screen; the plain pty attach never sends Ctrl+\
… Ctrl+] keys, needs-you note, links, panes and clipboard
… here, the chat's status; docs for attaching without tmux
…to the suite

The conversation log stays at the bottom while output grows (mutation and
resize observers), the header follows a rename, and More agents counts only
installed ones. Choosing a grouping brings the list tools back inline, the
scratch cleanup is reachable from the ⋯ menu when the page is short, a launch
profile is left to the server to judge, and sessions without a project say
so again. Browser tests follow controls into the card and header menus.
Revive used to close the session's terminal first and only then find the
agent's program missing, leaving nothing. The check now runs first, so a
refusal leaves the session as it was. The revive browser test gets an
installed stand-in agent.
A fresh machine has no git identity. Commit on a new branch used to switch the
person's own folder first and only then fail at the commit with "Commit step
commit failed". The server now checks with git var before anything moves and
answers no_git_identity; the Commit tab says nothing was changed and shows the
two git config commands. Real-git API test plus a browser test at 1440 and 390
that also sweeps the round-two controls for contrast in light and dark.
# Conflicts:
#	web/index.html
#	web/static/react/assets/PaneViews-B5L5XKMF.js
#	web/static/react/assets/PaneViews-B6rbhOIr.js
#	web/static/react/assets/PaneViews-D8gj3EW6.js
#	web/static/react/assets/RichMarkdown-CdeDviL6.js
#	web/static/react/assets/RichMarkdown-CkKq-iQw.js
#	web/static/react/assets/RichMarkdown-Q7wKu4Uf.js
#	web/static/react/assets/Workbench-CdOmoDCG.js
#	web/static/react/assets/Workbench-D51V6bXy.js
#	web/static/react/assets/Workbench-DBwIuJ1J.js
#	web/static/react/assets/abnfDiagram-VCTEODGH-CgOqIBwZ.js
#	web/static/react/assets/abnfDiagram-VCTEODGH-DKY9TBy2.js
#	web/static/react/assets/abnfDiagram-VCTEODGH-ltFbF4bW.js
#	web/static/react/assets/action-C0ldWb1-.js
#	web/static/react/assets/action-D3z6nmti.js
#	web/static/react/assets/action-DgoT6u-Z.js
#	web/static/react/assets/app-Bmi8DgMA.js
#	web/static/react/assets/app-CTcV2nNz.js
#	web/static/react/assets/app-HJ02Pyjy.js
#	web/static/react/assets/architectureDiagram-5GKGNRK7-BRTty8u2.js
#	web/static/react/assets/architectureDiagram-5GKGNRK7-Bw87b9i6.js
#	web/static/react/assets/architectureDiagram-5GKGNRK7-CFEfKN02.js
#	web/static/react/assets/blockDiagram-I7D4REHJ-B43PE8Y2.js
#	web/static/react/assets/blockDiagram-I7D4REHJ-JwTq3G7e.js
#	web/static/react/assets/blockDiagram-I7D4REHJ-QYYDLsdu.js
#	web/static/react/assets/c4Diagram-7LVT6UL2-BWoAerJ6.js
#	web/static/react/assets/c4Diagram-7LVT6UL2-BZZhjbEk.js
#	web/static/react/assets/c4Diagram-7LVT6UL2-D--ne6hm.js
#	web/static/react/assets/chunk-4HAMMTFA-CdyC4Ca2.js
#	web/static/react/assets/chunk-4HAMMTFA-Dak6WsV_.js
#	web/static/react/assets/chunk-4HAMMTFA-mdRFDOQ4.js
#	web/static/react/assets/chunk-75Z2AOVW-957CGxL_.js
#	web/static/react/assets/chunk-75Z2AOVW-Cg5bWo8T.js
#	web/static/react/assets/chunk-75Z2AOVW-D3qL2gXT.js
#	web/static/react/assets/chunk-DU6HZSFF-BFfOPqFa.js
#	web/static/react/assets/chunk-DU6HZSFF-Cbm9CLOn.js
#	web/static/react/assets/chunk-DU6HZSFF-D1jeAJym.js
#	web/static/react/assets/chunk-F27PBJKO-B6p4kuxZ.js
#	web/static/react/assets/chunk-F27PBJKO-CmHVe2h8.js
#	web/static/react/assets/chunk-F27PBJKO-DR5D88Sn.js
#	web/static/react/assets/chunk-GMAD6QVW-BbSp6lwD.js
#	web/static/react/assets/chunk-GMAD6QVW-BlJGfzaZ.js
#	web/static/react/assets/chunk-GMAD6QVW-DJ0HFV-9.js
#	web/static/react/assets/chunk-GVQU2GXP-C5zDAV40.js
#	web/static/react/assets/chunk-GVQU2GXP-C9WxBu4F.js
#	web/static/react/assets/chunk-GVQU2GXP-CauUILic.js
#	web/static/react/assets/chunk-IMKFNOWR-BUSVbXBH.js
#	web/static/react/assets/chunk-IMKFNOWR-ChnfBiKh.js
#	web/static/react/assets/chunk-IMKFNOWR-DvqWDvr9.js
#	web/static/react/assets/chunk-L3NEJ4N5-BWybKPpb.js
#	web/static/react/assets/chunk-L3NEJ4N5-CANtKTzf.js
#	web/static/react/assets/chunk-L3NEJ4N5-DVIsDcNf.js
#	web/static/react/assets/chunk-OSK3NFVY-3uy8HQ7C.js
#	web/static/react/assets/chunk-OSK3NFVY-CNsef5RK.js
#	web/static/react/assets/chunk-OSK3NFVY-YOvPXRUq.js
#	web/static/react/assets/chunk-P2QGCYS3-B_X5W4pU.js
#	web/static/react/assets/chunk-P2QGCYS3-HOusNWqu.js
#	web/static/react/assets/chunk-P2QGCYS3-ZYJrOuD2.js
#	web/static/react/assets/chunk-POPQ4Y6H-B0DgyP_F.js
#	web/static/react/assets/chunk-POPQ4Y6H-BS1qkyAi.js
#	web/static/react/assets/chunk-POPQ4Y6H-jcI2QP6z.js
#	web/static/react/assets/chunk-PWAF6VOD-3-U8Cpu4.js
#	web/static/react/assets/chunk-PWAF6VOD-CqU5YIKz.js
#	web/static/react/assets/chunk-PWAF6VOD-FiDglwd7.js
#	web/static/react/assets/chunk-SHT3W25Y-3X5XhVEE.js
#	web/static/react/assets/chunk-SHT3W25Y-B99-GcGT.js
#	web/static/react/assets/chunk-SHT3W25Y-Cw59llsa.js
#	web/static/react/assets/chunk-SVP7TREG-C8nDz84A.js
#	web/static/react/assets/chunk-SVP7TREG-CLFgXFZw.js
#	web/static/react/assets/chunk-SVP7TREG-DqIbIAXI.js
#	web/static/react/assets/chunk-TICWLB2K-11py4ySH.js
#	web/static/react/assets/chunk-TICWLB2K-BcBOiewN.js
#	web/static/react/assets/chunk-TICWLB2K-CgD3mLAO.js
#	web/static/react/assets/cynefinDiagram-5FMLGOSQ-Bg8npMjQ.js
#	web/static/react/assets/cynefinDiagram-5FMLGOSQ-CUdy8fVG.js
#	web/static/react/assets/cynefinDiagram-5FMLGOSQ-DPGGFZfU.js
#	web/static/react/assets/dagre-GXQ25YYZ-BIRe1ppJ.js
#	web/static/react/assets/dagre-GXQ25YYZ-BhaXSzM7.js
#	web/static/react/assets/dagre-GXQ25YYZ-DW0SlLhR.js
#	web/static/react/assets/diagram-S7CK7UJ4-A65jJNTc.js
#	web/static/react/assets/diagram-S7CK7UJ4-Cfkh_bWv.js
#	web/static/react/assets/diagram-S7CK7UJ4-TX-CUmRL.js
#	web/static/react/assets/diagram-UQ7AKVKN-BZ_Yrtak.js
#	web/static/react/assets/diagram-UQ7AKVKN-CxWkeyO6.js
#	web/static/react/assets/diagram-UQ7AKVKN-DUycjvAt.js
#	web/static/react/assets/diagram-VSXAHHWV-BKT4N91g.js
#	web/static/react/assets/diagram-VSXAHHWV-BY1yhvj0.js
#	web/static/react/assets/diagram-VSXAHHWV-DnIO4wHH.js
#	web/static/react/assets/diagram-VX7I27RA-CgyAV71U.js
#	web/static/react/assets/diagram-VX7I27RA-D6YGjufm.js
#	web/static/react/assets/diagram-VX7I27RA-wfzKvUn1.js
#	web/static/react/assets/diagram-Z3DM3KII-6dpWLJra.js
#	web/static/react/assets/diagram-Z3DM3KII-BGrgvCjH.js
#	web/static/react/assets/diagram-Z3DM3KII-ElIQm19k.js
#	web/static/react/assets/ebnfDiagram-PWID7BFC-CCY2WEk6.js
#	web/static/react/assets/ebnfDiagram-PWID7BFC-Ccs2G2jj.js
#	web/static/react/assets/ebnfDiagram-PWID7BFC-gy61n7Pj.js
#	web/static/react/assets/erDiagram-RLTQ6QDP-BfMFG3Uk.js
#	web/static/react/assets/erDiagram-RLTQ6QDP-CzLrDTTx.js
#	web/static/react/assets/erDiagram-RLTQ6QDP-VacA07Jt.js
#	web/static/react/assets/es-BjvOFIqx.js
#	web/static/react/assets/es-CQ2xsPic.js
#	web/static/react/assets/es-Jd9UP7tf.js
#	web/static/react/assets/fr-BgU7KYtZ.js
#	web/static/react/assets/fr-DbwLjgwa.js
#	web/static/react/assets/fr-YIn9Z5ej.js
#	web/static/react/assets/ganttDiagram-EL5Y4UJY-Ci-nGf4e.js
#	web/static/react/assets/ganttDiagram-EL5Y4UJY-RoMyoJZo.js
#	web/static/react/assets/ganttDiagram-EL5Y4UJY-wq9CeWvh.js
#	web/static/react/assets/gitGraphDiagram-WWUBYQGX-Amb8k2nU.js
#	web/static/react/assets/gitGraphDiagram-WWUBYQGX-B5S4-kda.js
#	web/static/react/assets/gitGraphDiagram-WWUBYQGX-_uk_m_Ju.js
#	web/static/react/assets/infoDiagram-27XIBGKW-BB0h5pdC.js
#	web/static/react/assets/infoDiagram-27XIBGKW-DPcEo2-Q.js
#	web/static/react/assets/infoDiagram-27XIBGKW-t_KF5Tyy.js
#	web/static/react/assets/ishikawaDiagram-5VMMS53U-CdFMBx5t.js
#	web/static/react/assets/ishikawaDiagram-5VMMS53U-CgKrljNZ.js
#	web/static/react/assets/ishikawaDiagram-5VMMS53U-CwY29Ce4.js
#	web/static/react/assets/ja-Ct-b0xPU.js
#	web/static/react/assets/ja-FORQR6Ty.js
#	web/static/react/assets/ja-KZkHyd2O.js
#	web/static/react/assets/journeyDiagram-3NMN7TZE-5nXEDwSI.js
#	web/static/react/assets/journeyDiagram-3NMN7TZE-BMe8gNYL.js
#	web/static/react/assets/journeyDiagram-3NMN7TZE-QKge-W8H.js
#	web/static/react/assets/jsx-runtime-B_8u7U8_.js
#	web/static/react/assets/jsx-runtime-CTc3L-Ek.js
#	web/static/react/assets/jsx-runtime-DKr7__-1.js
#	web/static/react/assets/kanban-definition-UXKFOSKX-BY3m2yUg.js
#	web/static/react/assets/kanban-definition-UXKFOSKX-BcKeO5IL.js
#	web/static/react/assets/kanban-definition-UXKFOSKX-o0E0YNRC.js
#	web/static/react/assets/ko-BANBmYm_.js
#	web/static/react/assets/ko-DVlu-jXb.js
#	web/static/react/assets/ko-dZHXPESm.js
#	web/static/react/assets/line-CVGzKhp0.js
#	web/static/react/assets/line-CbwlDtMl.js
#	web/static/react/assets/line-DC7CO8aV.js
#	web/static/react/assets/mermaid.core-BGmpGPki.js
#	web/static/react/assets/mermaid.core-SfATCJyh.js
#	web/static/react/assets/mermaid.core-dnpdoiFF.js
#	web/static/react/assets/mindmap-definition-YA3MSWOX-B1OW5K1R.js
#	web/static/react/assets/mindmap-definition-YA3MSWOX-BAQTsDJp.js
#	web/static/react/assets/mindmap-definition-YA3MSWOX-wh3goASK.js
#	web/static/react/assets/pegDiagram-XKGWAZYB-BBFo6umg.js
#	web/static/react/assets/pegDiagram-XKGWAZYB-CRcNrAE8.js
#	web/static/react/assets/pegDiagram-XKGWAZYB-CfgG_gTA.js
#	web/static/react/assets/pieDiagram-E7YTZNPT-CWzaKJcK.js
#	web/static/react/assets/pieDiagram-E7YTZNPT-D-qkL8A_.js
#	web/static/react/assets/pieDiagram-E7YTZNPT-DmQ5x8x-.js
#	web/static/react/assets/quadrantDiagram-AXDQQJYC-DDGStmic.js
#	web/static/react/assets/quadrantDiagram-AXDQQJYC-jUfP4SSH.js
#	web/static/react/assets/quadrantDiagram-AXDQQJYC-zpdD6FHB.js
#	web/static/react/assets/railroadDiagram-O6MQD6OU-B4_T6yJ4.js
#	web/static/react/assets/railroadDiagram-O6MQD6OU-BEnMhdQg.js
#	web/static/react/assets/railroadDiagram-O6MQD6OU-BhqMYPSm.js
#	web/static/react/assets/requirementDiagram-BXWQKSXE-CZWXnnvi.js
#	web/static/react/assets/requirementDiagram-BXWQKSXE-D6FkA4AD.js
#	web/static/react/assets/requirementDiagram-BXWQKSXE-DGCx52gO.js
#	web/static/react/assets/sankeyDiagram-P5KCCOFB-BK5FpyRT.js
#	web/static/react/assets/sankeyDiagram-P5KCCOFB-CS1UKujk.js
#	web/static/react/assets/sankeyDiagram-P5KCCOFB-EwRSS07u.js
#	web/static/react/assets/sequenceDiagram-WJ2MYXX4-CYrcmF2P.js
#	web/static/react/assets/sequenceDiagram-WJ2MYXX4-DuEm_vQY.js
#	web/static/react/assets/sequenceDiagram-WJ2MYXX4-o4cxGATG.js
#	web/static/react/assets/stateDiagram-D77RDMKH-BQQpVrjB.js
#	web/static/react/assets/stateDiagram-D77RDMKH-Cme-Qrye.js
#	web/static/react/assets/stateDiagram-D77RDMKH-JMBeW-em.js
#	web/static/react/assets/swimlanes-42K2YHIH-D__z8anH.js
#	web/static/react/assets/swimlanes-42K2YHIH-dBGym0sa.js
#	web/static/react/assets/swimlanes-42K2YHIH-i7QtUajN.js
#	web/static/react/assets/terminal-B-uCaZZ-.js
#	web/static/react/assets/terminal-BBKSMpBk.js
#	web/static/react/assets/terminal-BiylDP49.js
#	web/static/react/assets/timeline-definition-24CTP7MA-C7hlhG_y.js
#	web/static/react/assets/timeline-definition-24CTP7MA-Ck_0IoYa.js
#	web/static/react/assets/timeline-definition-24CTP7MA-Dx47N7s_.js
#	web/static/react/assets/tokens-C3cMAG2N.js
#	web/static/react/assets/tokens-DbSIDRBH.js
#	web/static/react/assets/tokens-Dpc2hDHL.js
#	web/static/react/assets/vennDiagram-4TSXK5OY-Bn3YdQn8.js
#	web/static/react/assets/vennDiagram-4TSXK5OY-Ca1EfFJq.js
#	web/static/react/assets/vennDiagram-4TSXK5OY-Cnbex8V3.js
#	web/static/react/assets/viewers-CA2cj8y4.js
#	web/static/react/assets/viewers-Cw-ARQKe.js
#	web/static/react/assets/viewers-DTiiYeVX.js
#	web/static/react/assets/wardleyDiagram-VM6X3IG4-B9aUY15Q.js
#	web/static/react/assets/wardleyDiagram-VM6X3IG4-BYGpe6xM.js
#	web/static/react/assets/wardleyDiagram-VM6X3IG4-DbnJi7ui.js
#	web/static/react/assets/xychartDiagram-S5SC5T6Z-Cwo52OlL.js
#	web/static/react/assets/xychartDiagram-S5SC5T6Z-D2sYm3QZ.js
#	web/static/react/assets/xychartDiagram-S5SC5T6Z-i5cnNGF0.js
#	web/static/react/assets/zh-BttOdNY4.js
#	web/static/react/assets/zh-CeF9vD5r.js
#	web/static/react/assets/zh-DF7kEYYZ.js
#	web/static/sw.js
#	web/static/terminal.html
# Conflicts:
#	frontend/src/i18n/en/board.ts
#	frontend/src/i18n/es/board.ts
#	frontend/src/i18n/fr/board.ts
#	frontend/src/i18n/ja/board.ts
#	frontend/src/i18n/ko/board.ts
#	frontend/src/i18n/zh/board.ts
#	frontend/src/sessions/Conversation.tsx
#	web/index.html
#	web/static/react/assets/PaneViews-CGmk3RZC.js
#	web/static/react/assets/RichMarkdown-CdeDviL6.js
#	web/static/react/assets/RichMarkdown-CkKq-iQw.js
#	web/static/react/assets/RichMarkdown-DpZ7QT0X.js
#	web/static/react/assets/Workbench-BIN2kjb-.js
#	web/static/react/assets/Workbench-CdOmoDCG.js
#	web/static/react/assets/Workbench-DBwIuJ1J.js
#	web/static/react/assets/abnfDiagram-VCTEODGH-DYK8uF4W.js
#	web/static/react/assets/action-DSlPwQaw.js
#	web/static/react/assets/app-Bmi8DgMA.js
#	web/static/react/assets/architectureDiagram-5GKGNRK7-BRTty8u2.js
#	web/static/react/assets/architectureDiagram-5GKGNRK7-CFEfKN02.js
#	web/static/react/assets/architectureDiagram-5GKGNRK7-DqKWnehx.js
#	web/static/react/assets/blockDiagram-I7D4REHJ-7Q6t1H_c.js
#	web/static/react/assets/blockDiagram-I7D4REHJ-B43PE8Y2.js
#	web/static/react/assets/blockDiagram-I7D4REHJ-QYYDLsdu.js
#	web/static/react/assets/c4Diagram-7LVT6UL2-BWoAerJ6.js
#	web/static/react/assets/c4Diagram-7LVT6UL2-BZZhjbEk.js
#	web/static/react/assets/c4Diagram-7LVT6UL2-mzXM1e0G.js
#	web/static/react/assets/chunk-4HAMMTFA-CdyC4Ca2.js
#	web/static/react/assets/chunk-4HAMMTFA-DF0czc-P.js
#	web/static/react/assets/chunk-4HAMMTFA-mdRFDOQ4.js
#	web/static/react/assets/chunk-75Z2AOVW-957CGxL_.js
#	web/static/react/assets/chunk-75Z2AOVW-CGmBNe08.js
#	web/static/react/assets/chunk-75Z2AOVW-Cg5bWo8T.js
#	web/static/react/assets/chunk-DU6HZSFF-BFfOPqFa.js
#	web/static/react/assets/chunk-DU6HZSFF-C1dsg9Mw.js
#	web/static/react/assets/chunk-DU6HZSFF-D1jeAJym.js
#	web/static/react/assets/chunk-F27PBJKO-C5jXgOkd.js
#	web/static/react/assets/chunk-GMAD6QVW-BbSp6lwD.js
#	web/static/react/assets/chunk-GMAD6QVW-BlJGfzaZ.js
#	web/static/react/assets/chunk-GMAD6QVW-CtMfgxep.js
#	web/static/react/assets/chunk-GVQU2GXP-Cpv7fJ-a.js
#	web/static/react/assets/chunk-IMKFNOWR-BUSVbXBH.js
#	web/static/react/assets/chunk-IMKFNOWR-ChnfBiKh.js
#	web/static/react/assets/chunk-IMKFNOWR-kW9hg2lU.js
#	web/static/react/assets/chunk-L3NEJ4N5-B2NwHw-L.js
#	web/static/react/assets/chunk-OSK3NFVY-3uy8HQ7C.js
#	web/static/react/assets/chunk-OSK3NFVY-CLe3B2w8.js
#	web/static/react/assets/chunk-OSK3NFVY-CNsef5RK.js
#	web/static/react/assets/chunk-P2QGCYS3-RVpLW1XP.js
#	web/static/react/assets/chunk-POPQ4Y6H-Dq0QmBVR.js
#	web/static/react/assets/chunk-PWAF6VOD-Bn-6bXKJ.js
#	web/static/react/assets/chunk-SHT3W25Y-3X5XhVEE.js
#	web/static/react/assets/chunk-SHT3W25Y-B1A9q2LV.js
#	web/static/react/assets/chunk-SHT3W25Y-B99-GcGT.js
#	web/static/react/assets/chunk-SVP7TREG-C8nDz84A.js
#	web/static/react/assets/chunk-SVP7TREG-CLFgXFZw.js
#	web/static/react/assets/chunk-SVP7TREG-Ddj-QEfB.js
#	web/static/react/assets/chunk-TICWLB2K-11py4ySH.js
#	web/static/react/assets/chunk-TICWLB2K-BcBOiewN.js
#	web/static/react/assets/chunk-TICWLB2K-DwQJOU6r.js
#	web/static/react/assets/cynefinDiagram-5FMLGOSQ-Bg8npMjQ.js
#	web/static/react/assets/cynefinDiagram-5FMLGOSQ-DPGGFZfU.js
#	web/static/react/assets/cynefinDiagram-5FMLGOSQ-Ww9PRz2F.js
#	web/static/react/assets/dagre-GXQ25YYZ-BIRe1ppJ.js
#	web/static/react/assets/dagre-GXQ25YYZ-BVhsupmT.js
#	web/static/react/assets/dagre-GXQ25YYZ-DW0SlLhR.js
#	web/static/react/assets/diagram-S7CK7UJ4-A65jJNTc.js
#	web/static/react/assets/diagram-S7CK7UJ4-D_yMzCgn.js
#	web/static/react/assets/diagram-S7CK7UJ4-TX-CUmRL.js
#	web/static/react/assets/diagram-UQ7AKVKN-B-DJZkbx.js
#	web/static/react/assets/diagram-UQ7AKVKN-BZ_Yrtak.js
#	web/static/react/assets/diagram-UQ7AKVKN-CxWkeyO6.js
#	web/static/react/assets/diagram-VSXAHHWV-BKT4N91g.js
#	web/static/react/assets/diagram-VSXAHHWV-DnIO4wHH.js
#	web/static/react/assets/diagram-VSXAHHWV-hEQIKUX0.js
#	web/static/react/assets/diagram-VX7I27RA-B6lTtsTe.js
#	web/static/react/assets/diagram-Z3DM3KII-CcQnC9wy.js
#	web/static/react/assets/ebnfDiagram-PWID7BFC-DTzsPDgv.js
#	web/static/react/assets/erDiagram-RLTQ6QDP-BfMFG3Uk.js
#	web/static/react/assets/erDiagram-RLTQ6QDP-CzLrDTTx.js
#	web/static/react/assets/erDiagram-RLTQ6QDP-Tyud8vqe.js
#	web/static/react/assets/es-BPYU4L0D.js
#	web/static/react/assets/es-BjvOFIqx.js
#	web/static/react/assets/es-Jd9UP7tf.js
#	web/static/react/assets/fr-BgU7KYtZ.js
#	web/static/react/assets/fr-D6u_E_zV.js
#	web/static/react/assets/fr-YIn9Z5ej.js
#	web/static/react/assets/ganttDiagram-EL5Y4UJY-C7BqW9tT.js
#	web/static/react/assets/ganttDiagram-EL5Y4UJY-Ci-nGf4e.js
#	web/static/react/assets/ganttDiagram-EL5Y4UJY-RoMyoJZo.js
#	web/static/react/assets/gitGraphDiagram-WWUBYQGX-Amb8k2nU.js
#	web/static/react/assets/gitGraphDiagram-WWUBYQGX-B5S4-kda.js
#	web/static/react/assets/gitGraphDiagram-WWUBYQGX-wlNhr8_6.js
#	web/static/react/assets/infoDiagram-27XIBGKW-CuZGOhQs.js
#	web/static/react/assets/ishikawaDiagram-5VMMS53U-BokmpuXN.js
#	web/static/react/assets/ishikawaDiagram-5VMMS53U-CdFMBx5t.js
#	web/static/react/assets/ishikawaDiagram-5VMMS53U-CgKrljNZ.js
#	web/static/react/assets/ja-BjpQdtHz.js
#	web/static/react/assets/ja-Ct-b0xPU.js
#	web/static/react/assets/ja-FORQR6Ty.js
#	web/static/react/assets/journeyDiagram-3NMN7TZE-5nXEDwSI.js
#	web/static/react/assets/journeyDiagram-3NMN7TZE-B0Hb5kZr.js
#	web/static/react/assets/journeyDiagram-3NMN7TZE-BMe8gNYL.js
#	web/static/react/assets/jsx-runtime-B_8u7U8_.js
#	web/static/react/assets/jsx-runtime-CTc3L-Ek.js
#	web/static/react/assets/jsx-runtime-zL88avyV.js
#	web/static/react/assets/kanban-definition-UXKFOSKX-BY3m2yUg.js
#	web/static/react/assets/kanban-definition-UXKFOSKX-CZWtMwmJ.js
#	web/static/react/assets/kanban-definition-UXKFOSKX-o0E0YNRC.js
#	web/static/react/assets/ko-BANBmYm_.js
#	web/static/react/assets/ko-C_A5s4U2.js
#	web/static/react/assets/ko-dZHXPESm.js
#	web/static/react/assets/line-B2RVsozf.js
#	web/static/react/assets/mermaid.core-BGmpGPki.js
#	web/static/react/assets/mermaid.core-DepdohST.js
#	web/static/react/assets/mermaid.core-dnpdoiFF.js
#	web/static/react/assets/mindmap-definition-YA3MSWOX-B1OW5K1R.js
#	web/static/react/assets/mindmap-definition-YA3MSWOX-BAQTsDJp.js
#	web/static/react/assets/mindmap-definition-YA3MSWOX-CepnbBBo.js
#	web/static/react/assets/pegDiagram-XKGWAZYB-ImVa88mr.js
#	web/static/react/assets/pieDiagram-E7YTZNPT-CWzaKJcK.js
#	web/static/react/assets/pieDiagram-E7YTZNPT-D-qkL8A_.js
#	web/static/react/assets/pieDiagram-E7YTZNPT-DvamMSYL.js
#	web/static/react/assets/quadrantDiagram-AXDQQJYC-DDGStmic.js
#	web/static/react/assets/quadrantDiagram-AXDQQJYC-jUfP4SSH.js
#	web/static/react/assets/quadrantDiagram-AXDQQJYC-ry0Abme0.js
#	web/static/react/assets/railroadDiagram-O6MQD6OU-dmqUR8U3.js
#	web/static/react/assets/requirementDiagram-BXWQKSXE-CZWXnnvi.js
#	web/static/react/assets/requirementDiagram-BXWQKSXE-D6FkA4AD.js
#	web/static/react/assets/requirementDiagram-BXWQKSXE-DZFEfC-s.js
#	web/static/react/assets/sankeyDiagram-P5KCCOFB-BK5FpyRT.js
#	web/static/react/assets/sankeyDiagram-P5KCCOFB-C8DTTeUV.js
#	web/static/react/assets/sankeyDiagram-P5KCCOFB-CS1UKujk.js
#	web/static/react/assets/sequenceDiagram-WJ2MYXX4-CYrcmF2P.js
#	web/static/react/assets/sequenceDiagram-WJ2MYXX4-CpU5URxC.js
#	web/static/react/assets/sequenceDiagram-WJ2MYXX4-o4cxGATG.js
#	web/static/react/assets/stateDiagram-D77RDMKH-B_CTuQvB.js
#	web/static/react/assets/swimlanes-42K2YHIH-DhyBOtOa.js
#	web/static/react/assets/terminal-B-uCaZZ-.js
#	web/static/react/assets/terminal-BBKSMpBk.js
#	web/static/react/assets/terminal-DLh1C7rX.js
#	web/static/react/assets/timeline-definition-24CTP7MA-C7hlhG_y.js
#	web/static/react/assets/timeline-definition-24CTP7MA-Ck_0IoYa.js
#	web/static/react/assets/timeline-definition-24CTP7MA-rZBP0s8x.js
#	web/static/react/assets/tokens-C3cMAG2N.js
#	web/static/react/assets/vennDiagram-4TSXK5OY-4ioyr7r_.js
#	web/static/react/assets/vennDiagram-4TSXK5OY-Bn3YdQn8.js
#	web/static/react/assets/vennDiagram-4TSXK5OY-Ca1EfFJq.js
#	web/static/react/assets/viewers-CA2cj8y4.js
#	web/static/react/assets/viewers-DTiiYeVX.js
#	web/static/react/assets/viewers-DZ54SDTB.js
#	web/static/react/assets/wardleyDiagram-VM6X3IG4-B9aUY15Q.js
#	web/static/react/assets/wardleyDiagram-VM6X3IG4-BYGpe6xM.js
#	web/static/react/assets/wardleyDiagram-VM6X3IG4-B_7wvo9t.js
#	web/static/react/assets/xychartDiagram-S5SC5T6Z-Cwo52OlL.js
#	web/static/react/assets/xychartDiagram-S5SC5T6Z-DaqkP2u7.js
#	web/static/react/assets/xychartDiagram-S5SC5T6Z-i5cnNGF0.js
#	web/static/react/assets/zh-ACTVu6OJ.js
#	web/static/react/assets/zh-BttOdNY4.js
#	web/static/react/assets/zh-CeF9vD5r.js
#	web/static/sw.js
#	web/static/terminal.html
On 2026-10-01 a restarted server marked eight live tmux sessions dead: auto
chose the PTY backend because stray test hosts held sessions on the user's
default socket, polled the tmux sessions there, and read them as missing.

- Each session records the backend holding it (sessions.session_backend,
  set on start, relaunch and adopt) and is polled, probed, attached, typed
  into and stopped through it. Rows from before are recorded on first poll.
- A session its backend reports missing is looked for in the target's other
  backends before it ends; when found, the row follows it. Scheduler runs
  get the same check before being called ghosts.
- auto prefers tmux on Linux when tmux holds Lectern sessions, whatever a
  PTY host holds.
- Local executors are no longer zero-sized, so two of them cannot share one
  TargetEnv.
- Tests never use the default PTY host socket: it is refused under
  LECTERN_PTYHOST_TEST_GUARD (set by Go test binaries, the isolated runner
  and the browser suite); the local-runtime tests and e2e workers get
  private sockets and stop their hosts.
…ation story

Both lines built the same simplicity round from 69dc2e5. Where both built
the same thing, one design is kept and the other's unique safety and tests
come with it:

- Phone on Wi-Fi: origin's runtime listener behind POST /api/phone/wifi and
  `lectern phone` as a client command that prefers a tailnet or server
  address; connect-ui's off switch (DELETE /api/phone/wifi, --off, Stop in
  Settings), runtime-token stripping, /api/local/ blocking, CGNAT and
  link-local exclusion, loopback-port reuse, rsc.io/qr rendering and the
  one-click Wi-Fi row. Pairing cookies drop Secure on plain HTTP from the
  network or on the Wi-Fi listener.
- Launch preflight: one check (agent_installed.go) with origin's shell-word
  parser and PATH overrides, run before any row or scratch folder, and
  connect-ui's "isn't installed ... Installed there" error.
- Launch secrets: origin's private mktemp environment file (it reaches
  sandboxes too); the subshell deletes it once read, the shell's report of a
  killed agent is discarded, and secrets stay out of saved launch settings.
- No-tmux attachment: connect-ui's bare client; origin's AttachProcess and
  its scrollback/direct-link plumbing are removed. Ctrl+\ handling uses
  origin's attachKeys.
- Session names: connect-ui's project-or-folder plus topic with #2, #3.
- Navigation: origin's desktop sidebar with every page; on narrow screens
  connect-ui's Sessions/Approvals/Settings + More, Tasks joining once used.
- Sessions page, cards, Start sheet: connect-ui's. Agent-exited reads
  Stopped (origin). Commit drafting keeps the suggested message until the
  draft arrives and never lets a refresh replace the draft.
- Approvals: origin's immediate expiry and late-request denial plus
  connect-ui's scheduler sweep.
- Database default: connect-ui's (state dir, existing ./lectern.db kept),
  plus LOCALAPPDATA on Windows. No new migrations on origin's side.
- Docs: one Getting started page with the per-OS details folded in; README
  keeps its version badge.

Web bundle rebuilt from the merged sources.
Failures seen only on a loaded machine, each with its cause:

- test_mobile_terminal::test_a_snippet_is_one_tap_and_the_list_is_the_operators:
  a quick command added in the terminal frame vanished. The app page's
  first /ui/prefs answer, arriving after the frame's write but before its
  storage event, rewrote the shared cache and its unsent list with the
  server's older copy, and the frame then put the defaults back. A load now
  takes other documents' unsent changes from the cache first (store test).
- test_session_review::test_review_send_comments_and_commit_push_to_bare_remote:
  the drafted commit message arrived while the field was being typed into
  and was spliced into the text. Focusing the field now makes it the
  person's, as typing does.
- test_terminal_file_links::test_links_win_over_a_program_that_tracks_the_mouse:
  counted a click's release as a second press when it arrived late. It now
  counts presses only.
- test_quick_shell::test_cli_shell_picks_local_machine_and_keeps_blank_room:
  the attach wrapper could relay Ctrl-b d as one write, which tmux takes for
  a paste. The helper presses it again after clearing the line.
Audits, round-two status notes, unmerged-branch designs, dated comparison
evidence, the GPU lease protocol and test investigations are history, not
user documentation. Links from user docs, a frontend comment and the
marketing-asset checker follow the move. first-install-validation.md no
longer says Windows and macOS have no native runtime coverage: CI runs the
session backend, PTY host, web terminal and server smoke tests on both.
Host names, a tailnet IP, private paths, a personal file name and a
deployment log no longer appear in pages meant for users. The guide stops
pointing at an eval directory this repository does not have.
The first screen now says what Lectern is in one sentence, then gives the
install command for macOS/Linux and Windows (with Homebrew and Scoop), then
lectern claude, lectern up and lectern phone. Machines, SSH, Proxmox,
sandboxes and racing agents move under Going further. The release badge
reads the latest GitHub release; its alt text keeps the version that
TestVersionIsDeclaredOnce checks.
Install, first agent, approving in the browser, approving from the phone,
then review and commit, with what appears at each step. The phone step says
plainly that Wi-Fi pairing is local and unencrypted, and that notifications
need an HTTPS address from Tailscale or a relay.
…ent switching and text size behind ⋯ in plainer words
…lback drafts plainly, tuck push, amend and PR under Options, and say when there is nothing to commit
… inline git identity and the terminal approval strip
On Windows the test reads a ConPTY, which sends a rendering of the screen
each frame rather than the bytes written to it. The test popup named its
action and returned at once, and the client redrew over it before the next
frame, so ACTION_menu was never sent even though Ctrl+] m had worked. The
popup now appends what it was asked for to a file the test reads.
@JeremiahM37 JeremiahM37 closed this Oct 2, 2026
@JeremiahM37
JeremiahM37 deleted the win-attach-fix branch October 2, 2026 07:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant