diff --git a/frontend/src/lib/components/FlowBuilder.svelte b/frontend/src/lib/components/FlowBuilder.svelte index 7f3e96de0d..57cd8b2953 100644 --- a/frontend/src/lib/components/FlowBuilder.svelte +++ b/frontend/src/lib/components/FlowBuilder.svelte @@ -1582,7 +1582,13 @@ kind: 'flow', path: pathSnapshot ?? $pathStore, summaryContent: flowSummary, - pathTrigger: flowPathTrigger + // Gated like the summary's own editor: a host that allows neither field keeps the + // band's segment, which copies the path. + pathTrigger: + customUi?.topBar?.editablePath != false || + customUi?.topBar?.editableSummary != false + ? flowPathTrigger + : undefined }} actions={flowHeaderActions} contexts={headerContexts} diff --git a/frontend/src/lib/components/ScriptBuilder.svelte b/frontend/src/lib/components/ScriptBuilder.svelte index ad57b192bb..ad869ed492 100644 --- a/frontend/src/lib/components/ScriptBuilder.svelte +++ b/frontend/src/lib/components/ScriptBuilder.svelte @@ -2299,7 +2299,12 @@ // invalidates the band before this component is torn down. path: pathSnapshot ?? script?.path, summaryContent: scriptSummary, - pathTrigger: scriptPathTrigger + // Gated like the summary's own editor: a host that allows neither field keeps the + // band's segment, which copies the path. + pathTrigger: + customUi?.topBar?.editablePath != false || customUi?.topBar?.editableSummary != false + ? scriptPathTrigger + : undefined }} afterName={scriptMarks} actions={scriptHeaderActions} diff --git a/frontend/src/lib/components/flows/content/AgentEditorModal.svelte b/frontend/src/lib/components/flows/content/AgentEditorModal.svelte index 08e1906708..0280455e77 100644 --- a/frontend/src/lib/components/flows/content/AgentEditorModal.svelte +++ b/frontend/src/lib/components/flows/content/AgentEditorModal.svelte @@ -319,7 +319,9 @@ item={{ path: pathSnapshot ?? shownPath, summaryContent: agentSummary, - pathTrigger: agentPathTrigger + // Only where the rename behind it can be saved: a reader who cannot write this agent + // keeps the segment that copies the path, rather than an editor with nothing to edit. + pathTrigger: readOnly ? undefined : agentPathTrigger }} afterName={agentHint} actions={settings} diff --git a/frontend/src/lib/components/pageHeaderRegistry.svelte.ts b/frontend/src/lib/components/pageHeaderRegistry.svelte.ts index e499c77025..a68cda5401 100644 --- a/frontend/src/lib/components/pageHeaderRegistry.svelte.ts +++ b/frontend/src/lib/components/pageHeaderRegistry.svelte.ts @@ -6,7 +6,8 @@ export type PageHeaderItem = { /** Absent for an item the picker does not file under a kind — an agent's detail page. The * breadcrumb then names the item without claiming it is one of the three. */ kind?: WorkspaceItemKind - /** Shown whole. Clicking it opens `onEditName` where a page offers one, and copies otherwise. */ + /** Shown whole. Clicking it opens whatever the page hangs off it with `pathTrigger`, and copies + * the path where there is none. */ path: string | undefined /** Wraps the band's own path segment in whatever the page wants behind it — its rename * popover, anchored there rather than beside the summary, so the editor opens under the half diff --git a/frontend/src/lib/utils/forkColor.ts b/frontend/src/lib/utils/forkColor.ts index ca44541696..eb9af17b32 100644 --- a/frontend/src/lib/utils/forkColor.ts +++ b/frontend/src/lib/utils/forkColor.ts @@ -78,11 +78,14 @@ function contrast(a: number, b: number): number { return (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05) } -/** Luminance of what `hslFloorL` paints, not of the exact numbers: a percent of lightness is - * worth more than the margin being solved for. */ +/** Luminance of what the browser paints, which is neither the exact numbers nor the `hsl()` string + * alone: the string carries whole percents, and the channels it resolves to are 8-bit. Solving + * against the unrounded channels leaves the chosen lightness up to 0.025 short of the target once + * painted, which is enough to miss AA on a hue like #993388. */ function paintedLuminance(h: number, s: number, l: number): number { const [r, g, b] = hslToRgb(Math.round(h), Math.round(s * 100) / 100, Math.floor(l * 100) / 100) - return relativeLuminance(r, g, b) + const q = (x: number) => Math.round(x * 255) / 255 + return relativeLuminance(q(r), q(g), q(b)) } /**