aboutsummaryrefslogtreecommitdiff
path: root/src/profile/paths.ts
AgeCommit message (Collapse)Author
2026-10-14feat(cdp): /browser-target to switch browsers without leaving piIgor Soarez
Switching between the shared browser and this machine's own previously meant leaving pi and relaunching with BU_CDP_HTTP — and, less obviously, killing the daemon first, or the switch silently did not happen. /browser-target show the current target /browser-target local this machine's browser /browser-target default the built-in default /browser-target host:port somewhere else Precedence becomes env > stored > default. The environment still wins so a one-off `BU_CDP_HTTP=… pi` is never silently overridden by a choice made days ago; when it is set, the command says so rather than pretending to obey. Clearing falls back to the default rather than to local — "use the usual browser", not "go local". The daemon is the reason this needed more than a settings write. It is machine-wide, resolves its target once per process, and holds the WebSocket to the old browser, so re-reading the store would leave tool calls going to the old browser while /browser-status reported the new one. The command therefore replaces the process: the daemon now honours an inbound control/shutdown (the action already existed in the protocol, previously only sent daemon→client), and stopDaemon() asks for it and polls until the process is really gone before ensureDaemon() respawns it against the new target. /browser-status now reads the store too, so it cannot disagree with what the tools will do. Persistence mirrors the profile pin: atomic temp-file-plus-rename, and every read failure degrades to "nothing stored" so a corrupt file falls back to the default instead of breaking browser control. It is a separate file from the pin, so damage to one cannot cost you the other. The stored value stays in BU_CDP_HTTP's vocabulary so there is exactly one resolution path. 62 tests: the full precedence table including the stored tier, that a bad value is blamed on the source that set it rather than sending you hunting through shell config, that the command only accepts values resolution can actually use, and eight ways of damaging the store file.
2026-08-02refactor: tidy the whitespace the comment removal left behindamankumarsingh77
Drops leading blank lines where a file header was removed, collapses double blank lines, and closes the empty catch/handler blocks whose only content had been a comment. Whitespace only. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02refactor(profile): strip comment noiseamankumarsingh77
Removes module banners and comments restating the code. Keeps one-line notes for the ProcessSingleton user-data-dir rule, the sentinel-URL and async-spawn-error quirks, the replicated getAgentDir, pi's tilde-expansion mirroring, the Windows wmic removal, the macOS/Linux process-identification quirks, the picker's undefined-means-cancel contract, and the deliberately unpersisted browserContextId. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25feat: pin the agent to a chosen browser profile (#16)Aman Kumar
* feat: pin the agent to a chosen browser profile (#15) Harness tabs were created with a bare Target.createTarget, which places them in Chrome's defaultBrowserContextId — and that value follows window focus. Which profile the agent acted as therefore depended on which browser window the user last clicked, so the same task could run as a work account on one run and a personal account on the next. /browser-profile lists the connected browser's profiles as "Name (email)" and pins one to ~/.pi/agent/browser-harness.json, so the choice outlives the session. The same picker appears on first browser_setup when nothing is pinned; with no interactive UI, or on cancel, setup continues with a note and the previous behavior. Chrome offers no direct route to another profile: Target.createTarget rejects a foreign browserContextId, and openerId does not inherit the opener's context. The window is opened through the browser's own command line (--profile-directory, handed to the running browser by Chromium's ProcessSingleton) and identified by a unique file:// sentinel page, since a bare about:blank#token argument is discarded. Further tabs come from window.open evaluated with userGesture: true — the only CDP-reachable way to place a tab in a non-default browser context — correlated by a unique token so concurrent isolated tabs stay distinct. A failed handshake is reported, never silently redirected to another profile. All four tab-creation sites now funnel through cdp/target-factory, so open_urls and the isolated tabs behind web_search / read_page cannot run with a different profile's cookies than the visible tabs. Also fixed along the way: snap Chromium is discovered, Windows uses %LOCALAPPDATA%, browsers launched with an explicit --user-data-dir are found, the running browser is chosen by ranking candidates against the connected user-data-dir rather than taking the first process found, and an installed-but-closed browser no longer reads as running. CI runs the profile suites and a real-browser end-to-end test on ubuntu, macOS, and Windows — profile discovery is the one part of the harness whose behavior genuinely differs per OS. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: single-flight harness window creation Isolated tabs run concurrently (browser_read_page is registered unserialized), so several could each find "no harness window" and create one — two blank windows before this feature, two LAUNCHED profile windows after it. ensureHarnessWindow now shares one in-flight creation per client. Sharing introduces a second hazard: freshlyCreated is a claim on the seed tab, and if every waiter received it, they would all drive the same tab. Only the caller that started the creation keeps the claim; the rest open their own tab beside it. Covered by test/manual/profile-concurrency-test.ts (five concurrent isolated tabs, pinned and unpinned: distinct targets, one window, correct profile), wired into CI on Linux only — the coordination is pure JS and identical across platforms. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: tilde expansion differs by purpose on Windows CI on windows-latest caught this: join("~", "x") yields "~\x" there, and expandTilde only handled "~/". The two uses are not the same, so they no longer share a helper. The agent dir stays byte-compatible with pi's own expandTildePath ("~/" only, every platform) — being more lenient would put the pin file somewhere pi never looks. $CHROME_USER_DATA_DIR is ours to interpret, so it accepts "~\" as well, which is what a Windows user would type. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>