Service logs: the page's name is the breadcrumb's, so the `<h1>` is gone and the
search field, the timeframe and the two switches sit in the band beside it, with
the documentation tooltip after the name. ServiceLogsInner registers the band
itself, the way RunsPage does, since that route is its only caller, and the
`title` snippet the page used to hand it goes with the heading.
The search is the widest control there, because searching is what the page is
for, and it is the one that gives width back under pressure. The two switches
fold into a popover below a 1200px bar rather than at a phone's width, so the
field keeps its full width down to a much narrower window — folded rather than
dropped, because the page no longer carries a toolbar they could fall back to.
The timeframe control took no size of its own, so it defaulted to `md` beside a
`sm` field, and sat in a `w-48` box 20px narrower than its content, whose
overflow is visible and so spilled into its neighbours.
No `separator`: the two panes below start under the bar with borders of their
own, so at rest there is nothing for the band to divide.
Audit logs: the filters lose their labels. Each select says what it filters
while unset — "all usernames", "all resources" — and once set the value names
the field by itself. From and To become the TimeframeSelect the runs page uses,
which absorbs the standalone Refresh button, since that control's left half is
the refresh. `auditTimeframes` joins the runs and service-logs presets, with
"All time" first. The bounds stay the filters' own `after`/`before` rather than a
remembered preset label: the timeline's zoom writes them too, and a label could
then contradict the chart.
That takes the row from 1326px to 898px, so it stays inline down to a ~1500px
viewport instead of ~2500. The fold measures the row against the bar less what
the breadcrumb takes, plus a gap the two must never close — the breadcrumb
yields width grudgingly and the row not at all, so sized to just meet they
overlap rather than compress, and mid-resize the tooltip after the page's name
lands on the timeframe button.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three files conflicted, all where main reworked a page this branch had moved
into the header band.
service_logs: main moved the quick search and its parse errors into
ServiceLogsInner and gave the page a `title` snippet. Took main's page whole and
re-applied this branch's one line, `h-screen max-h-screen` to `h-full
max-h-full`, so the page stops claiming the viewport the band sits above.
AuditLogsFilters: main dropped `pageIndex` and added `inline` to pick a row or a
stacked layout. Took this branch's field rewrite — a label above its input per
the form layout in brand-guidelines.md, in place of the absolutely positioned
labels — and applied main's two changes on top. `inline` now switches between
that row and the same fields stacked for the popover, replacing the `2xl:`
breakpoint the rewrite still carried.
audit_logs: main replaced paging with load-more, put the details pane behind
AnimatedPane, and chose between inline and popover filters by measuring. Took
main's page whole and moved its title row into the band.
That measurement needed changing to survive the move. Main measured the row
against the slot it sits in, which worked because the slot was a flex-1 child of
a full-width header row. The band's action box is sized by its own content, so
measuring there asks whether the row fits inside itself — it always does, and
the filters would never fold. The row is now measured against the bar less what
the breadcrumb takes. Checked from 900px to 3000px: the row shows only where it
fits, nothing crosses the bar's right edge, and the page never scrolls sideways.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The page header decides whether a separator is drawn, so a page cannot draw a
second line under it. A registration asks for `onScroll` (the default, drawn
only while something passes under the bar), `always` for a page whose content
starts right beneath it, or `none` where the page genuinely draws its own first
line. Detail pages, the agent editor, workspace settings and the pipeline list
take `always`; the raw app editor takes `none`, since its splitpanes already
draw that line.
The pen that opens the rename popover becomes PathEditPen, shared by the
editors and the deployed pages so the two cannot drift, and the deployed pages
gain it. SummaryPathDisplay makes the pen the only trigger rather than the whole
name block, so the name is selectable text again. Renaming an agent goes through
ResourceService with only the fields the popover edits: the backend sets a
column per field it is given, so writing the config back would clobber a
concurrent edit. The popover also stops clearing a real collision verdict by
telling Path which path is its own.
Two Button fixes, both reaching call sites beyond this work:
- `dropdownItems` given as a function was asked for `.length`, which is its
arity and therefore 0, so a split button built that way rendered no caret.
Both app editors' Deploy dropdowns were unreachable.
- the anchor branch dropped `title`, so a link button had no tooltip.
The audit log filters move into the header actions at the design system's sizes
and trade absolutely positioned labels for the form layout in
brand-guidelines.md: a label above its input, 4px apart, fields 8px apart.
The deployed app viewer floors itself at `min-h-full` instead of claiming the
viewport, which would overhang the page box by the height of the band, and
carries Edit and a public-url link that fold into a menu on a narrow bar. The
root layout drops the legacy menu block, which rendered a second hidden sidebar
and 54 invisible tab stops, and marks the closed detached sidebar `inert`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: card layout and load-more for the audit logs page
* fix: stream audit log load-more with stop control and show inline filters from fhd
* fix: fit audit log filters to measured header width and hold timeline during load-more
* fix: keep audit log load-more available when a trimmed short batch has rows left
* fix: stream the ai chat compaction request instead of waiting on it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: reject a compaction stream stopped midway instead of keeping partial text
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: reject a compaction stream that ends without a finish reason
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: cover a completed responses stream in the streamed completion helper
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat: redesign the service logs page
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: drop a stale jump after a cached host switch and remove unused max_lines
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: keep focus on url sync and expose host selection and new logs to assistive tech
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: reset the tail on dropdown host picks, resume refresh after search, key log cache by host
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: clear the pending jump when a host switch needs no fetch
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat: show upcoming events when hovering a schedule's cron expression
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: read cron version from the draft for draft-only schedule previews
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat: replace the AI input filling toggle with an additional prompt for AI
* feat: pass the additional prompt for AI to MCP clients and shared AI guidance
* feat: shrink the run page AI card to a button and a collapsed prompt
* fix: offer writers a way to add a prompt for AI from the run page
* fix: keep a resource default set in the schema when the script is redeployed
Fixes#11493
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: keep a schema resource default only while the arg stays that resource type
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: drop a scalar resource default when the arg becomes a list
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: let legacy draft-only items be discarded from the home page
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: describe the legacy draft move guard as it now is
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat: add an instance setting routing all dependency jobs to one tag
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: keep bunnative locks on bun and explain the default dependency routing
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
`NavBreadcrumbTrigger` was `MeltButton` written again — same `use:melt` on a
plain button, same spread — so the workspace chevron uses the component that
already exists, and the sidebar handle is a `Button`.
`DetailPageHeader` carried its action row twice, once for the band and once
for the row it draws inside a session's preview panel, and the two had already
drifted: different dropdown size, no `unifiedSize` on the buttons, and the
deprecated `variant="contained" color="light" size="xs"` on the schedule
button. Both placements render the same two snippets now, at the size each
needs.
`OperatorPageKey` admitted every `operator_settings` field, including the three
write rights, which `sidebarPageAllowed`'s `=== true` rule answers wrongly: a
write right is granted unless withdrawn, so its absence means "never
configured". It is the ten visibility flags now.
A test over the registry's merge: later registration wins field by field,
actions sort by `actionsOrder` then registration, release gives its fields
back. That rule is why a component registering where it is not the page
renames someone else's band.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A deployed app opened in an AI session's preview panel renamed the band from
the session to the app, and put the app's Edit beside the session's name. The
viewer registered wherever it was mounted; it takes `ownsPageHeader` now, the
way the detail pages already did, and keeps Edit over its own canvas otherwise.
Both viewers also claimed the whole viewport under a band that takes 44px of
it, so a deployed app scrolled by exactly the height of its own header (the
low-code one measured 900px in an 856px box). The height comes from the host
now: the three standalone routes floor themselves at the viewport and
everything inside them is `h-full`. A raw app reached through `/app_embed` had
no height above it at all and collapsed to nothing; it fills the frame now,
though that route still fetches no bundle secret, so what it shows is blank —
as it is on main.
The agent editor's pen was a second editor of the same path that reported
nothing: an invalid path never reached the deploy gate the settings drawer's
field reports to. It binds to the same slot now. Two things that surfaced
with it: a rename never reached the trail, which read the deployed path; and
typing the saved path back raised "path already used", since the popover's
`initialPath` moves with the rename — `allowedExistingPath` is what says the
item already occupies it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Five files conflicted, all around the detail pages and the app viewer:
- DetailPageHeader: main's #11458 renders a flow's and a script's detail page
inside a session's preview pane, which has a band of its own. The header
therefore claims the page header only on the route that owns it
(`ownsPageHeader`), and collapses on either reason — the host saying its box
is narrow, or the band measuring itself below 1150px.
- DetailPageLayout: took main's, which makes the same `h-full` change and adds
the `wide` snippet parameter the header now reads.
- InWorkspaceAppViewer, PublicApp, sessions/+page: main's per-workspace
membership, deployed-tab reloads and tab-strip padding, beside this branch's
band registration and Edit placement.
Two changes in the same files ride along, since they cannot be separated from
the resolution:
- the deployed app's header is an ordinary band again — the hover reveal, the
corner handle and the pin preference are gone, and a deployed raw app now
sits under a 44px band like every other page.
- the agent editor carries the same pen and popover as the script, flow and app
editors (summary and resource path), and an agent's deployed page claims the
band instead of drawing a second header row under it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: add test key button to AI resource drawers
* fix: scope-check inline AI resource values and keep test model editable
* fix: keep test model editable for unsaved resources, own-key provider check
* fix: restore the save to workspace button on inline flow steps
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: make the inline step save to workspace button icon only
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: offer user scopes in the slack scope editor and drop the generated description on type change
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat: offer slack write scopes as bot and user scope options
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(sessions): show an item's deployed page in the preview panel
The preview panel showed an item's editor and nothing else. It now shows the
deployed page too, as a tab of its own.
**Two sides, two tabs.** The editor and the deployed page are different things
to look at, so `isItemTabFor` keys on the side rather than the item: asking for
a side already open focuses it, asking for the other opens it alongside. Two
editors for one item still cannot coexist — they would race its single
(kind, path) cell — but an editor beside a viewer is safe, since the viewer
reads the deployed version over the API and holds no cell. The tab breadcrumb
keeps re-pointing in place; `Exit & see details` and the detail page's `Edit`
open the other side instead of consuming the one you are on. A tab's label
carries `(edit)` when it is the editor side.
**The detail pages moved out of their routes.** `/scripts/get` and `/flows/get`
are now thin wrappers over `ScriptDetail` and `FlowDetail`, which the panel
renders too. Everything they reach — drawers, triggers, saved inputs — is scoped
to the viewer's workspace through `setOperatingWorkspace`, and every navigation
they attempt is caught by `interceptNav` and turned into a move inside the
panel, so nothing takes the browser out of the session. A plain click is
intercepted; ⌘-click and middle-click still open a real tab, which is why the
pages keep their `href`s.
**The picker opens what exists.** A row opens the deployed page, or the editor
when nothing is deployed there, and carries a Draft / Draft only badge in the
review dock's words. `WorkspaceItem` gained `draftOnly` and `hasDraft` from the
listers, which already returned both; deploys now invalidate the picker cache
through `itemDeployed`, so a just-deployed item stops reading as a draft. Rows
also carry a hover Edit action, reachable from the keyboard with the pick
modifier.
`open_preview` gained a `mode`, narrowed out of the advertised schema for a
session that cannot write drafts and re-checked per path in the handler, where
a refusal reports "couldn't check" apart from "denied". The mode is resolved
before those checks, so a call that omits it is gated as the editor it will
become.
Alongside, the workspace a detail page acts on is now the one it is showing
rather than the one the browser is navigated to: `MoveDrawer`,
`toggleWorkspaceErrorHandler` and the pages' own permission gates read the
operating workspace and its acting user, and `RunForm` mints a password
argument's ephemeral variable there too — in a fork session all of these
previously answered for the parent. `InWorkspaceAppViewer` hands the app's
`ctx` user down as a prop instead of writing the global `userStore`, which from
a session tab was re-pointing every permission check on the page.
Fixes found on the way: `DetailPageLayout` claimed `h-screen` inside a panel
that is not the viewport; Edit on a historical script version dropped the
version from the intercepted click; the Run button stayed spinning after a run
that left the page mounted; and the window-level run shortcut fired from a
collapsed panel and from keys another handler had already claimed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(sessions): historical edits, stale not-found, shared edit rights, tab labels
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(sessions): keep deployed-page links and workspace reads in the session
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(sessions): scope detail hrefs to the session, re-point the viewer's own tab
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(sessions): keep a previewed raw app's route out of the session URL
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(sessions): resolve edit-in-fork against the session workspace
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(sessions): read advanced run tags from the session workspace
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(sessions): fork from the session workspace, star only navigation items
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(sessions): mount only the side a preview tab shows
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(sessions): address CI review round 1 findings
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(sessions): route links in a deployed page's drawers through the panel
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(sessions): tell the chat which deployed page the panel shows
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(sessions): only a 404 reads as an undeployed raw app
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(sessions): scope the unparseable-JSON run gate to the form
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(sessions): a flow deleted from the panel stays in its tab
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(sessions): the picker's edit shortcut works on the current row
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(sessions): load-error toasts say what failed
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(sessions): keep an oversized invalid JSON editor in its form's run gate
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* revert: keep main's draft_only description in openapi.yaml
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: let slack connects issue a user token via user_scope
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore: keep trailing newline in ee-repo-ref
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore: bump ee-repo-ref
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: name the provider in slack token descriptions and refresh them on reconnect
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: drop the generated slack description when connecting another provider
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore: drop the slack scope pin migration, slack ignores scope on refresh
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: clear the generated slack description on client-credentials connects too
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore: update ee-repo-ref to ff4d04f17721d84fb9a1f655af50ff7e4e7dcbc7
This commit updates the EE repository reference after PR #837 was merged in windmill-ee-private.
Previous ee-repo-ref: 83298dcf23574d5ed05e6c767bf1d9b067ab7a95
New ee-repo-ref: ff4d04f17721d84fb9a1f655af50ff7e4e7dcbc7
Automated by sync-ee-ref workflow.
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
* feat: show human labels for oauth scope options in the connect dialog
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat: always show scope checkboxes, label gdocs and gchat scopes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat: offer default scopes as checkboxes for every oauth provider
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix: block runs while a JSON input does not parse
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: clear json editor error on unmount and flush editors before run
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: restore validity when a nullable arg input is cleared
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: let field editors parse before the run check and reset the message on view switch
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: clear the run refusal message when form validity changes
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
It read as if a search field were the only way to earn it, which stopped being
true when the app and pipeline editors' rows started scrolling inside their own
box. Both are the same bargain — the box may shrink because its contents can —
and the flag is what the bar reads to allow it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Measuring the band instead of estimating it: with the canvas toggles shown the
app editor's actions are 826-911px and the trail with the summary another ~500,
so the row overflowed the bar at every width up to about 1470 — the 1100 I set
from an estimate was wrong, and the 1350 before it was too. The toggles come out
at 1500 now, and the menu entries are what keeps all three reachable below that
rather than merely out of the way.
The two widest rows — this editor's and the pipeline's — scroll inside their own
box, which is the escape the rows they replaced had (`overflow-x-auto
whitespace-nowrap`). That answers pi's finding and clears the last 23-40px of
band overflow at middling widths, which predated the conversion. Measured after:
zero horizontal overflow from 852px of bar to 1392.
From the CI round's other findings:
- The pen is offered when either the summary or the path is editable, not the
path alone: a host that allowed one and refused the other could no longer edit
the summary from the band. `PathEditPopover` takes `pathEditable` to match, and
its label names whichever it is given.
- The four editors' comments called the summary read-only, which stopped being
true when the pen beside it started editing it.
- The pipeline's "centre group" comment described a layout it no longer has.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Codex found the app editor's canvas controls unreachable on an ordinary laptop:
the owning route collapsed at 1350px, and a 1440 window with the rail out leaves
1232, so the width, theme and breakpoint toggles were hidden with nothing in the
menu to replace them — and the breakpoint is the only way onto the mobile layout.
Measured on the band, the toggles are 240px beside 334 of other actions and a
~430 trail, so they fit to about 1050: the threshold is 1100 now, and below it
each of the three keeps a menu entry rather than disappearing.
An item with no summary read as a bare `·` with an invisible pen after it, since
the plain text replaced a field that had a placeholder. It now reads "Add a
summary..." in the italic SummaryPathDisplay uses for the same state, and the pen
stops hiding when there is nothing to hover.
Three more from the review:
- `actionsFlexible` says "these actions can give width back", which is true of the
Runs filter row and not of the pipeline's row of fixed buttons.
- `pathSnapshot ?? (newEditedPath || …)` keeps the `||` chain the five rename
sites read and the declaration documents; `??` had made the rest unreachable,
since `newEditedPath` is a string that is never undefined.
- The band bridged `contexts` onto the actions alone, while the pen that decides
whether a path is the caller's to change renders in `summaryContent`. The
breadcrumb's `afterName` and the summary are bridged the same way now, so that
permission check reads the tree that registered it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Found by sweeping every route under the band: the pipeline editor drew its own
row beneath it, 48px of a second header, while the band named only the section.
Its name is the band's now, the folder it is open on sits with that name — the
switcher is how you change pipelines, so it belongs to the name rather than to
the actions — and the mode switch, deploy-all, activity, refresh and overflow
menu are the bar's actions. The arrow back to the list stays: nothing else on the
page points there, and the sidebar does not list pipelines.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
It was the last editor route drawing its own header row under the band, and the
band named it "Agents" — `navPageFor`'s first-segment fallback, because nothing
on the route registered an item. The agent's path is the breadcrumb now, its
version badge reads after that name, the sentence that was the row's second line
became the hint beside it, and the Chat/Form switch, Settings, Evals, version
history and Deploy are the band's actions.
No trail levels in the registration: this layout opens settings in a drawer and
evals over the page, so unlike the dialog it never stands on a level — `trail` is
its root alone here.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The pen opened the path alone, which left the summary with nowhere to be edited
from the band. It carries a Summary field above the path now — the item's name
first, the address it lives at below — and the band's text follows it as the user
types.
`TextInput` with a label rather than the bar's inline field: `EditableInput`'s own
docs rule itself out inside a popover, and it wraps this same input in its edit
mode, so the field, the "Add a summary..." placeholder and the trim on commit are
the behaviour that was there, in the shape the deploy drawer's Summary field
already uses. The keydown stops at the field because every editor binds keys of
its own and a summary is prose.
`summaryEditable` carries the hosts' `customUi.topBar.editableSummary` through,
and the editors' own bar passes it false: that bar keeps its inline field, and
`hidePath` would take the pen with it, leaving a condensed session pane no way to
name the item at all.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* oauth: add gdocs and gchat providers, gchat icon
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* oauth: Google sign-in button for every accounts.google.com provider, least-privilege gchat default
- AppConnectInner: derive isGoogleSignin from the registry auth_url instead of a
hardcoded list, so gdocs/gchat/gforms/gcloud/gworkspace get Google's button.
- gchat default scopes: chat.messages is a restricted scope; default to
chat.spaces.readonly + chat.messages.create (both sensitive). chat.messages /
chat.messages.readonly stay selectable.
- BRAND_COLORS.md: GchatIcon row in sort order.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix: keep flow graph rendered between deploy and navigation
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* refactor: rename flow snapshot to avoid shadowing in loadFlow
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The band showed each editor's summary as an inline field, which put editing
where the page names what it is working on. The summary is text there now, with
its `title` for one the band truncates, and the pen that opens the path for
editing sits after it — the same popover the editors' own bar carries, at the end
of the name it renames. Every editor already has a field for the summary itself:
the script's settings, the flow's Settings tab, and both app editors' deploy
drawer.
The popover moves into `PathEditPopover` rather than being written out four more
times. It owns the open state and hands back the path as it was when it opened:
the band's trail reads that while the popover is open, so a path growing under
the pointer does not drag the pen — and floating-ui the popover — along with it.
`EditorHeader` renders the same component, so the session pane and the band
cannot drift apart.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This reverts commit 1da8d16740.
A folded file sidebar renders nothing of its own, so the toggle on the bar is the
only way back short of knowing ⌘B.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The band's edge listener captures every scroller in the app — Monaco, the audit
table, a run's logs — about once a frame while any of them moves, and it took two
`getBoundingClientRect()` reads before looking at `scrollTop`. It now answers from
`scrollTop` first and only measures when that answer differs from what the band
draws, which is the transition rather than the steady state. The rect check still
authorizes every change, so a scroller that does not start at the content's top
still cannot claim the edge.
The two agent routes main just added size themselves to the viewport, which is
44px more than the box the band leaves them. They measure 856 either way — the
layout's `min-h-0` column clamps them — so this is the sweep the rest of the
branch already had, making the height follow the box rather than depend on a
parent's clamp.
Six comments described the conversion rather than the code, which AGENTS.md calls
out by name. Each now states the constraint a reader could break: why the summary
keeps its popover here, why the audit hint is `afterName` and not an action, why a
run registers a `section` rather than an item, why the Runs filters are
`actionsFlexible`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The band is the workspace's header, not the raw editor's layout controls. ⌘B
still folds the file sidebar, and the editor's own bar keeps the button where it
draws one — a session pane.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The merge brought main's agents detail page, which reaches DetailPageHeader with
no `errorHandlerKind` — and the band's item required one. `WorkspaceItemKindIcon`
falls through to the script glyph for anything it does not know, so defaulting
would have labelled an agent a script; the kind is optional now and the trail
names the item without claiming it is one of the three.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A brand-new app is parked at a `draft_<uuid>` placeholder, and the band named
that rather than the path its Deploy will create — `newEditedPath` refuses the
placeholder for exactly this reason, and the editor's own bar read it. Both app
editors register it now. Verified: the trail reads `u/admin/gentle_app` while the
URL is still the draft.
The band's summary gets the `title` the editor's own bar had, so one the bar
truncates can still be read on hover.
The wrapper that hid AppExportButton on a phone never hid anything:
the component draws no trigger — it is the export drawer, which portals to
`body` — so the class toggle was inert in both states and the comment read as if
something moved. Dropped from both app editors.
Two comments corrected: `NAV_PAGES`' `icon` does reach the breadcrumb for all
eleven entries (`NavBreadcrumb` renders `routePage.icon`), so only `operatorKey`
goes unread for the four the sidebar groups separately; and the raw editor's
phone note described folding that does not happen — the file-sidebar toggle stays
in the band, Jobs and the export are already in the menu, and AI is what stands
down.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pinning brings the sidebar's handle back, and from behind it the unpin button sat
one slot over from where the pin had just been clicked — so a second click in the
same place opened the sidebar instead. An operator is detached by default, which
makes that the default state of the feature rather than an edge case.
`NAV_PAGES` claimed one table stops a page being called one thing in the nav and
another in the header, which holds for the seven entries the sidebar's main group
is built from and not for the four grouped separately — `/routes` was "Triggers"
in the header and "HTTP" in the nav. The comment now says which is which, and
that entry is named for the page rather than its group.
`sidebarPageAllowed` gets a table test: it decides what an operator sees, and its
`=== true` is what a future `Option`-style default would silently change.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The trailing-separator guard gave up on `f/demo/` entirely, which dropped the
whole trail to the kind chip and brought `f/demo` back on the first character of
the name. The levels the path does name come back now; only the leaf waits.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
It was the one editor route still rendering its own bar under the band, so it
showed two header rows and the band named the app "Apps raw" — `navPageFor`'s
first-segment fallback, because nothing on the route registered an item. Its top
bar now becomes the page header the way the script, flow and low-code app
editors' do: the path and summary are the breadcrumb's, the file-sidebar toggle,
autosave cloud, presence mark, menu, Diff, Jobs, export, AI and Deploy are the
header's actions, and the path is a plain label since this editor renames from
its deploy drawer.
The actions render under the band, outside the subtree `RawAppEditor` declares
the operating workspace in, and `OpenInSessionButton` asks that context who the
acting user is — so the workspace travels with them.
`operatingWorkspaceContextEntry()` hands it over without exporting the key.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: make hub integrations usable as examples in global chat
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep web search guidance in sync with provider capability
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: resync web search guidance before the request is built
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: carry loop web search availability into every prompt rebuild
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: drop web search guidance on the completions api fallback
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs: correct onBeforeIteration contract for the fallback re-entry
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: give the ai chat hub script descriptions and integration metadata
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: treat authored hub metadata as evidence the scripts were curated
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: treat hub curated as three-state and speak only for a stated true
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* test: let the benchmark hub serve integration metadata
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* test: benchmark the hub tool against a real integration's scripts and metadata
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* test: cover two more real integrations where the scripts already answer
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* test: report metadata_source from whether the fixture has authored meta
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: parse the hub resource type schema instead of relaying it as a string
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: match integration suggestions on slug words instead of substrings
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: search the integration a query names outright instead of ranking past it
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: reject hub integration slugs that would re-target the proxied request
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: add a mentioned integration's hits instead of filtering the search to it
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: keep named-integration hits under the content cap and unmangle fixture placeholders
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: cut the middle of a capped hub result instead of repeating its tail
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: cap hub results by keeping the best of the ranked and named hits
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: keep a named integration that ranking placed below the content cap
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: let plan mode use the hub integration lookup
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* feat: mark which hub integrations carry authored provider knowledge
The hub flags the integrations whose document holds hand-written provider
knowledge, so a caller can tell before spending a call on the metadata
endpoint: 18 of ~216 qualify, and for the rest the endpoint returns what
was inferred from the same scripts a search already hands back.
Carry the flag onto search results, where the model first meets a slug, so
get_hub_integration is aimed at the few instead of guessed at. A hub that
predates the flag omits it and nothing is marked.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: stop the documented mark reading as a reason not to call
The flag says the hub additionally holds provider knowledge checked against
the live API. It is not a signal to skip the lookup elsewhere: that call
still returns the resource type and the usage-ranked examples, neither of
which a search result carries, and neither guessable.
The prompt said to read a script instead when the mark is absent, which
traded those for a guess on the ~198 undocumented integrations.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: keep the benchmark's documented flag true to what it serves
The eval hub reported Baremetrics and Holded as undocumented while its
metadata endpoint handed back their authored notes, so a case could teach
the model the flag means nothing. Derive it from both fixture sources, and
pin the agreement.
Also trims the documentedIntegrations comment to the four lines AGENTS.md
allows, keeping the case-folding constraint.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: keep the benchmark hub mostly undocumented, like the real one
Adding holded and baremetrics to the documented set resolved the fixture's
contradiction the wrong way: it left five of six integrations marked, against
the live hub's 18 of ~216, and claimed authored notes for two the hub reports
as having none. Drop the notes instead. Their auth and endpoints are in their
shipped scripts, which is what the cases that use them are about.
Also drops the last two places still describing the flag as a reason to spend
or skip the metadata call.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* refactor: let the model name the integration instead of guessing it from the query
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* refactor: word web search guidance conditionally instead of tracking provider capability
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: open the hub metadata route to job tokens and share one integrations fetch
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: record a copied hub script's source where write_script keeps it
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* test: pin that a query narrows to the integration it was given
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: match integration suggestions on the name the hub curates
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: name an integration the hub leaves unnamed from the local word table
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
All four fail `prettier --check` on the branch and pass at the merge base.
`raw_apps/utils.ts` also fails but already did at the base, so it is left alone.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`splitItemPath` documents that it gives up on a path still being typed, but
`f/demo/` is three parts and returned a leaf with an empty name — a blank
segment in the trail. The editor binds the path live, so the breadcrumb sees
every keystroke.
Tested here rather than `navPageFor`'s sort: no two `NAV_PAGES` paths nest, so
the longest-prefix case that test claimed to pin has only one candidate. Renamed
it to what it actually checks.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Second review round, three reachable defects plus one decision:
- A public raw app was 150px tall. The bundle's iframe is `h-full`, and dropping
its `min-h-screen` left nothing to resolve against on the share, embed and
custom-path routes — none of which has a layout above them. Measured: 150px in
a 900px viewport. The floor goes back for those routes and stays off inside the
workspace, where the layout hands a height down and `min-h-screen` would
overflow it by the band.
- The band retracted out from under its own open menu on a deployed app. Last
round taught the sidebar card to hold while the pointer is in a portaled menu
and left its sibling alone, but the band opens menus too — the workspace disc,
the fork family, every path level. One helper now, used by both closers.
- `bandPeeked` outlived the page it belonged to. Clicking a control in the band
navigates away, and the next page may not be one the band floats over, so the
hover handlers that would clear it are gone — leaving the band already down
when a full-bleed page came back. `beforeNavigate` clears it.
- An embed has no band to carry a control, so the app's Edit floats over the
canvas there, where it sat before the band existed. Registering it as the
band's `afterName` under `navHidden` instead would have cost the app 44px of
the iframe for a row holding one button.
Reading "is the workspace navigation hidden" now has one definition
(`isMenuHidden`), since a page has to answer it too: the flag is sticky inside an
iframe, so the raw query param is the wrong thing to read.
Also inset the band by the rail only when there is a rail — an embed reserved
its width and crowded its own controls into a compact layout early.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`prettier --check` fails on all three at the previous head. Whitespace only,
apart from one Button tag that fits on a line.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The operator tour's last step named AI sessions among the pages the sidebar
opens, which operators have no way to reach. The nav handle's comment named the
AI chat layout's menu button as a second way into the card; that button and its
prop are gone, and the corner control on a page that hides the band is what
stands in for the handle now.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Four controls the page-header conversion could put out of reach, each found by a
review pass and reproduced in the browser:
- The flow editor's preview buttons. `topbarWidth` is bound only in the branch a
full-page editor does not render, so `compactTopbar` was permanently false
there; below the 800px phone bar `phoneTopbar` dropped the buttons inline and
the graph overlay never took them, leaving FlowPreviewButtons mounted nowhere
and step testing, whole-flow testing and "Test flow & record" no-ops through
optional calls. It now measures the header the way ScriptBuilder and
AppEditorHeader do, and the inline and overlay conditions are exact
complements.
- The pin on a deployed app. The band lands over the corner handle that called
it down, so the pointer that arrives there hits the band. The band carries the
pin itself now, on the same pixels, in place of the sidebar handle it hides.
- The detached sidebar's own menus. They portal to `body`, so moving into one
left the card and closed it 200ms later, sliding it out from under the menu
being read. The card holds while the pointer is in a menu and takes the close
from the leave of that.
- A deployed app's name for a read-only viewer. The breadcrumb was registered
behind write access, so without it the trail fell back to the section name
"Apps"; and the Edit button rode `afterName`, which the band drops for an
embed along with the trail. The name is registered for whoever opened the app,
and what sits after it survives `navHidden` as the page's own control.
navPageFor gets a table test: it answers both the sidebar links and the
breadcrumb label, and its longest-prefix and first-segment rules are what made
the "Apps" fallback look like a correct answer.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>