Files
hermes-agent/apps/desktop/electron/window-growth.ts
T
Siddharth Balyan cbe9e5b294 chore(desktop): literal comments across the onboarding flow (#108438)
* chore(desktop): literal comments in the guide script and runbooks

Comment-only change to onboarding-script.ts and setup-profile.ts. The module
headers now state the purpose and the constraints that shaped each file. The
notes beside the runbook strings keep one fact per sentence, or are deleted
when the string beside them says the same thing. The runbook text, the
persona, the option pills and the SOUL text are unchanged.

Both versions transpile to identical output with comments removed.

* chore(desktop): literal comments in the guide chat cards and stores

Comment-only change to the guided chat's cards, directive dispatcher, option
catalog, assembly module and chip. Metaphor and personification are replaced
by the name of the atom, effect or CSS property they stood for. Comments that
restate the code are deleted. Two stale facts are corrected in place: the
mini layout trees point at app/contrib/layout-presets.ts, and the skip button
sets the onboarding phase to skipped rather than done.

One comment line in cards/frame.tsx from bb/connector-ui-e2e-v2 loses a
metaphor and an em dash; its fact is unchanged.

* chore(desktop): literal comments in the handoff and first build

Comment-only change to the handoff wiring, the kickoff, the receipt store,
the first-build check-ins, the handoff tour, the connector rows and the
machine profile store. Every kept comment names the caller, the constraint or
the defect it prevents. The claim that the tour never throws is removed: the
function can reject and its caller does not catch.

Five comment blocks in connector-tool.tsx written on bb/connector-ui-e2e-v2
lose personification, dramatic capitals and em dashes. Every fact in them
stays, and no block moves.

* chore(desktop): literal comments in the intro reveal

Comment-only change to the intro reveal's clock, timeline, cube renderer,
sound, scenes, store and README. Animation comments now name the actual
ramp, easing or offset with its number. Four comments that contradicted the
code are corrected: the first texture slot opens at 3700 ms, the tear settles
from 1 to 0 over 460 ms, the typing weight delays the character it sits on,
and INTRO_EXIT_MS is wall time in index.tsx but score time in the overlay.

* chore(desktop): literal comments in the Electron onboarding windows

Comment-only change to the window growth geometry and the two onboarding
windows. The 768 px floor keeps its one fact: the floor uses Math.ceil where
the deltas round, because rounding 906.24 DIP down leaves the media query
false. The comment that placed the CSS-pixel to DIP conversion at getBounds
now points at growWindowBounds, where it happens.

* chore(gateway): literal docstrings in the onboarding RPCs and the tour tool

Docstring and comment-only change. The module summaries state what each
module does and where authorization comes from, without contrast pairs. The
tool descriptions the model reads are unchanged. Two words in the tour tool's
module docstring lose personification; the rest of that docstring is as it
was.

ast.dump of both versions, with docstrings stripped, is identical for all
three files.

* chore(desktop): literal punctuation in the relaunch and film-end notes

Comment-only change to four lines that bb/connector-ui-e2e-v2 added to the
boot gate, the gate store and the intro gate. Each em dash becomes a colon, a
full stop or a pair of parentheses; one emphasis capital is lowercased. The
facts in the notes are unchanged.
2026-09-12 10:00:08 +05:30

77 lines
2.8 KiB
TypeScript

/**
* Geometry for the main window as the guided chat grows it.
*
* Extracted from the `chat-onboarding:grow` handler so the resulting size can be asserted in a unit test
* instead of checked by eye on a first run.
*/
import type { Rectangle } from 'electron'
export interface GrowRequest {
bottom?: number
left?: number
/** Floor for the resulting viewport width in CSS pixels, used to clear a responsive breakpoint. */
minWidth?: number
right?: number
top?: number
}
export interface GrowInputs {
/** Current window bounds, frame included. */
bounds: { height: number; width: number }
/** `bounds.width` minus the content width, non-zero on platforms that draw a window frame. `minWidth` is a
* viewport floor, so the frame width is added to it. */
frameWidth?: number
/** Display work area the result is centred in and clamped to. */
workArea: { height: number; width: number; x: number; y: number }
/** Renderer zoom factor. Requests arrive in CSS pixels; window bounds are in DIP. */
zoom?: number
}
/** Cap on each value converted from the request, so a malformed request cannot ask for an oversized window.
* The work area clamp below is usually the stricter limit. */
const MAX_DELTA_PX = 4000
/** Fraction of the display work area a grown window may fill. Below 1 so the result keeps a margin instead
* of looking maximized. */
const MAX_WORK_AREA = 0.92
export function growWindowBounds(
request: GrowRequest | null | undefined,
{ bounds, frameWidth = 0, workArea, zoom = 1 }: GrowInputs
) {
const dip = (value: number | undefined, round: (n: number) => number) =>
Math.max(0, Math.min(MAX_DELTA_PX, round((Number(value) || 0) * zoom)))
const toDip = (value?: number) => dip(value, Math.round)
// The floor uses Math.ceil where the deltas round to nearest. At 118% zoom a 768px floor is 906.24 DIP:
// rounding to nearest would give 906 DIP, a 767.8px viewport, and the media query the floor exists to
// satisfy would stay false.
const requestedMin = dip(request?.minWidth, Math.ceil)
const grown = bounds.width + toDip(request?.left) + toDip(request?.right)
// The floor applies before the work area clamp, so a floor wider than the display is dropped rather than
// growing the window off-screen to satisfy the breakpoint.
const width = Math.min(
Math.max(grown, requestedMin ? requestedMin + frameWidth : 0),
Math.round(workArea.width * MAX_WORK_AREA)
)
const height = Math.min(
bounds.height + toDip(request?.top) + toDip(request?.bottom),
Math.round(workArea.height * MAX_WORK_AREA)
)
return centeredBounds(workArea, width, height)
}
export function centeredBounds(workArea: Rectangle, width: number, height: number): Rectangle {
return {
height,
width,
x: Math.round(workArea.x + (workArea.width - width) / 2),
y: Math.round(workArea.y + (workArea.height - height) / 2)
}
}