Files
hermes-agent/web/src/lib/profile-bootstrap.ts
liguoyu a8cccc22f2 fix(dashboard): profile-less chat deep links inherit the launcher's preselected profile
`hermes dashboard` from a named profile re-execs as `-p default dashboard --open-profile P`,
but `--open-profile` only reached the one URL `_maybe_open_browser()` opened. A `/chat?resume=<id>`
deep link without `?profile=` initialised `ProfileProvider` with the empty (launch) scope, so the
embedded chat ran in the default profile — no MCP servers, wrong model/skills — while the switcher
showed P. No error, no indication.

The server now records `initial_profile` on `app.state` and injects it into the SPA bootstrap as
`window.__HERMES_INITIAL_PROFILE__` (escaped for the script context); the Vite dev proxy forwards
it. `ProfileProvider` uses it only when the URL carries no `profile` param: an explicit
`?profile=` (including an explicit empty one) still wins, and the sticky-active-profile alignment
no longer replaces a launch-preselected scope.

Closes #73085. Salvage of #73260 (cherry-pick of 99e341cdef0 resolved onto the split
web_server_dashboard.py; start_server assertion dropped as a change-detector).
2026-09-18 15:12:27 -07:00

32 lines
754 B
TypeScript

declare global {
interface Window {
__HERMES_INITIAL_PROFILE__?: string;
}
}
export function dashboardInitialProfile(): string {
if (typeof window === "undefined") return "";
return window.__HERMES_INITIAL_PROFILE__ ?? "";
}
export function initialProfileScope(
searchParams: URLSearchParams,
bootstrapProfile = dashboardInitialProfile(),
): string {
const urlProfile = searchParams.get("profile");
return urlProfile === null ? bootstrapProfile : urlProfile;
}
export function shouldAdoptActiveProfile(
urlProfile: string | null,
bootstrapProfile: string,
currentProfile: string,
activeProfile: string,
): boolean {
return (
urlProfile === null &&
!bootstrapProfile &&
activeProfile !== currentProfile
);
}