Compare commits

..
Author SHA1 Message Date
Paul Bottein f05f11bf47 Normalize offsets in sun and calendar trigger descriptions 2026-10-08 11:45:21 +02:00
Paul Bottein 1be2a691af Use the offset duration mode for sun and calendar offsets 2026-10-08 11:14:03 +02:00
Paul Bottein e47a7c3a45 Allow sections to contain badges and sections (#54624) 2026-10-08 09:30:26 +01:00
WendelinandClaude Opus 5.5 da70ab7268 Refactor UI support checks into static methods and add validation helpers (#54493)
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Claude <[email protected]>
2026-10-08 10:27:10 +02:00
Franck Nijhof 2f15c7640f Keep boolean fields inline in the narrow action editor (#54686) 2026-10-08 09:18:40 +01:00
Bram KragtenandClaude Opus 5.5 1c8da1329e Add focus indicator to entity and sensor cards (#54644)
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-08 09:16:21 +01:00
Franck Nijhof a9c449f502 Load the HLS source once instead of on every media attach (#54683) 2026-10-08 08:55:09 +01:00
Franck Nijhof 568d842245 Let long dropdown submenus scroll (#54692) 2026-10-08 07:48:26 +00:00
Petar Petrov 796795818d Show the newest history states when the browser clock runs behind (#54688) 2026-10-08 08:44:19 +01:00
Franck Nijhof 33c1a3acfd Keep a cleared input value when focusing it again (#54690) 2026-10-08 09:40:27 +02:00
Franck Nijhof 9e0f0931ae Keep the key order when duplicating a script (#54687) 2026-10-08 09:29:30 +02:00
b71c47f2e8 Add unit of measurement selector (#54391)
* WIP

* Implement unit of measurement picker and selector

* Disable units for device classes that do not support units

* Fix no unit

* Follow sensor entity unit rules in unit of measurement selector

Non-numeric device classes only allow no unit, and a device class or
state class without a unit table (such as monetary or measurement)
no longer restricts the units.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Follow up on comments

* Lint error

* Add context info to config

* Only clear the unit when the context filters change

ha-form, the blueprint editor and the gallery create a new context object
on every render, so editing an unrelated field counted as a context
change and could clear a saved unit. Compare the filter values instead.

A filter can be a list of device classes or state classes, so compare
them by value rather than by reference.

Co-authored-by: Petar Petrov <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-10-08 09:25:14 +03:00
karwosts 6afbc6322d Fix unhandled undefined label registry access (#54659) 2026-10-08 09:13:19 +03:00
bd286f2519 Add power values to energy dashboard (#54627)
* Bugfixes

* Remove useless updates

* Fix updating issue

* Remove useless check

* Rename test case for clarity

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-10-08 05:49:43 +00:00
Jump-333 fb16219c5b Add legend values in the devices details graph (#54631)
* Add legend values in the electricity page

* Fix localization issue and tests

* Add tests and fix localization issues

* Remove energy usage graph legend
2026-10-08 08:25:34 +03:00
Aidan Timson 4852d3c609 Add repository source filter and grouping to Marketplace (#54654)
* Add a source filter and group by source to the marketplace

* Plural form

* Test that marketplace browse links keep the source

* Drop the Marketplace filter pane rendering test
2026-10-08 08:22:14 +03:00
Jump-333 26c332d922 Remove duplicate condition from the automation editor code (#54674)
Remove duplicate condition
2026-10-08 08:13:04 +03:00
renovate[bot]andPetar Petrov b829ba9eca Update dependency jsdom to v30.1.2 (#54642)
* Update dependency jsdom to v30.1.2

* Focus shadow-rendered buttons in dialog-form tests

jsdom 30.1.2 no longer focuses light-DOM children of a shadow host
without a slot. The ha-form mock has no slot, so the opener buttons
were never rendered. Put them in the form's shadow root, where real
ha-form controls live.

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <[email protected]>
2026-10-08 06:40:44 +02:00
Franck Nijhof 46c65973a0 Wrap descriptions in voice assistant settings (#54678) 2026-10-08 06:39:03 +02:00
karwosts 4bb7908f60 Fix create floor memoization issue (#54675) 2026-10-08 06:38:34 +02:00
Paul Bottein bc21992178 Snap the map overview bottom sheet to fixed positions (#54663)
* Snap the map overview bottom sheet to fixed positions

* Include the safe area in the collapsed stop and follow reduced motion
2026-10-07 17:50:09 +02:00
Bram KragtenandClaude Opus 5.5 28f53d9f5a Show the next demo card on the home page demo again (#54646)
* Show the next demo card on the home page demo again

The home overview strategy now generates the favorites section itself
instead of returning a common-controls section strategy, so the demo
strategy no longer found the section to add its card to. Find the
favorites section by its heading instead.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Keep at least six favorites next to the demo card

The section strategy used to get a limit of two less, so seven tiles
became six. Only drop as many tiles as needed to keep six.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Keep the current user when the demo user subscription refreshes

The auth/current_user mock answered with the user from startup, so the
user subscription reset a changed user, like the non-admin scenario of
the e2e tests, to the initial admin user.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-07 17:33:31 +02:00
Aidan Timson d2fa820035 Add group by to Marketplace tables (#54653)
* Add group by status and type to the marketplace

* Update the marketplace dashboard test for grouping

* Group the marketplace by status by default

* Type the Marketplace grouping events and drop the panel test
2026-10-07 17:05:45 +02:00
Petar Petrov 0e34aa06c1 Align history timeline X axis with line charts (#54657) 2026-10-07 17:53:03 +03:00
Marcin BauerandClaude Opus 5.5 bb168601b8 Restore left-column timeline names on the history-graph card (#54661)
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-07 15:47:15 +01:00
Aidan Timson 1823e783ee E2E test fix: Keep the current user in the demo auth stub (#54658) 2026-10-07 15:56:00 +02:00
Marcin BauerandClaude Opus 5.5 03a815bb2e Fix long entity names overflowing the entities picker (#54656)
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-07 13:13:50 +00:00
Marcin BauerandClaude Opus 5.5 adde734800 Make disabled automation rows easier to read (#54650)
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-07 14:58:02 +02:00
Petar Petrov 8598a35c88 Add reset zoom button to network graphs (#54510) 2026-10-07 14:30:10 +02:00
WendelinandClaude Opus 5.5 7008f2ee38 Keep dropdown menus within the viewport and wrap long items (#54643)
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Claude <[email protected]>
2026-10-07 14:23:54 +02:00
Paul Bottein 0a8a71049b Use generic paths to address Lovelace dashboard items (#54207)
* Use generic paths to address Lovelace dashboard items

* Return node target for container paths

* Remove dropped card node when creating a section from a drop

* Refuse to write through a missing list item

* Only build card and badge paths in edit mode

* Use optional badge config in edit badge dialog params

* Append cards in a single write in addCards

* Append badges in a single write in addBadges

* Pass a save callback to the badge edit dialog

* Handle ll-create-card from custom layouts that don't bubble it
2026-10-07 14:20:51 +02:00
Bram KragtenandClaude Opus 5.5 79488d0c09 Mock editing the own profile in the demo (#54645)
The demo did not answer person/update_own_profile, so saving the profile
dialog showed an error. Also answer auth/current_user, so the user
subscription picks up the new name.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-07 15:00:39 +03:00
WendelinandClaude d0c09951e6 Dismiss reboot/shutdown toast when frontend reconnects (#54640)
The "Rebooting system" toast was shown without an id and with no
timeout, so nothing could ever close it and it stayed on screen after
the host came back. Give it an id, dismiss it when the connection is
re-established, and also when the action fails with an error dialog.

Fixes #54630


Claude-Session: https://claude.ai/code/session_01SkS1AB8w2GPUuRBaDDmsEu

Co-authored-by: Claude <[email protected]>
2026-10-07 10:37:54 +02:00
Aidan Timsonandcopilot-swe-agent[bot] 3d57d1b949 Remove the blocking-label workflow (#54064)
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-10-07 10:33:37 +02:00
Maarten Lakerveld d02b605916 Zone editor: fit without passive zones, hide covered radius handles, name tooltips, and start new zones at the map center (#54597)
* Leave passive zones out of the zones map fit

Opening the zones page fitted the map around every zone, so a few remote
passive zones pushed the view out to the whole globe and adding a zone took
a lot of zooming. Passive zones are still drawn and editable, but no longer
count toward the fit unless they are the only zones there are. Editable
locations gained a fit flag for this.

Fixes #54595

* Hide a zone's radius handle while the circle is under its icon

Zoomed out on the zones page, every zone's radius handle collapsed onto the
zone icon and covered it. The handle now hides while the radius on screen is
shorter than the icon's half width, so it returns as soon as the circle's
edge shows past the icon, and it stays while the radius is being dragged.

* Show a zone's name in a tooltip when hovering its marker on the zones map

The marker only had a native title, which appears late and in the
browser's own style. Every named editable location now gets an ha-tooltip
anchored to its element, so hovering a zone icon on the zones page names
it promptly; the native title is dropped so the two do not stack.

* Start a new zone at the center of the zones map

Create zone placed the new zone at a random spot up to 500 meters from
home, so it landed somewhere unexpected and often off-screen. When the zones
page has its map open, a new zone now starts at the center of the current
view, so panning to the right place first works as expected. A location
handed in, as from a person's Create zone action, still wins; without a map
the random offset around home remains.
2026-10-07 10:12:08 +02:00
Maarten Lakerveld a9c1531e37 Map: float every marker, keep the selection in the URL, pan-first focus, and fix attribution and zone radius display (#54596)
* Auto-hide compact map attribution and restyle it for dark mode

MapLibre decides compact mode from the map canvas width alone (640px), so
shrinking the window flipped the attribution from compact back to inline
when the sidebar became a drawer and the map got wider. The engine now adds
the control itself and forces compact on a narrow viewport (870px, the app's
own narrow layout), swapping it when the breakpoint changes.

MapLibre only collapsed the opened compact attribution on a drag; it now
also collapses by itself after five seconds, unless the user opened it from
the info button.

MapLibre's stylesheet hardcodes a white attribution with black text, which
Home Assistant never overrode, so it stood out on a dark map. The dark mode
rules now match the zoom control styling, and the inline text color is set
explicitly instead of inherited from a page that may be in the other mode.

* Add show_zone_radius option to the map card

In panel layout the map hides zone radii except on the Zones tab, for the
selected zone, and while editing. A user asked to always see them, so the
new option draws the radius of every visible zone on all tabs. Other layouts
already show radii and are unaffected.

* Regroup map clusters up front for every fit

Clicking a bubble already regrouped its members at the zoom the fit would
land on, so they parted as the animation started. Any other way of zooming
in, such as picking a person in the map overview, waited for the move to end
before the bubble split. The fit itself now does the regrouping, for all
markers, so every animated fit shows the bubbles as they will end up.

* Return the map to its previous view from the overview's back button

Leaving a selected person or zone cleared the selection but left the map
zoomed in on it. The card now remembers where the map was when the overview
drilled in: the exact camera, or the previous entity's fit when one selection
followed another, and the back button eases back there. A camera that was
still auto-fitting resumes auto-fit instead of freezing. Clicking the map to
deselect stays put, since that is the user looking around.

Engines gain getView, and setView can animate.

* Float the selected map marker above a dot at its location

Selecting a person or device marked it with a ring only, and inside a zone
it stayed hidden in the zone's bubble. The selected marker is now excluded
from clustering, drawn a quarter larger, and hangs above a small dot at the
exact coordinate with a tail pointing down to it. The accuracy circle around
the dot carries the entity color, so the ring is dropped; an entity that
reports no accuracy gets a nominal 5 meter circle so the color still shows.
A fix of 10 meters or better draws that circle as a soft disc without an
outline, since a hard edge would claim more precision than is known; map
circles gained an outline option for this. The engine's marker anchor puts
the dot on the coordinate; both engines support it. Bubble avatars keep
their size.

* Open more info from a button in the map overview detail

The selected person, device or zone's name was the only way to the more-info
dialog, which made the title read as a link. The name is plain text now and
a filled More info button sits below the activity, where the user expects an
action. Focus still moves to the name when the detail view opens.

* Always show the selected marker's accuracy circle

The circle only appeared for a GPS fix looser than 100 meters, so most
phones never showed one. The selected marker now floats above a dot at its
coordinate, so even a small circle around that dot reads clearly; it is
never hidden for the selected entity. Focusing still fits the circle into
view only above 100 meters, since a tighter circle fits at the focus zoom.

* Describe every toggle in the map card editor

Only Show all and Show zone radius explained themselves; Scale ruler, Auto
fit, Fit zones and Cluster markers now have helper text too.

* Float every map marker above its location

Only the selected marker hung above a dot with a tail; the rest sat
centered on their coordinate, so a marker's frame always hid the spot it
marked. Every entity marker is now a pin whose tail points just above its
coordinate. Selecting one scales its frame up and shows the dot at the
exact location. Cluster bubble avatars keep their plain frames.

* Keep the map overview selection in browser history

The card remembered a single camera to restore from the overview's back
button, so after selecting one entity and then another the original view
was lost, and back from the second left the map zoomed on the first while
the overview showed the list. The selected entity now lives in the URL as
an entity_id query parameter; selecting pushes a history entry, and so
does deselecting, whether from the overview's back arrow or a click on
the map, so the browser's back and forward step through every selection.
The overview's arrow itself always returns to the list. Selecting focuses
the entity; deselecting leaves the map where it is. Only selectable
domains are accepted from the URL; anything else is dropped from it. The
saved camera, the animated setView and the autoFit view flag had no
other users.

* Pan to a selected map entity instead of zooming in on it

Focusing a person jumped to zoom 19 and a zone fitted its circle, which
often zoomed much further in than the user had been. Selecting now keeps
the current zoom and pans the entity into the free part of the view. It
only zooms in when another marker sits within 80 screen pixels, and then
just far enough to clear it, capped at zoom 17. Markers at the very same
position cannot be separated by zooming and are left alone. A zone is
fitted as its whole circle with a little room around it under that same
zoom cap, so a zone that fits the view keeps the zoom and a bigger one
zooms out just enough. A marker already on screen eases over; one off
screen flies there in an arc. Fits gain a fly option for this, and every
other fit now eases straight to its bounds on both engines, where
MapLibre used to fly. Map-engine gains pixelDistance, the Web Mercator
screen distance at a zoom level, with a test for its scale.

* Float every cluster bubble above its location

Only a bubble attached to a zone had a tail and hung above the zone's
circle; a bubble of nearby markers sat centered on the cluster, hiding the
spot it stood for. Every bubble now has the tail and floats above its
location with the same lift as a single marker's pin, so the two read as
one style. A zone's bubble keeps floating above the zone circle.
2026-10-07 10:09:07 +02:00
Matthias AlphartandClaude 87166c98dc Sort selected weekdays in time trigger and condition (#54623)
Co-authored-by: Claude <[email protected]>
2026-10-07 09:16:10 +02:00
Artur Pragacz 89c333894d Consider next name part when unprefixing entity name (#54633)
* Consider next name part when unprefixing entity name

* Adjust
2026-10-07 08:39:45 +03:00
karwosts d994db64cb Fix script duplication (#54637) 2026-10-07 08:20:57 +03:00
renovate[bot] d6a3c6efcc Update dependency @versatiles/style to v6.1.1 (#54629)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-07 05:01:37 +00:00
Paul Botteinandcopilot-swe-agent[bot] ce58026788 Fix section editor crash while typing a strategy in YAML (#54622)
* Fix section editor crash while typing a strategy in YAML

* Reject array-valued section strategies in YAML

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-10-07 04:59:26 +00:00
2e09d1a43b Correct system and diagnostics API types in the frontend (#54290)
* Correct system and diagnostics API types in the frontend

Compare the system health, log, repairs and related data modules with
the handlers that produce them, and fix the mismatches.

The system health failure detail was read from a key that does not
exist, so a failed check rendered blank. Repairs issues carry several
always-present nullable fields and no active flag. Saving the core
config and ignoring a repair return nothing, and the icon types were
missing a nesting level.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YDqKNfAAvMV7zJJNodsHfK

* Surface the HTTP fallback port and the failure reason

Warn separately when the server fell back to the previous default
port, which the saved configuration warning did not cover.

Show the diagnostic message a failed configuration carries, and fall
back to the error code when there is none.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YDqKNfAAvMV7zJJNodsHfK

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-10-07 06:52:57 +02:00
WendelinandClaude Opus 5.5 45e2392eeb Fix leaked WebRTC peer connections in ha-web-rtc-player (#54557)
* Abandon superseded WebRTC starts to avoid leaking peer connections

If ha-web-rtc-player was disconnected (or restarted) while awaiting the
WebRTC client configuration, the start continued afterwards and created
an RTCPeerConnection that nothing ever closed.

Track a start id that is bumped on every clean up and bail out when a
start has been superseded. Negotiation now also checks that it still
belongs to the current peer connection.

Fixes #54482

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_014ZzvX8SAHt1knzzJNULtZx

* Bind WebRTC signaling callbacks to their own peer connection

Events of an offer subscription that belongs to a superseded start could
still reach the current stream before the unsubscribe completed, sending
candidates to the old session or applying the old answer to the new
offer. Ignore events whose peer connection is no longer the current one,
and don't report errors from operations rejected because a superseded
connection was closed.

Also show an error instead of leaving an unhandled rejection when
fetching the WebRTC client configuration fails.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_014ZzvX8SAHt1knzzJNULtZx

* Localize WebRTC player errors and handle rejected offer subscriptions

Error messages of ha-web-rtc-player were hardcoded English strings. They
are now stored as an error type plus the backend message and localized
when rendering.

The try/catch around webRtcOffer() never caught anything because the
subscription returns a promise, so a rejected offer left an unhandled
rejection and no error. Handle the rejection, and don't let clean up
re-raise it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_014ZzvX8SAHt1knzzJNULtZx

* Rename WebRTC start id to clean up count

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_014ZzvX8SAHt1knzzJNULtZx

* Don't start a WebRTC stream on a disconnected player

Lit still runs a pending update after the element was disconnected, so
a player added and removed in the same task (or given a new entityid
after removal) started a stream after its last clean up, which nothing
closed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_014ZzvX8SAHt1knzzJNULtZx

---------

Co-authored-by: Claude <[email protected]>
2026-10-07 06:52:10 +02:00
renovate[bot] b0c5ea6296 Update pnpm to v12.9.1 (#54635)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-07 06:49:20 +02:00
renovate[bot] c0204eeb25 Update dependency maplibre-gl to v6.12.0 (#54636)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-07 06:49:03 +02:00
59444f72bc Add a gallery page for ha-picker-combo-box (#54588)
* Add a gallery page for ha-picker-combo-box

The picker combo box is only ever seen inside a popover or dialog, which
makes its two render paths and two row highlights hard to inspect. This
page renders it directly in four states: a plain list under the
MAX_PLAIN_LIST_ITEMS threshold, a virtualized list of 200 items, an empty
list, and one with a current value pinned into view.

The component takes no hass, so the page provides internationalizationContext
directly rather than going through a fake hass object.

Co-Authored-By: Claude Opus 5 <[email protected]>

* WIP - combobox gallery

* Tighten the picker combo box gallery text

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Improve documentation for ha-picker-combo-box

Clarified rendering behavior and filtering logic in the documentation. Updated keyboard shortcuts and added information about selected sections.

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Fix Prettier formatting in picker combo box gallery page

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5 <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-10-06 13:52:15 +00:00
Petar Petrov 6856449bd3 Drop hass from the home summary card (#54606)
* Drop hass from the home summary card

The card consumes the contexts it reads and computes its summary text
from statesContext, so it only re-renders when the text changes. It
subscribes to the energy collection through EnergyCollectionController,
which gains a beforeSubscribe hook to set today's period, and fires
hass-action like the button card. isSecurityAlertActive and the battery
filters take the values they need.

* Test isSecurityAlertActive against every alert domain
2026-10-06 15:42:24 +02:00
Petar Petrov 9fa168e22c Pass registries to generateEntityFilter as separate values (#54605)
generateEntityFilter takes states, entities, devices, areas and floors
instead of a hass-shaped object, so callers without hass can use it.
2026-10-06 15:24:18 +02:00
Marcin BauerandClaude Opus 5.5 6d6aaecb39 Remove no-op refresh button from activity panel (#54620)
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-06 15:20:22 +02:00
Jump-333 d9f2baeeb4 Add badge for the wait for a template row (#54529)
* Add badge for the wait for a template row

* Removed literal text filter
2026-10-06 15:35:55 +03:00
Aidan Timson 234eb800bb Fetch nightly translations artifact directly with retry backoff (#54574)
* Fetch nightly translations artifact directly with backoff

* Type nightly translations fetch and use shared retry helper

* Retry GitHub API calls in workflow scripts
2026-10-06 15:27:36 +03:00
Wendelin 40c76b3993 Upgrade webawesome to version 3.14 (#54616)
* Upgrade @home-assistant/webawesome to version 3.14.0-ha.0 in package.json and pnpm-lock.yaml

* Update bundle size budget for frontend-modern and frontend-legacy
2026-10-06 15:11:29 +03:00
WendelinandClaude 7ca12940d9 Increase touch area of ha-checkbox (#54617)
Co-authored-by: Claude <[email protected]>
2026-10-06 13:11:20 +01:00
Aidan Timson 19630745d8 Follow webawesome fork releases in Renovate (#54619) 2026-10-06 12:08:17 +00:00
Marcin BauerandClaude Opus 5.5 69f83e0ddc Move dashboard edit mode help button to the overflow menu (#54608)
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-06 14:34:55 +03:00
Marcin BauerandClaude Opus 5.5 afac5d6e56 Add undo action to cut toast in automation editor (#54612)
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-06 13:19:41 +02:00
Aidan Timson c40846ada7 Skip release delay for first-party packages (#54614) 2026-10-06 13:18:24 +02:00
Bram KragtenandClaude 388c4f856b Simplify CI workflow: make build depend on lint and test (#54609)
Co-authored-by: Claude <[email protected]>
2026-10-06 12:09:47 +01:00
Aidan Timson 7051fd27f7 Add a custom repositories page to the Marketplace (#54604)
Manage custom Marketplace repositories on their own page
2026-10-06 12:27:42 +03:00
Jonathan 6fca7a89b6 Show the requested run when a trace page switches item (#54591) 2026-10-06 11:26:46 +02:00
Wendelin 121b3dade7 Fix HaChipBase border radius (#54603)
Add border-radius to HaChipBase styles for improved appearance
2026-10-06 12:19:56 +03:00
Marcin BauerandClaude Opus 5.5 5a5611df6b Load History and Activity results only after closing the sources sheet on mobile (#54602)
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-06 11:05:39 +02:00
Paul Bottein a7c435e1a0 Show referenced triggers instead of generated IDs in automation and trace descriptions (#54587) 2026-10-06 10:52:45 +02:00
Petar Petrov 8bc7ab0e74 Drop hass from the energy total badges and the statistics graph card (#54590)
The badges and the card subscribe to the energy collection through
EnergyCollectionController and consume contexts for everything else.
statistics-chart moves to contexts with them and regenerates on a theme
change. The controller unsubscribes when config() returns undefined, so
turning energy_date_selection off stops the subscription.
2026-10-06 09:40:38 +01:00
Bram KragtenandClaude Opus 5.5 5ca2ac68a3 Use standard Apache 2.0 license text so GitHub detects it (#54599)
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-06 10:35:17 +02:00
Petar Petrov eb43b1eab8 Migrate energy, power, gas and water cards to context instead of hass (#54560)
* Migrate energy, power, gas and water cards to context instead of hass

The cards consume only the context slices they read. A new
EnergyCollectionController replaces SubscribeMixin for the energy
collection subscription. ha-chart-base, ha-sankey-chart and
hui-energy-period-selector move to contexts too, and the energy and
recorder helpers take Pick<HomeAssistant, ...> slices.

* Inline the energy collection Pick type

* Pass values instead of hass-shaped objects to energy and recorder helpers

The helpers take states, formatEntityName, callWS, locale or panelUrl
directly. getEnergyDataCollection takes the connection plus an options
object, since it needs several inputs.

* Use consumeContext in EnergyCollectionController

The controller extends ContextController and declares its consumed
values as decorated fields instead of wiring each subscription by hand.

* Consume the internationalization context once in energy cards and charts

ha-chart-base, the period selector and the energy cards read both
localize and locale, so they consume the whole context as _i18n
instead of subscribing to it twice.

* Drop the connected-host guard from EnergyCollectionController

ContextController now defers its setup on connected hosts, so the
controller no longer needs to guard against running before its options
are set.
2026-10-06 10:27:06 +02:00
Petar Petrov 96684da7a7 Add a consumeContext decorator for reactive controllers (#54575)
* Add a consumeContext decorator for reactive controllers

Controllers extend ContextController and decorate their fields with
consumeContext({ context, subscribe, transform }). The base class keeps
each field current and calls contextUpdated() only when the transformed
value changes. ServiceInfoController uses it instead of its own
ContextSubscriptionController wiring.

* Defer context setup on connected hosts and check consumeContext fields

A controller created on a connected host no longer runs subclass code
from super(): Lit calls hostConnected() from addController(), so the
subscriptions are set up after construction instead. consumeContext
also rejects public fields that cannot hold the stored value, like
@consume does.
2026-10-06 10:08:11 +02:00
WendelinandClaude Sonnet 5.5 13e9127bdb Fix config entry state styling (#54584)
* Restore needs attention color on config entry rows

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PMDcr7YWpvXhByiZZqoeAc

* Restore config entry row state styling

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PMDcr7YWpvXhByiZZqoeAc

* Highlight config entry state with border color instead of tint

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PMDcr7YWpvXhByiZZqoeAc

* Add quiet fill background to config entry states

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PMDcr7YWpvXhByiZZqoeAc

* Use semantic colors for config entry state borders

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PMDcr7YWpvXhByiZZqoeAc

* Drop state border colors and use semantic text colors

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PMDcr7YWpvXhByiZZqoeAc

* Use semantic color for config entry link icon

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PMDcr7YWpvXhByiZZqoeAc

* Add divider between discovered and attention flow rows

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PMDcr7YWpvXhByiZZqoeAc

* Use semantic border and fill colors for discovered and attention lists

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PMDcr7YWpvXhByiZZqoeAc

* Use warning colors for discovered list too

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PMDcr7YWpvXhByiZZqoeAc

* Use standard divider color for flow list borders

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PMDcr7YWpvXhByiZZqoeAc

* Use border width token for flow list borders

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PMDcr7YWpvXhByiZZqoeAc

* Restore warning icon color for failed unload state

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PMDcr7YWpvXhByiZZqoeAc

* review

---------

Co-authored-by: Claude <[email protected]>
2026-10-06 09:59:54 +02:00
karwosts 9a45b6a200 Cleanup multiple unnecessary usages of entitySources (#54556)
* Cleanup multiple unnecessary usages of entitySources

* performance

* don't need entitySources for device integration

* memoize and filter device integration lookups

* Fix race condition fetching config entries

* Gate deviceIntegratonLookup in selector.ts on integration filter
2026-10-06 09:56:57 +03:00
Einar Skreslett a3f5929ddd Fix invisible inherited label tooltip text colour (#54521)
* fix invisible inherited label tooltip text colour

* fix tooltip while keeping theme text colour
2026-10-06 05:51:42 +00:00
Aidan Timson 0fed256025 Use context in Marketplace, prepare shared layouts for future context migrations (#54566)
* Read config and translations from context in shared layouts

* Use context instead of hass in Marketplace pages

* Provide contexts in Marketplace and tabs subpage tests

* Use provideHass for the Marketplace dialog test host

* Pass entities to tab page filters

* Update tab filters when entities change

* Fall back to hass localize in error screen

* Note when to inline error screen localize
2026-10-06 08:35:04 +03:00
ae3b3eefb3 Forward OAuth authorization parameters to the login flow (#54548)
* Forward OAuth authorization request parameters to the login flow

* Defer OAuth resource forwarding to a separate change

* Test preservation of empty PKCE parameters

* Do not forward state to the login flow

Core does not use state. The frontend appends it to the redirect
after the login flow finishes. The createLoginFlow type excludes
state, because Core rejects unknown fields.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Reduce the login flow change to forwarding response_type

Keep the positional createLoginFlow signature, the existing property
and import order, and the existing tests. Forward response_type and
send empty PKCE values instead of dropping them.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Paulus Schoutsen <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-06 08:33:40 +03:00
renovate[bot] 1e9d0432b3 Update dependency eslint to v10.12.0 (#54593)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-06 06:58:30 +02:00
renovate[bot] 60027ef4b1 Update pnpm to v12.9.0 (#54594)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-06 06:48:33 +02:00
Paul Bottein 5b25a220df Treat an entity name equal to its device name as no own name (#54585)
* Treat an entity name equal to its device name as no own name

* Use the same device name check when computing entity names

* Only check the user-set name against the device name

* Add tests for the device name check

* Clarify why only the user-set name is matched loosely
2026-10-05 18:54:27 +02:00
Paul Bottein 74c44e7c71 Fix first badges cut off in centered scrolling view header (#54565) 2026-10-05 18:50:36 +02:00
Paul Bottein 7b6561491a Fix option labels overflowing horizontal control selects (#54582) 2026-10-05 15:38:32 +00:00
Paul Bottein 17e0352ecf Show then branch before else in trace graph (#54583) 2026-10-05 17:03:31 +02:00
Maarten Lakerveld 7b379d587c Bump home-assistant-js-websocket to 9.7.1 (#54577)
Exclude our own packages from the 3-day minimumReleaseAge rule so
fixes we publish ourselves can be picked up immediately. The
no-downgrade trust policy still rejects unsigned releases.
2026-10-05 16:54:43 +02:00
Paul Bottein 6b32c87702 Fix map history paths flickering on every update (#54573)
Update map paths and zone circles in place instead of redrawing them
2026-10-05 15:40:34 +03:00
Jan-Philipp Benecke 2482b47d0b Hide dangling trace graph connectors when nothing follows (#54568) 2026-10-05 13:53:55 +02:00
Wendelin e9507ad201 Fix styling for config entry device rows (#54570) 2026-10-05 12:29:17 +01:00
Paul Bottein c26790e54d Add light color card feature with hue scrubber (#54219)
* Add light color card feature with hue scrubber

* Keep only the hue example in the scrubber gallery page

* Fix cancel event, card suggestion and white light hue in light color feature

* Update saturation gradient live while dragging hue

* Send terminal slider-moved after keyboard changes in scrubber

* Fix End key in wrap mode and keep focus when swapping light color controls

* Center collapsed hue preview on current hue and animate scrubber wrap by shortest path

* Hide the light color indicators when the light has no color
2026-10-05 12:16:16 +02:00
Aidan Timson 7eeca385a8 Shorten Marketplace warning countdown in development (#54564) 2026-10-05 11:55:17 +02:00
0149516743 Highlight the picker row that Enter would pick (#54319)
Co-authored-by: Claude Opus 5 <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2026-10-05 11:54:25 +02:00
karwosts a270426d98 Show entity diagnostic in a readonly editor w/ copy button (#54536) 2026-10-05 12:26:05 +03:00
Wendelin f8d70893a1 config-area-page fix missing list-item import (#54563) 2026-10-05 09:25:46 +00:00
karwosts 2cc6112d6f Fix stale missing entities in target picker (#54544) 2026-10-05 12:10:13 +03:00
Jason Hunter bfe09bd2e7 Preserve OAuth callback state through login and onboarding (#54547)
Preserve OAuth callback state when logging in and resuming onboarding
2026-10-05 09:52:41 +03:00
Jump-333 d1370c8577 Add source names for SoC badges (#54370)
* Add device names for SoC badges

* Fixed reload issues

* Removed useless fallback

* Modified badge name source

* Remove useless check
2026-10-05 08:19:33 +03:00
renovate[bot] 430890f401 Update dependency @types/node to v24.19.1 (#54553)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-05 07:05:29 +02:00
renovate[bot] ba536e13e7 Update home-assistant/actions digest to 06749dd (#54552)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-05 07:05:10 +02:00
renovate[bot] 4278d16a62 Update github/codeql-action action to v4.38.2 (#54555)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-05 07:04:46 +02:00
renovate[bot] 1c28b7fef1 Update dependency globals to v17.13.0 (#54539)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-04 21:04:49 +02:00
renovate[bot] f867b6186f Update dependency vite to v8.3.2 (#54541)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-04 19:50:00 +02:00
Paulus SchoutsenandClaude Opus 5.5 7432e63c16 Show the Marketplace risks alert full width without an icon (#54540)
* Show the Marketplace risks alert full width without an icon

The risks alert spans the full card width, so it reads as a band in the
card. The text aligns with the card content. The alert icon is hidden
because the heading already shows a large warning icon.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wt676c2KAQ1NnNWNRm7dV5

* Scope the full-width alert styles to the risks alert

The error alert for a failed acceptance keeps its icon, corners and
padding.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wt676c2KAQ1NnNWNRm7dV5

* Start-align the Marketplace warning heading and intro

The heading and intro line up with the risks and the checkbox below
them. The warning icon stays centered.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wt676c2KAQ1NnNWNRm7dV5

---------

Co-authored-by: Claude <[email protected]>
2026-10-04 19:49:40 +02:00
Paulus SchoutsenandClaude 0bda4a13ca Add the Marketplace to the demo (#54546)
The demo registers the Marketplace panel and mocks its read commands.
A list of community repositories shows on the discover, browse and
installed pages, and each repository has its own page. The warning
screen is skipped.

The mocks load with the config panel chunk. A loaded Marketplace config
entry lets the panel start. Commands that change the Marketplace, such
as install and uninstall, are not mocked.


Claude-Session: https://claude.ai/code/session_01Wt676c2KAQ1NnNWNRm7dV5

Co-authored-by: Claude <[email protected]>
2026-10-04 19:48:24 +02:00
karwosts dd0a0df88f Fix max_columns number selector (#54542) 2026-10-04 15:51:41 +02:00
renovate[bot] 6775b1e2bb Update vitest monorepo to v5.0.3 (#54535)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-04 08:56:20 +02:00
renovate[bot] 06df4046a9 Update pnpm to v12.8.2 (#54538)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-04 08:56:16 +02:00
renovate[bot] 634b6ddfcd Update dependency browserslist to v4.29.3 (#54531)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-03 08:06:47 +02:00
Paulus SchoutsenandClaude 970bb12856 Hide MCP URL hint until the server is enabled (#54532)
When the MCP server is not set up, the card has no URLs to show.
The description told the user to add one of the URLs below. Show
only the documentation link until the server is enabled.


Claude-Session: https://claude.ai/code/session_01MeyiXPWWRNRpD2XHVrtPSr

Co-authored-by: Claude <[email protected]>
2026-10-03 08:06:41 +02:00
Jan-Philipp Benecke c03750e605 Handle undefined trigger condition IDs in rendering (#54527)
* Handle undefined trigger condition IDs in rendering

* Handle trigger conditions without ID in editor and updates
2026-10-02 16:41:55 +02:00
Maarten Lakerveld 655e11ac1c Keep padded map fits within the poles (#54526)
The MapLibre engine pads a fit by a fraction of its span. A zone whose
circle reaches a pole, or markers far apart, pushed the padded
latitude past 90, and MapLibre throws on such bounds, so the fit never
happened and the console filled with errors. The padded latitude is
now clamped to the poles.

Fixes #54498
2026-10-02 15:03:02 +02:00
Paul Bottein b25cf13401 Add signed and offset modes to the duration selector (#54111)
* Add signed and offset modes to the duration selector

* Remove translation key from the duration selector

* Address review comments on the duration selector

* Expose the duration selector mode in the selector editor

* Remove allow_negative from the selector editor

* Migrate allow_negative to mode when editing a duration selector

* Derive the magnitude of mixed-sign legacy durations from their total

* Test the duration sign and value helpers

* Merge the duration sign helpers into normalizeDuration

* Omit the negative flag for positive signed durations

* Keep the pending offset type in local state instead of writing negative false

* Keep the offset type when the duration is cleared to zero

* Rename the offset type state

* Address remaining Copilot comments on the duration selector

* Simplify the duration sign handling

* Reset the offset type when the duration changes from outside

* Translate the duration selector mode in the selector editor

* Write negative durations as negative components instead of a negative key

* Simplify duration sign handling around a single normalizeDuration

* Keep the offset type as local state and refresh duration fields with live

* Forget the emitted duration after an external change

* Keep the duration sign at zero and use selector units everywhere

* Simplify duration sign handling and compute typed negative values

* Hide the clear button of offset durations
2026-10-02 09:02:45 +00:00
Wendelin 24c3ab6061 Use optional short issue title localization to repairs dialog (#54506)
Add short issue title localization to repairs dialog
2026-10-02 07:52:22 +00:00
Bram KragtenandClaude Opus 5.5 2c73378e9d Cache map tiles per asset class and stop refetching what still works (#54451)
* Cache map tiles per asset class and stop refetching what still works

The service worker kept glyphs, sprites and tiles in one 500-entry LRU, so
panning around evicted the fonts that every label on every map needs. Glyphs
and sprites move to a cache of their own, on the 30 day age core already sends
them with, and the tile ceiling goes up.

The TileJSON was deliberately left on the network because it is the switching
point for the tile source. Every map waits on it before asking for a tile
though, and at a five minute max-age that is a round trip before the first one.
Served stale-while-revalidate instead: out of the cache immediately, refreshed
behind it, so a moved endpoint still arrives.

The raster fallback redrew on every token rotation, refetching every tile on
screen twice an hour whether or not anything had failed. Later tiles pick up a
new token by themselves, so only a layer that actually had one refused needs
asking again - and since a refused tile is the only sign that path gets that
its token is stale, it now asks for a new one instead of waiting for the
refresh interval to come round.

Style requests that are in flight are shared, so a dashboard of maps, or a
theme toggle switching all of them at once, fetches each style once. Only while
in flight: a settled request is dropped, or a style that failed once would
never be fetched again.

Co-Authored-By: Claude Opus 5 <[email protected]>

* Hand the raster fallback the current map tiles token

A rotation is only announced once, so a vector layer that later falls back
handed the raster layer the token it was created with, and the refresh that
follows a refused tile fetches the already-current token and announces
nothing. The vector layer now tracks rotations itself.

Also covers in-flight style sharing, and passes a map style rather than
`false` in the raster recovery tests.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5 <[email protected]>
2026-10-02 09:50:33 +02:00
Paul Bottein d8e09dd120 Show entered and left in map zone activity (#54516)
* Show arrived and left in map zone activity

* Use entered instead of arrived in map zone activity
2026-10-02 07:49:26 +00:00
Jan-Philipp Benecke 6cdfafcbf9 Fix misplaced trace graph icons on iOS (#54520) 2026-10-02 09:40:29 +02:00
Elias Lecomte 4819cd6d27 Fix long source name overflow in energy dashboard totals (#54522)
* Fix long source name overflow in energy dashboard totals

* style: format with prettier
2026-10-02 09:39:16 +02:00
karwosts c5f099dab7 Remove spurious color clear button (#54515)
* Improve number selectors in section settings

* Fix sections editor default color
2026-10-02 09:33:42 +02:00
renovate[bot]andSimon Lamon 2da41b6e59 Update dependency zxing-wasm to v3.1.4 (#54480)
* Update dependency zxing-wasm to v3.1.4

* Update type-fest version to 5.10.0

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Simon Lamon <[email protected]>
2026-10-02 09:27:41 +02:00
renovate[bot] b7bb487208 Update pnpm to v12.8.1 (#54523)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-02 08:11:53 +03:00
renovate[bot] dfaf2a6f72 Update dependency @types/luxon to v3.7.6 (#54525)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-02 08:10:43 +03:00
renovate[bot] 8639ccde06 Update dependency typescript-eslint to v8.71.0 (#54517)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-01 20:07:31 +02:00
ee67f6b99f Add dependency review workflow (#54490)
* Add dependency review workflow with npm metadata checks

* Temporarily run dependency review on push

* Remove temporary push trigger from dependency review

* Encode the full package name in npm registry URLs

* Check optional/peer dependencies and fail on npm registry errors

Co-authored-by: timmo001 <[email protected]>

* Convert npm metadata check to TypeScript

* Type workflow scripts with Node 24 types instead of DOM

* Detect npm alias target changes as new dependencies

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-10-01 20:02:11 +02:00
renovate[bot] e569664724 Update dependency @rspack/core to v2.2.8 (#54514)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-01 19:58:07 +02:00
Maarten Lakerveld c113eb1f9a Fix map overview tabs, activity timeline, cluster counts, zone fit and the new-zone route (#54512)
* Show four avatars in a cluster bubble before counting

A bubble capped at three avatars added a +1 chip for the fourth
member, taking a fourth slot to hide one avatar. Four members now show
as four avatars; from five on, three avatars and a count fill the same
four slots.

* Open the new zone dialog on every visit to /config/zone/new

The route was only handled in firstUpdated. The config panel is kept
alive between visits and the router reuses the zone page when it is
already the current one, so "Create zone from current location" did
nothing once the zone list had been opened earlier in the session. The
route is now handled on every route change, like /edit/ already was.

The dialog also opened before the more-info dialog it was launched
from had finished leaving the history, and that departure closed the
new dialog again. The page now awaits the replace navigation, which
waits for closing dialogs, before opening it.

* Hide the map overview while the dashboard is being edited

In panel view edit mode the map card kept rendering its overview. On
phones that is a bottom sheet fixed over the bottom of the screen,
which covered the card's edit bar and the view's add button, so the
map dashboard could not be edited in portrait. The overview is for
using the map, not configuring it, so it is left out while editing.

* Show only the overview tabs that have something to list

People and Zones were always offered, with an empty message when the
map card's entities held none of them; only Devices was hidden when
empty. All three now appear only with entries, the first remaining tab
takes over when the selected one empties, and the overview tells the
card so its marker filter follows. The empty-tab messages are gone
with the empty tabs.

* List the person of the current user first, as "Me"

The overview's People tab sorted everyone alike. The person linked to
the user looking at the map now comes first and is named "Me" in the
list and the detail header, through a localized string. Their initials
still come from their real name.

* Draw the overview activity as a timeline

The activity list reused logbook rows: the person's name on every row,
the state pushed to the right, dividers between rows. It is now a
timeline of its own. Each row names where the person went, with the
clock time and how long ago underneath, hung off a dot in the zone's
color with a rail to the next row. A zone's rows name who came or
left and where they are. Five rows show at first, with a "Show more"
button for the rest. The overview no longer needs the broad hass
object, which only the logbook row took.

* Fit the map to its zones when they are all it shows

Zones only joined the auto-fit with the fit_zones option. The panel
map does not set it, so on the Zones tab, with no people or devices
left, the fit found nothing and jumped straight to the home
coordinates at the default zoom. Zones now stand in whenever nothing
else is on the map, which goes through the animated fit like the
other tabs. With fit_zones they still join a fit of people and devices.
2026-10-01 17:56:01 +02:00
Franck Nijhof 1f98d6ef6b Add Marketplace panel (#54437)
* Add store panel as a copy of the HACS frontend

Verbatim copy of src/ from hacs/frontend at d97dce0 into src/panels/store. Imports still point at the HACS submodule layout and the iframe shell is still present; this is the baseline for the port.

* Rewrite store panel imports and drop the iframe shell

Every import that pointed at the old `homeassistant-frontend` submodule now
resolves inside this repository's `src/` tree. Five components were renamed or
removed upstream, so they point at their current equivalents: `ha-button-menu`
and `ha-menu` to `ha-dropdown`, `ha-md-menu-item` to `ha-dropdown-item`,
`ha-fab` to `ha-button`, and `ha-circular-progress` to `ha-spinner`. The
`@material/mwc-button` and `@material/mwc-linear-progress` side-effect imports
are gone with them; those packages are no longer dependencies here.

`main.ts` becomes `ha-panel-store.ts` and registers `ha-panel-store`. It now
receives `hass`, `narrow`, `route` and `panel` from the panel resolver, so
everything that only made sense inside an iframe is removed: applying themes to
the parent element, forwarding haptic and keydown events to the main window,
bridging `location-changed`, the document-level navigation click handler, the
dialog manager, the injected body stylesheet, and the redirect to the default
route. `entrypoint.ts`, `extra.ts`, `html/` and `version.ts` are deleted for the
same reason.

* Move store panel translations into the frontend translation tree

The panel's own translation bundle is gone. Its keys now live under
`ui.panel.store` in `src/translations/en.json`, and `panel.store` gives the
sidebar its "Community store" title. Every `hacs.localize("some.key")` call
became `hass.localize("ui.panel.store.some.key")`, which means the `localize`
member on the `Hacs` interface, the `HacsLocalizeKeys` type and the localize
bootstrap in `HacsElement` are no longer needed. `TranslationDict` is derived
straight from `en.json`, so the moved keys type-check without any casts.

`dialog_about.frontend_version` did not come along: its only consumer was the
frontend version constant that went away with the iframe shell.

* Hold store panel state in the panel instead of a HACS mixin

The panel element now owns the repository list and the info payload as
internal state, loads both on first update and refreshes them from the
store/subscribe signals through SubscribeMixin. That drops the
HacsElement base class and its logger, so the hacs object handed to the
child components is plain data. Children that used to patch that object
with an update-hacs event now fire store-refresh instead and let the
panel refetch.

Also moves every WebSocket command over to the store/ prefix and trims
the info payload to what the backend still returns.

* Update the store panel to current frontend components

Rebuilds the panel on the components the frontend ships today: the
dialogs get their heading from ha-dialog itself and their buttons from
ha-dialog-footer, the overflow menus become ha-dropdown with
ha-dropdown-item, the download action becomes a fab-slotted ha-button,
and the progress and spinner indicators move to ha-progress-bar and
ha-spinner. brandsUrl loses the dropped useFallback option.

Also clears the eslint backlog the panel came in with: no arrow
functions in templates, no console calls, alt text on the brand images,
and private members named consistently.

* Register the store panel and route old HACS paths

Add the store panel to the panel resolver so the backend can serve it,
and move every internal navigation path in the panel from /hacs to
/store. The /hacsfiles static prefix stays, the backend serves it.

Repoint the hacs_repository my-redirect at the store panel and add a
store_repository alias next to it. Both keep the same target, so the
owner, repository, and category parameters still reach the panel's
redirect handler. Existing README badges keep working.

* Rename HACS to Community store in the store panel

Bring the ported panel in line with the repository conventions: panel
parts are ha-*, dialogs are dialog-* with a matching show-dialog-*
helper, and the typo in the overflow menu filename is fixed.

Rename the code identifiers to match, so the panel talks about a store
instead of HACS: StoreData, StoreInfo, StoreDispatchEvent, a store
property on the child elements, storeStyles and --store-* custom
properties.

Reword every user-facing string that named HACS. Backend names stay put:
the hacs_dispatch_* signal values, the /hacsfiles static prefix, the
hacs_repository my-redirect key, and the hacs.xyz documentation and
catalog infrastructure.

The stale HACS-REPOSITORY-PANEL nodeName check now matches the element
it was always meant to match, so removing a repository from its own page
navigates back again.

* Show a message when the store panel is opened without the integration

The panel is registered on every install while the integration is only set up on some, so an empty store must not try to talk to a backend that is not there.

* Link the Community store from the Settings dashboard

The store panel is hidden from the sidebar, so reach it from the Settings dashboard instead and give its pages a way back.

* Fit the store pages into the main layout

The repository page still sized itself to the viewport and the router recoloured the header with sidebar colours, both leftovers from running inside an iframe. Next to the sidebar that made the page a sidebar-width too wide, pushing the toolbar menu off-screen and un-centering the card.

* Let the quick bar create My links for store repositories

The repository page listened for the "m" key on the document body and opened a My link itself, which fought the quick bar's own "m" shortcut once the panel stopped living in an iframe. The quick bar now resolves a store repository page to the hacs_repository redirect by looking up the repository name, and the panel's handler is gone. The reload after installing a dashboard resource no longer goes through the main window helper, and unused scrollbar styles are dropped.

* Remove the external links from the store menu

The About dialog, the issue tracker link and the link to the HACS GitHub organisation pointed at a project outside Home Assistant. The store is part of Home Assistant now, so they go. The documentation link stays until the documentation moves.

* Fix runtime bugs in the store panel

* Remove external HACS leftovers from the store panel

* Tidy types and conventions in the store panel

* Clean up the store panel translations

* Give the store redirect error screen its hass and narrow properties

Without them the screen's back and refresh buttons render without labels.

* Use the store signal names and local resource URLs

The backend renames these in lockstep: the dispatcher signals lose their
`hacs_dispatch_` prefix, and downloaded dashboard resources are served
from `/local/community/` with a `v` cache-busting parameter instead of
the store-owned `/hacsfiles/` route and `hacstag`.

* Drop the disabled reasons the store backend no longer reports

Setup failures now surface through the config entry state instead of a disabled store, so only the runtime reasons remain.

* Rename the Community store to Marketplace

The panel, its elements, dialogs, data types, WebSocket commands,
dispatcher signals and translations now use marketplace, matching the
renamed backend domain. The hacs_repository My link keeps its slug.

* Finish the Marketplace panel

* Confirm replacing a built-in integration with the download

* Fix README links, older versions and grouping in the Marketplace panel

* Handle list continuations and placeholder characters in Marketplace READMEs

- Indented lines inside a list item are treated as text, so their links and issue references get rewritten.
- A README that already contains the private placeholder characters is left alone.

* Keep indented code inside list items literal in Marketplace READMEs

* Fix the warning title, icon colors and dead subscriptions in the Marketplace panel

- The warning takes its title from the Marketplace translations, it is not empty on a direct visit.
- Icons keep the colors of the menu or chip they are in.
- Dismissing new repositories is offered whatever the filters show.
- The dialogs no longer subscribe to an error signal the backend never sends.
- The custom repositories list names the category in the language of the user.

* Handle the edges of the Marketplace panel more carefully

- The warning can be continued again when the panel did not take over.
- Only a query with an owner and a repository opens a repository as a My link.
- Links to /hacs inside Home Assistant open the Marketplace.
- A rate limit after the download dialog closed opens nothing.
- A removed entry takes its catalog with it.
- The quick bar says why it could not make a My link for a repository.

* Type the Marketplace panel against the backend contract

- The data types match what the backend sends.
- Errors are caught as unknown and read through one helper.
- Events are typed from their declarations.
- Spacing uses the theme tokens.

* Make the wording of Marketplace actions clearer

* Leave the way back from the Marketplace warning to the header

* Show the download progress in the Marketplace download dialog

* Offer to set up a newly downloaded integration right away

* Make the Marketplace download dialog plainer and move other versions to the menu

- One sentence says what the download or update does, no paths or technical details.
- Warnings span the top of the dialog, like in the more-info dialog.
- The progress shows where the update dialog shows it, and the button shows it is busy.
- A restart is only mentioned for updates of integrations.
- Choosing another version moved to the repository menu, it opens on its own when the newest version is too new.

* Use the consume decorator of the frontend in the Marketplace dialogs

* Save the Marketplace search, and keep search and filters per session

* Lay out the Marketplace repository page like the other Settings detail pages

* Bring the Marketplace list page in line with the other Settings lists

* Use the standard Settings dialogs, styles and strings in the Marketplace

* Name the Marketplace data helpers like the rest of the frontend and drop the global refresh event

* Center the Marketplace warning and say how long accepting it lasts

* Call it installing in the Marketplace, and set up right after installing

* Use the uninstall command of the Marketplace

* Fix the row menu, the failed setup screen and README links in the Marketplace panel

* Guide uninstalling an integration that is in use, and offer it after deleting the last entry

* Fix reinstalling, filters, stale pages and README handling in the Marketplace panel

* Explain why an integration in use can not be uninstalled

* Test that accepting the warning and uninstalling in use really happen

* Point HACS links and icons at the Marketplace, and clarify its copy

* Share the error message and menu rendering of the Marketplace panel

* Split the long renders of the Marketplace panel

* Treat Marketplace repository ids as strings

* Guide the user after installing or uninstalling from the Marketplace

* Count down before the Marketplace warning can be accepted, and show it only once

* Show what to do next and who made it on the Marketplace repository page

* Title the Marketplace repository page Marketplace and keep signals one line

* Say which Home Assistant a Marketplace repository requires

"Works with Home Assistant 2025.1 or newer" read as a promise it had been tried there. It is a minimum the repository asks for, so say it that way.

* Explain adding to the Marketplace from a GitHub link

The dialog was called "Custom repositories" and opened on a list of them. Someone adding their first one saw an empty list and two bare fields.

It now says what it is for, and that what is added this way is made by the community like everything else in the Marketplace. Both fields say what they want. The list of what was added from links comes after that, under its own heading, and only once there is any.

* Give the Marketplace Discover, Browse and Installed tabs

The Marketplace was one long table, grouped by status. Finding what you have installed, or what waits for an update, meant scrolling past everything else.

Discover opens with what is popular and what changed lately. Each section links to Browse, sorted and filtered the way the section picked from it. The sorting and filters are in that link, so it works in a new tab or when shared too. Browse is the full table, without the grouping. Installed lists only what is installed, and its tab says how many updates wait.

On the tables, the icon shows a check for what is installed and an arrow for what waits for an update. The search says how many items it looks through. Adding from a GitHub link also got its own button in the toolbar.

Tabs take an optional badge for the update count.

* Find out what is added from a link in the Marketplace

The dialog asks only for the link. What it holds is found out when it is added, and only when that does not settle it, the dialog asks for the type, from what it might be.

* Fix races and lost answers in the Marketplace panel

The add from link dialog could add another link than the one it looked at, a See all link followed a second time kept the filters of the first, Retry did not retry a My link, and a My link that finished late replaced the repository opened meanwhile. A /hacs link from a dashboard showed the Marketplace without its translations. Uninstalling after deleting the last entry could hang when it failed, and a failed removal from the list closed as if it worked. Code inside a quote in a README got issue links.

* Tidy up small things in the Marketplace panel

The README was prepared again for every change of an entity, a screen reader heard the name of a tab but not its badge, and four exports and a type member were left from before.

* Show Marketplace errors in the language of the user and refresh less

Errors from the backend are translated with their key and placeholders in
the panel and when offering to uninstall after deleting an entry, with the
message of Home Assistant as fallback. The repository page reloads after
updating its information, since the list does not carry everything it
shows. Repository signals share one list request, with one more after it
when anything changed meanwhile, and Discover parses each date once.

* Fix the Marketplace strings that showed placeholders and wrong plurals

The add repository question showed {repository} literally, the quotes
around it escaped the placeholder. Seconds, downloads, stars and issues
now say one instead of ones, the status names match across the list and
the repository page, and the GitHub and log messages read the same as
the rest.

* Handle the review of the Marketplace panel

Links to /hacs reach beforeRender again, a route alias was resolved
before it. A refetch on a signal no longer opens the GitHub dialog by
itself, a failed release list is told once, and a failed first load is
translated without logging to the console. Deleting an entry only offers
the uninstall for custom integrations, after the restart and credential
prompts. The YAML resource address carries the version and is encoded.
Applied links mark their history entry instead of listening on the
window, and the last updated column sorts on a number.

* Rewrite Marketplace README addresses once they are rendered

ha-markdown gets an optional rewriteUrl, which runs over every link and
image of the rendered HTML in an inert template, before anything loads.
The README of a repository uses it, so reference links, entities and
unquoted attributes no longer slip through as addresses on Home
Assistant. The regular expressions that set aside links and addresses
for issue references only start where those can start, a README with a
long word or many unclosed links no longer freezes the page.
2026-10-01 11:19:21 -04:00
renovate[bot] e01f5b830f Update dependency @versatiles/style to v6.0.3 (#54509) 2026-10-01 15:45:05 +01:00
Petar Petrov b85cd00cc8 Detect the ESPHome Z-Wave discovery flow by the device MAC (#54513) 2026-10-01 16:44:38 +02:00
Paul Bottein e63fe4d631 Fix area switch for entities without their own name (#54503) 2026-10-01 15:30:53 +02:00
Aidan Timson d24d9d6051 Replace ha-ripple Material base with own implementation (#54508)
* Replace ha-ripple Material base with own implementation

* Remove ha-ripple origin comment

* Restore ha-ripple control setter and CSS zoom handling

* Defer ha-ripple forced-colors check to event handling
2026-10-01 15:10:44 +02:00
Bram Kragten 6c882f47bb Resolve split devices in the logbook card (#54507) 2026-10-01 14:59:12 +02:00
Petar Petrov 3689442f43 Fix double side padding around more-info history and activity (#54511) 2026-10-01 14:16:18 +02:00
Bram KragtenandClaude Opus 5 d19635b6bd Draw the globe against a sky when the map is zoomed out (#54485)
Co-authored-by: Claude Opus 5 <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-01 14:14:40 +02:00
Bram KragtenandClaude Opus 5 6ef7072e08 Add ha/no-unused-element-import lint rule (#54210)
Co-authored-by: Claude Opus 5 <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-01 13:27:03 +02:00
renovate[bot] 36829e0e05 Update dependency browserslist to v4.29.2 (#54504)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-01 11:46:51 +02:00
574c89b5fd Update dependency sortablejs to v1.15.7 (#54476)
* Update dependency sortablejs to v1.15.7

* Move sortablejs patch to 1.15.7 and update lockfile

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: timmo001 <[email protected]>
2026-10-01 12:34:39 +03:00
4384336476 Migrate combo box item to new lists (#54453)
* Move pickers onto the new list components

Pickers, the quick bar, the automation element search and the card
picker entity tree now use ha-list-base and its item family instead of
Material Web list items.

- Add a virtual-focus mode to ha-list-base and ha-list-virtualized:
  focus stays in a search field and the list marks the active row.
- Render picker rows as ha-list-item-option, with the current value as
  the selected option.
- Make ha-combo-box-item a presentational row layout on ha-row-item.
- Render ha-picker-field as a native button with the clear button next
  to it.
- Let held arrow keys repeat in pickers and the automation search.
- Fix list items not unregistering after they leave the DOM, and an
  unhandled rejection when a virtualized list is removed mid-layout.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Fix section titles

* fix e2e

* mage entity tree search like picker and automation

* remove comments

* fix picker field aria label

* fix disabled field style selector

* Update src/components/ha-picker-combo-box.ts

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-10-01 08:46:56 +00:00
Paul Bottein bc5eb1af2d Give zones their own map colors and prefer white zone icons (#54499)
* Give zones their own map color sequence

* Prefer white zone icons when contrast allows
2026-10-01 10:43:10 +02:00
renovate[bot] 6c81951d88 Update pnpm to v12.8.0 (#54502) 2026-10-01 09:23:18 +01:00
renovate[bot]andPetar Petrov 36b31d2c50 Update dependency tinykeys to v4.0.1 (#54479)
* Update dependency tinykeys to v4.0.1

* Move tinykeys patch to 4.0.1 and update lockfile

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <[email protected]>
2026-10-01 10:06:16 +02:00
Aidan Timson e98710867f Ignore .pnpm-store directory (#54500) 2026-10-01 07:55:01 +00:00
renovate[bot] b5afb05d7b Update dependency @lezer/highlight to v1.2.5 (#54501) 2026-10-01 07:53:56 +00:00
Aidan Timson 3f882c9a9b Type check workflow scripts (#54494)
* Convert workflow scripts to TypeScript

* Type check workflow scripts in lint:types
2026-10-01 08:39:21 +01:00
renovate[bot] 94c7d6e20a Update dependency @versatiles/style to v6.0.2 (#54497)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-01 08:25:05 +03:00
Bram KragtenandClaude Opus 5 8acc456dfd Hash the pnpm patches directory in the rspack cache version (#54478)
The persistent cache version still hashed `.yarn/patches`, which moved to
`patches/` in #54392. The lookup is guarded by `existsSync`, so it failed
silently and patch contents stopped contributing to the version at all.

That hash is the only thing that notices a patch change: a patch alters a
package's files but not its version, which is all rspack's node_modules
snapshot checks. Editing a patch therefore left the cache version
identical and the build reused stale compiled modules.

Co-authored-by: Claude Opus 5 <[email protected]>
2026-10-01 08:22:39 +03:00
Tom Mittelstädtand1358 d68a113f4c Give tentative calendar events a striped background (#54483)
* Give tentative calendar events a striped background

A tentative bar gets a light fill in its calendar color with diagonal stripes in the text color, instead of the outline alone. A tentative dot keeps its color and size and gets stripes in the calendar's contrast color. The stripes set a tentative event apart from past days, which are already drawn faded. They repeat on whole pixels, so every stripe looks the same.

* Strengthen tentative dot stripes and add a forced-colors fallback

The stripes on a tentative dot are its only cue, so they now reach at least 3:1 against the dot. In forced colors the stripes and the dot's fill are dropped, so a tentative bar falls back to a dashed border and a tentative dot to a ring of the same size.

---------

Co-authored-by: 1358 <[email protected]>
2026-10-01 08:21:40 +03:00
karwosts 95a4ca587b Improve number selectors in section settings (#54487) 2026-10-01 08:17:13 +03:00
Jan Čermák f5ac90a1f9 Copy locale data to the landing page build (#54488)
The landing page bundle includes the Intl polyfill. When a browser
needs a polyfill, it loads locale data from /static/locale-data/.
The landing page build never copied that directory, so these requests
returned 404. The language picker then showed raw language codes.

Fixes home-assistant/landingpage#216
2026-10-01 08:14:20 +03:00
renovate[bot] 6b060d3082 Update pnpm to v12 (#54486)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-30 21:41:00 +02:00
Bram Kragten 2f8bdf4260 Bump saturation of the default light mode map (#54492)
bump saturation of the default light mode map
2026-09-30 19:28:52 +00:00
Paul Bottein ee1e27772f Show people and zones on the demo map (#54496) 2026-09-30 21:19:22 +02:00
Bram Kragten d7f8d25a1d Bumped version to 20260930.0 2026-09-30 16:22:54 +02:00
Bram Kragten 33615bc5dc Merge branch 'rc' into dev 2026-09-30 16:21:00 +02:00
Bram Kragten 87105ea76a Fix ha-map crash when themes are not loaded yet (#54489) 2026-09-30 16:13:11 +02:00
Paul Bottein c1ea783993 Fade scrolling badges only where content is hidden (#54469)
* Fade scrolling badges only where content is hidden

* Add tests for the scroll fade controller

* Ignore Safari overscroll when fading scrolling badges
2026-09-30 16:01:10 +02:00
51e8f4792a Migrate chips from Material to Web Awesome (#54124)
* Migrate chips from Material to Web Awesome

* Fix button mock for chip inheritance in config flow tests

* Reflect chip disabled state and test chip interaction contracts

Co-authored-by: timmo001 <[email protected]>

* Delete test/components/chips.test.ts

* Restore legend chip sizing in chart and distribution card

* Skip chip set arrow navigation with a single chip

* Import ha-svg-icon in filter chip

* Improve chip disabled states, icon sizing and focus after removal

* Use toolbar role for chip sets only when labelled

* Drop href from disabled link chips

* Restore toolbar role for chip sets

* Forward referrerPolicy to link chips

Co-authored-by: timmo001 <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-09-30 16:55:06 +03:00
Bram KragtenandClaude Opus 5 e174e924e8 Let users pick and adjust the map style (#54477)
Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-30 15:54:51 +02:00
Petar Petrov 8c1ef5954a Address review feedback on the ESPHome device setup (#54474) 2026-09-30 14:56:42 +02:00
Maarten Lakerveld 82a6dffe29 Map bug fixes - Show map markers per overview tab, hide markers behind the globe, and cluster bubbling fixes (#54467) 2026-09-30 14:55:40 +02:00
renovate[bot] 8a916c56a5 Update dependency @lezer/common to v1.5.3 (#54475) 2026-09-30 11:44:42 +00:00
Bram KragtenandClaude Opus 5 6834cce8d6 Recolor the default vector map style (#54473)
Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-30 13:35:13 +02:00
Franck NijhofandClaude 2679d83028 Migrate from Yarn to pnpm (#54392)
* Migrate from Yarn to pnpm

Switch the package manager to pnpm 11, keeping every resolved
dependency version from yarn.lock.

- Move resolutions to pnpm overrides and Yarn patches to patches/
- Enable supply-chain protection: 3 day minimum release age,
  trust policy that blocks provenance downgrades, and dependency
  build scripts denied by default
- Declare dependencies that were imported but only available through
  Yarn's hoisting: zrender, @lezer/common, zxing-wasm,
  @babel/helper-compilation-targets, core-js-compat, @types/geojson
- Look up pinned license overrides in pnpm's node_modules layout
- Update CI, scripts, git hooks, Renovate, and documentation

* Cache the pnpm store with node_modules in CI

Jobs that restore the shared node_modules cache skip the install, so
the pnpm store is empty there. The license file generation runs
`pnpm licenses list`, which reads package metadata from the store and
fails without it.

* Point the demo e2e comment at the real test:e2e:demo script

---------

Co-authored-by: Claude <[email protected]>
2026-09-30 11:32:16 +00:00
Petar Petrov ddd1db7961 Add ESPHome device setup checklist (#53781)
* Add an ESPHome device setup checklist on the device page.

Surface advertised proxy capabilities in a banner and dialog so users can continue Bluetooth, audio, Z-Wave, and serial setup after the device is added.

* Harden the ESPHome setup wizard after review feedback.

Show cached capabilities while offline, wait for user data before the banner, and expose setup status to assistive tech.

* Mark ESPHome serial setup completed when a UART port is in use.

* Mark ESPHome Z-Wave setup completed when zwave_js matches the proxy home ID.

* Align the ESPHome setup wizard with Sendspin audio and the existing add-integration dialog.

Music stays incomplete until Music Assistant is installed and Sendspin is on, and serial setup no longer offers a hardcoded integration list.

* Fix storage chart size labels after bidirectional isolate

bidiIsolate can return undefined, so the gigabyte formatter needs a string fallback for the type check.

* Show the ESPHome setup banner only for music, Z-Wave, or serial devices, and use the finished headline once nothing remains to set up.

* Let the ESPHome music row finish once Music Assistant is installed.

The Sendspin switch is optional and matched by object id, a finished checklist uses the reminder, and the storage chart label matches dev after the bidiIsolate change.

* Give ESPHome music setup its own sequence so Sendspin is enabled after the Music Assistant offer.

* Show ESPHome audio install progress after the offer buttons hide, and drop the guest PIN step until that switch exists.

* Keep ESPHome setup on the device's own Z-Wave and music steps when discovery already started or Music Assistant is cancelled.

A detected controller was treated as not started, cancelling the Music Assistant dialog still enabled Sendspin, and a missing discovery flow opened a generic Z-Wave flow.

* Keep ESPHome setup honest when USB usage or Z-Wave flow lookup fails.

A failed USB scan was shown as unused ports, overlapping capability requests could overwrite a newer result, and a rejected Z-Wave flow lookup never showed the retry error.

* Use the repo consume decorator in the ESPHome setup UI.
2026-09-30 14:17:17 +03:00
Tom Mittelstädtand1358 3f4c57d31b Mark tentative calendar events (#54457)
* Mark tentative calendar events

A tentative event is drawn hollow: a ring instead of a dot and an outline instead of a filled block. The event dialog names the status. Confirmed events and events without a status look as before.

* Remove the tests for tentative events

---------

Co-authored-by: 1358 <[email protected]>
2026-09-30 13:53:31 +03:00
Aidan Timson 619abbc55f Note addressed review threads so they can be resolved (#54471) 2026-09-30 10:48:10 +00:00
Aidan Timson 5361cf04cd Make review comments lead with removal of unwanted code (#54470)
Lead review comments with removal when guidance rules code out
2026-09-30 12:37:18 +02:00
Faizan Saiyed 305b7cbc4b Fix light color temperature gradient in RTL (#54468) 2026-09-30 10:30:57 +00:00
Marcin BauerandClaude Opus 5.5 468afadee2 Keep bottom sheet header fixed while content scrolls (#54466)
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-09-30 11:05:04 +01:00
Petar Petrov 06ac6a59be Patch ECharts so pinch zoom follows the fingers (#54465) 2026-09-30 11:31:28 +02:00
Artur Pragacz 37827ea9a2 Fix computed entity name in voice settings (#54454) 2026-09-30 10:32:37 +02:00
dependabot[bot] 1ff226ebbd Bump undici from 6.28.0 to 6.29.0 (#54462)
Bumps [undici](https://github.com/nodejs/undici) from 6.28.0 to 6.29.0.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v6.28.0...v6.29.0)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 6.29.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-30 06:45:58 +02:00
7de77d5f91 Skip remaining upstream-only workflows on forks (#54458)
Forks lack the RelativeCI, Lokalise, and wheels secrets, so these
workflows fail on every sync of a fork's dev branch and email the fork
owner. Release Drafter also creates a stray draft release on the fork.

Guard them with the same repository check as the scheduled workflows:
- RelativeCI upload jobs (workflow_run after CI)
- Translations upload (push to dev touching en.json)
- Release Drafter (push to dev)
- Release landing-page job (release published)

Co-authored-by: Paulus Schoutsen <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-09-29 21:59:12 +02:00
karwosts 12226569a3 Fix two invalid attributes (#54456) 2026-09-29 19:34:16 +02:00
Bram KragtenandClaude Opus 5 8e061973ee Send the map tiles token in a header, so tile URLs stop rotating (#54452)
The access token rotates every half hour and lives in the query string, so it
is part of the browser's cache key: every rotation orphans every cached tile,
and the week-long max-age core sends is worth nothing. The service worker works
around it by stripping the token from its own cache key, but a service worker
only runs on https or localhost - on a plain http LAN origin, which is how a
lot of instances and the companion apps are reached, there is no cache at all
between the map and the network.

Anything that can set a header sends the token there instead, which leaves the
URL, and with it the cache key, stable across rotations. Raster tiles come from
an <img> and stay on the query parameter, and so does Cast: cross-origin a
custom header would cost a CORS preflight per tile.

Needs the matching core change; against a core without it the proxy refuses
every tile.

Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-29 16:30:54 +00:00
karwosts e427136cdc Fix cover/value more-info icons (#54455) 2026-09-29 16:14:32 +00:00
b7aa648f0b Automation row threshold details (#54049)
* Add ha-automation-row-threshold component and integrate with automation rows

* Update ha-automation-row-behavior config property to be optional and adjust condition rendering based on target entity count

* Fix order and review

* add format number

* remove row-behavior and adopt row order

* Update range formatting to use an en dash

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Fix minus

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: MindFreeze <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-29 17:12:52 +02:00
Paul Bottein 2ea40a6b96 Add button role and label to card and badge edit controls (#54449) 2026-09-29 17:06:30 +02:00
Markus TuominenandClaude Fable 5.1 924b55c443 Fix description of the enable new entities system option (#54446)
The description said newly discovered devices would be automatically
added, but the setting controls whether newly discovered entities are
enabled. Devices and entities are still added either way; when the
option is off, new entities are created disabled.

Co-authored-by: Claude Fable 5.1 <[email protected]>
2026-09-29 15:02:44 +00:00
WendelinandClaude Opus 5.5 cb971dc1a3 Replace ContextConsumer with ContextSubscriptionController (#54450)
* Replace ContextConsumer with ContextSubscriptionController

`@lit/context`'s `ContextConsumer` has the same problem as its `consume`
decorator: it calls `host.requestUpdate()` on every provider notification.

- Migrate `ha-map`, `hui-map-card`, `automation-trigger-controller` and
  `service-info-controller` to `ContextSubscriptionController`. Their
  callbacks already write to `@state()` fields or request an update
  themselves when the result changes.
- Accept any `ReactiveControllerHost` element as controller host, so plain
  controllers can use it.
- Forbid importing `ContextConsumer` from `@lit/context` with ESLint.
- Document the controller in the contexts skill.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UFoL6HHkeK4X9gx4xo9of6

* Use own consume in profile dialog and picture upload

Both were added in #54400 with `consume` from `@lit/context`, which the
lint rule now forbids and which forces a host update on every context
change.

Drop `@state()` from the consumed fields that are only read outside the
render cycle: `_api` and `_connection` in both components, and `_states`
and `_hassConfig` in the profile dialog, which only seeds its form from
them in `connectedCallback`.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UFoL6HHkeK4X9gx4xo9of6

---------

Co-authored-by: Claude <[email protected]>
2026-09-29 16:55:20 +02:00
Paul Bottein 74adb1da49 Add UI support for section strategies (#54040)
* Add UI support for section strategies

* Use card editor style YAML toggle for sections
2026-09-29 16:12:12 +02:00
renovate[bot] 682c68c1e3 Update dependency maplibre-gl to v6.11.2 (#54448) 2026-09-29 14:09:01 +00:00
68c5e080ac Update dependency maplibre-gl to v6 [SECURITY] (#54073)
Co-authored-by: Maarten Lakerveld <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: bramkragten <[email protected]>
Co-authored-by: Bram Kragten <[email protected]>
2026-09-29 15:58:42 +02:00
Jeremy Cook c3d872734d Stop cropping tile info text in fixed-height grid cells (#54237) 2026-09-29 14:28:21 +01:00
WendelinandClaude 5fb0090c71 Add own consume decorator that does not force host updates (#54443)
Co-authored-by: Claude <[email protected]>
2026-09-29 15:04:51 +02:00
Wendelin 498a25a488 Fix target picker section height (#54445) 2026-09-29 16:00:53 +03:00
Franck NijhofandClaude Opus 5.5 e908f75074 Let users edit their own name and picture from their profile (#54400)
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Claude <[email protected]>
2026-09-29 13:25:27 +02:00
Petar Petrov 5054c17381 Render login fields in the light DOM so password managers can find them (#54278) 2026-09-29 12:31:24 +02:00
Aidan Timson e30caa464f Show load errors on config data table pages (#54434)
* Show config entry load errors with retry on devices page

* Show load errors on config data table pages

* Show load errors in the data table

* Use data table load errors on config pages

* Keep table semantics and block retries during load errors

* Add default load error text and English fallbacks to data table
2026-09-29 12:18:43 +02:00
Aidan Timson 27c06e067c Show skeleton rows while data tables load (#54328)
* Show skeleton rows while data tables load

* Use skeleton placeholders for devices metadata

* Announce data table loading to screen readers

* Inline data table skeleton rows

* Simplify devices metadata placeholders

* Show loading state in more config data tables

* Leave Bluetooth advertisement loading for the follow-up

* Preserve table cell semantics while loading

* Show loading labels for pending integration groups

* Handle devices page load failures

* Show config entry load errors with retry on devices page

* Move data table cell helpers into the class

* Remove config entries reload listener on disconnect

* Say error in devices integrations load failure text

* Clarify devices integrations load failure has an unknown cause

* Move devices load failure alert to a follow-up

* Show dashboards skeleton until custom dashboards load
2026-09-29 11:37:17 +02:00
Paul Bottein cacfb940f6 Use the device area when the entity uses the device name (#54235)
* Use the device area when the entity uses the device name

* Keep the device area switch off after turning it off
2026-09-29 09:52:32 +02:00
Paul Bottein 73451bb8b4 Add a switch to use the device name for entities (#54021)
* Add a checkbox to use the device name for entities

* Replace checkbox with a use device name switch row

* Only treat an empty name as using the device name

* Keep child view titles in the settings view

* Use row item for the device name row

* Treat an empty entity name as using the device name

* Remove unused icon button next import

* Follow the device name when renaming entities named after their device

* Keep the empty name when renaming Z-Wave entities

* Use the device name for ZHA entities with an empty name
2026-09-29 09:31:50 +02:00
Paul Bottein 717e79063b Omit owners in another area from entity context (#54193)
* Omit owners in another area from entity context

* Rename context source to next name part

* Use picker display for entity editor rows
2026-09-29 09:19:18 +02:00
renovate[bot] 25259ff668 Update dependency lint-staged to v17.6.0 (#54442)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-29 09:49:57 +03:00
João Pedro Hickmann 955344b44c Use tap-to-show chart tooltips for touch input (#54353)
* Use tap-to-show chart tooltips for touch input

On mobile-size screens the tooltip already opens on a tap (#24083), but
touch devices above that size kept the hover trigger, so the tooltip
followed the finger. Touching the axis pointer handle, which sits below
the grid, then hid the tooltip and the handle, so the handle added for
touch devices (#26088) could not be dragged.

Open the tooltip on a tap whenever the chart is used with touch, and keep
hover for a mouse, also on devices that have both: the trigger follows the
pointer type of the last pointer event, which arrives before the touch and
mouse events echarts handles.

With the tooltip opened by a tap, a tap anywhere else on the page closes
it.

* Clean up the outside tap listener and treat pen as touch

Remove the outside tap listener when the chart is recreated, since the
new chart starts with its handle hidden and nothing would remove it.
Only switch to tap-to-show tooltips on touch devices, where the handle
and outside tap handlers are installed, and count a pen as touch as
echarts does. Restore the full echarts default trigger, including
mousewheel, when switching back to the mouse.

* Close the chart tooltip on a pen tap outside it

A pen counts as touch for tap-to-show tooltips, but it does not reliably
fire touch events, so tapping outside with a pen left the tooltip open.
Listen to pointerdown instead and leave out the mouse, since echarts
already hides the tooltip when the mouse leaves the chart.

* Switch the chart tooltip trigger in the capture phase
2026-09-29 09:33:16 +03:00
dependabot[bot] 4627b92de1 Bump ip-address from 10.5.0 to 10.7.2 (#54441)
Bumps [ip-address](https://github.com/beaugunderson/ip-address) from 10.5.0 to 10.7.2.
- [Release notes](https://github.com/beaugunderson/ip-address/releases)
- [Commits](https://github.com/beaugunderson/ip-address/compare/v10.5.0...v10.7.2)

---
updated-dependencies:
- dependency-name: ip-address
  dependency-version: 10.7.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-29 09:28:53 +03:00
Maarten Lakerveld ed2d316f00 Map marker styling (#54308)
* Expose CSS parts on ha-entity-marker

Styling tools can target ::part(marker) and ::part(picture) from the
map's scope, so a style applies to markers as they are created instead
of being re-injected into each new element. Documents the marker's
custom properties and parts as its styling surface.

* Reuse cluster bubble avatars across rebuilds

Cluster bubbles are rebuilt whenever the camera settles or an entity
changes state, and each rebuild created new ha-entity-marker elements.
Pictures were re-decoded, the entity state subscription was torn down
and set up again, and styles applied to a marker by styling tools were
lost on every pan or zoom.

Avatars are now cached per entity id and moved into the new bubble.
An avatar still on screen is left alone: Leaflet's markercluster keeps
the outgoing bubble visible during its zoom animation, and taking its
avatar would empty it mid-fade. Avatars of entities no longer shown are
dropped when entities are redrawn.

* Rebuild Leaflet cluster icons on every add

markercluster caches a cluster's icon object and re-appends the same bubble
element when zooming back out, without asking for a new one. Once avatars
are reused across bubbles, a cluster that splits (removed before its child
is created) loses its avatars to the child bubble and comes back empty.
Building the divIcon inside createIcon runs the builder on every add, so
the shown bubble always takes the avatars from the cache.

* Export the marker parts through ha-map

Both ha-entity-marker instances live in ha-map's shadow root, so their
parts were unreachable from outside. Each marker now exports them under
the generic names and per entity, e.g. marker-person-anne, so a page can
style one person's marker with ha-map::part(marker-person-anne).

* Reuse entity markers across redraws

Every state change of a listed entity redraws all markers, and until now
only cluster avatars kept their element. Standalone markers now come from
the same per-entity cache through one helper, which also carries the
reuse guard: an element still on screen is left alone and a fresh one
takes its place, since Leaflet keeps an outgoing bubble during its zoom
animation. Duplicate entities in one draw get their own element.
2026-09-29 09:18:06 +03:00
github-actions[bot]andpiitaya fd8bf65f3d Update sensor entity constants (#54440)
Co-authored-by: piitaya <[email protected]>
2026-09-29 06:16:39 +00:00
Maarten Lakerveld 5229607bb9 Versatiles style bump to v6 (#54432)
* Generate the map styles with @versatiles/style v6

v6 removed the colorful and eclipse builders; osm({ theme }) replaces
them, with eclipse mapping to the retuned colorful-dark palette. The
sprite sheet is renamed from basics to base and its icon ids change,
so core's tile proxy has to serve the base sheet before this ships.

v6 also defaults to the globe projection and the styles keep it. Only
the MapLibre engine renders them: from ha-map the Leaflet engine runs
without WebGL2 or raster-only after a MapLibre failure, so nothing
ties the map to Mercator any more.

* Bundle the VersaTiles base sprite sheet

The styles referenced the sprite sheet through core's proxy, which
fetched it from the OpenStreetMap Foundation. The OSMF only mirrors
the retired v5 basics sheet, and VersaTiles warns that the assets on
tiles.versatiles.org change with every release, so neither is a stable
source for the exact sheet the pinned @versatiles/style expects.

The base sheet now ships with the frontend under static/map/sprites,
fetched from the versatiles-style release matching the installed
package with `yarn gulp update-map-sprites`. The style build checks
that every icon the styles reference exists in the bundled sheet, so a
bump that renames icons fails the build instead of shipping POIs
without icons. Sprites resolve against the page rather than the
instance, since on Cast the frontend is not served by the instance,
and the demo no longer needs its own sprite override.

* Open a PR when the bundled map sprite sheet drifts

Runs the sprite update after a push to dev touches package.json, which
is how a @versatiles/style bump lands, and opens a PR with the
re-vendored sheet when it changed. Mirrors the device class and sensor
constant sync workflows.

* Exclude vendored map sprite metadata from Prettier

The sprite JSON is extracted verbatim from the @versatiles/style release
in its upstream compact form, which fails prettier --check. Ignoring it
keeps lint green and keeps the sync workflow's drift check byte-identical
with upstream.

* Format map-assets.js with Prettier

* Note that the sprite sheet ships with the frontend

The module header still said sprites come through core's proxy, which
stopped being true when the sheet was bundled.

* Gate merges on the bundled map sprite sheet

A @versatiles/style bump that references new icons used to fail only the
build job, which the dev ruleset does not require, so the bump could be
merged red and the post-merge sync workflow was left to repair it. Run
the sprite check in the required lint job instead, so the sheet has to be
re-vendored on the dependency PR itself, and drop the sync workflow that
existed to clean up after the merge.

* Only treat image properties as sprite references

The sprite check walked every string under layout and paint, so any
base-prefixed text value would have failed the required lint job without
asking for an image. Collect from the image-bearing properties only.

* Version the sprite URL with a hash of the vendored sheet

Core serves /static with a month of max-age and the service worker does
not precache the map assets, so a re-vendored sheet at the same URL would
keep coming from the browser cache next to a freshly fetched style that
expects the new icons. Append a short content hash of the four sheet
files as a query parameter. MapLibre appends the format and extension to
the pathname, so the query survives, and the test now guards that the
absolute-URL rewrite keeps it too.
2026-09-29 09:15:51 +03:00
karwosts e5ef589931 Fix Object object error messages from websocket errors (#54438)
* Fix Object object error messages from websocket errors

* simplify
2026-09-29 09:14:09 +03:00
dependabot[bot] 1ef136f851 Bump fast-uri from 3.1.6 to 3.1.8 (#54439)
Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.6 to 3.1.8.
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.6...v3.1.8)

---
updated-dependencies:
- dependency-name: fast-uri
  dependency-version: 3.1.8
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-29 09:13:18 +03:00
Paulus Schoutsen b3a7c35685 Revert "Add a user picker to an assist pipeline" (#54433)
Revert "Add a user picker to an assist pipeline (#54276)"

This reverts commit 0cb50303c3.
2026-09-28 18:12:58 +02:00
João Pedro Hickmann f3f42492ce Only start chart sonification from the keyboard (#54354)
* Only start chart sonification from the keyboard

Clicking or tapping a chart focuses it, which loaded Chart2Music and, once
connected, moved the tooltip to the first data point. On touch devices the
tooltip jumped to the start of the chart right after the first tap.

Chart2Music only responds to the keyboard, so start it on keyboard focus
(:focus-visible), or on the first key pressed in a chart that was focused
by pointer.

* Replay the key that starts chart sonification

Chart2Music only listens for keys once it is connected, so the first key
pressed on a chart focused by pointer only started loading it, and a
navigation key scrolled the page. Hold navigation keys and Space back
from the page while loading and replay the key once connected, unless a
page shortcut already handled it. Lone modifiers, Meta shortcuts and
Ctrl or Alt with anything but a navigation key are left to the browser.

* Move the chart keydown listener above the focus listeners

Keeps it apart from the pointer listeners added in #54353, so the two
PRs merge without conflicts.

* Drop the keyboard fallback and key replay, only start on focus-visible
2026-09-28 16:45:59 +03:00
Maarten Lakerveld 50b0b3f493 Fix the device class and sensor constant sync workflows (#54431) 2026-09-28 15:24:56 +02:00
Petar Petrov c49085e830 Show battery discharge per battery in energy usage graph (#54341) 2026-09-28 14:52:42 +02:00
d9ac1c1452 Update dependency prettier to v3.9.9 (#54397)
Co-authored-by: timmo001 <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-09-28 14:40:28 +02:00
João Pedro Hickmann 93c1543127 Hide the chart tooltip while panning with the mouse (#54356)
* Hide the chart tooltip while panning with the mouse

Dragging a zoomed chart with the mouse pans it, and the tooltip kept
following the pointer across the moving data. Hide it while the pan moves
the chart, from the datazoom handler, and show it again when the mouse
button is released, also when that happens outside the chart.

* Restore the configured tooltip visibility after panning

Reset the press and pan state on disconnect, and hide and restore each
configured tooltip instead of forcing a single tooltip on.

* Only track primary mouse button presses for panning

A right click could leave the press flag set when the context menu took
the mouseup, and zrender doesn't mark touch as touch when it listens to
pointer events, as on Edge. Either way a later zoom hid the tooltip.

* Move the pan state cleanup and helpers away from #54353's changes

Resets the pan state after the legend cleanup and places the mouseup and
tooltip helpers after the data zoom handler, so the two PRs merge
without conflicts.

* Use the zrender mouseup to end panning instead of a window listener
2026-09-28 15:40:13 +03:00
Aidan Timson e16f683a5a Share shadow root host lookup (#54430) 2026-09-28 13:49:11 +02:00
Paul Bottein 99d2742f4a Fix list item supporting text ellipsis (#54429) 2026-09-28 11:27:27 +00:00
WendelinandClaude Opus 5.5 ca51e06181 Fix dev server failing after translation changes (#54420)
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Claude <[email protected]>
2026-09-28 11:54:15 +01:00
renovate[bot] c8593510c4 Update vitest monorepo to v5.0.2 (#54426) 2026-09-28 10:49:27 +00:00
renovate[bot]andPetar Petrov dbc9bf2288 Update formatjs (#54414)
Co-authored-by: Petar Petrov <[email protected]>
2026-09-28 11:41:44 +01:00
WendelinandClaude 410e22388b Fix bidiIsolate return type for string input (#54427)
Add overloads so bidiIsolate returns string when given a string,
fixing the type error in storage-breakdown-chart introduced in #54205.


Claude-Session: https://claude.ai/code/session_01Rtu8Rd2oU3DM6oiy23f63z

Co-authored-by: Claude <[email protected]>
2026-09-28 10:38:48 +00:00
renovate[bot] 16183f9ecf Update dependency intl-messageformat to v12 (#54424) 2026-09-28 11:15:53 +02:00
Yosi LevyandCopilot Autofix powered by AI 2386e84da4 RTL fixes - units (#54205)
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-28 11:10:55 +02:00
Petar Petrov 90aa8462fb Fix date range picker ranges in server time zone mode (#54422) 2026-09-28 11:03:34 +02:00
Petar Petrov 11d41b837f Fix energy ranges counting an extra day across time zones (#54423)
* Fix energy ranges counting an extra day across time zones

* Test energy statistics request ranges
2026-09-28 10:52:38 +02:00
João Pedro Hickmann 83af6058b7 Fix chart tooltip lag when dragging on touch devices (#54352) 2026-09-28 10:25:22 +02:00
WendelinandClaude 788eb4d781 Show app count in installed apps search placeholder (#54415)
Claude-Session: https://claude.ai/code/session_01SXNDbcPtJDCrtJZVzdj9uD

Co-authored-by: Claude <[email protected]>
2026-09-28 10:11:59 +03:00
renovate[bot] 9283c8ba91 Update Playwright (#54417)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-28 10:11:13 +03:00
renovate[bot] 0ec99e866b Update dependency jsdom to v30.1.1 (#54413)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-28 10:08:55 +03:00
karwosts 40d2aedc1d Restore by-card tab in footer dialog (#54403) 2026-09-28 08:59:25 +02:00
renovate[bot] 66321c57d2 Update dependency home-assistant-js-websocket to v9.7.0 (#54412)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-28 08:59:51 +03:00
renovate[bot] f990c85b32 Update dependency eslint to v10.11.0 (#54411)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-28 08:59:28 +03:00
nokside 97336c4009 Add default support to object selector fields (#53739)
* Add default support to object selector fields

* Clone object selector field defaults

* Use unknown for object selector defaults

* Use deepClone for object selector defaults
2026-09-28 08:42:28 +03:00
Dominik c3e84e4bb4 Remove backdrop from text-only markdown (#54390) 2026-09-28 08:41:56 +03:00
renovate[bot] 90f8e2f8d6 Update dependency browserslist to v4.29.1 (#54410)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-28 08:39:38 +03:00
renovate[bot] daaa673113 Update dependency @lokalise/node-api to v16.6.0 (#54409)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-28 08:39:12 +03:00
Paulus SchoutsenandClaude 113d645dad Hide the host in the MCP server URLs (#54375)
The MCP card showed the full URLs, which reveal the host of the
Home Assistant instance in screenshots. The card now shows only the
path. The copy button still copies the full URL.


Claude-Session: https://claude.ai/code/session_01GXiaNSBbB8C33fBL9yg5EP

Co-authored-by: Claude <[email protected]>
2026-09-28 05:57:05 +02:00
renovate[bot] 2d05e8f90f Update Yarn to v4.18.1 (#54407)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-28 05:53:15 +02:00
renovate[bot] c376786885 Update dependency @html-eslint/eslint-plugin to v0.66.1 (#54408)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-28 03:41:36 +00:00
renovate[bot] 61e15a6a4a Update dependency typescript-eslint to v8.70.1 (#54401)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-28 03:38:50 +00:00
Franck NijhofandClaude b4d65e3b83 Use a toggle for unlimited login attempts in HTTP config (#54399)
Use an unlimited toggle for the HTTP login attempts threshold

Core uses -1 to mean unlimited login attempts. Instead of asking users to
type -1, show an "Unlimited login attempts" toggle and only show the
number field when it is off. The -1 mapping stays internal to the form.

Co-authored-by: Claude <[email protected]>
2026-09-28 05:31:20 +02:00
renovate[bot] 728bb8055c Update dependency @lezer/highlight to v1.2.4 (#54387)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-28 05:29:27 +02:00
renovate[bot] 70e8cd376b Update dependency @rspack/core to v2.2.7 (#54388)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-28 05:29:09 +02:00
renovate[bot] 9fc555ced6 Update dependency fs-extra to v11.4.1 (#54394)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-28 05:28:40 +02:00
renovate[bot] 72b3a52a2e Update dependency js-yaml to v5.4.2 (#54395)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-28 05:28:21 +02:00
renovate[bot] dbbaa3e626 Update dependency marked to v18.0.14 (#54396)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-28 05:27:25 +02:00
renovate[bot] 11401b2a79 Update dependency vite to v8.3.1 (#54402)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-28 05:26:34 +02:00
renovate[bot] 01124ffbb2 Update vitest monorepo to v5.0.1 (#54405)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-28 05:26:01 +02:00
Allen Porter fd19a0e4e3 Forward PKCE code_challenge parameters in login flow (#54389)
* Forward PKCE code_challenge parameters in login flow

* Move auth data test to test/data/auth.test.ts
2026-09-27 17:59:30 -04:00
Marcel van der Veldt 40270f5a86 Send the right route to apps opened from their sidebar entry (#54404) 2026-09-27 17:58:26 -04:00
Franck Nijhof e7d76ce6c9 Move GitHub Actions updates from Dependabot to Renovate (#54382) 2026-09-27 19:34:43 +02:00
renovate[bot] 6c53fd6c4f Update CodeMirror (#54385)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-27 15:24:41 +02:00
renovate[bot] d54b818d83 Update babel monorepo to v8.0.6 (#54384)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-27 15:24:24 +02:00
Franck Nijhof c4f1a1bea2 Fix Renovate keeping the Playwright container update pending forever (#54380) 2026-09-27 15:24:10 +02:00
Felix Schneider 0cb50303c3 Add a user picker to an assist pipeline (#54276)
Let an assist pipeline act as a user

Needs home-assistant/core#182750.
2026-09-27 08:01:51 +00:00
Paulus SchoutsenandClaude Opus 5.5 d16e04a2b4 Enable the MCP server in one click (#54349)
* Enable MCP in one click and show discovered MCP servers

Enable now creates the Model Context Protocol Server entry without a
dialog and then opens the options flow. If the config flow still asks
for input, the config flow dialog opens instead.

The MCP card lists MCP servers that apps offer through Supervisor
discovery, with actions to add or ignore each one. The section is
hidden when nothing is discovered.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GXiaNSBbB8C33fBL9yg5EP

* Move discovered MCP servers to a separate pull request

This pull request only makes Enable create the Model Context Protocol
Server entry without a dialog.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GXiaNSBbB8C33fBL9yg5EP

* Keep the options closed after enabling the MCP server

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GXiaNSBbB8C33fBL9yg5EP

* Keep the Enable button loading until the MCP card reloads

The button became clickable again while the card was still loading
the new entry.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GXiaNSBbB8C33fBL9yg5EP

---------

Co-authored-by: Claude <[email protected]>
2026-09-27 07:42:38 +00:00
Paulus SchoutsenandClaude 21957ed41f Correct registry and auth API types in the frontend (#54288)
Compare the registry, auth and tag data modules with the handlers that
produce them, and fix the mismatches.

Updating a floor returned the floor entry, not an area. Looking up
extended entity entries returns null for an id the registry does not
know, so the callers now drop those before use.

Correct the refresh token payload, which was missing the provider type
and typed several always-present nullable fields as optional, and drop
a field the auth provider list does not return.


Claude-Session: https://claude.ai/code/session_01YDqKNfAAvMV7zJJNodsHfK

Co-authored-by: Claude <[email protected]>
2026-09-27 09:37:36 +02:00
Paulus SchoutsenandClaude Opus 5 8b5302ac06 Correct device protocol API types in the frontend (#54287)
* Correct device protocol API types in the frontend

Compare the Z-Wave, Zigbee, Matter, Thread, MQTT, Bluetooth and
ESPHome data modules with the handlers that produce them, and fix the
mismatches.

Widen the unions the backends have outgrown. The Zigbee radio type
gained a member the union did not list, and the Matter topology node
kind is documented as an open set.

Correct several declared results that never matched the wire,
including the rebuild and abort commands, the smart start calls, and
the log level setter. Mark the many controller and node fields the
Z-Wave server can omit as nullable, and split the MQTT debug message
type from the subscription message, which carries no timestamp.

Correct the Zigbee signal strength, which the frontend typed as text
and the library reports as a number.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YDqKNfAAvMV7zJJNodsHfK

* Separate the Z-Wave set config parameter result from its display state

The command reports a numeric SetValueStatus, but the type declared a
string status and an error field the backend never sends. The node
config view reused that type for its own row state, so it fed the
number straight into a translation key and the result line rendered
nothing.

Type the command result as sent, give the view its own state, and map
one to the other.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YDqKNfAAvMV7zJJNodsHfK

---------

Co-authored-by: Claude <[email protected]>
2026-09-27 09:36:11 +02:00
Paulus SchoutsenandClaude 4db73f6a3d Correct backup, onboarding and cloud API types in the frontend (#54286)
Compare the backup, onboarding and cloud data modules with the
handlers that produce them, and fix the mismatches.

Several backup calls declared the wrong result. Deleting a backup
returns agent errors, generating one returns a job id rather than a
backup id, and restoring one returns nothing. The backup list carries
extended content, not the base type.

Add the blocked manager state, which is the state the manager starts
in and replays to new subscribers, along with the event reason fields
and the core_restart restore state.

Correct the onboarding installation type, which listed a value the
backend never sends and omitted one it does, and narrow the cloud
onboarding status to the single field that endpoint returns.

Remove the cloud strict connection preference and its translations.
No such preference exists in core, so the warning it gated could never
render.


Claude-Session: https://claude.ai/code/session_01YDqKNfAAvMV7zJJNodsHfK

Co-authored-by: Claude <[email protected]>
2026-09-27 09:35:47 +02:00
Paulus SchoutsenandClaude 7c5a7c81e5 Hide MCP options for a disabled MCP server entry (#54369)
A disabled Model Context Protocol Server entry showed the URLs and the
options flow, although the server does not run. The card now shows
Enable instead, which enables the existing entry.


Claude-Session: https://claude.ai/code/session_01GXiaNSBbB8C33fBL9yg5EP

Co-authored-by: Claude <[email protected]>
2026-09-27 09:34:30 +02:00
karwosts 8da3713ec4 Standardize translation function for 'Ctrl' key. (#54368) 2026-09-27 09:33:47 +02:00
karwosts e7f60b8583 Fix multiple invocations of image cropper (#54376) 2026-09-27 09:32:09 +02:00
dependabot[bot] 6d7ecb90a1 Bump the codeql-action group across 1 directory with 2 updates (#54377)
Bumps the codeql-action group with 2 updates in the / directory: [github/codeql-action/init](https://github.com/github/codeql-action) and [github/codeql-action/analyze](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.38.0 to 4.38.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/b96794f015dfd88f77b49b1c93e0fa7110f94c63...1c5b675653bb5c22dbe9b12b556ec555138e09fd)

Updates `github/codeql-action/analyze` from 4.38.0 to 4.38.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/b96794f015dfd88f77b49b1c93e0fa7110f94c63...1c5b675653bb5c22dbe9b12b556ec555138e09fd)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.38.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.38.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-27 09:32:06 +02:00
Tom Carpenter 8fcf822025 Fix energy period selector icon resizing (#54372)
On narrow screens, the energy period selector resizes its date picker icon to ensure there is enough space to render the buttons. However the CSS used to target this icon is not specific enough meaning the resize leaks into elements within the date picker itself.

To fix this, add a part specifier to the date range inputs on the ha-date-range-picker, and target the CSS at that. This prevents targetted CSS from leaking into the picker itself.
2026-09-27 08:43:45 +02:00
Paulus SchoutsenandClaude 6878828996 Fix type error for notifications without a title (#54374)
A persistent notification can have a null title, but estimateDirection
takes a string. The function already treats a falsy value as an empty
string, so the behavior does not change.


Claude-Session: https://claude.ai/code/session_01GXiaNSBbB8C33fBL9yg5EP

Co-authored-by: Claude <[email protected]>
2026-09-26 20:36:14 -07:00
Paulus SchoutsenandClaude Opus 5 5c187a4e13 Correct Assist pipeline and speech API types in the frontend (#54285)
* Correct Assist pipeline and speech API types in the frontend

Compare the pipeline, conversation, speech and Wyoming data modules
with the handlers that produce them, and fix the mismatches.

The pipeline run events were the furthest adrift. Correct the wake
word, speech-to-text, intent and text-to-speech payloads, add the
stt-vad-start and stt-vad-end events, and drop keys the backend never
sends.

Two of these were live bugs. The chat log subscription nests its
payload under chat_log, so the log was read one level too high. The
debug view read the wake word result as ww_id, which is wake_word_id,
so that field always rendered undefined.

Rewrite the Wyoming info types against the wyoming library, which the
previous types modelled as empty tuples.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YDqKNfAAvMV7zJJNodsHfK

* Leave the chat log tool result to its own change

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YDqKNfAAvMV7zJJNodsHfK

---------

Co-authored-by: Claude <[email protected]>
2026-09-26 13:13:08 +02:00
56f695f4ed Clarify that IP bans do not expire (#54365)
* Clarify that IP bans do not expire

* Apply suggestion from @silamon

Co-authored-by: Simon Lamon <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
Co-authored-by: Simon Lamon <[email protected]>
2026-09-26 11:52:21 +02:00
João Pedro Hickmann e0b7b929dd Skip drawing hidden line chart symbols to speed up tooltips (#54355)
* Don't draw the invisible symbols of line charts

The chart theme sets a 1px symbol for line series, so symbols are not
visible, but echarts still draws one per data point. Every tooltip or
axis pointer move repaints the whole layer, including those hundreds of
symbols: on a power sources graph with 200 points per series, one drag
step repainted about 1000 elements.

Set showSymbol: false in the theme. Echarts still draws the symbol of the
hovered point. On a slow tablet this cut the repaint per drag step from
about 50ms to 8ms and roughly halved the frame time while dragging.

* Fix ECharts capitalization
2026-09-26 12:38:51 +03:00
Paulus SchoutsenandClaude Opus 5 f0c63f8840 Correct config flow and integration API types in the frontend (#54289)
* Correct config flow and integration API types in the frontend

Compare the config entry, flow and manifest data modules with the
handlers that produce them, and fix the mismatches.

Split the in-progress flow message into a discriminated union, because
the removed event carries no flow. Mark the flow step fields the
backend sends as null, and correct the manifest, where the discovery
entries and several always-optional keys did not match the schema.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YDqKNfAAvMV7zJJNodsHfK

* Request a single config flow handler type

The endpoint indexes one key, and only "helper" and "integration"
exist. Asking for a list joined them into one unknown key, so looking
up a non-helper integration raised on the backend.

Add the config entry unloading state and the virtual integration type,
both of which the backend reports, with the strings they render.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YDqKNfAAvMV7zJJNodsHfK

---------

Co-authored-by: Claude <[email protected]>
2026-09-26 10:44:43 +02:00
Paulus SchoutsenandClaude 1ac04b0a65 Correct energy, history and recorder API types in the frontend (#54292)
Compare the energy, history and recorder data modules with the
handlers that produce them, and fix the mismatches.

History states omit attributes when the caller asks for a minimal
response, which both subscriptions do, so the field is optional and
the readers now guard it. Statistics omit the values that were not
requested, and the validation issues carry nullable placeholders.


Claude-Session: https://claude.ai/code/session_01YDqKNfAAvMV7zJJNodsHfK

Co-authored-by: Claude <[email protected]>
2026-09-26 10:41:17 +02:00
Paulus SchoutsenandClaude a7eb100132 Correct entity domain and helper API types in the frontend (#54293)
Compare the entity domain and helper data modules with the domains
that produce the attributes, and fix the mismatches.

Add supported feature flags the domains define and the frontend did
not list, and add attributes the domains report. Remove attributes
that are service fields rather than state, and the light colour
temperature keys core replaced with the kelvin forms.

Correct the weather forecast, where the event carries the whole list
and the wind speed is a number, and correct the image update command,
which sent the wrong id.


Claude-Session: https://claude.ai/code/session_01YDqKNfAAvMV7zJJNodsHfK

Co-authored-by: Claude <[email protected]>
2026-09-26 10:40:32 +02:00
237bf119e7 Keep zone occupants in one map bubble (#54307)
* Keep zone occupants in one map bubble

Several bubbles piled up on a zone marker. A person inside a zone whose
state did not name it (stale or router-based tracking) had no zone key
and showed as a loose marker under the bubble, or formed a second
bubble on the same spot. Occupants spread beyond the group radius fell
back to proximity clusters, and every cluster of same-zone members was
pinned above the zone marker, stacking bubbles. Zoomed out, each zone
kept its own bubble even when the zone markers overlapped.

Zone membership now also follows position: an entity inside a drawn
zone's circle joins that zone's bubble. The engine hands the builder
the group key, so only the zone's own group is pinned to its marker and
proximity clusters show where their members are. Proximity is measured
against every member of a group rather than only its first. Bubbles
whose rectangles would overlap on screen merge into one plain bubble,
keeping the zone's tail only when a single zone is involved.

The Leaflet fallback ignores group keys, so it no longer pins bubbles
to zones there.

* Fix map cluster test lint types

Co-authored-by: maartenla <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-09-26 09:56:02 +02:00
Balloob BotandPaulus Schoutsen 4a6765d886 Skip upstream-only scheduled workflows on forks (#54366)
Co-authored-by: Paulus Schoutsen <[email protected]>
2026-09-26 07:50:09 +00:00
Jan-Philipp BeneckeandClaude Opus 5 8c5c35ca06 Describe trace graph nodes for screen readers (#54358)
* Describe trace graph nodes for screen readers

The trace graph is drawn entirely in SVG. Its nodes and branches are
keyboard reachable, but carried no accessible name and no role, so a
screen reader announced nothing while tabbing through a run. Everything
the graph says about the outcome of a step — the error badge, the
strike-through, the dashed outline, the repeat count — was visual only.

Each focusable stop now carries the same step description the automation
editor shows, followed by what the run did with that step. The ARIA is
written at the call sites in hat-script-graph, which is the only place
that knows whether an element is a step or just layout: the branch heads,
the then/else arrows, the failed-condition cross and the spacers are
marked aria-hidden, while the branch that merely groups the triggers is
left alone so the triggers inside it stay in the accessibility tree.

The names themselves are built by buildTraceLabels, a pure function that
walks the trace tree and returns one string per node path, reusing the
same describers the editor uses. The trace panels call it because they
already own hass, and memoize it on the trace, so the graph takes a plain
record and stays a leaf: it subscribes to nothing, and entity state
changes no longer rerender it.

Co-Authored-By: Claude Opus 5 <[email protected]>

* Process code review comments

Fix the memoization of the trace labels: `hass` is replaced on every
state update, so comparing it rebuilt every label on every state event,
which was worse than the rerendering the labels were hoisted out of the
graph to avoid. Compare everything but `hass`, and let an absent entity
registry stay undefined rather than allocating a new array each render.

Report whether a condition passed or failed instead of only that it ran.
That outcome is otherwise shown by the tracked path and by a cross on a
node that is aria-hidden, so it never reached a screen reader.

Drop `role="button"` from the nodes. Selection follows focus and nothing
handles clicks or key presses, so the role promised an activation that
does not exist. The branches keep `role="group"`, which makes no such
promise.

Pass the integration manifests through from both trace panels, so the
names match the ones the automation editor shows.

Co-Authored-By: Claude Opus 5 <[email protected]>

* Process code review comments

Give the leaf nodes `role="img"`. Dropping `role="button"` left them with
the implicit generic role, on which ARIA prohibits an author-provided
name, so the labels risked being ignored and the nodes going back to
being unnamed focus stops. A node draws one step and slots only
decoration, so `img` names it without claiming it is a control. The
branches keep `role="group"`, since `img` would make their focusable
children presentational. `aria-disabled` goes with the button role: it is
unsupported on `img`, and the state is already part of the name.

Assert the nested steps in the label coverage test. It only checked the
building blocks and the choose options, so a regression in the recursion
through branch children would have gone unnoticed.

Co-Authored-By: Claude Opus 5 <[email protected]>

---------

Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-25 20:25:04 +02:00
Yosi LevyandCopilot Autofix powered by AI a3cb6d8202 Automatic direction for alerts and notifications (#54342)
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-25 16:52:45 +01:00
Dr.Blank f60a40de72 Show security rating scale in app rating dialog (#54345) 2026-09-25 14:53:07 +01:00
Aidan TimsonandCopilot Autofix powered by AI 465f4a8227 Add shared skeleton components (#54325)
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-25 14:52:14 +01:00
Paulus SchoutsenandClaude 87763fb59d Load MDI icon chunks from the static path (#54347)
ha-icon fetched the MDI chunks from a fixed /static/mdi/ path. Use
__STATIC_PATH__ instead, like the translation and locale data fetches.
The value is /static/ in all current builds, so nothing changes today.
Builds that serve static files from another location, such as an embed
on another site, can now load icons.


Claude-Session: https://claude.ai/code/session_01HqnRKRicxMCBK3EuxYXimM

Co-authored-by: Claude <[email protected]>
2026-09-25 07:08:25 +02:00
Aidan TimsonandCopilot Autofix powered by AI f4bb4e242d Improve data table loading (#54322)
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-24 18:24:20 +01:00
Aidan Timson eb91411cfe Fix bottom padding in device and area add to dialogs (#54337) 2026-09-24 18:05:37 +03:00
Aidan Timson 1767632811 Fix unstyled border router rows in Thread panel (#54340)
Import list item components in Thread panel
2026-09-24 18:04:19 +03:00
Aidan Timson 7c5dd1841b Stop agents asking for tests on visual components (#54343) 2026-09-24 15:58:22 +01:00
Petar PetrovandMindFreeze d8effd44b2 Wrap refresh token supporting text on narrow screens (#54338)
Co-authored-by: MindFreeze <[email protected]>
2026-09-24 11:38:09 +01:00
Copilotandtimmo001 182563d943 Wait for Start to be enabled in onboarding E2E tests (#54329)
Co-authored-by: timmo001 <[email protected]>
2026-09-24 09:58:46 +03:00
Bruno Pantaleão Gonçalves e5f1cb0b1f Hide menu button when external app provides the sidebar (#54321) 2026-09-23 15:44:07 +01:00
Paulus SchoutsenandClaude b31da04913 Fix heading spacing in linked devices card (#54324)
Co-authored-by: Claude <[email protected]>
2026-09-23 15:41:27 +01:00
Franck Nijhof d35c398bfd Bump js-yaml to 4.3.2 (#54320) 2026-09-23 13:46:57 +01:00
Aidan Timson 71f9285e70 Fix initial scroll position in log details (#54315) 2026-09-23 09:50:28 +03:00
Aidan TimsonandNorbert Rittel 117392d71e Add a bug report link to log details (#54305)
* Share GitHub issue URLs and type integration queries

* Share the documentation base URL

* Add a bug report link to log details

* Add horizontal divider

* Name the destination in the log report link text

* Move log reporting into the alert below the header

* Clarify log reporting guidance and alert spacing

* Update src/translations/en.json

Co-authored-by: Norbert Rittel <[email protected]>

* Prefill installation type in log reports

* Add serial comma to log reporting guidance

* Fix log report loading and large log handling

* Clarify custom Frontend modules in log reporting guidance

* Use version-aware documentation links in log reports

* Use contexts and limit health requests in log details

---------

Co-authored-by: Norbert Rittel <[email protected]>
2026-09-22 12:07:59 +02:00
Paulus SchoutsenandClaude 666f88c4da Correct automation, script and trace API types in the frontend (#54291)
Compare the automation, script, trace and blueprint data modules with
the schemas and handlers that produce them, and fix the mismatches.

Add trigger options the backend accepts and the frontend did not
declare, and widen the offsets and time values the schemas allow.
Device actions and their capabilities are often absent, so mark them
optional. Correct several declared results, including saving and
deleting a blueprint, and drop a trace field the backend never sets.


Claude-Session: https://claude.ai/code/session_01YDqKNfAAvMV7zJJNodsHfK

Co-authored-by: Claude <[email protected]>
2026-09-21 18:34:07 +02:00
b12f78c652 Climate dashboard: add my link (#54299)
Co-authored-by: Aidan Timson <[email protected]>
Co-authored-by: Simon Lamon <[email protected]>
2026-09-21 17:30:33 +01:00
Jan-Philipp Benecke 8e10d53012 Render real trigger/condition/action icons and unfinished branch state in trace graph (#54275)
* Render real trigger/condition/action icons and unfinished branch state in trace graph

* Process review: repeat body tracking, service and action icons

* Infer empty repeat body entry from the repeat config

* Track repeat bodies only by their traced steps
2026-09-21 18:30:23 +02:00
Aidan Timson 1813f386de Add field IDs to the bug report form (#54303)
* Add stable field IDs for frontend issue prefill

* Remove issue template prefill comment

* Add IDs to remaining issue form fields

* Link the issue reporting guide in the bug report form
2026-09-21 18:26:46 +02:00
c0ffeeca7 80202cd645 Connectivity panel: add my link (#54296)
Add my link for Connectivity panel
2026-09-21 18:16:49 +02:00
c0ffeeca7andAidan Timson c786f7d2e6 Lights dashboard: add my link (#54297)
Co-authored-by: Aidan Timson <[email protected]>
2026-09-21 18:16:24 +02:00
Paulus SchoutsenandClaude 1ac4382dc5 Correct Supervisor API types in the frontend (#54284)
Compare the hassio and supervisor data modules with the Supervisor
handlers that build the responses, and fix the mismatches.

Add fields the API returns that were missing, including system_managed,
boot_config, dns, host_uts, ingress_port, udev, usb and video. Correct
two names that never matched the wire: services_role is services, and
auto_uart is uart. Drop installed, which belongs to the store model
rather than the app info payload, and drop repositories from the app
list, which the list handler does not return.

Mark the many fields the Supervisor can return as null, and replace the
placeholder issue and suggestion string arrays in the resolution types
with the objects the API sends.


Claude-Session: https://claude.ai/code/session_01YDqKNfAAvMV7zJJNodsHfK

Co-authored-by: Claude <[email protected]>
2026-09-21 18:13:19 +02:00
Sirakorn Lamyai d0220b6a72 No username in filter condition for eligible users, to allow Command Line auth provider (#54280)
* fix: no username in filter condition for eligible users

* fix: hide user.username in brackets if username is null

* fix: hide username/password row only when linked user has homeassistant credential

* fix: validate ability to login using credentials length
2026-09-21 12:18:08 +02:00
c0ffeeca7 bf21bfa777 Modbus panel: add my link (#54302) 2026-09-21 11:02:07 +01:00
c0ffeeca7 1fc565b602 Security dashboard: add my link (#54298) 2026-09-21 10:33:43 +01:00
7ac932ff7e Use the tool result field in the chat log (#54294)
Co-authored-by: Claude Opus 5 <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Co-authored-by: Claude <[email protected]>
2026-09-21 09:57:30 +01:00
Petar Petrov 996ccd50d6 Filter config entry picker by requested subentry type (#54224) 2026-09-21 09:29:15 +01:00
Petar Petrov 24fde161c4 Fix calendar card refresh loop on browsers without Intl longOffset support (#54221) 2026-09-21 09:26:39 +01:00
Bruno Pantaleão Gonçalves d005f694e1 Let the map overview list scroll through the bottom safe area (#54282)
* Let the map sheet reach the screen edges

On a phone the map bleeds past the view's safe-area padding but the overview
sheet over it did not, so a strip of map stayed visible down the sheet's
trailing side and under it. The sheet now bleeds to the same edges.

Reaching the bottom of the screen means the list can scroll through the safe
area instead of stopping above it. The list keeps that much padding at its own
end, so the last row still clears the area once it is scrolled to.

* Drop the comments

* Drop the map card offsets, which never moved the sheet

On a phone the overview is a position: fixed dialog inside
ha-resizable-bottom-sheet, anchored to the viewport with its own bottom and
side insets, which this component already sets to zero. Offsetting the host
around it moved nothing, so the change was inert.

What is left is the part that runs inside the sheet: the list scrolling
through the panel's bottom padding instead of stopping above it.
2026-09-21 07:07:45 +02:00
karwosts 299e612646 Make helpers table robust to entity-id changes (#54261)
* Remove duplicate entityReg subscription in helpers

* initialize to undefined

* Make helpers table robust to entity-id changes
2026-09-20 11:04:50 +02:00
Jan-Philipp Benecke 5fa14d4173 Refresh trace graph primitives to match automation editor (#54253) 2026-09-20 11:04:37 +02:00
Petar Petrov a4d1cb0a57 Downsample the history timeline to the chart's pixel width (#54252)
* Extract the history timeline chart data transform

Move the body of state-history-chart-timeline's _generateData into
state-history-chart-timeline-data.ts, mirroring the line chart's
state-history-chart-line-data.ts. Environment inputs are passed in, so the
transform is a pure function that can be tested and benchmarked on its own.

No behaviour change.

* Downsample the history timeline to the chart's pixel width

The timeline emitted one rectangle per state change with no downsampling, so an
entity with tens of thousands of recorded changes produced tens of thousands of
rectangles and blocked the main thread for seconds inside ECharts' layout.

Bound the output by the chart's device-pixel width, the way ha-chart-base
already does for line series: segments at least one frame wide keep their exact
bounds, and runs of narrower ones resolve per frame to the state covering most
of that frame, merging with neighbours that resolve to the same state. Charts
whose state changes are all wider than a frame, which is the common case, keep
exactly the rectangles they had before.

The host also becomes a block box so it reports its own width; as an inline box
its clientWidth was always 0.

* Narrow the timeline data transform's hass parameter to the states it reads

* Pass entity states to the timeline data transform instead of hass
2026-09-20 10:49:25 +02:00
dependabot[bot] 43c3b51829 Bump the codeql-action group across 1 directory with 2 updates (#54274)
Bumps the codeql-action group with 2 updates in the / directory: [github/codeql-action/init](https://github.com/github/codeql-action) and [github/codeql-action/analyze](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.37.9 to 4.38.0
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/cdf488f595d80d6e07e03d4674febd5ab45fa938...b96794f015dfd88f77b49b1c93e0fa7110f94c63)

Updates `github/codeql-action/analyze` from 4.37.9 to 4.38.0
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/cdf488f595d80d6e07e03d4674febd5ab45fa938...b96794f015dfd88f77b49b1c93e0fa7110f94c63)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: codeql-action
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: codeql-action
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-20 09:04:49 +02:00
Jan-Philipp Benecke 66a454821a Show disabled automations as event chips instead of disabled bar (#54248) 2026-09-20 08:59:34 +03:00
Paulus SchoutsenandClaude Opus 5 4f713aa645 Fix card header line height when the title wraps (#54258)
* Tighten MCP card header line height

The shared ha-card header uses --ha-line-height-expanded (2), which leaves a
large gap between lines once "Model Context Protocol" wraps on narrow screens
or at a larger font scale. Use --ha-line-height-condensed for this header, the
same value the ZHA group pages already use.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cg5a2sBXVms8HCs2t96DNE

* Fix card header line height for all ha-card

The shared header used --ha-line-height-expanded (2), so at 24px every line
box was 48px tall. That leading doubled as the header's vertical spacing, so
a header that wraps got a 48px gap between its lines.

Separate the two concerns: --ha-line-height-condensed sets the leading, and
the padding carries the spacing the half-leading used to provide. A
single-line header goes from 76px to 73px, so existing cards keep their
look, while each extra line now adds 29px instead of 48px.

Drop the per-card override in mcp-pref, which the default now covers.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cg5a2sBXVms8HCs2t96DNE

---------

Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-20 08:57:03 +03:00
Rick van Hattem cedc2d5324 Add extended date range presets to Activity (#54273) 2026-09-19 18:55:08 -07:00
karwosts 15290231ea Remove duplicate entityReg subscription in helpers (#54257)
* Remove duplicate entityReg subscription in helpers

* initialize to undefined
2026-09-19 23:35:04 +02:00
Bruno Pantaleão Gonçalves 5960dfea0e Let the table rows reach the edges of the screen (#54267)
* Let the table rows reach the edges of the screen

The rows stopped at the safe area, so their dividers and the shading
behind a group header ended in a line down the middle of the screen. The
rows now span the full width while their content keeps the inset, so
nothing readable moves and nothing sits under the cutout.

* Bleed the row and group header backgrounds too

* Bleed the table itself so every row variant lines up
2026-09-19 23:10:14 +02:00
Bruno Pantaleão Gonçalves d830220eff Let the filters bar reach the edges of the screen (#54266)
* Let the filters bar reach the edges of the screen

The row of filter and sort controls stopped at the safe area, so on a
device with a horizontal inset it sat in a narrower strip than the list
below it, its bottom border stopping short of the edge. The bar now
spans the full width, its controls scroll under the inset, and a spacer
at the end keeps the last one clear of it by the inset plus the usual
16px. A scrolled flex row drops its end padding, so that space has to be
an item rather than padding.

The subpage keeps the inset as padding inside its scroller instead of an
outer margin, so the bar can bleed into it, and a narrow data table
gives the header row the full width rather than clipping it. The rows of
the table itself stay inside the safe area as before.

* Address review on the filters bar safe area
2026-09-19 22:55:22 +02:00
Bruno Pantaleão Gonçalves c6f72c9cf5 Let the map fill the screen on the map dashboard (#54263)
* Let the map fill the screen on the map dashboard

A map in a panel view stopped at the safe area, leaving a strip of empty
card beside it, and the drawer stopped there too. Map tiles carry no text
to read, so the map and the drawer now run to the edges of the screen,
while everything that is read or tapped stays inside the safe area: the
drawer's content, the card's buttons, and the map's own controls, which
already had insets for the drawer and now take the safe area as well.

The view container exposes the insets it applies as custom properties so
the card can cancel exactly those, and the bottom sheet takes its side
insets from properties that default to the safe area.

* Address review on the map full bleed
2026-09-19 22:37:43 +02:00
Bruno Pantaleão Gonçalves 60f7728d54 Let the settings cards reach the edges of the screen (#54269)
On a phone the cards on the settings page are full-width bands with a
border on top and bottom. They stopped at the safe area, so on a device
with a horizontal inset every band ended in a line down the middle of
the screen. The bands now span the full width and pad their contents by
the inset, so the rows inside them do not move.
2026-09-19 22:22:28 +02:00
Bruno Pantaleão Gonçalves 6014ee7744 Draw the header border across the safe area (#54265)
The header's background already reaches the edges of the screen, but the
row that carries the bottom border sits inside the header's safe area
padding, so on a device with a horizontal inset the border stopped short
of the edge. The row now spans that padding while its content stays
where it was.
2026-09-19 22:07:22 +02:00
Bruno Pantaleão Gonçalves f32833fcbe Keep the bottom tab bar inside the horizontal safe area (#54262)
On a device with a left or right inset the tabs ran underneath it, so the
last tab was clipped by the rounded corner. The bar keeps its full width,
so its background still reaches the edges of the screen, and only the
tabs inside it are inset.
2026-09-19 21:54:59 +02:00
Bruno Pantaleão Gonçalves a9295ac21b Centre toasts in the safe area (#54270)
Toasts were centred on the viewport, so on a device whose safe area is
not symmetric they sat off centre and ran under the cutout. They now
take the same centring offset the dialogs use, and the stack is capped
at the safe width so a wide toast cannot reach past the inset either.
2026-09-19 21:52:17 +02:00
Petar Petrov 66cc3f62c5 Refresh voice expose table when an entity alias changes (#54233) 2026-09-19 09:40:32 +02:00
Petar Petrov fb1a75edd4 Defer chart work while the chart is not visible (#54251)
* Defer chart work while the chart is not visible

ha-chart-base did its full update path no matter whether anyone could see
the chart: every data or options change re-ran the line downsampling and
chart.setOption, and the resulting animation kept repainting the canvas.
That applied to charts in a section hidden by a visibility condition, to
charts scrolled far off a long page, and to every chart in a background
tab, where live history charts kept paying it on each stream message.

Gate the work on rendered size, an IntersectionObserver with one viewport
of margin, and document.visibilityState. While invisible the chart records
which properties changed and replays them in a single setOption once it is
visible again. The initial setup is deferred the same way, so a chart that
first renders hidden is built at its real width, and a synced zoom that
arrives before that setup is replayed instead of dropped.

* Track chart visibility from the observers instead of measuring

Reading getBoundingClientRect() in willUpdate forced a synchronous layout
for every chart on every data or options change, right after the parent had
committed DOM. Keep the state the observers already report instead: whether
the resize entry has a non-zero content box, and whether the intersection
observer sees the element. Both start true so a chart on screen still
renders on its first update, and firstUpdated keeps one measurement so a
chart that first renders inside a hidden container defers its setup.

The observer margin is one screenful only on a phone; a desktop gets a fixed
band, where a whole viewport would cover most of the page.

A reset to the full range now clears a stored zoom rather than replaying it,
and the global reset no longer skips a chart that has not been built yet, so
a deferred chart cannot come back zoomed after everything else was reset.

* Queue a synced zoom while a chart rebuild is pending

* Use the observed chart width for the default height and downsampling

* Use MobileAwareMixin for the chart's mobile checks
2026-09-19 09:34:14 +02:00
Maarten Lakerveld 8f7184023a Improve zone editor (#54031)
* Show a zone's own icon and color on the zone dialog map

The location selector's icon option was never applied: the expression
parsed as (icon || radius) ? radius-icon : marker-icon, so the zone
dialog always showed the radius marker instead of the zone's icon. The
selector also gains a color option, and both zone dialogs pass the
zone's icon and its map color (the config panel hands the dialog the
zone's entity id for that), so the map in the dialog looks like the zone
does everywhere else, including the home zone and a live passive toggle.

* Show zone markers in the zone list

The zones list on the zone config page shows each zone as it looks on
the map: its color with its icon, or initials without one, instead of
a plain icon.

* Sort zones alphabetically with home first

The zone config page listed UI zones sorted and YAML zones after them in
state order; the map overview sorted all zones by name. Both now show the
home zone first and the rest alphabetically.

* Color the zone list and dialogs from the registry context

The zone list avatar and the zone dialog map take the registry entries; the
home zone dialog needs none, its color is fixed.

* Show zone initials in the editor and resolve color from registry

Fall back to the zone's initials (matching the list and map) when it has
no icon, and to a plain map-marker when there is no name yet, instead of
the map-marker-radius pin.

Resolve the zone's entity id reactively from the registry context the
dialog already consumes, so the marker color is correct even when the
registry loads after the dialog opens (e.g. direct /edit/ deep link).

* Preview the palette color a new zone will take

Creating a zone has no entity yet, so the marker fell back to the accent
color and then changed on save. Derive the prospective creation-order
color from the registry so the create preview matches the saved zone.

* Test the new zone's previewed color

Cover nextZoneColor: the next creation-order slot for an active zone (home
excluded) and the muted color for a passive one, so an off-by-one in the
slot count can't silently make the create preview differ from the saved zone.
2026-09-19 09:30:31 +02:00
Maarten Lakerveld f3aba8f142 Activity timeline dots colored by zone in map panel (#54030)
* Color activity timeline dots by zone

Zone changes in a person's or device's activity timeline show the dot in
that zone's color, the same color as its marker on the map and its row
in the zones tab; away and unknown stay grey. Arrivals and departures in
a zone's own timeline keep their green and grey.

* Color activity dots from the registry context

The zone color of a timeline entry takes the registry entries the overview
already consumes.
2026-09-19 08:23:36 +03:00
tzagimandYosi Levy 9c28c21792 Fix RTL bidi corruption of min/max temperature in more-info weather dialog (#54255)
* Fix RTL bidi corruption of min/max temperature in more-info weather dialog

* Fix direction also on attribution style

---------

Co-authored-by: Yosi Levy <[email protected]>
2026-09-19 08:15:50 +03:00
Jan-Philipp Benecke ccceddfd35 Add missing labels to previous and next tracked node in trace graph (#54244) 2026-09-19 08:13:19 +03:00
Jan-Philipp Benecke e633e5fb3e Introduce trace tree model for automation/script trace graphs (#54246)
* Introduce trace tree model for the automation/script trace graphs

* Process code review comments

* Process missed comments
2026-09-18 20:25:07 +02:00
WendelinandSimon Lamon 9a311b0518 Migrate md lists in 7 files (#54220)
* Fix network info secondary text size

* Migrate profile

* Migrate config-entries to list-base

* Revert wrapper a for ha-dropdown-item

* Revert wrapper a for ha-dropdown-item

* Copliot review

* Prettier

---------

Co-authored-by: Simon Lamon <[email protected]>
2026-09-18 16:20:11 +03:00
c07f421f74 Regenerate statistics chart data when the formatters change (#54232)
* Regenerate statistics chart data when the formatters change

statistics-chart resolves its series names once and caches them in
_chartData, and it rebuilt only when the fetched statistics changed. A
rename therefore left the legend showing the old name.

The formatters are replaced as a set whenever the registries change, so
comparing formatEntityName identity is enough to catch it. This covers
the statistics graph card and the more-info history dialog; the energy
dashboard cards cache their series the same way and are handled
separately.

Co-Authored-By: Claude Opus 5 <[email protected]>

* Refresh statistics chart legend labels

Co-authored-by: MindFreeze <[email protected]>

---------

Co-authored-by: Claude Opus 5 <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: MindFreeze <[email protected]>
2026-09-18 09:25:57 +02:00
Maarten Lakerveld 62acda8c08 New Map Panel (#54029)
* Add people, devices, and zones overview to the map card in panel view

When the map card is the single card of a panel view it shows a
floating overview with People, Devices, and Zones tabs styled as an
animated segmented control; on mobile it becomes a bottom sheet drawer
that can be collapsed by tap or swipe. People list their zone or Away
state with the last update time, devices only appear when they have a
location, and zones show their occupant count while passive zones are
hidden in this view.

Selecting a row or map marker opens a detail view with a back button,
a name that opens the more info dialog, and a 24h activity timeline:
zone changes for a person or device, arrivals and departures per person
for a zone. Selecting focuses the map (street level for people, the
radius for zones, shown only while selected), marks the selected marker
with a thicker border, shows the accuracy circle when the position is
imprecise, and clicking the map deselects. In panel layout the overview
sits at the start side, so the zoom control and map buttons move to the
other side: ha-map gains a zoom-position property for that, and honours
--ha-map-bottom-inset so the attribution and scale stay clear of the
bottom sheet.

* Resubscribe the map card's colors when the connection changes

The card kept its entity color subscription on whichever connection it
first saw. It now remembers that connection and subscribes anew when
hass brings a different one, as ha-map already does.

* Pause auto-fit before a deferred fit, and never select an empty tab

An explicit fit that had to wait for the engine or for a size did not
pause auto-fit until it ran, so an auto-fit queued in between could take
its place. The pause comes first now.

The overview's selected tab could be an empty, disabled one, showing an
empty list while another tab had content and leaving aria-selected on a
disabled button; the selection falls back to the first tab with items,
which the tab stop already did.

* Reuse the cards' show-more-info label in the map overview

The overview added its own copy of a label the other cards already have
translated; it uses the shared key and the duplicate is gone.

* Keep a focused marker clear of the overview

Focusing a person or zone fitted the full viewport, so the marker could
land under the overview: the start side on desktop, the bottom sheet on
phones. Fits now take viewport padding, both engines apply it per fit,
and the card passes the overview's size as padding on the side it covers,
honoring right-to-left layouts.

* Report activity that could not load, and list only events inside the window

A failed history request, or an instance without the history integration,
read as no recent activity; the panel now says the activity could not be
loaded. The first history sample is the state at the window's start, not
a change inside it, so a person who has not moved for days no longer shows
that old state as recent activity: samples before the window only seed
the previous state, for zones and people alike.

* Take the map card and overview colors from the registry context

The card no longer runs its own color subscription, and the overview reads
the registry entries for its zone list.

* Keep automatic fits clear of the overview

Only a selection fit knew about the drawer; the first fit and every
auto-fit used the whole viewport, so markers could land under the drawer.
ha-map takes a fit padding that automatic fits apply, and refits when it
changes, so the map settles once the drawer reports its size.

* Let the activity timeline scroll inside the drawer

On phones the drawer body is capped at 60vh and clips its overflow for the
collapse animation, so activity entries beyond that were unreachable. The
activity box now scrolls within the drawer.

* Keep the scale ruler and attribution beside the drawer on wide layouts

The bottom inset that lifts the map controls above the drawer only applied
on phones, so on desktop a tall drawer covered the scale ruler. ha-map gains
left and right insets for its bottom controls, and the card reserves the
drawer's width on the side it occupies.

* Extract the activity timeline parsing and test it

The window seeding, unavailable skipping and zone transition rules moved
into pure functions with tests, so a regression in the People or Zones
timeline no longer needs manual checking.

* Show the activity timeline as logbook rows

The overview rendered its own timeline items. It now uses ha-logbook-entry
in its narrow layout, so activity reads like the logbook everywhere: the
person, the zone they are in, and when. Arrivals and departures on the zone
tab are the same rows for the person who moved. The card hands hass to the
overview only for these rows.

* Let the resizable bottom sheet stay open at a minimum height

A persistent sheet stops at a pixel minimum instead of closing when dragged
down, can open at its content height within a configurable share of the
viewport rather than at least 55%, reports its height after opening and
resizing, and lets a host shrink the grab area below the handle for content
that sits right under it. The map overview uses all of this on phones; the
automation editor keeps the previous behavior.

* Show the overview as a bottom sheet on phones

The overview had its own collapsible panel with a handle button and swipe
handling. On phones it now renders inside ha-resizable-bottom-sheet in its
persistent mode, so it resizes like the automation editor's sheet and stops
at a strip with the tabs instead of closing. The sheet reports its height
for the map's insets and fit padding; wide layouts keep the floating panel.

* Let only the newest activity load show its result

Comparing the selected entity after the fetch let an older load for the
same entity pass when the user selected it, moved away, and came back,
so a stale result or failure flag could overwrite the newer one. Number
the loads and let only the most recent one commit its result.

* Include people without a location in the map overview

show_all builds the map entity list from located entities only, so people
whose location is currently unknown never reached the overview's people
list (with its no-location rows) or its zone activity history. Build a
separate overview list that adds those people back, while the map markers
keep the location filter.

* Move focus with the map overview detail view

Selecting an item swapped the list for the detail view (and back) without
moving focus, so keyboard and screen-reader users lost their place on the
removed element. Focus the detail heading when it opens, and restore focus
to the originating item when returning to the list.

* Keep the bottom sheet's minimum height correct after opening

minHeight is a pixel value converted to a viewport percentage and cached
once the sheet opens. Recompute it when the viewport changes (e.g. rotation)
so the cached percentage can no longer clip the persistent peek content, and
emit bottom-sheet-resized once a raised minimum has grown the sheet, so the
host updates its overlay padding instead of holding a stale value until the
next drag.

* Address Copilot review on the map overview

- Keep locationless people in the map entities so a marker appears once
  they are located, not only after a rebuild
- Restore focus to the active tab when a back navigation's row is on
  another tab
- Only reserve overview padding in panel layout

* Draw the cluster bubble and its tail with one shadow

The bubble carried its own box-shadow while the tail sat behind it, so the
bubble's shadow fell across the tail and showed a seam. The bubble and tail now
share one drop-shadow on the wrapper, so the tail reads as part of the bubble.

* Bubble a lone person or device in a zone

A zone group only bubbled with more than one member, so a single person or
device in a zone showed as a plain marker instead of a bubble at the zone.
Keyed (zone) groups now bubble even with one member, pinned to the zone; a
marker that is not in a zone still shows plainly.

* Recover located-later device trackers in the show_all overview

show_all freezes the located entities at generation, so a standalone device
tracker that gains a location afterwards stayed out of the Devices tab until
reload. Recover eligible standalone trackers alongside people, skipping those
that belong to a person.
2026-09-17 22:28:18 +01:00
Paul Bottein 193cbcbfac Allow removing orphaned areas in vacuum segment mapping (#54179)
* Allow removing orphaned areas in vacuum segment mapping

* Type event handler and use RTL-safe padding in vacuum area mapper

* Include the area name in the remove mapping label
2026-09-17 20:09:26 +00:00
Wendelin d43f7e58b6 Onboarding: Improve translation loading (#54176)
* onboarding: Improve translation loading

* Fix generic picker auth check

* fix _translationsReady default
2026-09-17 20:42:39 +02:00
Bruno Pantaleão Gonçalves fb419538c7 Fix login page safe area insets (#54229)
Center the login page inside the safe area

The authorize page only applied the top safe-area inset, so on devices
with side insets the card, password field, forgot password link and
help link were centered on the full viewport and clipped by the right
inset. Add the left and right insets to the content wrapper padding so
the auto margins center the card inside the safe area, and pad the
bottom inset as well.
2026-09-17 15:57:30 +02:00
c0ffeeca7 7c7549349a Add my link for serial panel under Connectivity (#54225) 2026-09-17 14:05:14 +02:00
Jan-Philipp Benecke 051f51dd26 Hide trigger index in trigger references unless triggered-by is edited (#54228) 2026-09-17 14:00:50 +02:00
Maarten Lakerveld 9a9d747899 Redesign map markers (#54025)
* Redesign map markers with zone circles and avatar cluster bubbles

Zones are drawn as colored circles containing the zone icon, using the
entity's color with the zone radius and GPS accuracy circles matching
it. Marker clusters render as a bubble of up to three rounded square
avatars with a +N chip; when all members are in the same zone and the
bubble would overlap that zone's circle, it floats above the circle,
pinned to the zone's coordinate, with a tail pointing at it. Individual
markers are rounded squares, and while history trails are shown bubble
avatars get borders in their entity color so trails can be matched.
Avatars in bubbles are clickable and open the entity, and the whole
bubble zooms in on its members.

ha-map gains per-entity hide_radius, hide_accuracy, and selected
options for hosts that manage a selection; ha-entity-marker exposes its
background and border width via CSS variables and a selected state with
a thicker border. The OSMF vector tiles carry some places twice (node
and boundary centroid); towns and larger now require a population,
keeping the node, and smaller places get a collision padding.

* Frame person and device markers, ring the selected one

Markers get a card-colored frame with a soft shadow instead of a thin
border in the entity color, and the selected marker gets a primary-color
ring outside that frame. With history trails shown the frame still takes
the entity color, so a marker can be matched to its trail, and the
markers redraw when trails appear or disappear.

* Drop the editor's drag classes

The engine sets the move cursor on the elements it actually drags, so the
zone marker and the named icon no longer carry a class for it, and the
editor's element cache no longer varies with editability.

* Keep dragged values on the zone page until they are saved

The engine used to guess at the host's save state: after a drag it
skipped one update that matched the pre-drag values, taking it for a
re-render with data the save had not yet replaced. That guess is wrong
when a save fails, since the old values are then the truth and the
marker stayed at an unsaved position. The engine now applies every host
update except while a drag is in progress.

The zone page, which knows when it is saving, keeps the dragged values
as pending edits and shows them until the saved data carries them; a
failed save drops them and the marker returns.

* Subscribe to entity colors only for maps that draw entities

Every map with a connection subscribed to the entity registry for the
creation-order colors, including editor maps that never draw an entity.
Onboarding's location picker is one, and its mocked server rejects the
registry request, failing the onboarding end-to-end tests. The
subscription now starts when a map first draws entities.

* Address code review on the marker redesign

The selected ring's color came from an inline outline-color that beat the
rule's outline shorthand by precedence, which reads as if the shorthand
won; the inline style now sets a variable the rule consumes, with the
primary color as fallback. A map whose connection context changes
resubscribes to the entity colors instead of staying bound to the old
connection. The zone page's willUpdate called the wrong lifecycle hook on
its base class.

* Tell the user when a dragged zone edit fails to save

A failed save dropped the pending edit and rethrew, which no caller
awaited, leaving an unhandled rejection and a marker that silently moved
back. The page now shows the error in a dialog instead.

* Drop the numeric cluster badge styles, follow a replaced connection for colors

Clusters are avatar bubbles now, so the styles for the old count badge
had nothing left to style. The shared entity color subscription is a
module-level singleton keyed to whichever connection subscribed first; a
map arriving with a different connection now takes the stream over
instead of reading colors from the old one.

* Fall back to the palette color for entities without one, recolor zones on theme change

An entity object without a color reached the accuracy circle's paint
with an undefined color; the map's own palette color fills in. The zone
page's markers are memoized on their data, while their colors come from
theme variables, so a theme change now bumps the color version and
recolors them at once.

* Redraw markers on a theme change, and test the entity color assignment

Marker and trail colors are resolved from theme variables when drawn, but
a theme change only swapped the base style, so the old palette stayed on
the markers until something else redrew them. Any change to the themes
now redraws entities and trails.

The color assignment gets unit tests: creation order per domain, ties
broken by registry id, the home zone kept out of the palette, muted
passive zones, a stable fallback for entities outside the registry, and
one shared registry stream released with the last subscriber.

* Count entity color subscriptions from the listener set

The listener set deduplicated a reused callback while a separate counter
counted every call, so the two could disagree and the shared registry
stream could leak or be released early. Each subscription is now its own
listener, the count is the set's size, and unsubscribing twice is a no-op.

* Release the entity color subscription when a map stops drawing entities

A map whose entities were unset kept its registry subscription, holding
the shared stream open for nothing. It is released along with the
markers, and the three release sites share one helper.

* Address code review on the marker redesign, third round

The zone page's updated() override never called its base, so once
willUpdate stopped misusing super.updated the subscribe mixin had no hook
left to run hassSubscribe when hass arrives after connection; the override
calls super.updated now.

Saves for one zone run in order, each looking the entry up when it starts,
so a second response can replace what the first produced, and a failure
only drops the pending values its own request carried. A passive zone that
is not drawn no longer anchors a cluster bubble. A map whose entity list
empties releases the color subscription, not only one whose list is unset.

* Address code review: drop settled zone save queues

The per-zone save chain kept its last resolved promise for the life of the panel.

* Remove label dedupe

The doubled place labels are a tile issue, not part of the marker redesign,
and the population filter did nothing on the OSMF tiles, which fill in a
default population for every place. It moves to its own branch.

* Address code review: keep the label mode in cluster bubbles

Bubble avatars only carried the label text and picture, so an entity set to
the icon label mode showed initials once clustered and the attribute mode lost
its unit. The icon flag and unit now travel with the cluster data.

* Address code review: color map card entities from the shared palette

The card kept its own color dictionary, so an entity could have a different
color on every map. It now uses the palette that ha-map and the zone editor
already share, ordered by registry creation; a configured color still wins.

* Address code review: take entity colors from the registry context

The color module kept its own shared registry subscription with listener
counting and connection takeover. The lazy fullEntitiesContext already does
that for the whole app, so the module is now pure: it turns the registry
entries into a palette index, memoized per registry update. Maps ask for
the context only once they draw entities, so an editor's map, as in
onboarding, never requests the registry; the map card and the zone page
consume it directly.

* Address code review: one palette sequence for zones, persons and trackers

Per-domain sequences all started at slot 0, so the first person and the
first zone shared a color and a person could match the zone it was in.

* Address code review: recolor history trails when the registry changes

The trail colors are memoized with the registry entries as a key, like the
marker colors, so trails recolor with their markers when the registry
arrives or changes.

* Address code review: follow theme changes and keep bubble focus

The map card rebuilds its entity colors and trail colors when the theme
changes, ha-map redraws editable circles on a theme change, and the
locations editor rebuilds its cached marker elements. A focused cluster
bubble keeps focus on the bubble that replaces it, and a caller naming a
marker by aria-labelledby keeps that name.

* Address code review: recolor the map card from the themes context

The card consumed the theme through hass, whose update gate only lets a
dark mode flip through, so switching between two light or two dark themes
kept the old palette. It now consumes the themes from the UI context, like
ha-map, and rebuilds its entity and trail colors whenever they change.

* Address code review: keep the editor alert clear of the zoom control in RTL

The zoom control sits at the physical top-left in either text direction,
but the alert used logical insets, so in RTL its clearance moved to the
right and it covered the control.

* Fix the bubble tail covering the middle member

The tail is a rotated square whose upper half sits under the bubble. It was
painted on top, so in an open bubble it covered the bottom of the middle
member's frame and selected ring as a white triangle. Both tails now sit
behind their bubble.

* Narrow the locations editor to the themes context

ha-locations-editor consumed the whole uiContext but only reads themes, so
it rerendered on unrelated panel, sidebar, and UI-state changes. Transform
the context to Themes, following the pattern in hui-map-card.

* Keep focus when a cluster collapses to a single marker

Regrouping restored focus only to a replacement cluster icon, but a group
that becomes a single member is shown as a standalone marker with no icon,
so focus fell back to the document. Focus the member element in that case.
2026-09-17 12:26:11 +01:00
Bruno Pantaleão Gonçalves 5b99462fdf Fix notification drawer right safe area inset (#54230)
Apply the right safe-area inset to the full-width notification drawer

The drawer spans the full viewport whenever narrow is true (viewport
under 870px), but the right inset padding on the header and list was
only applied below a 450px media query. Between those widths the close
button ended up under the right inset. Reflect narrow as an attribute
and key the padding off it so the inset follows the same rule as the
drawer width.
2026-09-17 14:22:39 +03:00
Jan-Philipp BeneckeandCopilot Autofix powered by AI 14ef770c44 Overlay trace graph step navigation on the graph (#54227)
* Overlay trace graph step navigation on the graph

* Fix height problem

* Increase margin

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-17 14:20:00 +03:00
Przemysław Kłys 6a9fca2cb9 Fix logbook labels for restored button states (#54203)
* Fix logbook labels for unavailable timestamp entities

* Fix restored button context classification
2026-09-17 06:40:09 +00:00
Petar Petrov 55ba59074e Fix energy distribution home ring overflowing to 100% grid (#54191)
* Fix energy distribution home ring overflowing to 100% grid

Size the home circle from allocated used_solar, used_battery, and
used_grid instead of net used_total so misaligned hours cannot produce
a negative grid arc.

* Add gallery demo for energy distribution home ring

Mock the issue 54185 daily totals with realistic hourly PV, battery,
and grid statistics, including an export-lagged card that overflows
the old ring math.

* Remove gallery energy distribution demo from this PR

Keep the home-ring fix and its unit tests; drop the gallery page
that was only used for local browser verification.

* Keep a zero-consumption home ring as a plain border

When solar is configured but allocated flows are all zero, leave the
arcs unset so the card can show the home outline instead of zero-length
dashes on a borderless circle.

* Keep a defined zero low-carbon home arc

The energy distribution card mounts the home SVG when solar or
lowCarbon is defined. Omitting a 0 leftover hid grid and battery
arcs on a no-solar 100% high-carbon ring.
2026-09-16 15:49:29 +02:00
Maarten Lakerveld eeb674dd5a Show the selected light control on light group members (#54167)
* Show the selected light control on light group members

When a light group's more-info dialog is switched to color temperature, the
member tiles listed below now show a color temperature slider instead of
brightness, so the children can be adjusted on the same axis as the group.

The light control fires light-main-control-changed whenever its main control
changes, and more-info-content picks the member tile feature from that.
Members that do not support color temperature keep their brightness slider,
and the color mode keeps brightness since there is no tile feature for it.
Legacy group.* entities are unchanged.

* Hide member light control when group is in RGB color mode

There is no RGB tile feature, so showing a brightness slider on group
members while the group control is set to color is inconsistent. Show no
control in that case instead, per review feedback.
2026-09-16 15:44:11 +02:00
Jan-Philipp Benecke afe6e84e3c Make trace pages resizable two-pane layouts (#54216)
* Make trace pages resizable two-pane layouts

* Remove cast

* Remove cast
2026-09-16 16:06:56 +03:00
Bruno Pantaleão Gonçalves 3ddbc8f4e3 Communicate entity control to external bus (#54215)
* Communicate entity control to external bus

* Prefer target entity ids and report disconnecting calls

* Split and lowercase entity ids like Core does

* Keep entity control reporting best effort

* Assert wildcard entity ids are dropped
2026-09-16 15:25:32 +03:00
Jan-Philipp Benecke 216468cf50 Strip unreferenced duplicate trigger IDs (#54214) 2026-09-16 13:52:04 +02:00
Bram KragtenandClaude Opus 5 0ef3e9c71a Resolve statistic labels with structured entity names (#54202)
* Resolve statistic labels with structured entity names

getStatisticLabel resolved names through computeStateName, so every
statistic-shaped label — the energy dashboard cards, the sankey cards,
hui-statistic-card, chart series names and the energy configuration
dialogs — showed the flat friendly_name attribute while the rest of the
UI composed names from the device, area and floor.

It now asks hass.formatEntityName for the default composition, which
also makes the entity branch of computeEnergyLabel redundant.

The metadata fallback stays: external statistics have no entity to
resolve a name against.

Co-Authored-By: Claude Opus 5 <[email protected]>

* Keep the entity name shape out of the core chunk

recorder.ts sits in the core entry chunk, so importing DEFAULT_ENTITY_NAME
from compute_entity_name_display dragged the registry-aware formatters and
their dependencies in with it and blew the core bundle budget by 4.1%.

The constant and the name types have no runtime dependencies, so they move
to their own module; compute_entity_name_display re-exports them so nothing
else has to change.

Co-Authored-By: Claude Opus 5 <[email protected]>

---------

Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-16 09:59:12 +03:00
Bram KragtenandClaude Opus 5 1266b0c87a Remove unused element registration imports (#54206)
ESLint cannot judge side-effect imports like `import "../../components/ha-card";`,
so dead component registrations accumulate unnoticed. A repo-wide scan matching
every side-effect import against the tag its module registers found 308 imports
whose element is never referenced anywhere in the importing file.

This removes the 84 that carry no registration risk: no other file instantiates
the tag without directly importing the defining module (checked for `<tag>`,
createElement/dynamicElement/customElements.get/whenDefined, and `custom:<tag>`
in Lovelace configs), and every affected module keeps at least one other
importer.

hui-weather-entity-row got ha-state-icon transitively through the dropped
hui-generic-entity-row import, so it now imports ha-state-icon directly, which
is the element it actually renders.

The gauge gallery page is left alone even though its .ts never names the tag: a
gallery page exists to register what its sibling .markdown demos render, and
that import is the registration.

The remaining 224 are deliberately out of scope. Their component is rendered
somewhere else without its own import, so they need the matching import added in
the same change.

Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-16 09:52:42 +03:00
Wendelin a695710beb Migrate md lists to new lists in 20 files - 2 (#54208)
* migrate to ha-list-base in 10 files

* migrate lists in 10 files
2026-09-15 19:23:46 +02:00
Wendelin f991efbc0a Migrate md lists to ha-list-base in 20 files (#54197)
* Migrated 10 files from md list to new lists

* migrate 10 files

* copilot review

* fix prettier
2026-09-15 19:06:53 +02:00
renovate[bot] 47306d1afd Update dependency intl-messageformat to v11.2.15 (#54213)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-15 16:33:19 +00:00
karwostsandCopilot Autofix powered by AI 1692067392 Fix create helper dialog (#54211)
* Fix create helper dialog

* Ensure loading state resets after import

Wrap import and dirty tracking in try-finally to ensure loading state is reset.

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-15 18:26:53 +02:00
Paul Bottein 546315ca5b Share entity display and search label helpers across pickers (#54192) 2026-09-15 15:45:04 +03:00
renovate[bot] 7c98912b73 Update formatjs (#54162)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-15 15:42:31 +03:00
Bram KragtenandClaude Opus 5 8c72e9c22d Remove unused Material Web wrappers (#54198)
`ha-outlined-button` and `ha-outlined-field` had no references anywhere
in the repository, so their custom elements were never registered at
runtime. `ha-sub-menu` was imported by five config panels, but no
template renders the tag.

Removes three `@material/web/**/internal/**` import sites; Material Web
is now only reached from chips, list, ripple and iconbutton.

Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-15 15:30:00 +03:00
Lucas Mindêllo de Andrade 892514ed21 Show toggle for fan entity only if TURN_ON or TURN_OFF is supported (#54188)
* fix(fan): keep toggle only if on off is supported

* feat(lovelace): add fan entity row

* code review adjusts
2026-09-15 15:26:14 +03:00
Bruno Pantaleão GonçalvesandClaude 06be6f433d Add more info opened and closed external bus messages (#54187)
Co-authored-by: Claude <[email protected]>
2026-09-15 09:29:34 +02:00
renovate[bot] e9a6e2936d Update dependency nanoid to v6 (#54189) 2026-09-15 07:13:27 +00:00
d3b7d787b4 Add trigger ID auto-generation and selection (#54130)
* Add trigger ID auto-generation and selection

* Fix trigger list index and descriptions

* Potential fix for blueprint crash

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Split cleanup

* Process Wendelin code review comments

* Process Marcin code review comments

* Remove unused controller config option

* Swap

* Fix minor review comments

* Update src/panels/config/automation/condition/types/ha-automation-condition-trigger.ts

* Update src/panels/config/automation/condition/types/ha-automation-condition-trigger.ts

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2026-09-15 09:07:03 +02:00
renovate[bot] 0662f8238f Update dependency hls.js to v1.7.3 (#54181)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-15 06:17:17 +02:00
Jonas PeterssonandJonas Petersson 8a59516d8f Support glass break binary sensors (#53989)
* feat(security): support glass break binary sensors

* fix: add glass_break translation for device class override dropdown

* fix: add glass_break to generated device classes list

* fix: add glass_break icon to entity component icons for demo/fake data

---------

Co-authored-by: Jonas Petersson <[email protected]>
2026-09-14 17:44:15 +02:00
Petar Petrov 0afe6bb136 Cap unsupported config warning height so YAML fallback stays visible (#54177) 2026-09-14 16:52:31 +02:00
Bram KragtenandClaude Opus 5 61b487f995 Rename "For" to "For at least" and let duration inputs fill the row (#54175)
Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-14 15:35:18 +02:00
91abff2d0c Hide "for" on state condition when matching an attribute (#52710)
* Hide "for" on state condition when matching an attribute

The legacy state condition measures the `for` duration against
`last_changed`, which only updates on state changes, not attribute
changes. So `for` together with `attribute` is unreliable and core is
moving to reject it. Omit the `for` field when an attribute is selected,
drop any lingering duration value, and explain why via a helper.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Keep "for" visible but disabled when matching an attribute

Removing the field left the explanation pointing at a control that was no
longer on screen. Keep "for" in the form, disable it while an attribute is
selected, and move the helper text under it.

Co-Authored-By: Claude Opus 5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.8 <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-09-14 16:32:15 +03:00
Bram KragtenandClaude Opus 5 53d16c97fe Keep helper text readable on disabled fields (#54174)
Disabled fields dimmed their helper text to the disabled ink color, which
drops it to 2.6:1 contrast in light mode (5.7:1 when enabled). Helper text
is guidance about the control rather than part of its value, and it is often
the only thing explaining why a field is disabled, so keep it at its regular
contrast. The disabled state is still carried by the label, the value, and
the missing clear button.

Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-14 16:17:43 +03:00
Bram KragtenandClaude Opus 5 7493bfc86c Honor configured name in bootstrap formatEntityName (#54172)
Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-14 14:39:26 +02:00
infernalK ca1eb4ed7d Fix TypeError when hass.panels changes while rebuild() is in flight (#54171)
_updateRoutes() awaits this.rebuild() and then reads
this.hass.panels[this._currentPage].component_name without checking that
the entry still exists. hass.panels can be replaced again while the
rebuild() await is pending (e.g. multiple integrations or HACS-managed
Lovelace resources updating panels around startup), leaving
this._currentPage pointing at a panel that is no longer present. The
resulting TypeError breaks rendering of the current dashboard.

Guard the access after the await and bail out when the panel is gone:
willUpdate already re-triggers _updateRoutes for the newer hass.panels
value in that race, so returning early is safe and avoids the crash.

Fixes #54006
2026-09-14 15:38:16 +03:00
Petar PetrovandCopilot Autofix powered by AI c1dd17c4f9 Show Energy Now view for water and gas flow without power sensors (#54100)
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-14 14:34:38 +02:00
Stu Kabakoff 5c74a84d01 show up to 5 discrete buttons on fan cards (#54137)
show up to 5 discrete buttons to fan card
2026-09-14 14:14:41 +02:00
shbatmandPetar Petrov a51d255ec3 Show disabled entities when filtering entities by device or area (#53444)
* Show disabled entities when filtering entities by device or area

The device and area filters on the entities config page resolve their
selection through search/related, which omits disabled entities. Opt in
to the new include_disabled_entities option there, so that filtering by
a device or area no longer hides that device's disabled entities.

The option is only set on the entities page, so every other consumer of
findRelated keeps its current behaviour.

* Update src/panels/config/entities/ha-config-entities.ts

Co-authored-by: Petar Petrov <[email protected]>

* Update src/panels/config/entities/ha-config-entities.ts

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-09-14 13:25:35 +02:00
Petar Petrov 8c0dec0d9a Align stacked statistics lines across recorder gaps (#54166)
ECharts stacks a time axis by data index, so a statistic with a gap or a
different range shifted every stacked line after it. Merge the stacked line
datasets onto one timeline, let ECharts sample them after stacking, and hide
the padded null rows in the tooltip.
2026-09-14 13:49:48 +03:00
renovate[bot] 2c4b3c9109 Update dependency @rsdoctor/rspack-plugin to v1.6.4 (#54170)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-14 13:34:56 +03:00
Petar Petrov c75bd2b5f0 Fix inconsistent grid labels in energy usage graph (#54168)
Make energy usage graph grid consumption label name-first
2026-09-14 12:07:18 +02:00
Wendelin 9b1665f5bf Refactor more-info update backup row (#54119)
* Extract and refactor update-backup

* run requests in parallel

* Separate fetches

* fix
2026-09-14 10:53:46 +02:00
Wendelin 603528bf47 Landing page: provide and use i18n context (#54128)
Migrate landing page to internationalization context
2026-09-14 10:45:08 +02:00
Wendelin 030b962e26 ha-auth use i18n context (#54127)
Use i18n context in ha-auth
2026-09-14 10:39:07 +02:00
Wendelin 85a34aeeee Onboarding: use localize context (#54126)
* Migrate onboarding to use localize context

* Load onboarding fragment translations after hass initialization.
2026-09-14 10:29:02 +02:00
iven 44dd2249b5 Fix calendar card collapsing with auto height (#54159)
* Fix calendar card collapsing with auto height

* Detect auto height from legacy layout_options
2026-09-14 09:52:04 +02:00
Yosi Levy f073a12cbd RTL chevron fixes (#53771)
* RTL chevron fixes

* Name changes

* Label fix

* Fix missing import
2026-09-14 09:43:41 +02:00
Yosi Levy 7dec4a57e8 Various RTL fixes (#54117)
* Various RTL fixes

* Fixes - no keyboard focus

* Fix style
2026-09-14 06:47:51 +02:00
Paulus SchoutsenandClaude aa78f368b1 Fix discovery list covering card corners on network page (#54157)
The ha-md-list inside the network discovery card draws its own surface
background. That square background hides the rounded bottom corners of
the card. Remove the list background so the card shows through.


Claude-Session: https://claude.ai/code/session_01PLf4NaCFm5tWguyUSmSAEx

Co-authored-by: Claude <[email protected]>
2026-09-14 06:47:01 +02:00
renovate[bot] 06901dedaa Update dependency lint-staged to v17.5.1 (#54155)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-14 06:45:23 +02:00
renovate[bot] 43f194dad2 Update dependency vite to v8.3.0 (#54156)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-14 06:45:04 +02:00
renovate[bot] e7acf97b1a Update babel monorepo to v8.0.5 (#54161)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-14 06:44:12 +02:00
Paulus SchoutsenandClaude Opus 5 9409db7fda Show YAML-configured Modbus hubs in the Modbus panel (#54134)
* Show YAML-configured Modbus hubs in the connections panel

The backend now lists a hub configured in YAML as a connection of its
own, flagged with its source. Render those rows with the hub name and
the units it addresses, marked as configured in YAML, since there is no
config entry to link to.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018gAhZ9auwjmQaTg91efAD4

* Demo the Modbus YAML hub on a TCP device

One serial port cannot carry two links, so a YAML hub sharing the
RS-485 port was not a state the panel can reach. Put the hub on the TCP
device an integration also talks to, where two sockets are real.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018gAhZ9auwjmQaTg91efAD4

---------

Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-13 07:08:44 +00:00
dependabot[bot] d917df359f Bump home-assistant/actions/helpers/verify-version from a7c616ce81ccda50150bf1595786c71b1883fabb to 58bff37c8947f690ace498be413a9b78d6f30f93 (#54138)
Bump home-assistant/actions/helpers/verify-version

Bumps [home-assistant/actions/helpers/verify-version](https://github.com/home-assistant/actions) from a7c616ce81ccda50150bf1595786c71b1883fabb to 58bff37c8947f690ace498be413a9b78d6f30f93.
- [Release notes](https://github.com/home-assistant/actions/releases)
- [Commits](https://github.com/home-assistant/actions/compare/a7c616ce81ccda50150bf1595786c71b1883fabb...58bff37c8947f690ace498be413a9b78d6f30f93)

---
updated-dependencies:
- dependency-name: home-assistant/actions/helpers/verify-version
  dependency-version: 58bff37c8947f690ace498be413a9b78d6f30f93
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 09:36:50 +03:00
Petar PetrovandCursor Agent 6dcca89185 Move history-graph card timeline names under the bars (#54102)
* Move history-graph card timeline names under the bars

Enable the same inside-labels layout as the History panel on the
Lovelace history-graph card. Custom entity names still override
the default Device ▸ Entity labels from computeHistory.

* Keep compact timeline rows when names are hidden

inside-labels only applies when the history-graph card is showing
names, and the timeline uses the taller row height only when those
under-bar labels are actually drawn.

* Match timeline row height to when inside labels are drawn

Use the same chunked || showNames condition as the axis options so
virtualized charts keep enough room for under-bar names. String YAML
names still apply when the entity is missing from current state;
structured names fall through to computeHistory instead of the entity ID.

* Preserve structured YAML names without a current state

formatEntityName still needs an entity id when the override is an
EntityNameItem. Use a stub state so device/text/entity name configs
apply even if the entity is missing from hass.states.

---------

Co-authored-by: Cursor Agent <[email protected]>
2026-09-12 13:28:53 +02:00
Wendelin 3f1b2ef65f Onboarding: lite internationalization context (#54125)
* Add internatinalization context to onboarding

* Use the context in welcome
2026-09-12 11:53:30 +02:00
Petar Petrov 34afbe37c3 Use ha-control-circular-slider in the light card (#54123)
Replace the legacy @thomasloven/round-slider brightness ring with the
in-house ha-control-circular-slider (already used by the thermostat and
humidifier cards). The card keeps its layout, center toggle button,
brightness readout, size, and all config options, so existing dashboards
are unaffected. The light card was the last consumer of round-slider, so
the dependency and its patch are dropped.
2026-09-12 11:53:05 +02:00
renovate[bot] 848e81313e Update dependency jszip to v3.10.2 (#54132)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-12 09:32:56 +03:00
Paul Bottein 24e7bd306a Sync My redirects with my.home-assistant.io (#53956) 2026-09-11 16:13:45 +02:00
3791548067 Show every selector on the gallery selector page (#54121)
* Show the serial port selector in the gallery

The selector page had no serial_port entry, so the picker could only be
exercised against a running instance with real hardware attached.

Add it to "One of each", backed by a scan mock with one port per section
the picker groups by. The entry carries a flow context, and the page now
forwards that to ha-selector, because the recommended and not recommended
grouping is keyed off the domain a config flow supplies.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NTxTXXEY4FnQryNFbtB5tf

* Answer the ingress panel list in the supervisor demo stub

The navigation picker waits for that collection before it enables itself,
so with the endpoint rejecting it stayed disabled for the whole demo and
gallery, with nothing on screen to say why.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NTxTXXEY4FnQryNFbtB5tf

* Show every selector on the gallery selector page

Twenty-nine of the sixty selectors had no entry, so they could only be
looked at inside a config flow or a blueprint that happened to use one.

Add the missing entries to "One of each", with the mocks the assist and
statistic pickers need to return a list. A few carry a value or a config
because they render their fallback without one: the meta selector reads
the first key of its value, the period selector offers its custom-period
editor, and the voice list is fetched per engine and language.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NTxTXXEY4FnQryNFbtB5tf

* Add new serial port configuration

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-11 17:11:41 +03:00
01cef9a99b Fix trigger 'for' choose (#53749)
* Fix trigger 'for' choose

* fix stub

* try something else

* merge duration-selector with create_duration_data

* handle negatives

* default ms to false for selector

* Handle hidden duration units in ha-duration-input

createDurationData grew three flags describing which fields the duration
input renders, but the input already owns enableDay, enableMillisecond,
enableSecond and allowNegative. Fold the units it does not render there
instead, so createDurationData keeps its single-argument signature.

This handles days and milliseconds symmetrically, and covers every
ha-duration-input consumer rather than only ha-selector-duration:
ha-form-positive_time_period_dict passes .data straight through without
enable-day and dropped days in exactly the same way.

A leading "-" negates the whole period in cv.time_period_str, so the
sign is now always distributed across all parts. The calendar trigger is
the only caller that can see a negative value and does its own sign
handling, so it takes the absolute value of every part instead of just
hours, and copies the duration first since createDurationData returns
dict values by reference.

Co-Authored-By: Claude Opus 5 <[email protected]>

* cleanup calendar trigger

* Refine duration type check for object values

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

---------

Co-authored-by: Bram Kragten <[email protected]>
Co-authored-by: Claude Opus 5 <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-11 16:34:29 +03:00
Bram Kragten 380e9b5a81 Bumped version to 20260826.7 2026-09-11 15:31:53 +02:00
Paulus SchoutsenandClaude de21f7ef43 Prevent closing the backup restore dialog by clicking outside (#54095)
Prevent scrim close on backup restore dialog

Clicking outside the restore dialog dismissed it unless the encryption
key field was dirty. Restoring a backup is destructive, so guard the
dialog at every step.


Claude-Session: https://claude.ai/code/session_017eZQ6BTz6MervuG3Zb8RLp

Co-authored-by: Claude <[email protected]>
2026-09-11 15:31:20 +02:00
Petar Petrov fa3c12050c Fix login form ignoring password-manager autofill (#54076) 2026-09-11 15:31:19 +02:00
Wendelin bee8497724 Fix update last backup description (#54066) 2026-09-11 15:31:18 +02:00
Wendelin 2de21fad27 Fix automation trigger/condition platform default behavior (#54062)
* Fix platform behavior default

* Fix race condition by updating target entity count and setting default behavior
2026-09-11 15:31:17 +02:00
Wendelin 72fcf19091 Fix add TCA mobile list width (#54054) 2026-09-11 15:31:16 +02:00
nokside efa322cc6b Fix and centralize selector initial value handling (#53729)
* Fix and centralize selector initial value handling

* Fix unsupported selector initial values

* Omit undefined choose child values

* Fix device class and object selector initial values
2026-09-11 15:31:15 +02:00
Steffen ProbstandClaude Fable 5 8eb179a0d9 Show pointer cursor on the whole track of the light card's round-slider (#53723)
The classic light card uses @thomasloven/round-slider, whose invisible
`.shadowpath` arc already accepts click/drag (nearest handle follows), but
only the handle dot showed a pointer cursor. Patch the dependency (same
mechanism as leaflet-draw/sortablejs) so the whole track shows the pointer,
and falls back to the default cursor when the slider is disabled or has no
handle. Adds a `--round-slider-path-cursor` override (defaults to
`--round-slider-handle-cursor`).

Co-authored-by: Claude Fable 5 <[email protected]>
2026-09-11 16:10:07 +03:00
pcan08andClaude Sonnet 4.6 34e9b50920 Redesign integration card and remove double navigation (#52828)
* Redesign integration card to align with apps card style

Replace ha-button navigation links with a plain count badge, remove the
ha-icon-next chevron, make the entire card clickable on all content, and match the apps card hover/separator/spacing patterns.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Extract integration card footer into ha-integration-card-footer

Move footer rendering logic (count badge, custom/cloud/yaml icons) and
their computations into a dedicated component, mirroring the
ha-integration-header split.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Rename `ha-integration-header` to `ha-integration-card-header`

* Fix count badge vertical centering in integration card footer

* Replace hardcoded pixel values with spacing tokens

* Remove redundant physical margin properties

* Use consistent <span> elements for footer icons

* Remove dead CSS properties

* Add align-items: flex-start to secondary row

* Push integration card footer to bottom regardless of title length

* Migrate to Lit contexts

* Remove idvider in app and integration card

---------

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
2026-09-11 15:16:09 +03:00
Paul Bottein 2ebe452334 Add idle state and stop action to lawn mower (#53957) 2026-09-11 09:58:49 +00:00
renovate[bot] 3052989e9d Update dependency @rspack/core to v2.2.3 (#54118) 2026-09-11 11:39:13 +02:00
Preethi Pantangi fcab4004b2 Reserve min-height for view header to prevent layout shift (#54115) 2026-09-11 09:55:18 +01:00
renovate[bot] 4610adb368 Update dependency marked to v18.0.12 (#54114)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-11 06:42:59 +02:00
renovate[bot] e0dba17b66 Update dependency typescript-eslint to v8.70.0 (#54112)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-11 06:42:41 +02:00
karwosts eee0f9447b Format media selector in object selector (#54107)
Format media selector in object title
2026-09-10 18:34:03 +02:00
Paul Bottein 8d149a914f Add parent device to entity ID format (#54060)
* Add parent device to entity ID format editor

* Explain entity ID format examples with their context

* Share the entity name type list with the entity ID format editor

* Keep filter chip padding stable without a leading icon

* Show one entity ID format example at a time in a separate card

* Shorten entity ID format example names
2026-09-10 16:52:04 +03:00
Paul Bottein b2bb3e9d9d Nest child devices under their parent in device trees (#54063)
* Nest child devices under their parent in the entity tree

* Resolve device entries through shared helpers in the automation target browser

* Nest child devices under their parent when browsing automation targets

* Nest child devices under their parent in target details

* Skip child device rows already nested under their parent in area targets

* Fix expanding the automation target tree to an entity attached to an area

* Skip labeled child device rows already nested under a labeled parent

* Extract target sub-row computation and test child device nesting

* Use the inherited area when hiding filtered child devices

* Keep a parent device as a group row when a child device matches

* Keep child devices at the top level when their parent is disabled

* Drop disabled-parent special cases, core disables children with their parent
2026-09-10 15:46:28 +02:00
karwostsandCopilot Autofix powered by AI 13ef9712bc Use 'image_proxy' endpoint for image entity backgrounds (#54038)
* Use 'image_proxy' endpoint for image entity backgrounds

* Update image source URL with hassUrl method

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* handle concurrent updates

* more robust

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-10 16:42:26 +03:00
Jump-333 40b27608c0 Add buttons style to target-humidity card feature (#53901)
* Add buttons style to target-humidity card feature

* Removed step configuration per-card

* Remove 'step' key from style list in translations

* Add target humidity step to humidity card feature

* Fixed a typo

* Updated style and style_list keys with localization keys.
2026-09-10 16:31:54 +03:00
Aidan Timson e0f03254b5 Show active alerts on Home dashboard (#53526)
* Show security alerts on Home

* Refresh Home security alerts

* Fix Home security alert state handling

* Fix Home alert fallback state

* Render Home alerts as individual cards

* Implement as summaries alerts and warnings in secondary for security
2026-09-10 16:03:49 +03:00
Petar Petrov 35dcba4f3f Fix login form ignoring password-manager autofill (#54076) 2026-09-10 14:31:57 +02:00
Paul Bottein ec4bfc9255 Add parent device to entity context (#53766)
* Add parent device to entity context

* Fix parent device context display edge cases

* Fix parent device context in suggestions and completions

* Order entity name parts by hierarchy

* Remove unused parent device missing string

* Add parent device to logbook entry context

* Show inherited area and parent device for device targets

* Test parent device search in the entity tree

* Show inherited area and parent device in the automation target header

* Move the device domain lookup out of target row item data

* Pass registries to memoized entity name lists

* Document parent device in logbook name detail
2026-09-10 13:38:39 +02:00
Maarten Lakerveld 3b9e026aff Edit zones and locations on the map engine instead of leaflet-draw (#54023)
* Edit zones and locations on the map engine instead of leaflet-draw

ha-locations-editor (zone config, the location selector, onboarding)
used raw Leaflet layers and leaflet-draw, which pinned it to the Leaflet
engine. Its interaction surface is three gestures - drag a marker, drag
a zone center, drag a zone radius handle - so no editing library is
needed.

MapEngine gains an optional editing capability (draggable markers and an
addEditableCircle primitive) plus panTo and containsLocation. Only the
MapLibre engine implements editing: the circle geometry plus a draggable
center marker and a draggable radius handle on the east edge, the radius
derived from the great-circle distance between them, redrawn per frame
while dragging. The handle has a touch-sized hit target and is a
keyboard-operable slider with an accessible name. The Leaflet engine
stays a viewing fallback: without WebGL2 an editor shows its locations
as static markers and a notice that this browser cannot edit on the map.

ha-map exposes editableLocations and fires
editable-location-moved/resized/clicked and editing-available-changed.
Locations are reconciled by id: position and radius changes move the
existing handles, while a changed icon, name, color, or editability
rebuilds the marker, so edits made in the form fields show up on the
map on either engine. ha-locations-editor becomes a thin layer over
that with its public contract unchanged, so its consumers need no
changes; it reads localize from the internationalization context instead
of taking hass.

The zone panel no longer zooms the map when a selection comes from the
map itself. Clicking or dragging a marker selects its list item, and
mwc-list reports that programmatic selection with the same "property"
request-selected event a click ends with. The two are told apart by
timing: a selection from the map has already set the active entry when
its event arrives, while a click's event arrives before the handler
sets it. Skipping the programmatic event also keeps the item selected,
which the shared request-selected helper would otherwise reset.

The layers property and the engine selector are removed along with the
leaflet-draw dependency and its patch: Leaflet is now purely the viewing
fallback, selected by WebGL2 support alone. The Leaflet engine keeps a
leafletMap field for the ha-map fit tests, which run on it in jsdom.

* Keep the retained circle data current while resizing

The engine keeps its source specifications to rebuild them after a style
swap; the editable circle's redraw updates that copy along with the map.

* Address code review on map editing

Editable markers, the circle center on both engines, and the static
fallback center activate on Enter and Space, as their button role
promises. Locations without a name get a localized one, since onboarding
and the location selector pass none. The resize handle's advertised
maximum follows the radius instead of being exceeded by it, and the
handle stays near the circle at high latitudes.

Clicking the active zone row zoomed to it again upstream but was
swallowed by the check that told a map-driven selection from a click; a
one-shot flag on selections made in code replaces that inference. The
engine rebuilds its sources from its own record on a style swap, so a
radius changed while the style was unloaded is not lost.

* Test the map editing path

The MapLibre engine's editable circle against the fake map: dragging the
center moves the circle and the handle and reports the drop, dragging the
handle resizes and snaps it back, arrow keys resize in steps committed on
release, the advertised maximum follows a larger radius, one update
echoing pre-drag values is ignored, the center activates by click, Enter
and Space but not after a drag, and removal clears markers, layers and
listeners.

ha-map's reconciliation of editable locations through a fake engine with
editing support: circles and markers are drawn, moved in place, rebuilt
when their appearance changes and removed when dropped, move, resize and
activation events carry the location id, and an engine without editing
support shows the locations statically.

* Leave zone row selection to the user

Clicking or dragging a zone on the map, and saving one in the dialog,
selected its row in code. That selection fires the same request-selected
event a click ends with, so the page had to tell the two apart, and the
row could not be shown selected and stay clickable at the same time: the
highlight never actually appeared. The list now only follows the user's
own clicks, which removes that bookkeeping along with the zoom that a
radius drag used to trigger.

* Hand marker elements back clean, and record sources before the style loads

MapLibre leaves its positioning class and transform on a marker element
after removal. Hosts like ha-locations-editor cache their elements and
hand them to whatever engine draws next: after a fatal WebGL failure that
is the Leaflet fallback, which shows the locations statically. A removed
element, and every element still on the map when the engine is destroyed,
is reset so it arrives as a plain element. The editable circle's center
gets the same treatment.

Custom sources and layers are now recorded when added and only inserted
into the map once the style has loaded. A circle moved while a swapped
style was still loading therefore reaches the record, and a swap in that
window carries it over; the deferred insert skips what the swap already
placed.

* Guard a keyboard resize against host updates like a drag

Arrow-key resizing changed the radius without arming the pre-edit guard
that pointer drags use, so a host re-render with the old radius while a
key was held, or its echo right after the commit, snapped the circle
back. A key resize now counts as a drag from the first key press until
the commit.

* Let the engine own the drag cursor, and tidy the fallback notice

The move cursor came from stylesheets keyed on whether a location may be
edited, so it showed on circles that cannot move and on the static
Leaflet fallback. The MapLibre engine now sets it on the elements it
actually made draggable and clears it when handing them back.

The fallback notice said the browser cannot edit locations, while
clicking the map to place one still works there; it now names what is
missing, dragging markers and resizing zones. The editor's
internationalization context is reactive, like its neighbours.

* Show the fallback notice only when a location is editable

The Leaflet fallback showed the notice for every editor, including ones
whose locations are all read-only, where nothing is missing.

* Drop the named icon's move cursor, and describe the fallback as a map state

The Leaflet fallback draws named location icons statically, but the
stylesheet still gave the ones marked editable a move cursor. The engine
sets that cursor on the elements it actually drags, so the rule goes.

The fallback notice blamed the browser, while MapLibre can also be
unavailable after a failed start or a lost WebGL context; it now
describes what the map offers. The resize handle's east point only guards
the pole itself, so its distance agrees with distanceMeters wherever a
zone can be.

* Announce the fallback notice, and let test frames redraw

The notice appears after the engine has been chosen, so helper text
would not reach a screen reader; it is an alert now. The engine test's
frame stub returned an id that landed in the engine's pending frame after
the callback had cleared it, so every redraw after the first was skipped.

* Show the fallback notice over the map, and keep handle clicks off the map

The notice followed a map that fills the editor's fixed height, so it
landed outside the box: clipped in onboarding, spilling into the form in
the location selector. It now sits over the top of the map, clear of the
zoom control.

The resize handle was the one marker whose click reached MapLibre's map
click, which a pin-on-click host takes as a request to move the location
there; the handle stops it like the other markers do.

* Share one circle geometry, and keep arrow keys on the handle

Drawing, fitting, and handle placement each converted meters to degrees
on their own, with different pole guards, so above 89.4 degrees the
resize handle left the drawn circle. They now share one conversion that
also agrees with distanceMeters; only the pole itself is guarded.

Arrow keys on the resize handle also reached MapLibre's keyboard handler
and panned the map while resizing; the handle keeps them.

* Drop the zone page's active entry

It only re-selected the row the user had just clicked, after the shared
request-selected helper had reset it, which fired the selection event a
second time and zoomed to the zone twice. The row highlight comes from
the list itself and nothing else read the value, so the list no longer
mirrors a selection at all.

* Make marker activation opt-in, and relabel handles on language change

Every editable marker was a focusable button whose activation fired an
event, whether or not the host did anything with it: the zone page and
the location selector do not. Activation is now opt-in per location; the
onboarding search results opt in, and a marker that does not act on it is
draggable without button semantics. The engine contract separates taking
pointer input from being a keyboard-focusable button for that.

Marker titles and handle labels are localized when drawn, so a language
change, or localization arriving after the first draw, redraws them.

* Own the accessibility attributes the engine sets, and use spherical circle geometry

setMarkerAccessibility only filled in what was missing and nothing removed
it, so a cached element rebuilt with a new title or a different role kept
the old attributes. The helper now records what it set, replaces exactly
that on a rebuild, and clears it when the element leaves the map, while a
caller's own attributes stay untouched.

The flat meters-to-degrees conversion broke down for large circles near
the poles, wrapping longitude and producing latitudes beyond 90. Handle
placement and the polygon now use the great-circle destination, and the
fitted bounds a spherical box that spans all longitudes once the circle
reaches a pole, so all three agree with distanceMeters everywhere.
2026-09-10 11:31:06 +02:00
Petar Petrov 569bcc01da Fix frozen solar-to-grid dot and phantom solar dot in energy distribution card (#54085) 2026-09-10 10:20:38 +01:00
Petar PetrovandCursor Agent 8ea28508c3 Move history timeline names under the bars (#54086)
Co-authored-by: Cursor Agent <[email protected]>
2026-09-10 09:58:48 +01:00
Dominik c3e341bdb3 Unify trend-graph and temperature-forecast card-features (#54037)
Unify trend-graph and temperature-forecast
2026-09-10 09:01:57 +03:00
Paulus SchoutsenandClaude 58de8df46a Prevent closing the backup restore dialog by clicking outside (#54095)
Prevent scrim close on backup restore dialog

Clicking outside the restore dialog dismissed it unless the encryption
key field was dirty. Restoring a backup is destructive, so guard the
dialog at every step.


Claude-Session: https://claude.ai/code/session_017eZQ6BTz6MervuG3Zb8RLp

Co-authored-by: Claude <[email protected]>
2026-09-10 08:15:47 +03:00
karwosts 3447e1d862 An empty placeholder for entity-filter-badge in edit mode (#54096) 2026-09-10 08:15:02 +03:00
renovate[bot] 105a2a2423 Update Node.js to v24.21.0 (#54097)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-10 07:00:24 +02:00
Larai 27efa82a89 Fix accessible names for analytics consent switches (#54083) 2026-09-09 18:23:13 +02:00
Josef Zweck 19cf7f2613 Allow shared translations for subentry abort (#53964)
* Allow shared translations for subentry abort

* load translation
2026-09-09 18:18:41 +02:00
Josef Zweck fcd25e41a0 Make sure we load shared translations in config flow (#54084)
* Make sure we load shared translations in config flow

* load translation for specified domain
2026-09-09 18:18:00 +02:00
Aidan TimsonandPetar Petrov f942a5afe5 Add visibility condition reordering (#53252)
Co-authored-by: Petar Petrov <[email protected]>
2026-09-09 14:49:01 +02:00
Aidan TimsonandCopilot Autofix powered by AI 89b745b851 Add contextual descriptions to rows in card condition editor (#52817)
* Add row targets UI to entity state and numeric state in card condition editor

* Use automation descriptions instead of target ui

* Type check

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Format condition editor

* Fix contextual condition descriptions

* Resolve state references in condition descriptions

* Share automation condition headers with visibility conditions

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-09 15:29:42 +03:00
Maarten LakerveldandCopilot Autofix powered by AI ac582cbfbb Run ha-map on a runtime-selected engine: MapLibre GL native or Leaflet (#54022)
* Run ha-map on a runtime-selected engine: MapLibre GL native or Leaflet

ha-map no longer drives Leaflet directly. All primitive operations -
camera, HTML element markers, meter-radius circles, history paths,
clustering with a pluggable icon builder, scale ruler, dark mode - go
through a MapEngine interface, and the engine is selected at runtime:

- MapLibreMapEngine renders the vector base map natively where WebGL2 is
  available, without Leaflet in the loop: continuous fractional zoom,
  DOM markers synced to the basemap every frame, GeoJSON zone and
  accuracy circles below the labels, GeoJSON history trails with hover
  popups, and a pixel-distance cluster grid recomputed when the camera
  settles. Dark mode swaps the style while carrying the custom layers
  over, and rotation and pitch stay disabled for north-up dashboards.
- LeafletMapEngine wraps the existing behavior unchanged (vector tiles
  through the maplibre adapter with the raster fallback, markercluster)
  for browsers without WebGL2 - the legacy floor includes iOS 12-14 and
  kiosk browsers without hardware acceleration - and for
  ha-locations-editor, which manages raw Leaflet layers with
  leaflet-draw and declares engine=leaflet.

A permanently lost WebGL context rebuilds the map on the Leaflet engine
instead of leaving a dead canvas. Zoom levels keep Leaflet semantics
across engines. MapLibre's stylesheet is shipped to /static/map for the
native engine's controls and popups.

* Enhance keyboard accessibility for icon click

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Fix dark mode style application logic

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Address code review on the map engine

A fatal engine event during setup was dropped because the in-flight
setup owned the loading flag; the fallback request is now recorded and
setup switches to Leaflet once init settles. Entity markers accept Enter
and Space, as both engines make them focusable buttons. History points
show their popup on tap as well as hover, since touch has no hover.

Tests cover the engine choice and fallback paths, including a fatal
event mid-setup, and the MapLibre engine itself against a fake map:
style swaps, queued layer work, custom layer carry-over, failed style
requests, token refusal recovery, context-loss grace, and clustering.

* Address second code review round on the map engine

A cluster whose members share a spot, or that sits at maximum zoom,
could never be opened: fitting its bounds changed nothing and the next
regroup recreated it. Activating such a cluster now opens it: all its
members are shown in a bubble with a tail pointing at their spot, each
reachable on its own, until the map moves again.

An engine whose init failed, or was abandoned by a disconnect or a fatal
event during setup, was never destroyed and could keep a WebGL context;
setup now destroys any engine that did not become the active one.

The Leaflet engine sizes the cluster element like MapLibre does, so
cluster bubbles no longer shrink to their text.

* Keep the engine's own record of its map sources and layers

Carrying zone circles and history paths over a style swap relied on
MapLibre serializing the outgoing style into transformStyle's previous
argument. The engine now keeps the source and layer specifications it
added and rebuilds them into the new style itself, so the carry-over no
longer depends on what MapLibre hands over, and a missing previous style
cannot drop them.

* Address review: setup teardown, marker input, cluster focus

An engine still setting up could not be torn down: ha-map only held it
once init resolved, so removing the element mid-load kept its WebGL
context alive and left the loading guard set, ignoring a reconnect. The
engine being set up is now tracked and destroyed on disconnect, a stale
setup notices it was superseded, and the MapLibre engine settles a
pending init when destroyed.

Non-interactive markers let pointer input through, as they do on
Leaflet. Opening a cluster from the keyboard moves focus to its first
member, and a member that has focus when the bubble closes hands it to
the icon that replaces it.

* Tear down an engine that fails while still setting up

A fatal event during setup only flagged the fallback and waited for
init to settle, which relied on MapLibre still firing style.load. The
engine being set up is destroyed instead, which settles its init, so the
setup hands over to Leaflet without depending on the failed engine.

* Make history point popups readable on MapLibre

MapLibre's stylesheet is linked into the map's shadow root and wins over
the component styles on equal specificity, property by property: its
white popup background applied while our white text color did too,
leaving the timestamp invisible. The popup rules now carry !important,
as the Leaflet tooltip rules already do for the same reason.

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-09 15:26:28 +03:00
Petar Petrov dab85a9239 Add show_values toggle to all Sankey cards (#54075) 2026-09-09 12:09:44 +01:00
Wendelin 29e0e9db87 Add paste to add automation element by target (#54052) 2026-09-09 11:08:37 +01:00
Wendelin 3ce90a7a68 Fix update last backup description (#54066) 2026-09-09 10:59:17 +02:00
dependabot[bot] d6260482e0 Bump svgo from 4.0.2 to 4.1.0 (#54078)
Signed-off-by: dependabot[bot] <[email protected]>
2026-09-09 08:49:27 +01:00
ca24b16702 Add show_values toggle to energy and power Sankey cards (#53925)
* Add show_values toggle to energy and power Sankey cards

Adds a boolean config option that renders each node's value directly
on its diagram label (e.g. "Solar\n3.4 kWh"), stripping HTML from the
valueFormatter output for ECharts plain-text labels.

Fix show_values label alignment on Sankey nodes

Collapse internal whitespace in valueFormatter output after stripping
HTML tags, so "7.7\n      kWh" becomes "7.7 kWh" on a single line.

* Address review feedback on show_values

Removes the HTML-tag-stripping regex from the label formatter (an
incomplete-sanitization pattern flagged by CodeQL); the value
formatter never returns HTML and the label renders as plain ECharts
canvas text, so no stripping is needed. Splits the vertical
label-sizing measurement on all whitespace instead of literal spaces,
so the newline-separated value line is measured correctly. Scopes
show_values to the energy and power Sankey card configs instead of
the shared Sankey base, and hides the option in the card editor for
water and water-flow cards, since those cards don't support it.

* Apply batched suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Format Sankey card templates with Prettier

Restore Prettier wrapping around the show_values template bindings so CI lint:prettier passes.

* Fix vertical Sankey value labels wrapping on thin nodes

Unicode isolates around show_values text were treated as wrap characters, and font sizing ignored ECharts minMargin, so short names like TV with small values split mid-word. Size labels to the inner wrap width and keep LTR with a mark instead of isolates.

* Reserve extra bottom space for vertical Sankey values

When show_values is on, node labels can be three lines (name, number, unit). Increase the vertical series bottom inset from the single-line 25px so the lowest row is not clipped.

* Keep locale grouping spaces in Sankey value labels

Trim formatter output without collapsing internal whitespace, so narrow no-break thousands separators are not turned into wrap points. Measure the longest word on regular spaces and newlines only.

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Co-authored-by: Cursor Agent <[email protected]>
2026-09-09 09:32:27 +03:00
Wendelin 380bcb8315 Fix automation trigger/condition platform default behavior (#54062)
* Fix platform behavior default

* Fix race condition by updating target entity count and setting default behavior
2026-09-09 08:28:23 +03:00
karwosts 9902924ffa Use heading elements for heading-card (#54068) 2026-09-09 08:27:45 +03:00
Paulus SchoutsenandClaude Opus 5 cb0c03ab8b Add a Modbus panel (#54036)
* Add a Modbus panel

The Modbus integration exposes the connections it keeps open over
`modbus/connections/list`. This surfaces them under Connectivity, mirroring the
Serial panel: one entry per physical device, grouped by whether the link is up,
naming the config entries holding units on it.

Because one device is shared by every integration talking to it, the panel is
where a shared RS-485 bus or gateway becomes visible — the two integrations on
`/dev/ttyUSB1` cannot be seen from either integration's own page.

The Serial panel gains the other half of that: a port carrying a Modbus
connection now points at the Modbus panel. The two are matched on the device
path, which Modbus stores as configured, so both the scanned and the resolved
path are compared. Reaching Modbus is not required for the Serial panel to
load.

Demo fixtures come with it, so the connections and the shared bus can be seen
without a Home Assistant instance. The RS-485 port the Serial demo already
lists gains the two integrations that hold units on it.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01FjmjZsxhdj9ekGmhFHXg3p

* Modbus: show link state as an indicator, not a verdict

A closed link is not a fault. The library opens one when an integration next
polls, and a device is free to drop an idle one in between, so grouping the
connections into Connected and Disconnected cards behind a warning icon
reported trouble where there was none.

One list now, ordered by address alone, with a per-row indicator. A link
opening or closing no longer moves a row between cards, and the summary is a
count rather than a health verdict.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01FjmjZsxhdj9ekGmhFHXg3p

* Modbus: a serial port is open, not connected

Opening a serial port proves a device node exists; nothing on the wire has to
answer. Only a network connection performs a handshake, so "Connected" was
promising more than a serial row can know. Those rows read Open and Closed.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01FjmjZsxhdj9ekGmhFHXg3p

---------

Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-09 07:08:22 +02:00
Aidan Timson 64cda9e0e7 Clarify companion skill selection before frontend review (#54067) 2026-09-08 20:21:56 +02:00
renovate[bot] 94fdea6f00 Update dependency vite to v8.2.2 (#54058)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-08 15:26:50 +02:00
Petar PetrovandAidan Timson 37de8c4b15 Delegate dashboard visibility conditions to core (#52904)
* Add dashboard visibility condition classifier, translator and splitter

Pure-logic foundation for delegating dashboard visibility conditions to
core (#52836).

- Add a VisibilityCondition type spanning the client-only lovelace
  conditions (screen, user, view_columns, location, time) and core
  automation conditions, alongside the existing lovelace Condition.
- translate.ts: classify conditions as client- or server-evaluated and
  translate server ones to core format (entity -> entity_id, state_not
  -> not-wrap, numeric bound coercion), preserving lovelace's
  not = not(AND) semantics.
- split.ts: split a tree into maximal server subtrees (one subscription
  each, sibling-grouped) plus a three-valued client combiner.

* Add reactive condition evaluator controller

Phase B of delegating dashboard visibility conditions to core (#52836).

- ConditionEvaluatorController opens one subscribe_condition per server
  subtree, evaluates client leaves locally, observes screen/time
  boundaries, and exposes a tri-state visible/hidden/unknown result plus
  error. It recomputes on push/listener/hass/context change, debounces
  re-subscription when the tree changes, and tears down on disconnect.
- Add observeConditionChanges to listeners.ts (notify-only, decoupled
  from checkConditionsMet) and widen extract.ts to the VisibilityCondition
  tree, factoring time-boundary scheduling into a shared helper.

* Harden condition translation for incomplete and odd numeric inputs

Follow-up to the adversarial review of the translator (#52836):

- Incomplete/garbage state conditions (no entity, no value, or an empty
  object) now translate to an always-false core condition instead of a
  schema-invalid `state`, matching checkConditionsMet and avoiding a
  broken grouped subscription.
- numeric_state bounds: coerce only finite numeric strings (incl. "" -> 0)
  to numbers, pass genuine entity-id references through, and drop junk or
  non-finite strings (matching lovelace's "NaN -> ignored" and never
  emitting a non-JSON-serializable Infinity).

* Fix condition evaluator controller lifecycle edge cases

Follow-up to the adversarial review of the controller (#52836):

- Key re-subscription on a structural signature of the condition tree
  rather than array reference identity, so a host re-deriving the array
  each render neither starves the debounce nor churns subscriptions.
- Reset the published result to `unknown` on host disconnect so a
  detached/reconnecting host never renders a stale, no-longer-live result.
- Read hass lazily in the time-boundary listeners so timezone changes are
  picked up on the next boundary instead of being pinned at subscribe time.

* Evaluate dashboard visibility through the reactive condition evaluator

Rework ConditionalListenerMixin to derive visibility from
ConditionEvaluatorController instead of evaluating checkConditionsMet
synchronously. Stateful conditions (state, numeric_state, template, sun,
zone, device, integration) are delegated to core via subscribe_condition;
client-only conditions (screen, user, view_columns, location, time) stay
local. The mixin re-feeds the evaluator on connect and on hass/config/
column changes, and drives _updateVisibility from its tri-state verdict.

Consumers (hui-card, hui-badge, hui-section, hui-heading-badge,
hui-view-sidebar, hui-conditional-base) now read the mixin's
_conditionsVisible(), which prefers the server-aware verdict and falls back
to an optimistic synchronous seed while a server subtree is pending — exact
for legacy lovelace conditions (no flash for existing dashboards) and hidden
for core-only conditions until the server reports.

- fold the host entity_id context into the evaluator path via
  addEntityToCondition, and read core-format entity_id in
  checkStateCondition / checkStateNumericCondition so seed and server agree
- addEntityToCondition no longer grafts a context entity onto an
  already-core condition that carries its own entity_id
- the conditional card/row now evaluates legacy {entity, state} conditions
- cache the entity-folded array so the evaluator's signature memo holds
  across hass updates, and drop the cached verdict when the tree changes by
  value so the seed is used for the new tree

* Add server condition types to the dashboard visibility editor

Let the visibility editor add and edit the core-format server condition
types (template, sun, zone, device) by embedding the automation condition
editors, which already speak core format. ha-card-condition-editor
dispatches these types to ha-automation-condition-editor; the existing
lovelace editors and the and/or/not containers are unchanged, and because
the logical editors nest ha-card-condition-editor, mixed trees dispatch
each child correctly.

- extend the add-condition menu with the new types (icons + labels)
- suppress the client-side live-test for server-class conditions (and any
  logical tree containing one); checkConditionsMet can't evaluate them, so
  the indicator stays neutral instead of showing a misleading failure

Server-backed live-test and read-both/write-new conversion of lovelace
state/numeric_state conditions are follow-ups.

* Evaluate the visibility condition editor live-test through the reactive evaluator

Drive the per-condition live-test indicator with the same
ConditionEvaluatorController the dashboard uses at runtime, so server-class
conditions (template/sun/zone/device and core-format state/numeric_state) get
a real subscribe_condition-backed verdict instead of a neutral indicator.
Client-only conditions stay evaluated locally and mixed logical trees combine
both via three-valued logic.

- Fold the card entity into the observed condition exactly as the runtime
  mixin does, and memoize the folded array so the evaluator's signature memo
  keeps hitting on hass-only updates.
- Map the evaluator verdict to the indicator: visible -> pass, hidden -> fail,
  pending -> unknown, server error -> invalid (raw error shown as the tooltip
  detail, localized label kept as the aria-label).
- Keep a client-side validity check for purely client trees so a malformed
  client-only config still surfaces as invalid.
- Recurse the no-entity (filter-mode) suppression so nested entity-less
  conditions are handled, and report an as-yet-unknown manual test as no
  result rather than a failure.
- Drop the now-unused invalid-config alert and its orphaned translation keys.

* Evaluate the visibility status banner server-side

Drive the card-level visibility summary banner with the same
ConditionEvaluatorController used by the per-condition live-test, so a set
containing server-class conditions reports its real visible/hidden verdict
instead of being flagged as an invalid configuration.

- Add a distinct "unknown" banner state for while a server result is still
  pending, separate from "invalid" (a genuine configuration error).
- Keep a client-side validity check for purely client trees, and fold the
  card entity into the observed conditions, matching the per-condition editor.
- Extract isPureClientCondition (every leaf client-side, as opposed to
  isClientCondition's any-leaf) so both consumers share one classifier.

* Edit dashboard state conditions via the core condition editors

Route `state` / `numeric_state` visibility conditions to the core automation
condition editors (outside entity-filter mode), so they share one editing
surface with the server-class types and are authored in core format.

- Read both: existing lovelace-format conditions (`entity`, `state_not`, …)
  are translated to core for display; a `state_not` shows as `not(state)`.
- Write new with touch-to-convert: opening a condition leaves it untouched;
  editing or adding one persists it in core format (`entity_id`, `state` list).
- Entity-filter mode keeps the lovelace no-entity syntax and editors.
- Register the core `state` / `numeric_state` editors (dynamicElement only
  renders a tag, it does not define the element) and widen the editor chain's
  condition arrays to the mixed visibility union.

* Remove the superseded client-only condition listeners

The dashboard now evaluates visibility through the reactive condition
evaluator (which uses `observeConditionChanges`), so the old synchronous
client-only listener path has no remaining callers.

- Delete `ConditionListenersController` and the `setupConditionListeners` /
  `setupMediaQueryListeners` / `setupTimeListeners` helpers.
- Keep `observeConditionChanges` and the shared time-boundary scheduler, and
  re-point their tests onto it so the scheduling edge cases stay covered.

* Pin the condition editor live-test for hidden and invalid configs

The per-row live-test set `invalid` (or hidden) directly but left its
evaluator callback unguarded, so the evaluator's torn-down `unknown`
result — fired ~500ms after observing `undefined` — clobbered the pinned
state until the next hass tick re-pinned it, causing a transient flicker.

Add the same `_override` guard the sibling visibility-status banner
already uses: the hidden / client-invalid branches set the result
directly and pin it, and the evaluator callback ignores results while
pinned.

* Remove the orphaned conditional-listener no-op methods

`addConditionalListener` / `clearConditionalListeners` became no-op
shims once the evaluator took over subscriptions and teardown; their only
callers were the listener-wiring removed in the migration. Drop both
methods, the mixin's now-redundant `disconnectedCallback` override, and
the stale `clearConditionalListeners()` call in hui-conditional-base.

* Accept server-evaluated conditions in validateConditionalConfig

The conditional card/row/element gate their config on
validateConditionalConfig, which only knew the client-side condition
types and rejected the server-evaluated ones (template, sun, zone,
device, and integration-provided conditions). Now that those are
authorable and delegated to core, accept them — core validates them —
so configuring one no longer throws "Invalid configuration".

* Evaluate conditional picture element visibility server-side

The picture-elements `conditional` element was the one visibility
consumer still evaluating fully client-side, so its stateful conditions
were not delegated to core (and server-class types it could not evaluate
fell through to a permanently-hidden result). Convert it to a
ReactiveElement driven by ConditionalListenerMixin, exactly like its
sibling hui-conditional-base, so the evaluator delegates stateful
conditions through subscribe_condition and evaluates the client-only
ones locally.

* Keep conditional cards mounted while hidden for server conditions

A conditional card gated on a server-evaluated condition (template, sun,
zone, device) never reappeared: hui-card removes a hidden child card from
the DOM, tearing down the evaluator, and the synchronous seed can revive a
client condition but not a server one, so the subscription was never
(re)opened and the server result that would show the card never arrived.

Set connectedWhileHidden so the conditional card/row stay mounted while
hidden and keep their subscriptions alive, like the other cards that must
keep working while hidden. The inner element is still unmounted when
hidden, so there is no extra render cost.

* Load config translations for the reused condition editors

The dashboard visibility editor reuses the automation condition editors
(state, numeric_state, template, sun, zone, device), which label their
form fields from the `config` translation fragment. The lovelace panel
never loads that fragment, so those labels rendered blank — e.g. the
numeric_state limit-type selectors and the above/below fields.

Load the `config` fragment when the conditions editor first renders, so
the embedded editors resolve their labels.

* Fold the card entity into entity-less conditions on read

A card with a host entity can carry entity-less state / numeric_state
visibility conditions that implicitly target that entity (folded in at
runtime). The editor translated them with an empty entity_id, so the
reused automation editor showed an empty, invalid entity field.

Fold the current-mode context entity into the displayed condition, and
recompute it when the entity context arrives (it can follow the
condition). Opening still does not rewrite the stored config; only
editing converts it to explicit core format.

* Demote the unused state/numeric_state condition editors to base classes

With the automation condition editors handling state / numeric_state in
the dashboard editor, the lovelace `ha-card-condition-state` and
`ha-card-condition-numeric_state` elements are no longer rendered. Their
only remaining role is as the base class for the entity-filter
`-no_entity` variants, so drop the now-dead custom-element registrations
(and the redundant side-effect imports) while keeping the shared logic.

* Format condition editors

* Fix condition editor indentation

* Invalidate the condition evaluator result as soon as the tree changes

When the observed tree changed by value, the controller kept the old
split and subscriptions alive until the debounced re-subscribe fired, so
it kept publishing (and the editor's Test action reported) the previous
tree's verdict, and a host that had already reset to unknown never got a
notification when the new tree settled on the same result.

Tear the old tree down when the signature changes and publish unknown
until the new subscription reports. Trees with nothing to subscribe to
re-evaluate immediately rather than waiting out the debounce.

Track a pending re-subscribe with its own flag: undefined is a valid
signature (observation cleared), so using it as the "nothing pending"
marker kept rescheduling the timer on every hass update and could leave
the previous subscription open indefinitely.

* Translate bound-less numeric_state conditions to a schema-valid core condition

Dropping a junk or non-finite bound could leave a numeric_state condition
with neither above nor below, which core's schema rejects; because sibling
server conditions are grouped into one subscription, that single invalid
leaf failed the whole group and hid the content. Lovelace merely ignored
such bounds and only required the value to be numeric, so express that
residual check as a template condition instead. An entity-less
numeric_state resolves to always-false, matching checkConditionsMet.

* Validate every visibility condition client-side and handle unsupported automation editor configs

validateConditionalConfig already accepts the server-evaluated types, so
gating it behind "every condition is client-only" only served to skip
validation as soon as a server condition was present; a malformed screen
condition next to a template condition was reported as hidden rather than
invalid. Run it for the whole set.

The embedded automation condition editors fire ui-mode-not-available when
an existing core config fails their UI struct. Fall back to YAML with the
struct warnings, as the automation condition row does, instead of
rendering a blank editor while still claiming UI support.

* Type dashboard visibility contracts as VisibilityCondition

Card, badge, section, view sidebar and heading badge visibility, plus the
conditional card, row and element conditions, still declared the
lovelace-only Condition type, so the newly supported template, sun, zone,
device and integration conditions were invalid at the config boundary and
needed casts throughout. Declare them as VisibilityCondition, widen
validateConditionalConfig accordingly and drop the casts that made
redundant. Entity-filter conditions stay lovelace-only.

* Subscribe when hass arrives after the conditions were observed

The subscribed signature was recorded before checking that hass was
available. A host that connected with its config set but received hass
later therefore never subscribed: the later observe saw the same
signature, found no split and stayed unknown for good. Only record the
signature once a subscription is actually opened.

* Seed pending visibility with a three-valued local evaluation

While a server result was pending, the mixin ran the whole tree through
the legacy client evaluator. Core-only leaves default to false there, so
not: [template] was inverted to visible until core replied, and core
state / numeric_state options such as for, match and value_template were
ignored, both contradicting the no-flash guarantee.

Evaluate locally only the leaves the legacy evaluator reproduces exactly
(client-only types, lovelace state / numeric_state, and core ones without
those options), keep every other leaf unknown through and / or / not, and
hide while the outcome still depends on an unknown leaf.

* Hide server-only condition types in entity-filter mode

The map and entity-filter cards still evaluate their conditions locally
with checkConditionsMet, where template / sun / zone / device fall through
to a failing state check and filter out every entity. Don't offer them in
the add menu for that mode.

* Leave conditions carrying enabled to the server in the local seed

Core treats a disabled condition as neutral (and enabled may be a
template), while the legacy evaluator ignores enabled altogether. A
pending not: [disabled failing state, ...] was therefore seeded visible
although core reports hidden. Treat any node carrying enabled as unknown.

* Reject filter-incompatible pasted conditions in entity-filter mode

The condition clipboard is shared across editors in the session, so a
template / sun / zone / device condition, or a core-format leaf pinned to
its own entity_id, could be pasted into a map or entity-filter editor,
where the local evaluator would filter out every entity or evaluate the
wrong one. Hide the paste entry and ignore the action for such clipboard
contents while in filter mode.

* Re-feed the section visibility evaluator after a strategy config resolves

_config is not reactive, and for a strategy section it is assigned after
the Lit update that last fed the evaluator, so _conditionsVisible kept
reading the verdict for the raw or previous config until the next hass
update. Re-run setupConditionalListeners right after assigning it.

* Hide content whenever a server condition subtree errors

An errored subtree was recorded as false and fed through the combinators,
so a client-side not inverted it and an invalid server condition could
show content; the runtime mixin only looks at the result, not the error.
Force the result to hidden while any subtree is in error.

* Honor enabled: false on visibility conditions

Core skips a disabled condition inside a compound: it neither passes nor
fails. Rebuilding logical conditions during translation dropped enabled
(and the other row metadata), so a disabled server-side group was
evaluated, and the mixed-tree split and the local seed ignored it as well.

Preserve the row metadata on translated logical conditions, skip disabled
nodes when splitting and when seeding, and leave a template-valued
enabled on a seeded node unknown since only core can render it.

* Type the conditional card conditions as VisibilityCondition

ConditionalCardConfig, the contract HuiConditionalBase actually consumes,
still declared the lovelace-only union, unlike the row and element
contracts.

* Keep a client-side node with a template-valued enabled unknown

Only core can render enabled: "{{ ... }}", and core never sees a mixed or
client-only node, so the split silently treated such a node as enabled
and let its children decide visibility. Keep it unknown instead, erring
toward hiding and matching the optimistic seed.

* Whitelist the condition types usable as entity filters

The filter-compatibility check only excluded the four built-in server
types, so an integration-provided condition copied from a visibility
editor could still be pasted into an entity-filter editor, where the
local evaluator cannot evaluate it and filters out every entity. Check
against the types checkConditionsMet supports instead.

* Fold the host entity into legacy entity-less conditions as well

A legacy condition such as { state: "on" } has no condition key, so
addEntityToCondition never stamped the card entity on it. That used to be
harmless because checkConditionsMet fell back to the evaluation context,
but the server translation has no context and turned the condition into
always-false once core reported. Treat the legacy shape as the state
condition it is, and make the helper generic over the visibility union so
callers no longer need casts.

* Keep the lovelace outcome for infinite numeric bounds

Number("1e400") is Infinity, which lovelace does not ignore: above +inf
or below -inf can never pass, while above -inf or below +inf always do.
Dropping such a bound could flip an untouched condition from hidden to
visible. Resolve the unsatisfiable cases to always-false and drop only the
vacuous ones. Infinity is not JSON-serializable, so neither is ever sent.

* Only leave a template-valued enabled unknown in the local seed

The check also matched enabled: true, so an explicitly enabled condition
was seeded unknown and the card hidden until core responded, exactly the
flash the seed is meant to avoid.

* Show no test chip while the condition evaluator reports an error

An invalid server condition evaluates to hidden plus an error; reading
only the result turned Test into a transient "not met" chip that
contradicted the invalid live indicator.

* Seed only core conditions the client compares identically

The optimistic seed still admitted core-format shapes the legacy evaluator
handles differently: an attribute comparison (core compares the raw value,
the client stringifies it) and an entity-valued numeric bound (core errors
when the entity is missing, the client ignores the bound). Leave those
unknown until core reports.

* Accept a single condition as the children of a logical condition

Core's LogicalCondition allows conditions to be one condition or a list,
but every traversal here assumed a list and crashed on the single shape.
Widen the type accordingly and route all traversals through one helper.

* Keep lovelace leaves with legacy-only semantics client-side

Core compares raw attribute values, only dereferences input_* comparison
values and errors on a missing bound entity, where lovelace stringifies
the attribute, resolves any existing entity and ignores the bound.
Delegating such existing conditions changed their visibility silently.

Classify a lovelace-format state / numeric_state leaf that relies on any
of those as client-side so it keeps its exact legacy evaluation; once the
user edits it, it is saved in core format and evaluated by core.

* Drop the pinned editor indicators when leaving an override branch

The empty and client-invalid branches pin the indicator and clear the
evaluator, which is then already unknown; when the condition becomes
valid the pending observation is unknown too, so no notification arrives
and the stale pinned state stayed visible until core first responded.

* Reject core's single-child logical shorthand as an entity filter

Filter consumers and the filter-mode editor expect the lovelace list
shape for logical children, so a pasted core condition using the
single-child shorthand caused a runtime error there. Require a list in
the filter-compatibility check and traverse defensively when looking for
no-entity conditions.

* Seed only core leaves whose entity is present and, for numeric_state, bounded

Core errors on a missing entity and rejects a bound-less numeric_state,
while the client evaluates a missing entity as unknown and passes any
numeric value, so both shapes could flash visible before the subscription
error arrived. Leave them unknown until core reports.

* Re-subscribe when the hass connection object is replaced

Subscriptions are bound to the connection they were opened on. An
unchanged tree observed with a hass carrying a different connection kept
the stale subscriptions; re-open them in that case while still not
churning on ordinary hass updates.

* Keep non-finite bounds distinguishable in the condition signature

JSON.stringify serializes Infinity, -Infinity and NaN alike as null, so
flipping a YAML .inf bound produced the same signature and the old
subscription stayed active.

* Seed lovelace leaves only while their target entity exists

Core reports an error for a condition on a missing entity, which hides the
tree, while the legacy evaluator compares against the literal unknown.
Seeding such a leaf optimistically could therefore flash the content
before the error arrived; leave it unknown instead.

* Do not seed a core state condition that compares against another entity

checkConditionsMet dereferences any existing entity used as a comparison
value, while core only dereferences input_* entities, so such a core leaf
could flash visible before the subscription reported false. Apply the
same entity-reference guard the legacy classification uses.

* Preserve row metadata when rebuilding lovelace leaves

Both the evaluation translation and the editor's display conversion
rebuilt lovelace state / numeric_state leaves without enabled, alias and
note, so editing a disabled legacy condition silently re-enabled it and a
template-valued enabled was dropped before reaching core.

* Surface template rendering errors from condition subscriptions

subscribe_condition events carry template_errors next to a result when a
template inside the condition failed to render. Forward them through the
evaluator's error so the editor flags the condition, without overriding
core's result the way a hard error does.

* Treat a null numeric bound as absent

Lovelace ignores a null bound (== null), but the translator only checked
for undefined and Number(null) turned it into an unintended 0. The editor
conversion now skips null bounds as well.

* Keep the and wrapper for a single-child not and row metadata on fallbacks

Core skips a disabled child, so a bare not over one child evaluates to
true where lovelace's not (¬ of the AND of its children) gives false; the
and wrapper restores that for any arity. The always-false and numeric
value fallbacks also dropped enabled, alias and note, so a template-disabled
leaf would have participated in its parent regardless.

* Treat an empty legacy entity as absent everywhere

checkStateCondition falls back to the host entity with entity || context,
so an existing condition with entity: "" targeted the card entity. The
entity fold, the optimistic seed, the editor conversion and the
translation used nullish checks instead, which kept the empty string and
turned such a condition into an error or an always-false leaf. Use the
same truthy fallback throughout.

* Append non-finite values to the condition signature instead of substituting

A marker string standing in for Infinity could in principle collide with
an equal user string. Keep plain JSON and append the ordered non-finite
values, which is unambiguous.

* Remove a stray brace rendered under every condition editor

A leftover interpolation terminator outside the template expression
rendered a literal "}" below the condition content. Also reject pasting a
condition pinned to an explicit entity into an entity filter, where the
fold-in would keep it and judge every candidate by the copied entity.

* Tidy the optimistic seed's leaf check

Condense its doc comment, take the states map rather than the whole hass
object, and simplify the bound checks.

* Tighten comments on dashboard condition evaluation.

---------

Co-authored-by: Aidan Timson <[email protected]>
2026-09-08 12:53:50 +00:00
841729af93 Upgrade vitest to v5 (#54011)
* Update vitest monorepo to v5

* Add required Vite peer dependency for Vitest 5

* Migrate benchmarks to the Vitest 5 context API

* Stub read-only jsdom globals in Vitest tests

* Revise benchmark reporting instructions in README

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Aidan Timson <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-08 14:29:24 +03:00
Clément NotinandCopilot Autofix powered by AI e3f92a6df3 Add 'timedelta_string' to documented Jinja completions (#54056)
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-08 11:13:23 +02:00
Wendelin a781228706 Fix add TCA mobile list width (#54054) 2026-09-08 09:43:44 +01:00
renovate[bot] f9e02b628f Update dependency lint-staged to v17.5.0 (#54055) 2026-09-08 09:42:01 +01:00
Clément Notin af8a80f0fe Add timedelta_string template completion (#54050) 2026-09-08 10:32:44 +02:00
chaim-shwartz c01a140751 Fix crash when hass.auth is undefined in partial-panel-resolver (#53962) 2026-09-07 18:33:04 +00:00
e50eaaa865 Add more automation row details (#54018)
* Add for and offset to trigger and condition rows

* Add actions with timeout.

* fix separator

* Fix templated automation row durations

Co-authored-by: wendevlin <[email protected]>

* review

* Enhance duration validation with finite check

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Add behavior inrow

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-07 20:31:23 +02:00
renovate[bot] cd8b975a38 Update dependency @codemirror/state to v6.7.4 (#54045)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-07 18:26:07 +00:00
Aidan TimsonandCopilot Autofix powered by AI 5dd3a4b662 Add UI/UX readiness skill and strengthen review guidance (#54032)
* Create UX readyness skill

* Refine UI/UX review skill responsibilities

* Account for existing PR review feedback

* Clarify UI/UX readiness evidence

* Simplify UI/UX readiness routes

* Update review guidelines for pull requests

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Handle optional gallery artifacts

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-07 20:21:40 +02:00
renovate[bot] e5fa96465c Update dependency eslint to v10.10.0 (#54044)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-07 20:17:55 +02:00
renovate[bot] 79467b51b1 Update dependency browserslist to v4.28.9 (#54043)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-07 20:17:49 +02:00
Maarten Lakerveld c3cc2217bf Don't zoom the zone map when opening the home zone editor (#54033) 2026-09-07 14:34:17 +01:00
Marcin BauerandClaude Opus 5 6e6e4d4c4d Point at the sources pane from history and activity empty states (#54019)
Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-07 14:09:13 +02:00
Aidan Timson f6cbe49d81 Resolve Supervisor browser URLs against Home Assistant (#53944)
* Resolve browser URLs against Home Assistant

* Resolve Supervisor log download URLs against Home Assistant
2026-09-07 13:12:49 +02:00
Aidan Timson 1e9592a0b8 Resolve Supervisor URLs against HA context for icons (#53942)
Resolve Supervisor URLs against Home Assistant
2026-09-07 12:07:28 +01:00
Aidan Timson b2b0491c99 Centralize Supervisor app icons (#53941)
* Centralize Supervisor app icons

* Constrain app icons in combo boxes

* Preserve quick bar app icon styles

* Style colored app icons in combo box items

* Use fixed dimensions for colored app icons
2026-09-07 12:01:55 +01:00
Petar PetrovandCursor Agent 9bffae3ee4 Exit scene live mode when leaving the editor (#53837)
* Exit scene live mode when leaving the editor

Leaving the page previously only unsubscribed, so live-activated
device states stayed behind. Restore stored states unless the tab
is hidden for panel suspend.

* Drop extra unit tests for scene live-mode disconnect.

* Restore scene live states only on editor disconnect.

Back and delete already unmount the editor, which now exits live
mode, so a second applyScene was redundant.

* Resubscribe to scene live edits after hidden-tab suspend.

Existing scenes stayed in live mode when the panel was reattached,
but the state_changed subscription was not restored.

* Keep the scene live subscription across hidden-tab suspend.

Unsubscribing and resubscribing on reattach races the closed
websocket; leaving the subscription in place lets the library
restore it after reconnect.

* Tear down scene live mode on hidden-tab route changes.

document.hidden is not enough: saving a new scene remounts a
new editor. Skip teardown only when an ancestor was detached
(panel suspend). Reuse an existing live subscription on
reattach so new scenes do not get duplicate listeners.

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Cursor Agent <[email protected]>
2026-09-07 12:08:46 +02:00
renovate[bot] a287aacd98 Update dependency @codemirror/state to v6.7.3 (#54020) 2026-09-07 11:05:14 +01:00
renovate[bot] b29b0bd083 Update dependency @codemirror/view to v6.43.11 (#54010) 2026-09-07 09:24:46 +01:00
ae8aa3813b Add Radio frequency to the demo (#53976)
Co-authored-by: Claude Opus 5 <[email protected]>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2026-09-07 08:27:43 +01:00
Petar Petrov 770caf62f7 Prompt for unsaved changes on history back navigation (#53919) 2026-09-07 09:17:19 +02:00
iven 8fed3ac0c8 Use a readable text color for calendar events (#54009) 2026-09-07 06:54:52 +00:00
98f5bdd703 Add Tags to the demo (#53977)
Co-authored-by: Claude Opus 5 <[email protected]>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Simon Lamon <[email protected]>
2026-09-07 08:39:04 +02:00
karwosts 8e13ba872d Fix 'select all with issues' (#54007) 2026-09-07 08:35:46 +02:00
Dominik 37433c787f Adjust clock and notification drawer backdrop (#54012) 2026-09-07 06:22:14 +00:00
Paulus SchoutsenandClaude Opus 5 dc7ee8dc5a Serial: send consumers to their own config panel (#54000)
* Serial: send consumers to their own config panel

A port used by Zigbee or Z-Wave led to that integration's entry on the
integration page, which is a device list — not where the radio on that port is
managed. Point those consumers at the integration's own panel instead.

Which panel that is was already decided in `ha-config-entry-row`, from the
panels an integration registers at runtime falling back to
`integrationsWithPanel`. That resolution moves to `getConfigPanelPath` so both
callers stay in step, and so a port picks up any panel the integration page
would already link to.

A consumer that is not running keeps its integration-page link: its panel is
not loaded to receive it.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01FjmjZsxhdj9ekGmhFHXg3p

* Serial: send the Thread radio to the Thread panel

A Thread radio is held by the Open Thread Border Router app rather than by a
config entry, so it never reached the panel resolution. Map the app to the
integration behind it and look the panel up from there.

The panel is only offered when its integration is loaded, which an app being
started does not imply.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01FjmjZsxhdj9ekGmhFHXg3p

---------

Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-06 08:27:25 +02:00
karwosts ddc99501af Handle sequence: null in script. (#53999) 2026-09-06 08:25:35 +02:00
karwosts 5ec87269dc Show errors in blueprint editor (#53996) 2026-09-06 08:24:35 +02:00
renovate[bot] 53cf986491 Update dependency @lokalise/node-api to v16.4.1 (#53997)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-06 08:24:19 +02:00
renovate[bot] 0388cb8cd0 Update dependency hls.js to v1.7.2 (#53998)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-06 08:24:16 +02:00
dependabot[bot] cfefa39b84 Bump the codeql-action group across 1 directory with 2 updates (#54002)
Bumps the codeql-action group with 2 updates in the / directory: [github/codeql-action/init](https://github.com/github/codeql-action) and [github/codeql-action/analyze](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.37.8 to 4.37.9
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28...cdf488f595d80d6e07e03d4674febd5ab45fa938)

Updates `github/codeql-action/analyze` from 4.37.8 to 4.37.9
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28...cdf488f595d80d6e07e03d4674febd5ab45fa938)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-06 08:23:44 +02:00
Paulus SchoutsenandClaude Opus 5 5a907614af Add Thread to the demo (#53970)
* Add Bluetooth to the demo

Load the bluetooth integration and mock its scanner, advertisement and
connection subscriptions, so the Bluetooth panel, its adapter info,
monitors and network map render in the demo.

Also adds the scaffolding the other Settings > Connectivity panels build
on: a per-integration fixtures contract, registry builders, and the two
registries that collect components, WS command prefixes and registry data
from each integration. `addEntities` now carries `device_id` and
`platform` into the mocked display entity registry, which the panels use
to count entities per device and per integration.

Mocked subscriptions emit their first message from a timeout. Subscribing
is synchronous in the mock, so an immediate callback lands before the
subscriber is ready: `createCollection` overwrote it with its empty
initial fetch, and pages that ignore messages received before their first
render dropped it.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Serve integration manifests for the demo's config entries

The integration page reads back the manifest it fetches without guarding,
so opening one for a domain the demo had no manifest for threw. Bluetooth
now ships its manifest through the connectivity fixtures, and manifest/get
falls back to a generated manifest rather than answering with undefined,
which also covers the entries that already lacked one.

Adds a demo E2E test that opens the Bluetooth panel and asserts its counts
are non-zero. The connectivity mocks reach the panel through lazy mock
registration and deferred first emissions, neither of which the demo suite
covered; without them the panel renders but stays empty.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Cover the Bluetooth scanner details subscription in the demo E2E test

The dashboard's adapter count comes from the config entries, so the test
passed even with the scanner details subscription broken, while the
adapter page and network map stayed incomplete.

The adapter page renders a settings button only for adapters that are not
remote scanners, which it knows from the scanner type in those details, so
asserting one button across the three adapters covers the subscription
without asserting on copy.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Keep connectivity entities when switching demos

Switching demos replaces the whole state map, and only the energy entities
were added back, so every connectivity state disappeared until a reload.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Add Thread to the demo

Load the thread and otbr integrations and mock router discovery, dataset
listing and border router info, so the Thread panel renders in the demo.
The preferred network holds Home Assistant's own border router alongside a
HomePod mini and a Nest Hub; an Amazon Echo forms the one other network.

Widens ThreadRouter's brand union with "amazon", which the backend
already returns. The union is still not exhaustive.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Mock the Thread actions and match the dataset casing

The extended PAN ID was lowercase while the TLV string carries it uppercase.
The dataset dialog looks for one inside the other with a case-sensitive
`includes`, so the preferred network's info showed neither the border
router's URL nor its active dataset.

The panel also offers adding a dataset, choosing the preferred network and
border router, resetting the border router and changing its channel, none of
which were mocked, so each rejected as unimplemented. They now change the
mocked data, and `otbr/set_channel` answers with the delay the panel reads
back.

`ThreadRouter["brand"]` is no longer a union. It only reaches `brandsUrl`,
and the backend resolves it from the border agent's vendor name, so every
new vendor meant another frontend change for no typing benefit.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Push Thread network changes to the discovery stream

The panel groups the routers it draws from `thread/discover_routers`, not
from `otbr/info`, so changing the network only in the info left the border
router drawn under its old network for good. The mock now keeps its
subscribers and announces the router again when it moves.

A reset also has to put the border router on a network of its own instead of
reusing the existing extended PAN ID, which the panel groups by, and it adds
that network rather than taking over the preferred one, so the way back onto
the original network stays available.

`ThreadRouter["brand"]` is null for a vendor the backend does not know, and
the panel now leaves out the icon in that case rather than requesting one
that cannot exist.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Build the Thread datasets from real TLVs

The pasted dataset TLV was malformed: an odd number of hex digits, a network
name field declaring ten bytes for nine, and a network key that ran into the
next type, so a decoder derailed partway through. Datasets are now assembled
from type/length/value triplets, which keeps the declared lengths honest and
each dataset's own extended PAN ID and network name inside its TLV.

Each dataset carries its own, so `thread/get_dataset_tlv` answers for the
dataset it was asked about and rejects an unknown one, and moving the border
router carries the active dataset with it rather than leaving the previous
network's behind, which would have hidden the URL again on the new network.

An imported dataset takes its extended PAN ID from the type 0x02 field
instead of the first sixteen characters, which were the timestamp, and a
reset generates eight hexadecimal bytes rather than a value starting
"RESET".

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Import Thread datasets from the credentials given

The import invented the channel, network name and PAN ID and stored a
rebuilt TLV, so importing real credentials showed a different network than
the one submitted and read back different credentials. It now takes all four
fields from the TLV and keeps that TLV verbatim.

Anything that does not decode is refused rather than falling back to a
generated ID, so the panel shows its error path for malformed credentials.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Treat a Thread import as a revision of the network it names

Datasets sharing an extended PAN ID are revisions of one network, so
importing credentials for a network that is already known updates it rather
than adding a second card for it, and only a newer active timestamp wins.
Re-importing the credentials the demo itself shows used to duplicate the
network.

The active timestamp is now required, as the backend requires it, and a
reset leaves the default router unset, since nominating one is its own
action in the panel.

A router without a brand no longer reserves the avatar column, so its name
is not left indented against an empty graphic.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Keep the Thread dataset, credentials and channel in step

Deleting a dataset left its credentials behind, so reading them back returned
a network the panel had already dropped. They go with it now.

Changing the channel only moved the border router's reported channel, leaving
the dataset and its active TLV on the old one, so the channel prompt and the
dataset dialog disagreed on the next read. A reset had the mirror problem,
installing a channel 15 network without moving the reported channel. Both
carry the dataset, its TLV and the channel together.

Network names are decoded as UTF-8 rather than one character per byte, so a
non-ASCII name reads correctly and a sequence the backend would refuse is
refused here.

Adds a demo test for the panel: the two networks it starts with, the reset
and rejoin that only show up if the discovery subscription is told, and
credentials being per dataset and going away with one. Checked that it bites
by dropping the announcement, which fails it on the card count after a reset.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Refuse repeated tags and a zero channel in a Thread dataset

A repeated type is malformed and the backend's parser refuses it, rather
than letting the later one win, and a channel field carrying zero is not a
channel it accepts. An absent channel is still fine.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Change the Thread channel without rewriting the credentials

Rebuilding the dataset TLV from its summary replaced the network key, PSKc,
mesh-local prefix, security policy and anything else this mock does not
model with fixture constants, so changing the channel on an imported network
silently swapped its credentials for someone else's. Only the channel
triplet is rewritten now, leaving the rest of the TLV as it was.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Drop the remaining comments from the Thread mock

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

---------

Co-authored-by: Claude <[email protected]>
2026-09-06 08:23:07 +02:00
Paulus SchoutsenandClaude Opus 5 c325392e79 Add Zigbee to the demo (#53971)
* Add Bluetooth to the demo

Load the bluetooth integration and mock its scanner, advertisement and
connection subscriptions, so the Bluetooth panel, its adapter info,
monitors and network map render in the demo.

Also adds the scaffolding the other Settings > Connectivity panels build
on: a per-integration fixtures contract, registry builders, and the two
registries that collect components, WS command prefixes and registry data
from each integration. `addEntities` now carries `device_id` and
`platform` into the mocked display entity registry, which the panels use
to count entities per device and per integration.

Mocked subscriptions emit their first message from a timeout. Subscribing
is synchronous in the mock, so an immediate callback lands before the
subscriber is ready: `createCollection` overwrote it with its empty
initial fetch, and pages that ignore messages received before their first
render dropped it.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Serve integration manifests for the demo's config entries

The integration page reads back the manifest it fetches without guarding,
so opening one for a domain the demo had no manifest for threw. Bluetooth
now ships its manifest through the connectivity fixtures, and manifest/get
falls back to a generated manifest rather than answering with undefined,
which also covers the entries that already lacked one.

Adds a demo E2E test that opens the Bluetooth panel and asserts its counts
are non-zero. The connectivity mocks reach the panel through lazy mock
registration and deferred first emissions, neither of which the demo suite
covered; without them the panel renders but stays empty.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Cover the Bluetooth scanner details subscription in the demo E2E test

The dashboard's adapter count comes from the config entries, so the test
passed even with the scanner details subscription broken, while the
adapter page and network map stayed incomplete.

The adapter page renders a settings button only for adapters that are not
remote scanners, which it knows from the scanner type in those details, so
asserting one button across the three adapters covers the subscription
without asserting on copy.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Keep connectivity entities when switching demos

Switching demos replaces the whole state map, and only the energy entities
were added back, so every connectivity state disappeared until a reload.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Add Zigbee to the demo

Load the zha integration and mock its devices, groups, configuration and
network settings, so the Zigbee panel, its options, groups, network info
and network map render in the demo. Neighbor tables give the map a mesh of
routers and end devices.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Give the Zigbee temperature sensor a unique entity ID

sensor.bedroom_temperature already exists in the home demo config, whose
entities are added last and overwrote the display registry entry,
detaching it from its Zigbee device and undercounting the panel's
entities on that demo.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Label the Zigbee options and take the offline plug unavailable

The options page localizes every field through the backend translations and
falls back to the raw identifier, so the pages showed names like
alarm_master_code. Seed a key per schema field, for the global options as
well as the alarm ones.

The panel reports the TV plug as offline, so its entity has to agree.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Mock the Zigbee panel's write actions

Saving either options page, downloading a backup, changing the channel and
adding or removing a group or its members all rejected as unimplemented, so
every one of those visible controls failed. They now change the mocked state
that the panel refetches.

Saving merges into the stored configuration rather than replacing it, the
way the backend does, so saving one section leaves the rest alone.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Seed the ZHA unavailability timeouts and copy the configuration

The options page falls back to two hours when these keys are absent, so the
battery timeout showed 2 hours where ZHA's default is 6. Both are seeded
now.

The configuration response handed out the backing object, and both editors
mutate the fetched data as controls change, so an edit the user never saved
survived leaving the page. It is copied on the way out; only the update
command writes to the stored configuration.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* List the groupable Zigbee devices

The create group page and the add members dialog build their pickers from
this command, so returning nothing left both permanently empty and made the
group commands unreachable from the panel. The lights and plugs are listed
now.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Keep the Zigbee pairing page, backups and group rows honest

The add device page subscribes to the permit command as soon as it opens, so
with nothing registered it sat on its spinner for the full permit duration
behind a rejected subscription. A subscription that simply stays open is
enough, since nothing pairs in the demo.

A backup shared its network and node objects with the live settings, so
changing the channel afterwards rewrote the stored backup, which is the one
thing a backup must not do. They are copied now.

Group endpoints carried no entities, so both pickers labelled every light
and plug "No entities". Each now carries the entity the fixtures give it.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Wire up the ZHA device pages in the demo

The ZHA info card and device actions look up the device's `zigbee`
connection and render nothing without it, so the demo devices only ever
showed the generic device page. Add the connection, and mock the two
commands that become reachable through it: the manage page's cluster
list (with each cluster's attributes and commands, so the attribute and
command tabs are usable), and the reconfiguration subscription, which
now walks the device's clusters and terminates instead of rejecting.

Written attributes are remembered, so reading one back agrees with what
the write button reported.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Carry the registry area on the ZHA device payloads

The group pickers read the area straight off the device payload rather
than resolving the device registry, so the plugs listed no area. The
backend fills it in from the registry; derive it from the registry
fixtures here for the same reason, so the two cannot drift apart.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Make the Zigbee bindings tab work

Both bind buttons ended in their error state: `zha/groups/bind` and
`zha/groups/unbind` were never registered. Registering them is not
enough on its own — group binding lists only a device's client side, so
with every mocked cluster on the server side the table read "No data"
and the button could never be enabled. The remotes now carry the `out`
clusters they would have on real hardware, and `zha/devices/bindable`
returns the routers, so the device half of the tab is no longer hidden.

Also drops the `any` from the configuration update payload, which
already has an exact type.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

---------

Co-authored-by: Claude <[email protected]>
2026-09-05 09:54:59 +02:00
Paulus SchoutsenandClaude Opus 5 241b8c5771 Add Z-Wave to the demo (#53972)
* Add Bluetooth to the demo

Load the bluetooth integration and mock its scanner, advertisement and
connection subscriptions, so the Bluetooth panel, its adapter info,
monitors and network map render in the demo.

Also adds the scaffolding the other Settings > Connectivity panels build
on: a per-integration fixtures contract, registry builders, and the two
registries that collect components, WS command prefixes and registry data
from each integration. `addEntities` now carries `device_id` and
`platform` into the mocked display entity registry, which the panels use
to count entities per device and per integration.

Mocked subscriptions emit their first message from a timeout. Subscribing
is synchronous in the mock, so an immediate callback lands before the
subscriber is ready: `createCollection` overwrote it with its empty
initial fetch, and pages that ignore messages received before their first
render dropped it.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Serve integration manifests for the demo's config entries

The integration page reads back the manifest it fetches without guarding,
so opening one for a domain the demo had no manifest for threw. Bluetooth
now ships its manifest through the connectivity fixtures, and manifest/get
falls back to a generated manifest rather than answering with undefined,
which also covers the entries that already lacked one.

Adds a demo E2E test that opens the Bluetooth panel and asserts its counts
are non-zero. The connectivity mocks reach the panel through lazy mock
registration and deferred first emissions, neither of which the demo suite
covered; without them the panel renders but stays empty.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Cover the Bluetooth scanner details subscription in the demo E2E test

The dashboard's adapter count comes from the config entries, so the test
passed even with the scanner details subscription broken, while the
adapter page and network map stayed incomplete.

The adapter page renders a settings button only for adapters that are not
remote scanners, which it knows from the scanner type in those details, so
asserting one button across the three adapters covers the subscription
without asserting on copy.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Keep connectivity entities when switching demos

Switching demos replaces the whole state map, and only the energy entities
were added back, so every connectivity state disappeared until a reload.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Add Z-Wave to the demo

Load the zwave_js integration and mock its network status, provisioning
entries and node and controller statistics, so the Z-Wave panel, its
options, statistics, network info, provisioned devices and network map
render in the demo. Last working routes give the map a mesh with
repeaters, asleep and dead nodes.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Give the Z-Wave motion sensor a unique entity ID

binary_sensor.kitchen_motion already exists in the home demo config, whose
entities are added last and overwrote the display registry entry,
detaching it from its Z-Wave device and undercounting the panel's entities
on that demo.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

---------

Co-authored-by: Claude <[email protected]>
2026-09-04 16:20:53 +00:00
06e55141f5 Add MQTT to the demo (#53973)
* Add Bluetooth to the demo

Load the bluetooth integration and mock its scanner, advertisement and
connection subscriptions, so the Bluetooth panel, its adapter info,
monitors and network map render in the demo.

Also adds the scaffolding the other Settings > Connectivity panels build
on: a per-integration fixtures contract, registry builders, and the two
registries that collect components, WS command prefixes and registry data
from each integration. `addEntities` now carries `device_id` and
`platform` into the mocked display entity registry, which the panels use
to count entities per device and per integration.

Mocked subscriptions emit their first message from a timeout. Subscribing
is synchronous in the mock, so an immediate callback lands before the
subscriber is ready: `createCollection` overwrote it with its empty
initial fetch, and pages that ignore messages received before their first
render dropped it.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Serve integration manifests for the demo's config entries

The integration page reads back the manifest it fetches without guarding,
so opening one for a domain the demo had no manifest for threw. Bluetooth
now ships its manifest through the connectivity fixtures, and manifest/get
falls back to a generated manifest rather than answering with undefined,
which also covers the entries that already lacked one.

Adds a demo E2E test that opens the Bluetooth panel and asserts its counts
are non-zero. The connectivity mocks reach the panel through lazy mock
registration and deferred first emissions, neither of which the demo suite
covered; without them the panel renders but stays empty.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Cover the Bluetooth scanner details subscription in the demo E2E test

The dashboard's adapter count comes from the config entries, so the test
passed even with the scanner details subscription broken, while the
adapter page and network map stayed incomplete.

The adapter page renders a settings button only for adapters that are not
remote scanners, which it knows from the scanner type in those details, so
asserting one button across the three adapters covers the subscription
without asserting on copy.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Keep connectivity entities when switching demos

Switching demos replaces the whole state map, and only the energy entities
were added back, so every connectivity state disappeared until a reload.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Add MQTT to the demo

Load the mqtt integration and mock topic subscriptions and device debug
info, so the MQTT panel renders in the demo and its listen card streams
messages on the topic you subscribe to.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Give the MQTT sensor entities unique entity IDs

sensor.kitchen_temperature already exists in the home demo config, whose
entities are added last and overwrote the display registry entry,
detaching it from its MQTT device and undercounting the panel's entities
on that demo.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Key the MQTT debug info by device and send real payloads

The debug info ignored the requested device, so the garage door's MQTT info
showed the fridge sensor's entity. Return the entities of the device that
was asked for, and nothing for one that is not MQTT.

The discovery payload is the config object, not a JSON string:
`mqtt-discovery-payload` dumps it as YAML, so a string rendered as one
quoted scalar. The frontend type said string while the component already
required an object; it now matches what the backend sends.

A subscription takes a topic filter, so echoing it back as the message topic
invented topics no broker could publish. Wildcard levels now resolve to a
concrete matching topic.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Allow an empty MQTT discovery payload

An entity with debug traffic but nothing discovered has no config, and the
backend sends an empty string, so narrowing the field to an object alone was
wrong in the other direction.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Simon Lamon <[email protected]>
2026-09-04 15:55:21 +00:00
Paulus SchoutsenandClaude Opus 5 f6751a8c44 Add Infrared to the demo (#53975)
* Add Bluetooth to the demo

Load the bluetooth integration and mock its scanner, advertisement and
connection subscriptions, so the Bluetooth panel, its adapter info,
monitors and network map render in the demo.

Also adds the scaffolding the other Settings > Connectivity panels build
on: a per-integration fixtures contract, registry builders, and the two
registries that collect components, WS command prefixes and registry data
from each integration. `addEntities` now carries `device_id` and
`platform` into the mocked display entity registry, which the panels use
to count entities per device and per integration.

Mocked subscriptions emit their first message from a timeout. Subscribing
is synchronous in the mock, so an immediate callback lands before the
subscriber is ready: `createCollection` overwrote it with its empty
initial fetch, and pages that ignore messages received before their first
render dropped it.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Serve integration manifests for the demo's config entries

The integration page reads back the manifest it fetches without guarding,
so opening one for a domain the demo had no manifest for threw. Bluetooth
now ships its manifest through the connectivity fixtures, and manifest/get
falls back to a generated manifest rather than answering with undefined,
which also covers the entries that already lacked one.

Adds a demo E2E test that opens the Bluetooth panel and asserts its counts
are non-zero. The connectivity mocks reach the panel through lazy mock
registration and deferred first emissions, neither of which the demo suite
covered; without them the panel renders but stays empty.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Cover the Bluetooth scanner details subscription in the demo E2E test

The dashboard's adapter count comes from the config entries, so the test
passed even with the scanner details subscription broken, while the
adapter page and network map stayed incomplete.

The adapter page renders a settings button only for adapters that are not
remote scanners, which it knows from the scanner type in those details, so
asserting one button across the three adapters covers the subscription
without asserting on copy.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Keep connectivity entities when switching demos

Switching demos replaces the whole state map, and only the energy entities
were added back, so every connectivity state disappeared until a reload.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Add Infrared to the demo

Load the infrared integration and add the emitter and receiver proxy
entities it reads, so the Infrared panel and its device list render in the
demo. The panel is entity driven, so it needs no WebSocket mock.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

---------

Co-authored-by: Claude <[email protected]>
2026-09-04 17:48:40 +02:00
renovate[bot] 1fb138337a Update dependency @rspack/core to v2.2.2 (#53982)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-04 17:36:36 +02:00
Paulus SchoutsenandClaude Opus 5 50df620a01 Add Matter to the demo (#53968)
* Add Matter to the demo

Load the matter integration and mock its network topology, so the Matter
panel and its network map render in the demo, with a Thread and Wi-Fi
topology that includes a border router and an offline node.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Key Matter node diagnostics by device

The diagnostics and ping mocks ignored the requested device, so every
Matter device reported node 1 on Thread and available. The device page
gates its actions on that: the offline garden sensor offered actions that
need a live node, and the Wi-Fi plug offered a Thread network link.

Both are now derived from the topology the map already renders, so a
device's node ID, transport, node type and availability match it, and an
unknown device is rejected as the backend would.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Give Matter fixtures unique entity IDs and mock its device actions

lock.front_door and sensor.garden_temperature already exist in the home
demo config, whose entities are added last and overwrote the display
registry entries, detaching them from their Matter devices. The panel
counted 3 entities instead of 5 on that demo. Renamed to a side door lock
and a patio sensor, which no demo config uses.

The device page offers commissioning, fabric and credential actions for an
available node, none of which were mocked, so each failed with
command_not_mocked.

Adds a demo E2E test for the panel and its map. Emptying the topology
subscription fails it.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Mock the Matter lock services and fix the commissioning codes

The lock device exposes "Manage lock", whose dialog reads back the response
of matter.get_lock_info and matter.get_lock_users; neither was mocked, so
it always showed its load-failed alert.

setup_pin_code carried the manual pairing code. The three commissioning
codes now agree on the Matter test payload for passcode 20202021.

Pinging an unknown device rejects like the diagnostics command, matching
the backend, which resolves the device before acting either way.

The E2E test now reads the diagnostics of a Thread, a Wi-Fi and an offline
device, so a regression back to one shared response fails it.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Return a credential result and gate the Matter Thread action

`setMatterLockCredential` reads `user_index` off the per-entity response, so
the demo's empty object made saving a code throw. Return the indices the
dialog reads back, and drop the mock for a `clear_lock_credential` service
the frontend never calls.

The device action linking to the Thread panel did not check that the
integration is loaded, unlike the same link on the Matter dashboard, so it
could navigate to a panel that is not there.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Keep the mocked Matter lock users across changes

The manage dialog reloads the list after every add, edit and delete, so the
static response made each change look like it was reverted. Keep the users
per lock entity and mutate them, and hand back a copy so the dialog's
reactive state sees a new list.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

---------

Co-authored-by: Claude <[email protected]>
2026-09-04 17:34:09 +02:00
renovate[bot] e581172474 Update dependency globals to v17.12.0 (#53981)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-04 13:25:55 +02:00
Paulus SchoutsenandClaude Opus 5 59f16eeca2 Add Serial to the demo (#53974)
* Add Bluetooth to the demo

Load the bluetooth integration and mock its scanner, advertisement and
connection subscriptions, so the Bluetooth panel, its adapter info,
monitors and network map render in the demo.

Also adds the scaffolding the other Settings > Connectivity panels build
on: a per-integration fixtures contract, registry builders, and the two
registries that collect components, WS command prefixes and registry data
from each integration. `addEntities` now carries `device_id` and
`platform` into the mocked display entity registry, which the panels use
to count entities per device and per integration.

Mocked subscriptions emit their first message from a timeout. Subscribing
is synchronous in the mock, so an immediate callback lands before the
subscriber is ready: `createCollection` overwrote it with its empty
initial fetch, and pages that ignore messages received before their first
render dropped it.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Serve integration manifests for the demo's config entries

The integration page reads back the manifest it fetches without guarding,
so opening one for a domain the demo had no manifest for threw. Bluetooth
now ships its manifest through the connectivity fixtures, and manifest/get
falls back to a generated manifest rather than answering with undefined,
which also covers the entries that already lacked one.

Adds a demo E2E test that opens the Bluetooth panel and asserts its counts
are non-zero. The connectivity mocks reach the panel through lazy mock
registration and deferred first emissions, neither of which the demo suite
covered; without them the panel renders but stays empty.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Cover the Bluetooth scanner details subscription in the demo E2E test

The dashboard's adapter count comes from the config entries, so the test
passed even with the scanner details subscription broken, while the
adapter page and network map stayed incomplete.

The adapter page renders a settings button only for adapters that are not
remote scanners, which it knows from the scanner type in those details, so
asserting one button across the three adapters covers the subscription
without asserting on copy.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Keep connectivity entities when switching demos

Switching demos replaces the whole state map, and only the energy entities
were added back, so every connectivity state disappeared until a reload.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

* Add Serial to the demo

Load the usb integration and mock the serial port listing, so the Serial
panel renders in the demo with connected, available and disconnected
ports.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C6PpwxkMaHCWkEFA27YnLE

---------

Co-authored-by: Claude <[email protected]>
2026-09-04 13:19:36 +02:00
Bram Kragten 18f79dfc91 Bumped version to 20260826.6 2026-09-04 12:40:08 +02:00
Paul Bottein 5861c7487c Only select ha-input-copy text on click when readonly (#53959) 2026-09-04 12:39:01 +02:00
Wendelin 9dbfa821d3 History: Fix "add targets" on empty state (#53953)
Fix history empty targets button only on closed filterbar
2026-09-04 12:38:59 +02:00
Bram KragtenandCopilot Autofix powered by AI 1821e8fd67 Check if failed import is from us, or from user, and check if chunck 404's (#53940)
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-04 12:38:58 +02:00
Paul Bottein c8a3aa1d9a Hide empty labels row in more-info related view (#53939) 2026-09-04 12:38:57 +02:00
karwostsandCopilot Autofix powered by AI 6c606a4968 Fix websocket hang in picture card (#53930)
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-04 12:38:56 +02:00
Stefan AgnerandCopilot Autofix powered by AI f59a4b4996 Clarify what uninstalling an app deletes (#53923)
* Clarify what uninstalling an app deletes

The uninstall dialog offered a single switch labeled "Also remove app
data". That named the wrong thing twice over: the switch sends
remove_config, which Supervisor applies to the app's configuration
folder, while the app's data folder is deleted on uninstall either way,
independent of the switch.

Relabel the switch after the folder it actually removes, and state in the
dialog that uninstalling permanently deletes the app's stored data, so
the unconditional part of the operation is no longer implied to be
optional.

Rename the local variable and the uninstallHassioAddon parameter to
removeConfig to match the API field they carry.

* Move the app name out of the uninstall dialog title

Dialog guidelines ask to keep user generated content out of titles, as
names can get long enough to be unreadable there. The name now carries
the sentence in the body, which already describes what is deleted.

* Scope the uninstall warning to the app's private data folder

Uninstalling deletes the app's data folder and, when the app maps it,
the public config folder. Files the app wrote through the share, media
or Home Assistant config mappings stay where they are, so promising
that all of its data goes away is wrong for those apps.

Name the folder the deletion is limited to, and say the configuration
folder is only deleted if the app uses one, matching how the Supervisor
API documents the field. Also switch the label to "delete" for
consistency with the sentence above it.

* Name what an app actually keeps in its data folder

Checked the 30 most installed apps for what they write there. It holds
databases (MariaDB, InfluxDB, Grafana, UniFi, Nginx Proxy Manager,
AdGuard), credentials and network identity (Matter fabrics, the Thread
network key, Tailscale node state, Z-Wave JS settings, Mosquitto
accounts) and internal state such as caches and SSH host keys.

"Any other files it created" reaches past all of that. ESPHome keeps
device configuration in the Home Assistant config folder, Node-RED sets
its user directory to /config, WireGuard writes its keys to /ssl, and
those survive an uninstall.

* Fix punctuation in uninstall dialog text

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-04 12:38:55 +02:00
Paulus SchoutsenandClaude Opus 5 1cda8ee42d Add Bluetooth to the demo (#53967)
Co-authored-by: Claude Opus 5 <[email protected]>
Co-authored-by: Claude <[email protected]>
2026-09-04 12:30:33 +02:00
karwostsandCopilot Autofix powered by AI 87a4a70352 Fix websocket hang in picture card (#53930)
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-04 12:23:16 +02:00
renovate[bot] 046cf4de14 Update dependency typescript-eslint to v8.69.0 (#53961)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-03 19:57:06 +02:00
renovate[bot] d0d5b93106 Update CodeMirror (#53960)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-03 19:56:25 +02:00
Paul Bottein 3f2c0dae1b Only select ha-input-copy text on click when readonly (#53959) 2026-09-03 19:43:22 +02:00
Aidan Timson 5dea28504e Improve config panels type safety (#53955)
* Improve config type safety

* Type config search event targets

* Type config event handler targets

* Restore
2026-09-03 15:46:28 +02:00
Jan BouwhuisandPaul Bottein 8e1c4e93cf Add reusable state class selector (#53880)
* Add state class selector

* Update src/components/ha-state-class-picker.ts

Co-authored-by: Paul Bottein <[email protected]>

* Fix linter issue

* Rename `state_classes_filter` to `state_classes` as suggested

* Update and rename stateClasses property

* Fis missed rename

* Add default values

---------

Co-authored-by: Paul Bottein <[email protected]>
2026-09-03 15:42:38 +02:00
Bram KragtenandCopilot Autofix powered by AI 5513abbe8f Check if failed import is from us, or from user, and check if chunck 404's (#53940)
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-03 15:15:46 +02:00
Stefan AgnerandCopilot Autofix powered by AI a9862a8f7c Clarify what uninstalling an app deletes (#53923)
* Clarify what uninstalling an app deletes

The uninstall dialog offered a single switch labeled "Also remove app
data". That named the wrong thing twice over: the switch sends
remove_config, which Supervisor applies to the app's configuration
folder, while the app's data folder is deleted on uninstall either way,
independent of the switch.

Relabel the switch after the folder it actually removes, and state in the
dialog that uninstalling permanently deletes the app's stored data, so
the unconditional part of the operation is no longer implied to be
optional.

Rename the local variable and the uninstallHassioAddon parameter to
removeConfig to match the API field they carry.

* Move the app name out of the uninstall dialog title

Dialog guidelines ask to keep user generated content out of titles, as
names can get long enough to be unreadable there. The name now carries
the sentence in the body, which already describes what is deleted.

* Scope the uninstall warning to the app's private data folder

Uninstalling deletes the app's data folder and, when the app maps it,
the public config folder. Files the app wrote through the share, media
or Home Assistant config mappings stay where they are, so promising
that all of its data goes away is wrong for those apps.

Name the folder the deletion is limited to, and say the configuration
folder is only deleted if the app uses one, matching how the Supervisor
API documents the field. Also switch the label to "delete" for
consistency with the sentence above it.

* Name what an app actually keeps in its data folder

Checked the 30 most installed apps for what they write there. It holds
databases (MariaDB, InfluxDB, Grafana, UniFi, Nginx Proxy Manager,
AdGuard), credentials and network identity (Matter fabrics, the Thread
network key, Tailscale node state, Z-Wave JS settings, Mosquitto
accounts) and internal state such as caches and SSH host keys.

"Any other files it created" reaches past all of that. ESPHome keeps
device configuration in the Home Assistant config folder, Node-RED sets
its user directory to /config, WireGuard writes its keys to /ssl, and
those survive an uninstall.

* Fix punctuation in uninstall dialog text

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-03 15:02:09 +02:00
Wendelin d23314f4ff History: Fix "add targets" on empty state (#53953)
Fix history empty targets button only on closed filterbar
2026-09-03 11:56:12 +02:00
dependabot[bot] fcc5b381d3 Bump fast-uri from 3.1.5 to 3.1.6 (#53946)
Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.5 to 3.1.6.
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.5...v3.1.6)

---
updated-dependencies:
- dependency-name: fast-uri
  dependency-version: 3.1.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 06:23:38 +02:00
renovate[bot] 564205a3f3 Update tsparticles to v4.4.0 (#53951)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-03 06:23:01 +02:00
renovate[bot] 86fb936d14 Update dependency @octokit/auth-oauth-device to v8.0.5 (#53950)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-03 06:22:44 +02:00
Jump-333andCopilot Autofix powered by AI 497b7fce49 Add offline devices count to Matter (#53949)
* Added offline devices count to Matter

* Change condition to check for unavailable nodes

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Improve offline devices error handling

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-03 06:22:26 +02:00
Paul Bottein 251aac7e2e Hide empty labels row in more-info related view (#53939) 2026-09-02 19:16:01 +02:00
renovate[bot] 8d2106ccc8 Update dependency @formatjs/intl-datetimeformat to v7.6.1 (#53945)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-02 18:24:09 +02:00
Paul Bottein 3de2637da7 Rename AI settings URL from /config/ai-tasks to /config/ai (#53933) 2026-09-02 18:05:59 +02:00
Jump-333 36d048c8ab Add select-slider card feature for select/input_select tile control (#53876)
* Add select-slider card feature for select/input_select tile control

* Modified select-slider card feature to become just a style of the preexistent select-options

* Modified name icons to segmented and removed suggestion

* Fixed issues with punctuation and spaces

* Renamed segmented to buttons
2026-09-02 12:52:54 +00:00
Paul Bottein 4d7d5231d6 Fix seek bar position jumps while dragging and seeking (#53924)
* Keep seek bar position while dragging

* Unify seek bar progress handling in a shared controller
2026-09-02 14:33:43 +03:00
Aidan Timson b5709a56b0 Wait for connectivity, serial, storage settings readiness (#53935)
* Wait for connectivity settings readiness

* Wait for serial settings readiness

* Wait for storage settings readiness

* Simplify delayed serial scenario

* Test delayed connectivity readiness
2026-09-02 14:25:27 +03:00
Bram Kragten 4c08607dfe Bumped version to 20260826.4 2026-09-02 12:32:22 +02:00
Paulus SchoutsenandClaude Opus 5 f082816d9c Group the connectivity panels behind a Connectivity settings page (#53905)
* Group the connectivity panels behind a Connectivity settings page

Move the connectivity panels (Matter, Zigbee, Z-Wave, KNX, MQTT, Thread,
Bluetooth, serial, infrared, radio frequency, Insteon, and tags) behind a new
Connectivity page. It sits with Voice assistants in the second settings group,
where those panels used to be listed individually.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Y7Yy1BcbkMjCZEtkTEqyKm

* Update config panel e2e coverage for the Connectivity page

The connectivity panels moved off the settings root, so split the link smoke
cases and assert them on the Connectivity page instead. Add a route smoke case
for /config/connectivity.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Y7Yy1BcbkMjCZEtkTEqyKm

---------

Co-authored-by: Claude <[email protected]>
2026-09-02 12:30:56 +02:00
Bram Kragten b503862853 Bumped version to 20260826.3 2026-09-02 10:50:44 +02:00
Bram Kragten 1afa83d244 Fix stale trigger/condition lists (#53932) 2026-09-02 10:50:23 +02:00
Petar Petrov 7b93dde3c6 Only pan sankey charts on touch devices once zoomed (#53931) 2026-09-02 10:50:22 +02:00
Paul Bottein f8cb27b7ab Migrate add-to action list to grouped list style (#53921) 2026-09-02 10:50:21 +02:00
Paul Bottein 62f1509be4 Split more-info related and details views (#53920)
* Split more-info related and details views

* Update the related view e2e smoke case
2026-09-02 10:50:20 +02:00
Bram Kragten 1b834303d0 Fix stale trigger/condition lists (#53932) 2026-09-02 10:44:43 +02:00
Petar Petrov b455a34998 Only pan sankey charts on touch devices once zoomed (#53931) 2026-09-02 10:36:09 +02:00
Paul Bottein d84ef6b1bb Fit the picker popover to its list and align style with the select menu (#53801)
* Fit the picker popover to its list and align it with the select menu

* Use styleMap for the popover custom properties

* Fix combo box list not rendering for direct embedders
2026-09-02 10:15:53 +02:00
Paulus SchoutsenandClaude Opus 5 10ae5c1dd6 Rename AI tasks settings to AI and add Model Context Protocol card (#53906)
* Rename AI tasks settings to AI and add Model Context Protocol card

The AI settings page now shows a second card for the Model Context
Protocol server. When no mcp_server config entry exists, a centered
button starts the config flow. When enabled, the card shows the server
URL, an alphabetical list of registered LLM APIs with copy buttons for
their URLs, a configure button that opens the options flow, and a
disable action that deletes the config entry.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RQUrBPMXN35UQ19ZYPRpEZ

* Mock MCP server config entry and LLM APIs in demo

Lets the demo show the enabled state of the Model Context Protocol
card on the AI settings page.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RQUrBPMXN35UQ19ZYPRpEZ

* Rename MCP server URL row and mock MCP in the demo

The row heading did not say what makes this endpoint different from the
per API endpoints below it. Call it "Your MCP URL" and show the config
entry title, so it is clear which APIs it serves.

Mock an MCP server config entry and the registered LLM APIs in the demo.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RQUrBPMXN35UQ19ZYPRpEZ

* Simplify MCP card URLs to labeled copy buttons

Build the URLs from the origin Home Assistant is browsed on, so the
copied URL is reachable for whoever copies it.

Drop the URL text from the card and label the copy action, which was an
unlabeled icon that did not say it copies a URL. Name the API section
Individual MCP APIs so it is clear those are MCP endpoints too.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RQUrBPMXN35UQ19ZYPRpEZ

* Move MCP disable action into a header overflow menu

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RQUrBPMXN35UQ19ZYPRpEZ

* Align MCP card header actions and drop the disable icon

Put the help and overflow buttons in the header row so they line up with
each other and the title, instead of positioning them absolutely.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RQUrBPMXN35UQ19ZYPRpEZ

* Rename MCP card row to Your MCP API

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RQUrBPMXN35UQ19ZYPRpEZ

* Drop trailing word from MCP card description

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RQUrBPMXN35UQ19ZYPRpEZ

* Put configure before copy and drop Calendar from the demo

Ordering the configure button first lines the copy buttons up across all
rows. Calendar is not an LLM API integrations register, so mock only
Assist and Music Assistant.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RQUrBPMXN35UQ19ZYPRpEZ

* Always show the MCP configure button

The options flow is now in core, so the entry always supports options.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RQUrBPMXN35UQ19ZYPRpEZ

* Tell users where to add the MCP URL

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RQUrBPMXN35UQ19ZYPRpEZ

* Link the MCP docs from the card description

Point at the integration documentation for agent-specific instructions,
and call them AI agents.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RQUrBPMXN35UQ19ZYPRpEZ

* Drop the MCP card help icon

The description links the documentation, so the header icon is a second
link to the same page.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RQUrBPMXN35UQ19ZYPRpEZ

* Show MCP URLs in outlined rows

Give each URL its own outlined row with the URL under the name, and copy
with an icon button, so the URLs are visible before copying.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RQUrBPMXN35UQ19ZYPRpEZ

* Use hassUrl for MCP URLs and show load errors

Build the URLs with the standard helper instead of the window location.

Catch a failing load and show an alert. Without it a failed load left
the card with neither the URLs nor the enable button.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RQUrBPMXN35UQ19ZYPRpEZ

* Show a spinner while the MCP card loads

Without it the card showed only its description until the config entries
arrived.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RQUrBPMXN35UQ19ZYPRpEZ

---------

Co-authored-by: Claude <[email protected]>
2026-09-02 08:38:21 +03:00
renovate[bot] 74967ef6ee Update dependency generate-license-file to v4.2.5 (#53929)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-02 08:23:09 +03:00
Maarten Lakerveld 46de23727f Remove ES5 specific code (#53899)
* Remove web components polyfills and ES5 custom elements adapter

All supported browsers (legacy floor: Chrome 59, Safari/iOS 12, Firefox 94)
have native shadow DOM and custom elements, so the webcomponents bundle,
ShadyCSS branch, and lit polyfill-support are unreachable. The legacy build
now emits ES2017 classes, so custom-elements-es5-adapter and the
window.loadES5Adapter hook (no known third-party consumers) are removed.
Also stops shipping the never-loaded dialog-polyfill css and drops both
now-unused dependencies.

* Remove keyed-es5 Terser workaround

The custom keyed directive existed because Terser with ecma: 5 miscompiled
the destructured update() parameters (#28732). The legacy build now minifies
with ecma: 2017, so the stock lit-html keyed directive works in both builds.

* Remove old-browser JS shims and stale ES5 build references

Drops the IE-only navigator.msMaxTouchPoints check, replaces the
toggleAttribute helper with the native method (polyfilled automatically for
Chrome < 69 in the legacy build), and removes babel excludes for the
uninstalled proxy-polyfill and unfetch packages. Updates comments that
still described the legacy build as ES5.

* Remove vendor prefixes for no-longer-supported browsers

Deletes -ms- prefixes (IE/EdgeHTML only) and -webkit-/-moz- prefixed
declarations that every supported browser understands unprefixed, or that
Lightning CSS re-adds automatically from the unprefixed property in
production builds. Blocks that only had prefixed user-select now use the
standard property (previously Firefox got no user-select there at all).
Converts the four -webkit-linear-gradient() declarations - the sole
gradient syntax on those sliders - to standard linear-gradient().

* Remove dead html_url custom panel support

html_url pointed to an HTML Import, a Polymer-era feature removed from
Chrome in 2019 and never shipped elsewhere. The loader has not handled the
html type for years (it fell through to a rejection), and core's
panel_custom integration no longer accepts the option, so the branch was
unreachable. Also drops the ha-panel-${name} legacy tag naming that was
keyed on html_url.

* Repair list-plugins-and-polyfills script for Babel 8

The audit script died at startup since the Babel 8 update: preset-env no
longer exposes lib/debug.js (logPlugin is now inlined locally, built on the
public getInclusionReasons helper) and babel-plugin-polyfill-corejs3 v1 no
longer ships lib/shipped-proposals.js (list inlined).

Instead of invoking the preset with a hand-mocked plugin API - the part
that kept drifting - the plugin listing now runs a real transform of an
empty file with preset-env in debug mode, declaring the same caller
capabilities as babel-loader. The polyfill listing now passes the
configured core-js version to core-js-compat, mirroring the provider's own
filtering so the report cannot list modules the installed core-js lacks.
Output is byte-identical to the direct-invocation approach. Also documents
the script in the build-scripts README.

* Correct macOS floor for Safari 26 in companion app UA regex

Safari 26 ships for macOS 14 Sonoma and 15 Sequoia, not only macOS 26, so
the SAFARI_TO_MACOS entry breaking the minimum-supported-macOS pattern
would have sent updated macOS 14/15 companion apps to the legacy build
once the modern floor reaches Safari 26.

* Remove orphaned values left behind by vendor prefix removal

* Require macOS 14.6 for Safari 26 in companion app UA regex
2026-09-02 08:15:36 +03:00
Paul Bottein dc5d9f48bb Migrate add-to action list to grouped list style (#53921) 2026-09-01 16:28:30 +02:00
Paul Bottein 3d3cdabfe7 Split more-info related and details views (#53920)
* Split more-info related and details views

* Update the related view e2e smoke case
2026-09-01 16:17:37 +02:00
Paul Bottein 4b1f12c0ef Add seek support to the browser media player (#53917) 2026-09-01 14:44:21 +02:00
Bram Kragten efcf93191f Bumped version to 20260826.2 2026-09-01 10:34:13 +02:00
Maarten Lakerveld 577ededaf4 Fix log entry details collapsing to an ellipsis on narrow screens (#53881)
The secondary line of system log entries was made inline-block in #53575
to apply text direction. An inline-block is an atomic inline, so the
parent's text-overflow: ellipsis hid the whole line whenever it did not
fit, leaving only "…" on mobile. Use unicode-bidi: isolate instead so
direction still applies while the text truncates normally.

Fixes #53879
2026-09-01 10:33:46 +02:00
Paul Bottein 1cd16ad301 Always allow saving vacuum segment mapping (#53862) 2026-09-01 10:33:44 +02:00
Paul Bottein 2c2f733a82 Remove vacuum battery_level attribute unit (#53855) 2026-09-01 10:33:43 +02:00
Krisjanis Lejejs 22df9c704c Use the cloud auto-login flow in the voice satellite wizard (#53854)
Replace the wizard's own registration and sign-in screens with the cloud
panel's, extracted into cloud-register-card, so signing up mid-wizard gets
email-confirmation auto login instead of the legacy register plus login
polling. The wizard's copy of the login error ladder goes with it.

Drive the registration state from cloud/status rather than from the cloud
events, which carry nothing it does not already hold. The waiting view now
clears when the pending registration does, so a restart no longer leaves it
spinning on a registration the backend has forgotten.

Depends on the auto-login state fix in home-assistant/core#180423: without
it a retry loop that gives up before the register view stores its controller
leaves cloud/status reporting a pending registration with no reason, which
this no longer reads from the event instead.
2026-09-01 10:33:42 +02:00
Maarten Lakerveld d73341b2f8 Allow negative number entry on iOS when the number selector has no min (#53852)
The iOS workaround from #52925 only applied when the selector had an
explicit negative min. The numeric threshold selector used by the power
triggers passes a number selector without a min, so the digit-only keypad
(without a minus key) was still shown. Treat a missing min as allowing
negatives too.

Also leave inputmode unset instead of forcing "text": on a number input
iOS then shows the Numbers and Punctuation keyboard, which has a minus
key and fits numeric entry better than the full QWERTY keyboard.

Fixes #53747
2026-09-01 10:33:41 +02:00
Bram Kragten 907d15e7c1 Load the base map through core's tile proxy (#53845)
Co-authored-by: Claude Opus 5 <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
(cherry picked from commit a9d7712fb2)
2026-09-01 10:32:08 +02:00
Maarten Lakerveld 662ac1dc57 Fix RTL map labels and add English names to non-Latin ones (#53856)
* Load MapLibre RTL text plugin so Hebrew and Arabic map labels read correctly

The vector base map never registered MapLibre's RTL text plugin, so
right-to-left scripts were shaped left to right and every label came out
reversed. Ship @mapbox/mapbox-gl-rtl-text from /static/map/ alongside the
glyphs (no third-party host) and register it once, lazily, before the
first vector layer is created.

Fixes #53851

* Add the English name to map labels in non-Latin scripts

Before the move to vector tiles the CARTO basemap showed English names
everywhere. The OSM style shows local names, which most users cannot
read in Cyrillic, Arabic, Hebrew or CJK regions. Keep the local name and
add the English one from the tiles under it - in parentheses for street
labels, which cannot break lines. Latin-script names are left alone, so
Köln stays Köln.

(cherry picked from commit 156840b6ff)
2026-09-01 10:32:02 +02:00
Paul Bottein 39e7a05258 Fix the History timeline labels and tooltip placement (#53843)
* Draw History timeline names in a label column again

* Keep the timeline tooltip level with the hovered row
2026-09-01 10:27:21 +02:00
Paul Bottein 5cb7de5ac6 Fix weather forecast tabs in the more info dialog (#53841) 2026-09-01 10:27:20 +02:00
Paulus Schoutsen 0c7d3c8483 Render camera favorites as camera tiles (#53814) 2026-09-01 10:27:18 +02:00
lalexdotcom c92e5aa134 Report the fallback camera preview as loaded in ha-camera-stream (#53810)
`ha-camera-stream` declares a `load` event and both of its video players fire it through `fireEvent(this, "load")`, but the MJPEG and snapshot fallback `<img>` never does. Every camera without a working stream therefore goes through the one path that stays silent.

`hui-image` listens for that event to record `_lastImageHeight`, and that value is what drops the `.ratio` class so the container can size to its content. Without it the container keeps the 16:9 padding box it falls back to before anything is measured, while the picture is drawn at its own ratio and overflows. Measured against a 600x410 camera in a 600px wide card: the container stays 337.5px tall while the picture is drawn 410px tall, and it is still so ten seconds after the card is built.

Firing the event from the fallback image settles it: the container becomes 410px, matching the picture, and the 16:9 fallback goes back to being a placeholder for the first frame instead of a permanent state. Cameras that do have a stream are unaffected — they already fire `load` from their player.
2026-09-01 10:27:17 +02:00
a9d7712fb2 Load the base map through core's tile proxy (#53845)
Co-authored-by: Claude Opus 5 <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-09-01 10:26:18 +02:00
Krisjanis Lejejs a03efc1c5d Use the cloud auto-login flow in the voice satellite wizard (#53854)
Replace the wizard's own registration and sign-in screens with the cloud
panel's, extracted into cloud-register-card, so signing up mid-wizard gets
email-confirmation auto login instead of the legacy register plus login
polling. The wizard's copy of the login error ladder goes with it.

Drive the registration state from cloud/status rather than from the cloud
events, which carry nothing it does not already hold. The waiting view now
clears when the pending registration does, so a restart no longer leaves it
spinning on a registration the backend has forgotten.

Depends on the auto-login state fix in home-assistant/core#180423: without
it a retry loop that gives up before the register view stores its controller
leaves cloud/status reporting a pending registration with no reason, which
this no longer reads from the event instead.
2026-09-01 10:04:56 +03:00
Paulus SchoutsenandClaude Opus 5 9f7c353ad0 Group the connectivity panels behind a Connectivity settings page (#53905)
* Group the connectivity panels behind a Connectivity settings page

Move the connectivity panels (Matter, Zigbee, Z-Wave, KNX, MQTT, Thread,
Bluetooth, serial, infrared, radio frequency, Insteon, and tags) behind a new
Connectivity page. It sits with Voice assistants in the second settings group,
where those panels used to be listed individually.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Y7Yy1BcbkMjCZEtkTEqyKm

* Update config panel e2e coverage for the Connectivity page

The connectivity panels moved off the settings root, so split the link smoke
cases and assert them on the Connectivity page instead. Add a route smoke case
for /config/connectivity.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Y7Yy1BcbkMjCZEtkTEqyKm

---------

Co-authored-by: Claude <[email protected]>
2026-09-01 08:37:57 +03:00
lalexdotcom 350fae4107 Report the fallback camera preview as loaded in ha-camera-stream (#53810)
`ha-camera-stream` declares a `load` event and both of its video players fire it through `fireEvent(this, "load")`, but the MJPEG and snapshot fallback `<img>` never does. Every camera without a working stream therefore goes through the one path that stays silent.

`hui-image` listens for that event to record `_lastImageHeight`, and that value is what drops the `.ratio` class so the container can size to its content. Without it the container keeps the 16:9 padding box it falls back to before anything is measured, while the picture is drawn at its own ratio and overflows. Measured against a 600x410 camera in a 600px wide card: the container stays 337.5px tall while the picture is drawn 410px tall, and it is still so ten seconds after the card is built.

Firing the event from the fallback image settles it: the container becomes 410px, matching the picture, and the 16:9 fallback goes back to being a placeholder for the first frame instead of a permanent state. Cameras that do have a stream are unaffected — they already fire `load` from their player.
2026-08-31 13:36:48 +00:00
Maarten LakerveldandCopilot Autofix powered by AI e09c4084b7 Timer UI enhancements (#53793)
* Add timer data helpers for formatter-based display and duration serialization

Refactor computeDisplayTimer to take formatEntityState instead of hass so
context-migrated components can reuse it, add finishes_at to TimerEntity,
and add durationDataToTimerString for serializing duration input values.

* Modernize timer more-info dialog with state header and live countdown

Use ha-more-info-state-header with a ticking remaining-time display and
the standard more-info control layout. Adds timer to
DOMAINS_WITH_NEW_MORE_INFO, replacing the legacy state-card row.

* Add timer-actions and timer-presets card features

timer-actions shows start/pause/cancel/finish buttons (finish opt-in)
with state-aware disabling; start becomes restart while active.
timer-presets shows configurable one-tap durations that call timer.start.
Timer tile suggestions default to the timer-actions feature.

* Pulse timer red when it finishes

When a timer runs out or timer.finish is called, the tile icon and the
more-info countdown pulse red twice. Cancelling does not pulse: the new
timerJustFinished helper distinguishes the transitions via the
last_transition attribute. Honors prefers-reduced-motion.

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Send normalized duration for timer presets

Presets are parsed leniently by createDurationData like other duration
inputs, but the raw config value was sent to timer.start. A malformed
preset such as 1:nope:00 rendered as 1 h yet was rejected by core. Store
the normalized seconds so the label and the service call always match.

* Store timer presets on the entity instead of the card config

Review feedback: presets belong to the timer entity, like cover favorite
positions and light favorite colors. They now live in the entity registry
options and are edited in the more info dialog through the shared favorites
UI, which also brings reset and copy to other timers. The tile feature keeps
its style option but reads the presets from the registry.

* Reject a zero duration when adding or editing a timer preset

A zero duration passed the form's required check but was then treated as a
cancel, so saving the prefilled 0:00:00 silently did nothing. Form dialogs
now take an optional submit-time validate hook that blocks the submit and
shows a field error, and the preset dialog uses it to require at least one
second.

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-08-31 14:12:26 +03:00
nokside 946722daa2 Optimize update entities computation in hui-updates-card (#53878) 2026-08-31 12:28:18 +03:00
karwostsandPetar Petrov 3b038d5372 Support multiple for media selector (#53815)
* Support multiple for media selector

* Update src/components/ha-selector/ha-selector-media.ts

Co-authored-by: Petar Petrov <[email protected]>

* add to UI

* merge fix

* add helper

* Modify media item picker for clearable and image upload

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-08-31 12:02:03 +03:00
Paul Bottein 6b7d387175 Fix weather forecast tabs in the more info dialog (#53841) 2026-08-30 19:52:50 +02:00
renovate[bot] 8a4202ea19 Update dependency lint-staged to v17.4.1 (#53887)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-30 16:47:46 +02:00
renovate[bot] 2eaf1112f2 Update dependency @rspack/core to v2.2.1 (#53886)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-30 16:47:26 +02:00
dependabot[bot] d30ff07394 Bump the codeql-action group across 1 directory with 2 updates (#53884)
Bumps the codeql-action group with 2 updates in the / directory: [github/codeql-action/init](https://github.com/github/codeql-action) and [github/codeql-action/analyze](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.37.7 to 4.37.8
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd...db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28)

Updates `github/codeql-action/analyze` from 4.37.7 to 4.37.8
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd...db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-30 09:59:04 +03:00
renovate[bot] 5616b52979 Update dependency js-yaml to v5.4.1 (#53883)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-30 07:55:36 +03:00
Maarten Lakerveld 4219288701 Fix log entry details collapsing to an ellipsis on narrow screens (#53881)
The secondary line of system log entries was made inline-block in #53575
to apply text direction. An inline-block is an atomic inline, so the
parent's text-overflow: ellipsis hid the whole line whenever it did not
fit, leaving only "…" on mobile. Use unicode-bidi: isolate instead so
direction still applies while the text truncates normally.

Fixes #53879
2026-08-29 21:54:56 +02:00
nokside 09b221cf45 Fix date, datetime, and color temperature initial values (#53863) 2026-08-29 16:21:44 +03:00
renovate[bot] 89a467cac7 Update dependency @rspack/core to v2.2.0 (#53872)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-29 07:15:53 +00:00
Brandon c29b693038 Make the media selector clear button follow image_upload (#53866) 2026-08-29 09:14:05 +02:00
renovate[bot] 7ab178d045 Update Node.js to v24.20.0 (#53871)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-29 09:08:01 +02:00
renovate[bot] 538523c58b Update dependency generate-license-file to v4.2.4 (#53868)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-29 09:07:39 +02:00
136cf0c8bf Revamp user settings page & navigation (#52070)
* refactor(profile): split general section into subpages with dashboard navigation

Replace the two-tab profile layout (general/security) with a dashboard-first
navigation structure. The general section is split into three focused subpages
(preferences, localization, browser), each wrapping the original row components
unchanged. A new dashboard page provides a user card (name, owner badge, logout)
and a navigation list linking to all four subpages.

Add ha-navigation-list as a reusable component for page navigation lists.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* refactor: remove orphan translation keys after general section split

Drop tabs.general and current_user, which were only used in the now-deleted
ha-profile-section-general.ts and the old profileSections tab config.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* refactor(profile): align dashboard layout with Bluetooth panel pattern

Replace .content with .container (padding on wrapper, max-width/margin on
cards) to match the layout convention used in protocol panels like Bluetooth.
Always show the chevron in ha-navigation-list, removing the narrow condition.
Drop the unused narrow prop from ha-navigation-list.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* refactor: move ha-config-navigation-list to src/components

Makes the component available outside the config panel. Update import
paths in the two existing config consumers and use it in the profile
dashboard. Remove the now-unused ha-navigation-list (which relied on
ha-md-list/ha-md-list-item).

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* fix: security subpage width and card spacing

Use .container > * instead of ha-card to apply max-width and margin,
since the security cards are custom elements whose inner ha-card lives
in their own shadow DOM and is unreachable from the parent stylesheet.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* refactor(profile): move language setting to localization subpage

Language is a regional/cultural preference, consistent with the other
settings in localization (time zone, date and time formats).

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* refactor(profile): rename profile subpage labels

- "User preferences" -> "Appearance"
- "Browser settings" -> "This browser"
- "Mobile app settings" -> "This mobile app"

* feat(profile): surface theme picker on dashboard page

Move ha-pick-theme-row from the Appearance subpage to the profile
dashboard, between the user card and the navigation list. Theme and
dark mode are now accessible directly without navigating to a subpage.

Update Appearance description to reflect its new scope.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* refactor(profile): restructure theme row layout and labels

Split dark mode and color pickers into separate ha-settings-row elements
with headings. Move reset button outside the color-row to keep the label
vertically stable when the button appears. Add padding to reset row.
Rename "Reset" to "Reset colors" for clarity.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* add title to theme settings card

* refactor(profile): apply theme row layout improvements to ha-theme-settings

Migrate the dark mode and color pickers layout from ha-pick-theme-row into
ha-theme-settings: use separate ha-settings-row elements with headings for
dark mode and custom colors, move reset button outside as a sibling element.
Add colors label to ThemeSettingsLabels interface.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* refactor(profile): migrate theme settings to ha-list-item-base layout

Replace ha-settings-row elements in ha-theme-settings with ha-list-item-base
inside ha-list-base for a more compact appearance. Split color pickers into
individual rows (one per color). Reduce vertical padding to --ha-space-2.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* refactor(profile): combine color pickers into single row with label

Merge primary and accent color pickers into one ha-list-item-base row
under a "Custom colors" headline. Restore labels on individual pickers
and increase their min-width to 150px.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* fix(profile): stack theme settings rows vertically in narrow mode

Reflect narrow prop on host and use ::part(base/end) to stack all
ha-list-item-base rows in column layout on narrow screens, preventing
headline truncation from oversized end slot controls.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Fix test:e2e:demo

* fix broken links

* Add my links

* Use s instead of smal for ha-button size

Co-authored-by: Maarten Lakerveld <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
Co-authored-by: Maarten Lakerveld <[email protected]>
2026-08-28 21:57:59 +02:00
renovate[bot] 920c858056 Update dependency @lokalise/node-api to v16.4.0 (#53865)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-28 21:57:46 +02:00
renovate[bot] 3d2a4bfa04 Update dependency generate-license-file to v4.2.3 (#53864)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-28 21:57:43 +02:00
Paul Bottein e2c9b2cb79 Always allow saving vacuum segment mapping (#53862) 2026-08-28 17:21:14 +02:00
Maarten Lakerveld d38ee185bf Allow negative number entry on iOS when the number selector has no min (#53852)
The iOS workaround from #52925 only applied when the selector had an
explicit negative min. The numeric threshold selector used by the power
triggers passes a number selector without a min, so the digit-only keypad
(without a minus key) was still shown. Treat a missing min as allowing
negatives too.

Also leave inputmode unset instead of forcing "text": on a number input
iOS then shows the Numbers and Punctuation keyboard, which has a minus
key and fits numeric entry better than the full QWERTY keyboard.

Fixes #53747
2026-08-28 16:50:01 +02:00
Rishab MehtaandPetar Petrov 7e10f50419 Prefer neighbor relationship over raw LQI in ZHA network graph fallback (#53764)
* Prefer neighbor relationship over raw LQI in ZHA network graph fallback

* Create zha-network-data.test.ts

* Fix relative import paths and test connectivity via BFS instead of exact edges

* Add test coverage for extended relationship priority

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

* Just capitalizing relationshipPriority → RELATIONSHIP_PRIORITY in those two spots — nothing else changes.

* Update zha-network-data.ts

* Update zha-network-data.test.ts

* Update zha-network-data.ts

* Update zha-network-data.ts

* Update zha-network-data.test.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-08-28 15:47:00 +03:00
nokside 070fd96d6c Fix and centralize selector initial value handling (#53729)
* Fix and centralize selector initial value handling

* Fix unsupported selector initial values

* Omit undefined choose child values

* Fix device class and object selector initial values
2026-08-28 15:45:57 +03:00
Maarten Lakerveld 156840b6ff Fix RTL map labels and add English names to non-Latin ones (#53856)
* Load MapLibre RTL text plugin so Hebrew and Arabic map labels read correctly

The vector base map never registered MapLibre's RTL text plugin, so
right-to-left scripts were shaped left to right and every label came out
reversed. Ship @mapbox/mapbox-gl-rtl-text from /static/map/ alongside the
glyphs (no third-party host) and register it once, lazily, before the
first vector layer is created.

Fixes #53851

* Add the English name to map labels in non-Latin scripts

Before the move to vector tiles the CARTO basemap showed English names
everywhere. The OSM style shows local names, which most users cannot
read in Cyrillic, Arabic, Hebrew or CJK regions. Keep the local name and
add the English one from the tiles under it - in parentheses for street
labels, which cannot break lines. Latin-script names are left alone, so
Köln stays Köln.
2026-08-28 14:44:43 +03:00
5ff7a05ec5 feat: option to show add event button in calendar card (#53055)
* feat: option to show add event button in calendar card

* fix: remove translation file

* refactor: rename show_addfab to show_add_event

* fix: css calendar height

* feat: add event styling options

* Delete translations/backend/en.json

* fix: translation file

* fix: translations file

* fix: no box shadow when button below calendar

* fix: inconsistent narrow mode calculation

* fix: screen reader compability

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* fix: margin-inline-start for rtl layout support

* fix: use literal union instead of string in editor

* fix: use sentence case

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* fix: remove unused class

* feat: use visible parameter to toggle editor elements

* refactor: split add-fab into mulitple attributes for ha-full-calendar

* fix: lint type error

* fix: editor defaults

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-08-28 14:39:17 +03:00
MartinandPetar Petrov c3643555ab Respect gas entity display precision in energy dashboard (#53712)
* Respect gas display precision in gas graph

The gas graph previously formatted the total gas consumption using the generic number formatter, which could ignore the display precision  configured on the selected gas entity.

Use the configured gas entity's display precision for both the visible total chip and the total consumption tooltip.

This keeps the gas graph consistent with the entity configuration. For example, a gas entity configured with 3 decimal places will display 0.009 m³ instead of being rounded to 0.01 m³.

* Use configured gas entity display precision in energy distribution card

The energy distribution card previously formatted gas usage with the generic
energy formatter, which could ignore the display precision configured on the
selected gas entity.

Use the display precision of the configured gas consumption entity when
formatting the gas value in the energy distribution card.

This keeps the displayed value consistent with the entity configuration. For
example, a gas entity configured with 3 decimal places will now display
0.009 m³ instead of being rounded to 0.01 m³.

* Respect gas display precision in energy sources table

The energy sources table previously formatted gas values using the generic number formatter, which could ignore the display precision configured on the selected gas entity.

Use the configured gas entity's display precision for both individual gas source rows and the gas total row.

This keeps gas values consistent with the entity configuration. For example, a gas entity configured with 3 decimal places will display 0.009 m³ instead of being rounded to 0.01 m³.

* Use highest gas display precision for energy distribution

The energy distribution card previously used the display precision of the first configured gas source for the aggregated gas value.

Use the highest configured display precision across all gas sources instead of special-casing the first source.

This avoids making source 0 authoritative for an aggregate value and preserves the greatest configured precision when multiple gas sources are present.

* Use highest gas display precision for energy distribution

The energy distribution card previously used the display precision of the first configured gas source for the aggregated gas value.

Use the highest configured display precision across all gas sources instead of special-casing the first source.

This avoids making source 0 authoritative for an aggregate value and preserves the greatest configured precision when multiple gas sources are present.

* Use highest gas display precision in gas graph

The gas graph previously used the display precision of the first configured gas source for its aggregated total.

Use the highest configured display precision across all gas sources instead of special-casing source 0.

This keeps the graph total and tooltip consistent with the greatest configured precision when multiple gas sources are present.

* Use display_precision for entity precision

Replace dp with display_precision when reading precision from hass.entities, matching the EntityRegistryDisplayEntry type used by the frontend.

* Use display_precision for entity precision

Replace dp with display_precision when reading precision from hass.entities, matching the EntityRegistryDisplayEntry type used by the frontend.

* Use display_precision for entity precision

Replace dp with display_precision when reading precision from hass.entities, matching the EntityRegistryDisplayEntry type used by the frontend.

* Use display_precision for entity precision

Replace dp with display_precision when reading precision from hass.entities, matching the EntityRegistryDisplayEntry type used by the frontend.

* Use display_precision for entity precision

Replace dp with display_precision when reading precision from hass.entities, matching the EntityRegistryDisplayEntry type used by the frontend.

* Use display_precision for entity precision

Replace dp with display_precision when reading precision from hass.entities, matching the EntityRegistryDisplayEntry type used by the frontend.

* Restore consumption formatting in energy distribution card

* Respect gas display precision in energy sources table

* Respect gas display precision in energy graph

* Respect display precision in formatConsumptionShort

* Pass gas display precision to consumption formatter

Add logic to calculate gas display precision based on available sources.

* Use gas display precision for graph y-axis

* Update distribution card on gas precision changes

* Update sources table on gas precision changes

* Update gas graph when display precision changes

Refresh the gas graph when a gas entity's display precision or unit of measurement changes, ensuring the configured precision is applied without waiting for new energy data.

* Update distribution card on gas unit changes

Refactor gas source display precision check and update unit of measurement comparison.

* Derive gas display precision with a getter

* Fix hass change handling in energy sources table

* Fix hass change handling in gas graph

* Fix hass change handling in energy distribution

* Fix gas unit narrowing in energy distribution

* Fix formatting in gas graph card

Refactor gasDisplayPrecisions assignment for better readability.

* Fix formatting in energy sources table

* Fix Prettier formatting in energy gas cards

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-08-28 11:15:12 +00:00
Paul Bottein ae2c296272 Remove vacuum battery_level attribute unit (#53855) 2026-08-28 12:42:38 +02:00
noksideandMaarten Lakerveld 1db1c8024e Improve low battery entity lookup (#53850)
* Improve low battery entity lookup

* Apply suggestions from code review

Co-authored-by: Maarten Lakerveld <[email protected]>

* Fix formatting

---------

Co-authored-by: Maarten Lakerveld <[email protected]>
2026-08-28 10:47:44 +02:00
renovate[bot] 2f003ca999 Update dependency js-yaml to v5.4.0 (#53853) 2026-08-28 08:58:36 +01:00
Maarten Lakerveld b1d8a21aaa Don't close drawer when a nested tooltip hides (#53809)
wa-after-hide from a tooltip inside the drawer (e.g. the exact time
tooltip on a persistent notification) bubbled to the wa-drawer listener
and was treated as the drawer closing. Only handle the drawer's own event.

Fixes #52901
2026-08-28 08:45:28 +01:00
renovate[bot] cde2e66229 Update dependency typescript-eslint to v8.68.0 (#53848)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-28 06:45:08 +02:00
Paulus Schoutsen 71d5500ed8 Render camera favorites as camera tiles (#53814) 2026-08-28 00:05:02 +02:00
renovate[bot] 462321a3c8 Update dependency eslint to v10.9.1 (#53846)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-27 22:02:51 +02:00
renovate[bot] afc0c36dd9 Update dependency marked to v18.0.11 (#53847)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-27 22:02:43 +02:00
Bram Kragten 7f86074e07 Revert "Load the base map through core's tile proxy"
This reverts commit 4b9e47079c.
2026-08-27 19:15:16 +02:00
Bram KragtenandClaude Opus 5 4b9e47079c Load the base map through core's tile proxy
Core now proxies both vector and raster tiles, which is what lets them be
requested with an application User-Agent and without a referrer - a
browser can set neither. So the frontend stops talking to OpenStreetMap
and CARTO directly and goes through /api/map_tiles.

The proxy is token gated, so `ha-map` fetches one over the WebSocket
before setting up, following the brands token pattern: cached at module
level, refreshed well inside its lifetime so a dashboard left open for
days keeps working. The blocking wait is kept to about a second - a
backend without the proxy must not hold the map hostage - and the
remaining retries run in the background to ride through the window after
a restart where the WebSocket is up but the handler is not registered
yet.

Two things that are not obvious and cost a measurement each:

MapLibre's `transformRequest` has to return absolute URLs. Tiles are
fetched from a worker, which has no document to resolve a relative URL
against, and the TileJSON that core serves has relative `tiles`. Measured
with a relative TileJSON on one origin: with absolute URLs the style
loads and 8,456 features render; without them exactly one request is made
- the style - and nothing else loads, with no error reported anywhere.

Leaflet bakes its URL template at layer creation and throws while
building a tile URL if a template variable is undefined. So the raster
layer takes the token as an option Leaflet substitutes per request, which
also means a refreshed token is picked up without recreating the layer,
and an absent one is empty rather than missing: the tiles 403 and the
markers still draw.

The asset pipeline shrinks to generating two styles. Glyphs and sprites
come from the proxy, so the 48 MB build-time download, the digest
verification, the glyph range filtering and the bold-range guard are all
gone, along with 5.4 MB from the wheel. `localIdeographFontFamily` goes
too: the complete glyph set is reachable now, so CJK renders in Noto
rather than a device font.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 18:14:59 +02:00
Paul Bottein e3b9c6e143 Fix the History timeline labels and tooltip placement (#53843)
* Draw History timeline names in a label column again

* Keep the timeline tooltip level with the hovered row
2026-08-27 17:36:06 +02:00
Bram Kragten 8f73718a35 Bumped version to 20260826.1 2026-08-27 17:07:22 +02:00
Paul Bottein 4bf2acdb43 Show serial port info in a bottom sheet on mobile (#53839) 2026-08-27 17:06:48 +02:00
Shay Redmond f622e5eeb9 Small copy improvements for Cloud feature list (#53833) 2026-08-27 17:06:47 +02:00
Paul Bottein 595068597f Keep the row config when changing a device automation type (#53832) 2026-08-27 17:06:46 +02:00
Aidan Timson c708f35ab6 Fix MQTT subscribe controls layout (#53831) 2026-08-27 17:06:45 +02:00
Aidan Timson 205874c800 Show app icons for serial port consumers (#53827) 2026-08-27 17:06:44 +02:00
Petar Petrov 47ddcbe2e5 Fix editor state leaking when switching automations, scripts, or scenes (#53826)
* Fix editor state leaking when switching automations, scripts, or scenes

Recreate the page when the item id in the route changes so YAML mode,
undo history, and scene live state cannot carry over to the next item.

* Declare itemId on editor routes instead of guessing from the path

Path-shape matching remounted nested config routers, Lovelace, and
developer tools. Recreate only where edit/show routes opt in.

* Do not restore scene live states when the editor is torn down

A remounted editor starts in review; disconnect only needs to drop
the subscription, not undo device changes from live mode.

* Use the normal create path when remounting itemId pages

Clear the current page instead of calling _createPanel directly so
load and the loading screen still run. Drop the redundant cache delete.

* Fix dialog-form tests leaking focus restore after jsdom teardown

Nested submit/cancel schedules a nextRender callback that ran after
Vitest tore down HTMLElement, failing CI with an unhandled rejection.
2026-08-27 17:06:43 +02:00
Petar Petrov c43b8bfbe0 Do not show empty Grid legend item on energy usage graph (#53822)
Do not add empty combined Grid series on energy usage graph
2026-08-27 17:06:41 +02:00
Bram KragtenandClaude Opus 5 e349b00b15 Replace CARTO raster tiles with OpenStreetMap vector tiles (#53816)
Co-authored-by: Claude Opus 5 <[email protected]>
2026-08-27 17:06:40 +02:00
Paul Bottein 0bb8bdc98a Clarify the replaced device state in pickers and target rows (#53807) 2026-08-27 17:06:39 +02:00
Petar Petrov bbc5385843 Fix more-info dialog rewriting the URL after navigation (#53806) 2026-08-27 17:06:37 +02:00
Paul Bottein 43dc5651d3 Keep the automation config when replacing a device in device automations (#53805) 2026-08-27 17:06:36 +02:00
Aidan Timson 18dcf7abc0 Refine entity details context section (#53797) 2026-08-27 17:06:35 +02:00
221f184cb1 Remove no-op User-Agent header from Nominatim requests (#53834)
* Remove no-op User-Agent header from Nominatim requests

`User-Agent` is a forbidden header name for browser fetch/XHR, so the
option passed to both Nominatim calls was silently dropped and the
browser's own User-Agent went out instead. Verified in Chromium against
a local echo server: the header never took effect, the outgoing UA was
the browser default, and zero preflights were received — had it been
applied, the non-safelisted header would have forced an OPTIONS
preflight that Nominatim does not answer.

Identification towards Nominatim is done by the `email` query parameter
both calls already send, which is what the Nominatim usage policy
accepts, so nothing changes on the wire. Drop the misleading dead code
and note in a comment why the header cannot be set from a browser.

`hass` is still needed by both functions for `hass.locale.language`, so
the signatures are unchanged.

Co-Authored-By: Claude Opus 5 <[email protected]>

* Apply suggestions from code review

Co-authored-by: Maarten Lakerveld <[email protected]>

---------

Co-authored-by: Claude Opus 5 <[email protected]>
Co-authored-by: Maarten Lakerveld <[email protected]>
Co-authored-by: Maarten Lakerveld <[email protected]>
2026-08-27 15:04:28 +00:00
Petar Petrov 27cbbdb83f Fix editor state leaking when switching automations, scripts, or scenes (#53826)
* Fix editor state leaking when switching automations, scripts, or scenes

Recreate the page when the item id in the route changes so YAML mode,
undo history, and scene live state cannot carry over to the next item.

* Declare itemId on editor routes instead of guessing from the path

Path-shape matching remounted nested config routers, Lovelace, and
developer tools. Recreate only where edit/show routes opt in.

* Do not restore scene live states when the editor is torn down

A remounted editor starts in review; disconnect only needs to drop
the subscription, not undo device changes from live mode.

* Use the normal create path when remounting itemId pages

Clear the current page instead of calling _createPanel directly so
load and the loading screen still run. Drop the redundant cache delete.

* Fix dialog-form tests leaking focus restore after jsdom teardown

Nested submit/cancel schedules a nextRender callback that ran after
Vitest tore down HTMLElement, failing CI with an unhandled rejection.
2026-08-27 17:04:18 +02:00
Bram KragtenandClaude Opus 5 337e88560e Replace CARTO raster tiles with OpenStreetMap vector tiles (#53816)
Co-authored-by: Claude Opus 5 <[email protected]>
2026-08-27 16:35:43 +02:00
Paul Bottein 9c96c56558 Show serial port info in a bottom sheet on mobile (#53839) 2026-08-27 16:33:47 +02:00
Aidan Timson 27e0c4492c Refine entity details context section (#53797) 2026-08-27 15:21:26 +01:00
Paul Bottein 80889c3cea Keep the row config when changing a device automation type (#53832) 2026-08-27 16:16:25 +02:00
Paul Bottein cbbaf51e75 Keep the automation config when replacing a device in device automations (#53805) 2026-08-27 16:14:47 +02:00
Petar Petrov 9778a54305 Stop a percentage Y axis expanding past 100 (#53824)
A percentage has a real ceiling the way zero is a real floor, but the gap that
keeps series off the plot edges did not know that: a battery reading 20-100%
rounded out to an axis labelled up to 120%, and one sitting flat at 100% — a
device left on the charger — reached 160%.

Recognise the unit at the two line-chart call sites and hold the axis at 100,
mirroring the existing zero clamp. Only while the data stays under it, since
power factor is also reported in % and is signed.
2026-08-27 17:14:04 +03:00
Petar Petrov b9125537c0 Show Z-Wave neighbor connections in the network visualization (#53677)
* Show Z-Wave neighbor connections in the network visualization

* Fetch neighbors in bulk and hide them behind a toggle

* Warn that loading neighbor data turns off the adapter
2026-08-27 15:59:52 +03:00
Petar Petrov fd6017a963 Guarantee a Y-axis gap on history and statistics charts (#53821)
* Guarantee a Y-axis gap on history and statistics charts

ECharts floors the axis minimum and ceils the maximum to a tick multiple,
so quantized states that land exactly on a tick leave the data flush against
the plot edge — which collapses the climate and humidifier action bands to
zero height, since an area fill is based at the axis minimum.

Widen the auto-scaled extent by a fraction of the span so that same rounding
always has something to round away, keeping the axis anchored at zero for
single-signed data and preserving the window ECharts gives a constant series.

* Widen the Y-axis gap threshold to 2% of the span

A nudge only large enough to break an exact tie left the gap unchanged
whenever the data sat just above a tick rather than on it, so a chart could
still render with a hairline of headroom.

Because ECharts rounds out to a whole tick afterwards, this constant does not
set the size of the resulting gap — it decides which axes count as too flat to
leave alone. At 2% the worst case over the tick cycle goes from nothing to
around 3% of the plot, while every measured chart keeps the framing it had.
2026-08-27 15:57:50 +03:00
Shay Redmond e0f5d6d6b3 Small copy improvements for Cloud feature list (#53833) 2026-08-27 08:54:57 -04:00
noksideandPetar Petrov 193ab1b424 Deduplicate in-flight requests (#53786)
* Deduplicate in-flight requests

* Use callWS for in-flight request ownership

* Avoid mutating shared request results

* Deep-freeze shared in-flight request results

Centralize immutability in shareInFlightRequest using deep-freeze so
callers do not need readonly types on shared API shapes.

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-08-27 12:48:59 +00:00
Maarten Lakerveld 4a3b6db411 Make digital clock card font size themeable (#53808)
The digital clock hardcoded 1.5rem/3rem/4rem, which ignored
--ha-font-size-scale and could not be overridden from a theme. Use
--ha-clock-card-digital-font-size-{small,medium,large} with defaults based
on the font size scale (24px/48px/64px).

Fixes #51602
2026-08-27 12:05:11 +00:00
Aidan Timson 46271d0435 Show app icons for serial port consumers (#53827) 2026-08-27 13:26:19 +02:00
Aidan Timson d4bc02c86b Fix MQTT subscribe controls layout (#53831) 2026-08-27 13:25:40 +02:00
Marcin BauerandClaude Opus 5 a12ae9a8ed Expand tree nodes on double-click in the automation editor (#53830)
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-08-27 11:52:25 +01:00
Maarten Lakerveld 6095787294 Derive energy CSV time columns from exported rows (#53828)
The CSV header used the timestamps of every statistic in the energy
collection. Since the power sources chart (#27501) that includes the
power statistics, which are fetched at a finer period than the energy
statistics (hourly for a month view, where energy is daily), adding
empty hourly columns between the daily energy values. Collect the rows
first and build the time columns only from the data that is actually
exported.

Fixes #52381
2026-08-27 12:51:33 +02:00
Petar Petrov 127702b96f Fix more-info dialog rewriting the URL after navigation (#53806) 2026-08-27 09:51:29 +01:00
Petar Petrov 56a6c5d9fb Do not show empty Grid legend item on energy usage graph (#53822)
Do not add empty combined Grid series on energy usage graph
2026-08-27 11:49:22 +03:00
Petar Petrov 3b686dc3b9 Prompt for unsaved changes on programmatic navigation (#53804)
* Prompt for unsaved changes on programmatic navigation

* Tidy unsaved-changes guard tests

* Drop navigations superseded while an unsaved-changes prompt is open
2026-08-27 11:09:09 +03:00
Aidan Timson c5e8dea750 Fix centering for no history found in graph card feature (#53795)
* Fix centering for no history found in graph card feature

* Drop classMap
2026-08-27 11:08:18 +03:00
renovate[bot] 29cd46eb9e Update dependency minify-literals to v2.2.0 (#53812)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-26 20:24:56 +02:00
Paul Bottein 92b3081896 Clarify the replaced device state in pickers and target rows (#53807) 2026-08-26 19:48:52 +02:00
Shay Redmond 527319ab5e Remove the unnecessary spacing around the ha-alert components (#53799)
Remove the unnecessary spacing around the subscription ha-alert components
2026-08-26 14:01:38 +00:00
Maarten Lakerveld 8d3877c388 Fix Expose page crash when filtered by assistant (#53803)
The assistants URL filter can skip creating a row for entities that are
only exposed via Cloud (Alexa/Google) manual config, but the sortable key
was still assigned to the missing row, throwing a TypeError and leaving
the page on an infinite spinner. Only assign the key when the row exists.

Fixes #53689
2026-08-26 13:43:50 +00:00
Aidan Timson 66b9fbd4bf Fix view background config reference (#53802) 2026-08-26 15:40:31 +02:00
Bram Kragten a406abfdcd Merge branch 'rc' into dev 2026-08-26 14:48:07 +02:00
Bram Kragten fddc6e5506 Bumped version to 20260826.0 2026-08-26 14:47:19 +02:00
Petar Petrov 69518334bb Keep the frame minimum when a gap marker shares the frame (#53580)
The chart data modules push a null y value to break the line where an
entity was unavailable. downSampleLineData read it with Number(), and
Number(null) is 0, which is not NaN, so the isNaN guard did not fire.
The marker then competed as a real value of 0 and won its frame's
minimum slot whenever the readings were positive, discarding the
frame's actual minimum and widening the rendered gap.

Keep markers out of the min/max comparisons entirely and hold at most
one per frame in its own slot. It is emitted, after the frame's values,
only when no kept value follows it: a marker followed by a value in its
own frame is a gap that closed within one frame, which is about one
device pixel wide and too narrow to show. That check runs per frame at
emit time, so the per-point path stays as it was. Keeping every marker
instead would blow up the output on series that are mostly null, such
as the climate heating dataset, which went from 823 to 14525 points
before this was bounded.

Skipping markers before the numeric work also makes gapped series
faster: 16% on a series with a few gaps, 27% on one that is mostly
gaps. Both now have benchmark coverage, which the gap path lacked.

Mean mode no longer averages markers in as zero.
2026-08-26 15:29:12 +03:00
Petar Petrov 7a387004d6 Cache media source resolutions for view backgrounds (#53615)
Cache resolved media source URLs for view backgrounds
2026-08-26 15:28:34 +03:00
Paul Bottein 1e9993785d Add reusable device class picker (#53798) 2026-08-26 13:26:32 +02:00
renovate[bot] 1a3a93e3b9 Update dependency cropperjs to v1.6.3 (#53796) 2026-08-26 11:33:32 +01:00
Jan Bouwhuis c6dd741bb5 Add device class selector (#53672)
* Add sesnor device class selector

* Remove unused constants

* Remove stale test case and import

* Fix CI tests

* Add domain and make selector generic

* Follow up comments

* Use import
2026-08-26 12:23:26 +02:00
Krisjanis Lejejs 24f522b7ae Improve cloud login/sign up pages, add auto login (#53790)
* Improve cloud login/sign up pages, add auto login

* Improve trual button text

* Improve event subscription, fix email wrapping
2026-08-26 05:17:59 -04:00
Petar Petrov 0594229a45 Fix choose-view dialog showing another dashboard's views (#53792)
* Show the selected dashboard's views in the choose-view dialog

* Block the choose-view action while the dashboard config loads
2026-08-26 12:08:06 +03:00
Josef Zweck 615fd58324 Allow cross domain translations for config entry setup errors (#53791) 2026-08-26 09:35:48 +01:00
Paul Bottein fb35194041 Share favorites editor and security entity filter (#53785) 2026-08-26 09:11:48 +03:00
Paul Bottein d4e3ec858e Remove pulse from security dashboard alerts (#53784) 2026-08-26 08:24:31 +03:00
renovate[bot] 6516b8de68 Update dependency @bundle-stats/plugin-webpack-filter to v4.22.3 (#53783)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-25 18:10:10 +02:00
Paul Bottein edb2f98d03 Show targets in automation traces (#53718) 2026-08-25 18:50:04 +03:00
Aidan Timson 5ae95a1ea2 Add favorites to Security dashboard (#53512)
* Add favorites to security dashboard

* Use contexts in favorites editor

* Update src/translations/en.json

Co-authored-by: Paul Bottein <[email protected]>

* Address security favorites review

---------

Co-authored-by: Paul Bottein <[email protected]>
2026-08-25 17:46:03 +02:00
Aidan Timson d0371e506f Add active alerts to Security dashboard (#53031)
* Add security dashboard alerts

* Fix security alerts editor and card defaults

* Use consistent security editor icons

* Fix security dashboard alert state

* Fix lint

* Render security alerts as individual cards

* Use context data in security alerts editor

* Add pulse for alerts

Co-authored-by: Paul Bottein <[email protected]>

* Use explicit cover and lock alert states

* Fix test

* Remove security panel rendering tests

* Use complete states

Co-authored-by: Paul Bottein <[email protected]>

* Remove camera

Co-authored-by: Paul Bottein <[email protected]>

* open state only

Co-authored-by: Paul Bottein <[email protected]>

* Remove security entity filter cache

* Format

* Update security alert visibility tests

---------

Co-authored-by: Paul Bottein <[email protected]>
2026-08-25 17:28:46 +02:00
Paul Bottein 872205c352 Remove template and default-value tests (#53779) 2026-08-25 17:14:00 +03:00
tormazs bf939babfd Fix ha-control-select losing its value when activated by a screen reader (#53777)
The option handlers read the value from ev.target, which is whichever
element the click landed on. Real pointer events are retargeted to the
outer role="radio" element by .option .content { pointer-events: none },
but a screen reader's synthetic activation click is not hit-tested, so it
lands on the inner content element, which has no value.

ev.currentTarget is always the element the listener is bound to, so it
always carries the value.
2026-08-25 15:39:05 +03:00
nokside d41b21b9d6 Fix timeCachePromiseFunc cache handling (#53773)
Fix promise cache result handling
2026-08-25 15:31:08 +03:00
Jan Bouwhuis 7e495f38d2 Expand sensor entity constants and add device classes (#53748)
* Expand sensor entity constants and add device classes

* Updated constants

* Fix typo

* Fix name

* Restore part original generated script comment

* Add convertible units and fix null type

* Fix type

* Update constants

* Fix import SENSOR_NUMERIC_DEVICE_CLASSES
2026-08-25 14:28:13 +02:00
Petar Petrov 5cff0cb4c9 Focus nested form-dialog fields when a nested level is pushed (#53757)
* Focus nested form-dialog fields after a nested level is pushed.

Host focus on ha-form does not pierce selector shadows, so keyboard
focus stayed on the opener instead of the nested controls.

* Simplify nested form-dialog focus and fix CI types.

Wait one render and focus the first real control instead of waiting for
custom-element upgrades or walking a general focusable tree.

* Wait for lazy selector upgrades before nested form focus.

nextRender is not enough on a cold selector chunk; wait for undefined
custom elements so nested focus does not depend on network timing.
2026-08-25 15:14:33 +03:00
Paul Bottein dbe2e2c079 Reflect the active filters in the target picker counts (#53716) 2026-08-25 13:53:26 +02:00
Paul Bottein e22b770252 Clarify when agents should add tests (#53775) 2026-08-25 12:28:47 +01:00
Paul Bottein fd388d99bf Show area and disable pulse by default in alert card (#53774) 2026-08-25 12:17:52 +01:00
Aidan Timson f9bfc66d5b Add alert card (#53758)
* Add security alerts card

* Fix security alert cards

* Validate security alert card configuration

* Keep a single generic alert card

* Use entity context in alert card
2026-08-25 10:45:53 +01:00
renovate[bot] c4ab017aed Update dependency @rspack/dev-server to v2.2.1 (#53772) 2026-08-25 09:27:59 +01:00
Paul Bottein e22ef3e1f3 Merge the domain and device class filters into a type filter (#53710)
* Merge the domain and device class filters into a type filter

* Only scan the entities while the type filter panel is open
2026-08-25 08:12:00 +02:00
renovate[bot] 7a3764790b Update dependency @types/luxon to v3.7.5 (#53770)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-25 08:40:20 +03:00
karwosts c499c2e030 Fix more-info setting dirty state tracking (#53762) 2026-08-25 07:02:41 +02:00
Raman GuptaandClaude Opus 5 13ec52ddbe Fix Z-Wave add node security strategy selection not sticking (#53769)
The security strategy step rendered ha-form with a data object built
from a @state field that was never assigned, so the form was always
bound to an undefined strategy. ha-form's own optimistic data update
made the radio look selected after a click, but the next re-render of
the step (triggered by any hass update) re-committed the undefined
value and cleared the selection.

Make the step a controlled component: the dialog already owns
_inclusionStrategy and resets it when navigating back, so pass it down
as a property instead of keeping a second, unused copy in the child.


Claude-Session: https://claude.ai/code/session_011MGgDoAUxzf9KBexn6uiPc

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-08-25 07:01:47 +02:00
wollewandkarwosts d288cfd30a Add supported_speeds parameter for cover movement actions (#53572)
add supported_speeds for cover service actions

Co-authored-by: karwosts <[email protected]>
2026-08-24 20:10:19 +02:00
karwosts 643e8934b4 Allow media selector to optionally select a media directory (#27873)
Allow media browser to select a directory
2026-08-24 20:05:21 +02:00
renovate[bot] 9f3ca39738 Update dependency eslint to v10.9.0 (#53765)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-24 17:03:14 +03:00
renovate[bot] 8cee5155e6 Update dependency @rsdoctor/rspack-plugin to v1.6.3 (#53761) 2026-08-24 14:37:06 +01:00
Paul Bottein 15341a0aad Show climate summary card with only temperature sensors (#53760) 2026-08-24 14:51:04 +02:00
Petar Petrov 9f8a2253ac Add keyboard and screen reader navigation to the energy device charts (#53754)
* Sonify value-first charts now that the extension reads them

* Announce device names instead of statistic ids in sonified charts
2026-08-24 14:45:43 +02:00
Maarten Lakerveld 97df5a5bf0 Key more-info details memoize on attribute name formatter (#53755)
_getDetailData caches on stateObj alone while formatting via this.hass,
so results go stale when translation-based format functions reload (e.g.
backend translations finishing after open, or a language switch) until
the entity next changes state. Pass hass.formatEntityAttributeName as an
extra memoize argument so the cache invalidates when format functions
are recreated.
2026-08-24 11:59:22 +02:00
Petar Petrov 19cd06bb8c Fix energy period rollover overnight and in the first hour (#53717)
* Fix energy dashboard staying on yesterday after midnight.

* Catch up the energy live day before subscribe fetches.

* Keep energy day math in the server timezone so DST cannot skip a live day.

Browser-local addDays can jump a calendar day on a 23-hour DST fallback.
Assert against tz-internal endOfDay/addDays under Europe/Berlin so UTC CI
catches a regression, and prove the 01:00 timer and catch-up refresh fetch
the live day rather than only updating collection.start.

* Don't follow the live day from midnightRollover alone.

A stored non-today preset would otherwise be discarded on the first subscribe. Drop tautological UTC DST tests that cannot fail.
2026-08-24 10:16:00 +02:00
nokside fcca87b368 Fix editing nested multiple object selector items (#53709)
* Fix editing nested multiple object selectors

* Fix nested form dialog close and focus restoration

Cancel all pending nested form levels when the physical dialog closes, and restore focus to the opener after nested submit or cancel.

Add regression coverage for both behaviors.

* Fix selector object test types
2026-08-24 09:41:58 +03:00
puddly 2eb3b025d8 Add a serial panel (#53699)
* WIP: Initial attempt

* Arrange into sections

* Clean up UI

* Add descriptions

* Align with Core changes

* Address review feedback and add an info dialog

* Combine websocket commands into one

* Drop unnecessary info dialog rows

* Add a status bar

* Expose `resolved_device` as well
2026-08-24 06:58:23 +02:00
DawnWang 43628c5d69 Fix error badge creation on cold load (#53752) 2026-08-24 04:53:53 +00:00
renovate[bot] 0f52c00821 Update dependency echarts-extension-chart2music to v0.1.1 (#53753)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-24 06:48:24 +02:00
dependabot[bot] 20f70cde7a Bump the codeql-action group across 1 directory with 2 updates (#53744)
Bumps the codeql-action group with 2 updates in the / directory: [github/codeql-action/init](https://github.com/github/codeql-action) and [github/codeql-action/analyze](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.37.6 to 4.37.7
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/5595ccaf912efad79be6eef63a5619ff05969be3...ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd)

Updates `github/codeql-action/analyze` from 4.37.6 to 4.37.7
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/5595ccaf912efad79be6eef63a5619ff05969be3...ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-23 09:55:54 +02:00
renovate[bot] b38d7bcb26 Update dependency hls.js to v1.7.1 (#53741)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-22 22:20:30 +02:00
Petar Petrov 0572d71699 Replace a remembered yesterday energy period when picking now (#53735) 2026-08-22 17:36:40 +02:00
renovate[bot] bcd13fcaf7 Update vitest monorepo to v4.1.11 (#53732)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-21 21:35:37 +02:00
renovate[bot] 308eac97ee Update dependency marked to v18.0.10 (#53725)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-21 06:37:46 +02:00
Paul Bottein 6da851219d Fix stacked toasts when a dashboard is updated in another session (#53719) 2026-08-20 21:34:08 +02:00
renovate[bot] 970be43c3d Update dependency intl-messageformat to v11.2.14 (#53722)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-20 21:01:27 +02:00
karwosts 8bb718a486 Cleanup some attributes code (#53713) 2026-08-20 20:54:59 +02:00
Josef Zweck 0e0bc389f8 Show result of action for button presses (#53645)
* Show result of action on button feature

* Add button entity

* Add to button entities

* add to tile icon

* Delay for spinner

* Remove result indicator from tile icon
2026-08-20 16:49:55 +02:00
Petar Petrov 70a482e0ed Add keyboard and screen reader navigation to charts (#53533)
* Add keyboard and screen reader navigation to charts via Chart2Music

* Mark charts as busy while the sonification chunk loads

* Skip chart sonification when there is nothing to navigate

* Drop the direct chart2music dependency

* Exclude legend-hidden series when judging chart sonifiability

* Push statistics chart times as numbers so sonification reads real dates
2026-08-20 16:55:11 +03:00
Maarten Lakerveld 5a0db4a796 Show Assist greeting in the assistant's language (#53707)
The greeting sits in the assistant's chat bubble, so render it in the pipeline's language instead of the interface language. Falls back to the interface language when no translation is available (issue #53703).
2026-08-20 12:49:40 +02:00
622f3e97e6 Add RepairsFlow as a next_flow from a RepairsFlow (#51744)
* fix flowType in config subentry flows/next_flow

* suggested changes

* Repair Flow Next Flow Repair

* Add repair flow support a new repair flow as the next_flow

* Add support for the next_flow being another repair flow

* fix lint errors

* Reviewer response and fix linter error

* Revert to generics to avoid multiple casts

* Move show-dialog-repair-flows to dialogs

* Update src/dialogs/config-flow/dialog-data-entry-flow.ts

* Apply suggestions from code review

* Apply suggestion from @MindFreeze

* format

---------

Co-authored-by: Petar Petrov <[email protected]>
Co-authored-by: Paulus Schoutsen <[email protected]>
2026-08-20 11:24:23 +03:00
renovate[bot] 3091362040 Update dependency @html-eslint/eslint-plugin to v0.65.0 (#53714)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-20 11:08:20 +03:00
Paul Bottein 3c7560a4e2 Add indeterminate and controlled selection to lists (#53706) 2026-08-19 23:26:40 +02:00
Petar PetrovandSimon Lamon a9e178cb0e Show per-mount storage usage on the storage page (#53683)
* Show per-mount storage usage on the storage page

Each active mount now fetches its own usage from the Supervisor and renders
a bar with a used-of-total line under its address. The requests are not
awaited, so a slow or unreachable server cannot hold up the rows, and a
failed one simply leaves that row without usage.

fetchHostDisksUsage now takes a disk and an optional max_depth. The data
disk callers keep their depth of 3; mounts send no depth at all, since
walking one costs a round trip per directory and the Supervisor already
has a sensible per-target default.

* Vertically align ha-bar

---------

Co-authored-by: Simon Lamon <[email protected]>
2026-08-19 21:18:37 +02:00
23b83fbd27 Update browserlist (#53691)
* update browserlist for better packaging

* add results of bundle changes

* update browserlist, budgets and ecma terser rewrite level

* remove results.md used for testing

* Apply suggestion from @silamon

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Simon Lamon <[email protected]>
2026-08-19 18:45:22 +00:00
Marcin BauerandClaude Opus 5 62849e2630 Fix outlined button border colors (#53704)
The brand outline pointed at a token that doesn't exist, so CSS fell back
to the neutral border and brand outlined buttons drew a gray ring.

Disabled outlined buttons only reset their background and label, keeping
the variant-coloured border.

Also add outlined to the gallery: it has always been a valid appearance
but was missing from the documented list the gallery grid is built from,
which is why both bugs went unnoticed.

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-08-19 20:37:09 +02:00
renovate[bot] aa3e11f6e9 Update CodeMirror (#53705)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-19 20:34:12 +02:00
Paul BotteinandPetar Petrov 82ed13b7fc Fix filter pane expand animation and use a bottom sheet in narrow mode (#53684)
* Fix filter pane expand animation and use a bottom sheet in narrow mode

* Update src/common/controllers/filter-panel-controller.ts

Co-authored-by: Petar Petrov <[email protected]>

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-08-19 16:18:40 +03:00
Petar Petrov 089592e7e3 Ignore stale History statistics fetches after the selection changes (#53700)
* Ignore stale History statistics fetches after the selection changes.

A slower fetchStatistics call could finish after a newer sources or date-range request and replace the charts the user is looking at.

* Update src/panels/history/ha-panel-history.ts

---------

Co-authored-by: Paul Bottein <[email protected]>
2026-08-19 12:00:43 +02:00
Paul Bottein 4bc9b2be7b Remove the unused compact mode from the target picker (#53685) 2026-08-19 11:48:43 +03:00
renovate[bot] 1778b7abff Update dependency barcode-detector to v3.2.2 (#53702)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-19 11:39:58 +03:00
90567a491a Redesign History and Activity filtering into a sources pane (#53630)
* Redesign History and Activity filtering into a sources pane

Give both panels the toolbar + left pane layout of the data tables, and
merge target picking and filtering into one "Sources" surface, per the UX
discussion.

- ha-filter-pane: pane on wide screens, bottom sheet on narrow ones,
  mirroring the filter pane of hass-tabs-subpage-data-table
- ha-sources-picker: target picker plus domain, device class and
  integration filters, shared by both panels
- ha-filter-device-classes: new filter panel, labelled with the backend
  device class names
- ha-filter-pane-chip and ha-empty-state: the chip with a filter count
  badge and the centered placeholder both panels need
- ha-date-range-nav: the date range picker as one pill with previous and
  next steppers, for the toolbar
- History draws timeline names above their bar (inside-labels), which
  gives long names the full width
- Activity keeps a floating date header while scrolling, and reset moved
  into the overflow menu next to refresh and download
- Drop the now unused compact and add-on-top modes of ha-target-picker,
  including ha-target-picker-value-chip
- Right-align the clear button in the domains filter header, matching the
  other filter panels

Co-Authored-By: Claude Opus 5 <[email protected]>

* Remove dead code breaking the type check

* Fix stuck loading state when the selection resolves to no entity

* Keep the target picker out of the redesign

* Remember the source filters across visits

* Truncate timeline names that do not fit the plot

* Show device class icons in the sources filter

* Open the sources pane by default on wide screens

* Show the entity count in the sources chip

* Count the same entities in the sources chip and the target picker

* Fix sources resolution, fetching and filter badge in History and Activity

* Update src/panels/history/ha-panel-history.ts

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Claude Opus 5 <[email protected]>
Co-authored-by: Paul Bottein <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-08-19 11:31:10 +03:00
Paul Bottein 409e2b315f Skip entities assigned to another area when resolving area targets (#53693) 2026-08-19 08:46:45 +03:00
Petar Petrov eb1f8c1fab Add Matter network topology visualization page (#53247)
* Add Matter network topology visualization page

* Add central Home Assistant node to Matter network graph

* Refine Matter graph HA node: theme-aware memoization, drop dead branch

* Render Matter 'unknown' link strength as a present, neutral link

* Pass devices to getDeviceArea so bridged nodes inherit their area

* Distinguish position-unknown Matter graph anchors and name border routers

Anchors to a hubless component only mean the node is reachable, so draw
them dotted instead of reusing the solid line that marks a real path
through a border router or access point.

Also prefer the border router mDNS host name over vendor and model,
which several vendors report identically on every unit.

* Name Matter access points by SSID and show their radio address

Access points were labelled with a BSSID, and the same address was
repeated as the node context. Prefer the SSID for the label and keep the
radio address as context only when it differs, so the radios of one mesh
stay distinguishable without repeating the label.

Falls back to today's BSSID against servers that do not send an SSID.

* Colour Matter graph links by transport and float unknown neighbours

Unknown Thread neighbours are not commissioned on our fabric, so Home
Assistant has no operational path to them. A group made only of unknown
devices no longer draws an anchor to the Home Assistant node and floats
instead of claiming a connection that does not exist.

Link colour now encodes the transport, purple for Thread and pink for
Wi-Fi, with the signal level left on the line width and spelled out in
the tooltip. A dead link keeps the disabled colour, which is the only
thing separating it from a healthy weak one now that both are width 1.
The edge tooltip names the network, since the graph legend describes
nodes only and cannot carry a link entry.

* Float Matter nodes whose route to Home Assistant is unknown

Only border routers and access points get an edge to the Home Assistant
node, because only those are a path we can actually see. A node in a
group with neither was previously anchored to Home Assistant with a
dotted line, which reads as a physical connection that was never
observed.

Removing the anchor makes the component walk that picked a
representative dead code, so it goes too.

* Match the dashboard's line semantics for Matter graph links

Dash an edge whose endpoint is inferred rather than commissioned, or is
offline, which is the same pair of conditions the matter.js dashboard
dashes on. Stop drawing a link whose every direction is dead: the
summary strength is the strongest direction, so none means a stale
neighbour entry, and the dashboard never draws one either.

That also retires the grey dead-link colour, since such links no longer
reach the graph.

* Carry the transport colour onto the Home Assistant edges

An edge from Home Assistant to a hub now takes the colour of the network
behind it, so one transport reads as one colour the whole way back
instead of changing hue at the hub.

Wi-Fi moves from pink to orange: pink sat close to the error red used
for offline nodes, while orange is far from both that red and the Thread
purple.

* Give the Wi-Fi access point node its transport colour

The access point wore indigo while everything else on its network was
orange. Deriving the category colour from the same helper the links use
keeps a hub and its links one hue, and gives the Wi-Fi colour a legend
entry it did not have before.

* Give the border router node its transport colour too

Both hub categories now derive their colour from the same helper as the
links, so a network is one hue from Home Assistant through its hub to
the devices, and each legend swatch keys the links of that transport.

The border router also gains contrast: the shared Thread purple is
legible on both the light and the dark card background, where the deep
purple it replaces was not.
2026-08-19 08:02:49 +03:00
Paul Bottein 29cf30fc1a Fix check for updates toasts stacking (#53696) 2026-08-19 06:45:52 +02:00
renovate[bot] f88535c446 Lock file maintenance (#53698)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-19 06:43:45 +02:00
Jan Bouwhuis b9fd639bb7 Add improved mqtt panel to config section (#53653)
* Add mqtt config dashboard shortcut

* Improve MQTT subscribe panel formatting and add copy button

* Standardize MQTT options flow button to a nav card style

* Refactor MQTT dashboard

* Improve style

* Add link to broker connection settings

* Test the effect of not exporting the SVG data

* Move MQTT svg icon to separate file
2026-08-18 19:00:28 +02:00
Paul Bottein 2925dfc14e Show entity name in template autocomplete info panel (#53695) 2026-08-18 18:54:03 +02:00
Yosi Levy bb7ec34532 Addons RTL fix (#53692)
Addon RTL fix
2026-08-18 17:01:41 +02:00
Stefan AgnerandClaude Fable 5 89015bc135 Fix backup progress segment order to match backend execution order (#53652)
* Fix backup progress segment order to match backend execution order

The segmented backup progress bar showed Apps, Media, Home Assistant,
but Supervisor backs up Home Assistant first since 2024 (supervisor#5203),
then add-ons, then folders. The Home Assistant segment activated first
while Apps/Media incorrectly showed as completed, and the bar regressed
once the apps stage started.

Also move the await-addon-restart stages into the last creation group,
since Supervisor awaits add-on restarts after the backup file is
finished, keeping the progress bar monotonic.

Co-Authored-By: Claude Fable 5 <[email protected]>

* Keep await restart stages out of MEDIA_STAGES

Give them their own constant and merge them into the last creation
group only where the ordering constraint applies.

Co-Authored-By: Claude Fable 5 <[email protected]>

* Group backup setup stages with the first progress segment

addon_repositories/app_repositories (and docker_config on older
Supervisors) are emitted while the backup is initialized, before the
home_assistant stage, so grouping them with the apps segment made the
bar regress at the start of a backup.

Co-Authored-By: Claude Fable 5 <[email protected]>

---------

Co-authored-by: Claude Fable 5 <[email protected]>
2026-08-18 13:52:07 +03:00
Petar Petrov 343f1e840a Fix Z-Wave network visualization showing wrong route edges (#53676)
Fix repeater mapping and route direction in Z-Wave network graph
2026-08-18 08:07:24 +03:00
G Johansson 1369f80eb0 Allow using description in create_entry for repair flows (#53671) 2026-08-17 22:08:57 +02:00
Paul Bottein cd52f7b193 Fix the clear button alignment in the domains filter (#53687) 2026-08-17 17:47:35 +00:00
renovate[bot] 86dea86b6c Update dependency js-yaml to v5.3.0 (#53679)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-17 17:16:53 +00:00
Paul Bottein 04035016b0 Extract the data table filter chip into ha-filter-pane-chip (#53682) 2026-08-17 19:16:46 +02:00
Petar Petrov 52b0b46991 Group sankey devices by count as well as by value (#53680)
* Group sankey devices by count as well as by value

The 0.1%-of-total value threshold only catches devices that are a
negligible share of the home total. A breaker panel with dozens of
similar-sized circuit clamps sits entirely above it, so nothing groups and
every node collapses toward the 1px minimum with labels shrinking to match.

Cap the number of named children per parent too, defaulting to 20 (the
readable capacity of the default 400px card). Over-cap devices are grouped
into the same per-parent "Other" node the value threshold already produces,
so the flow arithmetic is unchanged, and the cap is configurable per card
via max_devices.

* Clarify the max_devices label is per upstream device, not per floor or area

* Make max_devices budget named devices, not nodes

A cap of 20 rendered 19 devices because a slot was reserved for the Other
node, and a cap of 1 rendered none. The option now means what its name and
its namesake on the devices graph mean: at most this many devices are shown
by name, with Other as overhead on top.

* Extract the sankey device cap into findDevicesOverCap

Moves the count-cap logic out of buildSankeyDeviceNodes into an exported
function that takes the graph it needs, so it can be unit tested directly,
and trims the commentary to the two non-obvious rules (why the whole subtree
is grouped, and why at least two devices are).
2026-08-17 19:14:48 +02:00
Stefan AgnerandClaude Fable 5 d5389b5bef Fall back to option key for untranslated repair menu options (#53681)
Repair fix flows build their menu from the suggestions the backend
reports. A suggestion this frontend has no translation for yet (e.g. a
newer Supervisor offering a new repair suggestion) rendered as an
empty, unlabeled menu entry. Show the raw option key instead, matching
the fallback the form step header already uses.

Co-authored-by: Claude Fable 5 <[email protected]>
2026-08-17 15:23:02 +02:00
Logan RosenandCopilot App f828c636a2 Fix Energy configuration back navigation (#53574)
* Fix Energy configuration back navigation

Co-authored-by: Copilot App <[email protected]>

* Align app E2E navigation with production

Co-authored-by: Copilot App <[email protected]>

---------

Co-authored-by: Copilot App <[email protected]>
2026-08-17 12:45:08 +03:00
Petar Petrov e91337b320 Log console error when a dashboard resource fails to load (#53675)
* Log console error when a dashboard resource fails to load

* Include the rejection reason in the resource load error
2026-08-17 10:04:51 +02:00
karwosts 8ab7c118a9 Fix custom weather icons (#53667) 2026-08-17 06:52:16 +02:00
karwosts 0eafb1f4b4 Add themes to yaml reload menu (#53673) 2026-08-17 06:03:12 +02:00
neyzandkarwosts 9a7722a02e Remove weather card pointer cursor when it has no action (#53654)
* Remove weather card pointer cursor when it has no action

* use hasAnyAction helper

---------

Co-authored-by: karwosts <[email protected]>
2026-08-16 09:38:05 -07:00
renovate[bot] 3e184eeb39 Update dependency @rspack/core to v2.1.10 (#53663)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-16 12:37:16 +02:00
renovate[bot] 61be4e2952 Update dependency @rsdoctor/rspack-plugin to v1.6.2 (#53662)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-16 12:13:08 +02:00
Paul Bottein 315cf97e56 Prevent the sidebar from scrolling the dashboard (#53644) 2026-08-16 06:27:47 +00:00
karwosts 771a8aa4c9 Fix negative button of duration selector (#53646) 2026-08-16 06:27:17 +00:00
G JohanssonandSimon Lamon d9aa649854 Remove deprecated battery props from vacuum (#53005)
Co-authored-by: Simon Lamon <[email protected]>
2026-08-16 06:26:54 +00:00
karwostsandSimon Lamon 7a087cd6d0 Ability to link a person to an existing user (#53550)
* Support linking a person to an existing user

* Don't delete preexisting user on cancel submit

* retry ci

* Don't show choice when no floating users exist

* collapse to single dialog

---------

Co-authored-by: Simon Lamon <[email protected]>
2026-08-16 06:25:03 +00:00
renovate[bot] 32a30468bb Update dependency globals to v17.10.0 (#53647)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-16 06:24:56 +00:00
karwosts 0ace3cedfb Add disabled to button group (#53651) 2026-08-16 06:24:33 +00:00
karwosts aba7478e26 Fix choose selector minor issues (#53648) 2026-08-16 06:24:28 +00:00
renovate[bot] c8b2e5160a Update dependency hls.js to v1.6.18 (#53649)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-16 06:21:52 +00:00
dependabot[bot] 4c46ca0918 Bump the codeql-action group across 1 directory with 2 updates (#53661)
Bumps the codeql-action group with 2 updates in the / directory: [github/codeql-action/init](https://github.com/github/codeql-action) and [github/codeql-action/analyze](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.37.4 to 4.37.6
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/f205ea1c3313d32999d8d6a48b4f6530d4437b38...5595ccaf912efad79be6eef63a5619ff05969be3)

Updates `github/codeql-action/analyze` from 4.37.4 to 4.37.6
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/f205ea1c3313d32999d8d6a48b4f6530d4437b38...5595ccaf912efad79be6eef63a5619ff05969be3)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-16 06:20:49 +00:00
Logan RosenandCopilot App 0483106f61 Restore bundle size budget headroom (#53659)
Co-authored-by: Copilot App <[email protected]>
2026-08-16 08:16:29 +02:00
Paul Bottein 7e0c572f69 Replace automation state color with a badge (#53627)
* Replace state color with a badge in automation picker

* Fix data table spacing and text truncation on mobile
2026-08-14 15:31:14 +02:00
renovate[bot] e4438a20cb Update dependency @rspack/core to v2.1.9 (#53642) 2026-08-14 14:13:06 +01:00
Aidan Timson ec418498a7 Make date picker navigation arrows themeable (#53639) 2026-08-14 16:05:46 +03:00
8122baca00 Add more deep links to more-info dialogs (#53628)
* Add deep links to more-info dialogs

* Fix

* Preserve existing URL hash in createMoreInfoUrl and removeMoreInfoUrl

Co-authored-by: timmo001 <[email protected]>

* Preserve explicit empty hash and move more-info restoration to app owner

Co-authored-by: timmo001 <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-08-14 16:02:58 +03:00
Paul Bottein 79738dd257 Add activity detail dialog (#53362)
* Add activity detail dialog

* Apply review fixes to activity detail dialog

* Resolve previous state from history in logbook detail dialog

* Disable text selection on clickable logbook rows

* Document run discovery as a fallback for missing context ids

* Scope the detail chain to the subject's cause path

* Replace clickable logbook rows with explicit detail affordances

* Show the cause badge on automation and integration rows

* Map scheduled and Home Assistant causes to their trigger icons

* Replace logbook detail affordances with full-width rows

* Frame the activity detail dialog with ha-grouped-list

* Add missing import

* Fix milliseconds placement in activity chain times
2026-08-14 15:57:03 +03:00
Bram Kragten f23c8f0e23 Fix sub device tree indicator (#53638) 2026-08-14 09:18:06 +01:00
Bram Kragten 91c28c2f58 Bumped version to 20260729.7 2026-08-14 09:59:26 +02:00
Paul Bottein 1f299d98e0 Fix clipped focus ring on media player playback buttons (#53632) 2026-08-14 09:58:33 +02:00
Petar Petrov a74926aef6 Fix sensor card graph footers not receiving hass on lazy upgrade (#53576) 2026-08-14 09:58:32 +02:00
Bram Kragten 437a4cedf9 Check for wheel on PyPI simple index instead of JSON API (#53549) 2026-08-14 09:58:31 +02:00
Bram Kragten 55913d7505 Fix panels missing updates (#53548) 2026-08-14 09:58:30 +02:00
Paulus SchoutsenandClaude 0bb654c70c Mock entity ID format WS commands in the demo (#53520)
Co-authored-by: Claude <[email protected]>
2026-08-14 09:58:30 +02:00
Petar Petrov f578cb0526 Guard registry lookups in the target picker item row (#53637) 2026-08-14 09:55:54 +02:00
renovate[bot] 78878897cc Update dependency typescript-eslint to v8.67.0 (#53634)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-14 06:46:42 +02:00
Petar PetrovandSimon Lamon 9472d8ad12 Add device context to energy individual device names (#53603)
Add device context to energy individual device labels

Co-authored-by: Simon Lamon <[email protected]>
2026-08-13 18:52:28 +02:00
Paul Bottein 94cbe4467b Lay out inline features in two columns (#53631)
* Lay out inline features in two columns

* Detect stacked features from the slot

* Rename tile container layout classes

* Rename the below features in the layout helper

* Keep area card features below at full width

* Stretch the area card features below the inline one

* Keep area card features compact outside the compact type

* Revert "Keep area card features compact outside the compact type"

This reverts commit 48268cb4e2.

* Reapply "Keep area card features compact outside the compact type"

This reverts commit e10bb27e2f.

* Keep the inline feature compact on condensed cards
2026-08-13 18:00:47 +03:00
Paul Bottein 043abb69af Keep control select in the tab order without a selection (#53633) 2026-08-13 15:54:59 +01:00
Paul Bottein b6b8fe641f Fix clipped focus ring on media player playback buttons (#53632) 2026-08-13 15:54:49 +01:00
Bram KragtenandClaude Opus 4.8 70bb08b101 Child devices UI (#53619)
* Add child devices UI

Surface child devices throughout the config UI so they read as first-class
devices nested under their parent:

- Device page: a "Sub-devices" card lists a device's children, and a child's
  page shows a "Part of <parent>" link (hardware/model/config-entry are
  already inherited from the parent by the registry resolver).
- Integration page: children are nested and indented under their parent
  device in the config-entry and subentry device lists.
- Device picker: children are ordered and indented under their parent with a
  tree connector, mirroring the area/floor picker.
- Naming: the device picker's secondary label and search now include the
  parent device name for children, so they stay identifiable in flat views.

Follow-up to the child devices data layer (#53617).

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Add child devices to demo and gallery mock data

A power strip parent with two outlet children in the demo device stubs and
the ha-selector gallery demo, so child device rendering (nesting, tree
indentation, parent-context naming, inherited area) can be exercised without
a running backend.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Refine child devices UI and target resolution

Follow-up polish so child devices behave like a normal device everywhere:

- Targets & filters: a parent device qualifies for and resolves to its
  children's entities (getDevices filter, deviceMeetsFilter,
  deviceMeetsTargetSelector, resolveEntityIDs and the target-chip "split into
  entities" expand), matching core's server-side target resolution. Selecting a
  parent excludes its children from the picker.
- Pickers: keep a parent visible when a child matches the search (device and
  target pickers), fix the target picker's nested order (unsorted search +
  recomputed last-child flag), and render the sub-device tree in the target
  picker's device group.
- Area/naming: the area field shows only the (inherited) area again; the parent
  name remains a search term.
- Integration page: correct the tree end connector and align it in narrow mode.
- A parent-disabled child can no longer be enabled from the settings dialog.
- Devices dashboard: show "Part of <parent>" under a sub-device's name and add a
  hidden-by-default, searchable and groupable Parent device column that groups a
  parent together with its children.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Address review on child devices UI

Align target resolution with core and fix picker/table details:

- Only a directly targeted device expands to its child devices. Labels are
  never inherited by children (core's target helper is explicit about this) and
  areas resolve by effective-area membership, so deviceMeetsFilter and
  deviceMeetsTargetSelector evaluate a device's own entities again.
- Add devicesInEffectiveArea, mirroring core's dr.async_entries_for_area: an
  area contains its devices plus children that inherit the area, but not a child
  with a different explicit area. Used for area expansion, area matching and the
  area chip's split action.
- Device picker: add a searchFn that restores the nested parent/child order
  after the fuzzy search and recomputes the last visible child, so a child can
  no longer be ranked above its parent and connectors stay correct.
- Devices dashboard: derive the family group name from the family's parent
  device with the same fallback for parents and children, so an unnamed parent
  cannot end up in a different group than its children.
- Child devices card: pass the device registry so a child shows its inherited
  area.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Fix formatting in device picker row renderer

Reindent the row renderer template after it gained a block body, so Prettier
is satisfied.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Make the child device tree connector span the full row

The connector was a fixed 48px box centred in a taller two-line row, and its
SVG was letterboxed by the default preserveAspectRatio, so the dashed line
stopped short of the row edges and consecutive children never visually
connected.

Let the indicator stretch (preserveAspectRatio="none") and give it the full row
height, so the line runs edge to edge with the elbow at the vertical centre.
non-scaling-stroke keeps the line width and dash pattern identical however far
it is stretched; existing 48x48 usages render unchanged.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

---------

Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-08-13 17:45:31 +03:00
JulianHockandClaude Opus 5 4259ddee24 Show remaining tile card features below when position is inline (#53310)
* Show remaining tile card features below when position is inline

Previously the tile card silently dropped every feature after the first
one when "features_position" was set to "inline". The first feature is
now rendered next to the name as before, and any additional features are
stacked underneath, the same way they are in "bottom" position.

The tile container gained a "features-bottom" slot for this, and the
card size and grid options now account for the extra rows.

* Add tests for hui-tile-card size and grid options calculations

* Enhance hui-tile-card to support inline feature layout and improve feature counting logic

* reduce vertical gap for inline features

---------

Co-authored-by: Claude Opus 5 <[email protected]>
2026-08-13 15:45:00 +02:00
6c5ac1ea84 Add background editor to dashboard detail editor (#51644)
* Setup

* Use same slot layout

* Fill tabs

* Move content rendering to dedicated function

* Self review

* Save dashboard details before background

Co-authored-by: timmo001 <[email protected]>

* Protect strategy dashboard config

* Apply dashboard background review fixes

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-08-13 16:27:34 +03:00
Petar Petrov 5224fa2048 Seed selector values when enabling optional service fields (#53629) 2026-08-13 15:27:07 +02:00
Bram KragtenandClaude Opus 4.8 22ca986cce Skip source maps in the gallery build for e2e (#53625)
The gallery build is the only e2e build that still emits source maps: unlike
demo and the e2e test app, `bundle.config.gallery` never accepted
`isTestBuild`, so the production build always used `nosources-source-map` —
even though the artifact is only ever loaded by Playwright.

The e2e run's gallery artifact contains 693 `.map` files (14 MB of a 105 MB
dist); the demo artifact, which already passes `is-test`, contains none.

Thread `isTestBuild` through the gallery config and set `is-test: true` for the
e2e gallery build, so those maps are no longer generated. The design
deployment and preview workflows do not set `IS_TEST`, so they keep their
source maps.

Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-08-13 13:11:23 +03:00
7f8bf69424 List running automations & scripts in restart dialog (#53523)
* List running automations & scripts in restart dialog

* Don't need a new dialog

* Update src/translations/en.json

Co-authored-by: Norbert Rittel <[email protected]>

* Show running automations in quick bar restart confirmation

---------

Co-authored-by: Petar Petrov <[email protected]>
Co-authored-by: Norbert Rittel <[email protected]>
2026-08-13 09:10:23 +00:00
Aidan Timson 92224411e1 Add context to entity details (#53624)
* Add context to entity details

* Include entity context in YAML details

* Remove category from entity details

* Only link integrations with config entries
2026-08-13 12:04:12 +03:00
b52d58eccb Always group updates page entities by integration (#53480)
* Always group updates page entities by integration

Every integration now gets its own card on the updates page, titled with
the integration name, even when it only has a single update entity. The
catch-all Integrations card is removed. The Update all button is only
shown for cards with more than one entity.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01DTuGyvS1i7w1B1xEGCEVhs

* Show update button on cards with a single update

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Paul Bottein <[email protected]>
2026-08-13 08:59:25 +00:00
Bram KragtenandClaude Opus 4.8 a9cc47888a Add child devices to the device registry (#53617)
* Add child devices to the device registry

Child devices arrive over the WebSocket as stripped entries in the flat
config/device_registry/list response (discriminated by the absence of
full-device fields). Resolve them into complete DeviceRegistryEntry
objects at ingestion so hass.devices only ever holds full entries and the
~200 downstream consumers stay unchanged:

- config-entry association comes from the child's own config_entry_id, so
  children still appear under their integration;
- hardware/display fields are inherited from the parent device;
- connections/via_device_id are not inherited.

Adds parent_device_id and the new "device" disabled_by value to the types.

Frontend data layer for home-assistant/core#178666.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Resolve child device effective area in the UI

A child device without an area of its own inherits its parent's area,
mirroring core's async_get_effective_area_id. getDeviceArea now takes the
devices map and falls back to the parent, so children show in the parent's
area everywhere a normal device would: the device dashboard (area column,
grouping and filtering via computeDeviceAreaLabel) and the device page
header.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Address review on child devices data layer

- Discriminate stripped child entries on `connections` (present on every full
  device, never on a stripped child) instead of the deprecated `config_entries`
  compatibility field that core plans to remove.
- Make getDeviceArea's `devices` argument required and update all callers, so a
  child device's effective (inherited) area is resolved consistently everywhere,
  including the device picker's selected-value renderer and the integration
  device rows.
- Lock the enable switch in the device settings dialog when a device is disabled
  by its parent (disabled_by "device"); core ignores enabling a child while its
  parent is disabled.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Inherit the parent device area when resolving entity areas

Extract getDeviceAreaId so an entity on a child device resolves to the child's
effective area (the parent's area when the child has none), matching core's
entity area resolution. Applies to both getEntityAreaId and
getEntityEntryContext, which previously read device.area_id directly.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

---------

Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-08-13 11:57:28 +03:00
Paul Bottein ea0ceecbfc Add ha-grouped-list component (#53618) 2026-08-13 08:47:14 +01:00
Bram KragtenandClaude Opus 4.8 5f007a1575 Run the frontend build in parallel with lint and tests (#53623)
* Run the frontend build in parallel with lint and tests

The build job waited for lint and test because a full build was expensive
enough that we did not want to spend it on a PR that fails its checks. With
the rspack persistent cache it now takes ~3 min instead of ~5, and it is the
longest job in the run, so serialising it behind the others dominates CI
wall-clock: 8s + max(lint 86s, test 123s) + build 194s.

Depend only on prepare-dependencies so all three run together, which brings a
successful run down from ~5.5 min to ~3.5 min — the build itself becomes the
floor.

To avoid finishing an expensive build for a PR that is already broken, each of
the three jobs cancels the whole run when it fails. The cancel step needs
`actions: write`; on pull requests from forks the token stays read-only, so it
is a no-op there and the jobs just run to completion.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Keep the Actions write scope away from pull request code

The cancellation needed `actions: write`, and granting it at workflow scope
handed it to every job — including the ones that check out the pull request
and pass GITHUB_TOKEN into the gulp build, so PR-controlled code (or a
compromised dependency) would have had write access to Actions.

Move the cancellation into its own job that holds `actions: write` on its own
and never checks out the repository, so the elevated token is never exposed to
PR code. It cannot simply `needs` the checks — a dependent job only starts once
they have all finished, which is too late to cancel anything — so it polls the
run's job statuses and cancels on the first failure.

Costs one extra (idle) runner slot for the duration of the run.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

---------

Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-08-13 08:48:24 +03:00
Bram Kragten f360a22927 Wait for analytics data during onboarding (#53621) 2026-08-13 06:56:16 +02:00
Paul Bottein a67111e41f Render state and numeric state entities as row targets (#53610)
* Render state and numeric state entities as row targets

* Add tests for entity-less trigger and condition descriptions
2026-08-13 06:53:44 +02:00
Bram KragtenandClaude Opus 4.8 4b7d3a7e4f Add rspack persistent cache (nightly writes, CI reads) (#53611)
Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-08-12 22:30:42 +02:00
Petar Petrov 88be7adafa Stop number box rows from reserving unused space (#53614) 2026-08-12 14:42:09 +01:00
Paul Bottein 91a6d737b3 Fix row target badge height and font (#53612) 2026-08-12 10:17:08 +01:00
Petar Petrov 22c3a6fe67 Don't trim the selected value in pickers (#53613) 2026-08-12 10:16:39 +01:00
Petar Petrov bcc799970a Fix lowercase view button in blueprint in-use dialog (#53609) 2026-08-12 09:55:34 +01:00
Petar Petrov 31d4a37c15 Fix time condition summary when before is midnight (#53608) 2026-08-12 09:51:51 +01:00
Paul Bottein 49ea96e091 Add icon button group animation (#53597)
* Animate the selected toggle circle in ha-icon-button-group

* Round the light color wheels to fit the selected ring

* Use lit motion
2026-08-12 10:19:07 +03:00
Bram KragtenandClaude Opus 4.8 08b33ccbc1 Decouple translations artifact from the nightly build (#53602)
* Skip backend translations download in nightly build

The nightly only builds the app (build-app), which does not merge backend
translations — the shipped app fetches those from core at runtime. The
backend Lokalise export is a whole-project download across all languages
and the slowest part of the translations step. Skipping it, as the release
already does, cuts several minutes off every nightly.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Decouple translations artifact into a parallel job

The full translations (including the slow Lokalise backend/core export) are
only needed for the uploaded `translations` artifact, not the wheel:
build-app does not merge backend translations. Move that download and the
artifact upload into a separate `translations` job that runs in parallel
with the build, so the backend export no longer sits on the build's
critical path. Both jobs run in the same workflow run, so consumers still
find both the `wheels` and `translations` artifacts.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

---------

Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-08-11 20:48:38 +02:00
Aidan Timson 048e754149 Match tokens card actions position and size of button with others (#53605) 2026-08-11 18:22:19 +02:00
Aidan Timson 3a30ea5973 Fix loading states for async config pages (#53604) 2026-08-11 15:32:53 +02:00
Aidan Timson f7836fd3d5 Show loading screen while Labs features load (#53601) 2026-08-11 16:11:04 +03:00
Paul Bottein 03d8c092ce Render the target picker entities count as a button (#53598)
* Implement the xs button size

* Render the target picker entities count as a button
2026-08-11 15:40:14 +03:00
Aidan Timson b3aa3c83d5 Change area navigation to icon button in device page (#53600)
* Add area navigation button to device page

* Remove area button tooltip
2026-08-11 15:00:00 +03:00
Bram KragtenandClaude Opus 4.8 85c7d071fe Recover from a stale build after boot (#53582)
* Recover from a stale build after boot (lazy-chunk 404s)

When the app stays open across a Home Assistant upgrade, the previous
build's content-hashed lazy chunks are deleted, so opening a dialog,
more-info, card, or panel that was not yet loaded 404s. Today that
dead-ends: dialogs fail silently, panels show a Back-only error screen.

Add a shared recovery authority (recover-stale-build.ts): detect a stale
hashed-chunk load failure and either reload onto the current build (drop
the service worker + caches, cache-busting nav, one-shot cooldown guard)
or, when an editor has unsaved changes, show a non-dismissable toast that
reloads once the dirty state clears. Hook it into the global
error/unhandledrejection handlers, the router's swallowed load error, and
give hass-error-screen a reload action. Chunk-error patterns come from a
JSON single source shared with the boot guard.

Part of home-assistant/epics#113.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Wire stale-build recovery into more paths, add tests

- make-dialog-manager: don't cache a rejected dialog import, so a stale
  chunk 404 (or transient failure) no longer permanently breaks that
  dialog until a full page reload — a later open re-imports.
- home-assistant: _checkUpdate now uses reloadFresh() instead of the
  no-longer-effective location.reload(true) (forceGet is ignored by
  modern browsers).
- connection-mixin: drop the dead reload(true) forceGet arg on the
  safe_mode reload.
- Add unit tests for isStaleBuildError and the recoverFromStaleBuild
  clean / dirty / dev-demo / non-stale / loop-guard branches.

Part of home-assistant/epics#113.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Recover in the companion app via the reload_and_clear_cache command

The iOS/Android companion app (WKWebView) has no service worker, and its
document HTTP cache is not cleared by the Cache API, so the web-level
reload path is ineffective there. When an external bus is present,
reloadFresh() now fires the native `frontend/reload_and_clear_cache`
command (shipped in home-assistant/iOS#5190) so the app purges its cache
and reloads; browsers still take the web path.

Adds the outgoing message type and extracts the bus transport into an
exported fireExternalBusMessage() so it can be sent without a hass/bus
reference.

Closes #53405. Part of home-assistant/epics#113.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Address Copilot review feedback

- reloadFresh: only send frontend/reload_and_clear_cache to the WebKit
  (iOS) bridge; Android and browsers take the service-worker + cache-clear
  path (Android's WebView has a service worker). Fail closed when the
  sessionStorage cooldown marker can't be persisted so it can't loop. Return
  whether a reload was actually started, so a guard-blocked failure is still
  surfaced/logged instead of silently swallowed.
- Add a dirty-aware reloadForUpdate() and route _checkUpdate and the error
  screen's Refresh button through it; drop the dirty toast's immediate
  action (it auto-reloads once changes are saved/discarded).
- Set showReload on the error-screen element at the call site so router
  overrides (e.g. ToolsRouter) can't drop it.
- Tests: exercise the WebKit bridge and the SW/cache-clear branch; assert
  the dirty toast has no reload action.

Part of home-assistant/epics#113.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

---------

Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-08-11 13:37:44 +02:00
Aidan Timson 6fe34bbf7e Add device link to Bluetooth advertisement dialog (#53599) 2026-08-11 14:27:06 +03:00
Aidan Timson 5291a84c87 Align highlighted config entries to the top (#53595)
* Align highlighted config entries to the top

* Apply suggestion from @timmo001
2026-08-11 10:54:58 +00:00
Paul Bottein c0575fcb42 Unify back navigation across subpages (#53501)
* Unify back navigation across subpages

* Address back navigation review findings

* Fix state

* Add missing back path

* Remove back path from editors to fix unsaved changes prompt

* Use more specific back fallback paths
2026-08-11 10:39:38 +00:00
Dennis BergmannandPetar Petrov ea98a85088 Reserve scrollbar gutter in more-info dialog to prevent flicker (#53522)
* Reserve scrollbar gutter in more-info dialog to prevent flicker

* Update src/dialogs/more-info/ha-more-info-dialog.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-08-11 10:33:12 +00:00
Bram Kragten a1370e331f Replace remove device command (#53594) 2026-08-11 11:22:28 +02:00
pcan08 75e862540f Add light-effect tile card feature and related suggestion (#53589) 2026-08-11 08:52:15 +02:00
Petar Petrov fd0fdb37fe Fix history graphs redrawing with a different shape every few seconds (#53578)
Anchor history graph downsampling to absolute time
2026-08-11 08:48:28 +02:00
renovate[bot] 4893e65841 Update dependency eslint to v10.8.1 (#53591)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-11 08:05:37 +03:00
renovate[bot] 38946ad69d Update dependency @types/luxon to v3.7.4 (#53588)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-10 22:27:59 +02:00
pcan08 c0b296a5a2 Add vacuum-fan-speed tile card feature and add related tile suggestions (#53551)
* Add vacuum-fan-speed tile card feature and add related tile suggestions

* Remove multi feature suggestion
2026-08-10 19:45:02 +02:00
Bram Kragten 8b9cf84ee8 Dont ship unused old translation keys (#53583)
* dont ship unused old translation keys

* avoid prototype pollution
2026-08-10 15:32:09 +02:00
Bram Kragten c61622de43 Dont download core translations when releasing app (#53585)
dont download core translations when releasing app
2026-08-10 15:31:18 +02:00
Bram Kragten affce99c9b Cache compression output across builds to speed up releases (#53561) 2026-08-10 13:35:32 +02:00
karwosts 22993a9d0a Fix areas/floors reorder config page (#53553) 2026-08-10 10:31:09 +01:00
Yosi Levy 89b7ff694d Fix ha-selector-number (#53577) 2026-08-10 10:29:54 +02:00
Petar Petrov 5a7c2ac175 Fix sensor card graph footers not receiving hass on lazy upgrade (#53576) 2026-08-10 08:57:12 +01:00
Yosi Levy 6e007c8c9a Fix date display in logs (#53575) 2026-08-10 08:46:13 +01:00
Bram Kragten a0969d0b08 Fix panels missing updates (#53548) 2026-08-10 08:36:49 +01:00
dependabot[bot] 070251f360 Bump pypa/gh-action-pypi-publish from 1.14.1 to 1.14.2 (#53568)
Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.14.1 to 1.14.2.
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/ba38be9e461d3875417946c167d0b5f3d385a247...dc37677b2e1c63e2034f94d8a5b11f265b73ba33)

---
updated-dependencies:
- dependency-name: pypa/gh-action-pypi-publish
  dependency-version: 1.14.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-09 10:43:57 +02:00
dependabot[bot] 11d38fcd6a Bump home-assistant/actions/helpers/verify-version from ab22029681aa532bfe7de5774a9972d67bfbd2c0 to a7c616ce81ccda50150bf1595786c71b1883fabb (#53566)
Bump home-assistant/actions/helpers/verify-version

Bumps [home-assistant/actions/helpers/verify-version](https://github.com/home-assistant/actions) from ab22029681aa532bfe7de5774a9972d67bfbd2c0 to a7c616ce81ccda50150bf1595786c71b1883fabb.
- [Release notes](https://github.com/home-assistant/actions/releases)
- [Commits](https://github.com/home-assistant/actions/compare/ab22029681aa532bfe7de5774a9972d67bfbd2c0...a7c616ce81ccda50150bf1595786c71b1883fabb)

---
updated-dependencies:
- dependency-name: home-assistant/actions/helpers/verify-version
  dependency-version: a7c616ce81ccda50150bf1595786c71b1883fabb
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-09 10:43:36 +02:00
dependabot[bot] ce6da0c03d Bump actions/stale from 10.4.0 to 11.0.0 (#53569)
Bumps [actions/stale](https://github.com/actions/stale) from 10.4.0 to 11.0.0.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/1e223db275d687790206a7acac4d1a11bd6fe629...4391f3da665fdf50b6810c1a66712fb9ba21aa93)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: 11.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-09 10:43:34 +02:00
dependabot[bot] 011af7c8ea Bump release-drafter/release-drafter from 7.6.0 to 7.7.0 (#53567)
Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 7.6.0 to 7.7.0.
- [Release notes](https://github.com/release-drafter/release-drafter/releases)
- [Commits](https://github.com/release-drafter/release-drafter/compare/eada3c96a64734dd381cfbda23511034e328ddb0...34d80673e067bdc0c24568d3af899c216adcfaa9)

---
updated-dependencies:
- dependency-name: release-drafter/release-drafter
  dependency-version: 7.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-09 10:43:26 +02:00
dependabot[bot] 94aa373387 Bump the codeql-action group across 1 directory with 2 updates (#53565)
Bumps the codeql-action group with 2 updates in the / directory: [github/codeql-action/init](https://github.com/github/codeql-action) and [github/codeql-action/analyze](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.37.3 to 4.37.4
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81...f205ea1c3313d32999d8d6a48b4f6530d4437b38)

Updates `github/codeql-action/analyze` from 4.37.3 to 4.37.4
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81...f205ea1c3313d32999d8d6a48b4f6530d4437b38)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-09 10:43:19 +02:00
Aura Herrero Ruiz c5bfbd7478 Fix camera domain "recording" state not being considered an active state (#53546)
* Correct stateActive for camera domain

* Use list of active states for camera domain
2026-08-08 18:32:52 +02:00
renovate[bot] 72fc9c7278 Update dependency hls.js to v1.6.17 (#53562)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-08 16:13:16 +00:00
Petar Petrov 79cf8b0f04 Add initial value setting to input_boolean helper dialog (#53516)
* Add initial value setting to input_boolean helper dialog

* Move toggle initial value into More options and clarify wording

* Move toggle initial value hint into an info tooltip
2026-08-08 18:02:40 +02:00
renovate[bot] 4a8fca8bb8 Update dependency @codemirror/view to v6.43.8 (#53556)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-08 12:46:29 +02:00
renovate[bot] 6a18686b1c Update dependency core-js to v3.50.0 (#53557)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-08 12:46:18 +02:00
Bram Kragten f456bd7dc6 Check for wheel on PyPI simple index instead of JSON API (#53549) 2026-08-07 20:59:18 +02:00
Bram Kragten 235541748b Bumped version to 20260729.6 2026-08-07 16:30:37 +02:00
Paul Bottein 6bd1d698ce Fix disabled save button when leaving an automation with unsaved changes (#53538) 2026-08-07 16:27:35 +02:00
Bram Kragten 18862b868f Wait with showing pending http changes dialog until loading screen is… (#53534)
* Wait with showing pending http changes dialog until loading screen is gone

* fix timing
2026-08-07 16:27:33 +02:00
Bram Kragten 662d817a5e Fix link to different port being handled as internal link (#53530) 2026-08-07 16:27:32 +02:00
Aidan Timson 7412ab5578 Remove "dev" from tools actions description (#53528)
* Remove "dev" from tools actions description

* Clarify vt is browser developer tools
2026-08-07 16:27:31 +02:00
Krisjanis Lejejs b2be0bd673 Remove cloud demo controls (#53524) 2026-08-07 16:27:30 +02:00
Bram Kragten a141432546 Don't disable interaction when row is disabled (#53517)
dont disable interaction when row is disabled
2026-08-07 16:27:29 +02:00
Paul Bottein cd50531b67 Stack the sidebar when only one column fits (#53515) 2026-08-07 16:27:29 +02:00
Petar Petrov f7438f4d0e Accept hostnames and localize validation messages in the HTTP config form (#53511)
Accept hostnames in HTTP config listen addresses and localize number validation
2026-08-07 16:27:28 +02:00
Petar Petrov a7fabb8a8c Only show the sidebar tab switcher when its tabs are labelled (#53508) 2026-08-07 16:26:46 +02:00
Aidan Timson 9dab55f39a Fix notification stacking (#53486)
* Stack notifications independently

* Preserve identified notifications on legacy close

* Preserve updated notifications during close

* Fix notification stack positioning

* Update src/managers/notification-manager.ts

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
(cherry picked from commit d03ba15c09)

# Conflicts:
#	test/panels/config/script/script-paste.test.ts
2026-08-07 16:23:38 +02:00
Paul Bottein 78a2d4d6df Fix disabled save button when leaving an automation with unsaved changes (#53538) 2026-08-07 13:40:00 +00:00
renovate[bot] 0f8d7b4d41 Update dependency @rspack/core to v2.1.8 (#53547)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-07 16:27:32 +03:00
renovate[bot] cf3009f408 Update dependency marked to v18.0.9 (#53544)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-07 16:26:21 +03:00
renovate[bot] bdf629f836 Update dependency typescript-eslint to v8.66.0 (#53541)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-07 05:18:39 +00:00
Krisjanis Lejejs 464b58af04 Add cloud page UI to the Gallery (#53532)
Add cloud page UI to the design
2026-08-06 17:03:08 +02:00
Bram Kragten 29a75209ac Wait with showing pending http changes dialog until loading screen is… (#53534)
* Wait with showing pending http changes dialog until loading screen is gone

* fix timing
2026-08-06 17:12:08 +03:00
Petar Petrov f89b3c23c7 Keep selected option visible in disabled select box (#53535) 2026-08-06 15:02:41 +01:00
Bram Kragten 29b631b960 Fix link to different port being handled as internal link (#53530) 2026-08-06 15:43:44 +02:00
renovate[bot] dd94a7bac1 Update dependency @rspack/dev-server to v2.2.0 (#53529) 2026-08-06 14:19:01 +01:00
Aidan Timson 34154195c8 Remove "dev" from tools actions description (#53528)
* Remove "dev" from tools actions description

* Clarify vt is browser developer tools
2026-08-06 14:53:54 +02:00
0b34fcb559 Show target-state entity icon in scene editor review mode (#52520)
* Show target-state entity icon in scene editor review mode

Render the entity badge in review mode (previously live-only) across both
the device-grouped and standalone entity lists. In review mode the badge
uses the scene's stored target state instead of the entity's live state, so
the icon previews what the scene will set once applied.

* Strip stale entity_picture from the synthesized review-mode state

state-badge hides the icon and renders a background image whenever a state
carries an entity_picture (see its willUpdate). A scene snapshots that URL
with an access token that is stale by the time review mode renders, so an
image-backed entity - for example a robot vacuum's "Map data" camera entity
on its device - showed a blank badge in review mode instead of an icon.

Drop entity_picture / entity_picture_local from the synthesized state so the
entity's own icon resolves. This is not a pre-existing defect: it handles a
case that rendering the badge in review mode (previous commit) introduces.

* Handle null and scalar scene entity values in review mode badges

An entity left without a value in the YAML editor parses as null, which
crashed the review-mode render. The scene config API also returns raw
scenes.yaml content without validation, so hand-edited scenes deliver
boolean states as-is (YAML 1.1 parses unquoted on/off as booleans);
these previously rendered as if the entity had no state at all.

Booleans map to on/off to match how the backend applies them when a
scene is activated (_convert_states in the homeassistant scene
platform). The backend rejects null and numeric states at save, but
review mode renders before save, so the frontend has to tolerate them.

* Extract and memoize the scene target-state synthesis

The editor re-renders on every hass change, and building a fresh state
object per row each time defeated Lit dirty-checking: every state-badge
re-ran willUpdate and every ha-state-icon restarted its async icon
resolution. Memoizing the synthesized objects per config keeps the
references stable so unchanged badges skip all of that.

Moving the synthesis to src/data/scene.ts makes it unit-testable; the
null, boolean, numeric, string, and picture-stripping cases are now
covered by tests.

* Sanitize brightness and rgb_color in the synthesized review-mode state

state-badge does arithmetic on brightness and joins rgb_color, assuming
backend-shaped values. Hand-typed YAML can hold both as strings: a
string rgb_color threw a TypeError that left the badge blank, and a
string brightness computed a brightness(36049%) filter that washed the
icon out to invisible. Coerce numeric-string brightness and drop
malformed values so the badge always renders the target state.

* Borrow the live device_class for review-mode badge icons

Icon resolution keys on device_class, which string-shorthand and
hand-written minimal scene entries do not carry, so a garage cover fell
back to the generic window icon and sensors to the domain default. Only
this identity attribute is borrowed from the live state - merging
stateful attributes like rgb_color would mis-color an off target.

* Reject unusable scene targets and trim the badge-state synthesis

Review-mode badges now render only when the scene holds a usable
target state. Entries with no state to show - null values, dicts
without a state key, arrays, non-scalar states - yield no badge
instead of falling back to the live state, which was
indistinguishable from a real target and, for dicts without a state,
crashed state-badge via stateColorCss on lights.

rgb_color and brightness are dropped from inactive targets: a live
entity never carries them while off, and state-badge applies them
without checking activity, so a scene turning a light off rendered an
active-looking colored icon.

Entity pictures are stripped only for DOMAINS_WITH_DYNAMIC_PICTURE,
matching createHistoricState in the logbook; stable pictures on other
domains are kept.

The brightness/rgb_color type coercion and the live device_class
borrowing are removed: they defended against hand-typed shapes that
state-badge already warns about, and the borrowing made the memoized
synthesis depend on hass state outside its memoize key.

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Przemysław Szypowicz <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-08-06 11:37:39 +00:00
Aidan Timson ea5a1bca99 Add onboarding end-to-end test (#53514)
* Add onboarding end-to-end test

* Reuse onboarding test data

* Fix onboarding E2E server routing

* Test onboarding through authenticated dashboard
2026-08-06 14:04:44 +03:00
Aura Herrero RuizandPetar Petrov 7ae5dafc95 Map card scale ruler (#53494)
* Scale ruler option for map card

* Only show ruler for the unit system configured

* Move attribution when ruler is in the same corner

* Match ruler style with the map and HA

* Update map card gallery page with the scale ruler options

* Use "UNIT_KM" to set the ruler's unit system

* Remove position option in favor of a boolean for only the bottom-left position

* Add dark mode theme to scale ruler

* Fix scale ruler style not respecting theme_mode

* Make the map card scale ruler react to config changes

Redraw the control from update() so toggling the option or changing the
unit system takes effect without a reload, and hold the themed colors in
custom properties so the forced light/dark rules no longer duplicate the
token values.

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-08-06 10:15:39 +00:00
Abílio Costa 52cc65cbfc Delay camera cleanup when hidden (#53518) 2026-08-06 09:35:07 +01:00
Paul Bottein f36330274d Stack the sidebar when only one column fits (#53515) 2026-08-06 11:26:19 +03:00
renovate[bot] a4912d0706 Update dependency globals to v17.9.0 (#53519) 2026-08-06 09:02:18 +01:00
Krisjanis Lejejs 3900a804f0 Remove cloud demo controls (#53524) 2026-08-06 02:42:29 -04:00
Paulus SchoutsenandClaude cd5dfdb86f Mock entity ID format WS commands in the demo (#53520)
Co-authored-by: Claude <[email protected]>
2026-08-05 19:00:40 +00:00
Bram Kragten a602865117 Don't disable interaction when row is disabled (#53517)
dont disable interaction when row is disabled
2026-08-05 17:31:21 +02:00
Petar Petrov f42a5012a9 Accept hostnames and localize validation messages in the HTTP config form (#53511)
Accept hostnames in HTTP config listen addresses and localize number validation
2026-08-05 12:52:52 +02:00
Petar Petrov 90f5c7a349 Only show the sidebar tab switcher when its tabs are labelled (#53508) 2026-08-05 12:31:15 +02:00
Aidan TimsonandPetar Petrov d03ba15c09 Fix notification stacking (#53486)
* Stack notifications independently

* Preserve identified notifications on legacy close

* Preserve updated notifications during close

* Fix notification stack positioning

* Update src/managers/notification-manager.ts

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-08-05 11:54:11 +03:00
Bram Kragten 7ac98b7fdd Bumped version to 20260729.5 2026-08-05 09:56:45 +02:00
karwosts 5c1c92e8ca Fix missing label in solar forecast dialog (#53506) 2026-08-05 09:56:31 +02:00
Paul Bottein bf9765d557 Fix back navigation loop on the cloud page (#53497) 2026-08-05 09:56:30 +02:00
Petar Petrov b013b1f929 Keep numeric slider and buttons within min and max when the step overshoots (#53489)
* Clamp numeric controls after snapping to the step

* Cover the pointer path, display and arrow keys at the bounds
2026-08-05 09:53:55 +02:00
Petar Petrov 8026a59e70 Fix wrong month in date picker calendar header (#53453) 2026-08-05 09:50:37 +02:00
Petar Petrov 7143acc860 Remove orphaned for_you translation key (#53509) 2026-08-05 08:30:11 +01:00
Aidan Timson c9c46d4507 Use typed gallery demo card configs (#53492) 2026-08-05 08:26:51 +01:00
5916775745 Wait for Integrations panel readiness (#53481)
* Wait for Integrations panel readiness

* Consolidate panel readiness tests

* Address panel readiness review feedback

Co-authored-by: timmo001 <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-08-05 08:44:16 +03:00
pcan08 52ee78d8a2 Add support for climate in target humidity feature (#53502)
* Add target humidity feature to climate entity

* Use target_humidity_step if any instead of fixed step

* Add target humidity for climate in suggestd tile card
2026-08-05 08:30:45 +03:00
146a089044 Type configuration event handlers (#53460)
* Type configuration event handlers

* Fix event handler element typings

Co-authored-by: timmo001 <[email protected]>

* Fix Prettier formatting in zha-options-page.ts and zwave_js-custom-param.ts

Co-authored-by: timmo001 <[email protected]>

* Correction

Co-authored-by: Petar Petrov <[email protected]>

* Correction

Co-authored-by: Petar Petrov <[email protected]>

* Fix TS cast and formatting in dialog-energy-grid-settings

Co-authored-by: timmo001 <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-08-05 08:23:14 +03:00
Paul Bottein 8c566b43b6 Compress faster by running brotli in parallel (#53495) 2026-08-05 08:19:30 +03:00
larryandClaude Opus 5 1089c5d1c5 Fix missing Internet heading in Home Assistant URL settings (#53498)
fix(config): always show the Internet URL heading

The "Internet" heading above the external URL field is rendered
inside a `hasCloud` conditional, so only users logged in to Home
Assistant Cloud ever see it. Everyone else gets an unlabeled URL
input, while the "Local network" heading below it always renders.
That leaves the local heading as the only label on the card, and it
sits below the external field, so the external field reads as though
it belongs to the local section.

Move the heading out of the conditional so it renders for every
user, leaving `hasCloud` to gate only the "Use Home Assistant Cloud"
toggle. The external section now has the same structure as the local
one: a heading followed by its list item.

The label was shown to non-Cloud users before #22379, inline beside
the field rather than as a heading. That PR converted both labels to
headings, kept the Cloud branch and dropped the non-Cloud one.


Claude-Session: https://claude.ai/code/session_01GQCiHCdQ4p3cPxXG6XNAa9

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-08-05 08:16:35 +03:00
Petar Petrov 2894113033 Keep numeric slider and buttons within min and max when the step overshoots (#53489)
* Clamp numeric controls after snapping to the step

* Cover the pointer path, display and arrow keys at the bounds
2026-08-05 08:02:58 +03:00
Petar Petrov b9bbef3bfc Add expand_legend option to energy graph cards (#53476) 2026-08-05 08:02:28 +03:00
Paul Bottein 706382cb68 Fix back navigation loop on the cloud page (#53497) 2026-08-05 06:50:34 +02:00
karwosts cc17921c22 Fix missing label in solar forecast dialog (#53506) 2026-08-05 06:49:42 +02:00
renovate[bot] b5ef563b71 Update octokit monorepo (#53505)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-05 06:43:34 +02:00
Petar Petrov 1b6e150def Remove dead UV_THREADPOOL_SIZE assignment from gulpfile (#53490)
gulpfile.js set process.env.UV_THREADPOOL_SIZE, but gulp's CLI loads the
gulpfile through liftoff, which does async fs work first. libuv has already
sized its threadpool to the default 4 by then, so the assignment never took
effect. Measured through the gulp CLI, effective threadpool size is 3.4 both
with and without the line, and only reaches 6.9 when the variable comes from
the environment.

Hoisting it earlier cannot fix it either, since the pool is sized before any
line of gulpfile.js runs, and setting it for real measurably changes nothing.
Remove it rather than plumb the variable through the build.
2026-08-04 15:52:42 +02:00
Petar Petrov 939b7012e2 Fix wrong month in date picker calendar header (#53453) 2026-08-04 15:37:00 +02:00
Paulus Schoutsen 488d3d9b37 Revert "Show the automation state on mobile in the automations table" (#53493) 2026-08-04 15:25:41 +02:00
Petar Petrov 08dedc415f Compress faster by running zopfli in a worker pool (#53488)
Compress with zopfli in a worker pool

compress-app gzips every build artifact with zopfli, but @gfx/zopfli is
synchronous WASM: it ran on the main thread, pinned a single core and blocked
the event loop for the whole step, so it dominated the production build.

Replace gulp-zopfli-green with an equivalent gulp transform that runs the same
compressor in a pool of worker_threads sized to availableParallelism(). The
compressed output is byte-identical, and @gfx/zopfli is no longer loaded on the
main thread of every gulp invocation.

On a 12-core machine compress-app drops from 6.98 min to 1.27 min, and the full
production build from 8.87 min to 3.32 min.
2026-08-04 15:11:45 +02:00
karwosts 400bf78ce0 Color icons for "on" automations in automation-picker (#53360)
colorize active icons in automation-picker
2026-08-04 15:46:14 +03:00
Przemysław SzypowiczandPrzemysław Szypowicz 9b2093125e Fix unreachable remove button on input chips with long labels (#53487)
Truncate long input chip labels

A chip with a long label, like an SSH public key in an add-on config
list option, grew past its container so the trailing remove button
ended up outside the visible area and could not be clicked. Cap the
chip at the container width so the built-in label ellipsis applies,
and show the full value as a native tooltip in the select selector.

Co-authored-by: Przemysław Szypowicz <[email protected]>
2026-08-04 15:42:35 +03:00
Bram Kragten ffa7cf17a6 Bumped version to 20260729.4 2026-08-04 13:19:17 +02:00
karwosts 5a5cec9060 Fix slow loading of entity rows in device page (#53471)
Fix lazy loading of entity rows in device page
2026-08-04 12:50:36 +02:00
Petar Petrov bb962ba3d8 Fix energy default period being saved under the wrong storage key (#53462) 2026-08-04 12:50:35 +02:00
Matthias AlphartandClaude Opus 5 d4a59ff1c7 Drop websocket collections created by an iframe panel on teardown (#53448)
* Drop websocket collections created by an iframe panel on teardown

`getCollection()` caches collections (entity registry, label registry, ...) on
the `Connection` object. A custom panel embedded in an iframe shares the
connection with the main window, so a collection the panel is the first to
request is created inside the iframe's realm.

When the user leaves the panel, `ha-panel-custom` removes the iframe and that
realm is destroyed - but the collection stays cached on the connection. Its
store, and the `setTimeout` that hands the cached state to new subscribers, are
gone, so every later subscriber waits forever for a callback that can never
fire. Since the registries moved to `LazyContextProvider` they are subscribed
on demand, which makes an iframe panel the first requester far more often: the
KNX panel's entity table renders empty after leaving and re-entering it, and
the main frontend can inherit the same dead cache.

Clean up from the iframe's own `pagehide` handler, while the realm is still
alive - `disconnectedCallback` on `ha-panel-custom` runs after the browsing
context is discarded, when `contentWindow` is already `null`.

Co-Authored-By: Claude Opus 5 <[email protected]>

* Use unknown instead of any in the CachedCollection shape

The helper never inspects the subscribed state, so the parameter type only
needs to be a placeholder.

Co-Authored-By: Claude Opus 5 <[email protected]>

---------

Co-authored-by: Claude Opus 5 <[email protected]>
2026-08-04 12:50:34 +02:00
karwosts f496d842a6 Allow to favorite the manual card (#53445) 2026-08-04 12:50:33 +02:00
Petar Petrov c14d07c845 Stop the statistics graph card editor looping while typing a name (#53434) 2026-08-04 12:50:32 +02:00
Petar Petrov 8a1f2e86bd Show progress on the Zigbee backup button while the backup is created (#53422) 2026-08-04 12:49:55 +02:00
renovate[bot] c0d963747a Update dependency @types/luxon to v3.7.3 (#53484)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-04 13:14:02 +03:00
Paul Bottein 1bcd43fb75 Add form divider between actions in interaction editor (#53483) 2026-08-04 11:55:07 +02:00
ce5925388c Add frontend review guidance (#53482)
* Add frontend review guidance

* Simplify frontend review skill routing

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-08-04 09:00:22 +00:00
jeffdunnandClaude Fable 5 088f72fcc4 Fix map loading fully zoomed out when fitted before layout (#53428)
Leaflet computes the zoom level that fits a set of bounds from the current
size of the map container. When ha-map's fit runs before the browser has
laid out the container (a race that hits when the Leaflet chunks are
already cached), the container measures 0x0, the computed zoom collapses
to the minimum, and the map shows the entire world. The later
invalidateSize() from the resize observer fixes the size but keeps the
zoom, so the map stays on the world view.

Defer fitting while the container has no size and run the pending fit
once the resize observer reports a usable size.

Co-authored-by: Claude Fable 5 <[email protected]>
2026-08-04 06:52:29 +00:00
renovate[bot] b93f09ffb2 Update dependency js-yaml to v5.2.3 (#53478)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-04 09:46:52 +03:00
Matthias AlphartandClaude Opus 5 fb499093e5 Drop websocket collections created by an iframe panel on teardown (#53448)
* Drop websocket collections created by an iframe panel on teardown

`getCollection()` caches collections (entity registry, label registry, ...) on
the `Connection` object. A custom panel embedded in an iframe shares the
connection with the main window, so a collection the panel is the first to
request is created inside the iframe's realm.

When the user leaves the panel, `ha-panel-custom` removes the iframe and that
realm is destroyed - but the collection stays cached on the connection. Its
store, and the `setTimeout` that hands the cached state to new subscribers, are
gone, so every later subscriber waits forever for a callback that can never
fire. Since the registries moved to `LazyContextProvider` they are subscribed
on demand, which makes an iframe panel the first requester far more often: the
KNX panel's entity table renders empty after leaving and re-entering it, and
the main frontend can inherit the same dead cache.

Clean up from the iframe's own `pagehide` handler, while the realm is still
alive - `disconnectedCallback` on `ha-panel-custom` runs after the browsing
context is discarded, when `contentWindow` is already `null`.

Co-Authored-By: Claude Opus 5 <[email protected]>

* Use unknown instead of any in the CachedCollection shape

The helper never inspects the subscribed state, so the parameter type only
needs to be a placeholder.

Co-Authored-By: Claude Opus 5 <[email protected]>

---------

Co-authored-by: Claude Opus 5 <[email protected]>
2026-08-04 09:31:42 +03:00
karwosts c97716d4ad Fix automation paste with variables (#53441)
* Fix automation paste with variables

* fix script

* fix stuff

* fix append

* fix script
2026-08-04 09:17:05 +03:00
dependabot[bot] b36361ca34 Bump fast-uri from 3.1.4 to 3.1.5 (#53474)
Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.4 to 3.1.5.
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.4...v3.1.5)

---
updated-dependencies:
- dependency-name: fast-uri
  dependency-version: 3.1.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-04 09:03:25 +03:00
dependabot[bot] 007a7916c0 Bump undici from 6.27.0 to 6.28.0 (#53475)
Bumps [undici](https://github.com/nodejs/undici) from 6.27.0 to 6.28.0.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v6.27.0...v6.28.0)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 6.28.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-04 09:02:51 +03:00
renovate[bot] 637f6955a8 Update dependency @types/leaflet to v1.9.22 (#53473)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-04 09:02:29 +03:00
b574aaa084 Type feature event handlers (#53461)
* Type feature event handlers

* Address event handler review feedback

Co-authored-by: timmo001 <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-08-04 08:28:13 +03:00
dependabot[bot] c1dca9b377 Bump postcss from 8.5.19 to 8.5.25 (#53465)
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.19 to 8.5.25.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.19...8.5.25)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.25
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-04 08:25:14 +03:00
dependabot[bot] c9963b7f92 Bump ip-address from 10.2.0 to 10.4.0 (#53470)
Bumps [ip-address](https://github.com/beaugunderson/ip-address) from 10.2.0 to 10.4.0.
- [Release notes](https://github.com/beaugunderson/ip-address/releases)
- [Commits](https://github.com/beaugunderson/ip-address/compare/v10.2.0...v10.4.0)

---
updated-dependencies:
- dependency-name: ip-address
  dependency-version: 10.4.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-04 08:24:52 +03:00
karwosts 42954152dc Fix slow loading of entity rows in device page (#53471)
Fix lazy loading of entity rows in device page
2026-08-04 08:24:19 +03:00
Petar Petrov f5a28977c2 Fix energy default period being saved under the wrong storage key (#53462) 2026-08-03 19:55:41 +02:00
renovate[bot] 9b1f407ff4 Update Node.js to v24.19.0 (#53463)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-03 19:54:38 +02:00
277822e51c Type application event contracts (#53459)
* Type application event contracts

* Remove redundant currentTarget casts

Co-authored-by: timmo001 <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-08-03 14:57:11 +00:00
4a2bca6d76 Type component event handlers (#53458)
* Type component event handlers

* Fix event handler types per review feedback

Co-authored-by: timmo001 <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-08-03 17:47:02 +03:00
Aidan Timson 8e47b5369e Apply minimum release age to all dependencies (#53464) 2026-08-03 14:26:32 +00:00
Petar Petrov 759ab155c7 Show progress on the Zigbee backup button while the backup is created (#53422) 2026-08-03 15:06:53 +01:00
karwosts 8de939a696 Fix unsaved-mixin race condition (#53435) 2026-08-03 17:04:42 +03:00
Petar Petrov 5c3d74502b Stop the statistics graph card editor looping while typing a name (#53434) 2026-08-03 16:30:06 +03:00
Aidan Timson 0bf67b603c Type and Lit skills (#53457)
Document frontend type and Lit guidance
2026-08-03 16:28:49 +03:00
renovate[bot] 01915f2e5a Update dependency lint-staged to v17.3.0 (#53456)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-03 14:53:15 +03:00
Aidan Timson cee1c91ed8 Home Assistant event handler types skill (#53452)
* Document Home Assistant event handler types

* Expand event handling guidance

* Prefer bottom event declarations

* Split event guidance into dedicated skill
2026-08-03 13:51:24 +03:00
renovate[bot] 954662f454 Update formatjs (#53451)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-03 08:35:14 +03:00
renovate[bot] c07fb2b7ec Update dependency intl-messageformat to v11.2.13 (#53450)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-03 05:33:41 +00:00
Sören Beye 041219a40c Fix js float weirdness in hui-energy-grid-balance-card (#53442) 2026-08-03 08:26:57 +03:00
karwosts f28a1c5370 Allow to favorite the manual card (#53445) 2026-08-03 08:23:17 +03:00
renovate[bot] 4099de96c3 Update Playwright (#53446)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-02 21:36:40 +02:00
dependabot[bot] 673ca45cde Bump home-assistant/actions/helpers/verify-version from e3fb68ebda13d88a0d695082f471ba2c83d025fb to ab22029681aa532bfe7de5774a9972d67bfbd2c0 (#53440)
Bump home-assistant/actions/helpers/verify-version

Bumps [home-assistant/actions/helpers/verify-version](https://github.com/home-assistant/actions) from e3fb68ebda13d88a0d695082f471ba2c83d025fb to ab22029681aa532bfe7de5774a9972d67bfbd2c0.
- [Release notes](https://github.com/home-assistant/actions/releases)
- [Commits](https://github.com/home-assistant/actions/compare/e3fb68ebda13d88a0d695082f471ba2c83d025fb...ab22029681aa532bfe7de5774a9972d67bfbd2c0)

---
updated-dependencies:
- dependency-name: home-assistant/actions/helpers/verify-version
  dependency-version: ab22029681aa532bfe7de5774a9972d67bfbd2c0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-02 09:45:26 +02:00
renovate[bot] 4dfc626363 Update Yarn to v4.18.0 (#53432)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-02 09:45:09 +02:00
dependabot[bot] 1206f0ae5d Bump the codeql-action group across 1 directory with 2 updates (#53439)
Bumps the codeql-action group with 2 updates in the / directory: [github/codeql-action/init](https://github.com/github/codeql-action) and [github/codeql-action/analyze](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.37.1 to 4.37.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/7188fc363630916deb702c7fdcf4e481b751f97a...e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81)

Updates `github/codeql-action/analyze` from 4.37.1 to 4.37.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/7188fc363630916deb702c7fdcf4e481b751f97a...e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-02 09:44:33 +02:00
renovate[bot] f71a938d02 Update dependency jsdom to v30.0.1 (#53431)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-01 13:09:13 +02:00
renovate[bot] e2cade842e Update dependency @rspack/core to v2.1.7 (#53430)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-01 13:09:11 +02:00
karwosts e6df5fd159 Reuse state-display for entities secondary info (#53260)
* Reuse state-content for entities secondary info

* migrate area

* Skip schema calculation when using predefined schema.

* add tooltip, migrate none

* timestamp for weather
2026-07-31 23:07:10 +02:00
0da3ec1151 Wait for calendar and media browser readiness (#53367)
* Wrap dashboard loading spinner in a delayed fade in component

* Expose initial view render completion

* Wait for dashboard initial readiness

* Signal initial Lovelace view readiness

* Aggregate dashboard view readiness

* Wait for generated panel readiness

* Test dashboard initial readiness

* Add fade in delay to correct dashboard loading

* Delay generated panel readiness until content

* Test generated dashboard initial readiness

* Guard component spread against undefined for unknown panels

Co-authored-by: timmo001 <[email protected]>

* Wait for calendar and media browser readiness

* Test calendar and media browser readiness

* Wait for media panel host readiness

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Simon Lamon <[email protected]>
2026-07-31 22:43:56 +02:00
46fdf9c91b Wait for dashboard initial readiness (#53357)
* Wrap dashboard loading spinner in a delayed fade in component

* Expose initial view render completion

* Wait for dashboard initial readiness

* Signal initial Lovelace view readiness

* Aggregate dashboard view readiness

* Wait for generated panel readiness

* Test dashboard initial readiness

* Add fade in delay to correct dashboard loading

* Delay generated panel readiness until content

* Test generated dashboard initial readiness

* Guard component spread against undefined for unknown panels

Co-authored-by: timmo001 <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-07-31 22:00:54 +02:00
80a026d9bf Recover from a stale index.html at boot (#53378)
* Recover from a stale index.html at boot

A cached, stale index.html imports the previous build's content-hashed
entry bundles (core.<hash>.js / app.<hash>.js). After an upgrade those
files 404, app.js never runs, <home-assistant> is never defined, and the
launch screen never clears. No bundled JS can recover this, because the
bundle itself failed to load.

Add a tiny, prod-only inline guard in index.html that catches the failed
entry load (capture-phase resource error + unhandledrejection) and does a
single, loop-guarded cache-busting reload, dropping the service worker and
caches on https first. core.ts strips the cache-bust param after a
successful boot.

Part of home-assistant/epics#113.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Share stale-build recovery patterns via a single JSON source

Move the boot guard's chunk-detection regexes into
stale-build-patterns.json and inject them into the inline guard at build
time (entry-html.js), so they stay in sync with the bundled recovery util
(util/recover-stale-build.ts, in the follow-up post-boot recovery) which
reads the same file — no more manually kept-in-sync copies.

Part of home-assistant/epics#113.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

---------

Co-authored-by: Claude Opus 4.8 <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-07-31 21:45:59 +02:00
dc5699fec3 Ask which occurrences to change in the recurring event dialog (#53423)
* Ask which occurrences to change in the recurring event dialog

Deleting or updating a recurring event offered "only this event" and "all
future events" as two long buttons, which a 320px dialog footer squeezed
until every word wrapped onto its own line.

Move the choice into the dialog body as a radio group and leave the footer
with Cancel plus a single confirm action. The dialog also becomes an alert,
so it stays a centered card on small viewports, and the confirm action is
only styled as destructive for the delete flows.

* Apply suggestions from code review

Co-authored-by: Aidan Timson <[email protected]>

* Update src/panels/calendar/confirm-event-dialog-box.ts

Co-authored-by: Aidan Timson <[email protected]>

---------

Co-authored-by: Aidan Timson <[email protected]>
Co-authored-by: Paul Bottein <[email protected]>
2026-07-31 21:42:02 +02:00
Bram Kragten 1454f4d081 Bumped version to 20260729.3 2026-07-31 16:44:13 +02:00
Paul Bottein 1a47c326b2 Fix tile name truncated too early (#53416) 2026-07-31 16:43:50 +02:00
Aidan Timson d8e827e08b Fix profile theme link colour (#53415) 2026-07-31 16:43:49 +02:00
John G. 301c907fa9 Fix typo in Google Home Matter pairing instructions (#53413)
Corrected a typo in the instructions for pairing a Matter device from Google Home with a pairing code.
2026-07-31 16:43:48 +02:00
karwosts 1ef3bc94d0 Add a few missing logbook csv fields (#53412) 2026-07-31 16:43:47 +02:00
Bram KragtenandSimon Lamon ba0367be2f use defaults provided by core for ports in strings, add url to new lo… (#53407)
* use defaults provided by core for ports in strings, add url to new location after restart

* Apply suggestions from code review

Co-authored-by: Simon Lamon <[email protected]>

---------

Co-authored-by: Simon Lamon <[email protected]>
2026-07-31 16:43:46 +02:00
Bram Kragten c186a31056 Prevent http confirm dialog from getting closed (#53406) 2026-07-31 16:43:45 +02:00
Paul BotteinandPetar Petrov bf8c92c95e Use backend slugify for the entity ID format preview (#53394)
* Use backend slugify for the entity ID format preview

* Update src/panels/config/core/ha-config-entity-id-format.ts

Co-authored-by: Petar Petrov <[email protected]>

* Use top-level slugify websocket command

* Fix formatting

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-07-31 16:43:44 +02:00
3a1d330a2f Offer to stop conflicting managed workflows (#53418)
* Offer to stop conflicting managed workflows

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Fix syntax error: misplaced brace before finally in confirmStopConflict

Co-authored-by: timmo001 <[email protected]>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Format

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-07-31 16:15:44 +03:00
Petar Petrov c8a29ae2f2 Keep progress button labelled while showing its result (#53426)
While the check or error icon covers the button, the button's content was
hidden with `visibility: hidden`, which also removes the label from the
accessibility tree. For the two seconds the result is shown, a screen
reader announced a button with no accessible name.

Fade the content out instead. It looks the same and reserves the same
space, but the label stays readable to assistive technology. The spinner
part keeps `visibility: hidden`, since a finished spinner should leave
the accessibility tree.
2026-07-31 15:50:36 +03:00
Aidan TimsonandCopilot Autofix powered by AI b1ccb6355d Wait for settings overview readiness (#53352)
* Wait for settings overview readiness

* Move panel readiness setup to constructor

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Cache bluetooth config entries fetch in settings navigation

* Fix child panel readiness registration race

* Avoid redundant settings navigation renders

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-07-31 13:22:00 +03:00
Aidan Timson 5f2086765a Add managed translation fetching to dev servers (#53417) 2026-07-31 13:20:50 +03:00
renovate[bot] 02c51a2789 Update dependency @rspack/core to v2.1.6 (#53420)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-31 11:39:06 +02:00
Paul Bottein 706421f3c5 Fix tile name truncated too early (#53416) 2026-07-31 11:52:23 +03:00
Aidan Timson cbc2e34638 Fix profile theme link colour (#53415) 2026-07-31 10:47:45 +02:00
Yosi Levy 0bc0b08978 RTL fixes (#53414) 2026-07-31 08:41:52 +01:00
karwostsandPetar Petrov 48394db843 Validate dialog-form on submit (#53381)
* Validate dialog-form on submit

* remove whitespace

* put errors on the stack

* Apply suggestion from @MindFreeze

Co-authored-by: Petar Petrov <[email protected]>

* Apply suggestion from @MindFreeze

* Fix botched suggestion apply in nested submit

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-07-31 07:14:40 +00:00
Paul BotteinandPetar Petrov 83dac08059 Use backend slugify for the entity ID format preview (#53394)
* Use backend slugify for the entity ID format preview

* Update src/panels/config/core/ha-config-entity-id-format.ts

Co-authored-by: Petar Petrov <[email protected]>

* Use top-level slugify websocket command

* Fix formatting

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-07-31 09:39:47 +03:00
Aidan Timson 3c6b70ded8 Prevent concurrent managed frontend workflows (#53396)
* Shared build and runner for all build,dev,test flows

* Harden managed process lifecycle

* Make build workflows deterministic

* Test build management contracts

* Queue shared generated output work

* Isolate generated inputs for dev servers

* Preserve dev server child failures

* Make generated lock test deterministic

* Keep test navigator configurable

* Block concurrent frontend workflows

* Simplify workflow lock ownership

* Focus workflow locking on managed commands

* Trim workflow lock unit tests

* Consolidate dev server lifecycle handlers
2026-07-31 09:30:49 +03:00
John G. 1e414f31dc Fix typo in Google Home Matter pairing instructions (#53413)
Corrected a typo in the instructions for pairing a Matter device from Google Home with a pairing code.
2026-07-31 04:27:25 +00:00
karwosts d013051f81 Add a few missing logbook csv fields (#53412) 2026-07-31 06:19:05 +02:00
Bram KragtenandSimon Lamon eb2efbb669 use defaults provided by core for ports in strings, add url to new lo… (#53407)
* use defaults provided by core for ports in strings, add url to new location after restart

* Apply suggestions from code review

Co-authored-by: Simon Lamon <[email protected]>

---------

Co-authored-by: Simon Lamon <[email protected]>
2026-07-31 06:08:38 +02:00
Bram Kragten 7e4d745b21 Prevent http confirm dialog from getting closed (#53406) 2026-07-31 06:08:18 +02:00
Bram Kragten 9743117abf Bumped version to 20260729.2 2026-07-30 23:27:41 +02:00
Petar Petrov 5e012973b2 Reject non-http URLs from integrations before using them as links (#53379) 2026-07-30 23:27:10 +02:00
Petar Petrov d01f7d98a5 Reject non-http URLs from integrations before using them as links (#53379) 2026-07-30 23:26:29 +02:00
Petar Petrov ea659f1b33 Show which energy power statistic is missing (#53404) 2026-07-30 23:25:16 +02:00
539803cb5b Search a media player's own library from the media browser (#53402)
* Search a media player's own library from the media browser

The media browser search only ever asked the media sources, so searching
inside a media player's own library (Music Assistant, Sonos, Squeezebox,
Jellyfin) failed. Ask the entity instead when the current item belongs to
it, the same way browsing already does.

* Update src/data/media_source.ts

* Remove blank line in media_source.ts

Removed unnecessary blank line at the top of media_source.ts

---------

Co-authored-by: Bram Kragten <[email protected]>
Co-authored-by: Simon Lamon <[email protected]>
2026-07-30 23:25:15 +02:00
karwosts 944d3332d1 Fix schedule editor dirty tracking (#53401) 2026-07-30 23:25:14 +02:00
Petar Petrov 4a267d160f Fix numeric input feature editor showing the wrong default style (#53398) 2026-07-30 23:25:13 +02:00
7edb9f8164 Launch screen tweaks (#53380)
* Polish the launch screen

- Use the system sans-serif font so the launch screen no longer blocks on
  loading Roboto
- Reduce the gap between the logo and the loading text
- Dim the loading text to 66% opacity
- Match the OHF logo variant to the applied theme instead of the system
  color scheme
- Make the launch screen text and buttons unselectable

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>

* Drop unit test

* Use classMap

* Drop view transition for css transition to avoid flash

---------

Co-authored-by: marcinbauer85 <[email protected]>
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-07-30 23:25:12 +02:00
renovate[bot] 6df6b556bd Update dependency @codemirror/view to v6.43.7 (#53409) 2026-07-30 22:34:36 +02:00
f5c6420fbc Search a media player's own library from the media browser (#53402)
* Search a media player's own library from the media browser

The media browser search only ever asked the media sources, so searching
inside a media player's own library (Music Assistant, Sonos, Squeezebox,
Jellyfin) failed. Ask the entity instead when the current item belongs to
it, the same way browsing already does.

* Update src/data/media_source.ts

* Remove blank line in media_source.ts

Removed unnecessary blank line at the top of media_source.ts

---------

Co-authored-by: Bram Kragten <[email protected]>
Co-authored-by: Simon Lamon <[email protected]>
2026-07-30 15:44:28 +00:00
karwosts 71ec76185f Fix schedule editor dirty tracking (#53401) 2026-07-30 17:37:18 +02:00
Petar Petrov f08ab2f331 Show which energy power statistic is missing (#53404) 2026-07-30 16:41:28 +02:00
Petar Petrov 77b0b9b5b8 Fix numeric input feature editor showing the wrong default style (#53398) 2026-07-30 16:37:16 +02:00
4fcc1adf3a Managed background builds and shared process management (#53374)
* Add managed modern production builds

* Harden managed build process controls

* Update managed process testing guidance

* Harden managed process file operations

* Share generated output process ownership

* Clean stale build state on status

* Address managed build review feedback

Co-authored-by: timmo001 <[email protected]>

* Use single compress task

* 1

Co-authored-by: Petar Petrov <[email protected]>

* Forward SIGHUP to foreground processes

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-07-30 13:25:10 +03:00
renovate[bot] 9699851c26 Update dependency jsdom to v30 (#53395)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-30 12:15:24 +02:00
Raman GuptaandClaude Fable 5 a318593c9f Add live updates to Z-Wave JS node config parameters (#53013)
* Fix Z-Wave JS config parameter value type

Type ZWaveJSNodeConfigParam.value as number | null instead of any,
matching what the backend sends. This surfaced two comparison bugs:

- The enumerated picker no-op check compared the stored number against
  the picker's string value, so it never matched and re-selecting the
  current option re-sent the command to the device.
- The numeric input guard coerced null (unknown value) to 0, so
  entering 0 for a parameter with an unknown value was ignored.

Co-Authored-By: Claude Fable 5 <[email protected]>

* Treat empty numeric input as invalid instead of 0

Co-Authored-By: Claude Fable 5 <[email protected]>

* Add live updates to Z-Wave JS node config parameters

Subscribe to config parameter value updates so the page reflects
changes made outside the UI (Z-Wave JS UI, another browser tab, or
the device itself) and so queued changes to sleeping nodes resolve
to a success message when the node wakes and applies them.

- Manage the subscription across connect/disconnect and device
  navigation, deriving deviceId reactively from the route
- Show success results briefly, then clear them automatically
- Clear stale error results when the parameter changes externally
- Discard fetch responses that arrive after navigating to another node

Co-Authored-By: Claude Fable 5 <[email protected]>

* Address review comments

- Use slice() instead of deprecated substr()
- Clear pending result timeouts when navigating to another node
- Handle subscription promise rejections so an older backend without
  the subscribe command degrades gracefully instead of logging
  unhandled rejections

Co-Authored-By: Claude Fable 5 <[email protected]>

---------

Co-authored-by: Claude Fable 5 <[email protected]>
2026-07-30 12:14:26 +02:00
749dd180ae Launch screen tweaks (#53380)
* Polish the launch screen

- Use the system sans-serif font so the launch screen no longer blocks on
  loading Roboto
- Reduce the gap between the logo and the loading text
- Dim the loading text to 66% opacity
- Match the OHF logo variant to the applied theme instead of the system
  color scheme
- Make the launch screen text and buttons unselectable

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>

* Drop unit test

* Use classMap

* Drop view transition for css transition to avoid flash

---------

Co-authored-by: marcinbauer85 <[email protected]>
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-07-30 12:13:49 +02:00
Bram Kragten ff814167c6 Bumped version to 20260729.1 2026-07-30 10:41:32 +02:00
Paul Bottein d08d8dde64 Show integration logo and name in the replace device dialog (#53384) 2026-07-30 10:41:12 +02:00
Bram Kragten 5da441ceed Strip empty strings from http config (#53377) 2026-07-30 10:41:11 +02:00
Paul Bottein 22e646a68a Allow area card name to wrap to two lines in vertical layout (#53370)
* Allow area card name to wrap to two lines in vertical layout

* Align vertical tile icons in grid sections

* Cut single big word
2026-07-30 10:41:11 +02:00
Maarten Lakerveldandcopilot-swe-agent[bot] d0ab20479f Tools > Template use WA Split Panel (#53021)
* Add Web Awesome Split Panel component

* Use SplitPanel for template page. Add vertical/horizontal option. Cleanup, use flexbox.

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-07-30 10:41:10 +02:00
Maarten Lakerveldandcopilot-swe-agent[bot] 247780e4c8 Tools > Template use WA Split Panel (#53021)
* Add Web Awesome Split Panel component

* Use SplitPanel for template page. Add vertical/horizontal option. Cleanup, use flexbox.

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-07-30 10:39:41 +02:00
Paul Bottein 7991090313 Allow area card name to wrap to two lines in vertical layout (#53370)
* Allow area card name to wrap to two lines in vertical layout

* Align vertical tile icons in grid sections

* Cut single big word
2026-07-30 10:03:43 +03:00
Aidan Timson 2efa0bd86d Prefetch home dashboard resources concurrently (#53373)
Load Home dashboard resources concurrently
2026-07-30 10:01:13 +03:00
0fad4f0097 Remove empty items on narrow data table secondary lines (#53382)
* Skip empty cells on the narrow data table secondary line

In narrow mode the main column renders every other visible column on a
secondary line, but the dot separator was inserted based on the column
index instead of whether the cell rendered anything. A row whose extra
columns are all empty showed a secondary line consisting only of dots,
and an empty column between two filled ones produced a double dot.

Filter empty cells out before joining, and return `nothing` instead of
`html`${nothing}`` for missing timestamps so those cells are detectably
empty too.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>

* Extract / clarify data table column visibility

* Fix unbound method and add all-empty secondary line test

Co-authored-by: timmo001 <[email protected]>

* Fix prettier formatting in ha-data-table test

Co-authored-by: timmo001 <[email protected]>

---------

Co-authored-by: marcinbauer85 <[email protected]>
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-07-30 07:07:43 +02:00
Marcin BauerandClaude Opus 5 2b90c9a628 Show the automation state on mobile in the automations table (#53375)
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-07-29 19:48:51 +02:00
renovate[bot] f3848df19d Update dependency globals to v17.8.0 (#53387)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-29 19:48:26 +02:00
renovate[bot] e2a91c358d Update Node.js to v24.18.1 (#53386)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-29 19:48:22 +02:00
Paul Bottein 8793cb58b9 Show integration logo and name in the replace device dialog (#53384) 2026-07-29 19:24:39 +02:00
Bram Kragten 2442bf662a Strip empty strings from http config (#53377) 2026-07-29 15:33:02 +02:00
Bram Kragten e42be9f4d6 Bumped version to 20260729.0 2026-07-29 14:52:39 +02:00
Bram Kragten a096f8383d Merge branch 'rc' into dev 2026-07-29 14:50:42 +02:00
Simon LamonandMaarten Lakerveld a3e59d64fc Pass browserlist targets to lightningcss (#53128)
* Pass browserlist targets to lightningcss

* Fix pass-browser-list branch (#53243)

Add failsafe for empty browserlist. Add comment to describe prefix issue in literals. Use default browserlistEnv naming convention. SW uses more efficient browserlist only targeting browsers that support sw.

* Increase JS budgets

---------

Co-authored-by: Maarten Lakerveld <[email protected]>
2026-07-29 14:33:33 +02:00
e90e8169cd Fix save button state in the energy battery and grid dialogs (#53371)
Editing only the battery capacity left the dirty state untouched, so
Save stayed disabled and the change could not be saved. Add the missing
dirty state update.

The Save button also read power config validity off the
ha-energy-power-config child element. Lit evaluates every binding in
render() before committing any of them, so disabled was computed from
the child's pre-update state and lagged one render behind. Derive
validity from the dialog's own power type and config instead, through a
shared helper extracted alongside the other pure power config helpers,
and cover that helper with unit tests.

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: bramkragten <[email protected]>
2026-07-29 12:29:48 +00:00
Petar Petrov 959a798b5c Reject non same-origin back paths before using them as links (#53376) 2026-07-29 14:13:47 +02:00
Petar Petrov 9c117d446e Show the generated power helper sensor in energy power settings (#53368) 2026-07-29 12:59:31 +02:00
Petar Petrov 11913292b1 Fix required field validation being skipped in the app bundle (#53359)
* Fix required field validation being skipped in the app bundle

* Route blur and invalid handling through the guarded validity check
2026-07-29 13:51:35 +03:00
Bram Kragten 52f2b5abed Add link on the device page to shared hardware devices (#53363) 2026-07-29 09:37:09 +02:00
Petar Petrov e658113ef4 Fix gauge value missing when the card is revealed by a visibility condition (#53321)
* Fix gauge value text missing when revealed by a visibility condition

* Use a resize controller to retry the measurement

* Give the gauge host a block display so its size is observed
2026-07-29 07:10:32 +02:00
Maarten Lakerveld c35e316ef7 Conditions/triggers/actions use the same logic for automation picker sorting (#53136)
* Conditions/triggers/actions use the same logic for automation picker sorting

* Move all Integrations to a separate integrations group.
2026-07-29 06:54:12 +02:00
Paul Bottein 946c40d8a3 Add entity ID format setting for new entities (#53268) 2026-07-28 22:03:59 +02:00
7ca7c08090 Add horizontal padding to vertical tile content (#53277)
* Add horizontal padding to vertical tile content

The vertical tile layout overrode the content padding to 10px 0,
removing the horizontal padding entirely. This allowed the tile name
in vertical cards (e.g. area cards on the default dashboard) to
truncate flush against the card edge. Keep the same 10px side padding
the horizontal layout uses.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011ciaPX4SwWZp1mB2mtvbqd

* Reduce vertical tile side padding to 4px

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011ciaPX4SwWZp1mB2mtvbqd

* Use 2px side padding for vertical tile content

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011ciaPX4SwWZp1mB2mtvbqd

* Apply suggestion from @piitaya

Co-authored-by: Paul Bottein <[email protected]>

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Simon Lamon <[email protected]>
Co-authored-by: Paul Bottein <[email protected]>
2026-07-28 18:38:09 +00:00
Aidan Timson 73865161e7 Move demo guidance into a skill (#53355)
Move demo agent guidance into a skill
2026-07-28 20:29:09 +02:00
Petar Petrov f9d1059ff6 Fire haptic feedback when pressing the button card feature (#53361) 2026-07-28 18:41:34 +02:00
Krisjanis Lejejs 691e77f948 Update cloud account page thank you text (#53354) 2026-07-28 15:54:11 +01:00
Bram KragtenandClaude Opus 4.8 6667d0e57e Surface replaced composite devices in device and target pickers (#53169)
Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-07-28 15:59:17 +02:00
Aidan Timson 70ec53ff43 Wait for initial panel readiness (#53351)
* Wait for initial panel readiness

* Keep panel readiness internal
2026-07-28 14:03:04 +01:00
Petar Petrov e34c1b9857 Fix launch screen styles breaking the index template (#53347) 2026-07-28 08:50:24 +01:00
Marcin BauerandClaude Opus 5 06580f3dbc Increase loading logomark pulse scale (#53349)
Bump the dot pulse in the launch screen logomark from scale(1.2) to
scale(1.3) so the animation reads more clearly.

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-07-28 07:29:52 +00:00
Petar Petrov fe8f32423f Fix flaky demo e2e sidebar helper on narrow viewports (#53348)
Fix race in demo e2e sidebar helper on narrow viewports

openDemoSidebar decided whether the sidebar was behind a modal drawer by
sampling ha-menu-button visibility. That element renders nothing until its
Lit contexts resolve, so right after load it reads as hidden on the narrow
layout too. The helper then took the wide-layout branch, never opened the
drawer, and the following panel assertion waited out its timeout on an
attached-but-hidden #sidebar-panel-map.

Read the layout from ha-drawer's type instead, which home-assistant-main
sets while committing its first render, and wait for the drawer to report
open after clicking the menu button.
2026-07-28 09:17:22 +02:00
b14343b831 Make the demo a Home Assistant Green running Home Assistant OS (#53326)
* Make the apps panel work in the demo

The apps panel is gated on the hassio component, so the demo redirected to
the "what is an app?" explainer instead of showing an app store. Enable
hassio and mock the supervisor endpoints behind it, with Music Assistant
and ESPHome Device Builder installed and running.

Enabling hassio also unlocks the supervisor parts of the system, storage,
hardware and network pages, so those endpoints are mocked too, otherwise
they render error banners.

Add a callApiRaw mock to provideHass so the app log tab can stream logs;
it wraps the existing REST mocks in a Response.

HassioAddonDetails.rating was typed "1-8" but is a number 1-8, as its only
consumers (RATING_ICON lookup, Number() comparisons) and the equivalent
field on StoreAddonDetails already assume.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01T4Xz1qN5chrxgPnC5V4PGz

* Show Home Assistant Green on OS 18.2 in the demo, drop app changelogs

Present the demo as a Home Assistant Green running Home Assistant OS 18.2,
and align the supervisor version and channel with it instead of the stale
2021 dev build the unused stub carried.

BOARD_NAMES had no entry for green, so the hardware page fell back to
"Generic hardware" with a raw "green" board id.

Mock /info as well; it is fetched by the about page once hassio is loaded.

Drop the demo changelogs. The app info page rendered the changelog link for
every installed app, ignoring the changelog flag the supervisor sends to say
whether the app ships one, so gate the link on it.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01T4Xz1qN5chrxgPnC5V4PGz

* Mock the hardware integration in the demo instead of BOARD_NAMES

The hardware page only gets a board picture and documentation link from the
hardware integration's info; the BOARD_NAMES map is a bare-name fallback for
when that integration is not loaded, which is why the page rendered a name
with no image. Mock hardware/info with what homeassistant_green reports, so
the board name, brands image and documentation link resolve the way they do
on a real Green, and revert the BOARD_NAMES entry added for the fallback.

Also mock hardware/subscribe_system_status so the processor and memory
charts have data, rounded the way the integration rounds psutil's values.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01T4Xz1qN5chrxgPnC5V4PGz

* Inline the changelog link and drop the demo component comment

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01T4Xz1qN5chrxgPnC5V4PGz

* Stream demo system status every second

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01T4Xz1qN5chrxgPnC5V4PGz

* Keep enabling hassio from the supervisor stub

The gallery calls mockHassioSupervisor from five pages and relies on it to
load the hassio component; dropping the push left the app selector and the
automation editors' hassio-gated pickers with nothing to fetch. Restore it,
guarded, since the demo now lists hassio in its own components.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01T4Xz1qN5chrxgPnC5V4PGz

* Note in the demo guide that the gallery imports its stubs

Twenty-five gallery pages import from demo/src/stubs, so a change that looks
fine in the demo can break the gallery. Also record why the demo is not a
reliable check: the gallery sees in-place hass.config mutations, the demo
does not.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01T4Xz1qN5chrxgPnC5V4PGz

* Guard the store changelog link too

Per review: the not-installed branch should honour the same changelog flag.
The supervisor reports it for store apps as well, alongside documentation,
so declare it on StoreAddonDetails.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01T4Xz1qN5chrxgPnC5V4PGz

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-07-28 09:42:58 +03:00
Paul Bottein 972ade22bf Add favorite cards to the card picker (#53338)
* Add favorite cards to the card picker

* Rename stored key
2026-07-28 08:43:00 +03:00
Aidan Timson 0e2a5e414b Implement new loading animation (#53328)
* Implement new svg animation

* Fix and speed up fade out transition

* Cleanup

* Remove unintentional scale in

* Match 250ms fade in and out

* Revert

* Fix small layout jump

* Pass localise as context isnt avaliable to a sibling (not a child of ha)

* Update ohf loading logomark

* Fix alt

* Update logomark again

* Reduce gap

* Font changes

* Load font for launch screen

* Smooth launch screen text loading

* Restore launch screen migration line breaks
2026-07-28 08:38:04 +03:00
karwosts 428a21175e Remove special case of grid[0] in energy (#53345) 2026-07-28 08:03:20 +03:00
Stefan AgnerandClaude Fable 5 1bcf6aa882 Fix network error briefly shown on landing page when Core comes up (#53339)
When Home Assistant Core comes up and the landing page backend is torn
down, the landing page sometimes briefly showed "Cannot get network
information" before reloading into onboarding. Two issues caused this:

- location.reload() does not stop script execution, so the error state
  was still set after the reload was triggered. Return early from both
  pollers when a reload is in progress.
- During the teardown gap where neither the Supervisor API nor Core
  responds yet, the jobs poller set _coreStatusChecked without arming
  the 60 second grace period, so the network info poller showed the
  error immediately instead of waiting. Arm the grace period in
  _checkCoreAvailability so both pollers share it consistently.

Co-authored-by: Claude Fable 5 <[email protected]>
2026-07-28 06:48:15 +02:00
renovate[bot] b7a1f1d0db Update dependency tar to v7.5.22 (#53340)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-28 06:45:32 +02:00
renovate[bot] 2bbd9d37e4 Update Playwright (#53344)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-28 06:45:15 +02:00
renovate[bot] f9bddc1228 Update dependency eslint to v10.8.0 (#53343)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-28 06:44:58 +02:00
Aidan Timson 669eab4d31 Hide superseded E2E failure comments (#53331) 2026-07-27 17:21:14 +03:00
Timothy ea179bd7fe Limit and avoid duplication when loaded is sent to mobile (#53335) 2026-07-27 17:08:12 +03:00
karwostsandPetar Petrov ef50cc0332 Abbreviate sections in automation add search dialog (#53286)
* Abbreviate sections in automation add search dialog

* fixes

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-07-27 13:59:43 +00:00
Aidan Timson ab0ce2a3b7 Keep Playwright Renovate updates together (#53336) 2026-07-27 13:54:53 +00:00
Petar Petrov 23bc2cf1c1 Share the sankey effective-parent walk across all four cards (#53329)
* Share the sankey effective-parent walk across all four cards

Each of the four sankey cards built its own `findEffectiveParent` to walk
`included_in_stat` up to the nearest rendered ancestor. The two cumulative
cards were byte-identical; the two instantaneous ones differed only in
comments and brace style. The pairs differed from each other only in which
id space they resolve to, which is exactly what `getId` already expresses.

Move the walk into `buildSankeyDeviceNodes`, which already receives
`devices`, `getId`, `getValue` and `minThreshold`, and drop the
`findEffectiveParent` option. A `renderedId` helper maps a stat_consumption
through `getId` to a node id, so one implementation covers both spaces.

Also folds in three incidental improvements:

- `deviceByStat` replaces each card's `deviceMap` plus the `deviceParents`
  map added in #53324.
- The walk is a bounded `for` instead of an unbounded `while`, which would
  hang on a cyclic `included_in_stat`. Cycles are prevented in the config UI
  but not validated in core.
- `getValue` is now called once per device instead of twice. For the
  cumulative cards it is `calculateStatisticSumGrowth`, which is O(points).

No behaviour change. Adds coverage for the instantaneous id space, which
had no hierarchy tests, and for a nested small consumer inside a rendered
parent's cluster.

* Keep small sankey devices attributed under a rendered ancestor

The nested-small-consumer filter from #53324 walks `included_in_stat` and
drops any small consumer whose chain reaches another small consumer. The
walk did not stop at ancestors that are rendered as their own node, so a
small device sitting under a rendered parent was dropped whenever anything
further up the chain happened to be small.

Such a consumer links to its rendered parent and never touches untracked,
so it cannot be double-counted through a small ancestor beyond it - and
dropping it does not fix the separate overlap between the rendered node and
that ancestor. It just loses a real device from the graph.

Stop the walk at the first rendered ancestor. Needs `included_in_stat` data
where a parent statistic reads smaller than its child, so it takes a gap or
a late start on the parent to trigger.
2026-07-27 14:59:02 +02:00
85e94841a9 Improve target picker group header (#53250)
* Improve target picker group header

- Show group item count only when the group is collapsed, styled as a
  secondary-color "(N)" next to the type label
- Thin the item-groups border to 1px via --ha-border-width-sm
- Remove the "Targets" pre-label before the target selector in the
  action, trigger and condition editors, moving its spacing/divider onto
  the selector itself

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

* Update src/components/target-picker/ha-target-picker-item-group.ts

Co-authored-by: Simon Lamon <[email protected]>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
Co-authored-by: Simon Lamon <[email protected]>
2026-07-27 14:37:34 +02:00
1de7230d9e Fall back to English when nightly translations cannot be fetched (#53272)
* Fall back to English when nightly translations cannot be fetched

Local builds no longer fail when the nightly translations fetch errors
(offline or invalid GitHub credentials); they warn and continue with
English only, like the existing no-token path. CI still fails so
releases cannot silently ship without translations.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01V3oj5uaCRRaoXRd5iEffhi

* Record fetched artifact only after successful extraction

A failure mid-fetch previously left a fresh artifact.json next to wiped
translations, so builds within the next 24 hours skipped the fetch and
silently built English only. Writing the artifact file last means a
failed fetch is retried by the next build.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01V3oj5uaCRRaoXRd5iEffhi

* Update build-scripts/gulp/fetch-nightly-translations.js

Co-authored-by: Simon Lamon <[email protected]>

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Simon Lamon <[email protected]>
2026-07-27 11:32:26 +00:00
Josef ZweckandPetar Petrov 7620f21033 Add search functionality to media browser (#53258)
* Add search functionality to media browser

* prettier

* add debounced search, clear properly

* abort in flight search, remove dead code

* prettier

* filter

* prettier

* Hide media type filter on root media sources page

* Only show media type filter for searchable sources

* Apply media type filter only to backend search, not local browse

* Move media type filter inside the search bar

* Add client-side filters for media browser results

* Center search spinner in media browser

* Revert "Add client-side filters for media browser results"

This reverts commit 3e1fc71fbd.

* Revert "Move media type filter inside the search bar"

This reverts commit 19dcb92ad1.

* Revert "Apply media type filter only to backend search, not local browse"

This reverts commit 9b4f86878d.

* Revert "Only show media type filter for searchable sources"

This reverts commit 6dca0ce24e.

* Revert "Hide media type filter on root media sources page"

This reverts commit 62bbe34b71.

* Revert "prettier"

This reverts commit d64f90865c.

* Revert "filter"

This reverts commit 56dc5450b2.

* Reapply "filter"

This reverts commit a18edb79e4.

* Reapply "prettier"

This reverts commit 224b8823ea.

* Reapply "Hide media type filter on root media sources page"

This reverts commit 9e447e2d68.

* Reapply "Only show media type filter for searchable sources"

This reverts commit f29bd8e434.

* Reapply "Apply media type filter only to backend search, not local browse"

This reverts commit e5c021a814.

* Reapply "Move media type filter inside the search bar"

This reverts commit c83d7b77a6.

* Reapply "Add client-side filters for media browser results"

This reverts commit 436e32eeea.

* Remove local filters panel from media browser

Removes the 'Filters' collapsible panel that included:
- Local text search filter
- Local media class filter chips
- Keeps media type dropdown filter in search bar

* Fix eslint: use const instead of let for notShown variable

* Fix prettier formatting

* remove debounced search

* remove char limit

* Search button, localize

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-07-27 09:42:46 +00:00
Maarten LakerveldandPetar Petrov 425a914d34 Sankey Energy: dont double count smallconsumer ancestor/children in other (#53324)
dont double count smallconsumer ancestor/children in other

Co-authored-by: Petar Petrov <[email protected]>
2026-07-27 09:42:32 +00:00
Copilotandtimmo001 f413e71d54 Fix Prettier formatting in dialog-energy-battery-settings.ts (#53325)
* Initial plan

* Fix Prettier formatting in dialog-energy-battery-settings.ts

Co-authored-by: timmo001 <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: timmo001 <[email protected]>
2026-07-27 12:34:03 +03:00
Paulus SchoutsenandClaude Fable 5 28045f6cd6 Hide the devices tile on home overview when the other devices view is empty (#53275)
* Show entities without a device in the home other devices view

The home overview counts area-less entities to decide whether to show
the devices tile, but the other devices view dropped any entity without
a device registry entry. Area-less entities that also have no device
(e.g. template or helper entities) thus produced a devices tile leading
to an empty view.

Group them under an "Others" section instead, matching how the home
area view handles entities without a device.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KZ6ydA22VeQndgynH4SxCV

* Hide the devices tile instead of showing entities without a device

Reverse the fix direction: entities without a device registry entry
should not be rendered by the other devices view. Instead, the home
overview should not show the devices tile when that view has nothing to
render.

Extract the filtering and device grouping into a shared
getOtherDevicesEntities helper used by both the other devices view and
the overview, so the devices tile is only shown when the view actually
has content.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KZ6ydA22VeQndgynH4SxCV

* Stop at the first matching entity when checking for other devices

The overview only needs to know whether the other devices view has any
content, so short-circuit on the first matching entity instead of
computing the full device grouping.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KZ6ydA22VeQndgynH4SxCV

* Inline the devices check in the overview strategy

Drop the extracted helper and keep the other devices view strategy
untouched. The overview inlines the check for area-less primary
entities that belong to a device, keeping the diff to the tile
condition only.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KZ6ydA22VeQndgynH4SxCV

---------

Co-authored-by: Claude <[email protected]>
2026-07-27 11:11:46 +03:00
Simon Lamon 34f3283850 Handle 0 not as undefined in choose selector (#53264)
* Handle 0 not as undefined in new choose selector

* Also handle null
2026-07-27 08:15:04 +03:00
Petar Petrov d02c4924c4 Fix history graph rendering as a spike when shown by a visibility condition (#53314)
Fix chart down sampling collapsing the series when the chart is hidden
2026-07-27 06:54:44 +02:00
Paulus SchoutsenandClaude Opus 5 e71bb867be Show Assist pipelines in the demo voice assistants panel (#53318)
* Show Assist pipelines in the demo voice assistants panel

The demo already mocked assist_pipeline/pipeline/list, but assist_pipeline
was not in the demo's loaded components, so assist-pref never rendered and
the panel only showed the cloud Alexa/Google cards.

Add assist_pipeline to the demo component list and rename the second mocked
pipeline from Local to ChatGPT, keeping Home Assistant Cloud preferred.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_0146VB8URemDGRFs8X4MDbA6

* Keep the Local pipeline in the demo assist mocks

Restore the Local pipeline alongside Home Assistant Cloud and ChatGPT, listed
above ChatGPT. Home Assistant Cloud stays preferred.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_0146VB8URemDGRFs8X4MDbA6

* Vary pipeline languages in the demo assist mocks

Set the Local pipeline to Dutch and the ChatGPT pipeline to Spanish, so the
demo shows assistants in different languages. Home Assistant Cloud stays
English and preferred.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_0146VB8URemDGRFs8X4MDbA6

* Drop the added comment in the demo component override

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_0146VB8URemDGRFs8X4MDbA6

---------

Co-authored-by: Claude <[email protected]>
2026-07-27 06:53:52 +02:00
renovate[bot] 60163efd56 Update dependency fs-extra to v11.4.0 (#53317)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-27 06:52:57 +02:00
Adrian Campos 351859c3d0 Fix typo in no_triggers message (#53319) 2026-07-27 06:52:41 +02:00
Petar Petrov 5f0f1f4867 Add battery capacity option for weighted state of charge (#52355)
* Add battery capacity option for weighted state of charge

* Add spacing between state of charge and capacity inputs
2026-07-27 06:02:28 +02:00
Paulus SchoutsenandClaude 18de8b13d3 Add a home page demo to the demo (#53311)
* Fix mocked entity states and demo config switching

Three small demo/mock fixes:

- Mocked entities dropped unit_of_measurement and state_class when
  writing to the state machine, so demo sensors rendered without a unit
  and the mocked history returned a single state for them
- The energy consumption sensor entity id had a stray tab, which fails
  entity id validation in cards that render it
- Switching demos saved the dashboard config before the new registries
  and entities reached the dashboard, so dashboard strategies generated
  against the previous data

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KZ6ydA22VeQndgynH4SxCV

* Add a home page demo to the demo

Adds the home page as the second demo, generated by the real home
dashboard strategies instead of a copy, so the demo shows what Home
Assistant builds from a home: floors with their areas, area cards with
temperature, and the summary views for lights, climate, security, media
players, maintenance, weather and energy.

The demo config provides the floors, areas and entities the strategies
need, including the temperature and humidity sensors of each area, and a
lock and a sprinkler as favorites.

Switching demos is a tile in the favorites section, so the demo looks
like a dashboard instead of carrying a card that no real home page would
have. Its feature row has the button to move to the next demo.

Demo navigation is fixed alongside it: navigate resolves paths like the
browser does for pushState and keeps query parameters in the URL query
instead of inside the hash, so panels can read them, and the route now
follows popstate, which is the only event a traversal fires when the
query changes too.

---------

Co-authored-by: Claude <[email protected]>
2026-07-26 17:41:30 +02:00
karwosts 39e70ff315 Show empty form errors (#53313) 2026-07-26 15:19:22 +00:00
Paulus SchoutsenandClaude Fable 5 14fd9114d6 Allow opening a specific demo via URL and document demo navigation for agents (#53281)
* Allow opening a specific demo via URL and document demo navigation for agents

Add a demo query parameter so a specific demo configuration can be
opened directly, e.g. /?demo=arsaboo. Add demo/AGENTS.md documenting the
demo URL scheme (demo selection and hash-based page routing), linked
from the root agent guide.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01V3oj5uaCRRaoXRd5iEffhi

* Merge demo slugs into the demoConfigs registry

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01V3oj5uaCRRaoXRd5iEffhi

* Key demoConfigs by slug

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01V3oj5uaCRRaoXRd5iEffhi

* Add demos index of slugs and drop confProm temporary

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01V3oj5uaCRRaoXRd5iEffhi

* Track selected demo by slug instead of index

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01V3oj5uaCRRaoXRd5iEffhi

* Restore original setDemoConfig flow and drop slug lowercasing

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01V3oj5uaCRRaoXRd5iEffhi

---------

Co-authored-by: Claude <[email protected]>
2026-07-26 17:15:10 +02:00
renovate[bot] 406a0b2bad Update dependency lint-staged to v17.2.0 (#53312)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-26 16:26:33 +02:00
Paulus SchoutsenandClaude 4c86785d21 Fix mocked entity states and demo config switching (#53300)
Three small demo/mock fixes:

- Mocked entities dropped unit_of_measurement and state_class when
  writing to the state machine, so demo sensors rendered without a unit
  and the mocked history returned a single state for them
- The energy consumption sensor entity id had a stray tab, which fails
  entity id validation in cards that render it
- Switching demos saved the dashboard config before the new registries
  and entities reached the dashboard, so dashboard strategies generated
  against the previous data


Claude-Session: https://claude.ai/code/session_01KZ6ydA22VeQndgynH4SxCV

Co-authored-by: Claude <[email protected]>
2026-07-26 16:25:37 +02:00
renovate[bot] 2aeb522eed Update dependency color-name to v2.1.1 (#53297)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-26 09:18:43 +00:00
Paulus SchoutsenandClaude Opus 5 bef1c0def6 Recompute sections view column count when the config changes (#53301)
* Recompute sections view column count when the config changes

The sections view element is reused when navigating between two sections
views, so a view with a different max_columns kept the column count of the
previous view until a resize made the ResizeObserver fire again.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KZ6ydA22VeQndgynH4SxCV

* Measure the host in the resize callback instead of the observer entries

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KZ6ydA22VeQndgynH4SxCV

* Clamp the column count to the config instead of caching it in the resize callback

---------

Co-authored-by: Claude <[email protected]>
2026-07-26 09:34:56 +03:00
dependabot[bot] f7e5bdb2a0 Bump the codeql-action group across 1 directory with 2 updates (#53303)
Bumps the codeql-action group with 2 updates in the / directory: [github/codeql-action/init](https://github.com/github/codeql-action) and [github/codeql-action/analyze](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.37.0 to 4.37.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/99df26d4f13ea111d4ec1a7dddef6063f76b97e9...7188fc363630916deb702c7fdcf4e481b751f97a)

Updates `github/codeql-action/analyze` from 4.37.0 to 4.37.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/99df26d4f13ea111d4ec1a7dddef6063f76b97e9...7188fc363630916deb702c7fdcf4e481b751f97a)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-26 09:29:35 +03:00
dependabot[bot] de59237cfb Bump home-assistant/actions/helpers/verify-version from f4ca6f671bd429efb108c0f2fa0ae8af0215986c to e3fb68ebda13d88a0d695082f471ba2c83d025fb (#53304)
Bump home-assistant/actions/helpers/verify-version

Bumps [home-assistant/actions/helpers/verify-version](https://github.com/home-assistant/actions) from f4ca6f671bd429efb108c0f2fa0ae8af0215986c to e3fb68ebda13d88a0d695082f471ba2c83d025fb.
- [Release notes](https://github.com/home-assistant/actions/releases)
- [Commits](https://github.com/home-assistant/actions/compare/f4ca6f671bd429efb108c0f2fa0ae8af0215986c...e3fb68ebda13d88a0d695082f471ba2c83d025fb)

---
updated-dependencies:
- dependency-name: home-assistant/actions/helpers/verify-version
  dependency-version: e3fb68ebda13d88a0d695082f471ba2c83d025fb
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-26 09:29:13 +03:00
dependabot[bot] f778572b89 Bump release-drafter/release-drafter from 7.5.1 to 7.6.0 (#53305)
Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 7.5.1 to 7.6.0.
- [Release notes](https://github.com/release-drafter/release-drafter/releases)
- [Commits](https://github.com/release-drafter/release-drafter/compare/4d75298e00d9e34c483e5ff8c68d0ea1c1940c1e...eada3c96a64734dd381cfbda23511034e328ddb0)

---
updated-dependencies:
- dependency-name: release-drafter/release-drafter
  dependency-version: 7.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-26 09:28:55 +03:00
dependabot[bot] d2c753b589 Bump actions/setup-python from 6.3.0 to 7.0.0 (#53306)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6.3.0 to 7.0.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/ece7cb06caefa5fff74198d8649806c4678c61a1...5fda3b95a4ea91299a34e894583c3862153e4b97)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-26 09:28:35 +03:00
dependabot[bot] 8fbb38a25d Bump pypa/gh-action-pypi-publish from 1.14.0 to 1.14.1 (#53307)
Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.14.0 to 1.14.1.
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/cef221092ed1bacb1cc03d23a2d87d1d172e277b...ba38be9e461d3875417946c167d0b5f3d385a247)

---
updated-dependencies:
- dependency-name: pypa/gh-action-pypi-publish
  dependency-version: 1.14.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-26 09:27:57 +03:00
dependabot[bot] 2f6c1388e8 Bump actions/checkout from 7.0.0 to 7.0.1 (#53308)
Bumps [actions/checkout](https://github.com/actions/checkout) from 7.0.0 to 7.0.1.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0...3d3c42e5aac5ba805825da76410c181273ba90b1)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-26 09:27:39 +03:00
dependabot[bot] ced5ffdd18 Bump actions/labeler from 6.2.0 to 7.0.0 (#53309)
Bumps [actions/labeler](https://github.com/actions/labeler) from 6.2.0 to 7.0.0.
- [Release notes](https://github.com/actions/labeler/releases)
- [Commits](https://github.com/actions/labeler/compare/b8dd2d9be0f68b860e7dae5dae7d772984eacd6d...bf12e9b00b37c5c0ca2b87b79b2daf7891dbda13)

---
updated-dependencies:
- dependency-name: actions/labeler
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-26 09:27:15 +03:00
Paulus SchoutsenandClaude 5a6a16ed27 Fix gallery type errors by letting registry mocks take the demo area and floor shapes (#53302)
Let gallery mocks use the demo area and floor shapes

The gallery passed full AreaRegistryEntry and FloorRegistryEntry objects to
mockAreaRegistry and mockFloorRegistry. Those data parameters were dropped
when the registries became demo-config-owned, which broke the gallery build.

Instead of restoring the verbose registry-entry parameters, have the mocks
accept the same DemoArea and DemoFloor shapes the demo configs use and seed
the registry through setDemoAreas/setDemoFloors. The gallery fixtures now
only spell out the fields they care about, matching how the other registry
mocks take their initial data.


Claude-Session: https://claude.ai/code/session_01PP4xVL8aDg5QAefLSmxY4C

Co-authored-by: Claude <[email protected]>
2026-07-25 18:15:30 -04:00
Aidan TimsonandSimon Lamon 3d1ed43edc Automatically activate frontend updates, support accessible toast actions, publish global dirty state (#53124)
* Support accessible toast actions

* Publish global dirty state changes

* Automatically activate frontend updates

* Add baseline tests for update dependencies

* Cover update dependency behaviour

* Render primary toast actions as filled

* Test notification toast lifecycle

* Document dirty state provider ownership

* Publish dirty state from editor updates

* Aggregate connected dirty state providers

---------

Co-authored-by: Simon Lamon <[email protected]>
2026-07-25 11:18:34 +02:00
Paulus SchoutsenandClaude d682830a3e Register the hidden default dashboard panels in the demo (#53278)
Register the light, climate, security and maintenance summary panels in
the demo, hidden from the sidebar like the home panel. This makes them
routable so strategy-generated dashboards can navigate to them.


Claude-Session: https://claude.ai/code/session_01KZ6ydA22VeQndgynH4SxCV

Co-authored-by: Claude <[email protected]>
2026-07-25 11:15:05 +02:00
dependabot[bot] 863aad24fc Bump js-yaml from 5.2.1 to 5.2.2 (#53292)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 5.2.1 to 5.2.2.
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/5.2.1...5.2.2)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 5.2.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-25 11:13:12 +02:00
Paulus SchoutsenandClaude 3284633ac9 Let demo configs provide areas and floors (#53280)
Make areas and floors part of the individual demo config data instead
of a single global registry:

- DemoConfig gains optional floors and areas, applied on initial load
  and when switching demos, so each demo brings (and clears) its own
  registries
- Areas can set a temperature and humidity entity
- Mock entities can be assigned to an area via EntityInput.area_id,
  which flows into the mocked entity registry used by area filtering


Claude-Session: https://claude.ai/code/session_01KZ6ydA22VeQndgynH4SxCV

Co-authored-by: Claude <[email protected]>
2026-07-25 11:03:27 +02:00
renovate[bot] 8dd54e0aa8 Update dependency lint-staged to v17.1.1 (#53290)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-25 11:01:06 +02:00
renovate[bot] 90a79d458f Update dependency tar to v7.5.21 (#53287)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-25 11:01:04 +02:00
Joakim Plate 34dba7ea5a Normalize number entity row input (#53284)
hui-number-entity-row.ts bound the raw stateObj.state string to the
non-slider ha-input, so a state like "50.0" showed decimals on the
device page. state-card-number.ts (used by the more-info dialog)
already normalizes via Number(state).toString(); apply the same here
so both views render consistently.
2026-07-24 18:25:56 +02:00
renovate[bot]andSimon Lamon e76e7d1064 Unpin dependency glob resolution (#53282)
* Pin dependency glob to 10.5.0

* Apply suggestions from code review

Co-authored-by: Simon Lamon <[email protected]>

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Simon Lamon <[email protected]>
2026-07-24 15:39:16 +00:00
Paulus SchoutsenandClaude b6675159ae Mock the usage prediction command in the demo (#53279)
Mock usage_prediction/common_control and load the usage_prediction
component so common-controls sections in strategy dashboards render
suggested entities in the demo. Entities that don't exist in the
currently loaded demo config are filtered out by the section strategy.


Claude-Session: https://claude.ai/code/session_01KZ6ydA22VeQndgynH4SxCV

Co-authored-by: Claude <[email protected]>
2026-07-24 17:20:29 +02:00
renovate[bot] 9d96d0b4aa Update dependency @rspack/core to v2.1.5 (#53276)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-24 13:07:05 +00:00
Paulus SchoutsenandClaude Fable 5 d900cc70c5 Fix unhandled error when the Cast SDK fails to load (#53271)
* Fix unhandled error when the Cast SDK fails to load

Resolve the Cast API as unavailable when the cast_sender.js script
fails to load (offline, blocked by an ad-blocker or firewall), instead
of leaking an unhandled promise rejection. Handle the resulting
getCastManager rejection in the demo cast row, matching hui-cast-row,
so the row hides itself.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01V3oj5uaCRRaoXRd5iEffhi

* Drop redundant comment

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01V3oj5uaCRRaoXRd5iEffhi

* Simplify promise memoization with ??=

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01V3oj5uaCRRaoXRd5iEffhi

* Revert "Simplify promise memoization with ??="

This reverts commit 5527741b6a.

---------

Co-authored-by: Claude <[email protected]>
2026-07-24 13:01:46 +00:00
pcan08 837baff26c Fix My Backups navigation (#53259) 2026-07-24 14:57:41 +02:00
Petar Petrov 43b4e247af Fix tile trend-graph feature not extending unchanging values to now (#53265)
Extend tile trend-graph feature to current time for unchanged sensors
2026-07-24 12:52:06 +02:00
renovate[bot] 17def3c5ee Update dependency prettier to v3.9.6 (#53267)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-24 12:46:59 +02:00
renovate[bot] ba15879662 Update dependency @rsdoctor/rspack-plugin to v1.6.1 (#53266)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-24 12:46:53 +02:00
renovate[bot] 0046f72641 Update dependency marked to v18.0.7 (#53263)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-24 05:41:12 +00:00
renovate[bot] f66ba11705 Update dependency typescript-eslint to v8.65.0 (#53262)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-24 08:30:42 +03:00
renovate[bot] bded4341df Update dependency sinon to v22.1.0 (#53261)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-24 08:30:21 +03:00
Bram Kragten 7a6091b5e2 Surface active HTTP config slot and reverted pending state (#53166) 2026-07-23 17:59:51 +02:00
Aidan Timson 6d12672c3e Update skill guidance, move gallery to skill (#53249)
* Correct frontend component and context guidance

* Clarify frontend benchmark requirements

* Move gallery guidance into a skill

* Clarify gallery guidance ownership

* Correct context API ownership
2026-07-23 17:47:02 +03:00
495562d748 Prepare copilot environment (#53241)
* Prepare Copilot build and test environment

* Cache Playwright browsers for Copilot

* Cache deps

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Remove indefinite playwright installs

* Spacing

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-07-23 17:03:18 +03:00
Paul Bottein 5cf7fb3a3d Fix inverted and missing feature checks in lock and lawn mower (#53222) 2026-07-23 15:58:55 +03:00
dependabot[bot] b6813ce060 Bump fast-uri from 3.1.3 to 3.1.4 (#53248)
Signed-off-by: dependabot[bot] <[email protected]>
2026-07-23 10:30:41 +01:00
Paul Bottein 3a060feb82 Unify number slider threshold across rows and state cards (#53224)
* Unify number slider threshold across rows and state cards

* Add showNumberSlider test
2026-07-23 09:37:12 +02:00
Petar Petrov ab39c4dd4a Group small device flows into "Other" in sankey cards and share logic (#53235)
The water and energy sankey cards skipped device flows below a hardcoded
0.01 while still counting them in the home total, so small-but-real
devices (e.g. 0.004 m³) were misattributed to "Untracked consumption".
Adopt the power/water-flow relative-threshold + "Other"-grouping strategy
and extract the logic shared by all four cards into energy/common/sankey.
2026-07-23 08:52:54 +02:00
Petar Petrov 82167a81f7 Keep ha-qr-code legible when theme colors collide (#53246)
Ensure ha-qr-code stays legible when theme colors collide
2026-07-23 09:43:31 +03:00
karwostsandPetar Petrov 1f14f8689c Cleanup some toggle behavior (#53242)
* Cleanup some toggle behavior

* fix tests

* prior behavior did not consider off

* Revert "prior behavior did not consider off"

This reverts commit 59cc93d308.

* Attempt rearranging features to address bundle growth failure

* Revert a no-longer-needed change to setup.ts

* Add test

* test

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-07-23 06:09:03 +00:00
karwosts 56966ee04b Add uom to selector-selector number (#53245) 2026-07-23 08:45:44 +03:00
Aidan Timson 598a987ba5 Share dependencies across E2E jobs (#53114)
* Share dependencies across E2E jobs

* Add container-compatible dependency cache

* Use one dependency cache key

* Centralise dependency cache preparation

* Separate Playwright dependency cache
2026-07-23 08:19:23 +03:00
Paul Bottein 8775d3f4c5 Use ha-form conditional field visibility in dashboard editors (#53239)
* Use ha-form conditional field visibility in dashboard editors

* Keep view and section editors on localize context
2026-07-22 16:09:17 +01:00
Paul Bottein 2771a565b9 Rename ha-form conditional field to visible and skip it in config flow submission (#53168)
* Skip hidden fields in config flow submission

* Resolve hidden fields until stable so they hold no value

* Rename ha-form conditional field from `hidden` to `visible`
2026-07-22 16:06:03 +02:00
Petar Petrov d3505cece0 Fix missing app update button on app info page (#53238)
Fix missing app update button by resolving update entity reactively
2026-07-22 15:17:34 +02:00
8579f77c12 Add demo theme persistence tests (#53237)
* Add demo theme persistence tests

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Use shared demo theme storage key in e2e tests

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-07-22 15:50:08 +03:00
Aidan Timson 6249e037ed Add ask assist command action to quick search (#53234)
* Add ask assist action to quick search and support params in dialog

* Support native android

* Group Ask Assist with quick search commands

* Hide Ask Assist when native Assist is active

* Test Ask Assist from quick search

* Fix

* Use new test structure
2026-07-22 15:18:04 +03:00
Paul Bottein 8beb4ee36e Migrate entities and glance card state_color to color (#53151)
* Migrate entities and glance card state_color to color

* Improve tests
2026-07-22 15:08:10 +03:00
Maarten Lakerveld 58ded99773 Onboarding survey (#53236)
Use new OHF shortlink service
2026-07-22 12:26:54 +02:00
Timothy 0d2b99b3a5 Disable LaunchScreen for mobile (#53171)
* Disable LaunchScreen for mobile

* Apply suggestions
2026-07-22 12:36:41 +03:00
WazoAkaRapaceandClaude Opus 4.7 4be7a32148 Fix energy graph off-by-one colors with export-only grid source (#53145)
Fix energy usage graph off-by-one colors with export-only grid source

When a grid source configured without an import sensor (export-only) was
listed before other grid sources, the energy usage graph card assigned
color indices based on the filtered `statIds.from_grid` array — skipping
that source — instead of the positional index in the user's energy
sources config. This shifted every subsequent grid source's color by one
relative to the energy sources table card, which uses positional indices.

Populate `colorIndices.from_grid` and `colorIndices.to_grid` during the
source loop using a positional `gridIdx` counter, so import-only and
export-only grid sources no longer shift the colors of sources that
follow them.

Co-authored-by: Claude Opus 4.7 <[email protected]>
2026-07-22 11:43:04 +03:00
Aidan Timson e47cebcf6e Workflows shared node modules cache (#53113)
* Benchmark shared dependency cache

* Avoid restoring warm producer cache

* Benchmark build with shared dependencies

* Use shared dependencies in CI

* Use one dependency cache key

* Allow manual CI runs

* Fall back when dependency cache is unavailable

* Keep dependency cache fallbacks fast
2026-07-22 10:16:08 +03:00
Petar Petrov e8bb029d7e Fix excessive y-axis decimals on near-flat energy charts (#53229) 2026-07-22 09:07:24 +02:00
Petar Petrov 4373f016c9 Fix energy usage graph stacking order for grid + solar without battery (#53230)
* Fix energy usage graph stacking so grid consumption stays above solar

* remove useless comment
2026-07-22 09:06:31 +02:00
renovate[bot]andPetar Petrov 9820428cd3 Update dependency @material/web to v2.5.0 (#53175)
* Update dependency @material/web to v2.5.0

* Update internal style imports for @material/web 2.5.0

2.5.0 renamed the generated internal `*-styles.js` modules to
`*-styles.cssresult.js` (they still export the named `styles`
CSSResult). Point our deep imports at the new paths.

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <[email protected]>
2026-07-22 07:02:17 +00:00
karwosts 4fa09b0085 Don't present toggle as a ui_action option for untoggleable entities (#53210)
* Don't present toggle as a ui_action option for untoggleable entities

* Fix climate enums

* unmemoize

* fix test

* Add button/valve to canToggleDomain
2026-07-22 08:13:39 +03:00
Aidan Timson 5d63fad772 Migrate section and view editors to conditional visibility (#53217) 2026-07-22 08:11:08 +03:00
Aidan Timson 7f27c9a948 E2E performance improvements and consolidation (#53057)
* Run e2e suites in parallel

* Make suites run as parallel jobs in CI. Merge reports after

* Consolidate app route e2e helpers

* Move app e2e smoke data out of spec

* Tighten app e2e smoke timeouts

* Split e2e helpers by suite

* Consolidate app e2e smoke data

* Move app e2e helpers into src

* Enable workers and full paralelism to tests. Use 60% for local (4 in my case) and 1 for CI

* Shard e2e tests

* Fold e2e-local into report job

* Fix name

* Format

* Double sharding count

* Shard demo (2) and gallery (3)

* rm

* 6,4,6

* Add local sharded e2e runner

* Queue e2e benchmark runs

* Use test mode for e2e builds

* Fix e2e benchmark concurrency

* Build e2e app artifact modern only

* Build demo e2e artifact modern only

* 4/4/2 sharding

* Remove local sharded e2e runner

* Use Playwright image for e2e tests

* Remove redundant e2e test cases

* Run e2e sidebar checks concurrently

* Consolidate config link e2e checks

* Avoid duplicate gallery page waits

* Avoid slow gallery alert count wait

* Run app e2e readiness waits concurrently

* Avoid duplicate gallery readiness wait

* Restore concurrency

* Restore concurrency

* Share parallel e2e smoke registration

* Restore demo page error tracking

* Remove ineffective gallery test mode

* Remove unused route project filtering

* Remove duplicate smoke test parallel mode

* Keep page error filtering internal

* Require helper reuse in test changes

* Clarify local E2E server workflow

* Stabilize demo sidebar navigation test

* Avoid concurrent cold E2E builds

* Validate E2E worker overrides

* Restore real demo sidebar clicks

* Keep app shell error checks strict

* Limit gallery shell error filtering

* Address E2E review findings
2026-07-21 22:27:37 +02:00
Maarten Lakerveld c07264fc27 Add onboarding survey toast (#53221)
Conditions/triggers/actions use the same logic for the automations picker sorting
2026-07-21 21:54:39 +02:00
renovate[bot] 978ad69c1b Update dependency lint-staged to v17.1.0 (#53227)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-21 21:45:41 +02:00
Paul Bottein 047ebd4524 Sync entity constants with core (#53223)
* Sync entity constants with core

* Suggest mean statistics graphs for measurement_angle sensors
2026-07-21 21:45:12 +02:00
karwosts a25aa656a3 Replace feature magic numbers in media-player-model (#53214) 2026-07-21 10:04:39 +02:00
Simon Lamon 88f244b9df Replace the memoize call to fullcalendar (#53215)
Replace the memoize one
2026-07-21 10:04:13 +02:00
Artur Pragacz ad3389fd4d Use registry for Alexa name override (#53216)
Use registry aliases for Alexa
2026-07-21 09:51:01 +02:00
Aidan Timson 5e6840ed9c Add Agents label and autolabel files (#53204)
* Add Agents pull request label

* Cover all agent configuration paths
2026-07-20 18:39:58 +02:00
renovate[bot] ba287779d4 Update dependency @formatjs/intl-datetimeformat to v7.5.2 (#53212)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-20 18:33:06 +02:00
Franck Nijhof 312fc8d2fb Add the Open Home Foundation AI Policy (#53211) 2026-07-20 16:09:20 +00:00
Aidan Timson 1109ae25cb Migrate timezone picker to context (#53206) 2026-07-20 14:19:06 +00:00
Aidan Timson fd3b25d13f Migrate to conditional visibility in clock card editor and use context (#53167) 2026-07-20 15:06:28 +01:00
Petar Petrovandcopilot-swe-agent[bot] 0f31fb50f8 Wrap long logbook entries instead of truncating them (#52972)
* Wrap long logbook entries instead of truncating them

* Resolve merge conflict: use overflow-wrap with RTL-safe text-align: end

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-07-20 13:39:32 +00:00
renovate[bot] f38a6cf44b Update dependency @lokalise/node-api to v16.3.0 (#53205) 2026-07-20 13:57:32 +01:00
Aidan Timson 8eab8a5505 Update frontend agent skill guidance (#53203)
* Document current dialog contracts

* Correct frontend testing guidance

* Fix localization placeholder example
2026-07-20 13:45:23 +02:00
Marcin BauerandClaude Opus 4.8 17fa5dbabf Use secondary color for home strategy empty-state icons (#53202)
The large empty-state icons in the home, area, other-devices, and
original-states view strategies were configured with icon_color:
"primary", which painted them in the accent color. At 64px this read
as a tappable button even though the icon is purely decorative.

Removing icon_color lets the icon fall back to the card's own
--secondary-text-color, so it reads as a muted illustration.

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-20 13:44:32 +02:00
dependabot[bot] a1a15ae674 Bump actions/setup-node from 6.4.0 to 7.0.0 in /.github/actions/setup (#53200)
Signed-off-by: dependabot[bot] <[email protected]>
2026-07-20 10:46:56 +01:00
Simon Lamon b421a96eb0 Fix initial value rendering in dialog-move-datadisk.ts (#53193) 2026-07-20 09:45:50 +01:00
Simon Lamon 7dbfb2f9d2 Add CodeQL action to Dependabot groups (#53191) 2026-07-20 09:44:44 +01:00
Simon Lamon c68cd67cbd Add grouping for formatjs packages (#53192) 2026-07-20 09:44:24 +01:00
renovate[bot] 6de9841b6e Update formatjs monorepo (#53190)
* Update formatjs monorepo

* Update dependency @formatjs/intl-pluralrules to v6.3.13

* Update dependency @formatjs/intl-numberformat to v9.3.14

* Update dependency @formatjs/intl-durationformat to v0.10.18

* Update dependency @formatjs/intl-displaynames to v7.3.13

* Update dependency @formatjs/intl-datetimeformat to v7.5.1

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-19 08:06:09 +00:00
dependabot[bot] 35193447bf Bump github/codeql-action/init from 4.36.3 to 4.37.0 (#53186)
* Bump github/codeql-action/init from 4.36.3 to 4.37.0

Bumps [github/codeql-action/init](https://github.com/github/codeql-action) from 4.36.3 to 4.37.0.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/54f647b7e1bb85c95cddabcd46b0c578ec92bc1a...99df26d4f13ea111d4ec1a7dddef6063f76b97e9)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>

* Bump github/codeql-action/analyze from 4.36.3 to 4.37.0

Bumps [github/codeql-action/analyze](https://github.com/github/codeql-action) from 4.36.3 to 4.37.0.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/54f647b7e1bb85c95cddabcd46b0c578ec92bc1a...99df26d4f13ea111d4ec1a7dddef6063f76b97e9)

---
updated-dependencies:
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-19 09:42:43 +02:00
renovate[bot] 650444e92d Update dependency @lokalise/node-api to v16.2.0 (#53177)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-19 09:13:40 +02:00
dependabot[bot] da9a78f752 Bump actions/stale from 10.3.0 to 10.4.0 (#53188)
Bumps [actions/stale](https://github.com/actions/stale) from 10.3.0 to 10.4.0.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899...1e223db275d687790206a7acac4d1a11bd6fe629)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: 10.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-19 09:13:19 +02:00
dependabot[bot] 9077290b39 Bump actions/labeler from 6.1.0 to 6.2.0 (#53187)
Bumps [actions/labeler](https://github.com/actions/labeler) from 6.1.0 to 6.2.0.
- [Release notes](https://github.com/actions/labeler/releases)
- [Commits](https://github.com/actions/labeler/compare/f27b608878404679385c85cfa523b85ccb86e213...b8dd2d9be0f68b860e7dae5dae7d772984eacd6d)

---
updated-dependencies:
- dependency-name: actions/labeler
  dependency-version: 6.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-19 09:12:59 +02:00
renovate[bot] e4c6ea29b3 Lock file maintenance (#53179)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-19 09:12:40 +02:00
renovate[bot] aa57c27739 Update dependency @rsdoctor/rspack-plugin to v1.6.0 (#53174)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-18 19:12:42 +02:00
Niklas WagnerandPetar Petrov 420137478e Add manufacturer, model, and model_id filtering to entity filter selector (#29636)
* Add manufacturer, model, and model_id filtering to entity selector

* Implement suggestion from review

* fix: simplify device data type

* Nest device filtering under `device` key in entity selector

* Fix race condition when fetching data

* Avoid config entries refetch loop on fetch failure

The catch handler reset _fetchedConfigEntries to false while also
assigning _configEntries, which re-rendered the component and re-armed
the fetch guard in updated() — an unbounded, no-backoff retry loop on
persistent failure. Keep the flag set so a failed fetch is not retried
on every re-render; the connection-change handler still retries on
reconnect.

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-07-18 09:51:15 +02:00
renovate[bot] 25bc81cf1f Update dependency @rspack/core to v2.1.4 (#53170)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-17 17:38:02 +02:00
Bram Kragten 2dabc28e7f Bumped version to 20260624.6 2026-07-17 16:42:23 +02:00
Paul Bottein fd70fcef2f Fix history graph editor crash on unavailable entity (#53141) 2026-07-17 16:42:08 +02:00
Paul Bottein 9bf46415f1 Fix save button not enabling on whitespace-only entity name changes (#53138) 2026-07-17 16:42:07 +02:00
Jan-Philipp Benecke c552af4c12 Remove custom app header text color in zha group page (#53101) 2026-07-17 16:42:06 +02:00
Paul Bottein 6b0f543fdb Add conditional field visibility to ha-form (#53165) 2026-07-17 14:06:04 +01:00
Bram KragtenandStefan Agner bbd26ce5a9 Improve messaging and error handling http config (#53126)
Co-authored-by: Stefan Agner <[email protected]>
2026-07-17 14:38:25 +02:00
pcan08 d3c23dd704 Limit clock card date picker to one value per group (#53160) 2026-07-17 08:53:28 +01:00
Paulus SchoutsenandClaude 7d4e5dc03f Use /store/reload instead of legacy /addons/reload alias when checking for add-on updates (#53162)
Use /store/reload instead of legacy /addons/reload alias

Supervisor's /addons/reload is a backwards-compat alias for
/store/reload. Core now refreshes the add-on update entities after a
/store/reload call proxied through the supervisor/api websocket command,
so use the canonical endpoint.


Claude-Session: https://claude.ai/code/session_01DCaDoYyqULQbZoc226wCp3

Co-authored-by: Claude <[email protected]>
2026-07-17 03:45:51 -04:00
renovate[bot] db22be5a30 Update dependency typescript-eslint to v8.64.0 (#53164)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-17 09:44:24 +02:00
Simon Lamon b896b20409 Output different url for demo deployment (#53158)
Output different url
2026-07-17 09:38:28 +02:00
renovate[bot] cb3b528ba3 Update dependency fuse.js to v7.5.0 (#53157) 2026-07-17 08:37:35 +01:00
karwosts 2ed8e0bd0d Add activity-panel CSV download (#53154) 2026-07-17 08:31:55 +01:00
renovate[bot] adc3393422 Update dependency @lokalise/node-api to v16.1.0 (#53156)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-16 18:11:34 +00:00
TowyTowyandClaude Fable 5 06b9b08809 Skip custom rows in entities/glance card format migration (#53074)
* Skip custom rows in entities/glance card format migration

The 2026.7.0 `format` -> `time_format` migration in the entities and
glance cards was applied to every row, including `type: custom:...` rows.
Custom rows own their config schema and some use `format` with unrelated
semantics (e.g. custom:multiple-entity-row uses `format: precision1`), so
rewriting `format` to `time_format` silently drops the option and breaks
the row's rendering.

Skip rows whose type starts with `custom:` so their config is left
untouched, matching how the frontend treats custom card/row configs as
opaque elsewhere.

Fixes #52935

Co-Authored-By: Claude Fable 5 <[email protected]>

* Extract entities/glance format migration into a testable module

Move `migrateEntitiesCardConfig` and `migrateGlanceCardConfig` out of the
card element modules into a standalone `migrate-card-config.ts` so they can
be imported by unit tests without pulling in the element modules'
build-time globals. Both card modules re-export the functions, so existing
importers (the card editors) are unaffected.

Add vitest coverage for the migration: native `format` -> `time_format`
migration, custom rows left untouched, unchanged configs returned by
identity, string rows passed through, and a pre-existing `time_format`
taking precedence over the legacy `format`.

Drop the custom-row guard from the glance migration. The glance card
renders each entity directly (name/icon/state) and never instantiates
custom rows via createRowElement, so a `custom:` type on a glance entity is
inert and the guard was dead code. The entities card does render custom
rows, so its guard stays.

Co-Authored-By: Claude Fable 5 <[email protected]>

---------

Co-authored-by: Claude Fable 5 <[email protected]>
2026-07-16 13:48:44 +00:00
Bruno Pantaleão Gonçalves ece84d42dc Send frontend/loaded event to companion apps when launch screen is removed (#53150) 2026-07-16 15:22:38 +02:00
renovate[bot]andAidan Timson e031e59b31 Update dependency barcode-detector to v3.2.1 (#53144)
Co-authored-by: Aidan Timson <[email protected]>
2026-07-16 09:48:13 +01:00
Paul Bottein 5bdccd2e4a Extract repeated indexed lookups into local variables (#53143) 2026-07-16 08:40:04 +01:00
Aidan Timson be27615851 Fix E2E theme scenario preferences (#53142)
* Fix E2E theme scenario preferences

* Clarify mock theme selection
2026-07-15 18:02:52 +02:00
Paul Bottein 48f3d45a2e Fix history graph editor crash on unavailable entity (#53141) 2026-07-15 15:48:02 +01:00
Aidan TimsonandCursor Agent f2a049b7c6 Install TypeScript 7 alongside TypeScript 6 API for tooling (#53122)
Co-authored-by: Cursor Agent <[email protected]>
2026-07-15 15:22:31 +01:00
Aidan TimsonandCopilot 1e691f0b64 Add date to clock card (#28866)
Co-authored-by: Copilot <[email protected]>
2026-07-15 15:22:21 +01:00
Aidan Timson 23d7f4772a Migrate demo theme settings storage (#53139) 2026-07-15 15:47:16 +02:00
Paul Bottein bd23592e77 Fix save button not enabling on whitespace-only entity name changes (#53138) 2026-07-15 14:34:21 +01:00
Stefan AgnerandClaude Fable 5 0fe80ef5f9 Remove legacy Supervisor REST API fallbacks from data layer (#53131)
* Remove legacy Supervisor REST fallbacks from data layer

The WebSocket proxy command (supervisor/api) was added in Core 2021.2.4
and the REST fallbacks only existed because the Supervisor panel used to
ship with Supervisor itself and could run against older Core versions.
Since the panel moved into the main frontend, the frontend is
version-locked with Core and these fallback paths are unreachable.

Co-Authored-By: Claude Fable 5 <[email protected]>

* Update create session test for WebSocket-only path

Co-Authored-By: Claude Fable 5 <[email protected]>

* Fix ts-ignore placement in create session test

Co-Authored-By: Claude Fable 5 <[email protected]>

* Use Pick<HomeAssistant, "callWS"> for ingress session functions

Narrows the hass parameter so test mocks typecheck without ts-ignore.

Co-Authored-By: Claude Fable 5 <[email protected]>

---------

Co-authored-by: Claude Fable 5 <[email protected]>
2026-07-15 13:23:32 +02:00
Aidan Timson 4327871c30 Add clear/reset action to Activity panel (#53137) 2026-07-15 11:56:24 +01:00
Bruno Pantaleão Gonçalves 88381e0b11 Revert "Add App settings entry to dashboard more menu" (#53135) 2026-07-15 08:11:33 +00:00
Bruno Pantaleão Gonçalves f44590a2aa Add App settings entry to dashboard more menu (#53130) 2026-07-15 08:39:52 +01:00
Bram Kragten 1c03daac41 Add safe area handling and opt-out to custom panels and apps (#53127) 2026-07-15 08:35:54 +01:00
Yosi Levy a2216c6bf5 Minor RTL fix (#53132) 2026-07-15 08:33:08 +01:00
renovate[bot] 4a755e00ac Update dependency tar to v7.5.20 (#53133) 2026-07-15 08:28:09 +01:00
Aidan Timson 36a9da37f8 Update FormatJS dependencies (#53121) 2026-07-14 12:31:09 +02:00
renovate[bot] cee5361525 Update dependency eslint to v10.7.0 (#53116)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-14 07:12:03 +02:00
renovate[bot] 5f46594ee2 Update tsparticles to v4.3.2 (#53112)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-13 13:15:36 +02:00
renovate[bot] 58bcf1e865 Update dependency @html-eslint/eslint-plugin to v0.64.0 (#53111) 2026-07-13 10:05:02 +01:00
Simon Lamon 196d71c4f7 Update demo deployment to output unique url again (#53091) 2026-07-13 09:52:33 +01:00
Logan RosenandCopilot App 7e60fbb66e Allow dismissing clean data entry flows (#53109)
Co-authored-by: Copilot App <[email protected]>

Copilot-Session: 67dc41de-ac39-4e22-8adb-c9d35b2a5672
2026-07-13 08:34:40 +03:00
renovate[bot] cea86f0aa0 Update dependency prettier to v3.9.5 (#53107)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-13 08:13:10 +03:00
renovate[bot] 85eb2c9f6e Update dependency marked to v18.0.6 (#53106)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-12 21:31:01 +02:00
renovate[bot] b401cd1500 Update dependency @rsdoctor/rspack-plugin to v1.5.18 (#53105)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-12 21:30:39 +02:00
Raphael Hehl 598e8d4a45 Route picture-elements taps to the nearest icon or label (#52928)
* Route picture-elements taps to the nearest icon or label

* Scope picture-elements double-tap per element and add gesture tests

* Drive routed taps through the shared action handler via a container resolver

* Clear the resolved gesture when a press becomes a multi-touch

* Route conditional-nested picture-elements taps to nearest target

Mark routed element types as delegated in createStyledHuiElement so elements built inside hui-conditional-element get the same nearest-target routing and hit boxes, and collect seeds from the full rendered subtree instead of only top-level elements.
2026-07-12 11:49:58 +02:00
renovate[bot] 030d777f26 Update formatjs monorepo (#53103)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-12 09:30:44 +00:00
Jan-Philipp Benecke 194b7edf3a Remove custom app header text color in zha group page (#53101) 2026-07-12 10:17:07 +02:00
dependabot[bot]andSimon Lamon 97ed3afe4b Bump github/codeql-action/init from 4.36.2 to 4.36.3 (#53097)
* Bump github/codeql-action/init from 4.36.2 to 4.36.3

Bumps [github/codeql-action/init](https://github.com/github/codeql-action) from 4.36.2 to 4.36.3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/8aad20d150bbac5944a9f9d289da16a4b0d87c1e...54f647b7e1bb85c95cddabcd46b0c578ec92bc1a)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.36.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>

* Update CodeQL action version to v4.36.3

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Simon Lamon <[email protected]>
2026-07-12 08:49:26 +02:00
renovate[bot] 77cc3cfe32 Update dependency @formatjs/intl-durationformat to v0.10.16 (#53098)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-12 08:31:06 +02:00
Simon Lamon 1350fd3674 Use ChevronRight instead of OpenInNew icon in ZHA group device list (#53087)
Update icon
2026-07-12 08:22:04 +03:00
Simon Lamon 9a283aba78 Pass in area in ZHA initialization area picker (#53086)
* Pass in area in ZHA initialization area picker

* Fixup
2026-07-12 08:21:04 +03:00
renovate[bot] 7f04b0884b Update dependency idb-keyval to v6.3.0 (#53090)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-11 22:31:18 +02:00
renovate[bot] a4c07e5fc2 Update Yarn to v4.17.1 (#53093)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-11 22:29:15 +02:00
Bram Kragten c573669786 Bumped version to 20260624.5 2026-07-10 14:57:54 +02:00
Petar Petrov 4e1ccab159 Restore per-second updating of ha-relative-time (#53070)
Restore per-second ticking for ha-relative-time
2026-07-10 14:57:14 +02:00
Petar Petrov 347d63bce9 Wrap device automation picker option labels instead of truncating (#53065) 2026-07-10 14:57:13 +02:00
Petar Petrov a1d7b31732 Fix cloning when drag-sorting a section to the last position (#53050) 2026-07-10 14:57:12 +02:00
Petar Petrov 4d61df7ed7 Fix target picker "Add target" popover opening off to the right (#53041) 2026-07-10 14:57:11 +02:00
Petar Petrov 991dda70fc Only show solar/battery legend in energy usage graph when configured (#53030) 2026-07-10 14:57:10 +02:00
Petar Petrov 58f5480ca3 Fix escape key discarding unsaved changes in dashboard editor (#53029) 2026-07-10 14:57:09 +02:00
Petar Petrov 1f20bc0749 Fix number/input_number slider clipped in entities card at certain zooms (#53017) 2026-07-10 14:57:09 +02:00
Petar Petrov 0846cb3be3 Fix tile trend graph rendering blank when shown by a visibility condition (#53016) 2026-07-10 14:57:08 +02:00
Petar Petrov 33afb77367 Fix My redirect for AI tasks to /config/ai-tasks (#53015) 2026-07-10 14:57:07 +02:00
Petar Petrov b2f85e2595 Fix history/logbook entity selection leaking across browser tabs (#53014)
Keep history and logbook entity selection independent per tab
2026-07-10 14:57:06 +02:00
Simon LamonandPetar Petrov 09956a7d9c No need to show rename when alias is already provided (#53003)
* No need to show rename when alias is already provided

* Update src/panels/config/script/ha-script-editor.ts

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-07-10 14:57:05 +02:00
Simon Lamon 8507e222f8 Add entity update tracking again in Automation and Script editor (#53002) 2026-07-10 14:57:04 +02:00
Petar Petrov 5737480398 Match Statistic card line height to Entity card (#52981) 2026-07-10 14:57:03 +02:00
Petar Petrov 44163b9ccb Fix focus loss in text selector with multiple (#52980) 2026-07-10 14:57:03 +02:00
renovate[bot] 42e0a1e4b5 Update dependency @rspack/core to v2.1.3 (#53081)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-10 13:09:57 +02:00
renovate[bot] 438e2e5173 Update dependency typescript-eslint to v8.63.0 (#53075)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-10 08:40:54 +03:00
Petar Petrov 0548f99057 Restore per-second updating of ha-relative-time (#53070)
Restore per-second ticking for ha-relative-time
2026-07-09 22:06:47 +02:00
elcaptain ea75339392 Update ohf.svg (#53071)
replaced depreciated logo version with correct one. svg will adapt to light/dark mode.
2026-07-09 22:05:28 +02:00
AlCalzone 7e244a706b Z-Wave: create users with credentials in a single API call (#52339)
* Z-Wave: use add_user service to add users with credentials

* refactor to match backend changes
2026-07-09 06:27:25 -04:00
renovate[bot] 7911aef6c0 Update vitest monorepo to v4.1.10 (#53067)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-09 11:44:12 +03:00
renovate[bot] ed00d4ded1 Update dependency @codemirror/view to v6.43.6 (#53066)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-09 11:43:36 +03:00
Petar Petrov be55a2197e Wrap device automation picker option labels instead of truncating (#53065) 2026-07-09 10:30:28 +02:00
Arsène Reymond a73c659840 fix: weather card more info on simple click (#53064) 2026-07-09 08:23:36 +03:00
Petar Petrov 207025d9a4 Recompute Y-axis tick precision when zooming charts (#52970) 2026-07-09 07:07:41 +02:00
renovate[bot] e9431105b0 Update dependency @codemirror/state to v6.7.1 (#53061)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-09 07:04:46 +02:00
Petar Petrov 1e5560fd42 Fix search icon overlapping label in dev tools states on Safari (#52924)
* Fix search icon overlapping label in ha-input on Safari

* Remove redundant connectedCallback re-observe in ha-input
2026-07-09 06:59:20 +02:00
Petar Petrov 369e446149 Fix energy graph axis limits and bar width with sparse statistics (#52946)
* Zero-fill energy chart buckets so sparse data keeps correct axis and bar width

* Anchor fill grid on compare series when main has no data
2026-07-09 06:53:06 +02:00
Aidan Timson 318dac3bf1 Split agents.md into skills (#53048)
* Split agents into skills, keeping architecture and commands in main file with routing for agents which dont follow standards

* Rename `copy` skill to `user-facing-text`
2026-07-09 06:51:15 +02:00
Petar Petrov 8ee9c95454 Fix cloning when drag-sorting a section to the last position (#53050) 2026-07-08 12:01:52 +01:00
Aidan Timson 8ea65987a7 Clarify E2E report failures (#53052)
* Clarify E2E report retry failures

* Add failing E2E report test

* Format E2E report project names

* Remove failing E2E report test
2026-07-08 14:01:26 +03:00
Yosi Levy ada5be6af5 Various RTL fixes (#53049) 2026-07-08 12:00:56 +01:00
Aidan Timson 5bcb6628b0 Add panel route e2e coverage (#53045)
* Add panel route e2e coverage

* Fix

* Ignore playwright mcp files

* Fix

* Remove bad mock

* Fix URL constructor

* Add panel url normalization tests

* Stabilise Lovelace URL normalization tests

* Fail Lovelace URL tests faster
2026-07-08 13:59:28 +03:00
Krisjanis Lejejs 24fd2241df Fix cloud account page onboarding width (#53053) 2026-07-08 11:59:14 +01:00
Aidan Timson db0813904c Add Settings panel e2e route coverage (#53044) 2026-07-08 10:53:32 +03:00
karwosts b30668995d Suggest picture card for image entities (#53046) 2026-07-08 06:00:58 +02:00
Petar Petrov 9ba003f86a Only re-render context consumers when the selected value changes (#52885)
The consume* decorators paired @lit/context's @consume({ subscribe: true })
with @transform to narrow a context down to a single value. ContextConsumer
calls host.requestUpdate() on every provider notification, so every consumer
ran an (often empty) render cycle on every unrelated statesContext change.

Replace the built-in consumer with a small reactive controller that subscribes
the same way but leaves update scheduling to the property setter, which already
gates on hasChanged. A render is now requested only when the selected value
actually changes.
2026-07-07 18:31:34 +02:00
Krisjanis Lejejs 0536e2cd2a Sync cloud page onboarding_postponed key, update styles (#53043) 2026-07-07 14:37:38 +01:00
Ryan MounceandClaude Fable 5 0c25f061ef Fix date range picker presets rendering blank when translations load late (#53040)
The preset ranges in ha-date-range-picker were computed once in
connectedCallback(). If the component connected before the translation
chunk containing the range labels had loaded, localize() returned an
empty string for every key, collapsing all presets into a single
empty-keyed entry — the preset list rendered blank and never recovered.

Compute _ranges in willUpdate() instead, recomputing whenever _i18n,
_hassConfig, or extendedPresets changes. This also fixes the presets
not updating when the locale or timezone changes while the page is open.

Co-authored-by: Claude Fable 5 <[email protected]>
2026-07-07 13:14:05 +00:00
Petar Petrov 62e5c9dee9 Fix target picker "Add target" popover opening off to the right (#53041) 2026-07-07 14:12:11 +01:00
Krisjanis Lejejs 36fa14ee26 Redesign cloud page (#53025)
* Redesign clould page

* Fix Prettier after upgrade

* Fix formatting after merge

* Further prettier fixes
2026-07-07 16:10:04 +03:00
Petar Petrov 14294998e7 Show date picker in energy-date-selection card without energy config (#53038) 2026-07-07 13:45:30 +01:00
Aidan Timson 60549695b0 Add auto-labels for tests (#53034) 2026-07-07 14:52:25 +03:00
dependabot[bot] 41068657bd Bump home-assistant/wheels from 2026.06.0 to 2026.07.0 (#53039)
Bumps [home-assistant/wheels](https://github.com/home-assistant/wheels) from 2026.06.0 to 2026.07.0.
- [Release notes](https://github.com/home-assistant/wheels/releases)
- [Commits](https://github.com/home-assistant/wheels/compare/34957438948e0b3dcde73c77750643dadae594f5...9e17ab1ed5c4c79d8b61e29fa63de25ca2710716)

---
updated-dependencies:
- dependency-name: home-assistant/wheels
  dependency-version: 2026.07.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-07 11:35:50 +00:00
renovate[bot] 7d11f283d2 Update dependency @codemirror/view to v6.43.5 (#53037)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-07 13:28:54 +02:00
0927a55a0c Merge Port 8123 feature branch to dev (#53022)
* Add HTTP server settings to the network panel (#51981)

* Fix focus loss in ha-input-multi when items change

* Add HTTP server settings to the network panel

* Surface fetch errors and validate before saving in HTTP config form

* Update src/panels/config/network/ha-config-http-form.ts

Co-authored-by: Paul Bottein <[email protected]>

* Group HTTP form fields into collapsible sections

* Add bottom margin to ha-input-multi add button

* Only apply add-button margin when helper text is present

* Update HTTP config form to new WebSocket API

---------

Co-authored-by: Paul Bottein <[email protected]>

* HTTP config: confirm or revert pending changes after restart (#52452)

* HTTP config: prompt admin to confirm or revert pending changes after restart

After saving HTTP server settings, core now writes the new config as pending,
restarts Home Assistant, and keeps the previous stable config as a recovery
fallback. The frontend now:

- Reads {stable, pending} from http/config and adds a promoteHttpConfig call.
- Asks the admin to confirm before saving (since saving now auto-restarts).
- After reconnect, shows a non-dismissable popup for admins with the changed
  fields, where Confirm promotes pending -> stable and Revert clears pending
  (which triggers another restart).
- Renders an info banner above the form whenever pending is set.

* Drop pending banner and pending handling from HTTP form

The popup blocks any other interaction while pending exists, so the form
is only reachable when pending is null. Stop fetching/displaying the
pending config and the unconfirmed-config banner.

* Use HTTP settings in dialog title

* Show auto-revert countdown in HTTP pending-config dialog (#52799)

* Show auto-revert countdown in HTTP pending-config dialog

Surface the new revert_at deadline (core PR #174428) in the popup that
opens after saving HTTP server settings. While pending, the dialog shows
a ticking 'Settings will revert in M:SS.' line; when the deadline passes
it switches into a reverted state with an info alert and a Close button.
Confirm/Revert remain available until the deadline.

* Add bottom margin to ha-alert in pending-config dialog

Without it the changes list sits flush against the reverted-state info
alert.

* text tweak

* Render under-a-minute revert countdown as '45 seconds'

secondsToDuration returns a bare '45' for under-a-minute durations, so
the line read 'Settings will revert in 45.'. formatNumericDuration uses
Intl unit formatting in that range, giving 'Settings will revert in
45 seconds.', and keeps the M:SS format above one minute.

* Fix Prettier formatting in dialog-http-pending-config.ts and ha-config-http-form.ts

---------

Co-authored-by: Paul Bottein <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-07-07 13:27:54 +02:00
Aidan Timson 9e75f9282e Extract shared workflow steps into composite actions (#52982) 2026-07-07 12:25:08 +01:00
Petar Petrov 56af189032 Hide external-link icon on internal repairs "Learn more" links (#53035) 2026-07-07 12:16:02 +01:00
Petar Petrov 02c99dd61d Only show solar/battery legend in energy usage graph when configured (#53030) 2026-07-07 12:13:02 +01:00
Petar Petrov f00342d522 Fix number/input_number slider clipped in entities card at certain zooms (#53017) 2026-07-07 12:12:00 +01:00
Petar Petrov 5538be0d0a Fix escape key discarding unsaved changes in dashboard editor (#53029) 2026-07-07 12:03:12 +01:00
Norbert Rittel 96b5c2910e Use more user-friendly 'Fit mode' options in Picture entity card (#53024)
More user-friendly 'Fit mode' options
2026-07-07 12:02:50 +03:00
Yosi Levy 30c44403de Fix RTL in selection in date time picker (#53020) 2026-07-06 16:27:14 +03:00
Petar Petrov 43c16f0c77 Fix tile trend graph rendering blank when shown by a visibility condition (#53016) 2026-07-06 11:46:55 +01:00
Petar Petrov 42fe3c6f97 Fix history/logbook entity selection leaking across browser tabs (#53014)
Keep history and logbook entity selection independent per tab
2026-07-06 13:11:51 +03:00
Petar Petrov 903f954947 Round fan speed slider display to whole percentages (#53004) 2026-07-06 11:08:54 +01:00
Petar Petrov 50e6691c30 Fix My redirect for AI tasks to /config/ai-tasks (#53015) 2026-07-06 11:08:41 +01:00
Simon Lamon b0e8d45003 Add entity update tracking again in Automation and Script editor (#53002) 2026-07-06 08:33:56 +01:00
Simon LamonandPetar Petrov 14e7f434e0 No need to show rename when alias is already provided (#53003)
* No need to show rename when alias is already provided

* Update src/panels/config/script/ha-script-editor.ts

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-07-06 05:47:35 +00:00
Raman GuptaandClaude Fable 5 535b1b03f2 Fix Z-Wave JS config parameter value type (#53011)
* Fix Z-Wave JS config parameter value type

Type ZWaveJSNodeConfigParam.value as number | null instead of any,
matching what the backend sends. This surfaced two comparison bugs:

- The enumerated picker no-op check compared the stored number against
  the picker's string value, so it never matched and re-selecting the
  current option re-sent the command to the device.
- The numeric input guard coerced null (unknown value) to 0, so
  entering 0 for a parameter with an unknown value was ignored.

Co-Authored-By: Claude Fable 5 <[email protected]>

* Treat empty numeric input as invalid instead of 0

Co-Authored-By: Claude Fable 5 <[email protected]>

---------

Co-authored-by: Claude Fable 5 <[email protected]>
2026-07-06 08:22:10 +03:00
dependabot[bot] 14db6c99fe Bump actions/cache from 5.0.5 to 6.1.0 (#52999)
Bumps [actions/cache](https://github.com/actions/cache) from 5.0.5 to 6.1.0.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/27d5ce7f107fe9357f9df03efb73ab90386fccae...55cc8345863c7cc4c66a329aec7e433d2d1c52a9)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-05 11:06:13 +03:00
dependabot[bot] 97226acab9 Bump release-drafter/release-drafter from 7.4.0 to 7.5.1 (#52998)
Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 7.4.0 to 7.5.1.
- [Release notes](https://github.com/release-drafter/release-drafter/releases)
- [Commits](https://github.com/release-drafter/release-drafter/compare/ed4bc48ec97379be2258e7b7ac2624a3e26ab809...4d75298e00d9e34c483e5ff8c68d0ea1c1940c1e)

---
updated-dependencies:
- dependency-name: release-drafter/release-drafter
  dependency-version: 7.5.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-05 11:05:42 +03:00
dependabot[bot] df0d1a945f Bump actions/setup-python from 6.2.0 to 6.3.0 (#52997)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6.2.0 to 6.3.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/a309ff8b426b58ec0e2a45f0f869d46889d02405...ece7cb06caefa5fff74198d8649806c4678c61a1)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: 6.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-05 11:05:24 +03:00
renovate[bot] dccd798c26 Update dependency js-yaml to v5.2.1 (#52996)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-05 11:05:06 +03:00
renovate[bot] 757c7a3e7f Update tsparticles to v4.3.1 (#52992)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-04 20:06:40 +02:00
Petar Petrov 7ccd1371bf Match Statistic card line height to Entity card (#52981) 2026-07-03 17:42:30 +02:00
fe9017fbdf Clean up energy dashboard card titles and labels (#28778)
* Remove usage labels from energy cards and rename Sources to Costs

- Remove redundant "usage" text from energy card titles and labels
- Simplify Sources table labels by removing "total" text
- Rename Sources table title to Costs

* Apply suggestion from @mindfreeze

* Apply suggestion from @balloob

* Keep 'total' in source type summary labels

Addresses review feedback from @karwosts — in the detail view,
dropping "total" from labels like "Gas total" makes the summary
row ambiguous when listed alongside individual source names.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-07-03 14:33:37 +00:00
Petar Petrov 86181e293a Fix focus loss in text selector with multiple (#52980) 2026-07-03 14:35:37 +01:00
Aidan Timson 0879d01dee Reduce scope of github token in CI build steps (#52977)
Scope GITHUB_TOKEN to the CI build steps
2026-07-03 14:52:49 +03:00
Aidan Timson de358e4834 Standardise translations upload on env block for Lokalise token (#52978)
* Standardise translations.yaml on env block for Lokalise token

* Trigger translations workflow on its own file changes
2026-07-03 14:52:01 +03:00
Aidan Timson d4855bfddd Disable credential persistence in device-class sync checkout (#52976) 2026-07-03 14:51:12 +03:00
Aidan Timson ce3b38f2b4 Standardise workflow file extensions to yaml over yml (#52979)
Standardise workflow file extensions on .yaml
2026-07-03 14:50:40 +03:00
Bram Kragten e79cd0c5b2 Bumped version to 20260624.4 2026-07-03 12:29:13 +02:00
Petar Petrov 52379b39e0 Fix My link for adding an add-on repository not doing anything (#52945) 2026-07-03 12:28:54 +02:00
Franck Nijhof 656e1bea8e Refresh the template tool documentation panel (#52941)
The About templates panel still pointed at the upstream Jinja2 docs and a
single extensions page. Rewrite the intro and link to the current templating
documentation instead: the learning guide (introduction, working with states,
debugging) and the searchable template functions reference.
2026-07-03 12:28:53 +02:00
Franck Nijhof 4ef3ed2f02 Link the config pane help icon to the dedicated docs page (#52940)
For built-in triggers, conditions, and actions, the help icon in the editor
config pane (and Developer Tools) linked to the integration page. Point it at
the dedicated page for that specific trigger/condition/action instead, e.g.
/triggers/air_quality.co2_changed. Custom integrations keep their own
documentation URL.
2026-07-03 12:28:27 +02:00
Aidan Timson 18608a17ca Surface all lint failures in a single CI run (#52975) 2026-07-03 11:27:12 +01:00
Aidan TimsonandCopilot Autofix powered by AI 80bffd605f Key Playwright browser cache on installed version (#52974)
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-07-03 11:26:57 +01:00
Petar Petrov fbad0ba885 Fix double bar in energy devices detail graph at start of day (#52939) 2026-07-03 12:25:06 +02:00
Petar Petrov c892691344 Add My links for infrared and radio frequency config panels (#52931) 2026-07-03 12:25:05 +02:00
Petar Petrov 811b7c7d98 Allow negative number entry in number selector on iOS (#52925)
Allow entering negative numbers in number selector on iOS
2026-07-03 12:24:37 +02:00
renovate[bot] f4778bef29 Update dependency @rspack/core to v2.1.2 (#52973) 2026-07-03 10:34:03 +01:00
Petar Petrov 0533b11816 Fix My link for adding an add-on repository not doing anything (#52945) 2026-07-03 10:17:55 +01:00
github-actions[bot]andMindFreeze 5f1e495203 Update numeric sensor device classes (#52969)
Co-authored-by: MindFreeze <[email protected]>
2026-07-03 05:41:21 +00:00
Aidan Timson 6f1b4fdc6c Add actionlint check for workflow files (#52958) 2026-07-03 08:37:05 +03:00
Aidan TimsonandCopilot Autofix powered by AI 67e1ca3f43 Add dev scripts and background support for agents (#52948)
* Dont open demo

* Scripts to run script/develop*

* Scripts for dev demo and gallery

* Background wrapper for agents with `--background`

* Background `yarn dev` and `dev:serve` for agents

* Dedupe lifecycle functions

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-07-03 08:31:58 +03:00
Aidan Timson 36330d8220 Update CodeQL workflow to current v4 template standard (#52957) 2026-07-03 08:25:49 +03:00
renovate[bot] 0df3919a49 Update dependency fs-extra to v11.3.6 (#52965)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-03 06:52:15 +02:00
renovate[bot] b5e03b23b9 Update dependency typescript-eslint to v8.62.1 (#52966)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-03 06:52:02 +02:00
renovate[bot] ca1ab06384 Update dependency prettier to v3.9.4 (#52967)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-03 06:51:49 +02:00
renovate[bot] fb7ed8bfd4 Update dependency minify-literals to v2.1.0 (#52968)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-03 06:51:34 +02:00
Aidan TimsonandNorbert Rittel b72b6c77bf Developer Tools -> Tools: Frontend panels (#52927)
* Rename

* Rename developer tools element tags and imports

* Point config panel routing at /config/tools

* Redirect old developer tools URLs to /config/tools

* Add tools my-link redirects

* Rename developer tools panel to Tools

* Update e2e tests for the tools panel

* Update developer tools link in issue template

* Rename developer tools translation keys to tools

* Load config fragment for statistics repairs

* Update bug report description

* Redirect old developer tools URLs on initial load and add tools e2e tests

* Casing

Co-authored-by: Norbert Rittel <[email protected]>

---------

Co-authored-by: Norbert Rittel <[email protected]>
2026-07-02 19:43:52 +02:00
Petar Petrov 7f0ddae91e Allow negative number entry in number selector on iOS (#52925)
Allow entering negative numbers in number selector on iOS
2026-07-02 19:42:03 +02:00
Petar Petrov 71e4303fa5 Fix double bar in energy devices detail graph at start of day (#52939) 2026-07-02 19:39:17 +02:00
Aidan Timson 9bb7704a3a Add e2e app tests for sidebar and map (#52950)
* Add app e2e sidebar and map coverage

* Add more app e2e sidebar coverage
2026-07-02 19:36:59 +02:00
Aidan Timson 3cc9817b90 Standardise Netlify deploy URLs with json flag (#52956) 2026-07-02 17:44:09 +02:00
renovate[bot] 674755e430 Update dependency prettier to v3.9.3 (#52947)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-02 15:14:39 +03:00
Franck Nijhof f84664909f Link the config pane help icon to the dedicated docs page (#52940)
For built-in triggers, conditions, and actions, the help icon in the editor
config pane (and Developer Tools) linked to the integration page. Point it at
the dedicated page for that specific trigger/condition/action instead, e.g.
/triggers/air_quality.co2_changed. Custom integrations keep their own
documentation URL.
2026-07-02 14:26:57 +03:00
Franck Nijhof 4fd631f229 Refresh the template tool documentation panel (#52941)
The About templates panel still pointed at the upstream Jinja2 docs and a
single extensions page. Rewrite the intro and link to the current templating
documentation instead: the learning guide (introduction, working with states,
debugging) and the searchable template functions reference.
2026-07-02 14:18:07 +03:00
renovate[bot] 18cf41b793 Update dependency @rsdoctor/rspack-plugin to v1.5.17 (#52943)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-02 14:14:44 +03:00
renovate[bot] e28788cb95 Update dependency idb-keyval to v6.2.6 (#52944)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-02 14:14:24 +03:00
Petar Petrov f81b43491d Add My links for infrared and radio frequency config panels (#52931) 2026-07-01 20:06:34 +02:00
Aidan Timson 23335fffdb Migrate hui-warning and hui-error-card to lazy context (#52926) 2026-07-01 15:32:50 +03:00
Bram Kragten 91dee86697 Bumped version to 20260624.3 2026-07-01 13:34:46 +02:00
Paul Bottein 9877377cb9 Show the event type in the logbook for event entities (#52863) 2026-07-01 13:34:34 +02:00
Paul Bottein 0a93a681e3 Show the event type in the logbook for event entities (#52863) 2026-07-01 13:32:10 +02:00
renovate[bot] 7bc2cad83e Update dependency eslint-plugin-import-x to v4.17.1 (#52923)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-01 14:17:12 +03:00
39ee60a8ef Migrate all card features to lazy context (#52922)
* Migrate all card features to lazy context

* Gate render() on _locale in hui-date-set-card-feature

* fix typo: rename supportsFanOscilatteCardFeatureFromState to supportsFanOscillateCardFeatureFromState

* Apply Prettier formatting to rebased card feature templates.

Co-authored-by: Cursor <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Cursor <[email protected]>
2026-07-01 14:16:48 +03:00
renovate[bot]andPetar Petrov e06d46e87f Update dependency prettier to v3.9.1 (#52913)
* Update dependency prettier to v3.9.1

* format

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <[email protected]>
2026-07-01 10:55:38 +00:00
renovate[bot] 45704587f3 Update tsparticles to v4.3.0 (#52919)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-01 08:39:30 +03:00
renovate[bot] f7c9033b22 Update dependency tar to v7.5.19 (#52920)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-01 08:39:05 +03:00
0edb5c5241 Show device area and entity count in connected devices list (#52914)
* Show device area and entity count in connected devices list

Display each connected (via) device's area and entity count as secondary
text, so devices that share a name (e.g. multiple Floor Heating devices)
can be told apart by their location and size. The count is read from the
full entity registry so it matches what the integration page shows.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Claude Opus 4.8 <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-06-30 14:01:18 +00:00
Bram Kragten 7a1c8c556f Bumped version to 20260624.2 2026-06-30 15:58:00 +02:00
Bram Kragten 2c3d8eb230 Show a warning when deprecated automation options where used and migr… (#52915)
Show a warning when deprecated automation options where used and migrated
2026-06-30 15:57:34 +02:00
Aidan Timson 67489affe7 Fix loading spinner position for more info weather forecast (#52903) 2026-06-30 15:57:33 +02:00
Paul Bottein 7fcbd8e245 Show dedicated icons for Cloud and Cast in Actvity and add tooltip (#52896) 2026-06-30 15:57:32 +02:00
Jan-Philipp Benecke 12a88231f3 Fix overflow issue in mobile automation target picker (#52883)
Fix overflow issue in mobile target picker
2026-06-30 15:57:31 +02:00
f66619fae6 Fix duplicate logbook entries in more info dialog after reconnect (#52880)
* Fix duplicate logbook entries after reconnect in more info dialog

When a more info dialog is left open while the app is backgrounded, the
WebSocket connection drops and reconnects on resume. The logbook stream
subscription relied on home-assistant-js-websocket's auto-resubscribe,
which replays the original subscription with its stale start_time. The
backend then resends the entire historical chunk, and ha-logbook appends
streamed events without deduplicating, so every entry was shown twice
(and a third time after another background/reconnect cycle).

Mirror the approach already used for the history stream: disable the
library's auto-resubscribe for the logbook event stream and have
ha-logbook listen for the connection "ready" event, resubscribing from a
clean state on reconnect instead of appending a replayed history chunk.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WYMwT7ZQJrjyzrNfGQyWaU

* Simplify logbook reconnect comments

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Paul Bottein <[email protected]>
2026-06-30 15:57:30 +02:00
Bram Kragten 3ca9b8b9aa Show a warning when deprecated automation options where used and migr… (#52915)
Show a warning when deprecated automation options where used and migrated
2026-06-30 16:45:33 +03:00
renovate[bot] ba10fd0447 Update dependency @codemirror/view to v6.43.4 (#52912)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-30 16:27:26 +03:00
renovate[bot] 3171e00929 Update dependency @html-eslint/eslint-plugin to v0.63.0 (#52911) 2026-06-30 08:57:12 +01:00
karwostsandPetar Petrov 032790750c Improve/unify icon behavior in entities and helpers tables (#52887)
* Improve/unify icon behavior in entities and helpers tables

* remove unused changedProp

* unused imports

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-06-30 07:41:14 +00:00
renovate[bot] 9807b9bb33 Update dependency prettier to v3.8.5 (#52905)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-30 08:23:16 +03:00
karwosts 29853ab37d Do not flicker "no items" when loading todo list (#52909) 2026-06-30 08:22:26 +03:00
renovate[bot] d9e996d901 Update dependency eslint to v10.6.0 (#52907)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-30 08:20:45 +03:00
renovate[bot] 3d1630e497 Update dependency @rspack/core to v2.1.1 (#52910)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-30 08:20:22 +03:00
renovate[bot] 301c08dc86 Update dependency js-yaml to v5.2.0 (#52908)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-30 06:35:14 +02:00
Aidan Timson bc9af7fc2f Fix loading spinner position for more info weather forecast (#52903) 2026-06-29 19:05:28 +02:00
renovate[bot] 86c1a81aca Update dependency @rspack/core to v2.1.0 (#52898)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-29 11:49:14 +03:00
renovate[bot] 05afa19a76 Update dependency js-yaml to v5.1.0 (#52899) 2026-06-29 08:08:48 +00:00
Bram KragtenandClaude Opus 4.8 66775f03dd Update dependency js-yaml to v5 (#52843)
Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-06-29 10:00:21 +02:00
renovate[bot] 53e47e58f1 Update dependency intl-messageformat to v11.2.9 (#52897)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-29 08:53:58 +03:00
Paul Bottein 7b2569346f Show dedicated icons for Cloud and Cast in Actvity and add tooltip (#52896) 2026-06-29 08:37:30 +03:00
renovate[bot] 72fe6e1cbb Update dependency tar to v7.5.17 (#52895)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-29 08:34:08 +03:00
26f270720a Fix duplicate logbook entries in more info dialog after reconnect (#52880)
* Fix duplicate logbook entries after reconnect in more info dialog

When a more info dialog is left open while the app is backgrounded, the
WebSocket connection drops and reconnects on resume. The logbook stream
subscription relied on home-assistant-js-websocket's auto-resubscribe,
which replays the original subscription with its stale start_time. The
backend then resends the entire historical chunk, and ha-logbook appends
streamed events without deduplicating, so every entry was shown twice
(and a third time after another background/reconnect cycle).

Mirror the approach already used for the history stream: disable the
library's auto-resubscribe for the logbook event stream and have
ha-logbook listen for the connection "ready" event, resubscribing from a
clean state on reconnect instead of appending a replayed history chunk.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WYMwT7ZQJrjyzrNfGQyWaU

* Simplify logbook reconnect comments

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Paul Bottein <[email protected]>
2026-06-28 21:34:07 +00:00
renovate[bot] e01bef53dc Update CodeMirror (#52894)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-28 08:16:16 +00:00
dependabot[bot] 04226dda32 Bump actions/download-artifact from 4.1.7 to 8.0.1 (#52889)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4.1.7 to 8.0.1.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/65a9edc5881444af0b9093a5e628f2fe47ea3b2e...3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: 8.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-28 10:08:55 +02:00
dependabot[bot] b8fc05d5c4 Bump actions/github-script from 7.0.1 to 9.0.0 (#52890)
Bumps [actions/github-script](https://github.com/actions/github-script) from 7.0.1 to 9.0.0.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v7.0.1...3a2844b7e9c422d3c10d287c895573f7108da1b3)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-version: 9.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-28 10:08:24 +02:00
dependabot[bot] d602e77fc3 Bump actions/checkout from 6.0.2 to 7.0.0 (#52891)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.2 to 7.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6.0.2...9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-28 10:08:04 +02:00
dependabot[bot] a19842bd4d Bump home-assistant/actions/helpers/verify-version from e91ad1948e57189485b9c1ad608af0c303946f89 to f4ca6f671bd429efb108c0f2fa0ae8af0215986c (#52893)
Bump home-assistant/actions/helpers/verify-version

Bumps [home-assistant/actions/helpers/verify-version](https://github.com/home-assistant/actions) from e91ad1948e57189485b9c1ad608af0c303946f89 to f4ca6f671bd429efb108c0f2fa0ae8af0215986c.
- [Release notes](https://github.com/home-assistant/actions/releases)
- [Commits](https://github.com/home-assistant/actions/compare/e91ad1948e57189485b9c1ad608af0c303946f89...f4ca6f671bd429efb108c0f2fa0ae8af0215986c)

---
updated-dependencies:
- dependency-name: home-assistant/actions/helpers/verify-version
  dependency-version: f4ca6f671bd429efb108c0f2fa0ae8af0215986c
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-28 10:07:40 +02:00
dependabot[bot] 13872baa8c Bump release-drafter/release-drafter from 7.3.1 to 7.4.0 (#52892)
Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 7.3.1 to 7.4.0.
- [Release notes](https://github.com/release-drafter/release-drafter/releases)
- [Commits](https://github.com/release-drafter/release-drafter/compare/693d20e7c1ce1a81d3a41962f85914253b518449...ed4bc48ec97379be2258e7b7ac2624a3e26ab809)

---
updated-dependencies:
- dependency-name: release-drafter/release-drafter
  dependency-version: 7.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-28 10:07:09 +02:00
karwosts a1aaf3fe33 Disconnect helpers table updates from hass states updates (#52878) 2026-06-27 13:49:18 +03:00
Jan-Philipp Benecke 84840dc922 Fix overflow issue in mobile automation target picker (#52883)
Fix overflow issue in mobile target picker
2026-06-27 10:20:02 +02:00
Petar Petrov 8e43688ed8 Add untracked consumption to intermediate devices in energy and water sankey cards (#52884) 2026-06-27 10:19:38 +02:00
Abílio Costa d9037b84c8 Add untracked power to intermediate upstream devices (#52882) 2026-06-27 10:11:01 +03:00
renovate[bot] c070765f54 Update dependency @rsdoctor/rspack-plugin to v1.5.16 (#52877)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-27 07:08:41 +00:00
renovate[bot] 8e5d976f7b Update CodeMirror (#52879)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-27 09:59:03 +03:00
renovate[bot] 2dbb052200 Update dependency @playwright/test to v1.61.1 (#52881)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-27 09:58:35 +03:00
TheOtherAdamandAdam Steen 3b04f29755 Handle disabled core log file (#52523)
* Handle disabled core log file

* Use typed logging config

* Address disabled log file UI review

* Align disabled log file metadata

---------

Co-authored-by: Adam Steen <[email protected]>
2026-06-26 18:49:15 +03:00
Aidan TimsonandCursor 865b5b1b80 Localize hardcoded UI strings in lovelace, logs, cloud, and media browse (#52869)
* Localize hardcoded UI strings in lovelace, logs, cloud, and media browse

Wire existing translation keys where available and add scoped keys for lovelace error sections and cloud support package privacy text.

Co-authored-by: Cursor <[email protected]>

* Keep loading ellipsis outside translatable strings

Localize the loading and preview labels without dots, then append ellipsis in the template so translators are not asked to copy punctuation.

Co-authored-by: Cursor <[email protected]>

* Fix manual entry localize key path

Use ui.components.selectors.selector.types.manual so the key resolves in en.json and TypeScript.

Co-authored-by: Cursor <[email protected]>

* Use property bindings for localized dialog and badge labels

Bind headerTitle and label as properties so localized strings pass correctly to ha-dialog and ha-badge.

Co-authored-by: Cursor <[email protected]>

* Format

* Use better path

---------

Co-authored-by: Cursor <[email protected]>
2026-06-26 05:08:55 +02:00
Aidan Timson b44c69b1b0 Add more info view smoke tests to e2e app spec (#52862)
* Add more info views to e2e app spec

* Add registry for light more info test

* Improve tests
2026-06-26 05:06:44 +02:00
Aidan Timson 27787e51f8 Add test:e2e:app:dev to not need to build for every test run (#52865)
* Add test:e2e:app:dev to not need to build for every test run

* Stop browser open

* Add test:e2e:app:dev
2026-06-26 05:05:09 +02:00
renovate[bot] dc7daf3156 Update dependency typescript-eslint to v8.62.0 (#52876)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-26 05:03:59 +02:00
renovate[bot] b898468193 Update dependency globals to v17.7.0 (#52875)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-26 05:03:42 +02:00
renovate[bot] 781aa116b8 Update dependency eslint-plugin-import-x to v4.17.0 (#52874)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-26 05:03:24 +02:00
Bram Kragten 43ff58010a Bumped version to 20260624.1 2026-06-25 16:16:23 +02:00
Copilot c391d571d7 Localize "(default)" label in Edit sidebar dialog (#52868)
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-06-25 16:15:51 +02:00
Petar Petrov 18e15f8a99 Group Sankey flow siblings under their parent to fix segment crossovers (#52867) 2026-06-25 16:15:50 +02:00
Paul Bottein dfdd55b649 Show dash for unavailable number entity in slider row (#52866) 2026-06-25 16:15:49 +02:00
Paul Bottein bed98776c3 Fix logbook padding and margin (#52864) 2026-06-25 16:15:48 +02:00
Paul Bottein ad37f1bb58 Show action labels instead of timestamps in the logbook (#52861) 2026-06-25 16:15:47 +02:00
Franck Nijhof 2a00b0d0ec Use choose selector for legacy trigger fields (#52859)
* Use choose selector for legacy trigger fields

Replace the duration-only selector on the `for` field in the state,
numeric_state, and template triggers with a choose selector that
offers both duration and template options.

Replace the hand-rolled lower_limit/upper_limit select toggle for
above/below in the numeric_state trigger with a choose selector
that switches between a fixed number and an entity reference.

Add translation entries for the choose selector toggle button labels.

* Shorten the numeric state value toggle label

Use "Value of an entity" instead of "Numeric value of another entity" for
the numeric state trigger toggle, so it stays compact.
2026-06-25 16:15:46 +02:00
Paul BotteinandClaude Opus 4.8 20efc35da3 Keep self-closing slashes when minifying svg`` templates (#52857)
Co-authored-by: Claude Opus 4.8 <[email protected]>
Co-authored-by: Claude <[email protected]>
2026-06-25 16:15:45 +02:00
Michael Hansen ac71b4c400 Add demo voice assistants and exposed entities (#52855) 2026-06-25 16:15:44 +02:00
Franck Nijhof b85422e652 Use the Jinja block comment for toggle-comment in templates (#52854)
The jinja2 editor mode is rendered on a YAML base, so Ctrl+/ inserted a "#"
line comment, which does nothing useful in a template. Give the jinja2
language a Jinja block comment token so toggle-comment wraps with {# #},
while the plain YAML mode keeps its # comment.
2026-06-25 16:15:43 +02:00
Paulus SchoutsenandClaude 4ff69aab8f Show supported frequencies column in radio frequency devices list (#52851)
Add a "Frequencies" column to the radio frequency devices (proxy) list so
users can see which frequency bands each transmitter supports. The supported
frequency ranges are formatted into a human-readable, locale-aware string
(picking Hz/kHz/MHz/GHz automatically) with a helper in the data layer.


Claude-Session: https://claude.ai/code/session_01SYyMTtBdrt7EBrVEt869Uw

Co-authored-by: Claude <[email protected]>
2026-06-25 16:15:42 +02:00
Bram Kragten ebb15d1118 Show warning when priming will not work for condition (#52709)
* Show warning when priming will not work for condition

* rename

* change to warning icon with tooltip

* review

* Update duration_to_seconds.test.ts
2026-06-25 16:15:41 +02:00
Simon Lamon 60c86899f3 Swap google-timezones-json to @vvo/tzdb (#52770) 2026-06-25 16:14:42 +02:00
Petar Petrov f8d870d6bb Group Sankey flow siblings under their parent to fix segment crossovers (#52867) 2026-06-25 16:12:52 +02:00
Copilot 4d82b352a9 Localize "(default)" label in Edit sidebar dialog (#52868)
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-06-25 16:02:29 +02:00
Paul Bottein 179b4cf77c Show dash for unavailable number entity in slider row (#52866) 2026-06-25 14:17:54 +02:00
Paul Bottein 542f07606a Fix logbook padding and margin (#52864) 2026-06-25 14:17:24 +02:00
Paul Bottein cf2c440e7b Show action labels instead of timestamps in the logbook (#52861) 2026-06-25 14:16:01 +02:00
Franck Nijhof 27fbabb71b Use choose selector for legacy trigger fields (#52859)
* Use choose selector for legacy trigger fields

Replace the duration-only selector on the `for` field in the state,
numeric_state, and template triggers with a choose selector that
offers both duration and template options.

Replace the hand-rolled lower_limit/upper_limit select toggle for
above/below in the numeric_state trigger with a choose selector
that switches between a fixed number and an entity reference.

Add translation entries for the choose selector toggle button labels.

* Shorten the numeric state value toggle label

Use "Value of an entity" instead of "Numeric value of another entity" for
the numeric state trigger toggle, so it stays compact.
2026-06-25 12:57:45 +02:00
Paul BotteinandClaude Opus 4.8 389af6e00c Keep self-closing slashes when minifying svg`` templates (#52857)
Co-authored-by: Claude Opus 4.8 <[email protected]>
Co-authored-by: Claude <[email protected]>
2026-06-25 10:31:58 +01:00
Bram Kragtenandcopilot-swe-agent[bot] 7ff4cf58e8 Split config sections from panel config, add CI for entrypoint size (#52830)
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-06-25 07:11:53 +00:00
renovate[bot] f849302876 Update dependency @rspack/dev-server to v2.1.0 (#52856)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-25 09:56:17 +03:00
Paulus SchoutsenandClaude 1db707937b Show supported frequencies column in radio frequency devices list (#52851)
Add a "Frequencies" column to the radio frequency devices (proxy) list so
users can see which frequency bands each transmitter supports. The supported
frequency ranges are formatted into a human-readable, locale-aware string
(picking Hz/kHz/MHz/GHz automatically) with a helper in the data layer.


Claude-Session: https://claude.ai/code/session_01SYyMTtBdrt7EBrVEt869Uw

Co-authored-by: Claude <[email protected]>
2026-06-25 08:08:29 +03:00
Franck Nijhof 70f0d12e43 Use the Jinja block comment for toggle-comment in templates (#52854)
The jinja2 editor mode is rendered on a YAML base, so Ctrl+/ inserted a "#"
line comment, which does nothing useful in a template. Give the jinja2
language a Jinja block comment token so toggle-comment wraps with {# #},
while the plain YAML mode keeps its # comment.
2026-06-25 08:06:54 +03:00
Michael Hansen 12bb09dad2 Add demo voice assistants and exposed entities (#52855) 2026-06-24 18:23:52 -04:00
Aidan Timson f08ffefe28 Output combined e2e report on failure to markdown comment (#52844)
* Output combined e2e report on failure to markdown comment

* Move to file, parse json file (markdown output didnt exist)

* Add syntax highlighting
2026-06-24 20:14:36 +02:00
Aidan TimsonandCopilot Autofix powered by AI 9de89278cd Move inline workflow mjs scripts to dedicated files, add to eslint config (#52846)
* Move inline workflow mjs scripts to dedicated files, add to eslint config

* Potential fix for pull request finding 'CodeQL / Incomplete multi-character sanitization'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-06-24 20:10:01 +02:00
renovate[bot] 207d997a3a Update playwright monorepo (#52839)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-24 18:16:49 +02:00
Bram Kragten 0bb32aa1b4 Provide Lit contexts to gallery demos; stop ignoring init errors (#52845) 2026-06-24 17:09:15 +02:00
Bram Kragten ba0310ee58 Show warning when priming will not work for condition (#52709)
* Show warning when priming will not work for condition

* rename

* change to warning icon with tooltip

* review

* Update duration_to_seconds.test.ts
2026-06-24 16:00:23 +02:00
Bram Kragten 7da090aec5 Merge branch 'rc' into dev 2026-06-24 15:33:18 +02:00
Bram Kragten f216d97315 Bumped version to 20260624.0 2026-06-24 15:29:46 +02:00
Aidan Timson ad21be1ace Allow middle click on dashboard views to open new tab (#52808)
* Allow opening Lovelace views in new tabs

* Allow opening Lovelace back targets in new tabs

* Review
2026-06-24 14:25:50 +02:00
Aidan Timson 811545581c Only run e2e report if jobs not cancelled (#52842) 2026-06-24 14:18:25 +02:00
Bram Kragten 807199c54b Add time and sun category to target view (#52819) 2026-06-24 14:11:21 +02:00
Bram KragtenandClaude Opus 4.8 77cef2429b Fix minify-literals build error in box-shadow gallery page (#52840)
Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-06-24 12:08:38 +00:00
Jan-Philipp BeneckeandBram Kragten b6eb4a50d9 Fix ES5 transpilation for lit-html (#52835)
Co-authored-by: Bram Kragten <[email protected]>
2026-06-24 11:59:06 +00:00
Aidan Timson 75fded1a43 Migrate entity picker to context (#52833) 2026-06-24 13:53:48 +02:00
Bram KragtenandClaude Opus 4.8 e53ffd76ac Add Playwright e2e tests (local Chromium) (#51929)
Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-06-24 13:50:47 +02:00
Petar Petrov 54c54fa5a2 Fix media player volume slider clipped at 100% in entities card (#52838) 2026-06-24 12:48:05 +01:00
Petar Petrov a4aec3a734 Replace babel-plugin-template-html-minifier with minify-literals (#52818) 2026-06-24 12:12:57 +02:00
Bram KragtenandClaude Opus 4.8 c73e735164 Fix search bar look in datatables (#52831)
Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-06-24 09:11:32 +00:00
Petar Petrov d4b1fe0c7f Roll the energy "Now" view over to the new day at midnight (#52829) 2026-06-24 10:08:41 +02:00
Dmytro Platov 8ecd350e6f Add Zigbee configuration handling and loading state to ZHA dashboard (#52697)
* Add Zigbee configuration handling and loading state to ZHA dashboard

- Introduced `findActiveZhaConfigEntry` function to filter active Zigbee config entries.
- Updated ZHAConfigDashboard to manage loading state and display a spinner while loading.
- Added UI elements for not configured state with appropriate translations.
- Created tests for `findActiveZhaConfigEntry` to ensure correct functionality.

* fix: remove unused config entry logic and update initialization checks

* Restore active config entry filter in _fetchConfigEntry

* Remove redundant config entry ternary in render
2026-06-24 06:48:18 +00:00
renovate[bot] a26de31a2d Update dependency lint-staged to v17.0.8 (#52825)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-24 07:33:20 +03:00
renovate[bot] 77110afc59 Update Node.js to v24.18.0 (#52827)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-24 07:32:55 +03:00
Paul Bottein 7b6e9ba738 Add by entity suggestions to the badge picker (#52733) 2026-06-23 21:07:14 +02:00
renovate[bot]andPetar Petrov 1b15bc721b Update babel monorepo (#52814)
* Update babel monorepo

* Migrate Core-JS polyfilling for Babel 8

Babel 8.0.1 removed preset-env's `useBuiltIns`/`corejs` options. Replace
them with the babel-plugin-polyfill-corejs3 provider directly
(`usage-global`), and pin transform-runtime's `moduleName` to
`@babel/runtime` so the provider doesn't redirect helpers to the
uninstalled `@babel/runtime-corejs3`.

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <[email protected]>
2026-06-23 15:38:07 +03:00
Bram Kragten 93a8d296a8 Move purpose-specific triggers and conditions out of labs (#52801) 2026-06-23 14:11:32 +02:00
Paul Bottein 734fed21a8 Add name detail option to activity card (#52815)
* Add name detail option to activity card

* Fix tests

* Review
2026-06-23 13:33:36 +02:00
Aidan Timson af203d640f Use helpers for related context (#52816) 2026-06-23 10:08:50 +00:00
Petar Petrov da29c8f536 Remove dead and unused hass props/bindings from migrated leaves (#52805) 2026-06-23 09:07:02 +01:00
Petar Petrov 8069596c87 Migrate registry display editors to context instead of hass (#52804) 2026-06-23 09:06:15 +01:00
Petar Petrov ace55fdb92 Migrate ha-qr-scanner to context instead of hass (#52806) 2026-06-23 09:04:51 +01:00
dae8adab98 Update babel monorepo to v8 (#52758)
* Update babel monorepo to v8

* Bugfixes option has been removed and is enabled by default

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Simon Lamon <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-06-23 09:56:55 +03:00
Paul Bottein 1522d979de Fix multi-term picker search ranking (#52807) 2026-06-23 08:15:37 +03:00
renovate[bot] 5fd253b2d3 Update dependency @types/luxon to v3.7.2 (#52812)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-23 08:12:52 +03:00
Paulus SchoutsenandClaude f7d5195161 Fix inverted managed check for cloud webhook disable (#52813)
The manage-cloudhook dialog showed "managed by an integration and cannot
be disabled" for webhooks the user enabled manually (e.g. an automation
webhook trigger), while letting integration-managed webhooks (e.g. the
mobile app) be disabled.

Core sets `managed: true` only for cloudhooks created programmatically by
an integration (via async_create_cloudhook) and `managed: false` for hooks
the user creates through the cloud panel. The dialog negated this flag, so
the message and disable link were shown for the wrong cases. Check the flag
directly so user-created hooks expose the disable link and integration
hooks show the informational message.


Claude-Session: https://claude.ai/code/session_01QuvU786Re5Rm1iCa8BhT8d

Co-authored-by: Claude <[email protected]>
2026-06-23 08:12:32 +03:00
karwosts b72791a9e2 time_format migration and enhancements in entities and glance cards (#52768)
* time_format migration and enhancements in entities and glance cards

* migration updates
2026-06-22 17:24:40 +02:00
Aidan Timson a3c0e8d519 Use related context in entity picker, send context on edit card/badge (#52798)
* Use related context in entity picker

* Include current item in context builder

* Fix

* Add tests

* Remove comment

* Support area context in card

* Add from rebase

* Add window.haContext.related to tests
2026-06-22 17:43:38 +03:00
Clément NotinandAidan Timson 19fcb9d2f7 Allow to open tabs in Developer tools to new tabs (middle-click, CTRL+Click...) (#52785)
Co-authored-by: Aidan Timson <[email protected]>
2026-06-22 14:36:49 +00:00
AlCalzone cbd90884ee Set ha-progress-ring-size before rendering (#52794)
Set ha-progress-ring-size before rendering
2026-06-22 15:33:00 +02:00
Aidan Timson fce1938f38 Add a debug to related context provider (#52793)
* Add a debug to related context provider

* context -> haContext
2026-06-22 14:34:34 +03:00
Bram KragtenandClaude Opus 4.8 24821d6f1b Sign brand images in state-badge via connection context (#52797)
* Sign brand images in state-badge via connection context

state-badge only signed entity_picture URLs when a `hass` object was
passed, calling `hass.hassUrl()` to append the brands access token.
Components migrated to Lit contexts (e.g. ha-config-updates on the
Settings → Updates page) no longer pass `hass`, so brand icon URLs like
/api/brands/integration/<domain>/icon.png were fetched without a token,
returning 403 and triggering unauthenticated-request log entries in core.

Consume connectionContext to obtain `hassUrl` so the token is added even
when `hass` isn't provided, and skip brand URLs entirely when they can't
be signed yet so no unauthenticated request fires.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Remove now-unused hass property from state-badge

With brand image signing handled via connectionContext, `hass` was only
used by state-badge to reach `hassUrl`. Drop the property entirely and
remove the `.hass` binding from all call sites; the connection context
provides `hassUrl` everywhere the component renders.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

---------

Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-06-22 14:33:24 +03:00
Petar Petrov 677d64c915 Use a picker with entity context for energy upstream device (#52788) 2026-06-22 12:12:20 +01:00
Petar Petrov fe06772a73 Pad chart Y-axis labels to consistent decimal precision (#52787) 2026-06-22 12:10:21 +01:00
Petar Petrov 170f8c371a Migrate action/service button rows to context instead of hass (#52789) 2026-06-22 12:09:32 +01:00
Petar Petrov 12841b5ff7 Migrate state-display leaves to context instead of hass (#52791) 2026-06-22 12:08:15 +01:00
Petar Petrov 5393b05636 Migrate filter components to context instead of hass (#52792) 2026-06-22 12:07:35 +01:00
Petar Petrov a384e2dbd6 Migrate UI/config leaf components to context instead of hass (#52790) 2026-06-22 12:04:20 +01:00
AlCalzone fd4936e547 Show circular progress when interviewing Z-Wave devices (#52795)
Use circular progress for interviewing Z-Wave devices
2026-06-22 13:35:40 +03:00
Bram Kragten 44d02420ae Add support for not triggered traces (#52708) 2026-06-22 11:59:39 +02:00
karwosts ebf80ecca0 Accept enter key to submit code dialog (#52784) 2026-06-22 08:11:46 +03:00
renovate[bot] bcfcc7bd5a Update tsparticles to v4.2.1 (#52786)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-22 08:05:56 +03:00
renovate[bot] f7933c31d7 Update dependency @rsdoctor/rspack-plugin to v1.5.15 (#52783)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-21 17:43:40 +02:00
HarvsG 3f4f4a5ead Clarify integration startup message in translations (#52772)
Updated the message for integration startup to clarify that not everything will be available until startup is finished.
2026-06-21 05:42:38 +00:00
renovate[bot] 44a269b87b Update tsparticles to v4.2.0 (#52776)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-21 08:34:48 +03:00
renovate[bot] 4f89056883 Update dependency @babel/helper-define-polyfill-provider to v1 (#52778)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-21 08:34:21 +03:00
Paulus SchoutsenandClaude 6a40f1965a Fix app panel flickering when waiting for app to finish starting up (#52781)
* Fix app panel flicker while waiting for app to start

Keep the loading screen up as a stable overlay while the ingress iframe
is still returning 502, and reload the iframe content in place instead
of unsetting the addon and rebuilding the whole panel each retry.

https://claude.ai/code/session_019fWWygHqYbM2H6FN9jWJu1

* Increase timeout

---------

Co-authored-by: Claude <[email protected]>
2026-06-21 08:33:36 +03:00
renovate[bot] 7e836d6cca Update fullcalendar monorepo to v6.1.21 (#52779)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-21 08:32:46 +03:00
renovate[bot] 1fab54831f Update dependency @rsdoctor/rspack-plugin to v1.5.14 (#52771)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-20 14:34:13 +02:00
Petar Petrov 4638582c6f Refactor energy dashboard card visibility to a single source of truth (#52673)
Make energy dashboard card visibility declarative via the catalog

Route the five energy view strategies and the dashboard strategy through
the shared ENERGY_CARD_CATALOG instead of re-deriving each card's
applicability conditions inline. A new isEnergyCardVisible() helper makes
the catalog the single source of truth for whether a card is shown, so the
strategies and the customise dialog can no longer disagree.

Behavior-preserving; adds a contract test pinning isEnergyCardVisible to
the catalog for every entry.
2026-06-20 09:06:35 +02:00
Franck Nijhof e5721fb134 Use singular verb for state condition matched with any (#52609)
A state condition with match "any" joins its entities with "or", but the
summary kept a plural verb for multiple entities, reading "If A or B are
on". With "or" English uses singular agreement: "If A or B is on". The
match "all" case joins with "and" and correctly stays plural.

Nest a select on a new matchAny flag inside the multiple-entities plural
branch so the verb agrees with the join. Other languages keep their
count-based plural (the extra argument is ignored). Add a test that renders
the actual en.json string to lock in the grammar.
2026-06-20 09:00:38 +02:00
Petar Petrov bfd8cb54c9 Split negative untracked energy into a toggleable series (#52698)
Negative "untracked" values (tracked devices reporting more than total
consumption, usually a meter resolution mismatch) rendered as confusing
below-zero bars in the devices detail graph. Move them into their own
"Over-reported consumption" series with its own legend item so users can
toggle them off, and only add the series when negatives actually exist.
2026-06-20 09:56:49 +03:00
Franck NijhofandSimon Lamon 89bd1058df Fix gauge card dropping negative and monetary values (#52751)
The gauge card reads its display value from the formatted state parts.
A monetary value is split into multiple value parts around the currency
symbol, so the minus sign lands in its own part. Taking only the first
value part meant a value like -182.95 GBP rendered as just "-".

Join all value parts so the full number is shown again.

Co-authored-by: Simon Lamon <[email protected]>
2026-06-20 08:45:28 +02:00
Paul Bottein 405727502f Fix negative monetary (#52766)
* Fix rendering of negative monetary values

* Fix tests
2026-06-20 08:34:47 +02:00
Marcin BauerandClaude Opus 4.8 dae105531f Fix left column resizing in add automation element dialog (#52745)
The left list column used flex: 4 against a flex: 6 right panel. Because
flex items default to min-width: auto, the right panel's content (which
varies per group) could dictate the split, so the left column width
shifted while browsing groups.

Give the left column a fixed width (flex: 0 0 360px) and let the right
panel take the rest with min-width: 0 so its content shrinks instead of
pushing the left column around.

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-20 08:09:11 +03:00
Franck Nijhof 5f790a4977 Offer category and floor names to the AI suggestion model (#52760)
The metadata suggestion schema sent the internal category and floor IDs as
the select options, so the model only saw opaque IDs and never picked one.
The result processor already maps the chosen value back to an ID by name, so
the two halves disagreed.

Offer the names as the option values instead, matching what the processor
expects, so the model can actually choose a category or floor.
2026-06-20 08:05:10 +03:00
Franck Nijhof d6c16e0736 Count not-ready Z-Wave devices separately from not included (#52757)
The network status on the Z-Wave dashboard added the not-ready nodes to
the provisioning entries and labeled the total as not included. Not-ready
nodes are included though, their interview just has not completed yet, so
this was confusing.

Report not-ready nodes as not ready and keep not included for the
provisioning entries that have not joined the network yet.
2026-06-20 08:04:11 +03:00
Franck Nijhof c562f58326 Group the time and duration input fields for screen readers (#52764)
The day, hour, minute, second, and millisecond inputs were rendered as
separate fields with a label that was not associated with them, so screen
readers announced them as unrelated inputs.

Wrap the fields in a role=group and label that group with the visible label,
so they are announced together as one labeled control.
2026-06-20 07:57:29 +03:00
Franck Nijhof ce5640d13a Fix time zone picker data gaps (UTC and Asia/Sakhalin) (#52754)
* Add UTC time zone to the time zone picker

The time zone list is built from google-timezones-json, which is missing
the bare "UTC" and "Etc/UTC" zones. Both are valid IANA identifiers and a
common server default, so an instance configured to UTC showed up as an
unknown time zone in the settings.

Add the two zones to the picker options, guarded against duplicates in
case the source list starts including them.

* Accept UTC time zone in the clock card config

The clock card validated its time_zone against the raw timezone list, so
it rejected UTC even though the picker now offers it. Validate against the
shared timezone options instead, keeping a single source.

* Correct the invalid Asia/Sakhalin time zone id

google-timezones-json ships Asia/Yuzhno-Sakhalinsk, which is not a valid
IANA identifier, so selecting it failed backend validation. Map it to the
correct Asia/Sakhalin id.
2026-06-20 07:56:15 +03:00
renovate[bot] 6ddcc83638 Update CodeMirror to v6.7.1 (#52767)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-19 22:54:11 +02:00
Franck Nijhof 396f495c9b Discard stale results in the template developer tool (#52762)
Subscribing to a template render is asynchronous and is triggered from a few
places, so two renders could overlap. The second subscription overwrote the
handle of the first, leaving it running, and its late results overwrote the
current ones. That is why the result window sometimes showed the output of a
previous template until the editor was nudged.

Track a render id and bail out (and ignore incoming results) once a newer
render has started.
2026-06-19 21:42:54 +02:00
Petar Petrov d994fd8928 Fix Assist chat freezing when thinking details are opened mid-stream (#52753)
Fix Assist chat freezing when thinking details opened mid-stream
2026-06-19 15:49:43 +02:00
Franck Nijhof 21d8fda76d Mask password values in object selector previews (#52748) 2026-06-19 14:30:57 +02:00
Bram Kragten 978c600236 Merge branch 'rc' 2026-06-19 14:26:47 +02:00
Bram Kragten 29759a6dc6 Bumped version to 20260527.7 2026-06-19 14:26:36 +02:00
Franck Nijhof bf85cb80de Auto-select first voice in required TTS voice picker (#52576)
When a voice was required and no value was set, the picker displayed the
first voice in the dropdown but kept its own value undefined and never
fired a value-changed event. As a result, the parent (for example the TTS
test card in the media browser) never learned the voice: the selected
voice id footer stayed hidden and no voice was sent on synthesis. This was
most noticeable for languages with a single available voice, where the
selection could not be changed to force an event.

Auto-select and emit the first voice when one is required and the current
value is missing or no longer valid for the loaded voices, so the value
matches what the dropdown shows. Non-required usages keep clearing the
value as before.
2026-06-19 14:26:16 +02:00
karwosts 64984cb2ed Harden helpers table against bad labels, fix registry editor (#52516)
* Harden helpers table against bad labels, fix registry editor

* Revert "Harden helpers table against bad labels, fix registry editor"

This reverts commit cf15e1da33.

* Don't attempt to render unknown labels
2026-06-19 14:25:39 +02:00
Paul Bottein 49716f4151 Replace until() in icon components with a shared async controller (#52746) 2026-06-19 14:15:54 +02:00
Aidan Timson 657bef6a75 Change dialog enter code to adaptive dialog (#52747) 2026-06-19 14:45:58 +03:00
Franck Nijhof 9edd330728 Fix inverted vertical sliders in RTL languages (#52750)
The control slider flipped its value mapping whenever the document
direction was right-to-left, including for vertical sliders. RTL only
mirrors the horizontal axis, so a vertical slider ended up upside down:
the light brightness and color temperature sliders in the more info
dialog reported the opposite of what they showed (1% gave the brightest
output, 100% the dimmest).

Only mirror for right-to-left when the slider is horizontal.
2026-06-19 14:39:53 +03:00
Petar Petrov 09e83b6450 Omit empty select fields from AI metadata suggestion task (#52749) 2026-06-19 12:40:28 +02:00
Franck Nijhof 9c3f3ed05d Stop icon components leaking memory on every state update (#52743) 2026-06-19 10:36:36 +02:00
Aidan Timson aec6c8c1e4 Effective dirty state, apply to card/badge editor (#52727)
* Effective dirty state

* Effective normalise function for those with defaults not undefined
2026-06-19 11:00:12 +03:00
Franck Nijhof 82f4ae1f08 Return to the device page from the Z-Wave node config view (#52735) 2026-06-19 10:56:21 +03:00
Franck Nijhof 2809091b44 Accept backup uploads by .tar extension, not just MIME type (#52744) 2026-06-19 07:52:05 +00:00
Simon Lamon b2dda0f739 Translate exceptions in hass api calls (#52718) 2026-06-19 07:44:06 +01:00
Franck Nijhof d64845f206 Support a list of entities in the zone trigger editor (#52738) 2026-06-19 07:36:05 +01:00
Franck Nijhof 44d929bf56 Label time trigger and condition days as days of the week (#52737) 2026-06-19 07:33:24 +01:00
Franck Nijhof 56cfff6922 Show real repeat iteration number in trace details (#52736) 2026-06-19 07:32:03 +01:00
Franck Nijhof be8782d928 Include diagnostic battery binary sensors in maintenance view (#52734) 2026-06-19 07:28:41 +01:00
renovate[bot] 2eba8425a7 Update typescript-eslint monorepo to v8.61.1 (#52740)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-19 07:23:14 +01:00
renovate[bot] 5ddc26df7a Update formatjs monorepo to v0.10.15 (#52739)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-19 07:17:11 +02:00
renovate[bot] 97516f5625 Lock file maintenance (#52741)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-19 07:16:44 +02:00
Aidan Timson e8c06b4220 Limit cover/valve card feature width to prevent overflow (#52730)
* Limit cover/valve card feature width to prevent overflow

* Remove comments and unnecessary getter
2026-06-18 17:05:27 +02:00
Paul BotteinandAidan Timson 4fd976dc8c List main entities first on the device page (#52728)
* List main entities first on the device page

* Update src/panels/config/devices/device-detail/ha-device-entities-card.ts

Co-authored-by: Aidan Timson <[email protected]>

---------

Co-authored-by: Aidan Timson <[email protected]>
2026-06-18 14:38:37 +00:00
karwosts f8d8dc4eaa Fix entities timestamp editor (#52729) 2026-06-18 14:14:27 +01:00
Petar Petrov 8ccda740ee Fix date/datetime selectors on the design gallery and align datetime fields (#52726)
* Provide i18n and config contexts to gallery ha-selector demo

* Align date and time fields in datetime selector
2026-06-18 13:25:07 +02:00
Aidan Timson 8528dd8a15 Migrate more info person, sun, weather controls to lazy context (#52706) 2026-06-18 12:26:05 +03:00
ac2f8ebce3 Add radio frequency panel (#52464)
* Add rf panel

* Tweaks

* Align canShowPage with dev PageNavigation type

* Restore page filter check in canShowPage

* Add transmitters list to radio frequency panel

Show transmitter status and a devices data table (name, type, last used)
with links to the device info page, and use the radio tower domain icon.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Update src/panels/config/integrations/integration-panels/radio_frequency/radio-frequency-transmitters.ts

Co-authored-by: Petar Petrov <[email protected]>

* adjust comments

* Rename radio frequency transmitters page to devices page

Mirror the infrared panel: rename the transmitters page to a devices
page, source the type column label from the integration's
entity_component name, fetch transmitters in the router and pass them to
both pages, and align user-facing copy to "devices".

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Handle radio frequency transmitter load errors

Wrap the transmitter fetch in try/catch and surface failures via an
alert dialog instead of leaving an unhandled rejection.

Also drop the duplicate PageNavigation.filter declaration introduced by
the dev merge (it already exists on dev).

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Claude Opus 4.8 <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-06-18 09:25:38 +00:00
renovate[bot] 1462f65f5a Update yarn monorepo to v4.17.0 (#52725)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-18 12:22:58 +03:00
renovate[bot] 3e9d3d90a1 Update vitest monorepo to v4.1.9 (#52724)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-18 09:21:56 +00:00
Aidan Timson f28898551b Reword advanced controls to more controls in siren (#52700)
Reword advanced to more in siren
2026-06-18 08:25:34 +03:00
Aidan Timson eabbcf3a95 Migrate more info lock / alarm to lazy context (#52703)
Migrate more info lock / alarm
2026-06-18 08:24:44 +03:00
Aidan Timson 01255cebc6 Remove "advanced" from security options in zwave search (#52702) 2026-06-18 08:24:17 +03:00
Aidan Timson d20e062de9 Migrate more info vaccum / lawn mower controls to lazy context (#52704) 2026-06-18 08:23:28 +03:00
Aidan Timson 835c0fa35c Migrate more info fan and light controls to lazy context (#52705) 2026-06-18 08:22:48 +03:00
Aidan Timson e308272d89 Migrate more info media controls to lazy context (#52707)
* Migrate more info media controls to lazy context

* Remove
2026-06-18 08:21:36 +03:00
renovate[bot] d2ae376058 Update Node.js to v24.17.0 (#52721)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-18 05:21:21 +00:00
fdd57645ee Add infrared panel (#52465)
* Add IR panel

* Tweaks

* Redesign infrared panel: device dashboard + table

Show a Bluetooth-style status card with the count of online IR devices,
linking to a separate data-table page that lists devices grouped from
their proxy entities. Devices expose a type (Emitter, Receiver, or
"Receiver, Emitter") and a "Last used" column derived from the most
recent entity state timestamp.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Pass localize instead of hass into _data memoizeOne

* Fix Prettier formatting in infrared-devices-page.ts

* Derive infrared devices from registries instead of infrared/list

Drop the infrared/list WebSocket call and compute the device dataset
from the entity/device registries in the dashboard router, passing it
down to the dashboard and devices pages.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Use infrared entity_component device class names for type labels

* Remove fallback strings from localize calls in infrared devices page

* Fix device class translation

* Cleanup

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-06-18 07:20:16 +02:00
karwosts 1ef1655a4c Add time_format selector to entities card entity-row-editor (#52715) 2026-06-18 08:18:31 +03:00
Paul Bottein aa1108fc41 Translate list attributes and device class in entity details (#52716) 2026-06-18 08:17:34 +03:00
karwosts e3c6a57080 Add short / long timestamp styles (#52719) 2026-06-18 08:16:34 +03:00
karwosts 1e22649ef8 Unify timestamp state domain lists (#52717) 2026-06-18 07:11:45 +02:00
karwosts 5abd04d09a Convert remaining EntityFeatures to enums (#52720) 2026-06-18 07:10:00 +02:00
karwosts a5bf35690b Add time format to entity badge (#52713) 2026-06-17 20:24:03 +02:00
karwosts d98eb47490 Decode supported features in more-info-details (#52712)
* Decode supported features in more-info-details

* Remove 'Supported features' translation entry
2026-06-17 18:33:18 +02:00
karwostsandPaul Bottein 738e92d27d Add time_format to tile card (#52450)
* Add time_format to tile card

* Updates

* incorrect type

* Apply suggestions from code review

Co-authored-by: Paul Bottein <[email protected]>

* code review feedback

* handle timestamp=0

---------

Co-authored-by: Paul Bottein <[email protected]>
2026-06-17 16:04:40 +02:00
Aidan Timson ade2e9272b Reword advanced settings to more options in helpers (#52701) 2026-06-17 15:47:24 +02:00
Simon Lamon d8ce60dfb6 Add icons to live condition test (#52458)
Add icons to live condition
2026-06-17 16:41:15 +03:00
Aidan Timson db9374925e Migrate more info climate (+ related) to lazy context (#52694)
* Migrate more info climate (+ related) to lazy context

* Remove hass
2026-06-17 13:19:46 +00:00
Aidan Timson 1bcd1293c0 Reword "advanced concept" in event trigger/action descriptions (#52699) 2026-06-17 16:07:57 +03:00
Aidan Timson b8cf061ebb Migrate more info datetime (+ related) to lazy context (#52696) 2026-06-17 16:01:01 +03:00
karwosts 6585da9a73 Fix continue_on_timeout toggle defaults in wait script actions (#52691)
Fix continue_on_timeout toggle in wait script actions
2026-06-17 13:26:21 +02:00
Paul Bottein 368df82e97 Redesign the Activity (logbook) as a timeline with entity context (#52498)
* Redesign the Activity (logbook) as a timeline with entity context

* Update color

* Refine logbook timeline layout and entry rendering

- Three layout modes in ha-logbook-entry: wide (entity → state inline),
  compact (entity/state + context/time), inline (state + cause icon + time)
- Entity name bold in wide and compact modes, consistent with tile card
- Cause icon shown inline next to the time in inline (single-entity) mode
- Unavailable state rendered as an empty circle dot
- Flash icon for entity-triggered causes
- "Show more" chevron link in logbook card, device page, and area page
- Extract _renderWide / _renderCompact / _renderInline from render()
- Scope entity-name flex layout to .line1 > .entity-name (compact only)

Co-Authored-By: Paul Bottein <[email protected]>

* Show cause icon in inline logbook entries

- Show cause icon (user avatar, trigger type, integration brand) next to
  the time in single-entity inline mode
- Use ha-trigger-icon for trigger-platform causes
- Use ha-domain-icon with brand-fallback for integration causes when
  context_domain is available, falling back to mdiPuzzle
- Tooltip with cause name on hover
- Icon size 18px, user avatar 18x18px

Co-Authored-By: Paul Bottein <[email protected]>

* Adjust cause icon sizes: 18px standalone, 16px inline with text

Co-Authored-By: Paul Bottein <[email protected]>

* Fix somes issues

* Refine logbook timeline rendering

* Fix logbook dot alignment, header link, and graph colors

* Use deterministic colors for select/input_select in logbook timeline

Assign colors by options list index instead of encounter order so
logbook dots always match the history chart colors, regardless of JS
chunk boundaries.

* Add relative time to logbook entries

Show short relative time alongside absolute in all layouts.
Cause moves to its own third line in compact when icon mode is active.

* Replace dual time display with click-to-toggle in logbook

Clicking any time value toggles between absolute (default) and relative
short format. State lives in the renderer and propagates via Lit
re-render when shouldUpdate allows it.

Date headers now show "Today · June 15" and "Yesterday · June 14"
for recent dates via Intl.RelativeTimeFormat.

* Fix time toggle not updating entries in virtualizer mode

Use @queryAll to directly update showRelative on all visible entries
after toggling, covering the virtualizer case where Lit re-render
alone does not propagate prop changes to already-rendered items.

Also remove the !item guard in _renderRow to fix the RenderItemFunction<T>
type mismatch.

* Refine logbook compact/wide layout and cause display

- Move time column to the right in wide layout
- Right-align time in compact cause row by wrapping cause+trace in meta-main
- Hide cause icon/label for automation and script entries in compact/inline mode (only show trace link)
- Make automation/script entity name always clickable (opens more-info)

* Refactor logbook cause into typed kinds with text phrases

Replace the untyped `iconPath`/`triggerPlatform` fields on `LogbookCause`
with a `kind` discriminator (`user`, `automation`, `script`, `state`,
`scheduled`, `homeassistant`, `integration`).

In timeline layout, causes now render as readable text phrases
("By Paul", "By automation: Mode nuit", "By state change: Porte entrée",
"Scheduled", "Via HomeKit") with a `·` separator before "View trace".
Entity names in those phrases are clickable when an entity id is available.

In list/inline layout, the icon badge uses the kind to pick the right
icon (avatar, robot, script, brand domain, puzzle) — no trigger-type
icon component needed anymore.

* Add show-cause mode to logbook list layout

Add a `show-cause` boolean prop to `ha-logbook-entry`, `ha-logbook-renderer`,
and `ha-logbook` that switches list mode from a compact icon badge to a full
cause phrase on a third line.

The third line uses a fixed-width prefix span and a flex-1 truncatable entity
button so long automation/script/entity names ellipsize cleanly. The trace
link always stays right-aligned on the same line.

Enable the mode in `ha-panel-logbook` so the main activity feed shows full
cause context for every entry.

* Rename logbook model identifiers to match HA conventions and clean up

- Rename resolve*/build* → compute*, kind → type, LogbookWhat → LogbookValue,
  model.what → model.value across model, renderer, and tests
- Merge EntryRenderCtx into LogbookRenderItem (extends LogbookItem) so layout
  methods receive one flat object instead of ctx.model.xxx
- Inline _causeUser, drop dead possibleEntity branch in message formatter
- Remove unused .cause and .cause-name CSS classes; fix padding-block
  inconsistency on timeline content

* Use ha-relative-time in logbook for auto-updating relative times

Replace the static relativeTime() string with <ha-relative-time> so the
displayed time updates every 60 s without a full re-render. Add a format
prop (Intl.RelativeTimeFormatStyle) to ha-relative-time to support the
short style needed by the logbook. Fix text-overflow ellipsis in the time
column by restructuring .time to use align-items: stretch with an inner
.time-content block that owns overflow/ellipsis, and display: contents on
ha-relative-time so its text participates in the parent's inline flow.

Also rename computeLogbookItem's internal param from item to entry to
avoid shadowing the outer item variable.

* Fix automation run value detection and timeline arrow display

User-triggered automation runs had context_user_id set but no source or
context_event_type, so isAutomationRun was false and the raw backend
message "triggered" (lowercase) was shown instead of the localized
"Triggered". Add context_user_id to the isAutomationRun check so all
automation runs get the proper localized value.

Restore the state arrow (→) in the timeline for all value.type === "state"
entries, including automation runs.

* Fix ha-relative-time interval and use textContent

The 60-second auto-update interval was never started when datetime is set
via Lit property binding, because connectedCallback runs before Lit sets
properties. Move the interval start/stop logic into update() watching the
datetime property change instead.

Also replace innerHTML with textContent since the relative time string is
always plain text.

* Remove comments

* Feedback
2026-06-17 13:23:08 +02:00
Aidan Timson 1d99a5dff9 Migrate more info actions to lazy context (#52693)
* Migrate more info actions to lazy context

* Restore file while hass is still needed down the deep chain
2026-06-17 12:23:52 +03:00
Aidan Timson 0ca72b763a Migrate more info toggles to lazy context (#52692) 2026-06-17 08:33:38 +00:00
Aidan Timson 31848a1efd Migrate more info cover + valve to lazy context (#52695) 2026-06-17 11:18:43 +03:00
Aidan TimsonandBram Kragten c6f79c2093 Add a pull request standards workflow (#52555)
Co-authored-by: Bram Kragten <[email protected]>
2026-06-17 08:38:24 +01:00
chli1 1a5ab1903a Add editable duration to timer more-info dialog (#52682)
Lets you set or change a timer's countdown directly from the more-info dialog via timer.start, including durations beyond the configured maximum.
2026-06-17 08:23:40 +03:00
Paulus Schoutsen a410a53524 Update app layout page (#52689) 2026-06-17 07:12:30 +02:00
karwosts 012889e51d Harden helpers table against bad labels, fix registry editor (#52516)
* Harden helpers table against bad labels, fix registry editor

* Revert "Harden helpers table against bad labels, fix registry editor"

This reverts commit cf15e1da33.

* Don't attempt to render unknown labels
2026-06-17 08:03:51 +03:00
karwosts 3b3788b722 Pin helper buttons to bottom of dialog (#52690) 2026-06-17 07:55:18 +03:00
Aidan Timson 9414bbc6ab Migrate more info update to lazy context (#52686) 2026-06-16 18:52:45 +02:00
Aidan Timson 287aabc9a3 Replace advanced with custom on share folder description (#52684) 2026-06-16 18:49:54 +02:00
Aidan Timson 2d505048c5 Less intimidating secondary text for dev tools (#52685) 2026-06-16 18:48:59 +02:00
Aidan Timson e07cbb9164 Rename Advanced options to More options on restart prompt (#52683) 2026-06-16 18:48:31 +02:00
Petar Petrov 9c56ce6386 Optimize energy devices-detail graph card data generation (#52651) 2026-06-16 12:20:38 +02:00
Petar PetrovandBram Kragten 30fd803506 Optimize power sources graph card data generation (#52652)
Co-authored-by: Bram Kragten <[email protected]>
2026-06-16 12:19:45 +02:00
Przemysław SzypowiczandPrzemysław Szypowicz 3ed9b7df8d Align scene editor entity names with the entity picker (#52517)
Co-authored-by: Przemysław Szypowicz <[email protected]>
2026-06-16 12:57:57 +03:00
Paul Bottein 1c38d80ab2 Fix flash of unformatted entity states on first load (#52663) 2026-06-16 11:42:39 +03:00
Paul Bottein 1c579e207f Add responsive column layout to device and area config pages (#52643) 2026-06-16 10:30:57 +03:00
dependabot[bot]andcopilot-swe-agent[bot] 1b27445485 Bump vite from 8.0.13 to 8.0.16 (#52662)
* Bump vite from 8.0.13 to 8.0.16

Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 8.0.13 to 8.0.16.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.0.16/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 8.0.16
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>

* Run yarn dedupe to fix tinyglobby deduplication check

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-06-16 05:34:06 +00:00
pcan08andClaude Sonnet 4.6 e977d4a9ec Align integration dashboard grid with design tokens (#52608)
* Align integration dashboard grid with design tokens

Replace hardcoded values with design tokens
Add mobile-safe min() in minmax, and add margin/margin-bottom to match
the apps page container spacing.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Remove useless margin bottom

---------

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
2026-06-16 08:27:03 +03:00
Paulus SchoutsenandClaude 001a842d2f Add the config panel to the demo (#52666)
* Add config panel with cloud to demo

Enable the config panel in the demo and add a logged-in Home Assistant
Cloud account mock so the cloud panel renders with realistic data
(subscription, remote access, text-to-speech, and webhooks).

https://claude.ai/code/session_01LuAsCpbhKpSKufH9FAHNxh

* Add rich mock data for all config panels in demo

Mock the WebSocket commands behind the remaining config panels so they
render with realistic data instead of erroring: integrations, devices,
entities, helpers, automations, scripts, blueprints, voice assistants,
zones, people, logs, backup, about, network, tags, and application
credentials. Adds coherent demo config entries, devices, and integration
manifests so the integrations and devices dashboards are populated.

* Demo: load brand images from CDN and fix more config panels

- Map brand/hardware images to the public brands.home-assistant.io CDN in
  demo mode, since there is no backend to serve the token-gated brands API.
- Honor the config entries domain filter so the Bluetooth card is no longer
  shown (and Bluetooth, which can't be mocked, stays out of the demo).
- Mock automation/script config and the trigger/condition platform
  subscriptions so the automation editor opens.
- Mock search/related so device, entity, and area pages stop erroring.

https://claude.ai/code/session_01LuAsCpbhKpSKufH9FAHNxh

* Demo: mock remaining config WS commands found by crawling

Crawled deep into every config panel (lists, detail pages, editors, and
dialogs) and mocked the WebSocket/REST commands that were still missing:

- auth/sign_path (log download)
- frontend/get_system_data
- config/entity_registry/get_entries (voice assistant expose)
- device_automation trigger/condition/action list + capabilities (device pages)
- validate_config (wired the existing config stub)
- cloud/alexa/entities and cloud/google_assistant/entities (expose)
- config/scene/config REST endpoint (scene editor)

https://claude.ai/code/session_01LuAsCpbhKpSKufH9FAHNxh

* Demo: code-split config panel mocks into a lazy chunk

The config panel mock data is no longer bundled into the demo's main entry
chunk. A loader is registered eagerly at startup and dynamically imports the
config mocks the first time a config-only WS/REST command is requested (i.e.
when the config panel is opened).

- Add mockLazyLoad(shouldLoad, loader) to the mock connection. On an unmocked
  command/path matching the predicate it awaits the loader (once) and retries,
  so there is no race between panel data fetches and mock registration.
- Move the config-only mocks behind stubs/config-panel.ts, imported lazily.
- Keep manifest/list eager since it is consumed app-wide via the manifests
  context and would otherwise pull in the chunk on the regular dashboard.

https://claude.ai/code/session_01LuAsCpbhKpSKufH9FAHNxh

---------

Co-authored-by: Claude <[email protected]>
2026-06-16 08:23:51 +03:00
Paulus SchoutsenandClaude 473be7f8c8 Allow color config on state-label-badge (#52669)
Forward the color option from StateLabelBadgeConfig through to the
underlying entity badge so legacy state-label-badges can pick a color
and pick up state-based icon coloring like hui-entity-badge.

Co-authored-by: Claude <[email protected]>
2026-06-16 08:18:53 +03:00
Tom Carpenter 0d9b257d4e Reverse import/export direction on grid neutrality gauge card (#52658)
Reverse import/export on grid neutrality gauge

Swap so that export is on the left, and import is on the right. This matches the orientation of the grid energy balance card, and means export is the negative side which visually makes more sense.
2026-06-16 08:15:15 +03:00
dependabot[bot] 22786df070 Bump launch-editor from 2.13.2 to 2.14.1 (#52661)
Bumps [launch-editor](https://github.com/vitejs/launch-editor) from 2.13.2 to 2.14.1.
- [Commits](https://github.com/vitejs/launch-editor/compare/v2.13.2...v2.14.1)

---
updated-dependencies:
- dependency-name: launch-editor
  dependency-version: 2.14.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-15 21:18:48 +02:00
renovate[bot] e5c849359b Update eslint monorepo to v10.5.0 (#52659)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-15 20:09:16 +02:00
Abílio Costa 4bfa4f2816 Add legend filter to energy usage graph card (#52485) 2026-06-15 19:42:49 +02:00
Bram Kragten afd86975d6 Fix date dedupe in statistics chart (#52656) 2026-06-15 18:10:31 +02:00
Petar Petrov 7b1eff9eef Optimize energy gas graph card data generation (#52654) 2026-06-15 16:50:17 +02:00
Petar Petrov 4f0c228756 Optimize energy solar graph card data generation (#52653) 2026-06-15 16:49:55 +02:00
Petar Petrov c86101ac6e Optimize energy data processing (#52648) 2026-06-15 16:42:25 +02:00
Petar Petrov 29fa351b16 Optimize history data processing (#52646) 2026-06-15 16:37:25 +02:00
Petar Petrov 7c67633146 Optimize energy chart line gap filling (#52645) 2026-06-15 16:36:13 +02:00
Petar Petrov 180e23ad9b Optimize statistics chart data generation (#52644) 2026-06-15 16:35:34 +02:00
Franck Nijhof 9e7ddb3e5e Preserve unchanged device, area, and floor registry entries (#52655) 2026-06-15 16:04:40 +02:00
Aidan Timson 4a0e46dc2c Subsections for gallery sidebar (#52640)
Implement sections for gallery sidebar
2026-06-15 16:38:00 +03:00
Franck Nijhof 6af0040e73 Preserve unchanged entity display entries across registry updates (#52641)
* Preserve unchanged entity display entries across registry updates

* Compare all display fields (integration reload can change source-defined ones)

* Use a generic preserveUnchangedRecord helper with deepEqual
2026-06-15 13:35:50 +00:00
Aidan Timson ba58ef6dc2 Update gallery home page content (#52642) 2026-06-15 15:30:34 +03:00
Aidan Timson fafbd7a674 Migrate last set of dialogs to dirty state provider and dialog behavior (#52639) 2026-06-15 15:26:43 +03:00
Aidan Timson 07290a5d7e Migrate 6 dialogs to dirty state provider and dialog behavior (#52637)
Migrate more dialogs to dirty state provider and dialog behavior
2026-06-15 15:23:34 +03:00
Aidan Timson 06141043a7 Migrate registry dialogs to dirty state provider and dialog behavior (#52636) 2026-06-15 15:19:18 +03:00
Aidan Timson 03e4f968b4 Migrate calendar, todo, helper dialogs to dirty state provider and dialog behavior (#52634) 2026-06-15 15:16:25 +03:00
Aidan Timson 17d4f67f69 Migrate matter,zwave,zha dialogs to dirty state provider and dialog behavior (#52633) 2026-06-15 15:12:02 +03:00
Petar Petrov 133a9171bc Add chart data processing optimization harness (#52550)
* Add deterministic fixtures and characterization tests for chart data processing

* Extract statistics chart data processing into a pure function

* Extract state history line chart data processing into a pure function

* Add benchmark suite for chart data processing

* Add chart data optimization playbook

* Point agent instructions at the chart optimization playbook
2026-06-15 12:53:01 +02:00
Franck Nijhof c2adc2b84a Use numeric timestamps instead of Date objects in history line chart data (#52631) 2026-06-15 11:22:57 +03:00
Franck Nijhof 2e3cbf6aab Index tooltip points by series in history line chart (#52630) 2026-06-15 11:16:11 +03:00
Franck Nijhof 82b2a60f32 Index chart legend datasets by id and name for O(1) lookup (#52632) 2026-06-15 11:03:36 +03:00
Franck Nijhof 2eb1811524 Don't mutate shared registry objects in the area page (#52611)
The area page resolved device and entity display names by writing them
back onto the registry entries returned by the (memoized) memberships,
which are the shared objects from hass.devices and the entity registry.
That overwrote each entry's raw name during render and leaked app-wide: an
unnamed device would get name set to the localized "Unnamed device", which
then short-circuits the entity-derived fallback elsewhere, and a device or
entity with no user name would have its name field corrupted in the
settings dialog.

Compute the display names on shallow copies and sort/render those instead,
leaving the shared registry objects untouched. The area page renders the
same names and order as before.
2026-06-15 11:00:31 +03:00
TheJulianJES 04b284159a Fix serial port selector integration domain in options flows (#52626)
* Pass the integration domain to the flow form context

In options flows the flow handler is the config entry id, not the
integration domain. Expose the resolved domain (falling back to the
handler for config flows) on the flow form context so selectors can rely
on the actual domain regardless of the flow type.

* Use the flow domain for serial port recommendations

The serial port selector marked a port as recommended by comparing
matching integrations against `context.handler`. In options flows the
handler is the config entry id, so an integration's own ports were
classified as "not recommended" and labelled "Used by <integration>".
Prefer `context.domain` (with a fallback to `handler`) so the
integration's own ports stay recommended in options flows too.

* Drop the handler fallback for the serial port selector domain

`step-flow-form` is the only context producer that sets `handler`, and it
now always sets `domain` alongside it, so the fallback never resolves to a
different value. In options flows `handler` is the config entry id anyway,
which would be the wrong value to fall back to.
2026-06-15 10:58:38 +03:00
renovate[bot] ddce581fdb Update formatjs monorepo to v7.4.9 (#52625)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-15 09:31:35 +02:00
Franck Nijhof 668a7df5cd Use American English spelling for badges behavior label (#52627) 2026-06-15 09:31:08 +02:00
Franck Nijhof d7cad1becd Add rel="noreferrer" to links opening in a new tab (#52628) 2026-06-15 09:30:22 +02:00
Franck Nijhof 1e412ad035 Replace O(n²) entity lookups with Map lookups in history and energy graph (#52629)
Replace O(n²) entity lookups with Map lookups in history merge and energy devices graph
2026-06-15 09:28:59 +02:00
Franck Nijhof 11611cd597 Hide redundant device name in group member list (#52593)
The member entity list in a group entity's more-info dialog always
prefixed each tile with the device name, even when every member belongs to
the same device (for example WLED segments under a single device), where it
adds no information.

Mirror the existing area_name handling: omit the device name when all
members share the same device, and fall back to the entity name so each
tile still has a label.
2026-06-15 09:23:44 +02:00
pcan08 0d545d744b Remove dead diagnostics code from integration card (#52606)
supportsDiagnostics and _diagnosticHandlers were no longer used in the
card template.
2026-06-14 22:03:19 +02:00
Petar Petrov f39dab2de5 Remove misleading "Total exported" line from energy usage tooltip (#52605) 2026-06-14 22:02:54 +02:00
Arsène Reymond 1527117015 fix: font-family for breadcrumb & select-anchor (#52612) 2026-06-14 21:55:32 +02:00
Franck Nijhof 26794560ac Remove unused emptyImageBase64 helper (#52614)
The emptyImageBase64 constant in src/common/empty_image_base64.ts has no
references anywhere in the codebase.
2026-06-14 21:54:45 +02:00
Franck Nijhof 976f9de8ad Remove unused timezone-datalist component (#52615)
The createTimezoneListEl helper in src/components/timezone-datalist.ts has
no references anywhere in the codebase. The google-timezones-json
dependency it used is still imported by other modules, so it is kept.
2026-06-14 21:54:23 +02:00
Franck Nijhof 6810bc5412 Remove unused scrollToTarget helper (#52616)
The default-exported scrollToTarget function in
src/common/dom/scroll-to-target.ts (a legacy copy from
paper-scroll-header-panel) has no references anywhere in the codebase.
2026-06-14 21:53:43 +02:00
Franck Nijhof a4ca54b80b Remove unused loadImg helper (#52617)
The loadImg export in load_resource.ts is not referenced anywhere; drop it
and narrow the internal _load tag type to the used values.
2026-06-14 21:52:59 +02:00
Franck Nijhof 07f0ef0ded Remove unused light helpers (#52619)
lightIsInColorMode and formatTempColor in data/light.ts are not referenced
anywhere in the codebase.
2026-06-14 21:52:25 +02:00
Franck Nijhof cf89bb32ab Remove unused replaceTileLayer helper (#52618)
Remove unused replaceTileLayer and LeafletDrawModuleType

Neither the replaceTileLayer helper nor the LeafletDrawModuleType type in
setup-leaflet-map.ts is referenced anywhere in the codebase.
2026-06-14 21:51:54 +02:00
Franck Nijhof ec5cbd16d8 Add accessible labels to entity ID copy/restore buttons (#52620)
The copy and restore icon buttons next to the entity ID field in the
entity settings dialog had no accessible name. Add descriptive labels
using two new translation keys.
2026-06-14 21:51:05 +02:00
Franck Nijhof 926abd7fc5 Replace Latin "e.g." with plain English in translations (#52621) 2026-06-14 21:50:27 +02:00
Franck Nijhof e227bbe9a2 Add tests for isTimestamp string utility (#52622) 2026-06-14 21:49:46 +02:00
Franck Nijhof f82b0b61e5 Add accessible labels to automation editor icon buttons (#52613)
Icon-only ha-icon-buttons have no accessible name, so screen readers
announce nothing. Add labels (using existing translation keys) to the
conversation trigger's add/remove sentence buttons and the integration
documentation buttons in the trigger and condition platform editors.
2026-06-14 15:21:24 +02:00
renovate[bot] a62c89ee00 Update dependency @rsdoctor/rspack-plugin to v1.5.13 (#52607)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-14 11:27:49 +02:00
Arjan 4b6d07134c Developer tools - State tab: allow to hide Device and Area columns (#52552)
* Allow to hide Device and Area columns

* Fix prettier error
2026-06-14 08:16:38 +02:00
dependabot[bot] 35829c301e Bump home-assistant/actions from 868e6cb4607727d764341a158d98872cd63fa658 to e91ad1948e57189485b9c1ad608af0c303946f89 (#52602)
Bump home-assistant/actions

Bumps [home-assistant/actions](https://github.com/home-assistant/actions) from 868e6cb4607727d764341a158d98872cd63fa658 to e91ad1948e57189485b9c1ad608af0c303946f89.
- [Release notes](https://github.com/home-assistant/actions/releases)
- [Commits](https://github.com/home-assistant/actions/compare/868e6cb4607727d764341a158d98872cd63fa658...e91ad1948e57189485b9c1ad608af0c303946f89)

---
updated-dependencies:
- dependency-name: home-assistant/actions
  dependency-version: e91ad1948e57189485b9c1ad608af0c303946f89
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-14 08:13:53 +02:00
dependabot[bot] a73f587591 Bump actions/checkout from 6.0.2 to 6.0.3 (#52603)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.2 to 6.0.3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/de0fac2e4500dabe0009e67214ff5f5447ce83dd...df4cb1c069e1874edd31b4311f1884172cec0e10)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-14 06:10:53 +00:00
dependabot[bot] 2e5f776af7 Bump home-assistant/wheels from 2025.12.0 to 2026.06.0 (#52604)
Bumps [home-assistant/wheels](https://github.com/home-assistant/wheels) from 2025.12.0 to 2026.06.0.
- [Release notes](https://github.com/home-assistant/wheels/releases)
- [Commits](https://github.com/home-assistant/wheels/compare/e5742a69d69f0e274e2689c998900c7d19652c21...34957438948e0b3dcde73c77750643dadae594f5)

---
updated-dependencies:
- dependency-name: home-assistant/wheels
  dependency-version: 2026.06.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-14 06:10:38 +00:00
dependabot[bot] e91cffe27c Bump github/codeql-action from 4.36.0 to 4.36.2 (#52601)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.36.0 to 4.36.2.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/7211b7c8077ea37d8641b6271f6a365a22a5fbfa...8aad20d150bbac5944a9f9d289da16a4b0d87c1e)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.36.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-14 06:10:18 +00:00
Sören Beye adbca5145c Fix energy graph stacking order (#52541) 2026-06-14 08:07:54 +02:00
Franck Nijhof 59d5ded6a5 Use Maps for registry lookups in automations picker (#52591)
The automations picker data builder resolved each automation's entity
registry entry by scanning the whole entity registry with find, and each
label by scanning the label registry, making both lookups scale with the
registry size for every row.

Build entity_id and label_id lookup Maps once and use them, so each row's
lookups are O(1). Behavior is unchanged.
2026-06-14 09:06:44 +03:00
Franck Nijhof daba5dd8be Retain option value type in select form field (#52594)
A config flow field guarded by vol.In([1, 5, 6]) sends numeric option
values, but the underlying select returns the chosen value as a string, and
ha-form-select forwarded that string unchanged. On submit the backend
validated "1" against [1, 5, 6] and rejected it as an invalid selection.

Map the selected value back to its original option in ha-form-select so the
source type is retained. String options are unaffected. The mapping is
extracted into matchSelectOptionValue and covered by unit tests.
2026-06-14 09:05:06 +03:00
Franck Nijhof 1e3e43ba46 Reduce per-entity work when building entity picker items (#52588)
getEntities builds the item list over every entity each time an entity
picker, the quick bar, or a target picker opens. On a large installation
that list construction did avoidable per-entity work:

- the include/exclude entity and domain filters used Array.includes,
  a linear scan per entity (O(entities x filter));
- computeRTL was recomputed for every entity although it only depends on
  the language and translation metadata;
- domainToName (a localize lookup) was called for every entity even though
  domains repeat heavily across entities.

Use Sets for the filters, hoist computeRTL out of the map, and cache the
domain name per domain. This speeds up opening pickers on large installs.
Behavior is unchanged. Add tests for getEntities, which had none.
2026-06-14 08:04:29 +02:00
Franck Nijhof e4cc1eaad2 Avoid mutating the input array in computeCssVariable (#52584)
computeCssVariable built its nested var() fallback chain with
props.reverse(), which reverses the caller's array in place. Every current
caller passes a freshly built array so there is no visible corruption
today, but mutating an input parameter is a latent trap: a shared,
memoized, or frozen array would produce wrong output or throw.

Use reduceRight to build the same chain from last to first without
mutating or copying the array. Output is unchanged. Add tests for
computeCssVariable (including a no-mutation guarantee) and computeCssValue,
which previously had no coverage.
2026-06-14 08:03:11 +02:00
Franck Nijhof 9aa687577f Use a Map for device label lookup in devices dashboard (#52590)
The devices dashboard data builder looked up each device label by scanning
the label registry with find, making it O(devices x labels x labelReg).

Build a label_id to entry Map once and use it for the lookups. Behavior is
unchanged.
2026-06-14 08:02:15 +02:00
Franck Nijhof 2556707370 Use a Set for entity-source lookup in helpers panel (#52587)
While the helpers configuration table is open, willUpdate recomputes the
helper entity list on every state change by filtering all states. The
membership test used Array.includes against the entity-source keys, a
linear scan run for every state, making the filter O(states x sources)
per state update.

Build a Set of the entity-source ids once and use Set.has for O(1)
lookups, dropping the filter to O(states + sources). Behavior is
unchanged.
2026-06-14 08:01:36 +02:00
Franck Nijhof 854c57c0e0 Prevent error logger from crashing on unparseable stack traces (#52575)
When createLogMessage received an error whose stack stacktrace-js could
not parse (for example a DOMException such as "AbortError: Transition was
skipped"), fromError threw "Cannot parse given Error object". That throw
escaped createLogMessage, so the global unhandledrejection handler logged
"Failure writing unhandled promise rejection to system log" and the
original error was never recorded.

Wrap the stacktrace extraction in a try/catch and fall back to the raw
error stack (or the provided stack fallback) so the logger stays robust
and still records the original error.
2026-06-14 09:01:31 +03:00
Franck Nijhof 055076c45e Use singular verb in zone condition summary (#52598)
The zone condition summary joins multiple entities with "or", so "If A or B
are in zone X" is grammatically wrong in English; "or" takes singular
agreement: "If A or B is in zone X".

Make both plural branches render "is" while keeping the numberOfEntities
placeholder, so it stays visible in the source language and translators can
keep a real plural where their grammar needs it.
2026-06-14 07:39:30 +02:00
Franck Nijhof d4ec72006d Use singular verb in numeric state trigger summary (#52592)
The numeric state trigger summary joins multiple entities with "or" but
switched the English verb to plural, reading "If A or B are above X". With
"or" the trigger fires when any one entity crosses the threshold, so English
uses singular agreement: "If A or B is above X".

Make both plural branches render "is" in the three English numeric_state
trigger description strings. The numberOfEntities placeholder is kept (not
replaced by a static "is") so it stays visible in the source language and
translators can keep using plural agreement where their grammar needs it.
The numeric_state condition is unchanged: it joins entities with "and" and
requires all to match.
2026-06-13 21:12:16 +02:00
renovate[bot] 393d6a8a0a Update rspack monorepo to v2.0.8 (#52595)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-13 20:42:51 +02:00
Franck Nijhof 4a030884f5 Skip entities table list rebuild on plain state changes (#52586)
While the entities configuration table is open, willUpdate rebuilt the
list of entities without a unique id on every hass update. Because each
state update produces a new states object, the oldHass.states !==
this.hass.states guard was always true, so on every state tick the panel
allocated a Set over all registry entities, iterated every state, and built
StateEntity objects, then discarded the result unless a non-registry entity
had actually been added.

Detect a newly added entity up front and only enter the rebuild when the
set of entity ids could have changed (or a registry, entity-sources, or
exposed-entities dependency changed). A plain state value change on an
existing entity can no longer trigger the rebuild. Behavior is unchanged:
the inner assignment already only ran when an entity was added.
2026-06-13 17:13:09 +02:00
pcan08andClaude Sonnet 4.6 f65596cad8 Align apps page search bar style with integrations page (#52581)
Align apps installed search bar style with integrations dashboard

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
2026-06-13 17:09:53 +02:00
Franck Nijhof 1449c17fd1 Hoist per-call allocations out of computeStateDisplay (#52585)
computeStateToPartsFromEntityAttributes runs for essentially every entity
state that is rendered, but it rebuilt several constants on every call: a
3-element domain array, a 15-element timestamp-domain array (both only used
for an includes() check), and the monetary part-type map.

Move these to module-level Set/object constants (matching the existing
STATE_COLORED_DOMAIN pattern in state_color.ts) and use Set.has(). Behavior
is unchanged; the domain lists are now named and documented.
2026-06-13 17:01:41 +02:00
Franck Nijhof ce0e6a7665 Cache Intl.NumberFormat instances in formatNumber (#52583)
formatNumberToParts, the engine behind formatNumber, built a new
Intl.NumberFormat on every call. It is invoked for essentially every
numeric state render, and constructing an Intl.NumberFormat is
comparatively expensive.

Cache the formatters in a Map keyed by (locale, options). Unlike the
single-entry memoizeOne used for the date formatters, the number format
options are derived per value, so a multi-entry cache is needed to avoid
thrashing. The number of distinct combinations is small and bounded in
practice. Output is unchanged.
2026-06-13 17:01:33 +02:00
Franck Nijhof 460dace974 Speed up bulk selection in data table (#52589)
select() looked up each id with a find over all filtered rows and checked
membership with includes on the growing checked-rows array, making a large
batch selection O(rows x ids) plus O(ids squared).

Build a row lookup Map once and track membership with a Set, dropping the
batch selection to O(rows + ids). Behavior is unchanged.
2026-06-13 16:58:37 +02:00
Franck Nijhof 7111d8a8a8 Auto-select first voice in required TTS voice picker (#52576)
When a voice was required and no value was set, the picker displayed the
first voice in the dropdown but kept its own value undefined and never
fired a value-changed event. As a result, the parent (for example the TTS
test card in the media browser) never learned the voice: the selected
voice id footer stayed hidden and no voice was sent on synthesis. This was
most noticeable for languages with a single available voice, where the
selection could not be changed to force an event.

Auto-select and emit the first voice when one is required and the current
value is missing or no longer valid for the loaded voices, so the value
matches what the dropdown shows. Non-required usages keep clearing the
value as before.
2026-06-13 16:51:57 +02:00
Franck Nijhof b96d1f2809 Center the to-do list reorder drag handle (#52582)
The reorder handle lives in the mwc list item meta slot, which is a fixed
24px tall box. The handle's vertical padding of 16px made the icon 56px
tall, overflowing that box and pushing the drag icon visually below the
row center.

Remove the vertical padding so the 24px icon fits the 24px meta slot and
stays centered. The horizontal padding is kept unchanged.
2026-06-13 16:51:18 +02:00
Franck Nijhof 26bdff9a16 Fix clipboard fallback throwing when active element is in the light DOM (#52578)
When the async Clipboard API is unavailable or rejects, copyToClipboard
falls back to a hidden textarea and execCommand. It appended that textarea
to deepActiveElement()?.getRootNode(). When the deepest active element
lives in the light DOM, getRootNode() returns the Document node, and
appending an element to a Document throws HierarchyRequestError (only the
single documentElement is allowed), so the fallback copy silently failed.

Append to document.body when the resolved root is a Document. Shadow roots
and elements keep holding the textarea directly, preserving execCommand
behavior inside dialogs that trap focus.
2026-06-13 11:14:57 +02:00
TheJulianJES 16ac66c1f8 Fix update entity progress text not showing when version is newer (#52579)
* Show installing status for update entities regardless of state

An install can be in progress while the update entity state is "off"
(e.g. downgrading firmware, where installed_version is newer than
latest_version). The installing check was nested inside the state ===
"on" branch, so these entities incorrectly showed "Up-to-date" instead
of "Installing (xx%)". Hoist the in-progress check above the state
branching so it always takes precedence.

* Show installing icon for update entities regardless of state

When an install is in progress (e.g. downgrading firmware), the entity
state can be "off" while installing. Show the installing icon
(mdi:package-down) whenever an install is in progress, before the
state-based icon selection.

Note: for entities with a brand entity_picture (e.g. Zigbee/ZHA
firmware updates), state-badge hides the icon in favour of the picture,
so this only affects update entities without a brand image.
2026-06-13 09:14:12 +00:00
Aidan Timson 8533dd586b Migrate home panel and profile dialogs to dirty state provider and dialog behaviour (#52559)
Migrate home panel and profile dialogs to dirty state provider and dialog behavior
2026-06-12 21:13:54 +02:00
Jan-Philipp Benecke 2cfb947c9b Migrate ha-config-info to use ha-list-base (#52574) 2026-06-12 19:13:08 +00:00
Aidan Timson 466cf2dfb2 Migrate automation dialogs to dirty state provider and dialog behaviour (#52558)
Migrate automation dialogs to dirty state provider and dialog behavior
2026-06-12 21:10:23 +02:00
Jan-Philipp Benecke 193bcad917 Adjust scrolling container of ha-top-app-bar-fixed pages (#52571)
* Adjust scrolling container of ha-top-app-bar-fixed pages

* Adjust scrolling behavior in ha-drawer

* Revert ha-drawer
2026-06-12 20:56:50 +02:00
Stefan Agner 52d32aec42 Add built-in Matter logo icon (#52568)
Add the Matter symbol as a bundled custom icon, available as
mdi:matter. Like the existing ESPHome and Music Assistant logos, the
SVG path is lazy-loaded and rendered with the foreground color.
2026-06-12 20:53:59 +02:00
renovate[bot] 9adb7215ce Update html-eslint monorepo to v0.62.0 (#52573)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-12 20:52:00 +02:00
renovate[bot] 273967fe70 Update dependency prettier to v3.8.4 (#52569)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-12 19:20:28 +03:00
renovate[bot] 382e07379b Update CodeMirror (#52567)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-12 13:24:05 +02:00
Andreas Schneider 01a8b8d3ef Pass network_only: false when commissioning Matter devices (#52456)
The backend defaults network_only to True, which causes BLE
commissioning to be skipped even when BLE proxies are connected. Passing
false lets the Matter server use BLE when proxies are available while
falling back to network commissioning when they are not.

It is only set to false for the following path:

Settings -> Matter -> Options -> Add manually
2026-06-12 09:33:42 +03:00
renovate[bot] 3bbce5607e Update typescript-eslint monorepo to v8.61.0 (#52562)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-11 21:58:53 +02:00
Petar Petrov 7ce052e2a8 Reduce allocations in downSampleLineData (#52551)
Replace the per-point grouping (a Map of arrays of {point, x, y} wrapper
objects, plus a second pass that re-walks each frame and, in mean mode,
two reduce() passes) with a single fixed accumulator per frame:

- mean mode keeps running sumX/sumY/count in arrival order, so the
  floating-point summation order is unchanged
- min/max mode tracks the min and max point incrementally with the same
  strict comparisons (first occurrence wins on ties) and the same
  min-before-max emit ordering

Each point is touched once; ~100k transient objects per large payload are
eliminated. Output is bit-identical. Speedups range from ~1.2x (mid-size)
to ~1.5-1.8x (100k-point) payloads, with substantially lower run-to-run
variance from reduced GC pressure. Payloads below maxDetails still
early-return unchanged.
2026-06-11 19:57:31 +02:00
Petar Petrov e929558a9a Fix clipped descenders in chart legend labels (#52554) 2026-06-11 19:47:16 +02:00
Aidan Timson 9cd4a6937f Migrate backup dialogs to dirty state provider and dialog behavior (#52549) 2026-06-11 17:12:57 +03:00
karwosts af617695b8 Make 'Add Card' more robust to bad yaml (#52556) 2026-06-11 17:08:05 +03:00
Aidan Timson 740ad9eb6b Migrate to dirty state provider for 5 dialogs (#52546)
* Add DirtyStateProviderMixin to dialogs (areas, backup, energy, helpers, person, voice assistant)

Migrate dialogs to DirtyStateProviderMixin for dirty state tracking via
Lit context. These dialogs do not use PreventUnsavedMixin and are fully
independent of the PreventUnsavedMixin contract change.

* Add disabled state

* Fix disable state

* Add check
2026-06-11 17:03:37 +03:00
Aidan Timson caeedc41e3 Migrate second set of dashboard dialogs to dirty state provider (#52538)
* Migrate second set of dashboard dialogs to dirty state provider

* Fix create dialog

* Add DirtyStateProviderMixin to Lovelace raw config editor

* Fix yaml mode check from review

* Fix
2026-06-11 16:46:24 +03:00
Bram Kragten 505966e84f Merge branch 'rc' 2026-06-11 15:42:36 +02:00
Bram Kragten 1ba71d940d Bumped version to 20260527.6 2026-06-11 15:42:24 +02:00
Aidan Timson 948b7489c2 Gate more info "Add to" button to admins (#52547) 2026-06-11 15:39:19 +02:00
Bram Kragten 370d755a9d Filter expired camera/image proxy requests in service worker (#52534)
Pre-validate the credential on camera_proxy, camera_proxy_stream and
image_proxy URLs before letting them hit core. Requests with a missing
or "undefined" token, or with an authSig JWT whose exp has passed, are
short-circuited to a synthetic 401 and never reach the server.

This silences spurious "Login attempt or request with invalid
authentication" warnings from homeassistant.components.http.ban that
fire when the browser replays a stale <img src> after BFCache restore,
tab resume, or a network change. The signed-path TTL is short (30s by
default) and image elements happily hold onto the URL long after that.

Limitations: service workers only run on secure contexts, so this does
not help users on plain http LAN access. A core-side fix to ban.py
that distinguishes expired-but-validly-signed paths from real login
attempts remains the principled fix and covers all clients.
2026-06-11 15:39:18 +02:00
Bram Kragten 57f0b7dbb7 Don't try to load brand images without a token (#52532) 2026-06-11 15:39:17 +02:00
Marcin BauerandClaude Opus 4.8 eb17fd4b31 Show condition row icon on mobile in visibility editor (#52527)
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-11 15:39:16 +02:00
Bram Kragten 92461f90d9 Fix camera/image proxy URLs sent with token=undefined (#52514) 2026-06-11 15:39:14 +02:00
4a43f22abf Add condition live testing to action conditions too (#52511)
* Add condition live testing to action conditions too

* Update src/panels/config/automation/action/ha-automation-action-row.ts

Co-authored-by: Petar Petrov <[email protected]>

* Apply prettier formatting

Co-Authored-By: Claude Opus 4.7 <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
Co-authored-by: Claude Opus 4.7 <[email protected]>
2026-06-11 15:39:13 +02:00
Jan-Philipp Benecke f2175f5fe7 Fix scrolling behavior for auto-height data table (#52508) 2026-06-11 15:39:12 +02:00
Jan-Philipp Benecke bc533c1fc9 Fix disabled action items icon button color in hui edit mode (#52507) 2026-06-11 15:39:10 +02:00
Petar Petrov 9cfdb9d2a2 Open more-info from energy pie chart legend, enlarge legend toggle on touch (#52506) 2026-06-11 15:39:09 +02:00
Bram Kragten fbb76a8ba0 Filter expired camera/image proxy requests in service worker (#52534)
Pre-validate the credential on camera_proxy, camera_proxy_stream and
image_proxy URLs before letting them hit core. Requests with a missing
or "undefined" token, or with an authSig JWT whose exp has passed, are
short-circuited to a synthetic 401 and never reach the server.

This silences spurious "Login attempt or request with invalid
authentication" warnings from homeassistant.components.http.ban that
fire when the browser replays a stale <img src> after BFCache restore,
tab resume, or a network change. The signed-path TTL is short (30s by
default) and image elements happily hold onto the URL long after that.

Limitations: service workers only run on secure contexts, so this does
not help users on plain http LAN access. A core-side fix to ban.py
that distinguishes expired-but-validly-signed paths from real login
attempts remains the principled fix and covers all clients.
2026-06-11 16:35:32 +03:00
Aidan Timson 3340637ff3 Migrate to dirty state provider for 4 areas (#52545)
* Add DirtyStateProviderMixin to dialogs (config entry, credentials, supervisor apps, voice assistant, zones)

Migrate dialogs to DirtyStateProviderMixin for dirty state tracking via
Lit context. These dialogs do not use PreventUnsavedMixin and are fully
independent of the PreventUnsavedMixin contract change.

* Fix disabled state

* Fix disabled state

* Drop voice assistant pipeline dialog changes (handled in dialogs-b)
2026-06-11 16:21:01 +03:00
Petar Petrov 534bea231c Open more-info from energy pie chart legend, enlarge legend toggle on touch (#52506) 2026-06-11 15:18:46 +02:00
Aidan Timson 8635951394 Migrate user dialogs to use dirty state provider (#52537)
* Migrate user dialogs to use dirty state provider

* Restore original dialog setups
2026-06-11 15:14:26 +03:00
Aidan Timson c46f286cb8 Gate more info "Add to" button to admins (#52547) 2026-06-11 13:12:39 +02:00
Petar Petrov cc6b51d53f Show a single toast with the update name when Update all fails (#52530) 2026-06-11 12:06:47 +01:00
karwosts 6915ca8fdd Remove dead code in hui-timestamp-display (#52544) 2026-06-11 08:40:55 +03:00
Jan-Philipp Benecke 677e53f685 Migrate maintenance panel topbar to ha-top-app-bar-fixed (#52540) 2026-06-11 08:40:08 +03:00
Aidan Timsonandcopilot-swe-agent[bot] 46b6ae8d7b Remove isDirty from PreventUnsavedMixin, migrate automation editors to DirtyStateProviderMixin (#52515)
* Remove isDirty from PreventUnsavedMixin, migrate to DirtyStateProviderMixin

Drop the legacy isDirty getter from PreventUnsavedMixin and switch to
isDirtyState (provided by DirtyStateProviderMixin). All consumers that
previously overrode isDirty are migrated to use DirtyStateProviderMixin
with proper dirty tracking:

- AutomationScriptEditorMixin: deep config comparison
- ha-scene-editor: revision counter with shallow comparison
- Blueprint editors + manual editor mixin: consume dirty context

This is the atomic core change — all isDirty overriders are migrated in
the same commit so no compatibility layer is needed.

* Fix dirty state not updated when YAML editor has invalid content

- ha-scene-editor: call _updateDirtyState on invalid YAML to increment
  the revision counter, marking the editor dirty
- ha-script-editor, ha-automation-editor: override isDirtyState to also
  return true when yamlErrors is set, ensuring the PreventUnsavedMixin
  navigation guard fires even when the user has never produced a valid
  intermediate config change

* FIx/migrate editor-toast

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-06-11 08:36:19 +03:00
Aidan Timson 09fda1ca1e Migrate energy dialogs to use dirty state provider (#52535)
* Migrate energy dialogs to use dirty state provider

* Migrate energy grid settings dialog

* Fix baseline for add mode

* Review
2026-06-11 08:28:39 +03:00
Jan-Philipp Benecke 7c1522b975 Migrate hass-error-screen to ha-top-app-bar-fixed (#52543) 2026-06-11 07:06:36 +02:00
Jan-Philipp Benecke d26ad7b354 Migrate hass-loading-screen to ha-top-app-bar-fixed (#52542) 2026-06-11 07:06:26 +02:00
Bram Kragten 66235a4c99 Don't try to load brand images without a token (#52532) 2026-06-10 18:09:35 +02:00
dependabot[bot] 6c02864334 Bump shell-quote from 1.8.3 to 1.8.4 (#52533)
Bumps [shell-quote](https://github.com/ljharb/shell-quote) from 1.8.3 to 1.8.4.
- [Changelog](https://github.com/ljharb/shell-quote/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/shell-quote/compare/v1.8.3...v1.8.4)

---
updated-dependencies:
- dependency-name: shell-quote
  dependency-version: 1.8.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-10 15:15:35 +03:00
Aidan Timson 3471cd103a Add a blocking labels workflow (#52531) 2026-06-10 13:53:51 +02:00
Jan-Philipp Benecke 9ae25d96f2 Move default menu/back button to ha-top-app-bar-fixed (#52444) 2026-06-10 12:11:09 +02:00
Marcin BauerandClaude Opus 4.8 02361f2517 Show condition row icon on mobile in visibility editor (#52527)
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-10 10:30:37 +02:00
Aidan Timsonandcopilot-swe-agent[bot] 38055b9244 Migrate vaccum segment mapping to dirty state provider (#52510)
* Migrate vaccum segment mapping to dirty state provider

* Use typed value-changed event in vacuum mapping view

* Use consumer key for vaccum segment mapping instead of new provider

* Completeness

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-06-10 09:49:01 +03:00
Aidan Timson d064127f18 Migrate lovelace editors to dirty state provider (#52509)
* Migrate lovelace editors to dirty state provider

* Type in signature

* Type in signature

* Keep saving
2026-06-10 08:45:11 +03:00
Jan-Philipp Benecke cb2d8db91b Migrate security panel topbar to ha-top-app-bar-fixed (#52519) 2026-06-10 08:33:28 +03:00
Joakim Plate 861d7757cc If redirect url has a trailing question mark our redirect is malformed (#52526) 2026-06-10 08:18:22 +03:00
1331ec9e2d Add condition live testing to action conditions too (#52511)
* Add condition live testing to action conditions too

* Update src/panels/config/automation/action/ha-automation-action-row.ts

Co-authored-by: Petar Petrov <[email protected]>

* Apply prettier formatting

Co-Authored-By: Claude Opus 4.7 <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
Co-authored-by: Claude Opus 4.7 <[email protected]>
2026-06-10 08:14:30 +03:00
Bram Kragten 0f81311c76 Fix camera/image proxy URLs sent with token=undefined (#52514) 2026-06-09 15:34:49 +01:00
Aidan TimsonandPetar Petrov 8a85d1cf31 Use typed query param handling in todo and refactor handler typing (#52505)
* Use typed query param handlers for todo

* Refactor to query param config obj

* Remove type casts

* Use main window

Co-authored-by: Petar Petrov <[email protected]>

* Fix import

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-06-09 11:40:45 +00:00
Przemysław SzypowiczandPrzemysław Szypowicz 9ba34bdf9a Add type and integration context to scene editor entity rows (#52494)
* Show entity area and device in scene editor entity lists

Entities already added to a scene only displayed their friendly name, so
several similarly named entities (e.g. multiple lights named LED) were
indistinguishable. Add a secondary line with the entity's area and device,
reusing computeEntityPickerDisplay so it matches the add-entity picker.
Applies to both the device-grouped and standalone entity lists.

* Add type and integration context to scene editor entity rows

Mirror the pickers used to add scene members: device-grouped entities show
their integration (e.g. Matter), like the device picker, while standalone
entities show their domain (e.g. Light), like the entity picker. Combined with
the area and device on the second line, this keeps entities distinguishable
once they are part of the scene.

---------

Co-authored-by: Przemysław Szypowicz <[email protected]>
2026-06-09 14:36:34 +03:00
Jan-Philipp Benecke f0f28789de Fix scrolling behavior for auto-height data table (#52508) 2026-06-09 14:21:40 +03:00
Jan-Philipp Benecke f007ea9da1 Fix disabled action items icon button color in hui edit mode (#52507) 2026-06-09 14:02:57 +03:00
Aidan Timson 8c51adf77f Revamp design/gallery to use theming and align with app ui (#52495)
* Dedicated gallery AGENTS.md

* Dont auto open the dev server for gallery

* Refactor and theme gallery

* Add icons

* Better positioning of icons

* Reorganise sidebar

* Remove extra title

* Remove header/toolbar height override

* Add some global spacing for content

* Show flipped theme mode for comparisions

* Remove unnesassary headings

* Fix eslint webpack resolution path for gallery vscode import errors

* Scroll item into view

* Fix theme variables

* Fix theme when system theme is dark and set to light

* Review

* Review

* Review

* Review

* Add mock

* Fix buttons
2026-06-09 13:35:56 +03:00
Aidan Timson 876c4d3e2e Dirty state context provider, update more info settings and categories to prevent scrim closure (#52358)
* Dirty state context provider

* Shallow state (new)

* Deep state (existing)

* Fix loop

* remove cast

* Move dirty state provider to dialog build level using deferred state

* Prevent scrim closure on category dirty state

* Discard dirty state on view change

* Move more info outside cache

* Refactor to allow multiple keys in dirty state, use default if not provided

* Fix child view rendering

* Deep clone to avoid mutations

* Fix state timing
2026-06-09 13:09:55 +03:00
cff72770e6 Revamp ZHA device management (#52368)
* Revamp ZHA device management

* Style cleanup

* Fix back navigation

* Update src/translations/en.json

Co-authored-by: Norbert Rittel <[email protected]>

* Process code review

* Fix translation

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Norbert Rittel <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-06-09 06:16:33 +00:00
renovate[bot] ff49fa78f8 Update dependency fuse.js to v7.4.2 (#52503)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-09 08:12:01 +03:00
Aidan Timson 914b90ffae Add typed query param helpers, add to history and activity (#52439) 2026-06-09 08:11:32 +03:00
ildar170975 1f1d520fdf Plant status card: add color for battery (#52457)
add color for battery
2026-06-08 14:16:14 +03:00
Bram Kragten 1cca5f3108 Use iOS provided device name for matter, and wait for iOS flow to be … (#52416) 2026-06-08 09:58:23 +02:00
renovate[bot] 0859202043 Update dependency rspack-manifest-plugin to v5.2.2 (#52492) 2026-06-08 08:23:51 +01:00
karwosts 125629ed39 Prevent spurious error flashes during helpers table load (#52479) 2026-06-08 08:34:18 +03:00
Abílio Costa bbfa71e974 Fix "show_legend" default in energy graph card editor (#52486) 2026-06-08 08:31:52 +03:00
Paulus SchoutsenandClaude 3e8c528863 Use attribute name as default label for state selector (#52490)
The state selector previously always defaulted its inner label to the
generic "State". When an attribute is configured (e.g. the source field
of media_player.select_source), default to the attribute's friendly name
instead, falling back to "State" when no concrete entity is available to
resolve the name.

Co-authored-by: Claude <[email protected]>
2026-06-08 08:31:13 +03:00
Paulus SchoutsenandClaude Opus 4.8 ffc4731205 Fix lost keyboard focus in virtualized list when scrolling to off-screen row (#52491)
Fix wrong scroll target in virtualized list setActiveItemIndex

When the requested row is outside the rendered range, setActiveItemIndex
scrolled to the raw index argument instead of the clamped/remapped
this.activeItemIndex it had just computed. If the requested index was out
of bounds or pointed at a non-focusable row (remapped to the first
focusable row), it scrolled to the wrong element (or none), so the active
row was never brought into view and keyboard focus was lost.

Use this.activeItemIndex, matching the other two element() call sites.

Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-06-08 08:30:09 +03:00
Paulus SchoutsenandClaude Opus 4.8 3b699da86c Fix add integration dialog error when picking an integration within a brand (#52489)
Fix missing domain on brand integration list items

When listing the integrations belonging to a brand in the add
integration dialog, the list item was missing the .domain property. The
click handler reads the domain from ev.currentTarget.domain, so it came
through as undefined and was sent to the backend as the config flow
handler, producing "required key not provided @ data['integration']".

This restores the .domain binding that was accidentally dropped in #52354.

Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-06-07 22:33:21 -04:00
Bram Kragten 0e1ea00eac Merge branch 'rc' 2026-06-07 20:19:56 +02:00
Bram Kragten 49f34e3a93 Bumped version to 20260527.5 2026-06-07 20:19:38 +02:00
karwosts e04e38f4de Fix yaml entity autocomplete (#52475) 2026-06-07 20:18:46 +02:00
karwosts b316ef5f45 Fix yaml entity autocomplete (#52475) 2026-06-07 20:17:47 +02:00
karwosts 6f372a8f70 Fix hui-editor search (#52453) 2026-06-07 19:44:48 +02:00
Aidan Timson cd728e221d Add maintenance my redirect (#52442)
Add maintenance My redirect
2026-06-07 19:44:47 +02:00
Jan-Philipp Benecke 6b6c159d5f Patch tinykeys v4 to make it compatible with older iOS versions (#52420)
* Downgrade tinykeys to 3.1.0 to make it compatible with older iOS versions

* Patch tinykeys v4

* Remove umd patch
2026-06-07 19:44:07 +02:00
Paul Bottein a4199d079b Add customize toggle to media player source and sound mode feature editors (#52414) 2026-06-07 19:41:15 +02:00
Aidan Timson f5edffc153 Match the card style of apps repo to installed (#52407) 2026-06-07 19:41:14 +02:00
ildar170975andPetar Petrov 78a2cd2485 Statistics graph card editor: add sub editor (#52182)
* add canEdit

* add canEdit

* add subEditor

* linter

* linter

* linter

* linter

* Remove div

* Update src/components/entity/ha-statistic-picker.ts

Co-authored-by: Petar Petrov <[email protected]>

* Update src/components/entity/ha-statistic-picker.ts

Co-authored-by: Petar Petrov <[email protected]>

* Update ha-statistic-picker.ts

* Update ha-statistic-picker.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-06-07 19:41:14 +02:00
renovate[bot] 2c3e61b126 Update formatjs monorepo (#52484)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-07 17:04:29 +00:00
renovate[bot] 3bd1d45fe1 Update dependency marked to v18.0.5 (#52482)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-07 19:00:55 +02:00
Tim van Dalen ae66cfc12e Don't show charging devices as low battery in Maintenance chip (#52238)
* Don't show charging devices as low battery in Maintenance chip

* Remove Companion app specific workaround
2026-06-07 07:30:57 -07:00
ildar170975 de45578c4c hui-entity-editor: add margins to add-button (#52454)
* add margins to add-button

* add margin to ha-selector-select
2026-06-07 10:03:56 +03:00
Paulus SchoutsenandClaude 1221e74776 Fix ha-textarea resize="auto" growing past max-height instead of scrolling (#52461)
* Cap size-adjuster height in ha-textarea resize=auto

When resize="auto", Web Awesome's textarea base is a CSS grid where the
real textarea and the size-adjuster share one cell, and both receive an
inline height equal to the content scrollHeight. We only capped the
textarea's max-height, so with long content the size-adjuster inflated
the grid row and the centered textarea was pushed down instead of
scrolling. Apply the same max-height cap to the textarea-adjuster part.

* Add capped autogrow demo to ha-textarea gallery page

Demonstrates resize="auto" with content that overflows the max-height,
so the textarea scrolls instead of growing unbounded. Serves as a visual
regression guard for the size-adjuster grid-row fix.

---------

Co-authored-by: Claude <[email protected]>
2026-06-07 09:55:02 +03:00
Paulus SchoutsenandClaude 04ae6eb3b4 Always show volume controls for assumed state media players in more info (#52466)
Co-authored-by: Claude <[email protected]>
2026-06-07 09:54:06 +03:00
karwosts 089849d283 Improve table no-data messages (#52474) 2026-06-07 09:52:19 +03:00
dependabot[bot] 70a20d8bcc Bump release-drafter/release-drafter from 7.3.0 to 7.3.1 (#52476)
Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 7.3.0 to 7.3.1.
- [Release notes](https://github.com/release-drafter/release-drafter/releases)
- [Commits](https://github.com/release-drafter/release-drafter/compare/c2e2804cc59f45f57076a99af580d0fedb697927...693d20e7c1ce1a81d3a41962f85914253b518449)

---
updated-dependencies:
- dependency-name: release-drafter/release-drafter
  dependency-version: 7.3.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-07 08:19:22 +02:00
renovate[bot] 6c448be3f1 Update CodeMirror to v6.20.3 (#52472)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-06 18:19:01 +02:00
renovate[bot] c6e5ae21e2 Update tsparticles to v4.1.3 (#52473)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-06 18:18:53 +02:00
Simon LamonandPaulus Schoutsen b8ac4f3f3e No animation for running state (#52455)
* No animation for runnig state

* Remove state-dot-pulse animation and media query

Removed unused keyframes and media query for animation.

---------

Co-authored-by: Paulus Schoutsen <[email protected]>
2026-06-06 11:42:55 -04:00
Paulus SchoutsenandClaude fab4022dee Remove unused PageNavigation.not_component (#52463)
Co-authored-by: Claude <[email protected]>
2026-06-06 11:37:55 +02:00
karwosts d70a42930b Fix helper no category message (#52462) 2026-06-06 11:35:09 +02:00
Paulus Schoutsen b91a087ab1 Fix oversized top-app-bar-fixed-adjust wrapper in gallery pages (#52467) 2026-06-06 08:00:39 +02:00
karwosts d45b5d20a2 Fix hui-editor search (#52453) 2026-06-05 20:27:21 +02:00
elcaptain ad593a6733 added Brand Personality (#52451)
* added Brand Personality

as a result of https://github.com/OpenHomeFoundation/roadmap/issues/124

* fixed formatting
2026-06-05 20:26:15 +02:00
Aidan Timson 18c084b4da Add maintenance my redirect (#52442)
Add maintenance My redirect
2026-06-05 20:21:43 +02:00
renovate[bot] d761a68bee Update yarn monorepo to v4.16.0 (#52449) 2026-06-05 14:52:54 +01:00
Petar Petrov 937abc7e86 Use context instead of hass in domain state display components (#52448) 2026-06-05 14:11:58 +01:00
Petar Petrov 6d3979be17 Use context instead of hass in cover and valve control rows (#52446) 2026-06-05 14:11:01 +01:00
Jan-Philipp Benecke ef44a2d682 Refactor developer tools to use top bar component (#52316)
* Refactor developer tools to use top bar component

* Format
2026-06-05 15:43:03 +03:00
renovate[bot] 378c5a3c9d Update rspack monorepo to v2.0.6 (#52447)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-05 15:31:29 +03:00
renovate[bot] aaea886d51 Update dependency idb-keyval to v6.2.5 (#52445)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-05 15:30:56 +03:00
Petar Petrov a040dca639 Use consumeLocalize instead of hass in localize-only leaf components (#52443) 2026-06-05 15:13:09 +03:00
Jan-Philipp Benecke a59f33d54c Use context instead of hass in ha-menu-button (#52433) 2026-06-05 09:24:57 +01:00
Petar Petrov 4326e1880b Document hass-to-context migration in frontend instructions (#52421) 2026-06-05 08:19:43 +01:00
Petar Petrov d8bd82d3bb Add hide/show cards to the energy dashboard (#52362) 2026-06-05 08:13:20 +01:00
Aidan Timson ca9879cb4e Fixes for more info script service control area (#52417)
* Use space tokens

* Fix overflow issue on entities

* Enforce narrow mode on target selectors

* Add action to full width selectors

* Function signature typing
2026-06-05 09:03:49 +03:00
Aidan Timson 89bd78463b Replace hass with lazy context in integration filters and update areas (#52390)
Replace hass with lazy context in settings areas
2026-06-05 09:01:51 +03:00
Aidan Timson 6350417c52 Add related context to scene editor (#52410) 2026-06-05 08:52:06 +03:00
renovate[bot]andPetar Petrov 7f6f29629f Update dependency barcode-detector to v3.2.0 (#52425)
* Update dependency barcode-detector to v3.2.0

* bump license version

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <[email protected]>
2026-06-05 05:35:28 +00:00
Jan-Philipp Benecke b224bd7077 Patch tinykeys v4 to make it compatible with older iOS versions (#52420)
* Downgrade tinykeys to 3.1.0 to make it compatible with older iOS versions

* Patch tinykeys v4

* Remove umd patch
2026-06-05 08:21:13 +03:00
renovate[bot] 6338d0ea4e Update dependency fuse.js to v7.4.1 (#52432)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-05 08:09:59 +03:00
renovate[bot] c21ffeacad Update typescript-eslint monorepo to v8.60.1 (#52428)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-05 08:05:11 +03:00
renovate[bot] 69b33ff015 Update dependency tar to v7.5.16 (#52423)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-04 20:22:43 +02:00
Bram Kragten 6e2968671b Check if package is available on pypi instead of fixed wait (#52419) 2026-06-04 17:12:00 +02:00
Paul Bottein 453d412549 Add customize toggle to media player source and sound mode feature editors (#52414) 2026-06-04 16:09:27 +01:00
renovate[bot] 4a3eea5d2b Update tsparticles to v4.1.2 (#52418)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-04 17:08:01 +02:00
Bram Kragten ee755ff58a Use zone location as location of person if no gps is available (#52415) 2026-06-04 17:49:23 +03:00
Aidan Timson 635a6442b4 Update agents on button size after #52391 (#52411)
* Update agents button size after #52391

* Add updated sizes
2026-06-04 17:41:37 +03:00
Paul Bottein 3608156e83 Show media player playback controls as disabled instead of hiding them (#52370)
* Show media player playback controls as disabled instead of hiding them

* Add on/off power by default
2026-06-04 15:55:05 +03:00
Bram Kragten 8529980bdd Show template errors in traces (#52412) 2026-06-04 13:54:08 +01:00
Paul Bottein 9ff508259f Migrate deprecated Web Awesome size values to short form (s/m/l) (#52391) 2026-06-04 13:32:33 +01:00
Petar Petrov 1ec4dc6c79 Trim redundancy in AI coding instructions (#52409) 2026-06-04 13:30:13 +01:00
Aidan Timson 39c88e573d Match the card style of apps repo to installed (#52407) 2026-06-04 13:49:13 +02:00
renovate[bot] 99eb752a68 Update vitest monorepo to v4.1.8 (#52405)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-04 11:39:55 +02:00
Jan-Philipp Benecke 9cc63c1f53 Use context instead of hass property in ha-area-picker (#52394)
* Use context instead of hass property in ha-area-picker

* Use state() on _areas
2026-06-04 11:42:54 +03:00
Aidan Timson d2188f600f Add related context event to trace pages (#52392)
* Add trace related context

* Review
2026-06-04 10:47:19 +03:00
Petar Petrov d69d4c592d Update AI coding instructions to match current frontend code (#52403)
Update AI coding instructions to match current frontend APIs

Fix outdated references in .github/copilot-instructions.md (symlinked as
CLAUDE.md and AGENTS.md): showAlertDialog import path, ESLint flat config,
ha-dialog width presets, ha-alert slots/props, ha-button variant/appearance
guidance, Web Awesome direction, and the querySelector pitfall.
2026-06-04 09:46:21 +02:00
Aidan Timson a97df0409c Fix editor context (#52393) 2026-06-04 09:24:05 +03:00
Aidan Timson 468756bd2f Add related context to area page (#52383) 2026-06-04 08:30:02 +03:00
ildar170975 cc43caa87b hui-card-picker: fix a path to "content" (#52398)
fix a path to "content"
2026-06-04 08:29:00 +03:00
renovate[bot] 1fb3efadfa Update dependency js-yaml to v4.2.0 (#52401)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-04 08:02:56 +03:00
WendelinandAidan Timson 69599352a3 Introduce list-virtualized (#52354)
* Fix keyboard nav and focus

* Simplify

* use virtualized list in zha

* update jsdocs

* Fix ha-domain-integration

* Update docs and clean up

* fix

* review

* Add translation

---------

Co-authored-by: Aidan Timson <[email protected]>
2026-06-04 07:58:59 +03:00
Simon Lamon 5c0f2feac1 Remove explicit netlify version (#52386) 2026-06-03 20:50:55 +02:00
renovate[bot] 033d035b18 Update dependency lint-staged to v17.0.7 (#52389) 2026-06-03 12:03:23 +01:00
Bram Kragten 156ab27cfa 20260527.4 (#52388) 2026-06-03 12:44:08 +02:00
Bram Kragten ba26e9f491 Bumped version to 20260527.4 2026-06-03 12:03:26 +02:00
Paul Bottein 8778fe8577 Restore search field autofocus in card and badge pickers (#52387) 2026-06-03 12:03:12 +02:00
Aidan Timson 6801aaea30 Fix automation building block action icon style (#52382) 2026-06-03 12:03:12 +02:00
WendelinandStefan Agner c3f5b6693a Landingpage download progress (#52359)
* Simplify and improve landingpage

* add core download progress

* reduce to 2 seconds

* Use round to display full integer as progress percentage

* Use find to get the job object

* Don't show progress label when progress is at 0

Before download starts, progress is at 0. At this point we may trying
to reach a server (and error out), so we aren't really in downloading
phase just yet. Simply treat 0 as "not started" and hide the progress
label until we have a real progress value.

---------

Co-authored-by: Stefan Agner <[email protected]>
2026-06-03 12:03:10 +02:00
Paul Bottein 04a986cd2c Restore search field autofocus in card and badge pickers (#52387) 2026-06-03 10:49:50 +01:00
WendelinandStefan Agner 5b09b1475d Landingpage download progress (#52359)
* Simplify and improve landingpage

* add core download progress

* reduce to 2 seconds

* Use round to display full integer as progress percentage

* Use find to get the job object

* Don't show progress label when progress is at 0

Before download starts, progress is at 0. At this point we may trying
to reach a server (and error out), so we aren't really in downloading
phase just yet. Simply treat 0 as "not started" and hide the progress
label until we have a real progress value.

---------

Co-authored-by: Stefan Agner <[email protected]>
2026-06-03 12:07:01 +03:00
Aidan Timson b1b9ac23cf Fix automation building block action icon style (#52382) 2026-06-03 10:21:48 +02:00
Paul Bottein aa19ca91a3 Add registryDependencies to strategies for selective regeneration (#30102) 2026-06-03 08:56:26 +02:00
Jan-Philipp Benecke 1388aa56ea Use consumeLocalize instead of hass in ha-icon-button-arrow-prev (#52377)
Use context in ha-icon-button-arrow-prev
2026-06-03 08:13:44 +03:00
renovate[bot] 6ca7ac1ca5 Update dependency fuse.js to v7.4.0 (#52379)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-03 08:13:03 +03:00
renovate[bot] d4380248c2 Update tsparticles to v4.1.1 (#52380)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-03 08:12:39 +03:00
Bram Kragten 68f75c82eb Bumped version to 20260527.3 2026-06-02 23:55:02 +02:00
Bram Kragten 6660e4799c Add tags in app store too, plus show if addon is installed already (#52373) 2026-06-02 23:54:24 +02:00
Petar Petrov 08bfafea21 Fix raw div tag showing in Sankey chart tooltips (#52365)
Fix raw div tag showing in sankey chart tooltips
2026-06-02 23:54:23 +02:00
Bram Kragten 5677e60fcc Matter add device: change how main entity is found (#52361)
Don't search for a entity based on main entity but use entity_category
2026-06-02 23:54:22 +02:00
Bram KragtenandSimon Lamon 73557e6464 Migrate trigger behavior (#52360)
* Migrate trigger behavior

* Apply suggestions from code review

Co-authored-by: Simon Lamon <[email protected]>

* Apply suggestions from code review

Co-authored-by: Simon Lamon <[email protected]>

---------

Co-authored-by: Simon Lamon <[email protected]>
2026-06-02 23:54:21 +02:00
e9e6c60d8b Move live-test indicator to badge on condition icon (#52352)
Co-authored-by: Claude Sonnet 4.6 (1M context) <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2026-06-02 23:54:20 +02:00
Aidan Timson 1651c210be Improve messaging and consolidate add to dialogs (#52330) 2026-06-02 23:54:19 +02:00
Jan-Philipp Benecke 14617aaf3c Fix hass-tabs-subpage narrow toggle (#52375) 2026-06-02 19:53:31 +02:00
Bram Kragten 42e1051d9c Add tags in app store too, plus show if addon is installed already (#52373) 2026-06-02 18:48:09 +02:00
cfe30114f0 Move live-test indicator to badge on condition icon (#52352)
Co-authored-by: Claude Sonnet 4.6 (1M context) <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2026-06-02 14:19:35 +00:00
Petar Petrov 288c03c248 Fix raw div tag showing in Sankey chart tooltips (#52365)
Fix raw div tag showing in sankey chart tooltips
2026-06-02 16:12:38 +02:00
renovate[bot] 8cd9a5adf6 Update dependency lint-staged to v17.0.6 (#52363)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-02 13:17:09 +00:00
Bram Kragten 4d3437b491 Matter add device: change how main entity is found (#52361)
Don't search for a entity based on main entity but use entity_category
2026-06-02 15:13:07 +02:00
Bram KragtenandSimon Lamon ceb51714be Migrate trigger behavior (#52360)
* Migrate trigger behavior

* Apply suggestions from code review

Co-authored-by: Simon Lamon <[email protected]>

* Apply suggestions from code review

Co-authored-by: Simon Lamon <[email protected]>

---------

Co-authored-by: Simon Lamon <[email protected]>
2026-06-02 15:00:34 +02:00
karwosts d2c868f904 Avoid double collection fetch when loading energy dashboard strategy (#52351)
* Avoid double collection fetch when loading energy

* Load the now collection in strategy if we're heading to /now
2026-06-02 12:19:05 +03:00
Copilot 9f34de5de6 Update dialog dismissal guideline (#52333)
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-06-02 12:07:19 +03:00
Jan-Philipp Benecke 6c9452aa5a Use context instead passing narrow down to hass-tabs-subpage (#52345)
Use context instead passing narrow down in hass-tabs-subpage
2026-06-02 12:06:47 +03:00
Aidan Timson 2cf79853aa Improve messaging and consolidate add to dialogs (#52330) 2026-06-02 10:32:56 +02:00
Petar Petrov 6152812138 Skip in-progress updates when triggering Update all (#52353)
Filter out updates that are already installing before calling the
update.install service, and disable a group's Update all button when
every update in it is already in progress.
2026-06-02 09:11:26 +02:00
Aidan Timson 5540a6c1ff Use options object instead of multiple undefined params for getAreas, getDevices, getEntities (#52342) 2026-06-02 08:52:02 +02:00
renovate[bot] e04297f2bd Update dependency date-fns to v4.4.0 (#52350)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-02 08:20:39 +03:00
renovate[bot] e89f76bbbb Update dependency eslint to v10.4.1 (#52349)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-02 08:20:07 +03:00
Bram Kragten 927c036454 Bumped version to 20260527.2 2026-06-01 19:52:36 +02:00
Paul Bottein 0fefcf809f Fix vacuum and lawn mower features not showing default buttons (#52343) 2026-06-01 19:52:19 +02:00
Bram Kragten a176f3c1ef Allow to set refresh url while dialog is open, use for matter device (#52341)
Allow to set refresh dialog while dialog is open, use for matter device
2026-06-01 19:52:18 +02:00
Wendelin c5152c3472 App-Info: Hide app title on narrow (#52337)
Hide app title on narrow
2026-06-01 19:52:17 +02:00
Wendelin 0150337522 Fix picker default popover-placement (#52336) 2026-06-01 19:52:16 +02:00
Paul Bottein 5d55d543b1 Respect backend order for floors and areas in entity tree (#52329) 2026-06-01 19:52:14 +02:00
George Caliment 4805b22289 Fixed filter flex direction on mobile + removed unused classes (#52327)
* Fixed filter flex direction on mobile + removed unused classes

* Removed hard-coded height to fill all viewport
2026-06-01 19:52:13 +02:00
Simon Lamon 8de411abc3 Show all counter actions if none specified (#52317)
Show all actions if none specified
2026-06-01 19:52:12 +02:00
Jan-Philipp Benecke e455d4384a Use right token for topbar shadow transition (#52306) 2026-06-01 19:52:11 +02:00
karwosts b0dbd825c8 Fix behavior for move view left/right (#52300) 2026-06-01 19:52:10 +02:00
karwosts 69d0fcb666 Fix untracked legend in detail graph card (#52299) 2026-06-01 19:52:09 +02:00
Simon Lamon f7c3ed3b77 Ignore location in description (#52297) 2026-06-01 19:52:08 +02:00
Jan-Philipp Benecke 5ee5b5120e Add box-shadow transition to top app bar (#52292) 2026-06-01 19:52:07 +02:00
karwosts 58fc8160fd Fix missing location data in calendar (#52291) 2026-06-01 19:52:06 +02:00
renovate[bot] 319ba3940e Update tsparticles to v4.1.0 (#52344)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-01 16:27:46 +00:00
Paul Bottein b9920065a2 Fix vacuum and lawn mower features not showing default buttons (#52343) 2026-06-01 18:13:38 +02:00
Petar PetrovandCopilot Autofix powered by AI 3bb5201d41 Potential fix for code scanning alert no. 3: Incomplete string escaping or encoding (#52332)
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-06-01 18:12:13 +02:00
Bram Kragten a0648b85ff Allow to set refresh url while dialog is open, use for matter device (#52341)
Allow to set refresh dialog while dialog is open, use for matter device
2026-06-01 18:11:23 +02:00
Petar Petrov 54f901c7c9 Group pending updates by category on the updates page (#52215) 2026-06-01 17:23:56 +02:00
Wendelin 2483a917f8 Fix picker default popover-placement (#52336) 2026-06-01 14:55:48 +01:00
renovate[bot] d9cae08f53 Update dependency @rspack/dev-server to v2.0.3 (#52338) 2026-06-01 14:55:47 +02:00
Aidan Timson 106b35d6cf Create related context, add automation element dialog search weighting for area (#52280)
* Create shared related context for quick bar and add automation element

* Provider mixin and dont pass sets when context can be used

* Direct use consume

* Move context provider into class and use in context mixin

* Cleanup

* Match signatures with lazy context provider

* Fix order of operations

* Typing

* Fix popstate on dialog launch/close

* Typing improvement
2026-06-01 15:49:50 +03:00
Wendelin f12d305688 App-Info: Hide app title on narrow (#52337)
Hide app title on narrow
2026-06-01 15:36:48 +03:00
Paul Bottein d2326b4f62 Respect backend order for floors and areas in entity tree (#52329) 2026-06-01 15:02:01 +03:00
Jan-Philipp Benecke ea9424053a Introduce narrow viewport context (#52320)
* Introduce narrow viewport context

* Format

* Revert sidebar narrow context

* Discard changes to src/components/ha-sidebar.ts
2026-06-01 14:58:57 +03:00
Petar PetrovandMindFreeze 70ffef8807 Remove unused dependencies (#52328)
Drop dependencies that are no longer referenced anywhere in the codebase:

- @material/mwc-base: declared directly but never imported; still pulled
  in transitively by the other @material/mwc-* packages, so the explicit
  declaration was redundant.
- @types/mocha: the test runner is Vitest (test files import describe/it/
  expect from "vitest"); no Mocha globals or namespace are used.
- @types/webspeechapi: no Web Speech API usage in the codebase, and the
  modern TypeScript lib.dom already ships these definitions.
- @types/babel__plugin-transform-runtime: the plugin is only referenced by
  string name in the Babel config, never imported as a typed module, so the
  type stub is unused.

Co-authored-by: MindFreeze <[email protected]>
2026-06-01 08:41:04 +02:00
Simon Lamon a32169f300 Ignore location in description (#52297) 2026-06-01 09:31:01 +03:00
Simon Lamon b508760d24 Show all counter actions if none specified (#52317)
Show all actions if none specified
2026-06-01 08:12:37 +03:00
Simon Lamon 541cab83de Fix lock workflow (#52318) 2026-06-01 08:11:45 +03:00
renovate[bot] 8e8f2bfa4c Update dependency @bundle-stats/plugin-webpack-filter to v4.22.2 (#52323)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-01 08:11:09 +03:00
George Caliment bafe21ab48 Fixed label assignment dropdown scroll and width on mobile screens (#52326)
* Fixed ha-config-entities label assignment dropdown scroll and width on mobile screens

* Made ha-label handle text ellipsis by itself
2026-06-01 08:10:42 +03:00
George Caliment ee56d7d003 Fixed filter flex direction on mobile + removed unused classes (#52327)
* Fixed filter flex direction on mobile + removed unused classes

* Removed hard-coded height to fill all viewport
2026-06-01 08:09:42 +03:00
renovate[bot] 486b6bb561 Update dependency @rsdoctor/rspack-plugin to v1.5.12 (#52319)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-31 11:47:39 +02:00
karwosts 9a9ceaebf2 Fix behavior for move view left/right (#52300) 2026-05-31 09:41:36 +02:00
Petar Petrov ff5bbf46ae Migrate date/time selectors to internationalization locale context (#52265)
Consume internationalizationContext for locale in ha-selector-date,
ha-selector-datetime, ha-selector-time, ha-selector-button-toggle, and
ha-selector-select (partial: hass kept where passed to children).
2026-05-31 09:16:43 +02:00
Petar Petrov 47fb4a2def Migrate hui-badge-edit-mode and hui-card-edit-mode to localize context (#52264)
* Migrate hui-badge-edit-mode and hui-card-edit-mode to localize context

Replace this.hass.localize with @consumeLocalize(); remove hass prop and
caller .hass bindings from Lovelace edit-mode overlays.

* Migrate hui-view-badges to localize context
2026-05-31 09:15:46 +02:00
Petar Petrov 0e716e5078 Migrate ha-person-badge and ha-user-badge to connection context (#52263)
* Migrate avatar badges off hass property (Group K)

Consume connectionContext for hassUrl and statesContext plus
consumeEntityState for the user badge person entity picture.
Remove .hass bindings from callers.

* Migrate ha-person-badge and ha-user-badge to connection context

Use connectionContext for hassUrl; ha-user-badge also consumes entity state
for person picture lookup.

* Fix ha-user-badge updates and restore hass binding

Use PropertyValues.has() to detect _states changes. Restore .hass bindings on
ha-user-picker callers and ha-generic-picker, which still require hass.

* Fix type error and restore hass on person subpage

- Type willUpdate with PropertyValues so changedProps.has("_states")
  type-checks (matches the other states-context consumers); fixes the
  failing lint:types CI check
- Restore .hass on hass-tabs-subpage in ha-config-person, which still
  requires hass and was crashing the person config page
- Drop now-dead .hass bindings on ha-user-badge in ha-user-picker
- Only rescan for the person entity when the user changes or the tracked
  entity is missing, instead of on every state update
2026-05-31 09:15:40 +02:00
dependabot[bot] 9e9fdfbad6 Bump home-assistant/actions from f6f29a7ee3fa0eccadf3620a7b9ee00ab54ec03b to 868e6cb4607727d764341a158d98872cd63fa658 (#52312)
Bump home-assistant/actions

Bumps [home-assistant/actions](https://github.com/home-assistant/actions) from f6f29a7ee3fa0eccadf3620a7b9ee00ab54ec03b to 868e6cb4607727d764341a158d98872cd63fa658.
- [Release notes](https://github.com/home-assistant/actions/releases)
- [Commits](https://github.com/home-assistant/actions/compare/f6f29a7ee3fa0eccadf3620a7b9ee00ab54ec03b...868e6cb4607727d764341a158d98872cd63fa658)

---
updated-dependencies:
- dependency-name: home-assistant/actions
  dependency-version: 868e6cb4607727d764341a158d98872cd63fa658
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-31 09:13:37 +02:00
dependabot[bot] 5ebdb99ba7 Bump actions/stale from 10.2.0 to 10.3.0 (#52313)
Bumps [actions/stale](https://github.com/actions/stale) from 10.2.0 to 10.3.0.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/b5d41d4e1d5dceea10e7104786b73624c18a190f...eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: 10.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-31 09:13:22 +02:00
dependabot[bot] 1ca454cf02 Bump github/codeql-action from 4.35.5 to 4.36.0 (#52315)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.35.5 to 4.36.0.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/9e0d7b8d25671d64c341c19c0152d693099fb5ba...7211b7c8077ea37d8641b6271f6a365a22a5fbfa)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.36.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-31 09:13:20 +02:00
renovate[bot] 859d23c187 Update formatjs monorepo (#52309)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-31 09:12:47 +02:00
renovate[bot] f9d205defe Update dependency @rspack/core to v2.0.5 (#52314)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-31 09:12:44 +02:00
dependabot[bot] 00cc4e2a5a Bump dessant/lock-threads from 6.0.0 to 6.0.2 (#52311)
Bumps [dessant/lock-threads](https://github.com/dessant/lock-threads) from 6.0.0 to 6.0.2.
- [Release notes](https://github.com/dessant/lock-threads/releases)
- [Changelog](https://github.com/dessant/lock-threads/blob/main/CHANGELOG.md)
- [Commits](https://github.com/dessant/lock-threads/compare/7266a7ce5c1df01b1c6db85bf8cd86c737dadbe7...89ae32b08ed1a541efecbab17912962a5e38981c)

---
updated-dependencies:
- dependency-name: dessant/lock-threads
  dependency-version: 6.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-31 08:44:20 +02:00
renovate[bot] 6571feb556 Update dependency terser-webpack-plugin to v5.6.1 (#52307)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-30 18:54:29 +00:00
renovate[bot] 4150bc0806 Update dependency license-checker-rseidelsohn to v5 (#52304)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-30 20:50:36 +02:00
renovate[bot] 958e3f2575 Update dependency @swc/helpers to v0.5.23 (#52303)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-30 20:47:53 +02:00
Jan-Philipp Benecke 3d3292e2ad Use right token for topbar shadow transition (#52306) 2026-05-30 20:47:26 +02:00
karwosts 75b9fb2e34 Fix untracked legend in detail graph card (#52299) 2026-05-30 07:53:40 +03:00
Jan-Philipp Benecke 38f0ce306b Add box-shadow transition to top app bar (#52292) 2026-05-29 18:01:44 +02:00
Petar PetrovandMindFreeze 1ffd19e20b Make battery dialog charge/discharge order consistent (#52295)
Order the energy fields as discharge then charge to match the power
fields in the energy panel battery settings dialog.

Co-authored-by: MindFreeze <[email protected]>
2026-05-29 18:01:14 +02:00
Aidan Timson 9a216cae46 Add cover and valve favorite positions to suggestions (#52273) 2026-05-29 08:33:23 +03:00
karwosts 41e6408508 Fix missing location data in calendar (#52291) 2026-05-29 08:32:15 +03:00
renovate[bot] 97e85bc06f Update dependency typescript-eslint to v8.60.0 (#52290)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-29 08:06:38 +03:00
Bram Kragten 30930e18ab Bumped version to 20260527.1 2026-05-28 16:47:56 +02:00
Paul Bottein 8d0978817d Don't lowercase translated default action label (#52283) 2026-05-28 16:45:20 +02:00
Paul Bottein fc684218ce Preserve PNG transparency on area pictures (#52282) 2026-05-28 16:45:18 +02:00
Paul Bottein 22f29b7561 Fix sun condition Between description showing reversed values (#52279) 2026-05-28 16:45:16 +02:00
Wendelin c7d48aba44 Fix automation add TCA paste (#52276)
Fix automation add paste
2026-05-28 16:45:15 +02:00
Wendelin aeb2285f30 App details improve mobile and icon (#52275)
* icon instead of logo, enable wrap

* Keep logo

* revert test url
2026-05-28 16:45:14 +02:00
Wendelin c692d7cd4e Card visibility-status use ha-alert (#52271) 2026-05-28 16:45:12 +02:00
Wendelin f2d7021a7d Fix automation note keyboard a11y (#52270) 2026-05-28 16:45:11 +02:00
Wendelin 3a649fba22 Fix automation behavior img file names (#52247)
fix behavior img names
2026-05-28 16:45:09 +02:00
Simon Lamon 5362b8f853 Don't redispatch the original event in a checklist item (#52242) 2026-05-28 16:45:08 +02:00
Wendelin d05800bda6 Fix ha-radio-option checked theming (#52237)
Update ha-radio-option theming to use checked-icon-color for text and border
2026-05-28 16:45:07 +02:00
Wendelin d67530ea37 Fix row target count flickering, keyboard nav, type device (#52236)
* Fix row target count flickering

* Add noninteractive for device, fix keyboard nav

* Noninteractive action, conditon

* Remove unsued hass

* invert noninteractive
2026-05-28 16:45:05 +02:00
Petar Petrov bbd7ef676e Render echarts tooltips with Lit templates (#52235)
* Render echarts tooltips with Lit templates

Replace raw HTML string interpolation in echarts tooltip formatters with Lit templates so user-controlled fields (entity friendly_name, device names, node labels) are auto-escaped instead of relying on per-string filterXSS. ha-chart-base now wraps any function tooltip.formatter into a stable per-formatter container and handles Lit TemplateResult / nothing / null returns; the public HaECOption type lets charts express Lit-returning formatters without per-callsite casts.

* Simplify

* Refactor _getSeries

* Small fix

* Fix merge mistake

* Marker component and wrapper test
2026-05-28 16:45:04 +02:00
Petar Petrov 5f2ad7fa01 Migrate hui-buttons-base and ha-selector-attribute to states context (partial hass) (#52262) 2026-05-28 16:16:10 +02:00
ildar170975andPetar Petrov 7b6b70023b Statistics graph card editor: add sub editor (#52182)
* add canEdit

* add canEdit

* add subEditor

* linter

* linter

* linter

* linter

* Remove div

* Update src/components/entity/ha-statistic-picker.ts

Co-authored-by: Petar Petrov <[email protected]>

* Update src/components/entity/ha-statistic-picker.ts

Co-authored-by: Petar Petrov <[email protected]>

* Update ha-statistic-picker.ts

* Update ha-statistic-picker.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-05-28 17:13:20 +03:00
Paul Bottein 256a06e35f Preserve PNG transparency on area pictures (#52282) 2026-05-28 16:08:16 +02:00
Paul Bottein 4e26c05ac6 Don't lowercase translated default action label (#52283) 2026-05-28 13:47:56 +00:00
Paul Bottein 04ee8ac415 Fix sun condition Between description showing reversed values (#52279) 2026-05-28 13:46:56 +00:00
Petar Petrov 63e144309c Migrate ha-selector choose/period/file/selector to localize context (#52266) 2026-05-28 15:32:21 +02:00
Petar Petrov 77039cda8e Migrate automation icon components to config and connection context (#52261) 2026-05-28 15:22:06 +02:00
Petar Petrovandcopilot-swe-agent[bot] ab5b4ed792 Drop unused hass prop from ha-selector-boolean, ha-selector-duration, ha-sunburst-chart (#52253)
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-05-28 13:21:47 +00:00
Petar Petrov a08905cd31 Migrate ha-relative-time and ha-absolute-time to localize/locale/config context (#52259)
* Migrate ha-relative-time and ha-absolute-time off hass property

Consume localize, locale, and config via Lit context so time primitives
only rerender when i18n or config slices change, and drop obsolete .hass
bindings from callers.

* Consume full i18n context in time display components

Use internationalizationContext directly for both localize and locale in
ha-relative-time and ha-absolute-time, avoiding mixed consumption patterns.
2026-05-28 16:16:11 +03:00
Petar Petrov a35349196f Migrate trace logbook components to localize context (#52260) 2026-05-28 15:14:44 +02:00
Petar Petrov dbdfdedd74 Migrate energy total badges to states/locale/localize context (partial hass) (#52255) 2026-05-28 15:01:31 +02:00
Petar Petrov a5c8547b2b Migrate ha-filter-blueprints and ha-filter-voice-assistants to localize context (#52252) 2026-05-28 14:59:13 +02:00
Jan-Philipp Benecke e373689a37 Refactor climate panel to use top bar component (#52245)
* Refactor climate panel to use top bar component

* Remove calc

* Remove

* Remove
2026-05-28 15:48:06 +03:00
Jan-Philipp Benecke 5edcdb8977 Refactor light panel to use top bar component (#52246)
* Refactor light panel to use top bar component

* Remove

* Remove

* Remove
2026-05-28 15:47:41 +03:00
Wendelin 26b8921e8c Fix automation behavior img file names (#52247)
fix behavior img names
2026-05-28 14:33:55 +02:00
Petar Petrov b8c201b6d3 Render echarts tooltips with Lit templates (#52235)
* Render echarts tooltips with Lit templates

Replace raw HTML string interpolation in echarts tooltip formatters with Lit templates so user-controlled fields (entity friendly_name, device names, node labels) are auto-escaped instead of relying on per-string filterXSS. ha-chart-base now wraps any function tooltip.formatter into a stable per-formatter container and handles Lit TemplateResult / nothing / null returns; the public HaECOption type lets charts express Lit-returning formatters without per-callsite casts.

* Simplify

* Refactor _getSeries

* Small fix

* Fix merge mistake

* Marker component and wrapper test
2026-05-28 14:27:47 +02:00
Wendelin 4a6c23c93e Fix automation add TCA paste (#52276)
Fix automation add paste
2026-05-28 14:22:52 +02:00
Wendelin e2712cb0b0 Fix row target count flickering, keyboard nav, type device (#52236)
* Fix row target count flickering

* Add noninteractive for device, fix keyboard nav

* Noninteractive action, conditon

* Remove unsued hass

* invert noninteractive
2026-05-28 14:14:26 +02:00
renovate[bot] db52cd0d8e Update babel monorepo to v7.29.7 (#52277)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-28 15:01:16 +03:00
Wendelin 4891783c86 App details improve mobile and icon (#52275)
* icon instead of logo, enable wrap

* Keep logo

* revert test url
2026-05-28 13:23:55 +02:00
Wendelin b73732acdb Card visibility-status use ha-alert (#52271) 2026-05-28 10:57:41 +01:00
Wendelin d950514104 Fix automation note keyboard a11y (#52270) 2026-05-28 10:56:12 +01:00
Simon Lamon f37cf1e848 Don't redispatch the original event in a checklist item (#52242) 2026-05-28 08:26:00 +03:00
Paulus SchoutsenandClaude a188ef1b7a Fix resend-verification flash and concurrency on cloud signup (#52244)
Resending the confirmation email reused the registration code path, so
the flash on the login screen said "Account created!" even though no
new account was created. Pass a message key to _verificationEmailSent
so resend can show "Verification email sent." instead.

_handleResendVerifyEmail also never set _requestInProgress, so the
resend button (and the start-trial button, which share that flag) were
not disabled while a resend was in flight and could be clicked
repeatedly. Set the flag at the start and clear it on terminal errors;
_verificationEmailSent already clears it on success.

Co-authored-by: Claude <[email protected]>
2026-05-28 08:11:54 +03:00
Wendelin 087ef159df Fix ha-radio-option checked theming (#52237)
Update ha-radio-option theming to use checked-icon-color for text and border
2026-05-27 15:58:00 +02:00
Bram Kragten e39e1b3f5b Merge branch 'rc' into dev 2026-05-27 15:29:28 +02:00
Bram Kragten ff583d2274 Bumped version to 20260527.0 2026-05-27 15:26:39 +02:00
Wendelin d4de29e073 Rename automation trigger behavior options (#52224) 2026-05-27 15:24:53 +02:00
Wendelin 97dfed0cc4 Rename automation comments to note (#52219) 2026-05-27 15:23:27 +02:00
Bram Kragten 8b3df752da Add associated zone option for device trackers (#52211) 2026-05-27 15:18:01 +02:00
Paul Bottein 8c0d547962 Render small media browser thumbnails without blur (#52230)
* Render small media browser thumbnails without blur

* Only 16 pixels and no svg

* Skip brand url

* Media selector
2026-05-27 15:17:20 +02:00
Wendelin 5e3d84f0ad Add live test state message tooltip (#52233) 2026-05-27 15:08:43 +02:00
Petar Petrov b4e30bdf63 Fix energy compare bars stacking when compare month has more days (#52221) 2026-05-27 15:01:33 +02:00
Petar Petrov 4fcae4231c Remove redundant log-axis non-positive data preprocessing (#52222) 2026-05-27 14:59:37 +02:00
Wendelin 2aecf33955 Fix app details in tablet width (#52234) 2026-05-27 14:54:02 +02:00
Paulus SchoutsenandClaude 5f26a2b3da Show verify-email flash after cloud signup (#52232)
Co-authored-by: Claude <[email protected]>
2026-05-27 14:46:24 +02:00
Paul Bottein b08f5bcb34 Add custom card suggestions in the entity card picker (#52228)
* Add custom card suggestions in the entity card picker

* Prettier

* rename function

* Use ensure array
2026-05-27 14:38:53 +02:00
Wendelin c329e5b827 Revert "Automation triggers - auto IDs" (#52226) 2026-05-27 14:19:38 +02:00
Paulus SchoutsenandClaude Opus 4.7 97f591337d Fix cloud TTS try dialog failing on default browser target (#52231)
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
2026-05-27 14:17:18 +02:00
Bram Kragten e6e6e75f73 Revert "Add-on iframe: delegate microphone + camera Permissions Policy" (#52229) 2026-05-27 13:08:57 +02:00
Wendelin ff334de0ca Fix checked radio option (#52227) 2026-05-27 12:46:14 +02:00
Bram Kragten 8dbe97b480 Add device step to matter add flow (#52216)
* Add device step to matter add flow

* Update matter-add-device-device-added.ts
2026-05-27 12:48:14 +03:00
Bram Kragten 7bea54851d Remove advanced mode completely (#52212) 2026-05-27 09:20:48 +00:00
renovate[bot] 7171575f8c Update dependency @html-eslint/eslint-plugin to v0.61.0 (#52220)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-27 11:20:41 +03:00
f4143c2070 Update dependency echarts to v6.1.0 (#52168)
* Update dependency echarts to v6.1.0

* Fix axis-proxy patch for echarts 6.1.0 AxisProxy internals

ECharts 6.1.0 uses hostedBy() and _window.value instead of direct model
comparison and _valueWindow. Update the boundaryFilter patch and contract
tests so CI passes with the dependency bump.

Co-authored-by: Cursor <[email protected]>

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <[email protected]>
Co-authored-by: Cursor <[email protected]>
2026-05-27 11:08:23 +03:00
Paul BotteinandWendelin bbe6b88533 Add more card suggestions in the entity card picker (#52218)
Co-authored-by: Wendelin <[email protected]>
2026-05-27 09:32:54 +02:00
Jan-Philipp Benecke 3a0c85cd3e Migrate top app bar to plain HTML and drop mwc dependency (#52165) 2026-05-27 08:57:38 +02:00
Petar PetrovandMindFreeze d22e2b8dd5 Add battery state of charge badges to energy panel (#52210)
Show battery SOC as entity badge on energy Now tab

Co-authored-by: MindFreeze <[email protected]>
2026-05-26 20:15:22 +02:00
Wendelin 45e7d86bf8 Increase helper font-size (#52214) 2026-05-26 13:41:37 +00:00
Petar Petrov d1bf5fe33c Use context instead of hass for localize in low level components (#52177) 2026-05-26 15:26:09 +02:00
Aidan Timson fb0a54231a Show device name tip with link to editor, disable update button when state is clean (#52024) 2026-05-26 13:32:16 +02:00
Jan-Philipp Benecke a147fc4fee Fix padding of vertical tile card content (#52198) 2026-05-26 08:21:05 +03:00
karwosts a300085208 Fix calendar panel for non-admin (#52203) 2026-05-26 08:20:26 +03:00
renovate[bot] 44989a6972 Update dependency date-fns to v4.3.0 (#52205)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 08:19:30 +03:00
Yosi Levy 54a8e6c294 RTL fix for automation row (#52200) 2026-05-25 12:38:34 +02:00
Yosi Levy bfec22d828 RTL fix for new suggestion tree (#52199) 2026-05-25 11:52:54 +02:00
stevenandClaude Sonnet 4.6 cde6450cfc Fix stale wake word display after wake word change in voice satellite set up wizard (#52194)
Fix stale wake word display after wake word change in satellite wizard

The config re-fetch was fire-and-forgotten, so the step transition to
STEP.WAKEWORD raced ahead with stale assistConfiguration. Awaiting the
fetch ensures the fresh active_wake_words are in place before rendering.

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
2026-05-25 07:41:56 +00:00
Petar Petrov ab39e70629 Recover brand icons after Home Assistant restart (#52158)
* Recover brand icons after Home Assistant restart

* Make _refreshBrandsAccessToken async
2026-05-25 09:36:50 +02:00
J. Nick Koston 69f209e3c3 Teach Bluetooth UI about auto scanning mode (#52192)
* Teach Bluetooth UI about auto scanning mode

* Drop unreachable auto cases and add isScannerStateMismatch tests
2026-05-25 09:30:03 +02:00
J. Nick Koston f4c5561a54 Show raw advertisement bytes in Bluetooth device info (#52193)
* Show raw advertisement bytes in Bluetooth device info

* Use plain div for raw hex to avoid fragile pre whitespace
2026-05-25 09:24:46 +02:00
renovate[bot] 5147937a6f Update dependency generate-license-file to v4.2.1 (#52195)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-25 09:24:42 +02:00
renovate[bot] ee39605aa7 Update dependency intl-messageformat to v11.2.7 (#52197)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-25 09:24:38 +02:00
renovate[bot] 4af4f1dc51 Update dependency idb-keyval to v6.2.4 (#52190)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-24 14:01:55 +00:00
renovate[bot] a2d8859d94 Update dependency @date-fns/tz to v1.5.0 (#52187)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-24 14:03:30 +03:00
renovate[bot] afea8180c4 Update dependency idb-keyval to v6.2.3 (#52186)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-24 13:53:50 +03:00
dependabot[bot] b9c077489d Bump github/codeql-action from 4.35.4 to 4.35.5 (#52183)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.35.4 to 4.35.5.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/68bde559dea0fdcac2102bfdf6230c5f70eb485e...9e0d7b8d25671d64c341c19c0152d693099fb5ba)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.35.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-24 09:33:38 +03:00
karwosts 440bb32056 Remove unintended sort from select selector (#52179) 2026-05-23 21:14:24 +02:00
renovate[bot] 8f371621ad Update dependency @rspack/core to v2.0.4 (#52178)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-23 16:18:20 +03:00
renovate[bot] 61815b20e3 Update vitest monorepo to v4.1.7 (#52173)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-23 13:03:54 +02:00
ildar170975 1942fa3a77 hui-entity-editor: fix vertical spacings (#52170)
fix spacings
2026-05-23 10:04:46 +02:00
renovate[bot] 865e67a06f Update Yarn to v4.15.0 (#52169)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-23 10:03:23 +02:00
renovate[bot] 412dce4c1f Update dependency tinykeys to v4 (#52172)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-23 10:02:58 +02:00
Jan-Philipp Benecke ced2ac7ad5 Fix ha-drawer z-index (#52167)
Fix ha-drawer index
2026-05-22 20:33:05 +02:00
renovate[bot] 6649f52bcd Update dependency tinykeys to v3.1.0 (#52166)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-22 17:38:26 +00:00
7dbd6ae5a2 Add-on iframe: delegate microphone + camera Permissions Policy (#52068)
* Add-on iframe: delegate microphone + camera Permissions Policy

The add-on ingress iframe in ``ha-panel-app.ts`` ships without an
``allow=`` attribute, so the Permissions Policy default of *deny*
applies for ``microphone`` and ``camera`` on the cross-origin
iframe. An add-on that wants to call ``getUserMedia`` — voice
notes, dictation, video calls, photo capture — fails silently with
``NotAllowedError`` before the browser even surfaces the permission
prompt.

The failure is most visible on the Android Companion app, where
there's no "open in a new tab" escape: the user presses the mic
button and nothing happens, no toast, no logs.

Delegate ``microphone``, ``camera``, and ``clipboard-write`` to the
add-on iframe. Add-ons are first-party software the user explicitly
installs, and Chrome's runtime permission prompt still gates the
hardware access — the ``allow=`` attribute just lets the iframe
*request* the prompt instead of being blocked at the policy layer.

``clipboard-write`` is bundled in because the next-most-frequent
silent-fail in add-on land is ``navigator.clipboard.writeText`` for
"copy link" / "copy code" affordances, blocked by the same
mechanism.

* Sandbox add-on ingress iframe without allow-same-origin

Split IFRAME_SANDBOX into two constants: IFRAME_SANDBOX (without
allow-same-origin) for add-on ingress iframes that need origin
isolation, and IFRAME_SANDBOX_SAME_ORIGIN for external iframes
that need same-origin access.

This ensures add-on iframes can't inherit camera/microphone
permissions already granted to the Home Assistant origin, and
prevents same-origin iframes from removing their own sandbox.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

---------

Co-authored-by: Paulus Schoutsen <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
2026-05-22 19:31:56 +02:00
Wendelin e1528d21b3 Migrate md-lists cloud dashboard and devtools (#52163)
Migrate lists in cloud and dev tools=
2026-05-22 18:24:16 +03:00
renovate[bot] 79cb3137f2 Update tsparticles to v4.0.5 (#52162)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-22 18:17:04 +03:00
Jan-Philipp Benecke 313360701a Revamp ZHA group page UI (#52124) 2026-05-22 16:24:59 +02:00
renovate[bot] b100d9577d Update formatjs monorepo (#52159)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-22 15:56:02 +03:00
Wendelin 44ce303302 Fix dropdown keyboard scroll (#52157) 2026-05-22 13:47:43 +01:00
Aidan Timson 8f76613068 Add more quick links to device page (#52137)
* Add more quick links to device page

* Move shared keys to common location
2026-05-22 12:45:37 +03:00
Aidan TimsonandWendelin 85dff6640a Use ha-list-nav for each section in device page related card (#52142)
Co-authored-by: Wendelin <[email protected]>
2026-05-22 11:22:36 +02:00
Aidan Timson ab7c892b6b Add to for area page (#52141)
* Setup add to area page

* Remove 3 buttons, move to single add to button next to add a picture button

* Use normal size buttons

* Restructure layout with picture

* Remove div when both conditions are met

* Use mixin

* Fix imports
2026-05-22 12:02:38 +03:00
Wendelin 3fe57ad724 webawesome 3.7.0 (#52155) 2026-05-22 11:24:16 +03:00
1caf1d99b5 Migrate theme-picker to ha-generic-picker (#52067)
Co-authored-by: Claude Sonnet 4.6 <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2026-05-22 06:32:39 +00:00
renovate[bot] 483df2fa2f Update dependency marked to v18.0.4 (#52153)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-22 08:52:04 +03:00
Stefan AgnerandClaude Opus 4.7 e0adb006b6 Show time zone picker in onboarding when browser can't resolve IANA zone (#52146)
Some environments (e.g. Android WebView/emulator) return a UTC offset like
"+00:00" from Intl.DateTimeFormat().resolvedOptions().timeZone instead of an
IANA zone name. Submitting that to saveCoreConfig fails with "invalid time
zone", leaving users stuck on the country step.

Detect this by checking the resolved value against the google-timezones-json
list used by ha-timezone-picker, and surface the picker on the core-config
step when no IANA zone could be detected from the browser or the location
detect API.

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
2026-05-22 08:26:50 +03:00
renovate[bot] 50e34015b3 Update tsparticles to v4.0.4 (#52152)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-22 08:23:24 +03:00
renovate[bot] c1c926c631 Update tsparticles to v4.0.3 (#52148)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-22 08:11:18 +03:00
renovate[bot] c41afac57c Update dependency typescript-eslint to v8.59.4 (#52147)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-22 08:10:58 +03:00
Aidan Timson 8856c26929 Add quick links to area page, add area query param support (#52133)
* Add quick links to area page

* Typing

* Add query param support for areas

* hint for the rest

* Add support for helpers

* Add counts
2026-05-21 18:59:20 +02:00
Wendelin 4a0fe3190c Backups: Migrate md-list to new list-base (#52136)
Migrate md-list to new list-base
2026-05-21 18:57:24 +02:00
karwosts 08f7e97462 Use display precision in statistic card (#52138) 2026-05-21 18:53:04 +02:00
Joakim Plate a5791c8c08 Switch to power-standby for media player (#52127) 2026-05-21 18:53:01 +02:00
Wendelin 6a98a74c58 Fix trigger time margin bottom (#52144)
Fix trigger time margin
2026-05-21 18:39:35 +02:00
renovate[bot] c1df3bc38e Update Node.js to v24.16.0 (#52140) 2026-05-21 17:03:13 +02:00
Wendelin 58d4edaa63 Respect via device in device picker, device list (#52131)
* Respect via device in device picker

* Add context to device data table too
2026-05-21 16:01:43 +02:00
Wendelin 176841e647 Automation triggers - auto IDs (#52129)
* Add auto trigger ids

* improve

* Fix paste with no trigger id

* Fix trigger-id-chip and add jsdocs

* review
2026-05-21 16:52:03 +03:00
renovate[bot] 0759e82b47 Update dependency date-fns to v4.2.1 (#52135)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-21 16:44:50 +03:00
karwosts 7c6609aee7 Make external statistic card unclickable (#52139) 2026-05-21 16:07:43 +03:00
7048c5f3d2 Add entity-first card picker for dashboard (#51651)
Co-authored-by: Wendelin <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-05-21 15:01:10 +02:00
Aidan Timson 9ed47be6c3 Add to for devices page, merge 3 cards into 1 related card (#52119)
* Add to for devices page

* Rename and reuse original dialogs, drop popover

* Reduce

* Lazy context

* Direct access lazy context

* Default width

* Merge automations and scripts cards

* Format

* Loading state

* Rename key

* Tooltip and move key

* Copy icons used in more info

* Sort

* Merge scenes into one "Related" card

* Adjust

* Fix no labs

* Use same wording for device actions

* Cleanup

* Comments for removal

* Cleanup

* Type check

* Template literals

* Add padding
2026-05-21 15:35:14 +03:00
Aidan Timson 128f4526e3 Fix no entities message in area page, improve message (#52130) 2026-05-21 15:23:26 +03:00
Wendelin 3f1b7ce391 Add automation item comments (#52090)
* Add automation comments

* Line wrap

* Review

* Add truncateWithEllipsis with tests

* Review
2026-05-21 13:50:51 +03:00
renovate[bot] 4073b4e1f5 Update dependency date-fns to v4.2.0 (#52132)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-21 13:46:57 +03:00
Paul BotteinandClaude Opus 4.7 86a24d1532 Add temperature and precipitation forecast card features (#51866)
* Rework weather forecast card features

* Add show labels option

* Some fixes

* Fixes and cleaning

* Update palette

* Add reference floor to precipitation bar scale

Light drizzle no longer fills the bar when it's also the period max.
Observed values above the floor still drive the scale (storms read full).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* Feedbacks

* Use weather unit

* Force celcius for gradient

---------

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
2026-05-21 13:42:26 +03:00
Wendelin 46bab5bb01 Automation row target count (#52118)
* Add automation row target count

* fix types
2026-05-20 16:23:40 +03:00
iluvdata e8f486af0a Allow integrations to specify the "domain" of the entity that is rendered in previews (#51829)
* Allow previews to use a domain

* Allow previews to specify preview entity domain

* Allow repair_flow to use previews

* Pull recent changes

* Add domain to previews for TemplatePreview
2026-05-20 12:30:03 +03:00
AlCalzone 211579eade Add Z-Wave credential mangement (#51591)
* first rough draft of Z-Wave credential mangement

* separate user and credentials, error handling, dialog tweaks

* align with upstream API changes, improve error handling

* align more with Matter, use lock entity for services

* remove get_credential_status service

* address review feedback, clarify user types

* user_index -> user_id, fix some pending states

* address review feedback

* clean up unused code, strongly type credential types

* Clear -> Delete, drop icons

* Simplify flow to 1 PIN/Password credential per user

* cleanup, comments, etc.

* address review feedback

* do not show existing credential data

* fix lint errors after branch update

* ignore non-enterable credential types when editing user
2026-05-20 12:05:13 +03:00
markvp f6458925c9 Add hidden device firmware column (#52117) 2026-05-20 08:35:32 +00:00
karwosts ae5e35e7ed Include low battery binary_sensors in low battery count (#52115)
Include low binary battery sensors in low battery count
2026-05-20 08:35:11 +03:00
karwosts 8c1727859a Restore battery chips in Home areas strategy (#52114) 2026-05-20 08:27:12 +03:00
WendelinandPetar Petrov 287562221f Remove live condition test tooltip (#52103)
* Remove live condition test hover

* Update src/components/automation/ha-automation-row-live-test.ts

Co-authored-by: Petar Petrov <[email protected]>

* Review

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-05-20 08:21:45 +03:00
Aidan Timson 2593dfed8d Type assertion and signature improvements for hui changed handlers (#52109)
* Type assertion and signature improvements

* Improve
2026-05-19 20:06:20 +02:00
2d92f1fb3b Forget filter from url: remaining pages (#52061)
* refactor: use separate storage and display filters in backup page

Apply the two-lists pattern in backup page: _filters (@state, display only) +
_storageFilters (@storage sessionStorage, state: false). _storageFilters
is only updated when not in URL mode (_fromUrl flag). Init moved from
connectedCallback to willUpdate(!hasUpdated).

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* refactor: use separate storage and display filters in scenes page

Apply the two-lists pattern in scenes page: _filters (@state, display only) +
_storageFilters (@storage sessionStorage, state: false, with
serializer/deserializer). _storageFilters is only updated when not in
URL mode (_fromUrl flag). Init moved from firstUpdated to
willUpdate(!hasUpdated). The existing updated() hook already calls
_applyFilters() when _entityReg changes, covering the reconnect case.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* refactor: use separate storage and display filters in automations page

Apply the two-lists pattern in automations page: _filters (@state, display only) +
_storageFilters (@storage sessionStorage, state: false, with
serializer/deserializer). _storageFilters is only updated when not in
URL mode (_fromUrl flag). _fromUrl is set before the await in the async
_filterBlueprint() to prevent any user change during the fetch from
persisting. Init moved from firstUpdated to willUpdate(!hasUpdated).

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* refactor: use separate storage and display filters in scripts page

Apply the two-lists pattern in scripts page: _filters (@state, display only) +
_storageFilters (@storage sessionStorage, state: false, with
serializer/deserializer). _storageFilters is only updated when not in
URL mode (_fromUrl flag). _fromUrl is set before the await in the async
_filterBlueprint() to prevent any user change during the fetch from
persisting. Init moved from firstUpdated to willUpdate(!hasUpdated).

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* fix: don't mix URL filters with storage filters in automation,script and scene pages

When URL params are present, _filters starts empty so URL methods build
from scratch. Previously, _filters was pre-populated from _storageFilters
and the spread in _filterLabel()/_filterBlueprint() would merge storage
filters into the URL-injected ones.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Update src/panels/config/backup/ha-config-backup-backups.ts

---------

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
Co-authored-by: Simon Lamon <[email protected]>
2026-05-19 17:47:47 +00:00
pcan08andClaude Sonnet 4.6 8cff4c6bd2 Helpers page: forget filter from url (#51989)
* fix(helpers): clear URL-injected filters on leaving helpers dashboard

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* fix(helpers): restore previous filters after URL-injected navigation

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* refactor: use separate storage and display filters

Apply the same pattern as devices and entities pages: split _filters into
a display-only @state and a _storageFilters persisted to sessionStorage.
_storageFilters is only updated when not in URL mode (_fromUrl flag), so
URL-injected filters never persist to storage.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* fix: reapply filters when helper entities load on reconnect

_applyFilters() was never called when _filters was restored from
sessionStorage, leaving _filteredHelperEntityIds undefined and the
table appearing empty. Call it whenever _helperEntities updates and
active filters are present.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
2026-05-19 19:43:31 +02:00
renovate[bot] 5aa8455861 Update tsparticles to v4.0.2 (#52110) 2026-05-19 14:08:32 +00:00
renovate[bot] 4d142734d8 Migrate Renovate config (#52105) 2026-05-19 14:07:06 +00:00
Aidan TimsonandWendelin eaecc76f36 Add to automation/script with triggers/conditions/actions (#51871)
* Setup default add to actions

* Setup default add to actions

* Move event into external only

* Split into sections

* Padding

* Refactor to single type and adapt app interface to frontend style and vice versa

* Refactor to single type and adapt app interface to frontend style and vice versa

* Condition action and navigation actions

* Open dialogs with trigger, condition, action dialogs

* Add divider before add to

* Move add to to the top

* Action

* Triggers and conditions labs feature check

* Suggestion

* Keep query state

* Change to automation_trigger

* Use typed key instead of finding with icon

* Apply suggestions from code review

Co-authored-by: Wendelin <[email protected]>

* Finish

* Reset state

* Fix navigation resets

* stated

Co-authored-by: Wendelin <[email protected]>

* Split

* Add import, sort imports

---------

Co-authored-by: Wendelin <[email protected]>
2026-05-19 14:57:44 +02:00
Aidan Timson 7dc0033c03 Improve typing on value-changed handlers in card features and state controls (#52107) 2026-05-19 14:28:52 +02:00
Paul Bottein 601e6d0542 Distinguish unknown from unavailable entity state (#52089) 2026-05-19 15:24:50 +03:00
Aidan Timson c7ca3dd837 Typing assertion and generic improvements on area controls and conditions (#52106) 2026-05-19 15:11:31 +03:00
renovate[bot] f75a376add Update dependency lint-staged to v17.0.5 (#52104) 2026-05-19 12:54:34 +01:00
Aidan Timson a541204ffb Match python version with core version (#52102) 2026-05-19 13:27:31 +02:00
Aidan Timson cbbce90eae Remove YARN_VERSION from netlify.toml (inherit packageManager) (#52101) 2026-05-19 13:26:33 +02:00
Wendelin 950de204aa Restyle and improve app info (#52100) 2026-05-19 09:37:38 +01:00
Jan-Philipp Benecke 91b6a4c4b6 Migrate energy sources table and drop mwc data table dependency (#52097)
* Migrate energy sources table and drop mwc data table dependency

* Address review comments

* Address review comments
2026-05-19 09:58:18 +03:00
karwostsandPetar Petrov 643cc4ca7d Make energy electric sources nameable (#52051)
Make electric sources nameable

Co-authored-by: Petar Petrov <[email protected]>
2026-05-19 06:37:49 +00:00
renovate[bot] 9ef71e6cf4 Update tsparticles to v4.0.1 (#52095)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-19 07:18:29 +02:00
renovate[bot] bface72af7 Lock file maintenance (#52096)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-19 07:18:12 +02:00
Paul Bottein 90028b2e22 Clarify cleaning order hint in vacuum more info (#52087) 2026-05-18 22:29:36 +02:00
Ben Hamilton (Ben Gertzfield) 914c48abd5 Allow media player source card feature when list is empty (#52094) 2026-05-18 19:05:12 +00:00
renovate[bot] 79c082acde Update dependency eslint to v10.4.0 (#52093)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-18 20:36:03 +02:00
Marcin BauerandClaude Sonnet 4.6 4728eb7231 Remove arrow icon from continue on error indicator (#52092)
The arrow-right icon next to the alert icon was decorative noise.
With automation comments (#52090) adding yet another icon, simplify
to a single mdiAlertCircleCheck indicator.

Co-authored-by: Claude Sonnet 4.6 (1M context) <[email protected]>
2026-05-18 17:28:14 +03:00
renovate[bot]andPetar Petrov d02b92bd32 Update dependency @tsparticles/engine to v4 (#52091)
* Update dependency @tsparticles/engine to v4

* Bump @tsparticles/preset-links to v4 to match engine

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <[email protected]>
2026-05-18 14:15:54 +00:00
Wendelin 98525d23e6 Lovelace condition live test (#52027)
* Add lovelace condition live test

* Add live card status

* Add empty text
2026-05-18 15:01:56 +02:00
Petar Petrov ec98b21276 Highlight problematic devices in Energy Dashboard list (#52088) 2026-05-18 10:18:27 +01:00
Paulus SchoutsenandClaude defad3beca Treat media player unknown state like off instead of unavailable (#52080)
* Show both power buttons for assumed-state media players when unknown

Media players with assumed state report an unknown state when their
actual power state can't be determined. In that case the entity row and
more info should still expose both turn on and turn off controls so the
user can operate the device.

https://claude.ai/code/session_01JyZojNPCCY65HmRVQaASkG

* Treat media player unknown state like off instead of unavailable

The media player controls lumped the "unknown" state in with
"unavailable" and hid all controls. An unknown state is closer to "off":
the device exists but its power state isn't reported, which is common
for assumed-state players. Only "unavailable" should hide the controls,
so an unknown-state player now shows the turn on button (and both power
buttons when it has an assumed state) in the entity row and more info.

https://claude.ai/code/session_01JyZojNPCCY65HmRVQaASkG

* Adjust comments and variable placement for media player state check

https://claude.ai/code/session_01JyZojNPCCY65HmRVQaASkG

---------

Co-authored-by: Claude <[email protected]>
2026-05-18 09:58:01 +03:00
Petar Petrov 635d61256b Fix Y-axis label precision in statistics and history charts (#52038) 2026-05-18 08:17:43 +02:00
renovate[bot] 60c5bea6e0 Update formatjs monorepo (#52085)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-18 07:03:08 +02:00
renovate[bot] aed83ccc07 Update dependency @codemirror/view to v6.43.0 (#52081)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-18 07:02:53 +02:00
pcan08andClaude Sonnet 4.6 85b2ca377a Add sound mode filtering to media-player-sound-mode feature (#52058)
* feat(tile-card): add sound mode filtering to media-player-sound-mode card feature

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Attempt to fix CI lint error

---------

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
2026-05-17 15:41:46 +03:00
Simon Lamon e194247f50 Add percentage of battery state of charge (#52065)
Add percentage of battery soc
2026-05-17 15:40:42 +03:00
karwosts c79956b893 Dynamically compute overflow for ha-data-table-labels (#52069)
* Dynamically compute overflow for ha-data-table-labels

* update
2026-05-17 15:39:49 +03:00
renovate[bot] abb4cbc263 Update dependency lit-html to v3.3.3 (#52073)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-17 07:01:11 +00:00
pcan08andClaude Sonnet 4.6 811397f740 Entities page: forget filter from url (#51988)
* fix(entities): clear URL-injected filters on leaving entities dashboard

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* fix(entities): restore previous filters after URL-injected navigation

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* refactor: use separate storage and display filters

Apply the same pattern as devices page: split _filters into a display-only
@state and a _storageFilters persisted to sessionStorage. _storageFilters
is only updated when not in URL mode (_fromUrl flag), so URL-injected
filters never persist to storage.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
2026-05-17 08:55:18 +02:00
dependabot[bot] c7c78bd587 Bump actions/labeler from 6.0.1 to 6.1.0 (#52077)
Bumps [actions/labeler](https://github.com/actions/labeler) from 6.0.1 to 6.1.0.
- [Release notes](https://github.com/actions/labeler/releases)
- [Commits](https://github.com/actions/labeler/compare/634933edcd8ababfe52f92936142cc22ac488b1b...f27b608878404679385c85cfa523b85ccb86e213)

---
updated-dependencies:
- dependency-name: actions/labeler
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-17 08:53:19 +02:00
renovate[bot] bf67a3ec1d Update formatjs monorepo (#52078)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-17 08:53:15 +02:00
dependabot[bot] b0772d6701 Bump relative-ci/agent-action from 3.2.2 to 3.2.3 (#52076)
Bumps [relative-ci/agent-action](https://github.com/relative-ci/agent-action) from 3.2.2 to 3.2.3.
- [Release notes](https://github.com/relative-ci/agent-action/releases)
- [Commits](https://github.com/relative-ci/agent-action/compare/3c681926017930047fc03acaa35cd6a44efcbfc3...fcf45416581928e8dd62eded78ce98c78e5149f8)

---
updated-dependencies:
- dependency-name: relative-ci/agent-action
  dependency-version: 3.2.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-17 08:53:09 +02:00
dependabot[bot] d484ef3f2f Bump release-drafter/release-drafter from 7.2.1 to 7.3.0 (#52075)
Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 7.2.1 to 7.3.0.
- [Release notes](https://github.com/release-drafter/release-drafter/releases)
- [Commits](https://github.com/release-drafter/release-drafter/compare/563bf132657a13ded0b01fcb723c5a58cdd824e2...c2e2804cc59f45f57076a99af580d0fedb697927)

---
updated-dependencies:
- dependency-name: release-drafter/release-drafter
  dependency-version: 7.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-17 08:53:06 +02:00
dependabot[bot] 6f8fffccbd Bump github/codeql-action from 4.35.3 to 4.35.4 (#52074)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.35.3 to 4.35.4.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/e46ed2cbd01164d986452f91f178727624ae40d7...68bde559dea0fdcac2102bfdf6230c5f70eb485e)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.35.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-17 08:53:03 +02:00
renovate[bot] df03a0dfd9 Update dependency lit to v3.3.3 (#52072)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-17 08:52:57 +02:00
renovate[bot] bb12cb19b5 Update dependency @rspack/core to v2.0.3 (#52059)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-15 15:53:06 +02:00
renovate[bot] 7baf7f4701 Update formatjs monorepo (#52060)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-15 15:52:44 +02:00
pcan08andClaude Sonnet 4.6 0dfb801ff6 Devices page: forget filter from url (#51986)
* fix(devices): clear URL-injected filters on leaving devices dashboard

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* fix(devices): restore previous filters after URL-injected navigation

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* refactor(devices): use separate storage and display filters

Replace the disconnect-callback approach with two distinct filter states:
- _storageFilters: persisted to sessionStorage, updated only when not in
  URL mode (manual filter changes and clear)
- _filters: display-only state, initialized from _storageFilters on first
  render, overwritten by URL params without touching storage

_storageFilters is frozen while _fromUrl is true, preserving the user's
previous manual filters for the next normal visit.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
2026-05-15 08:45:51 +02:00
renovate[bot]andPetar Petrov d94dcf50fb Update dependency eslint-plugin-lit to v2.3.1 (#52057)
* Update dependency eslint-plugin-lit to v2.3.1

* Fix lit/prefer-query-decorators violations

eslint-plugin-lit 2.3.0 introduced this rule. Replace querySelector
calls with @query/@queryAll decorators where the selector is static.
Use per-line disables for dynamic selectors that can't use decorators.

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <[email protected]>
2026-05-15 09:37:14 +03:00
Petar Petrov fb1f5ef722 Dev tools -> Templates: observe tip height with ResizeObserver (#52048)
Replaces the per-render scrollHeight read from #52012 with a
ResizeObserver started in firstUpdated, writing --tip-height directly to
the host style. Removes the need for a manual refresh when the viewport
crosses a wrap threshold, drops the unreachable isNaN check, and lets
the @query decorator stand in for the editor-tip id.
2026-05-15 08:37:04 +02:00
pcan08andClaude Sonnet 4.6 e5d5797d91 Add mute to media player volume slider feature (#52050)
* feat: add mute button to media-player-volume-slider card feature

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* refactor(tile-card): extract mute button logic into shared utility

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
2026-05-15 09:31:45 +03:00
pcan08andClaude Sonnet 4.6 adee24f745 fix filter badge count (increment) on panel re-open (#52054)
fix(filter): prevent badge count from incrementing on panel re-open

Integrations and domains filter panels use lazy rendering: the list is
destroyed on close and recreated on open. On recreation, MWC fires a
`selected` event with a diff for each pre-selected item, which the
diff-based handler interpreted as a new user selection, appending
duplicates to `this.value` on every expansion.

Switch both handlers to the full-set approach (`SelectedDetail<Set<number>>`)
already used by labels, states, and voice-assistants, rebuilding the value
from the complete index set. Add the `preserved` pattern to retain
selections hidden by the search filter. Also add `_value` to the `_domains`
memoize signature to ensure cache invalidation when the selection changes.

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
2026-05-15 08:38:13 +03:00
karwosts 1b695e24d0 Ensure statistics-graph-card uses correct external stat names (#52055) 2026-05-15 08:36:33 +03:00
pcan08andClaude Sonnet 4.6 7f9259edf9 Add shuffle and repeat controls to media-player-playback feature (#52052)
feat(tile-card): add shuffle and repeat controls to media-player-playback card feature

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
2026-05-14 20:55:14 +02:00
renovate[bot] 6954dc1a54 Update dependency typescript-eslint to v8.59.3 (#52056)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-14 18:37:14 +00:00
renovate[bot] 032d0fb332 Update vitest monorepo to v4.1.6 (#52053)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-14 20:28:13 +02:00
Jan-Philipp Benecke 43ed97da43 Migrate gallery drawer to ha-drawer and drop mwc-drawer dependency (#52031)
* Migrate gallery drawer to ha-drawer and drop md-drawer dependency

* Trigger Build

* Fix scrolling
2026-05-14 15:52:24 +02:00
Aidan Timson 9f4d35bc05 Remove advanced mode navigation gating (#52045) 2026-05-14 15:37:28 +03:00
ildar170975 11afde6b5f Dev tools -> Templates: fix editor height (#52012)
* fix editor height

* get a height of ha-tip by `Element.scrollHeight`

* minor cleanup
2026-05-14 15:34:23 +03:00
1b0dcb33b1 Add source filtering to media-player-source card feature (#52046)
Co-authored-by: Claude Sonnet 4.6 <[email protected]>
Co-authored-by: Aidan Timson <[email protected]>
2026-05-14 12:26:36 +00:00
Aidan Timson 67eecbc51d Remove "advanced" service controls (#52041)
Remove "Advanced" service controls
2026-05-14 15:19:52 +03:00
Bram Kragten 9298e00f20 Merge branch 'rc' 2026-05-14 11:32:44 +02:00
Bram Kragten 70085d4bad Bumped version to 20260429.4 2026-05-14 11:32:29 +02:00
Wendelin d83a553b62 Reactivate iOS focus element (#52020) 2026-05-14 11:31:23 +02:00
Wendelin cab5c6af30 Add macOS version mapping for Safari 26 support (#51999) 2026-05-14 11:24:44 +02:00
Petar Petrov d44d8a6dbd Fix water sankey untracked consumption with nested sub-trackers (#51998) 2026-05-14 11:24:43 +02:00
karwosts 3cf1d94b92 Fix sensor card when visibility changes (#51953)
* Fix sensor card when visibility changes

* History card

* map card

* trend graph

* minor change
2026-05-14 11:23:31 +02:00
Tom Carpenter 9f5f849e32 Fix demo instance mock recorder data generation (#51950)
Fix demo mock recorder data end times

The mock recorder was setting the start and end time for each of the samples to be the same value, causing the solar graph in the energy dashboard to render incorrectly.

Fix the recorder to set the end time of each sample to the start time of the next.
2026-05-14 11:21:23 +02:00
karwosts 27e9926363 Fix heading badge current-entity visibility (#51942) 2026-05-14 11:21:22 +02:00
karwosts efe734892a Fix create new person with login (#51939) 2026-05-14 11:21:21 +02:00
Tom Carpenter b3d79e312d Remove extra padding to right of ha-switch (#51932)
Fix empty padding to right of ha-switch

When the label slot for the ha-switch is empty, the initial margin is still present which causes an odd misalignment on the switches in e,g, the entities card.

To fix this, if the label slot is empty, hide the label to remove the unwanted margin.
2026-05-14 11:21:19 +02:00
Marcin BauerandClaude Sonnet 4.6 ecfef9e112 Improve continue on error tooltip in automation editor (#51926)
Co-authored-by: Claude Sonnet 4.6 (1M context) <[email protected]>
2026-05-14 11:21:18 +02:00
George Caliment ca960446f0 Fixed blueprint rows event result chip render when collapsed (#51910) 2026-05-14 11:21:17 +02:00
Petar Petrov a6eb722025 Clamp power sources graph usage line to non-negative (#51902) 2026-05-14 11:21:16 +02:00
Paul Bottein f3ff01ace4 Fix race condition loading home dashboard favorites (#51901) 2026-05-14 11:21:15 +02:00
karwosts d5e1a373ec Fix entity filter card (#51895) 2026-05-14 11:21:14 +02:00
Wendelin e1b9a1a185 Fix content padding picker (#51889) 2026-05-14 11:21:12 +02:00
Paul Bottein efe8eaa941 Move logs page search bar out of the toolbar (#51887) 2026-05-14 11:21:11 +02:00
Wendelin 5856196ef3 Improve automation event chips action, condition (#51886) 2026-05-14 11:21:10 +02:00
Clément NotinandWendelin 2671a8c64b Fix quick bar search not focused on first open (#51822)
Co-authored-by: Wendelin <[email protected]>
2026-05-14 11:21:09 +02:00
renovate[bot] 969ccf85d2 Update dependency @rsdoctor/rspack-plugin to v1.5.11 (#52040) 2026-05-14 08:51:19 +00:00
pcan08andClaude Sonnet 4.6 500ce18ae5 Add volume mute button to media player playback card feature (#52029)
feat: add volume mute button to media player playback card feature

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
2026-05-14 09:04:15 +03:00
b413a7742c Add mute button to media player volume buttons card f… (#52028)
* feat(lovelace): add mute button to media player volume buttons card feature

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* feat: add show_mute_button config option to volume buttons feature

* feat: disable show_mute_button option when entity does not support mute

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-05-14 05:27:21 +00:00
karwosts e84373fdbd Fix energy device name dialog placeholders (#52032)
* Fix energy device placeholders

* array indexes
2026-05-14 08:17:55 +03:00
Simon Lamon caaee14856 Sync selected index in ha-list-base after initialization (#52033)
* Fix selection when they register after selectedIndices has been initialized

* Better fix
2026-05-14 08:16:35 +03:00
karwosts 28f04df81d Improve statistic picker handling of external stats (#52037) 2026-05-14 08:15:54 +03:00
Wendelin 48a8c5b2d5 Migrate ha-md-list to ha-list-base 1 (#52019)
* Migrate ha-md-list to ha-list-base

* Migrate ha-md-list to ha-list-base

* Next batch

* review
2026-05-13 19:51:31 +02:00
Petar Petrov 45312ba7fd Fix water sankey untracked consumption with nested sub-trackers (#51998) 2026-05-13 18:26:41 +02:00
Jan-Philipp Benecke b5dad80e19 Migrate ha-drawer to Web Awesome drawer (#51990)
* Migrate ha-drawer to Web Awesome drawer

* Make CI happy

* Implement swipe gesture support for ha-drawer and fix RTL support

* Fix CI

* Fix CI

* Readd border

* Fix sidebar

* Layout fix

* Fix sluggish scroll on mobile

* Fix CI

* Add transition
2026-05-13 17:01:39 +02:00
Aidan TimsonandWendelin ae85263d91 Add context for hass.format*, replace hass with lazy context on yaml/code editor (#52021)
* Add context for `hass.format*`

* Remove hass and use lazy context for ha-code-editor

* Remove hass and use context where hass isnt needed extensively

* Finish context switch for code editor

* Remove hass from yaml-editor calls

* Cleanup unused

* Update src/util/documentation-url.ts

Co-authored-by: Wendelin <[email protected]>

* Fix

---------

Co-authored-by: Wendelin <[email protected]>
2026-05-13 16:57:06 +02:00
ildar170975andPetar Petrov c5000bcdde hui-history-graph-card-editor: add more options (#51749)
* add more options for history-graph-card

* add more options for history-graph-card

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-05-13 14:13:40 +00:00
karwosts 5e085c70b0 Make gas & water sources nameable (#52011)
* Make gas & water sources nameable

* Add placeholders
2026-05-13 17:11:20 +03:00
Wendelin 71fc44284c Add tags to installed apps (#51987)
* Add supervisor app state tags and update translations

* Update styles

* Review

* Review

* unknown icon, lighter running green
2026-05-13 16:02:33 +02:00
Petar Petrov b7e1e23eaa Position chart tooltip beside cursor instead of over data point (#51904) 2026-05-13 15:47:15 +02:00
Aidan TimsonandPetar Petrov 2ee7c6fc2a Add context to statistics panel (#52003)
* Add context to statistics panel

* Lazy context

* Cleanup

* Types

* Use api context, use registries, update helpers to only need api

* Infer type

Co-authored-by: Petar Petrov <[email protected]>

* Remove —

* Format

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-05-13 15:38:56 +03:00
Wendelin 7d069c4f5e Fix automation row event chip styles (#52022) 2026-05-13 13:08:16 +03:00
Aidan Timson 20bf8181dd Add context to states panel (#52007)
* Add device and area to states panel. Use lazy context

* Format

* Add filters for devices and areas

* Format

* Registries, api context
2026-05-13 13:03:03 +03:00
Bram Kragten 1884a06f98 Create third party license file during production build, add CI (#30360)
* Generate third party license file during production build

* Add license check CI step

* Address review comments: use license-checker-rseidelsohn, add version validation for LICENSE_OVERRIDES

* Fix license-checker-rseidelsohn import (CJS module, use require)
2026-05-13 11:28:22 +02:00
Wendelin 0c63078923 Reactivate iOS focus element (#52020) 2026-05-13 09:53:12 +01:00
WendelinandPetar Petrov c6ae47f1c8 Add automation live condition tests (#52004)
* add automation live condition

* Review

* Update src/panels/config/automation/condition/ha-automation-condition-row.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-05-13 10:19:12 +02:00
renovate[bot] 0a9fe0e0c7 Update dependency lint-staged to v17.0.4 (#52014)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-13 06:50:36 +02:00
ildar170975 c3480bc319 hui-statistics-graph-card-editor: remove unneeded </div> (#52015)
remove div
2026-05-13 06:50:22 +02:00
Wendelin 8af5908682 Fix add T/C/A floor auto open; Target details adaptive dialog. (#52001)
* Auto open single floor

* Use adaptive dialog for target details

* review
2026-05-12 19:28:24 +03:00
George Caliment 60e95b886c Fixed how ha-entity-toggle sets ha-switch styles var (#51984) 2026-05-12 16:46:01 +02:00
WendelinandPetar Petrov 0385ca8076 Add link to single integration entry warning (#51977)
* Add link to single integration entry warning

* Refactor single config entry warning: move function to dedicated file and update imports

* Implement single config entry warning dialog and update related functions

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-05-12 10:33:02 +00:00
Tom Carpenter 02c65fc8cb Position bars on statistics charts at centre of data point time range (#51957)
* Position statistics chart bars at centre of time range

When displaying 5minute or hourly data periods, position each bar at the midpoint of its start/end time. This mimics the behaviour in the various energy cards for consistency.

* Move limit comparison into pushData
Results in clearer function argument usage.

* Add time range for statistics-chart bar tooltip

When using hour/5minute periods the bars are recentred. Update the tooltips to show time range they cover.

* Omit time from tooltip for bars with periods of day or longer

Don't clutter the tooltip with unnecessary times of 0:00 when using day/month/year timescales on bar charts, just show the date range.

For week/month/year, we now also include the range of dates of the bar rather than just the start date.
2026-05-12 12:33:39 +03:00
Wendelin 49290d5c83 Add macOS version mapping for Safari 26 support (#51999) 2026-05-12 09:26:04 +02:00
Jan-Philipp Benecke 08aff3bfd7 Replace variable display in trace view with ha-code-editor (#51997)
* Replace variable display in trace view with ha-code-editor

* Replace variable display in trace view with ha-code-editor
2026-05-12 09:13:52 +03:00
Petar Petrov 455fa45b9c Show battery state of charge on the energy distribution card (#51812)
* Show battery state of charge on the energy distribution card

* css tweak

* Only show SOC-based battery icon when the period includes now
2026-05-12 08:38:04 +03:00
karwosts 2e56a4ec4c fix spurious timeline-chart exceptions (#51996) 2026-05-12 08:13:07 +03:00
Copilot 76131ff09e Hide standalone helpers and entities from the Home “Other devices” view (#51853)
* Initial plan

* Hide standalone helpers and entities from other devices view

Agent-Logs-Url: https://github.com/home-assistant/frontend/sessions/ecad0a9d-6983-4c5c-9728-6ef04be88e42

* Simplify other devices strategy test assertions

Agent-Logs-Url: https://github.com/home-assistant/frontend/sessions/ecad0a9d-6983-4c5c-9728-6ef04be88e42

* Clean up other devices strategy test helpers

Agent-Logs-Url: https://github.com/home-assistant/frontend/sessions/ecad0a9d-6983-4c5c-9728-6ef04be88e42

* Polish other devices strategy test fixtures

Agent-Logs-Url: https://github.com/home-assistant/frontend/sessions/ecad0a9d-6983-4c5c-9728-6ef04be88e42

* Remove other devices strategy test file

Agent-Logs-Url: https://github.com/home-assistant/frontend/sessions/2a54dac8-a7fc-42e5-a309-e0af02ca4303

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-05-11 20:27:00 +02:00
WendelinandSimon Lamon 89d8723c5a Fix dialog expose entity in firefox (#51974)
* Migrate dialog-expose-entity to new dialog and migrate everything thats needed for this.

* Load virtualizer after dialog show is ready

* Use entities context instead of registries in ha-state-icon

* fix types

* Update src/panels/config/voice-assistants/dialog-expose-entity.ts

---------

Co-authored-by: Simon Lamon <[email protected]>
2026-05-11 18:13:45 +00:00
renovate[bot] 7bdb63a6fe Update dependency terser-webpack-plugin to v5.6.0 (#51992)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-11 17:58:16 +00:00
Jan-Philipp Benecke eed79f1797 Use ha-tab-group for in automation/script trace page (#51991) 2026-05-11 19:50:10 +02:00
Joakim Plate 76665009da Let input entities date and number be active when unknown (#29306)
Let input of date and number be active when unknown
2026-05-11 17:54:40 +02:00
renovate[bot] 6d7d08fddc Update dependency lint-staged to v17.0.3 (#51985)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-11 17:52:39 +02:00
Alex van den Hoogen 77d4e6dc43 Fixes tile card misalignment (#25745) (#51964)
* Fixes tile card misalignment (#25745)

Removes an unnecessary vertical padding on the tile card content that causes a misalignment within the Android Companion app. This padding isn't needed because the contents are already vertically aligned with flexbox anyway.

* Added a min-height to tile container

As requested in the review, added a minimal height to the content of the
tile container to support non-section layouts.
2026-05-11 17:33:47 +02:00
Wendelin 7345256b30 Fix ha list ha sidebar (#51979)
* Fix ha-list in ha-sidebar

* Fix ha-row-item start/end slots
2026-05-11 16:34:37 +02:00
renovate[bot] e0d98e95fa Update dependency @lokalise/node-api to v16 (#51983)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-11 15:57:40 +03:00
renovate[bot] 17041044cf Update dependency @rsdoctor/rspack-plugin to v1.5.10 (#51982)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-11 15:14:55 +03:00
Marcin BauerandClaude Sonnet 4.6 9a10cd7fa8 Fix automation sidebar top padding (#51978)
Co-authored-by: Claude Sonnet 4.6 (1M context) <[email protected]>
2026-05-11 11:12:15 +01:00
Aidan Timson fa354aed2a Remove hass from dialog, bottom-sheet and callers (#51976)
* Remove hass prop from adaptive and bottom sheet

* Remove hass

* Remove hass prop from callers

* Prepare commented code for context

* Pass object

* Restore

* Restore

* Remove hass

* Remove hass
2026-05-11 12:01:11 +02:00
Wendelin c044d96712 Automation editor: Add click actions to row targets (#51909)
* Add click actions to automation row targets

* Review
2026-05-11 11:28:36 +03:00
Michael BisbjergandPetar Petrov 1b736960b2 Add backup locations filter (#51970)
* Add backup locations filter

* Update src/panels/config/backup/ha-config-backup.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-05-11 05:39:43 +00:00
George Caliment e8c8047ff9 Fixed blueprint rows event result chip render when collapsed (#51910) 2026-05-11 08:30:47 +03:00
karwosts 9376f4ce81 Fix sensor card when visibility changes (#51953)
* Fix sensor card when visibility changes

* History card

* map card

* trend graph

* minor change
2026-05-11 08:24:34 +03:00
renovate[bot] 7befa9782a Update dependency tar to v7.5.15 (#51969)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-11 08:10:15 +03:00
renovate[bot] 0186ec1265 Update dependency @codemirror/view to v6.42.1 (#51965)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-10 19:13:48 +02:00
Tom Carpenter 641c444fdc Fix demo instance mock recorder data generation (#51950)
Fix demo mock recorder data end times

The mock recorder was setting the start and end time for each of the samples to be the same value, causing the solar graph in the energy dashboard to render incorrectly.

Fix the recorder to set the end time of each sample to the start time of the next.
2026-05-10 10:18:44 +02:00
renovate[bot] 93dd2a5dc8 Update dependency fs-extra to v11.3.5 (#51956)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-10 10:00:13 +02:00
dependabot[bot] f7cf3d5b39 Bump github/codeql-action from 4.35.2 to 4.35.3 (#51959)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.35.2 to 4.35.3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/95e58e9a2cdfd71adc6e0353d5c52f41a045d225...e46ed2cbd01164d986452f91f178727624ae40d7)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.35.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-10 10:00:10 +02:00
dependabot[bot] b861543865 Bump release-drafter/release-drafter from 7.2.0 to 7.2.1 (#51960)
Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 7.2.0 to 7.2.1.
- [Release notes](https://github.com/release-drafter/release-drafter/releases)
- [Commits](https://github.com/release-drafter/release-drafter/compare/5de93583980a40bd78603b6dfdcda5b4df377b32...563bf132657a13ded0b01fcb723c5a58cdd824e2)

---
updated-dependencies:
- dependency-name: release-drafter/release-drafter
  dependency-version: 7.2.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-10 10:00:07 +02:00
renovate[bot] e749956eaa Update dependency @rspack/core to v2.0.2 (#51955)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-09 19:23:29 +02:00
renovate[bot] 5b0f0dade5 Update dependency lint-staged to v17.0.2 (#51952)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-09 15:06:17 +02:00
renovate[bot] f86d2753f7 Update dependency lint-staged to v17 (#51949)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-09 10:31:16 +00:00
renovate[bot] f3f549737f Update CodeMirror (#51948)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-09 10:31:01 +00:00
Petar Petrov d9929905b5 Localize trigger description in trace timeline (#51927) 2026-05-09 12:23:46 +02:00
renovate[bot] 25487e373e Update dependency sinon to v22 (#51945)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-09 09:20:09 +03:00
karwosts 2ff56d3eb7 Fix heading badge current-entity visibility (#51942) 2026-05-09 09:13:58 +03:00
renovate[bot] 6c4f7506b5 Update dependency tar to v7.5.14 (#51944)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-09 09:07:54 +03:00
karwosts 5755aebff6 Fix create new person with login (#51939) 2026-05-08 20:39:45 +02:00
dependabot[bot] 76996ea3cc Bump fast-uri from 3.1.0 to 3.1.2 (#51938)
Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.0 to 3.1.2.
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.0...v3.1.2)

---
updated-dependencies:
- dependency-name: fast-uri
  dependency-version: 3.1.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-08 18:17:23 +00:00
renovate[bot] d7d6766f80 Update dependency @babel/preset-env to v7.29.5 (#51935)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-08 20:11:42 +02:00
dependabot[bot] b632e8e6f8 Bump flatted from 3.4.1 to 3.4.2 (#51937)
Bumps [flatted](https://github.com/WebReflection/flatted) from 3.4.1 to 3.4.2.
- [Commits](https://github.com/WebReflection/flatted/compare/v3.4.1...v3.4.2)

---
updated-dependencies:
- dependency-name: flatted
  dependency-version: 3.4.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-08 18:09:10 +00:00
Tom Carpenter ee4eaaa613 Remove extra padding to right of ha-switch (#51932)
Fix empty padding to right of ha-switch

When the label slot for the ha-switch is empty, the initial margin is still present which causes an odd misalignment on the switches in e,g, the entities card.

To fix this, if the label slot is empty, hide the label to remove the unwanted margin.
2026-05-08 20:08:12 +02:00
renovate[bot] 395faebd0c Update formatjs monorepo (#51936)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-08 18:07:56 +00:00
Petar Petrov 71b8676e02 Treat unregistered entities as having no entity_category (#51925) 2026-05-08 20:06:31 +02:00
Petar Petrov d54516dd42 Show external access as disabled for local-only users (#51931) 2026-05-08 19:58:49 +02:00
Aidan Timson 1a3eef9c4f Refactor config flow dialog (#51924)
* Move buttons to standard footers

* Fix negative margin, use space tokens

* Space tokens with tweaks

* Hide form if empty

* Standardise padding

* Only show skip if no devices are assigned

* Use ref instead of queries

* nothing

* Token

* Typing
2026-05-08 17:56:21 +03:00
Aidan TimsonandPetar Petrov 1f2f9e6330 Filter all data points for integration page (#51923)
* Filter all datapoints for integration page (discovery, attention flows)

* Use multitermsearch

Co-authored-by: Petar Petrov <[email protected]>

* Split

* memoise flows

* memoise entries too

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-05-08 17:33:22 +03:00
Petar Petrov 1774219f9a Clamp power sources graph usage line to non-negative (#51902) 2026-05-08 13:36:07 +02:00
Marcin BauerandClaude Sonnet 4.6 ac66ad1a32 Improve continue on error tooltip in automation editor (#51926)
Co-authored-by: Claude Sonnet 4.6 (1M context) <[email protected]>
2026-05-08 13:34:34 +02:00
Wendelin 7bb51c746d Allow ha-list-items within sub components shadow DOM (#51907)
* Allow ha-list-items within sub components shadow dom.

* fix sort

* Fix start end slots
2026-05-08 09:24:13 +03:00
Tom Carpenter 13e32c41e0 Round bar chart end time to half-hour mark for hourly periods (#51916)
* Don't round bar chart end time for hourly periods

If we do this, it causes the last hour of the energy dashboard bar charts to be cut off. This went unnoticed previously because they were placed at times of xx:00, while now they are times of xx:30.

* Round to 30minute for hourly bars rather than leaving unrounded
This better matches the axes with line charts by cutting off padding into the next day, whilst leaving mid-point bars visible.

* Update tests to account for new behaviour
2026-05-08 08:51:27 +03:00
Tom Carpenter d89af52e3b Fix type exception in ha-chart-base _updateSankeyRoam() (#51917)
Fix type exception in chart _updateSankeyRoam

When there is no data for some series in the sankey chart, then the series map can contain null entries. This raised an exception as the _updateSankeyRoam tried to access the 'type' property on a null value.

Add an explicit check for null. Using != not !== to also filter undefined in case that ever shows up.
2026-05-08 08:48:24 +03:00
Simon Lamon da6114fa5f Deduplicate workbox by updating patch (#51919)
Deduplicate by updating patch
2026-05-08 08:47:25 +03:00
renovate[bot] c144533834 Update workbox monorepo to v7.4.1 (#51918)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-08 04:54:50 +00:00
renovate[bot] e6c6ab93ef Update dependency typescript-eslint to v8.59.2 (#51914)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-08 06:46:15 +02:00
renovate[bot] 62df56e5d9 Update dependency barcode-detector to v3.1.3 (#51913)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-08 06:46:00 +02:00
George Caliment d169eb9c49 Fix ResizeObserver loop on firefox browser (#51897)
* Fix ResizeObserver loop on firefox browser

* Replace requestAnimationFrame workaround
2026-05-07 15:46:04 +03:00
Aidan Timson 0e1aa400d7 Skeleton for graphs (loading animation) (#51882) 2026-05-07 10:20:35 +01:00
Petar Petrov 00e57454ed Add volume up/down to media player playback tile feature (#51898) 2026-05-07 09:52:15 +01:00
Paul Bottein 0e6b342b3f Fix race condition loading home dashboard favorites (#51901) 2026-05-07 09:47:07 +01:00
ildar170975andPetar Petrov 7ad8c27aa3 Statistics graph card: allow color customization (#51824)
* add a possibility to customize color

* add a possibility to customize color

* add GraphEntityConfig

* add basic color support

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-05-07 11:19:50 +03:00
ildar170975andPetar Petrov f01c202bbd History graph card: allow color customization for "line" graphs (#51802)
* add "color" option

* add GraphEntityConfig type

* add "color" option

* add "color" option

* add "color" option

* typescript-eslint/no-shadow

* linter

* add graphEntitiesConfigStruct

* import graphEntitiesConfigStruct

* typo in import

* leftout

* Create order-properties-graph.ts

* use common orderPropertiesGraphCard()

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

* Add missing Struct type import

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-05-07 07:17:06 +00:00
TimothyandPetar Petrov ac6439bb5b Give less importance to the custom tag and tag id in the UI (#51884)
* Give less importance to the custom tag and tag id in the UI

* Make an expandable version prefill with a tagID

* Improve Edit tag dialog to be more usable

* Apply manually prettier

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-05-07 06:17:54 +00:00
Wendelin 33d29e3abd New list components (#51705)
* add new ha-list options

* Refactor ha-list components to use ha-list-selectable and ha-list-item-option

* fix types in gallery

* fix filter-floor-areas

* Review

* Fix list aria-label
2026-05-07 08:47:10 +03:00
karwosts ca4ff25073 Fix entity filter card (#51895) 2026-05-07 08:44:42 +03:00
George Caliment a4b4e285d8 Fixed detail tooltip overflow on charts (card or card detail) (#51891) 2026-05-07 08:43:34 +03:00
dependabot[bot] 850b597e47 Bump ip-address from 10.1.0 to 10.2.0 (#51892)
Bumps [ip-address](https://github.com/beaugunderson/ip-address) from 10.1.0 to 10.2.0.
- [Commits](https://github.com/beaugunderson/ip-address/commits)

---
updated-dependencies:
- dependency-name: ip-address
  dependency-version: 10.2.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-06 18:00:40 +00:00
WendelinandCopilot b2e07c3ba5 Add ha-radio-group and ha-radio-option (#51864)
* add ha-radio-group and ha-radio-option

Co-authored-by: Copilot <[email protected]>

* Migrate ha-radio

* add docs, remove ha-radio

* update webawesome

---------

Co-authored-by: Copilot <[email protected]>
2026-05-06 19:51:02 +02:00
Aidan Timson 76c871b249 Add scenes and scripts to labels nav actions (#51888)
* Add scenes and scripts to labels nav actions

* Tighten type and flatten key
2026-05-06 19:40:41 +02:00
Wendelin c15d514918 Improve automation event chips action, condition (#51886) 2026-05-06 18:11:12 +02:00
Wendelin 8a52fa5f7a Fix content padding picker (#51889) 2026-05-06 18:09:01 +02:00
Paul Bottein 22c89ceff9 Move logs page search bar out of the toolbar (#51887) 2026-05-06 14:05:55 +00:00
Clément NotinandWendelin 764f99beb3 Fix quick bar search not focused on first open (#51822)
Co-authored-by: Wendelin <[email protected]>
2026-05-06 12:19:28 +00:00
Aidan Timson 64b242e89c Add error handling for AbortError in view transitions (#51883) 2026-05-06 14:07:26 +02:00
Bram Kragten 8620653a54 Merge branch 'rc' 2026-05-06 11:19:42 +02:00
Bram Kragten c4f4cbd323 Bumped version to 20260429.3 2026-05-06 11:18:01 +02:00
Paul Bottein 2e0df00f0f Fix name for battery entities without device (#51879) 2026-05-06 11:17:09 +02:00
Wendelin ce02f8072d Reduce progress bar default height (#51878)
reduce progress bar default height to 12px
2026-05-06 11:17:08 +02:00
Paul Bottein c973aa7516 Fix media controls in media player more info dialog (#51877) 2026-05-06 11:17:07 +02:00
Paul Bottein 1e2328707c Fix switch clipping in view visibility editor (#51876) 2026-05-06 11:17:06 +02:00
Wendelin 56368b88cd Remove duplicate definition in semantic colors (#51875)
* Remove duplicate definition in semantic colors

* rearrange surface tokens
2026-05-06 11:17:05 +02:00
Aidan TimsonandCursor fcd4f177c1 Fix Safari 14 legacy bundle require errors (#51868)
Co-authored-by: Cursor <[email protected]>
2026-05-06 11:17:04 +02:00
Wendelin 7423ae7316 Fix integration search shrink on mobile (#51867) 2026-05-06 11:17:03 +02:00
Marcin BauerandClaude Sonnet 4.6 4427c581f1 Fix automation row right padding and soften chip highlight animation (#51865)
Co-authored-by: Claude Sonnet 4.6 (1M context) <[email protected]>
2026-05-06 11:17:02 +02:00
Paul Bottein cf86bb9821 Use ha-switch instead of ha-control-switch in entity toggle (#51852) 2026-05-06 11:17:01 +02:00
karwosts 897802dc16 Change display for uptime sensors (#51830) 2026-05-06 11:17:00 +02:00
Aidan TimsonandCursor 103861bf71 Fix Safari 14 legacy bundle require errors (#51868)
Co-authored-by: Cursor <[email protected]>
2026-05-06 10:55:53 +02:00
Marcin BauerandClaude Sonnet 4.6 b0a885f504 Fix automation row right padding and soften chip highlight animation (#51865)
Co-authored-by: Claude Sonnet 4.6 (1M context) <[email protected]>
2026-05-06 09:26:21 +01:00
Paul Bottein d620919643 Fix switch clipping in view visibility editor (#51876) 2026-05-06 09:19:10 +01:00
Paul Bottein f190a4f75c Fix name for battery entities without device (#51879) 2026-05-06 08:15:54 +00:00
Wendelin 9c0f4ef8eb Remove duplicate definition in semantic colors (#51875)
* Remove duplicate definition in semantic colors

* rearrange surface tokens
2026-05-06 10:12:15 +02:00
GeorgeC f25692a6f3 Handle nested dialogs inside dialog-form (#51715) 2026-05-06 09:52:56 +02:00
Wendelin 8b0d193742 Reduce progress bar default height (#51878)
reduce progress bar default height to 12px
2026-05-06 09:39:23 +02:00
Paul Bottein da8dedbdea Fix media controls in media player more info dialog (#51877) 2026-05-06 09:24:10 +02:00
Wendelin 405ea0d09d Fix integration search shrink on mobile (#51867) 2026-05-05 13:12:52 +01:00
karwosts afce0703e3 Change display for uptime sensors (#51830) 2026-05-05 09:52:03 +02:00
Paul Bottein be0abafdff Use ha-switch instead of ha-control-switch in entity toggle (#51852) 2026-05-05 09:47:38 +02:00
renovate[bot] 4aa9b188a0 Update dependency globals to v17.6.0 (#51859)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-04 17:56:08 +00:00
renovate[bot] 1312cdceda Update dependency eslint to v10.3.0 (#51858)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-04 17:55:23 +00:00
renovate[bot] 7dddcc0feb Update dependency marked to v18.0.3 (#51855)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-04 17:33:32 +02:00
Paul Bottein 95edd6c2c2 20260429.2 (#51856) 2026-05-04 17:05:24 +02:00
Paul Bottein dd65173c5a Bumped version to 20260429.2 2026-05-04 17:04:06 +02:00
Paul Bottein cf26753f7d Remove daily and hourly forecast card features (#51854) 2026-05-04 17:03:54 +02:00
Paul Bottein d6ab8ffb16 Resolve service name and icon for shortcut card and badge (#51850) 2026-05-04 17:03:53 +02:00
Wendelin 2dc4b16eac Fix automation row target width (#51848) 2026-05-04 17:03:52 +02:00
Paul Bottein 1eba765bc2 Group areas floor vacuum clean (#51847) 2026-05-04 17:03:51 +02:00
Wendelin 398479ddd7 Use ha-switch in ha-automation-picker (#51846)
use ha-switch in ha-automation-picker
2026-05-04 17:03:50 +02:00
Paul Bottein c4fd7bb3e1 Fix entity toggle switch size (#51845) 2026-05-04 17:03:49 +02:00
Isaac (Kwangjin Ko) 4cfc67a95e ha-humidifier-state: fix incorrect translation key for 'Currently' (#51843) 2026-05-04 17:03:48 +02:00
Brooke Hatton e38d1964ca Remove battery chargers from maintenance dashboard (#51835) 2026-05-04 17:03:47 +02:00
Paul Bottein ec8b5c77bd Add min touch size for control switch (#51826) 2026-05-04 17:03:46 +02:00
Simon Lamon 425f2775e2 Missing toggle in switch group (#51825)
Missing toggle
2026-05-04 17:03:45 +02:00
Brooke Hatton 3a3d8191a3 Adjust Copy for maintenance summary card and include unavailable device count (#51815)
* Adjust Copy For summary card

* Further tweak copy and include unavailable devices
2026-05-04 17:03:44 +02:00
Aidan Timson 04fca68549 Add gap between hui editors and previews on mobile (#51811) 2026-05-04 17:03:43 +02:00
Paul Bottein 38a18e327c Remove daily and hourly forecast card features (#51854) 2026-05-04 14:23:57 +00:00
Paul Bottein a288ad4ab6 Resolve service name and icon for shortcut card and badge (#51850) 2026-05-04 14:21:42 +02:00
Paul Bottein 89a85d6f04 Group areas floor vacuum clean (#51847) 2026-05-04 13:23:06 +02:00
Wendelin 6f1d644676 Fix automation row target width (#51848) 2026-05-04 12:51:08 +02:00
Isaac (Kwangjin Ko) 3edf8beb5a ha-humidifier-state: fix incorrect translation key for 'Currently' (#51843) 2026-05-04 10:49:51 +00:00
Aidan TimsonandPetar Petrov 7b95baf36b Update actions devtool layout (#51786)
Co-authored-by: Petar Petrov <[email protected]>
2026-05-04 11:45:07 +02:00
Wendelin b9c9008135 Use ha-switch in ha-automation-picker (#51846)
use ha-switch in ha-automation-picker
2026-05-04 09:33:29 +00:00
Paul Bottein a8fb2e251e Fix entity toggle switch size (#51845) 2026-05-04 09:23:29 +00:00
Paul Bottein 5c93e7adbc Add min touch size for control switch (#51826) 2026-05-04 11:17:08 +02:00
renovate[bot] 4745cb4103 Update dependency @babel/preset-env to v7.29.3 (#51841)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-04 07:03:01 +02:00
renovate[bot] 0a27727b9f Update dependency jsdom to v29.1.1 (#51838)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-03 13:45:58 +03:00
ildar170975andPetar Petrov 2644706d5a Dev tools -> Template: make a "description" collapsible (#51777)
* make a "description" expandable

* add "about" label for devtools->templates

* Update src/translations/en.json

Co-authored-by: Petar Petrov <[email protected]>

* expandedWillChange -> expandedChanged

* Add type annotation to _expandedChanged method

* Add import for HASSDomEvent type

* prettier

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-05-03 08:01:43 +03:00
Simon Lamon dd25b448cf Missing toggle in switch group (#51825)
Missing toggle
2026-05-03 07:49:41 +03:00
renovate[bot] 884c110bcc Update dependency @formatjs/intl-durationformat to v0.10.7 (#51834)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-03 07:47:42 +03:00
Brooke Hatton c61ed9c56a Remove battery chargers from maintenance dashboard (#51835) 2026-05-02 20:10:34 -04:00
renovate[bot] b454a45ca3 Update formatjs monorepo (#51831)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-02 19:15:47 +02:00
renovate[bot] 3bc404bc01 Update dependency @html-eslint/eslint-plugin to v0.60.0 (#51832)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-02 19:15:24 +02:00
renovate[bot] f22fc0b68a Update dependency @rspack/core to v2.0.1 (#51827)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-01 17:26:18 +02:00
ildar170975 c78cfb4012 Picture card: fix default tap_action (#51819)
* fix default tap_action

* fix default tap_action

* Update hui-picture-card.ts

* use hasAnyAction
2026-05-01 09:50:17 +02:00
ildar170975 09e993ffd6 Helpers, Automations, Scenes & Scripts data tables: add a search by a label (#51794)
* allow to search by a label

* allow to search by a label

* allow to search by a label

* allow to search by a label
2026-05-01 09:44:59 +02:00
Aidan Timson f8f175426d Improve spacing on assist devtools (#51805) 2026-05-01 09:23:05 +02:00
renovate[bot] 89e3687f22 Update dependency typescript-eslint to v8.59.1 (#51818)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-01 09:36:39 +03:00
ildar170975 18a20576a9 hui-picture-header-footer: use hasAnyAction (#51821)
use hasAnyAction
2026-05-01 09:35:45 +03:00
ildar170975 8ee41e5d9b ha-chart-base: fix vertical misalignment in legend (#51816)
vert alignment of value
2026-05-01 09:35:00 +03:00
Brooke Hatton cac31ac55a Adjust Copy for maintenance summary card and include unavailable device count (#51815)
* Adjust Copy For summary card

* Further tweak copy and include unavailable devices
2026-04-30 16:47:09 -04:00
Paul Bottein 3046f3e47d 20260429.1 (#51817) 2026-04-30 20:33:33 +02:00
Paul Bottein 35601a0900 Bumped version to 20260429.1 2026-04-30 20:32:28 +02:00
WendelinandCopilot e7016c15af Fix ha-select undefined value (#51800)
Fix ha-select undefined

Co-authored-by: Copilot <[email protected]>
2026-04-30 20:32:08 +02:00
Wendelin 624521e30b Hide tooltip on mobile clients in ha-sidebar component (#51799) 2026-04-30 20:32:08 +02:00
Bram Kragten 4876bfa639 Add tooltips for Jinja editors (#51792)
* Add descriptions to Jinja2 tags, filters, expressions, tests and variables

All standard Jinja2 tags, filters, and expression completions now carry
info and detail strings so the autocomplete info popover shows meaningful
documentation when users browse them — not just HA-specific functions.

* Add keyboard shortcut tip to the template developer tool

A ha-tip below the editor card now shows users that Ctrl+Space triggers
autocomplete, Ctrl+F opens the search panel, and F11 toggles fullscreen,
making the editor's built-in features more discoverable.

* Add hover tooltips for Jinja2 functions, filters and expressions

Hovering over a function, filter, tag, test, or variable name inside a
Jinja2 template shows a tooltip with its signature and description.
Non-tag completions also get a help-circle icon linking to the
corresponding Home Assistant template-functions documentation page.

The tooltip is rendered as a custom Lit element (ha-code-editor-jinja-hover)
that takes the Completion object and an optional docUrl as properties.

The tooltip source (haJinjaHoverSource) is wired into ha-code-editor
via CodeMirror's hoverTooltip extension. The documentationUrl() helper
is used so the link points to the correct subdomain (www / rc / next)
based on the running HA version.

* Add hover tooltips for Jinja2 hover + arg value tooltips for entity/device/area

Wire haJinjaHoverSource into ha-code-editor via CodeMirror hoverTooltip.
Two types of hover are now shown in jinja2/yaml mode:

- Hovering a function/filter/tag/expression name shows its signature,
  description, and a doc-link icon (non-tags only).
- Hovering a string-literal argument of a known HA Jinja function (e.g.
  states(), device_name(), area_entities()) shows the friendly name,
  current state, device, and area for entity_id arguments; the device
  name and area for device_id arguments; and the area name for area_id
  arguments. The same applies to states["entity_id"] subscripts.

The arg-value tooltip reuses CompletionItem / ha-code-editor-completion-items
(the same component used for autocomplete info popovers) via a new
ha-code-editor-jinja-arg-hover element. HA registry data is passed from
ha-code-editor via a HassArgHoverContext interface to keep jinja_ha_completions.ts
free of HomeAssistant type imports.

* only add tip for autocomplete

* review
2026-04-30 20:32:07 +02:00
AlCalzoneandPetar Petrov 5dea0764b2 Expose Z-Wave exclusion instructions when removing device (#51788)
* Expose Z-Wave exclusion instructions when removing device

* text tweaks

* Apply suggestion from @MindFreeze

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

* bring back comment

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-04-30 20:32:05 +02:00
Matthias de BaatandPetar Petrov 8f002f2783 Promote backup encryption key and reorganize backup page (#51806)
* Promote backup encryption key and reorganize backup page

* Polish

* More polish

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-04-30 14:29:16 +00:00
Aidan Timson df754fcd0d Add gap between hui editors and previews on mobile (#51811) 2026-04-30 15:00:03 +03:00
Aidan Timson bc4437b3b5 Ally: Add aria labels to ha-icon-button and hui-root (#51784)
* Ally: Add aria labels to ha-icon-button and hui-root

* use aria-hidden

* Add hidden content for label to satisfy ally review

* Make fix in button instead (probably should update upstream)

* Aria label (pending wa update)
2026-04-30 09:20:56 +00:00
WendelinandCopilot c99b43dcf3 Use input button slots for a11y (#51801)
Co-authored-by: Copilot <[email protected]>
2026-04-30 09:12:23 +00:00
Bram Kragten 8945b917b3 Add tooltips for Jinja editors (#51792)
* Add descriptions to Jinja2 tags, filters, expressions, tests and variables

All standard Jinja2 tags, filters, and expression completions now carry
info and detail strings so the autocomplete info popover shows meaningful
documentation when users browse them — not just HA-specific functions.

* Add keyboard shortcut tip to the template developer tool

A ha-tip below the editor card now shows users that Ctrl+Space triggers
autocomplete, Ctrl+F opens the search panel, and F11 toggles fullscreen,
making the editor's built-in features more discoverable.

* Add hover tooltips for Jinja2 functions, filters and expressions

Hovering over a function, filter, tag, test, or variable name inside a
Jinja2 template shows a tooltip with its signature and description.
Non-tag completions also get a help-circle icon linking to the
corresponding Home Assistant template-functions documentation page.

The tooltip is rendered as a custom Lit element (ha-code-editor-jinja-hover)
that takes the Completion object and an optional docUrl as properties.

The tooltip source (haJinjaHoverSource) is wired into ha-code-editor
via CodeMirror's hoverTooltip extension. The documentationUrl() helper
is used so the link points to the correct subdomain (www / rc / next)
based on the running HA version.

* Add hover tooltips for Jinja2 hover + arg value tooltips for entity/device/area

Wire haJinjaHoverSource into ha-code-editor via CodeMirror hoverTooltip.
Two types of hover are now shown in jinja2/yaml mode:

- Hovering a function/filter/tag/expression name shows its signature,
  description, and a doc-link icon (non-tags only).
- Hovering a string-literal argument of a known HA Jinja function (e.g.
  states(), device_name(), area_entities()) shows the friendly name,
  current state, device, and area for entity_id arguments; the device
  name and area for device_id arguments; and the area name for area_id
  arguments. The same applies to states["entity_id"] subscripts.

The arg-value tooltip reuses CompletionItem / ha-code-editor-completion-items
(the same component used for autocomplete info popovers) via a new
ha-code-editor-jinja-arg-hover element. HA registry data is passed from
ha-code-editor via a HassArgHoverContext interface to keep jinja_ha_completions.ts
free of HomeAssistant type imports.

* only add tip for autocomplete

* review
2026-04-30 12:07:50 +03:00
Bram Kragten 4d75ea5198 Add inline YAML linting to the yaml code editor (#51791) 2026-04-30 08:42:12 +00:00
WendelinandCopilot ba3a63f856 Fix ha-select undefined value (#51800)
Fix ha-select undefined

Co-authored-by: Copilot <[email protected]>
2026-04-30 10:25:26 +03:00
renovate[bot] fd25d38be6 Update dependency jsdom to v29.1.0 (#51798)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-30 10:18:18 +03:00
Wendelin ac22374a00 Hide tooltip on mobile clients in ha-sidebar component (#51799) 2026-04-30 10:17:44 +03:00
AlCalzoneandPetar Petrov de529cc26b Expose Z-Wave exclusion instructions when removing device (#51788)
* Expose Z-Wave exclusion instructions when removing device

* text tweaks

* Apply suggestion from @MindFreeze

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

* bring back comment

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-04-30 06:06:21 +00:00
Aidan Timson 126db3e8df Refactor events devtools tab layout and events output card (#51789)
* Only show events output when there are any, types and margin

* Refactor to use pagination

* Fix

* Simplify, remove pinning and auto-follow, stay on event 1 and allow the user to move around manually

* Show info why only 30 events are keps

* Increase bufffer limit to 100, add explainer and tip when rolls over

* Update disclaimer

* Use buffer position and total instead of event id + total in counter

* Use fixed height and constrain editor

* Cleanup

* Cleanup

* Fix narrow layouts
2026-04-30 08:42:30 +03:00
Matthias de Baat ed6fd59968 Move preview device analytics button to card (#51787)
* Move preview device analytics button to card

* Add icon back
2026-04-29 17:36:06 +02:00
Paul Bottein 121ed7ac1f 20260429.0 (#51790) 2026-04-29 16:47:32 +02:00
Paul Bottein 962e941ec9 Merge branch 'master' into dev
# Conflicts:
#	build-scripts/gulp/download-translations.js
#	pyproject.toml
#	src/components/chart/ha-network-graph.ts
#	src/components/date-picker/date-range-picker.ts
#	src/components/date-picker/styles.ts
#	src/components/entity/ha-entity-name-picker.ts
#	src/components/ha-gauge.ts
#	src/components/ha-selector/ha-selector-numeric-threshold.ts
#	src/components/ha-toast.ts
#	src/components/input/ha-input.ts
#	src/data/icons.ts
#	src/dialogs/make-dialog-manager.ts
#	src/panels/config/automation/action/ha-automation-action-row.ts
#	src/panels/config/automation/add-automation-element-dialog.ts
#	src/panels/config/automation/condition/ha-automation-condition-row.ts
#	src/panels/config/automation/condition/types/ha-automation-condition-platform.ts
#	src/panels/config/automation/target/ha-automation-row-targets.ts
#	src/panels/config/automation/trigger/ha-automation-trigger-row.ts
#	src/panels/config/automation/trigger/types/ha-automation-trigger-platform.ts
#	src/panels/config/developer-tools/action/developer-tools-action.ts
#	src/panels/config/devices/ha-config-device-page.ts
#	src/panels/config/entities/entity-registry-settings-editor.ts
#	src/panels/config/ha-panel-config.ts
#	src/panels/config/integrations/integration-panels/zha/zha-device-card.ts
#	src/panels/lovelace/card-features/hui-trend-graph-card-feature.ts
#	src/panels/lovelace/cards/hui-gauge-card.ts
#	src/panels/lovelace/cards/hui-history-graph-card.ts
#	src/panels/lovelace/cards/hui-map-card.ts
#	src/panels/lovelace/sections/hui-section.ts
#	src/panels/lovelace/views/hui-view-footer.ts
#	src/state/quick-bar-mixin.ts
#	yarn.lock
2026-04-29 16:30:58 +02:00
Paul Bottein 31495b2de9 Bumped version to 20260429.0 2026-04-29 16:17:10 +02:00
f71dcaeac1 Add automation behavior selector (#30322)
* Add automation behavior selector

* Use mode option instead

* update design

* remove label

* Update src/translations/en.json

Co-authored-by: Norbert Rittel <[email protected]>

* Update src/translations/en.json

Co-authored-by: Norbert Rittel <[email protected]>

---------

Co-authored-by: Wendelin <[email protected]>
Co-authored-by: Wendelin <[email protected]>
Co-authored-by: Norbert Rittel <[email protected]>
2026-04-29 16:12:17 +02:00
WendelinandCopilot 26b1bfbe20 Automations: Flatten triggers/conditions list in pickers (#51785)
* Flat add trigger condition collections

* fix list order

Co-authored-by: Copilot <[email protected]>

---------

Co-authored-by: Copilot <[email protected]>
2026-04-29 16:11:42 +02:00
Tom Carpenter c6026507a5 Fix errors loading the demo site (#51695) 2026-04-29 12:04:51 +01:00
Bram KragtenandPaul Bottein 53b5b43c33 Remove domain prefix from actions (#51278)
* Remove domain prefix from actions

* Only do it for entity domains

---------

Co-authored-by: Paul Bottein <[email protected]>
2026-04-29 10:44:20 +00:00
Marcin BauerandClaude Sonnet 4.6 cb31afa432 config-flow: rename "Device created" heading to "Name and assign" (#51782)
The old heading "Device created" was a past-tense status message that didn't
communicate what the user needs to do next. The dialog contains a name field
and an area picker, so "Name and assign" better reflects the user's actual
task at this step.

Co-authored-by: Claude Sonnet 4.6 (1M context) <[email protected]>
2026-04-29 13:39:26 +03:00
Wendelin d5deff34ea Redesign automation row indicators (#51737)
add new triggered, test and ran chips
2026-04-29 12:04:27 +02:00
Marcin BauerandClaude Sonnet 4.6 1aed9f8b1f Add Ctrl/Cmd+Click legend solo shortcut to shortcuts dialog (#51781)
Co-authored-by: Claude Sonnet 4.6 (1M context) <[email protected]>
2026-04-29 08:17:09 +00:00
Petar PetrovandWendelin 34ec052568 Open more-info from energy devices detail graph legend (#51778)
Co-authored-by: Wendelin <[email protected]>
2026-04-29 07:16:01 +00:00
Petar Petrov 65f11ebc3f Fix duplicate ha-panel-custom on first mount (#51779) 2026-04-29 08:52:25 +02:00
36cadeef40 hui-gauge-card: fix displayed value & unit (#51751)
* Create compute_entity_unit_display.ts

* use computeEntityUnitDisplay()

* fix displayed value & unit

* use value AND valueText

* Update src/common/entity/compute_entity_unit_display.ts

Co-authored-by: Simon Lamon <[email protected]>

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Simon Lamon <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-04-29 06:16:14 +00:00
Bram Kragten 1ed1b7bfda Check for unknown value every render if value is unknown (#51760)
* Check for unknown value every render if value is unknown

* fix race in pickers that add items from the picker

* fix: use value imports for LitElement, html, nothing from lit
2026-04-29 08:55:03 +03:00
ildar170975 e7d9b5348e Dev tools -> Template: align buttons (#51775)
* align buttons

* prettier
2026-04-29 08:53:22 +03:00
Simone ChemelliandCopilot fa2c0278cb Add UPTIME sensor device class (#51716)
Co-authored-by: Copilot <[email protected]>
2026-04-29 07:20:40 +02:00
WendelinandCopilot fdd0636d9a Media player more info add controls tooltips (#51765)
Add tooltips to media player controls for improved accessibility

Co-authored-by: Copilot <[email protected]>
2026-04-29 07:20:02 +02:00
karwosts 39d1173a98 Copy new automation trace picker for scripts (#51776)
* Copy new automation trace picker for scripts

* Use shared component
2026-04-29 07:17:48 +02:00
Bram Kragten 907687c16d Don't just check system domains, for usage, but any domain (#51746) 2026-04-28 21:51:10 +02:00
Joep MeindertsmaandPetar Petrov 3e17779550 feat: Split legend interaction (click vs label) with hover effects (#28517)
* feat: Split legend interaction (click vs label) with icons and hover effects

* Address review feedback on chart legend split

- Rename `externalHiddenState` to `clickLabelForMoreInfo` and the event
  `chart-legend-click` to `legend-label-click` (the `chart-` prefix is
  reserved for echarts-proxy events).
- Use proper translation keys
  `ui.components.history_charts.{toggle_visibility,show_more_info}`
  instead of `ui.common.*` which don't exist.
- Drop the redundant tooltip on the label when it would duplicate the
  icon's "Toggle visibility" tooltip.
- Resolve the legend dataset id back to a real `entity_id` before
  opening more-info: strip known climate-attribute suffixes for history
  charts (`-current_temperature`, `-target_temperature*`, `-heating`/
  `-cooling`/`-drying`/`-fan`), and skip `isExternalStatistic` ids for
  statistics charts. Only fire `hass-more-info` if `hass.states[id]`
  resolves.

* Address followup review feedback on chart legend

- Restore stat-type suffix stripping in statistics chart. When the chart
  has a single entity, ha-chart-base falls back to raw series ids
  (`${statistic_id}-${type}`) for the legend, so clicking
  "sensor.foo (max)" otherwise tries to open `sensor.foo-max`.
- Cover humidifier multi-attribute datasets in the entity-id resolver
  alongside climate / water_heater (`-current_humidity`,
  `-target_humidity`, `-humidifying`, `-on`; `-drying` is already
  contributed by CLIMATE_MODE_CONFIGS). Rename the constant to
  ENTITY_DATASET_SUFFIXES to reflect the broader scope.
- Convert the two legend click targets to `<button type="button">` so
  Tab navigation, Enter/Space activation, and screen-reader semantics
  work. Add `aria-pressed` to the visibility toggle and a
  `:focus-visible` outline. Read the dataset id from `data-id` instead
  of `parentElement.id` so the handlers don't depend on DOM nesting.
- Scope the label hover underline to `.label-clickable` so charts that
  don't opt into more-info (network, sankey, sunburst, energy) keep the
  legacy non-underlined toggle behavior. Render the "Show more info"
  tooltip only when the click will actually fire.
- Drop the redundant physical `margin-right: 0` on the legend toggle;
  `margin-inline-end: 0` alone preserves the click-area extension on
  the start side in RTL.

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-04-28 21:41:42 +02:00
Paul Bottein c91802d552 Use full width name field for heading badge editor (#51769) 2026-04-28 21:37:02 +02:00
renovate[bot] 40f3d68f8b Update dependency @rspack/dev-server to v2.0.1 (#51764)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-28 21:30:29 +02:00
Paul Bottein 3aa2352f03 Reorder built-in summaries and custom shortcuts in one list (#51763)
* Reorder built-in summaries and custom shortcuts in one list

* Use summary term
2026-04-28 21:29:10 +02:00
puddly cc98634fad Add recommended ports to serial selector (#51773)
* Allow ha-form to forward context to selectors

* Categorize ports into recommended/not recommended

* Utilize the interface description

* Ignore copy/pasted product -> interface description
2026-04-28 14:46:28 -04:00
ildar170975 d61829e4d4 Dev tools -> Templates: add ha-scrollbar to render-pane (#51770) 2026-04-28 15:39:29 +00:00
WendelinandCopilot 95ce9cb8c1 Add input number unit picker (#51768)
Add unit of measurement options and integrate selector in input number form

Co-authored-by: Copilot <[email protected]>
2026-04-28 17:25:32 +02:00
Paul Bottein 846a20dd13 Revert global change from tooltip PR (#51766) 2026-04-28 17:06:54 +02:00
Aidan Timson 36031c7365 Fix capitalisation of integration on system log detail (#51762) 2026-04-28 13:27:18 +02:00
Paulus Schoutsen f99d95232a Show all the power buttons when media player is in assumed state (#51740) 2026-04-28 11:26:06 +02:00
Petar Petrov 5b4c08ad04 Add color and current temperature options to forecast features (#51761) 2026-04-28 11:20:31 +02:00
Petar Petrov b0b2d84287 Add precipitation visualization to forecast tile features (#51733) 2026-04-28 08:28:15 +01:00
WendelinandCopilot 0a43c29fea Simplify and fix target entity count (#51739)
* Simplify and fix target entity count

* Review

Co-authored-by: Copilot <[email protected]>

---------

Co-authored-by: Copilot <[email protected]>
2026-04-28 06:31:36 +00:00
61a8df1fa9 Modified the chart legend for climate temperature data sets (#51719)
* Modified the chart legend for climate temperature data sets to display the temperature value, not the overall entity state (previously hvac_mode).

* Use the helper computeAttributeValueDisplay in src/common/entity/compute_attribute_display.ts to format the temperature attribute values.

Co-authored-by: Copilot <[email protected]>

* Update src/components/chart/state-history-chart-line.ts

---------

Co-authored-by: Copilot <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-04-28 06:29:45 +00:00
mwolter805 ba3b335f47 Fix ha-panel-custom not restoring after suspendWhenHidden disconnect (#51727)
* fix: rebuild ha-panel-custom on reconnect after suspendWhenHidden

Why:
HA's PartialPanelResolver._onHidden() starts a 5-minute timer when a tab
is backgrounded. When it fires, non-iframe / non-app custom panels
(component_name="custom" without embed_iframe) are removed from the DOM,
which triggers ha-panel-custom.disconnectedCallback() -> _cleanupPanel().
That nulls _setProperties and destroys the child custom-panel element.

When the user returns, _onVisible() re-appends the same <ha-panel-custom>
element. ReactiveElement's base connectedCallback schedules an update,
but update() only calls _createPanel(this.panel) when
changedProps.has("panel") && !deepEqual(oldPanel, this.panel) -- the
panel reference hasn't changed, so nothing happens. _setProperties is
also undefined, so the property-forwarding branch exits early too.
Result: <ha-panel-custom> is present in the DOM but empty -- the user
sees a blank panel until they hard-reload.

Add a connectedCallback() override that rebuilds when the element was
previously cleaned up. Three guards keep it scoped to the recovery path:
  - !this._setProperties: sentinel for "_cleanupPanel ran".
    _setProperties is set inside _createPanel's success paths and only
    nulled in _cleanupPanel.
  - !this.hasChildNodes(): defends against the async window inside
    loadCustomPanel(config).then(...) for non-iframe panels, where a
    rapid detach->attach cycle could otherwise call _createPanel twice
    and append duplicate elements.
  - this.panel: skips first-mount, when the router hasn't assigned a
    panel yet. The existing update() path handles initial _createPanel
    via the changedProps.has("panel") branch.

Mirrors the existing disconnectedCallback override for symmetry.
10 lines + comment, no other file changes.

Affects every non-iframe sidebar custom panel in the HACS ecosystem
(Alarmo, Browser Mod, Homematic(IP) Local, MeshCore, others -- ~60k
combined HA-analytics installs). Reopens dormant home-assistant/frontend
issue #14510 (filed 2022-12-02, stale-bot closed without a fix).

Tests:
- yarn build succeeds locally; the affected chunk is captured for the
  pre-PR local-test on a real HA host.
- Manual repro on user's HA host (10.10.21.221) with the MeshCore
  custom panel: baseline (no patch) reproduces the blank-panel symptom
  after a 6-minute backgrounded tab. Patched chunk: panel rebuilds
  within ~2 seconds of returning. Exemption paths (iframe panel, app
  panel, custom panel with embed_iframe=true) verified to remain
  unaffected. Original chunk restored after testing.
- yarn lint and yarn test pass before PR submission (run before
  Phase 9).

* chore: trigger CLA recheck after author-email link
2026-04-28 08:34:00 +03:00
Wendelin 5449f31162 Fix target picker secondary entities support (#51729)
Add support for secondary entity filtering in target picker
2026-04-28 08:25:41 +03:00
Aidan TimsonandCopilot 1a992aa5f7 Change media browser player to generic picker component (#51734)
* Change media browser player to generic picker component

* Add disabled item support

* Use disabled items

* Sort as original

* Fix divider styling

* Cleanup

Co-authored-by: Copilot <[email protected]>

* Remove memo

Co-authored-by: Copilot <[email protected]>

* Typing

Co-authored-by: Copilot <[email protected]>

* Dont allow disabled items

---------

Co-authored-by: Copilot <[email protected]>
2026-04-28 08:24:29 +03:00
ildar170975 6303affe17 Dialogs: call "enlarge" on a wider area (#51750)
* increase an active "enlarge" area

Added a class to make the title span enlargeable.

* increase an active "enlarge" area

* increase an active "enlarge" area
2026-04-28 08:18:30 +03:00
karwosts fc0ac85223 More detailed trace selector via generic-picker (#51752) 2026-04-28 08:14:32 +03:00
dependabot[bot] 2efc1a658f Bump brace-expansion from 1.1.12 to 1.1.14 (#51753)
Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.12 to 1.1.14.
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.14)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 1.1.14
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-28 08:13:32 +03:00
renovate[bot] 371642ef3f Update formatjs monorepo (#51747)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-28 06:54:17 +02:00
Wendelin aff9ec4345 Improve debug callWs logs (#51741) 2026-04-27 17:36:58 +02:00
Paul Bottein 80e37e7136 Use current entity in state card conditions (#51708) 2026-04-27 14:59:05 +01:00
Yosi Levy 54a234debd Toast location RTL fix (#51735) 2026-04-27 14:04:33 +01:00
Wendelin eeb0fb3e4d Automation editor: Fix no target set in some actions (#51642)
Refactor target extraction in HaAutomationActionRow for improved legacy support
2026-04-27 14:45:34 +03:00
d5dc40fa1f Add entity context to media browser player picker (#51732)
* Add entity context to media browser player picker

Show area and device as a secondary line in both the active player pill
and the player picker dropdown, so users can identify speakers when
multiple players share similar names.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Update src/panels/media-browser/ha-bar-media-player.ts

Co-authored-by: Paul Bottein <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
Co-authored-by: Paul Bottein <[email protected]>
2026-04-27 10:32:39 +00:00
Paul Bottein df12232e93 Add attribute support for numeric state and state (#51706) 2026-04-27 10:11:25 +01:00
Wendelin 1a2e63a5ba Add floor/area: Replace popover with dropdown (#51730) 2026-04-27 08:43:05 +01:00
karwosts 581ba23f4e Stabilize more-info group rendering (#51725) 2026-04-27 08:20:23 +03:00
renovate[bot] 5dda82a8ac Update dependency terser-webpack-plugin to v5.5.0 (#51728)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-27 05:53:31 +02:00
Petar Petrov 5a296fadec Minimize Sankey flow crossings with barycenter sort (#51682)
* Minimize Sankey flow crossings with barycenter sort

* Cache section id-index maps across barycenter sweeps

* Thread graph edges through to sortNodesInSections
2026-04-26 21:42:26 +02:00
dependabot[bot] 5dc99a3dbd Bump actions/setup-node from 6.3.0 to 6.4.0 (#51722)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6.3.0 to 6.4.0.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/53b83947a5a98c8d113130e565377fae1a50d02f...48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: 6.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-26 13:53:02 +02:00
dependabot[bot] 2f36c64a21 Bump github/codeql-action from 4.35.1 to 4.35.2 (#51721)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.35.1 to 4.35.2.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/c10b8064de6f491fea524254123dbe5e09572f13...95e58e9a2cdfd71adc6e0353d5c52f41a045d225)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.35.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-26 13:52:59 +02:00
dependabot[bot] 59cfc82e7a Bump actions/cache from 5.0.4 to 5.0.5 (#51720)
Bumps [actions/cache](https://github.com/actions/cache) from 5.0.4 to 5.0.5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/668228422ae6a00e4ad889ee87cd7109ec5666a7...27d5ce7f107fe9357f9df03efb73ab90386fccae)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 5.0.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-26 13:52:56 +02:00
Paul Bottein edc36b28a6 Refactor home panel editor (#51701) 2026-04-25 15:48:12 +02:00
Logan RosenandCopilot 7b58162f81 Drop eslint-config-airbnb-base and cherry-pick rules (#51627)
Remove the unmaintained eslint-config-airbnb-base dependency (last
updated Nov 2021, no flat config support) along with its FlatCompat
shim infrastructure.

Replace with js.configs.recommended as the base config and explicitly
cherry-pick ~40 high-value safety and style rules from airbnb-base
that aren't already covered by other configs.

Remove 27 rule disables that only existed to suppress airbnb opinions,
and 5 dead TypeScript rule disables for rules no longer in the config.

Fix 4 real bugs caught by the newly added no-constant-binary-expression
rule where template literals were always truthy, making fallback values
unreachable.

Co-authored-by: Copilot <[email protected]>
2026-04-25 14:16:53 +03:00
dependabot[bot]andSimon Lamon 9e9f247c79 Bump vite from 8.0.2 to 8.0.9 (#51707)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Simon Lamon <[email protected]>
2026-04-24 21:16:28 +02:00
Bram Kragten b95fce5f24 Bumped version to 20260325.8 2026-04-24 17:26:41 +02:00
karwosts f6abbe80a2 Remove spurious map in original-states view (#51696) 2026-04-24 17:24:44 +02:00
Wendelin 71301ef5be Remove allow-mode-change in quick search (#51634)
Remove allow-mode-change attribute from ha-adaptive-dialog in QuickBar component
2026-04-24 17:24:43 +02:00
ildar170975 4af618ac6f Gauge card: fix a height in Horizontal stack (#51626)
remove styles for ":host"
2026-04-24 17:24:42 +02:00
Simon Lamon 5a21ef67cd Adjust gauge again (#51613) 2026-04-24 17:24:41 +02:00
karwosts 251b9a1b94 Fix gauge missing label on load (#51584) 2026-04-24 17:24:40 +02:00
karwosts cadaa47bf0 Fix gauge segmentLabels, cleanup sorting (#51583) 2026-04-24 17:24:39 +02:00
Jan Čermák 7ec864dc6d Fix rendering of select with multiple options in SupervisorAppConfig (#51585)
If the app config contains a schema field like this one:

```
privileges:
  - "list(ALTER|CREATE|...|UPDATE)?"
```

it was rendered incorrectly as a drop-down where only one item can be
selected - but this is wrong because of the preceding `-` denoting it
should be a list containing the listed values. Supervisor translated
this to an entry of type `select` with `multiple: true`. The `multiple`
flag wasn't passed along, with the flag set the field renders as
expected.

Fixes #51533
2026-04-24 17:08:12 +02:00
Wendelin 680ceb73e9 ha-select allow number values (#51564) 2026-04-24 17:08:11 +02:00
Wendelin ab31771055 Improve view footer card visibility handling (#51549) 2026-04-24 17:08:10 +02:00
Wendelin 07b9a6e287 Hide footer if card is not visible (#51544)
* Fix footer visibility logic in render method

* use card-visibility-changed
2026-04-24 17:08:09 +02:00
Wendelin be2c90cd1c Fix register admin quick search shortcuts (#51540) 2026-04-24 17:08:08 +02:00
Raphael HehlandPetar Petrov 2af4ff7c8f Fix history/sensor cards stuck loading after backend restart (#51531)
* Fix history/sensor cards stuck loading after backend restart

- Add { resubscribe: false } to history subscriptions to prevent
  corrupt HistoryStream state on auto-resubscription
- Add connection-status handlers to re-subscribe on reconnect
- Add sentinel pattern to prevent re-entrant async subscriptions
- Add shouldUpdate/updated retry when components become available
- Clear sensor device classes cache on WS error
- Clear _error on reconnect so cards can retry
- Add .catch() on unsubscribe to handle dead subscriptions

* Fix type annotation for callWS in getSensorNumericDeviceClasses

* Address review: type connection-status handlers, add reconnect to history panel

- Use HASSDomEvent<ConnectionStatus> instead of (ev as CustomEvent).detail
  for proper type safety on all connection-status handlers
- Add connection-status handler to ha-panel-history so it re-subscribes
  after backend restart (addresses concern about resubscribe: false)

* Address review: sentinel pattern, reconnect handling, stale data reset

- Add sentinel pattern to ha-more-info-history, ha-panel-history,
  hui-history-graph-card to prevent re-entrant subscription races
- Refactor hui-trend-graph-card-feature from SubscribeMixin to manual
  subscription management with connection-status reconnect support
- Reset stale history/statistics data on reconnect in
  hui-history-graph-card and hui-map-card before re-subscribing
- Wrap fetchStatistics and getSensorNumericDeviceClasses calls in
  ha-panel-history with try/catch to handle errors gracefully
- Chain .catch directly on subscribeHistoryStatesTimeWindow in
  hui-trend-graph-card-feature to avoid detached-promise race condition

* Centralize history stream reconnect handling in data layer

Move the reconnect logic from every consumer into `subscribeHistoryStream`
in data/history.ts. The helper listens to the connection's `ready` event
itself, and on reconnect creates a fresh `HistoryStream` and rebuilds
params (so `start_time` for the time-window variant is re-anchored to
"now"). `resubscribe: false` stays as an internal implementation detail.

Removes the duplicated `_handleConnectionStatus` boilerplate and
`connection-status` window listeners from all six history consumers.

* Render subscription errors and make _error reactive

`_error` was declared as a plain string field in hui-graph-header-footer
and ha-more-info-history (non-reactive) and typed as Error/string while
being assigned the WS error object. hui-trend-graph-card-feature had it
reactive but never rendered it.

Align all three with the hui-history-graph-card pattern: reactive
`{ code, message }` and a user-visible error branch in render(). Without
this, a failed subscription would leave the component stuck on a spinner
forever.

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-04-24 17:08:07 +02:00
8139b60248 Add radio_frequency domain entity platform (#51693)
Co-authored-by: balloob <[email protected]>
Co-authored-by: Claude <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-04-24 15:34:08 +01:00
Wendelin 386372ad00 Use control switch for entity toggle (#51654) 2026-04-24 16:12:33 +02:00
Petar PetrovandWendelin 9151b200a1 Add energy grid balance card (#51480)
Co-authored-by: Wendelin <[email protected]>
2026-04-24 14:04:15 +02:00
renovate[bot] f449c6c1c1 Update dependency @codemirror/search to v6.7.0 (#51704)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-24 14:47:13 +03:00
renovate[bot] d1eb3fd162 Update vitest monorepo to v4.1.5 (#51703)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-24 14:46:32 +03:00
pcan08andClaude Sonnet 4.6 71648078d8 Home dashboard: enable/disable entities suggestion (#51407)
* Allow showing/hiding welcome message on home overview

Add a toggle in the edit overview dialog to show or hide the
"Welcome, [user]" greeting header on the home overview page,
following the same pattern as the existing summary enable/disable.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Move welcome message toggle into its own section in home editor

The welcome message is a greeting header, not a summary card, so it
now lives in a separate "Greeting" section above the "Summaries" section.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* rename hidden_welcome_message to hide_welcome_message

* Use ha-form boolean selector for welcome message toggle

Replace manual label/ha-switch markup with ha-form using a boolean
selector for better accessibility and consistency with the rest of
the codebase.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Add helper text to welcome message toggle in home editor

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Remove greeting section header

* Allow enabling/disabling suggested entities on home overview

Add a toggle in the Overview edit dialog to show or hide the
usage-predicted entities that fill remaining slots alongside favorites.
When disabled, the usage prediction fetch is skipped entirely.
The favorites entities helper text is updated to no longer reference
suggestions, which now have their own dedicated toggle and description.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Use ha-input-helper-text for suggested entities description

Replace the raw <p class="section-description"> with ha-input-helper-text
for the suggested entities toggle description, using the proper HA
component for helper text styling instead of custom CSS.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Rename show_suggested_entities to hide_suggested_entities

Aligns with the hidden_summaries naming convention used elsewhere.
Logic is inverted accordingly: undefined means shown (default),
true means hidden.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Use ha-form boolean selector for suggested entities toggle

Replace the manual label+switch+helper-text with ha-form using a boolean
selector.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Refine suggested entities toggle label and callback signatures

Drop unused schema parameter from computeLabel/computeHelper callbacks
and shorten the label from "Show suggested entities" to "Suggested entities"
since the boolean checkbox already conveys the enabled/disabled intent.

* Group favorite entities picker and suggested toggle in expandable panel

Wrap ha-entities-picker and the suggested entities boolean in an outlined
ha-expansion-panel with a star-outline icon. Move the welcome message
toggle above the panel. Use "Favorite entities" as the panel header and
remove the redundant picker label.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Update entities description to use "include" instead of "show"

* Fix expansion panel content leaking when collapsed

Move inner padding from --expansion-panel-content-padding to a wrapper
div, matching the ha-form-expandable pattern, so no content is visible
when the panel is collapsed.

* Add spacing between alert and expansion panel in home editor dialog

* Move favorites description above picker, update helper text

- Add description paragraph above ha-entities-picker explaining the feature
- Update helper text to concise behavioral note: "Entities in your favorites always appear first."

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
2026-04-24 09:23:07 +02:00
Wendelin a1ac0a0941 Target picker respect primaryEntitiesOnly from selector (#51677) 2026-04-24 09:14:00 +02:00
Wendelin 625cadce26 Update webawesome to 3.3.1-ha.1 (#51697) 2026-04-24 09:09:42 +02:00
karwosts 407ea0d9a7 Remove spurious map in original-states view (#51696) 2026-04-24 07:15:39 +02:00
renovate[bot] 05bb7ef409 Update dependency typescript-eslint to v8.59.0 (#51694)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-23 18:24:13 +00:00
WendelinandTom Carpenter b1b64fa6f4 respect rtl in ha-control-slider (#51691)
* Control slider rtl

Co-authored-by: Tom Carpenter <[email protected]>
2026-04-23 18:15:09 +00:00
Petar Petrov bb4cf5ead7 Move Event received trigger to generic category in picker (#51675) 2026-04-23 14:51:40 +02:00
Petar Petrov 1466aff1ae Add daily forecast card feature (#51637)
* Add daily forecast card feature

* Address review feedback: validate forecast type, refresh on state change

* Use statesContext for current temp state

* Use internationalizationContext for localize

* Narrow support/resolve helpers to accept stateObj

* Use connection instead of hass for subscribeForecast

* Reduce opacity of current temp line

* Type states context consumer

* Use consumeEntityState decorator
2026-04-23 15:47:53 +03:00
Aidan TimsonandWendelin 867e8633f6 Adaptive popover, add to set date card feature (#51650)
Co-authored-by: Wendelin <[email protected]>
2026-04-23 12:33:23 +00:00
Petar Petrov 9d393f9fc5 Remove resources from hass object (#51676) 2026-04-23 14:32:35 +02:00
910276b860 Improve serial proxies look in serial port selector (#51673)
* Improve serial proxies look in serial port selector

* Use new format

* Custom renderer for value

* Update src/components/ha-selector/ha-selector-serial-port.ts

Co-authored-by: Copilot <[email protected]>

* format

---------

Co-authored-by: Petar Petrov <[email protected]>
Co-authored-by: Copilot <[email protected]>
2026-04-23 11:33:40 +00:00
Petar Petrovandrenovate[bot] d05cc25e66 Upgrade @rspack/core and @rspack/dev-server to v2 (#51674)
* Update dependency @rspack/dev-server to v2

* Upgrade @rspack/core to 2.0.0

Pairs with the @rspack/dev-server 2.0.0 bump in #51666 — dev-server v2
declares @rspack/core ^2.0.0-0 as a peer, so the two must move together.

Patches webpackbar to defend against non-string info in Rspack 2's
ProgressPlugin handler (otherwise `parseRequest` throws `split is not a
function` during compilation).

Verified locally: yarn lint:types, yarn test, yarn lint, script/build_frontend,
and all three rspack-dev-server-{demo,cast,gallery} tasks.

* Wrap webpackbar instead of patching it

Replace the yarn patch with a small SafeWebpackBar subclass that sanitizes
the progress `details` array before the upstream parseRequest sees it.
Keeps the fix local to the Rspack config where it belongs.

* Pass moduleIdentifier to webpackbar progress

Rspack 2's progress info is `{ builtModules, moduleIdentifier? }`.
moduleIdentifier is what v1 passed as a plain string, so extract it to
keep the "active module" line in the progress bar instead of blanking it.

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-23 13:16:14 +02:00
Petar Petrov f61b6f1163 Extract consumeStateObj / consumeEntityRegistryEntry decorators (#51652)
* Extract consumeStateObj / consumeEntityRegistryEntry decorators

* Address review: rename to consume-context-entry, tighten undefined check

* Rename entityId->entityIdPath, consumeStateObj->consumeEntityState, add consumeEntityStates
2026-04-22 17:49:34 +03:00
9893786682 Add activity log sidebar to security dashboard (#29901)
* Add activity log sidebar to security dashboard

Add a sidebar with a logbook card to the security domain dashboard,
filtered by security entities (cameras, locks, alarm panels, covers,
binary sensors) and person entities. The sidebar uses the sections view
sidebar layout with mobile tab support for switching between devices
and activity views on narrow screens.

https://claude.ai/code/session_01MCjuARQfuyowAbJ9fwiEnH

* Update src/panels/security/strategies/security-view-strategy.ts

* remove import

* Set max column to 3 and fix title margin

* Type fix

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
Co-authored-by: Paul Bottein <[email protected]>
2026-04-22 16:19:38 +03:00
João Palmeiro 09817d166a Fix sidebar layout to ensure all options are visible on mobile browsers (#51672) 2026-04-22 14:57:35 +02:00
ildar170975andPetar Petrov c83177b600 hui-dialog-edit-card: independent scrollbars (#29648)
* add independent scrollbars

* resolving conflicts

* cleanup

* resolving conflicts

* fix for ha-switch overflow

* add ha-scrollbar

* Avoid !important by scoping selectors to editor and preview

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-04-22 12:50:22 +00:00
Aidan TimsonandPetar Petrov 55670550ef Improve typing on lifestyle functions for changed props (5/5) (#51669)
* Split typing-common-funcs (5/5)

* Loosen

* Add missing typing

* Fix imports

Co-authored-by: Petar Petrov <[email protected]>

* Restore typing + stricter

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-04-22 15:49:03 +03:00
Aidan TimsonandPetar Petrov b3cf298b2d Improve typing on lifestyle functions for changed props (3/5) (#51667)
* Split typing-common-funcs (3/5)

* Fix

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

* Loosen

* Loosen

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-04-22 15:47:55 +03:00
Aidan Timson 278195de04 Improve typing on lifestyle functions for changed props (2/5) (#51665)
* Split typing-common-funcs (2/5)

* Fix

* Fix

* Fix

* Restore original
2026-04-22 15:46:45 +03:00
Paulus SchoutsenandClaude 579b7bf568 Update name and look and feel of Serial Port Selector (#51655)
* Auto-refresh serial ports every 5s in serial selector

Schedules the next fetch via setTimeout once the previous response
resolves, so slow responses don't stack requests. Refreshing is
stopped when the element is disconnected and restarted on reconnect.

* Refresh serial ports only while picker dropdown is open

Emit a picker-opened event from ha-generic-picker and use it in the
serial selector to drive a 5s refresh loop that only runs while the
dropdown is open. The initial load still happens on firstUpdated so
the dropdown has data when the user opens it.

* Allow refreshing picker items while dropdown is open

ha-picker-combo-box caches its items on first update, so the serial
selector's auto-refresh had no effect while the dropdown was open.
Add a public refreshItems() method to re-run getItems and update the
visible list, expose it through ha-generic-picker, and call it from
the serial selector after each refresh.

* Format with prettier

* Categorize serial ports and improve item display

Group ports by type in the serial selector dropdown — integration-provided
(URI-schemed like esphome://), USB (vid/pid), built-in, and unnamed local
ports — with a section header and filter chip for each. Within each section
items are sorted by product name, and unnamed ports (no description or
manufacturer) fall to the last section so they only appear when they
actually exist, which is mostly in dev environments.

Item display now leads with the product description and manufacturer; the
device path, vid:pid, and serial number move to a less prominent secondary
line. ESPHome entries show the ESPHome logo, other integration-provided
ports get a generic connection icon, USB ports a USB icon, and embedded
ports a memory chip icon.

* Rename Unnamed serial port category to Other

* Rename serial selector to serial_port selector

Updated the selector key from `serial` to `serial_port`, renamed the
class to HaSerialPortSelector / SerialPortSelector and the custom
element to `ha-selector-serial_port`, moved translations under
`ui.components.selectors.serial_port`, and renamed the file to
`ha-selector-serial-port.ts`.

---------

Co-authored-by: Claude <[email protected]>
2026-04-22 08:29:56 -04:00
Aidan Timson b6edecb888 Improve typing on lifestyle functions for changed props (4/5) (#51668)
* Split typing-common-funcs (4/5)

* Loosen

* Fix

* Fix

* Fix

* Restore
2026-04-22 15:16:57 +03:00
renovate[bot] c7972e1c1f Update dependency lodash.template to v4.18.0 [SECURITY] (#51348)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-22 14:01:24 +03:00
Aidan Timson 442d7fe3b4 Improve typing on lifestyle functions for changed props (1/5) (#51664)
* Split typing-common-funcs (1/5)

* Fix
2026-04-22 13:37:22 +03:00
karwosts ffcddf556d Consider entity precision in adjust-sum dialog (#51659)
* Consider entity precision in adjust sum dialog

* Adjust step selector
2026-04-22 08:08:49 +03:00
karwosts 0d3900f2cf Stop keydown events propagating from ha-textarea (#51661) 2026-04-22 08:07:21 +03:00
renovate[bot] 37b14a68b2 Update dependency @codemirror/view to v6.41.1 (#51660)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-22 08:03:41 +03:00
João Palmeiro 10e8189d5b Fix focus ring for HaFilterChip (#51657) 2026-04-21 19:24:28 +00:00
renovate[bot] 365b54b4fd Update dependency marked to v18.0.2 (#51653)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-21 17:14:37 +03:00
Jeremy CookandPetar Petrov b5a479b07e Add use_entity_picture option to picture-entity card (#51553)
* Add use_entity_picture option to picture-entity card

Allow picture-entity cards to display the entity's entity_picture attribute instead of requiring a manually configured image URL. This is particularly useful for entities that dynamically set their entity_picture (e.g., update entities showing component logos, custom integrations, etc.).

The static image configuration remains as a fallback when the entity_picture attribute is not present or when use_entity_picture is not enabled.

Changes:
- Add use_entity_picture boolean option to PictureEntityCardConfig
- Implement logic to check entity_picture attribute when enabled
- Update validation to accept use_entity_picture as valid image source
- Add editor toggle with helper text
- Add translation strings for the new option

* Rename use_entity_picture to show_entity_picture and add entity_picture_local support

Address review feedback:
- Rename use_entity_picture to show_entity_picture to match tile card and badge naming
- Check entity_picture_local first before entity_picture, following tile card pattern
- Update all references in types, card implementation, editor, and translations

* Fix TypeScript error for entity_picture_local access

* Address review feedback - less technical formulation

* Drop unnecessary cast in picture-entity card

Widen stateObj to HassEntity so entity_picture_local is accessible
without an inline cast, matching the tile-card pattern.

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-04-21 09:22:06 +00:00
Wendelin 389ac06e35 Use home-assistant.io/socials (#51649) 2026-04-21 08:21:49 +00:00
MikeDev96 c8459eb781 Add paste above/below buttons in automation editor (#51495)
* Add paste above/below buttons in automation editor

* Removed paste above option and renamed paste below to paste

* Added shortcut hint to paste options
2026-04-21 09:27:11 +02:00
Aidan Timson 74fd7b61f1 Add missing actions permission to stale workflow (#51638)
* Add missing actions permission to stale workflow

* Prioritise oldest updated items

* Don't change ordering
2026-04-21 08:45:10 +03:00
renovate[bot] 5d32bf338b Update dependency eslint to v10.2.1 (#51648)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-21 08:44:10 +03:00
Stefan AgnerandClaude Opus 4.7 4848e939b4 Fix supervisor My redirects for Container installs (#51645)
The supervisor_* My redirects (supervisor_store, supervisor_addons,
supervisor_app, supervisor_addon, supervisor_add_addon_repository) had
no component gate, so on Container installations they silently
navigated to broken pages. Gate them on the hassio component and route
the missing-hassio case through the existing no_supervisor error
message, which now links directly to the installation docs.

Also remove the unreachable /hassio/_my_redirect/ fallback that was
left behind by the standalone hassio panel removal (#29132), and
update the no_supervisor string: Home Assistant Supervised is no
longer a supported installation method (see architecture discussion
home-assistant/architecture#1198), only Home Assistant OS.

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
2026-04-20 18:32:30 +02:00
Stefan AgnerandClaude Opus 4.7 23acfc729c Remove dead /hassio URL references (#51643)
The standalone hassio panel at /hassio was removed in #29132 and
replaced by the apps panel under /config/apps in #28245. A couple of
references to the old URL path were missed: a dead branch in the
quick-bar My-link builder and a /hassio/ startsWith check that kept
the configuration sidebar item highlighted.

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
2026-04-20 18:13:06 +02:00
Paul Bottein 93110b1d70 Fix section config not propagating to layout element (#51640) 2026-04-20 15:29:16 +02:00
Wendelin 541c112159 Automation add TCA: Auto-expand single floor values (#51639)
Auto-expand floor section if only one floor is present
2026-04-20 14:06:58 +02:00
Aidan TimsonandPaul Bottein 84382fdf0d Support scrolling on heading cards (#51567)
* Clean

* Scrollable option

* Refactor

* Remove wrap

* Restore

* Show grab cursor when dragging

* Overflow handling

* Remove extra space on start and end item

* Shrink title

Co-authored-by: Paul Bottein <[email protected]>

* Increase min width of title, set var

* More specific

* Use 120px min on small layouts

* Try to fix sizing

* No unnessasary vars

* Format

---------

Co-authored-by: Paul Bottein <[email protected]>
2026-04-20 14:00:12 +02:00
591057b80d Tooltip styling and sidebar tooltips (#30386)
Co-authored-by: Claude Sonnet 4.6 (1M context) <[email protected]>
Co-authored-by: Wendelin <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2026-04-20 11:37:48 +00:00
Wendelin d220725e5b ha-switch webawesome (#51507) 2026-04-20 13:19:53 +02:00
renovate[bot] fdb4de9aa8 Update dependency @rsdoctor/rspack-plugin to v1.5.9 (#51636)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-20 13:09:24 +03:00
Aidan Timson c3b768c111 Allow for decimals in cover and valve favorites (#51633)
* Allow for decimals in cover and valve favorites

* Merge normalise functions
2026-04-20 12:43:38 +03:00
Wendelin 7d9874adfa Remove allow-mode-change in quick search (#51634)
Remove allow-mode-change attribute from ha-adaptive-dialog in QuickBar component
2026-04-20 12:33:29 +03:00
renovate[bot] 64ad41a533 Update Yarn to v4.14.1 (#51631)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-20 09:16:38 +03:00
renovate[bot]andPetar Petrov 520739dd0e Update formatjs monorepo (#51601)
* Update formatjs monorepo

* Fix types

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <[email protected]>
2026-04-20 06:07:59 +00:00
Aidan Timson 30f70e179a Fix inconsistency with template binary sensors (#51486)
Fix inconsistency with template binary sensors with template options flow
2026-04-20 08:35:49 +03:00
e66564ff65 Add apps group to navigation picker with all web UI addons (#51572)
* Add apps navigation group with ingress add-on panels

Add an "Apps" section to the navigation picker that shows all add-ons
with ingress support. Uses the /ingress/panels supervisor endpoint via
a cached collection to fetch add-on titles and icons in a single call.

https://claude.ai/code/session_01F8dUzfSWj8ZwDByVZ45BNj

* Fix no-shadow lint error for panels variable

Rename subscribe callback parameter from `panels` to `data` to avoid
shadowing the outer `panels` variable in _loadNavigationItems.

https://claude.ai/code/session_01F8dUzfSWj8ZwDByVZ45BNj

* Use subscribeOne helper for ingress panels collection

Replace hand-rolled Promise/subscribe/unsub pattern with the existing
subscribeOne utility for cleaner one-shot collection consumption.

https://claude.ai/code/session_01F8dUzfSWj8ZwDByVZ45BNj

* Add explicit type parameter to subscribeOne call

TypeScript cannot infer the generic type through the collection
subscribe chain, resulting in unknown type for panel entries.

https://claude.ai/code/session_01F8dUzfSWj8ZwDByVZ45BNj

* Add subscribeOneCollection helper for collection one-shot reads

Add a new subscribeOneCollection utility that takes a collection
directly instead of requiring the (conn, onChange) function pattern.
Use it in the navigation picker for cleaner ingress panel fetching.

https://claude.ai/code/session_01F8dUzfSWj8ZwDByVZ45BNj

* Use Collection type instead of custom Subscribable interface

https://claude.ai/code/session_01F8dUzfSWj8ZwDByVZ45BNj

* Add ingress panel support to subscribeNavigationPathInfo

* Use app panel variable

* Add tests

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Paul Bottein <[email protected]>
2026-04-20 08:28:01 +03:00
Paulus SchoutsenandClaude 70ac14ed52 Allow disabling the maintenance summary from the home editor (#51622)
https://claude.ai/code/session_01FkRan4yxJzdjJJmjSRtoY1

Co-authored-by: Claude <[email protected]>
2026-04-20 08:27:14 +03:00
renovate[bot] e0d881ff53 Update dependency marked to v18.0.1 (#51630)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-20 06:50:50 +02:00
Logan RosenandCopilot 61c0b7394e Remove core-only development checklist from PR template (#51624)
The PR template includes a checklist item linking to the development
checklist page, but that page only covers core/Python-specific items
(pypi, requirements_all.txt, CODEOWNERS, .strict-typing, Ruff). None
of these apply to the frontend repository.

No frontend-specific development checklist exists, so remove the item
entirely rather than link to irrelevant documentation. The "perfect PR
recommendations" checklist item already covers general PR best practices.

Co-authored-by: Copilot <[email protected]>
2026-04-20 06:50:33 +02:00
ildar170975 34b2509a76 Gauge card: fix a height in Horizontal stack (#51626)
remove styles for ":host"
2026-04-20 06:46:28 +02:00
renovate[bot] 7d03ef6dfc Update dependency typescript to v6.0.3 (#51628)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-20 06:41:27 +02:00
renovate[bot] 96b59c6171 Update Yarn to v4.14.0 (#51621)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-19 22:18:04 +02:00
renovate[bot] 7691d2ca4a Update dependency @codemirror/lang-jinja to v6.0.1 (#51618)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-19 22:17:47 +02:00
Simon Lamon da1c2bdee4 Adjust gauge again (#51613) 2026-04-19 08:55:54 +03:00
renovate[bot] 509443fbb2 Update dependency @bundle-stats/plugin-webpack-filter to v4.22.1 (#51610)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-18 09:02:13 +02:00
renovate[bot] 07992286b5 Update dependency prettier to v3.8.3 (#51611)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-18 09:01:52 +02:00
renovate[bot] cf7274b0ba Update dependency @rsdoctor/rspack-plugin to v1.5.8 (#51605)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-17 18:53:54 +02:00
Paulus SchoutsenandClaude Opus 4.6 501c72d203 Add config sub-routes to navigation picker (#51597)
Add Automations, Scenes, Scripts, Developer Tools, Integrations,
Devices, and Entities to the "Other routes" section of the navigation
picker. Also resolve these paths with proper labels and icons in
computeNavigationPathInfo so they display correctly everywhere
(shortcut cards, edit overview, etc.).

Co-authored-by: Claude Opus 4.6 <[email protected]>
2026-04-17 08:20:03 +03:00
karwosts a0ad488579 Fix gauge missing label on load (#51584) 2026-04-17 08:18:16 +03:00
renovate[bot] ead2d1296f Update dependency hls.js to v1.6.16 (#51599)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-17 07:09:15 +02:00
renovate[bot] 5ba5408e78 Update dependency typescript-eslint to v8.58.2 (#51600)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-17 07:08:59 +02:00
Paulus Schoutsen eecca1fa55 Add ESPHome logo (#51598) 2026-04-16 12:38:53 -04:00
Jeremy CookandPaul Bottein f2ba0fca73 Add per-section theme support (#29745)
* Add per-section theme support

* Fix linting errors: rename property parameter and use dot notation

* Fix TypeScript error: cast to any for __themes property

* Refactor theme application logic for race condition on first load, missing reconnect handling, and the fragile _applyTheme internals https://github.com/home-assistant/frontend/pull/29745

* correct formatting with prettier --write

* Fix theme application logic on reconnect by checking for theme configuration

* Pass section theme to background component for theme variable access

Section backgrounds now receive the section's theme and hass properties,
allowing them to apply the theme via applyThemesOnElement(). This enables
background components to access CSS variables from the section's theme,
particularly --ha-section-background-color when using the 'Default' color option.

Previously, the background component was rendered as a sibling to the section
element and couldn't access theme variables from the section's applied theme.
Now the theme is explicitly passed from hui-sections-view and applied to the
background component itself, making theme cascading work correctly.

* Reorder section settings: theme before background

* Add helper text support to theme selector

Theme selectors can now display helper text below the dropdown. Added helper property to ha-selector-theme and ha-theme-picker components, which is passed through to ha-select. Updated section theme label and added helper text to explain its purpose.

* Address PR review feedback: move theme to end and simplify label

- Move theme selector to end of form (after background section)
- Change label from 'Section theme' to 'Theme' as context is already clear

* Handle theme removal for background

---------

Co-authored-by: Paul Bottein <[email protected]>
2026-04-16 15:20:08 +00:00
Paulus SchoutsenandClaude Opus 4.6 fc448ab3a7 Add serial selector to initial form data (#51595)
Co-authored-by: Claude Opus 4.6 <[email protected]>
2026-04-16 15:46:11 +01:00
Paul Bottein 9269c1ff0a Redesign lawn mower more info dialog (#51596) 2026-04-16 16:45:21 +02:00
Petar Petrov b7dcbd559e Add hourly forecast card feature for weather entities (#51594) 2026-04-16 14:42:10 +01:00
Paul BotteinandClaude 80e0c098f8 Redesign vacuum more info dialog (#51380)
Co-authored-by: Claude <[email protected]>
2026-04-16 14:11:07 +02:00
Aidan Timson 364c793ee6 Support suggested name and icon for dashboards, add to map (#51592) 2026-04-16 14:03:44 +02:00
Aidan TimsonandWendelin 99f36e1aad Refactor weather forecast card to scroll (#51580)
Co-authored-by: Wendelin <[email protected]>
2026-04-16 11:42:06 +00:00
Aidan TimsonandPetar Petrov 25dcaa4eb8 Device and browser environment for debug tools (#51568)
* Add viewpoer environment card to debug tools

* Move

* Cleanup

* Remove

* Remove scroll listener

* Update translation

* Output as yaml

* Apply suggestion

Co-authored-by: Petar Petrov <[email protected]>

* Finish

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-04-16 13:32:29 +03:00
Wendelin d92f7e14b4 ha-checkbox with webawesome (#51581)
* ha-checkbox with webawesome

* Fix checkboxes

* remove mwc-checkbox

* Copilot review

* Fix data table range checkbox select
2026-04-16 13:12:04 +03:00
renovate[bot] 2c1bf3369d Update Node.js to v24.15.0 (#51590)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-16 11:45:13 +03:00
Paulus Schoutsen 81d57cf43c Add SerialSelector (#51573)
* Add SerialSelector

* Address comments
2026-04-16 10:45:45 +03:00
Paulus SchoutsenandPaul Bottein 09053533ff Add custom pages summaries (#51506)
* Add custom pages to home page summaries

* Address comments

* Extract helper

* Update UI editor and use shortcut card

---------

Co-authored-by: Paul Bottein <[email protected]>
2026-04-16 10:02:11 +03:00
Aidan Timson 7df61f239f Offset toast position, apply for automation/script editor (#51575)
* Alllow setting of toast position

* Switch to use offset

* Create wrapper for toast to offset with automation editor

* Use wrapper

* Add for clipboard pastes

* Make automation toasts dismissable

* Apply for script editor

* Rename
2026-04-16 09:57:06 +03:00
Paulus SchoutsenandClaude Opus 4.6 f89eace462 Resolve add-on name and icon for shortcut card /app/ navigation (#51587)
* Resolve add-on name and icon for shortcut card /app/ navigation paths

When a shortcut card or badge navigates to /app/{slug}, fetch the add-on's
panel info (title and icon) from the supervisor ingress panels endpoint and
display it instead of the generic "app" panel fallback.

Adds a cached collection for ingress panel data (title and icon per add-on)
using getCollection, so the data is fetched once per connection.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* Simplify

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
2026-04-16 09:41:36 +03:00
Wendelin 52956eefc6 ha-select allow number values (#51564) 2026-04-16 08:29:03 +02:00
Tom Carpenter 1fbbeba083 Correct statistic graph chart types to sentence case (#51579)
Correct statistic chart types to sentence case
2026-04-16 08:48:22 +03:00
Jan Čermák 4e0d2e290a Fix rendering of select with multiple options in SupervisorAppConfig (#51585)
If the app config contains a schema field like this one:

```
privileges:
  - "list(ALTER|CREATE|...|UPDATE)?"
```

it was rendered incorrectly as a drop-down where only one item can be
selected - but this is wrong because of the preceding `-` denoting it
should be a list containing the listed values. Supervisor translated
this to an entry of type `select` with `multiple: true`. The `multiple`
flag wasn't passed along, with the flag set the field renders as
expected.

Fixes #51533
2026-04-16 08:47:48 +03:00
Paulus SchoutsenandClaude 641773d5c4 Add Music Assistant icon (#51586)
* Add Music Assistant fallback domain icon

Add mdiMusic as the fallback icon for the music_assistant domain
in FALLBACK_DOMAIN_ICONS, so the integration has a proper icon
when dynamic icons are unavailable.

https://claude.ai/code/session_01GfNQCZL3dF1GXLRfhNRt25

* Revert "Add Music Assistant fallback domain icon"

This reverts commit 130d6eddee.

* Add Music Assistant logo as injectable mdi icon

Add the Music Assistant logo SVG as a special named icon, following
the same pattern as the Home Assistant logo (mdi:home-assistant).
This allows referencing mdi:music-assistant anywhere in the frontend
(e.g., add-on sidebar icon) and it resolves to the Music Assistant
logo SVG path.

https://claude.ai/code/session_01GfNQCZL3dF1GXLRfhNRt25

* Simplify logic to add more in future

---------

Co-authored-by: Claude <[email protected]>
2026-04-15 19:28:20 -04:00
karwosts 3b53867216 Fix gauge segmentLabels, cleanup sorting (#51583) 2026-04-15 16:57:17 +03:00
Paul BotteinandNorbert Rittel 7ea936088c Add shortcut badge (#51569)
* Add shortcut badge

* Fix label

* Update src/translations/en.json

Co-authored-by: Norbert Rittel <[email protected]>

* Update card description

* Feedbacks

---------

Co-authored-by: Norbert Rittel <[email protected]>
2026-04-15 16:54:19 +03:00
Aidan Timson 4281240383 Add grab cursor to more info weather forecast (#51582) 2026-04-15 14:58:19 +02:00
Timothy 6b6203986d Increase height of HAInputSearch (#51576) 2026-04-15 13:53:55 +01:00
renovate[bot] 6997ffa580 Update dependency globals to v17.5.0 (#51574)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-15 12:47:24 +03:00
Raphael HehlandPetar Petrov 2d2558db40 Fix history/sensor cards stuck loading after backend restart (#51531)
* Fix history/sensor cards stuck loading after backend restart

- Add { resubscribe: false } to history subscriptions to prevent
  corrupt HistoryStream state on auto-resubscription
- Add connection-status handlers to re-subscribe on reconnect
- Add sentinel pattern to prevent re-entrant async subscriptions
- Add shouldUpdate/updated retry when components become available
- Clear sensor device classes cache on WS error
- Clear _error on reconnect so cards can retry
- Add .catch() on unsubscribe to handle dead subscriptions

* Fix type annotation for callWS in getSensorNumericDeviceClasses

* Address review: type connection-status handlers, add reconnect to history panel

- Use HASSDomEvent<ConnectionStatus> instead of (ev as CustomEvent).detail
  for proper type safety on all connection-status handlers
- Add connection-status handler to ha-panel-history so it re-subscribes
  after backend restart (addresses concern about resubscribe: false)

* Address review: sentinel pattern, reconnect handling, stale data reset

- Add sentinel pattern to ha-more-info-history, ha-panel-history,
  hui-history-graph-card to prevent re-entrant subscription races
- Refactor hui-trend-graph-card-feature from SubscribeMixin to manual
  subscription management with connection-status reconnect support
- Reset stale history/statistics data on reconnect in
  hui-history-graph-card and hui-map-card before re-subscribing
- Wrap fetchStatistics and getSensorNumericDeviceClasses calls in
  ha-panel-history with try/catch to handle errors gracefully
- Chain .catch directly on subscribeHistoryStatesTimeWindow in
  hui-trend-graph-card-feature to avoid detached-promise race condition

* Centralize history stream reconnect handling in data layer

Move the reconnect logic from every consumer into `subscribeHistoryStream`
in data/history.ts. The helper listens to the connection's `ready` event
itself, and on reconnect creates a fresh `HistoryStream` and rebuilds
params (so `start_time` for the time-window variant is re-anchored to
"now"). `resubscribe: false` stays as an internal implementation detail.

Removes the duplicated `_handleConnectionStatus` boilerplate and
`connection-status` window listeners from all six history consumers.

* Render subscription errors and make _error reactive

`_error` was declared as a plain string field in hui-graph-header-footer
and ha-more-info-history (non-reactive) and typed as Error/string while
being assigned the WS error object. hui-trend-graph-card-feature had it
reactive but never rendered it.

Align all three with the hui-history-graph-card pattern: reactive
`{ code, message }` and a user-visible error branch in render(). Without
this, a failed subscription would leave the component stuck on a spinner
forever.

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-04-15 11:34:13 +03:00
Paul Bottein 039fc45532 Add shortcut card (#51562)
* Add shortcut card

* Improve action support
2026-04-15 08:53:08 +03:00
renovate[bot] 209e6f8def Update dependency sinon to v21.1.2 (#51571)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-14 20:44:08 +02:00
Yosi LevyandWendelin f6a19eb6c4 Fix entity ID orientation in device editor (#51560)
* Fix entity ID orientation

* Apply suggestions from code review

Co-authored-by: Wendelin <[email protected]>

* Fix indentation in entity-registry-settings-editor.ts

---------

Co-authored-by: Wendelin <[email protected]>
2026-04-14 17:49:39 +00:00
karwostsandPetar Petrov ceb9967deb Make picture elements editor sortable (#51563)
* Make picture elements editor sortable

* Update src/panels/lovelace/editor/hui-picture-elements-card-row-editor.ts

Co-authored-by: Petar Petrov <[email protected]>

* Update src/panels/lovelace/editor/hui-picture-elements-card-row-editor.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-04-14 15:00:07 +00:00
Tom Carpenter b2015465fb Add stacked chart types to Statistics Graph Card (#51530)
* Add stacked mode to statistics-chart

Allows displaying the entries as stacked lines or stacked bars. This means we can create charts similar to the energy graph cards but with alternate entities.

* Move fillDataGapsAndRoundCaps to components/chart

Now used in statistics-chart too, so move to common chart location.
Re-export in energy-chart-options.ts to minimise changes throughout energy cards.

* Correct order of line/bar in statistics graph card editor

Line and Bar options were unintentionally reversed in the displayed list.

* Support unstacked bar charts in fillDataGapsAndRoundCaps
2026-04-14 17:45:47 +03:00
karwosts 8e4c99049f Adjust outlier detection algorithm when partial 5minute data exists (#51561) 2026-04-14 16:44:12 +03:00
Petar Petrov 5a5b8c0bbd Add controls option to media player playback card feature (#30338)
* Add controls option to media player playback card feature

Allow users to configure which playback controls are shown and in what
order. When controls are explicitly configured, each selected control
is rendered as its own button in the specified order. When no controls
are configured, the original default behavior is preserved.

Also adds a configuration editor for the feature and fixes inline
feature padding in the tile card container.

* Revert padding changes to ha-tile-container

* Use computeMediaControls for default playback buttons

Reuse the shared computeMediaControls function for the default (no
explicit controls) path instead of duplicating the logic. Apply the
narrow filter to both paths via a shared _filterNarrow method.
2026-04-14 16:29:57 +03:00
Petar Petrov b60d189a69 Remove invalid dependabot cooldown option (#51558) 2026-04-14 10:28:35 +02:00
Aidan Timson 19ed00c677 Combine all entity modes card feature editors with shared base class (#51543)
* Combine all entity modes card feature editors with shared base class

* Remove hass from schema memo
2026-04-14 11:26:55 +03:00
Bram Kragten b92775ea2d Improve code editors (#51555)
* Update YAML and Jinja code editor support, support Jinja in YAML

* add autocomplete for ha jinja functions

* Use snippets and better autocomplete for jinja

* Add autocomplete for devices

* Add area, floor, label autocomplete

* Add yaml scalar type highlighter

* Add autocomplete for `states` var

* Add autocomplete for attributes

* Make autocomplete work on id and name

* Add missing functions that can also be used as filter
2026-04-14 09:19:37 +03:00
renovate[bot] b5bacf85dd Update dependency sinon to v21.1.1 (#51557)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-14 08:42:37 +03:00
Yosi Levy 8f4fe9ba4e Fix date picker header (#51552) 2026-04-13 22:02:36 +02:00
Wendelin 9179218336 Improve view footer card visibility handling (#51549) 2026-04-13 17:12:57 +02:00
JamesFromITandPaul Bottein 274ec50dbd Make dialog title a semantic heading element (#51521)
* Make dialog title a semantic heading element

* Move away from inheriting everything from modal title parent

* Update src/dialogs/generic/dialog-box.ts

---------

Co-authored-by: Paul Bottein <[email protected]>
2026-04-13 12:38:31 +00:00
Wendelin 2629881a18 Hide footer if card is not visible (#51544)
* Fix footer visibility logic in render method

* use card-visibility-changed
2026-04-13 14:00:44 +02:00
dependabot[bot] d7f143a65a Bump actions/github-script from 8.0.0 to 9.0.0 (#51539)
Bumps [actions/github-script](https://github.com/actions/github-script) from 8.0.0 to 9.0.0.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/ed597411d8f924073f98dfc5c65a23a2325f34cd...3a2844b7e9c422d3c10d287c895573f7108da1b3)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-version: 9.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-13 13:17:21 +02:00
Wendelin 9cce20bad1 Enhance sun condition automation: add 'between' option and improve duration formatting (#51502) 2026-04-13 11:58:20 +02:00
Aidan TimsonandClaude c9ad84b234 Register custom dashboard strategies (#51310)
* Allow custom dashboard strategies to register for the add dashboard dialog

Adds a window.customDashboardStrategies registration mechanism (mirroring
window.customCards) so third-party strategies can appear in the new dashboard
picker. Only dashboard-level strategies are surfaced; view and section
strategies are excluded. Custom strategies appear in their own section and
are included in search results.

https://claude.ai/code/session_019MXBdWUQrFQfH54QVjbq8y

* Rename custom dashboards heading to community dashboards

https://claude.ai/code/session_019MXBdWUQrFQfH54QVjbq8y

* Consolidate into a single customStrategies registry for all strategy types

The window.customStrategies array now accepts entries with a strategyType
field (dashboard, view, or section). The dialog filters for dashboard
strategies. This allows future use of the same registry for view and
section strategy registration.

https://claude.ai/code/session_019MXBdWUQrFQfH54QVjbq8y

* Space tokens

* Space tokens

* Add support for images

* Allow single image from custom strategy

* Load needed resources for new dashboard dialog

* Preload custom strategies

* Catch potential error

* Reset if error

* Improve typing

* Cache module resources to avoid duplicate loads

* Revert "Cache module resources to avoid duplicate loads"

This reverts commit 87bbcc04510034111b95073fafb0952e7dc2335f.

* Set a max height for dashboard images (match max height of current core images)

* Remove image support

---------

Co-authored-by: Claude <[email protected]>
2026-04-13 11:57:59 +02:00
Wendelin cb89b8aea8 Use wa-tag for target picker chips (#51482) 2026-04-13 11:57:46 +02:00
dependabot[bot] a5f4885d95 Bump home-assistant/actions from 5752577ea7cc5aefb064b0b21432f18fe4d6ba90 to f6f29a7ee3fa0eccadf3620a7b9ee00ab54ec03b (#51535)
Bump home-assistant/actions

Bumps [home-assistant/actions](https://github.com/home-assistant/actions) from 5752577ea7cc5aefb064b0b21432f18fe4d6ba90 to f6f29a7ee3fa0eccadf3620a7b9ee00ab54ec03b.
- [Release notes](https://github.com/home-assistant/actions/releases)
- [Commits](https://github.com/home-assistant/actions/compare/5752577ea7cc5aefb064b0b21432f18fe4d6ba90...f6f29a7ee3fa0eccadf3620a7b9ee00ab54ec03b)

---
updated-dependencies:
- dependency-name: home-assistant/actions
  dependency-version: f6f29a7ee3fa0eccadf3620a7b9ee00ab54ec03b
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-13 11:08:45 +02:00
Aidan Timson e2e114cb4e Add shared editor for all more info hints, add lights (#51542)
* Add more info redirect editor for light favorites

* Merge all hint feature editors to one shared component

* Fix
2026-04-13 11:07:55 +02:00
dependabot[bot] 4a0284455d Bump pypa/gh-action-pypi-publish from 1.13.0 to 1.14.0 (#51537)
Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.13.0 to 1.14.0.
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e...cef221092ed1bacb1cc03d23a2d87d1d172e277b)

---
updated-dependencies:
- dependency-name: pypa/gh-action-pypi-publish
  dependency-version: 1.14.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-13 11:06:10 +02:00
JamesFromIT d220eba9f7 Make history page title a semantic heading (#51527) 2026-04-13 08:39:50 +00:00
Paul Bottein 2edb0325aa Improve box shadow design tokens with multi-layer shadows (#51378) 2026-04-13 10:36:17 +02:00
dependabot[bot] 2e1582a9c1 Bump actions/upload-artifact from 7.0.0 to 7.0.1 (#51538)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-13 09:36:01 +01:00
dependabot[bot] 006cdf088a Bump release-drafter/release-drafter from 7.1.1 to 7.2.0 (#51536)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-13 09:35:46 +01:00
Wendelin d9b0bf21c0 Fix register admin quick search shortcuts (#51540) 2026-04-13 08:56:03 +01:00
JamesFromIT 7df059b4cf Make media management dialog heading a semantic heading element (#51522) 2026-04-13 06:41:36 +00:00
JamesFromIT 4cfc0dd6c3 Make media browser tab title a semantic heading element (#51528) 2026-04-13 06:36:32 +00:00
Carlos AguilarandCopilot fb9f182dcc Fix: Center more-info-media_player component volume buttons (#51517)
Co-authored-by: Copilot <[email protected]>
2026-04-13 06:33:05 +00:00
renovate[bot] 880b226d10 Update dependency sinon to v21.1.0 (#51529)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-13 07:04:53 +02:00
renovate[bot] 031e6ea789 Update dependency prettier to v3.8.2 (#51534)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-13 07:04:15 +02:00
pcan08 d025a842c4 Use header-subtitle in dialog-edit-home (#51525)
Replace the custom `<p class="description">` element and its associated
CSS with the built-in `headerSubtitle` property on `ha-dialog`.
2026-04-12 11:27:11 +02:00
Wendelin 775f145c9f Add ha-progress-bar highlight style variables (#51489)
Enhance ha-progress-bar styles and properties for improved customization
2026-04-12 09:51:01 +02:00
Paulus SchoutsenandClaude Opus 4.6 f9caf5365e Hide internal panels from navigation picker (#51497)
* Hide _my_redirect and notfound panels from navigation picker

These internal panels are not useful navigation targets and should not
appear in the "Other routes" section of the navigation picker.

https://claude.ai/code/session_01DT6YNh9gjLpTztxA6z79w5

* Address review: use panel constants and move to module level

- Add MY_REDIRECT_PANEL constant to src/data/panel.ts
- Use NOT_FOUND_PANEL and MY_REDIRECT_PANEL instead of string literals
- Move HIDDEN_PANELS to module level since it doesn't need recreation

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Add SYSTEM_PANELS constant and use in navigation picker and quick bar

- Add APP_PANEL constant and SYSTEM_PANELS array to data/panel.ts
- Use SYSTEM_PANELS in ha-navigation-picker.ts and quick_bar.ts
- Remove obsolete hassio panel filter from quick bar (no longer exists)
- Also hides the app panel from navigation picker

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

---------

Co-authored-by: Claude <[email protected]>
2026-04-12 09:49:15 +02:00
renovate[bot] b1419b7761 Update vitest monorepo to v4.1.4 (#51524)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-12 07:45:00 +00:00
Paulus SchoutsenandClaude be0a673d4e Add error handling for backup creation failures (#51520)
* Show error details when backup creation fails

When generateBackup or generateBackupWithAutomaticSettings raises an
error (e.g., not enough free space), the error details are now shown
to the user in an alert dialog instead of only being logged to the
console.

https://claude.ai/code/session_01XWxeS4ZxxZfnt8h2pLsSMn

* Consolidate duplicate try-catch into single block in _newBackup

https://claude.ai/code/session_01XWxeS4ZxxZfnt8h2pLsSMn

---------

Co-authored-by: Claude <[email protected]>
2026-04-12 09:39:10 +02:00
Aidan Timson 8e31316692 Add link to UX design in issue template (#51503) 2026-04-12 09:38:01 +02:00
renovate[bot] f9db26166f Update dependency typescript-eslint to v8.58.1 (#51514)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-11 11:00:39 +02:00
Bram Kragten f7e92b484a Bumped version to 20260325.7 2026-04-10 17:44:15 +02:00
Aidan TimsonandWendelin 9fab7bafdb Allow quick search for non-admins, while hiding inaccessible areas (#51456)
Co-authored-by: Wendelin <[email protected]>
2026-04-10 17:40:25 +02:00
Petar Petrov 0dabb02007 Fix dialog show animation broken by connectedCallback _open sync (#51450) 2026-04-10 17:38:06 +02:00
Petar Petrov 5b73e86786 Fix toast race condition causing stuck notifications (#51447) 2026-04-10 17:38:05 +02:00
Timothy 144d7c5c3f Android externalAppV2 (#51446) 2026-04-10 17:37:08 +02:00
Petar Petrov 8b396dc640 Preserve browser back/forward keyboard shortcuts in tab group (#51439) 2026-04-10 17:33:34 +02:00
Aidan Timson 9bf48d30ab Handle lazy loaded entity registry when editing scripts from more info (#51438)
* Handle lazy loaded entity registry when editing scripts from more info

* Remove extra check

* Fix type of mixin
2026-04-10 17:33:33 +02:00
GeorgeZ83andWendelin 35fee46f5b Fix media browser dialog window (#51423)
Co-authored-by: Wendelin <[email protected]>
2026-04-10 17:33:32 +02:00
Niccolò Betto 9ac6636029 Fix code input dialog undefined value concatenation (#51399) 2026-04-10 17:33:31 +02:00
Simon Lamon 136462114d Increase gauge thickness for accessibility reasons (#51382)
Increase thickness for accessability reasons
2026-04-10 17:33:30 +02:00
Wendelin 7ceba8d231 Add context groups (#51471) 2026-04-10 16:03:34 +02:00
renovate[bot] 2a0b4c8f18 Update vitest monorepo to v4.1.3 (#51505)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-10 10:52:27 +00:00
Aidan Timson 6c762e0105 Ignore local opencode directory (#51504) 2026-04-10 12:44:48 +02:00
renovate[bot] 4ceb4c3c2c Update dependency marked to v18 (#51499)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-10 08:58:35 +02:00
renovate[bot] cebdb46989 Update dependency jsdom to v29.0.2 (#51498)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-10 08:42:18 +02:00
Paulus SchoutsenandClaude 5aeae9ffa5 Fix duplicate "Add custom path" entry in navigation picker (#51496)
The navigation picker's _getItems was adding an "Add custom path" item,
but ha-picker-combo-box already adds one when allowCustomValue is set
and there's a search string. Remove the duplicate from _getItems since
the combo box handles it via the customValueLabel prop.

https://claude.ai/code/session_01NAB8bo1B6HuGFwKZVbvL1S

Co-authored-by: Claude <[email protected]>
2026-04-10 08:19:58 +03:00
Aidan TimsonandPaul Bottein 2ce62841cf Settings dashboard repairs and updates design update (#51491)
* Reuse headings for config dashboard repairs and updates

* Keep headings internal to card and remove icons

* Merge headings into components

* Remove extra component for heading

* Use correct back links

Co-authored-by: Paul Bottein <[email protected]>

---------

Co-authored-by: Paul Bottein <[email protected]>
2026-04-09 20:29:56 +02:00
Timothy 63c9b85e6c Android externalAppV2 (#51446) 2026-04-09 16:34:32 +02:00
Petar Petrov 03ace97a7e Enable zoom and pan on sankey charts (#51488) 2026-04-09 16:32:12 +02:00
renovate[bot] 9edcfaf6b3 Update dependency @lokalise/node-api to v15.7.1 (#51490)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-09 14:53:58 +01:00
Paul BotteinandWendelin 5cb7fdbfed Add search bar to integration page (#51485)
Co-authored-by: Wendelin <[email protected]>
2026-04-09 15:16:01 +02:00
Petar Petrov 5a0e1e89e6 Add click-to-open-more-info to energy and water sankey cards (#51487) 2026-04-09 11:03:28 +00:00
Aidan Timson 5ac6906943 Fix regressions for search inputs with focus scrollable changes (#51484) 2026-04-09 10:51:43 +01:00
pcan08andClaude Sonnet 4.6 cf1fb7751f Home dashboard: show hide welcome message header (#51401)
* Allow showing/hiding welcome message on home overview

Add a toggle in the edit overview dialog to show or hide the
"Welcome, [user]" greeting header on the home overview page,
following the same pattern as the existing summary enable/disable.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Move welcome message toggle into its own section in home editor

The welcome message is a greeting header, not a summary card, so it
now lives in a separate "Greeting" section above the "Summaries" section.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* rename hidden_welcome_message to hide_welcome_message

* Use ha-form boolean selector for welcome message toggle

Replace manual label/ha-switch markup with ha-form using a boolean
selector for better accessibility and consistency with the rest of
the codebase.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Add helper text to welcome message toggle in home editor

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Remove greeting section header

* Extract welcome message schema into a module-level constant

---------

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
2026-04-09 10:53:41 +02:00
Paul Bottein 22f8ee0d79 Refactor integration page to build device/sub-entry tree in parent (#51374)
* Refactor integration page to build device/sub-entry tree in parent

* Avoid concurrency update

* Fix memoize

* Fix device name display
2026-04-09 11:02:56 +03:00
Bram Kragten 9e7d162724 Use fieldname as fallback instead of trigger/condition (#51474) 2026-04-08 14:39:30 +00:00
Bram Kragten 14addf02b8 Remove unused deps (#51473) 2026-04-08 15:38:42 +01:00
renovate[bot] 17bcf59c6a Update dependency browserslist-useragent-regexp to v4.1.4 (#51470)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-08 14:19:40 +01:00
Stefan Agner 0b1aa4a901 Rename "Registries" menu entry to "Registry credentials" (#51469)
Container registries can't be added really, they are part of an image
name. So the menu entry is a bit misleading. This commit renames it to
"Registry credentials" to make it more clear that it's just about
credentials for registries, not about adding registries.
2026-04-08 15:35:35 +03:00
Aidan Timson aab2304d86 Remove extra "Community:" prefix for add badge dialog (#51465)
Remove extra "Custom:" naming
2026-04-08 10:35:01 +00:00
Aidan Timson c013f79826 Add links to logs in integration page (#51463)
* Add link to logs in integration page

* Join

* Add link to "Check the logs"

* Add to entry overflow when in error state
2026-04-08 13:34:59 +03:00
renovate[bot] 60236c2fee Update dependency @html-eslint/eslint-plugin to v0.59.0 (#51464)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-08 11:26:42 +01:00
Aidan TimsonandWendelin 20d53a2659 Allow quick search for non-admins, while hiding inaccessible areas (#51456)
Co-authored-by: Wendelin <[email protected]>
2026-04-08 09:50:36 +02:00
Mihail SîrbuandWendelin 6dbc38386c Add apps info page for non-HAOS installations (#30364)
Co-authored-by: Wendelin <[email protected]>
2026-04-08 07:02:47 +00:00
renovate[bot] ce5a19caa8 Update dependency marked to v17.0.6 (#51460)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-08 08:59:33 +02:00
WendelinandPetar Petrov 2cda06e7a6 Introduce ha-progress-bar (#51453)
* Replace mwc-linear-progress with ha-progress-bar

* Update src/panels/lovelace/cards/hui-media-control-card.ts

Co-authored-by: Petar Petrov <[email protected]>

* Remove duplicate import of ha-slider in hui-media-control-card.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-04-08 09:40:42 +03:00
renovate[bot]andPetar Petrov 65485ce8c9 Update dependency fuse.js to v7.3.0 (#51457)
* Update dependency fuse.js to v7.3.0

* type fix

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <[email protected]>
2026-04-08 05:28:37 +00:00
GeorgeZ83andWendelin b73ae60cea Fix media browser dialog window (#51423)
Co-authored-by: Wendelin <[email protected]>
2026-04-07 14:52:16 +00:00
Petar Petrov cef35c6c23 Center energy dashboard bar charts on period midpoint (#30325) 2026-04-07 16:51:35 +02:00
Petar Petrov 6b9685ec9f Fix time condition summary using "and" instead of "or" for midnight-crossing ranges (#51452) 2026-04-07 16:47:17 +02:00
Petar Petrov fc9289dc05 Fix incorrect timezone in automation time trigger/condition descriptions (#51454) 2026-04-07 14:09:28 +00:00
Aidan Timson 2a2bca2a61 Handle lazy loaded entity registry when editing scripts from more info (#51438)
* Handle lazy loaded entity registry when editing scripts from more info

* Remove extra check

* Fix type of mixin
2026-04-07 17:07:21 +03:00
Petar PetrovandClaude 1eda51ddbc Allow customizing initial map view with latitude, longitude, and zoom (#51444)
Co-authored-by: Claude <[email protected]>
2026-04-07 15:07:13 +01:00
Wendelin 22738f6d77 Remove fab (#51448)
* Remove ha-fab replace with ha-button

* Remove import of ha-fab component

* Remove mwc-fab
2026-04-07 15:46:36 +03:00
Petar Petrov 2f73351c35 Fix dialog show animation broken by connectedCallback _open sync (#51450) 2026-04-07 12:18:16 +00:00
Petar Petrov 44b442dc0e Fix toast race condition causing stuck notifications (#51447) 2026-04-07 13:13:18 +01:00
Aidan Timson 916731d0ee Restore custom wording for integrations (#51440) 2026-04-07 13:11:28 +01:00
Aidan Timson 5113594d6b Use script field name if available in row instead of key (#51445)
Use script field name if available in row
2026-04-07 14:46:17 +03:00
edd162df68 Use websocket subscription for calendar events (#27906)
* Use websocket subscription for calendar events

Replace polling-based calendar event fetching with real-time websocket subscriptions. This leverages the new subscription API added in core to provide automatic updates when calendar events change, eliminating the need for periodic polling.

The subscription pattern follows the same approach used for todo items, with proper lifecycle management and cleanup.

Related: home-assistant/core#156340
Related: #27565

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>

* Fix calendar events not loading on initial render

Remove premature subscription attempt in setConfig() that was failing because the date range wasn't available yet. The subscription now properly happens when the view-changed event fires from ha-full-calendar after initial render, which includes the necessary start/end dates.

This ensures calendar events load immediately when the component is first displayed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>

* Fix calendar subscription data format mismatch

The websocket subscription returns event data with fields named start and end, but the frontend was expecting dtstart and dtend. This caused events to not display because the data wasn't being properly mapped.

Now properly transform the subscription response format:
- Subscription format: start/end/summary/description
- Internal format: dtstart/dtend/summary/description

This ensures both initial event loading and real-time updates work correctly.

* Address PR review comments

Fixes based on Copilot review feedback:

1. **Fixed race conditions**: Made _unsubscribeAll() async and await it
   before creating new subscriptions to prevent old subscription events
   from updating UI after new subscriptions are created.

2. **Added error handling**: All unsubscribe operations now catch errors
   to handle cases where subscriptions may have already been closed.

3. **Fixed type safety**: Replaced 'any' type with proper
   CalendarEventSubscriptionData type and added interface definition
   for subscription response data structure.

4. **Improved error tracking**: Calendar card now accumulates errors from
   multiple calendars instead of only showing the last error.

5. **Prevented duplicate subscriptions**: Added checks to unsubscribe
   existing subscriptions before creating new ones in both
   _subscribeCalendarEvents and _requestSelected.

6. **Fixed null handling**: Properly convert null values to undefined
   for CalendarEventData fields to match expected types.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>

* Extract event normalization to shared utility function

Reduced code duplication by extracting the calendar event normalization
logic from both hui-calendar-card.ts and ha-panel-calendar.ts into a
shared utility function in calendar.ts.

The normalizeSubscriptionEventData() function handles the conversion
from subscription format (start/end) to internal format (dtstart/dtend)
in a single, reusable location.

This improves maintainability by ensuring consistent event normalization
across all calendar components and reduces the risk of divergence.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>

* Address additional review comments

Fixed remaining issues from code review:

1. **Added @state decorator to _errorCalendars**: Ensures proper reactivity
   in calendar card when errors occur or are cleared, triggering UI updates.

2. **Fixed error accumulation in panel calendar**: Panel now properly
   accumulates errors from multiple calendars similar to the card
   implementation, preventing previously failed calendars from being
   hidden when new errors occur.

3. **Removed duplicate subscription check**: Deleted redundant duplicate
   subscription prevention in _requestSelected() since
   _subscribeCalendarEvents() already handles this at lines 221-227.

Note: The [nitpick] comment about loading states during await is a
performance enhancement suggestion, not a required fix.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>

* Update src/panels/lovelace/cards/hui-calendar-card.ts

Co-authored-by: Copilot <[email protected]>

* Update src/panels/lovelace/cards/hui-calendar-card.ts

Co-authored-by: Copilot <[email protected]>

* Update src/panels/calendar/ha-panel-calendar.ts

Co-authored-by: Copilot <[email protected]>

* Refactor fetchCalendarEvents to use shared normalization utility

Eliminated code duplication by reusing normalizeSubscriptionEventData() in
fetchCalendarEvents(). After extracting date strings from the REST API
response format, we now convert to a subscription-like format and pass
it to the shared utility.

This ensures consistent event normalization across both REST API and
WebSocket subscription code paths, reducing maintenance burden and
potential for divergence.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>

* Move date normalization into normalizeSubscriptionEventData

The getCalendarDate helper is part of the normalization process and should be inside the normalization function. This makes normalizeSubscriptionEventData handle both REST API format (with dateTime/date objects) and subscription format (plain strings).

Changes:
- Moved getCalendarDate into normalizeSubscriptionEventData
- Updated CalendarEventSubscriptionData to accept string | any for start/end
- Made normalizeSubscriptionEventData return CalendarEvent | null for invalid dates
- Simplified fetchCalendarEvents to use the shared normalization
- Added null filtering in calendar card and panel event handlers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>

* Replace any types with proper TypeScript types

Added proper types for calendar event data:
- CalendarDateValue: Union type for date values (string | {dateTime} | {date})
- CalendarEventRestData: Interface for REST API event responses
- Updated fetchCalendarEvents to use CalendarEventRestData[]
- Updated CalendarEventSubscriptionData to use CalendarDateValue
- Updated getCalendarDate to use proper type guards with 'in' operator

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>

* Unify CalendarEventRestData and CalendarEventSubscriptionData

Both interfaces had identical structures, so unified them into a single
CalendarEventSubscriptionData interface that is used for both REST API
responses and WebSocket subscription data.

Changes:
- Removed CalendarEventRestData interface
- Updated fetchCalendarEvents to use CalendarEventSubscriptionData
- Added documentation clarifying the interface is used for both APIs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>

* PR comments

* fix import

* fix import

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Copilot <[email protected]>
2026-04-07 13:18:53 +02:00
Aidan Timson 6278d9be2f Focus scrollable content on load for data tables (#51372)
* Focus scrollable content on load for data tables

* Improve typing

* Replace any types

* Refocus on heading click

* Remove

* Focus on checkbox enable/disable

* Cleanup

* Remove unneeded track autofocus

* Reduce guard need

* Remove

* Merge
2026-04-07 13:51:16 +03:00
Petar Petrov ba2fef50d0 Preserve browser back/forward keyboard shortcuts in tab group (#51439) 2026-04-07 11:07:34 +01:00
ildar170975andPetar Petrov a9774e74cf Map card editor: add UI for conditions (#30247)
* add conditions to MapCardConfig

* add conditions to Map card editor

* support no_entity state/numeric_state conditions

* support no_entity state/numeric_state conditions

* support no_entity state/numeric_state conditions

* support no_entity state/numeric_state conditions

* Create ha-card-condition-numeric_state-no_entity.ts

* support no_entity state/numeric_state conditions

* support no_entity state/numeric_state conditions

* Create ha-card-condition-state-no_entity.ts

* support no_entity state/numeric_state conditions

* add UI for conditions

* remove comments

* linter

* resolving conflicts

* add no_entity property

* fix no_entity property

* Update ha-card-condition-or.ts

* Update ha-card-condition-state.ts

* Update ha-card-condition-and.ts

* Update ha-card-condition-not.ts

* Update ha-card-condition-editor.ts

* Update ha-card-conditions-editor.ts

* Update hui-map-card-editor.ts

* Update ha-selector.ts

* Update ha-selector-state.ts

* Create ha-selector-state-no_entity.ts

* linter

* Delete src/components/ha-selector/ha-selector-state-no_entity.ts

* revert

* Update ha-selector-state.ts

* Update ha-selector-state.ts

* Update selector.ts

* Update ha-card-condition-state.ts

* prettier

* fix addEntityToCondition

* Update src/translations/en.json

Co-authored-by: Petar Petrov <[email protected]>

* pass no_entity to _schema

* pass no_entity to _schema

* forgot smth

* prettier

* prettier

* prettier

* prettier

* get translated states manually

* Update hui-map-card-editor.ts

* prettier

* add zones

* Update hui-map-card-editor.ts

* add getStatesDomain()

* use getStatesDomain()

* prettier

* prettier

* prettier

* no_entity -> noEntity

* no_entity -> noEntity

* no_entity -> noEntity

* no_entity -> noEntity

* no_entity -> noEntity

* no_entity -> noEntity

* no_entity -> noEntity

* add attribute "no_entity"

* add attribute "no_entity"

* add attribute "no_entity"

* add attribute "no_entity"

* add attribute "no_entity"

* add attribute "no_entity"

* no_entity -> noEntity

* no_entity -> noEntity

* add attribute "no_entity"

* prettier

* add "@state" to _presetStates

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

* format

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-04-07 06:48:00 +00:00
Elias Axonov ae3d6c77ca Fix iOS long-press context menu showing on images (#9549) (#51432) 2026-04-07 08:55:14 +03:00
renovate[bot] 4f3feced1b Update dependency @eslint/eslintrc to v3.3.5 (#51436)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-07 08:53:44 +03:00
renovate[bot] 49dd217935 Update dependency eslint to v10.2.0 (#51437)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-07 08:52:56 +03:00
iluvdata 522cffffa8 fix flowType in showSubConfigFlowDialog in next_flow flows (#51389)
* fix flowType in config subentry flows/next_flow

* suggested changes
2026-04-07 08:34:34 +03:00
Petar Petrov 3124fbe08e Update eslint to v10.1.0 (#51352)
* Update eslint to v10.1.0

Migrate from eslint-plugin-import to eslint-plugin-import-x since the
original plugin uses removed ESLint 10 APIs (context.parserOptions,
context.parserPath). Airbnb-base non-import rules preserved via
FlatCompat with import rules stripped and replaced by import-x.

- eslint 9.39.4 → 10.1.0
- Add eslint-plugin-import-x 4.16.2
- Add @eslint/eslintrc and @eslint/js as explicit deps
- Remove --flag v10_config_lookup_from_file (now default)
- Replace /* eslint-env */ comment with config-based globals
- Update all import/ rule references to import-x/

* Remove unnecessary eslint-disable for generated gallery imports

The import-pages file is generated as .ts, so import-x/extensions
doesn't require an extension (ts: "never" in config).
2026-04-07 08:33:58 +03:00
renovate[bot] c705d4e4a1 Update dependency @types/chromecast-caf-receiver to v6.0.26 (#51431)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-06 20:13:59 +02:00
Alex Brown 446661915b Renamed manage lock added graceful degregation (#51293)
* Cleaned up experience when no pin support is possible to provide better messaging.

* Improvements to messaging depending on lock features

* Added documentation links

* Added prettier format
2026-04-06 16:46:00 +03:00
Brooke HattonandPetar Petrov 6048356e01 Add Maintenance summary card and dashboard (#30372)
* Add a summary for battery status and a battery strategy

* some cleanup around location given its a sub view and naming

* Use the device name rather than entity name

* Refactor into a maintenance panel

* Adjust naming

* rename

* Add maintenance dashboard to built in dashboard list

* use grey for maintenance colour

* Fix typos in maintenance panel

- _searchParms -> _searchParams
- Add Event type to _back parameter
- Fix duplicate closing tag

* Move maintenance strategy to src/panels/maintenance/strategies/

- Move maintenance-view-strategy.ts to maintenance panel directory
- Update import paths in get-strategy.ts, home-summaries.ts, and hui-home-summary-card.ts
- Fix ha-floor-icon import path in maintenance-view-strategy.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-04-06 15:26:29 +03:00
Tom Carpenter c44341331a Add Last 365 Days option to energy date selection (#51426)
* Add Last 365 Days option to energy date selection

There seem to be two use cases for the "Last 12 Months" option - those that expect it to produce whole months (original behaviour up to 2026.1, then again from 2026.4), and those that want an option for the last 365 days,

Given this descrepancy in expected behaviour, add an explicit "Last 365 days" option.

* Use subDays for last 365.
2026-04-06 13:44:51 +03:00
Aidan Timson 2d46304960 Update custom to community for user facing integrations, cards and badges (#51368)
* Update custom to community for user facing integrations, card, badges

* Rename as suggested
2026-04-06 11:57:01 +03:00
Wendelin b5ff6a991d Migrate ha-textarea (#51377)
* Migrate ha-textarea

* Fix autogrow

* fix styles
2026-04-06 11:54:55 +03:00
Aidan Timson 28254ca0f2 Focus scrollable content on load for integrations (#51379) 2026-04-06 11:49:16 +03:00
8605c235ac Add loading state to energy dashboard (#51392)
* Add loading state to energy dashboard

* Add fade-in/-out

* Update src/panels/lovelace/components/hui-energy-period-selector.ts

Co-authored-by: Tom Carpenter <[email protected]>

* Feedback

* Feedback

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Tom Carpenter <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-04-06 06:36:59 +00:00
dependabot[bot] 8325161d39 Bump home-assistant/actions from d56d093b9ab8d2105bc0cb6ee9bcc0ef4ec8b96d to 5752577ea7cc5aefb064b0b21432f18fe4d6ba90 (#51430)
Bump home-assistant/actions

Bumps [home-assistant/actions](https://github.com/home-assistant/actions) from d56d093b9ab8d2105bc0cb6ee9bcc0ef4ec8b96d to 5752577ea7cc5aefb064b0b21432f18fe4d6ba90.
- [Release notes](https://github.com/home-assistant/actions/releases)
- [Commits](https://github.com/home-assistant/actions/compare/d56d093b9ab8d2105bc0cb6ee9bcc0ef4ec8b96d...5752577ea7cc5aefb064b0b21432f18fe4d6ba90)

---
updated-dependencies:
- dependency-name: home-assistant/actions
  dependency-version: 5752577ea7cc5aefb064b0b21432f18fe4d6ba90
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-06 09:32:30 +03:00
Niccolò Betto 90057854c8 Fix code input dialog undefined value concatenation (#51399) 2026-04-06 06:07:23 +00:00
Simon Lamon 04c8c82966 Increase gauge thickness for accessibility reasons (#51382)
Increase thickness for accessability reasons
2026-04-06 08:59:55 +03:00
renovate[bot] 16b3add987 Update dependency eslint-import-resolver-webpack to v0.13.11 (#51424)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-06 08:48:42 +03:00
renovate[bot] f0e171076e Update dependency @swc/helpers to v0.5.21 (#51429)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-06 08:47:31 +03:00
renovate[bot] 48f0b78b95 Update dependency fuse.js to v7.2.0 (#51428)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-06 08:47:09 +03:00
renovate[bot] 32728d91d7 Update dependency barcode-detector to v3.1.2 (#51417)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-04 20:59:00 +02:00
renovate[bot] 0915a3e29c Update dependency @codemirror/view to v6.41.0 (#51416)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-04 20:26:38 +02:00
renovate[bot] 60c5888f6b Update dependency @rsdoctor/rspack-plugin to v1.5.7 (#51398)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-03 18:07:11 +02:00
renovate[bot] fb599b8b16 Update dependency @rspack/core to v1.7.11 (#51397)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-03 13:29:21 +02:00
Bram Kragten cf542197e0 Bumped version to 20260325.6 2026-04-03 13:01:51 +02:00
Bram Kragten 5c2627624a Always add options object to triggers and conditions (#51394) 2026-04-03 13:01:42 +02:00
Petar Petrov 698ded9d85 Only use inflight map for pending fragment translation loads (#51393) 2026-04-03 13:01:42 +02:00
Tim IttermannandBram Kragten 9a7fb96873 fix: null value error on ha-form-integer (#51385)
Co-authored-by: Bram Kragten <[email protected]>
2026-04-03 13:01:41 +02:00
Petar Petrov 204c5b5e14 Fix fragment translation race condition returning stale localize (#51381) 2026-04-03 13:01:40 +02:00
Petar Petrov 8ea3acfa98 Load energy translations in dashboard strategy before generating view titles (#51376) 2026-04-03 13:01:39 +02:00
Wendelin 306739773e Fix login on legacy browsers (#51373) 2026-04-03 13:01:38 +02:00
Petar Petrov 8b3fa3adac Fix next_flow dialog closing immediately after rendering (#51369) 2026-04-03 13:01:37 +02:00
Petar Petrov 37a1d59a24 Fix statistics-graph card not rendering self-imported stats (#51367) 2026-04-03 13:01:37 +02:00
Trevin Chow 6812884e00 Guard against orphaned label references in device list (#51359) 2026-04-03 13:01:36 +02:00
Trevin Chow bf7ef1f7ae Fix TypeError in Voice Assistants expose page with manual entity filters (#51357) 2026-04-03 13:01:35 +02:00
Paul Bottein fe57f601ba Fix device page entity names not refreshing after device rename (#51355) 2026-04-03 13:01:34 +02:00
Wendelin c89d478440 Fix input hint height (#51351) 2026-04-03 13:01:33 +02:00
Petar Petrov fa27d26e5f Fix history-graph card not showing first value (#51350) 2026-04-03 13:01:32 +02:00
Wendelin 18f411ef53 Fix generic picker filter section padding (#51334)
Fix padding in picker section for improved layout
2026-04-03 13:01:31 +02:00
Wendelin 24826e92f0 Fix picker search padding (#51331) 2026-04-03 13:01:30 +02:00
Wendelin ea9d369d88 Fix date input field shrink (#51330) 2026-04-03 13:01:29 +02:00
Bram Kragten b1a390789d Always add options object to triggers and conditions (#51394) 2026-04-03 12:59:58 +02:00
Trevin Chow 76c0dd1f1f Guard against orphaned label references in device list (#51359) 2026-04-03 09:00:05 +00:00
Trevin Chow 96dacfdeca Fix TypeError in Voice Assistants expose page with manual entity filters (#51357) 2026-04-03 10:51:44 +02:00
Petar Petrov 5f28ed35d2 Only use inflight map for pending fragment translation loads (#51393) 2026-04-03 10:39:50 +02:00
Petar Petrov edd7b4c3dc Fix fragment translation race condition returning stale localize (#51381) 2026-04-03 10:21:52 +02:00
Tim IttermannandBram Kragten cbea8bbf44 fix: null value error on ha-form-integer (#51385)
Co-authored-by: Bram Kragten <[email protected]>
2026-04-03 08:19:03 +00:00
Petar Petrov 23a41e4384 Fix next_flow dialog closing immediately after rendering (#51369) 2026-04-03 10:14:21 +02:00
renovate[bot] f747580b43 Update dependency typescript-eslint to v8.58.0 (#51386)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-03 06:56:48 +02:00
Brooke Hatton 98fc69674f Fix typos and syntax errors in ha-panel-climate.ts (#51388)
* Fix typos and syntax errors in ha-panel-climate.ts

- Rename _searchParms to _searchParams (typo fix)
- Fix duplicate closing hui-view-container tag
- Clean up formatting

* Fix duplicate hui-view-container closing tag in light and security panels
2026-04-03 06:56:29 +02:00
renovate[bot] ab1a58b3f3 Update dependency @rsdoctor/rspack-plugin to v1.5.6 (#51375)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-02 16:13:27 +01:00
Petar Petrov a7ff89385e Load energy translations in dashboard strategy before generating view titles (#51376) 2026-04-02 16:10:59 +01:00
Wendelin f3d41be3bf Fix login on legacy browsers (#51373) 2026-04-02 16:08:52 +02:00
Wendelin b73707751a Z-Wave rebuild routes add detail progress (#51361)
* WIP new dialog use states

* WIP add zwave rebuild network routes details

* Enhance Z-Wave JS rebuild network routes dialog with loading indicators and improved progress handling

* Remove hass param from `domain-icon`

* Remove unneeded @states

* List more compact

* fix prettier

* fix tests

* Rename device context to getDeviceArea
2026-04-02 16:51:33 +03:00
Petar Petrov 61bff43cdb Fix statistics-graph card not rendering self-imported stats (#51367) 2026-04-02 11:29:03 +01:00
Aidan Timson 0a0d08fa19 Remove advanced mode requirement reloading config (#51366) 2026-04-02 13:09:57 +03:00
Aidan Timson ae29ba63ff Remove advanced mode for dashboard url path creation (#51364)
Remove advanced mode requirement for dashboard url path creation
2026-04-02 13:08:30 +03:00
Aidan Timson 0579cd8eb6 Remove advanced mode requirement for manage resources link (#51363) 2026-04-02 13:08:07 +03:00
Aidan Timson 8c3eafec6d Remove advanced mode requirement for hardware data table (#51362) 2026-04-02 13:07:37 +03:00
Norbert Rittel b5c2e12016 Rename "Manual event" trigger and action to clarify (#51358) 2026-04-02 12:10:34 +03:00
CopilotandAidan Timson f7a13392cd Rename "Custom cards" to "Community cards" (#51312)
* Initial plan

* Rename custom cards to community cards

Agent-Logs-Url: https://github.com/home-assistant/frontend/sessions/874ac3ba-2f7e-48cd-a0c4-e2dc2b371d8d

* Rename badges

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Aidan Timson <[email protected]>
2026-04-02 10:47:29 +02:00
Paul Bottein a2cdd592f1 Fix device page entity names not refreshing after device rename (#51355) 2026-04-02 09:35:12 +01:00
Wendelin f04341a2a2 Fix input hint height (#51351) 2026-04-02 09:34:19 +01:00
Petar Petrov 91bdc80a67 Fix history-graph card not showing first value (#51350) 2026-04-02 10:13:59 +02:00
renovate[bot]andPetar Petrov b4824cc0a7 Update dependency typescript to v6 (#30363)
* Update dependency typescript to v6

* Fix deprecation

* Fix cast

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <[email protected]>
2026-04-02 08:59:32 +03:00
Paulus SchoutsenandClaude 28f375c0d4 Allow enabling/disabling summaries (#51319)
* Allow customizing home page summaries and adding quick links

Add ability to hide built-in summaries (light, climate, security,
media players, weather, energy) and add custom quick links to
dashboards, sidebar items, or other pages from the edit overview dialog.

https://claude.ai/code/session_01AqgbQULH5vfETibiba5RXH

* Remove quick links, focus on summary enable/disable only

https://claude.ai/code/session_01AqgbQULH5vfETibiba5RXH

* Match summary editor rows to dashboard order with icon, color, and toggle on right

Each summary row now shows its colored icon and title matching the
dashboard appearance, with the toggle switch moved to the right side.
Order matches the dashboard: light, climate, security, media players,
weather, energy, persons.

https://claude.ai/code/session_01AqgbQULH5vfETibiba5RXH

* Lint

* Apply suggestion from @balloob

---------

Co-authored-by: Claude <[email protected]>
2026-04-02 08:42:04 +03:00
Simon Lamon da7ccac811 No longer take the first action when no action is selected (#51341)
No longer take the first action when no action is selected
2026-04-02 08:21:02 +03:00
Aidan Timson a8ad921efd Create shared select card feature base class (#51333)
* Create shared select card feature base class

* Add sound mode and source features

* Remove serviceValueKey as its the same as attribute

* Migrate more

* Migrate select options

* Add fan direction

* Remove default usages
2026-04-01 17:58:11 +03:00
Petar PetrovandClaude 3b8f219800 Add customizable dismiss label to ha-alert component (#51337)
Co-authored-by: Claude <[email protected]>
2026-04-01 15:20:05 +01:00
Paul Bottein e36a2e1c70 Use view columns visibility condition in strategies (#51323) 2026-04-01 15:05:52 +03:00
Wendelin e06ea1047c Fix generic picker filter section padding (#51334)
Fix padding in picker section for improved layout
2026-04-01 15:04:24 +03:00
Petar Petrov 99cb997d08 Use localized string for empty logbook entries in trace view (#51324) 2026-04-01 15:03:42 +03:00
Wendelin ac3edd20f8 Fix picker search padding (#51331) 2026-04-01 09:30:49 +00:00
Wendelin 0d88d139f0 Fix date input field shrink (#51330) 2026-04-01 09:22:37 +00:00
Bram Kragten a9b026d0ef Bumped version to 20260325.5 2026-04-01 11:15:10 +02:00
Petar Petrov 35339906ec Fix layout of compare card in water/gas views (#51329) 2026-04-01 11:14:50 +02:00
Wendelin ce23f716cc Improve dialog open logic (#51328) 2026-04-01 11:14:49 +02:00
Petar Petrov aaf8fa199f Await energy translation fragment before generating dashboard strategy (#51327) 2026-04-01 11:14:48 +02:00
Aidan Timson fba430d507 Fix target item loading error (#51326) 2026-04-01 11:14:47 +02:00
Petar Petrov 59361cbd38 Fix ZHA device count not including devices without entities (#51322) 2026-04-01 11:14:46 +02:00
Petar Petrov b558117d8c Use ha-card-border-color for integration cards instead of divider-color (#51321) 2026-04-01 11:14:45 +02:00
Petar Petrov a7c8347751 Fix Fill example data inserting incorrect datetime format (#51320) 2026-04-01 11:14:44 +02:00
Wendelin 31ca9c849a Remove target description (#51315) 2026-04-01 11:14:43 +02:00
Petar Petrov b8d08ccb05 Use ha-card-border-color for integration cards instead of divider-color (#51321) 2026-04-01 11:13:24 +02:00
Petar Petrov 7c20316ba5 Fix layout of compare card in water/gas views (#51329) 2026-04-01 08:57:25 +00:00
Aidan Timson fa633efc87 Fix target item loading error (#51326) 2026-04-01 10:43:42 +02:00
Petar Petrov 85d461f0fd Await energy translation fragment before generating dashboard strategy (#51327) 2026-04-01 10:41:27 +02:00
Wendelin b55e1c9988 Improve dialog open logic (#51328) 2026-04-01 10:40:40 +02:00
Petar Petrov 1da349a36d Fix ZHA device count not including devices without entities (#51322) 2026-04-01 09:17:39 +01:00
Paul Bottein 74f7139a09 Add view columns visibility condition (#51288)
* Add view columns visibility condition

* Use max column, not column count

* Rename

* Remove editor
2026-04-01 10:11:53 +02:00
Petar Petrov 2911cc77fa Fix Fill example data inserting incorrect datetime format (#51320) 2026-04-01 06:43:09 +00:00
Wendelin ab20383a3a Migrate all from ha-textfield to ha-input (#30349) 2026-04-01 08:37:49 +02:00
karwostsandPetar Petrov 514cb9da9d Add due_date_period to todo UI, create period selector (#51263)
* Add due_date_period to todo UI, create period selector

* updates

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

* ??

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-04-01 09:10:15 +03:00
Wendelin 7c52ac8ca7 Remove target description (#51315) 2026-03-31 17:42:02 +02:00
Aidan TimsonandPetar Petrov 07b4a44228 Fix tile secondary info pop in (#51308)
* Add support for skeleton on tile info secondary text

* Show loading state for users of tile info

* Update src/components/tile/ha-tile-info.ts

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-31 17:38:03 +03:00
Bram Kragten 2b28a6c3f2 Update download-translations.js 2026-03-31 15:50:59 +02:00
Bram Kragten 6252d7e8f5 Bumped version to 20260325.4 2026-03-31 15:36:46 +02:00
Bram Kragten f42986adf6 Make translation downloading async (#51314) 2026-03-31 15:36:31 +02:00
Bram Kragten 84f2e304cf Make translation downloading async (#51314) 2026-03-31 13:35:05 +00:00
Bram Kragten 9e70ea3723 Bumped version to 20260325.3 2026-03-31 14:58:38 +02:00
Bram Kragten de3b7bf513 Fix has target check for actions (#51309) 2026-03-31 14:58:19 +02:00
Petar Petrov 2c5f491c9e Use boundaryFilter data zoom mode only for line charts (#51307) 2026-03-31 14:58:18 +02:00
Wendelin 1ef13c5100 Fix automation add TCA dialog sometimes not opening (#51306) 2026-03-31 14:58:17 +02:00
Aidan Timson c166335aca Fix above/below numeric state entity formatting (#51298) 2026-03-31 14:51:11 +02:00
Petar Petrov c64ec21eca Fix x-axis labels for statistics graph month/year periods (#51295) 2026-03-31 14:51:10 +02:00
Norbert Rittel 8d62056f4a Change picker descriptions of triggers to match new style (#51294) 2026-03-31 14:51:09 +02:00
Bram Kragten 62e73608b6 Triggers/conditions Add usage and grouping to new multi domains (#51287) 2026-03-31 14:51:08 +02:00
Wendelin aa66d8891c Improve date-range-picker mobile presets (#51285) 2026-03-31 14:51:07 +02:00
Paul Bottein 494a96c635 Hide section when all cards are hidden (#51281) 2026-03-31 14:51:06 +02:00
Petar Petrov 36d77f54ce Disable physics by default for large networks (#51277) 2026-03-31 14:51:05 +02:00
Wendelin 12fec9f580 Fix ha-dropdown z-index for legacy browsers (#51276) 2026-03-31 14:51:04 +02:00
Bram Kragten 5f1f55448a Numeric threshold selector: remove duplicate uom from input (#51275) 2026-03-31 14:51:03 +02:00
Paul Bottein 837e345ecf Reduce heading button badge font size and fix alignement (#51274)
Title: Reduce heading button badge font size and fix alignement
2026-03-31 14:51:02 +02:00
Wendelin 0929d7d18a Remove mobile-specific styles for date-range-picker (#51273)
Remove mobile-specific styles for date-picker component
2026-03-31 14:51:01 +02:00
Aidan Timson 70991d3c1e Limit ha-toast width to window, refactor CSS (#51272)
* Limit `ha-toast` width to window and use safe width

* Query assigned slots to stop actions display

* Constrain max-width

* Increase start/end padding
2026-03-31 14:51:00 +02:00
Wendelin 82e5bd62a1 Fix time input background (#51270)
Fix input color tokens
2026-03-31 14:50:59 +02:00
Wendelin b8adf4e866 Fix date-range-picker preset selection (#51269) 2026-03-31 14:50:58 +02:00
Tom Carpenter 111be984e0 Add date range picker time validation (#51267)
* Fix base time inputs reportValidity() function

The queryAll selector returns a NodeList not not an array. Need to spread it to an array before we can use every().

* Validate the date range picker time inputs

Enable auto validation to get the nice red underline on invalid values, and then check validity before accepting the input.

* Fix automatic 24hr value conversion in AM/PM format

When using AM/PM, entering a 24 hour value will automatically convert the first time. For example 15 will become 3. However if you then enter 15 again it will stay as 15 and not update.
To fix this, make sure we trigger an update of the input field once the current update cycle is complete.

* Validate time inputs on save not value update

In the value changed callback, the update 24->12hr input correction will not have been updated and therefore they will report invalid.
2026-03-31 14:50:57 +02:00
Tom Carpenter 78a2cbb532 Fix new date-range-picker rendering on small screens (#51257) 2026-03-31 14:50:56 +02:00
ildar170975 34b09b140b Map card editor: use context in attribute selector (#30393)
use context in attribute selector
2026-03-31 14:50:55 +02:00
Simon LamonandPetar Petrov f173f901c5 Gauge improvements (#30368)
* Gauge last improvements

* Change needle

* Fixup

* Feedback comments

* Update src/components/ha-gauge.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-31 14:50:55 +02:00
Aidan TimsonandPetar Petrov 18cd40ab01 Add select source card feature for supported media players (#51283)
* Add select source card feature for supported media players

* Show label

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

* Use shouldUpdate

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-31 15:44:18 +03:00
Bram Kragten 8e3b1dc6ac Triggers/conditions Add usage and grouping to new multi domains (#51287) 2026-03-31 12:42:15 +00:00
Bram Kragten 5cc223a582 Fix has target check for actions (#51309) 2026-03-31 14:37:46 +02:00
Wendelin 9a62a9217c Fix automation add TCA dialog sometimes not opening (#51306) 2026-03-31 13:36:56 +02:00
Simon LamonandPetar Petrov 70be747e9d Gauge improvements (#30368)
* Gauge last improvements

* Change needle

* Fixup

* Feedback comments

* Update src/components/ha-gauge.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-31 14:27:22 +03:00
Aidan Timson bb57a91494 Add select sound mode card feature for supported media players (#51282)
* Add sound mode card feature for supported media players

* Show label

* Use shouldUpdate
2026-03-31 11:25:00 +00:00
Paul Bottein 7e22e6c0e2 Rename "People at home" summary tile to "Presence" (#51305)
* Rename "People at home" summary tile to "Presence"

* Improve person translation
2026-03-31 13:59:52 +03:00
Wendelin c93f910e56 Fix system hardware caption translation (#51303) 2026-03-31 12:50:17 +02:00
Aidan Timson 8bf4ff5d25 Fix above/below numeric state entity formatting (#51298) 2026-03-31 12:49:37 +02:00
Wendelin debc3adf19 Remove hass property in ha-data-table (#51304) 2026-03-31 12:47:17 +02:00
Petar Petrov ae21017de8 Use boundaryFilter data zoom mode only for line charts (#51307) 2026-03-31 12:44:52 +02:00
Wendelin f15f518cc2 Improve date-range-picker mobile presets (#51285) 2026-03-31 12:39:54 +02:00
Paulus SchoutsenandPetar Petrov 0e44417051 Fix My link for apps (#51258)
* Clean up My link matching

* Fix My link for apps to include repository_url

* Apply suggestion from @MindFreeze

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-31 13:33:23 +03:00
Timothy 3581b43336 Add delay before revoking URL on Android (#51299) 2026-03-31 12:23:00 +02:00
Norbert Rittel 32b9676f97 Change picker descriptions of triggers to match new style (#51294) 2026-03-31 10:06:47 +02:00
Petar Petrov 7876642f35 Fix x-axis labels for statistics graph month/year periods (#51295) 2026-03-31 10:01:52 +02:00
Paul Bottein 0e3bcfad5e Hide section when all cards are hidden (#51281) 2026-03-31 08:38:09 +02:00
cd1c273d5a Add people at home summary tile to home overview dashboard (#30408)
* Add persons summary tile to home overview dashboard

Show how many people are currently home in the Summary section
of the default home dashboard. Only persons with at least one
tracking device are included. The tile only appears when the map
panel is loaded and at least one tracked person entity exists.
Tapping navigates to the map panel. Displays a count of persons
home or "Nobody" when all are away.

Co-authored-by: Copilot <[email protected]>

* Remove persons tile from home overview strategy

* Translation tweak

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Copilot <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-03-31 07:56:44 +03:00
d92ac4b4b7 Add solo-select gesture to chart legend (#30395)
* Add solo-select gesture to chart legend

Ctrl+click (Cmd+click on Mac) or long-press (touch, 500ms) a legend
item to solo-select it:
- Solo-click any item → hide everything else, show only that item
- Solo-click the only visible item → restore all

There is no special "solo mode" — the gesture simply sets which items
are hidden. Normal click/tap continues to toggle individual series,
including after a solo action (e.g. solo a, then click b to add it).

Closes https://github.com/orgs/home-assistant/discussions/1492

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* Deduplicate legend parsing in _renderLegend and _getAllLegendIds

Both methods parsed options.legend and filtered datasets identically.
Extract the shared logic into a new _getLegendItems method.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* Update src/components/chart/ha-chart-base.ts

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-03-30 15:08:16 +00:00
Petar Petrov bfecb1d4a9 Disable physics by default for large networks (#51277) 2026-03-30 14:22:11 +00:00
Wendelin 69a8db00fa Fix ha-dropdown z-index for legacy browsers (#51276) 2026-03-30 13:41:44 +00:00
Maarten Lakerveld bbda7affdc Add ability to duplicate a section (#30265)
* Add ability to duplicate a section

* Move section edit mode buttons to overflow menu

* Fix typing for concat and push parameters

* Fix incorrect clipboard typing for badges
2026-03-30 14:59:27 +02:00
Aidan Timson 10c90d222d Limit ha-toast width to window, refactor CSS (#51272)
* Limit `ha-toast` width to window and use safe width

* Query assigned slots to stop actions display

* Constrain max-width

* Increase start/end padding
2026-03-30 15:31:03 +03:00
Bram Kragten 072f70b49f Numeric threshold selector: remove duplicate uom from input (#51275) 2026-03-30 14:12:04 +02:00
Wendelin 7f2a5ecc27 Remove mobile-specific styles for date-range-picker (#51273)
Remove mobile-specific styles for date-picker component
2026-03-30 13:03:21 +02:00
Paul Bottein a42f6f864a Reduce heading button badge font size and fix alignement (#51274)
Title: Reduce heading button badge font size and fix alignement
2026-03-30 13:02:06 +02:00
Paulus Schoutsen a07772c514 Reload the app info after an update completes (#51261) 2026-03-30 10:42:16 +01:00
Tom Carpenter a6ab6e218f Fix new date-range-picker rendering on small screens (#51257) 2026-03-30 11:10:06 +02:00
ildar170975andWendelin ed96657085 Add getContrastedColorHex() to be used for contrasted text & background (or vice versa) (#29032)
Co-authored-by: Wendelin <[email protected]>
2026-03-30 10:57:28 +02:00
dependabot[bot] 50ca39722e Bump github/codeql-action from 4.34.1 to 4.35.1 (#51268)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-30 08:43:59 +01:00
Wendelin 7026e5b375 Fix date-range-picker preset selection (#51269) 2026-03-30 09:40:40 +02:00
Wendelin 37e8e1b728 Fix time input background (#51270)
Fix input color tokens
2026-03-30 09:39:57 +02:00
Paulus Schoutsen 48369854af link to supervisor logs on app install error (#51259) 2026-03-30 09:00:21 +02:00
Tom Carpenter 7715e01126 Add date range picker time validation (#51267)
* Fix base time inputs reportValidity() function

The queryAll selector returns a NodeList not not an array. Need to spread it to an array before we can use every().

* Validate the date range picker time inputs

Enable auto validation to get the nice red underline on invalid values, and then check validity before accepting the input.

* Fix automatic 24hr value conversion in AM/PM format

When using AM/PM, entering a 24 hour value will automatically convert the first time. For example 15 will become 3. However if you then enter 15 again it will stay as 15 and not update.
To fix this, make sure we trigger an update of the input field once the current update cycle is complete.

* Validate time inputs on save not value update

In the value changed callback, the update 24->12hr input correction will not have been updated and therefore they will report invalid.
2026-03-30 09:13:51 +03:00
renovate[bot] e4ee108e14 Update vitest monorepo to v4.1.2 (#51265)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-29 17:25:23 +00:00
renovate[bot] 407609c118 Update dependency @swc/helpers to v0.5.20 (#51264)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-29 17:25:18 +00:00
dependabot[bot] 68cbaf6481 Bump node-forge from 1.3.3 to 1.4.0 (#30398)
Bumps [node-forge](https://github.com/digitalbazaar/forge) from 1.3.3 to 1.4.0.
- [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/v1.3.3...v1.4.0)

---
updated-dependencies:
- dependency-name: node-forge
  dependency-version: 1.4.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-28 13:26:07 +01:00
renovate[bot] b9b249a317 Update dependency @codemirror/language to v6.12.3 (#30396)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-28 12:04:55 +01:00
Petar Petrov df6578dfdf Refactor climate HVAC mode handling to be data-driven (#30356)
Refactor climate HVAC mode handling in state-history-chart-line to be data-driven

Replace repetitive per-mode detection, dataset creation, and series population
blocks with a single CLIMATE_MODE_CONFIGS array and loops over active modes.
2026-03-28 10:15:45 +01:00
ildar170975 b4a07f504c Map card editor: use context in attribute selector (#30393)
use context in attribute selector
2026-03-28 10:13:44 +01:00
Norbert Rittel 24b8078a9c Clarify multiple choice of Chart types in Device energy graph card (#30389) 2026-03-28 09:31:19 +02:00
Paul Bottein ebb6ac8d8b Bumped version to 20260325.2 2026-03-27 22:09:10 +01:00
Wendelin abe214a33a Fix picker field disabled background (#30385) 2026-03-27 22:08:51 +01:00
Paul Bottein 248332ae27 Revert entity naming change (#30384) 2026-03-27 22:08:50 +01:00
Wendelin 82fc2fccdc Automation add TCA: Fix classMap usage (#30380) 2026-03-27 22:08:49 +01:00
Marcin BauerandWendelin c8f30a7ee4 Use dedicated tab copy in automation add dialogs (#30378)
Co-authored-by: Wendelin <[email protected]>
2026-03-27 22:08:48 +01:00
Norbert Rittel 77f48d91cd Shorten collection_key_description to fit available space (#30376) 2026-03-27 22:08:47 +01:00
Paul Bottein caa707a7b1 Only display entity name instead of friendly name in state info (#30365) 2026-03-27 22:08:46 +01:00
Petar Petrov 0bed0fa37e Fix negative currency display on sensor card (#30359) 2026-03-27 22:08:46 +01:00
Bram Kragten 5b6309d984 Numeric threshold selector fixes (#30350)
* Update numeric threshold

* Update ha-selector-numeric-threshold.ts
2026-03-27 22:08:45 +01:00
Aidan Timson 264818bc70 Fix floating ha-toast (#30344) 2026-03-27 22:08:44 +01:00
Paul Bottein 2bd8a657b8 Revert entity naming change (#30384) 2026-03-27 21:45:54 +01:00
Wendelin 61724a52ba Fix picker field disabled background (#30385) 2026-03-27 16:32:49 +01:00
Aidan Timson 67d73261a4 Fix floating ha-toast (#30344) 2026-03-27 14:06:47 +01:00
Marcin BauerandWendelin 419ba64bed Use dedicated tab copy in automation add dialogs (#30378)
Co-authored-by: Wendelin <[email protected]>
2026-03-27 12:46:11 +00:00
Norbert Rittel e87155bba3 Drop "entities" from "Group by floor / area" in Sankey diagrams (#30382) 2026-03-27 14:16:46 +02:00
Petar Petrov d8a3939e22 Fix negative currency display on sensor card (#30359) 2026-03-27 12:29:58 +01:00
Paul Bottein 5141b6aea9 Revert "Show device name prefix in entity name field" (#30381)
Revert "Show device name prefix in entity name field (#30358)"

This reverts commit e1ac7e98b0.
2026-03-27 12:20:00 +01:00
Wendelin 9aaf1bdd07 Automation add TCA: Fix classMap usage (#30380) 2026-03-27 12:14:51 +01:00
Stefan AgnerandClaude Opus 4.6 a0e7c8e9bb Use goBack with fallback for app uninstall navigation (#30377)
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
2026-03-27 08:31:19 +00:00
Bram Kragten 8f482776b9 Numeric threshold selector fixes (#30350)
* Update numeric threshold

* Update ha-selector-numeric-threshold.ts
2026-03-27 09:50:21 +02:00
Norbert Rittel 2c80183ded Shorten collection_key_description to fit available space (#30376) 2026-03-27 09:41:58 +02:00
Paul Bottein 9bd5e25ee3 Only display entity name instead of friendly name in state info (#30365) 2026-03-27 09:41:11 +02:00
dependabot[bot] 994193465f Bump picomatch from 2.3.1 to 2.3.2 (#30375)
Bumps [picomatch](https://github.com/micromatch/picomatch) from 2.3.1 to 2.3.2.
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2)

---
updated-dependencies:
- dependency-name: picomatch
  dependency-version: 2.3.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-27 08:37:15 +02:00
renovate[bot] 530b7ed457 Update dependency @rspack/core to v1.7.10 (#30374)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-27 08:17:55 +02:00
renovate[bot] 24332e8288 Update vitest monorepo to v4.1.1 (#30357)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-27 08:17:23 +02:00
renovate[bot] 980aaa2bac Update dependency typescript-eslint to v8.57.2 (#30367)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-27 08:16:47 +02:00
renovate[bot] 344856cbc4 Update dependency tar to v7.5.13 (#30371)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-27 08:16:19 +02:00
Bram Kragten 06877cbaaa Replace softprops/action-gh-release with gh release upload (#30362)
`replace softprops/action-gh-release` with `gh release upload`
2026-03-26 17:39:38 +01:00
Paul Bottein e1ac7e98b0 Show device name prefix in entity name field (#30358) 2026-03-26 17:13:24 +01:00
Bram Kragten d664ab6836 Bumped version to 20260325.1 2026-03-26 17:08:11 +01:00
Bram Kragten a6c4184054 Replace ua-parser-js with simple regexs (#30355) 2026-03-26 17:07:45 +01:00
karwosts cb6985eb7c Stabilize map colors (#30354) 2026-03-26 17:07:44 +01:00
Bram Kragten d466ab63bd Add target error badge if target is missing (#30352)
* Add target error badge if target is missing

* Don't show for newly added items
2026-03-26 17:07:40 +01:00
Paul Bottein 1132cdb364 Replace computeLovelaceEntityName with hass.formatEntityName (#30351) 2026-03-26 17:07:39 +01:00
Paul Bottein 0f9d48a03d Use hardcoded label for temperature and humidity sensor in climate dashboard (#30348)
* Only use entity name for climate view sensors

* Use hardcoded text
2026-03-26 17:07:38 +01:00
Paul Bottein 7e085d9b08 Fix stack card scrollbar clipping box-shadows (#30346)
* Fix stack card scrollbar clipping box-shadows

* Remove grid options

* Remove scrollbar
2026-03-26 17:07:37 +01:00
Timothy 1a62c7296c Set tap highlight color to transparent for button (#30340) 2026-03-26 17:07:36 +01:00
Petar Petrov be1921229c Fix energy pie chart legend showing raw data instead of formatted values (#30339) 2026-03-26 17:07:34 +01:00
Paul Bottein 640558ad35 Add composed/text mode toggle to entity name picker (#30337) 2026-03-26 17:07:33 +01:00
sir-Unknown 99636c9719 Fix calendar event description not preserving line breaks (#30329)
Add `white-space: pre-line` to the event description style so that
newlines in the calendar event description are rendered correctly
instead of being collapsed into a single line.
2026-03-26 17:07:32 +01:00
Paul Bottein 4b2426ab77 Add composed/text mode toggle to entity name picker (#30337) 2026-03-26 17:05:05 +01:00
Paul Bottein f9471d6b4c Replace computeLovelaceEntityName with hass.formatEntityName (#30351) 2026-03-26 17:01:26 +01:00
Bram Kragten 0645484258 Tighten action permissions (#30361) 2026-03-26 16:45:34 +01:00
Bram Kragten 2da3efb812 Add target error badge if target is missing (#30352)
* Add target error badge if target is missing

* Don't show for newly added items
2026-03-26 16:58:22 +02:00
Bram Kragten e3674e550f Replace ua-parser-js with simple regexs (#30355) 2026-03-26 14:48:05 +00:00
karwosts cff038fea4 Stabilize map colors (#30354) 2026-03-26 14:47:57 +00:00
Paulus Schoutsen bed39fd8e9 Hide features layout option until feature added (#30353) 2026-03-26 14:39:00 +00:00
arcsur b8346d0286 Support additional climate hvac_mode in state-history-chart-line (#30310)
* Support additional climate hvac_mode in state-history-chart-line

* Reverted changes to the chart legend to keep change focussed on the additonal hvac_mode support

* Remove the tests since they don't add value.
2026-03-26 14:36:08 +00:00
Petar Petrov 5f80b74322 Fix energy pie chart legend showing raw data instead of formatted values (#30339) 2026-03-26 16:29:16 +02:00
Paul Bottein 73e0f1e18d Use hardcoded label for temperature and humidity sensor in climate dashboard (#30348)
* Only use entity name for climate view sensors

* Use hardcoded text
2026-03-26 15:06:25 +01:00
Paul Bottein 0b16b735e8 Fix stack card scrollbar clipping box-shadows (#30346)
* Fix stack card scrollbar clipping box-shadows

* Remove grid options

* Remove scrollbar
2026-03-26 13:16:57 +01:00
Darren Griffin c88dcf10b9 Update Figma DesignKit link (#30342) 2026-03-26 09:47:31 +00:00
Timothy 08bc23e2e7 Set tap highlight color to transparent for button (#30340) 2026-03-26 08:55:27 +00:00
pefia 97d49f06b1 Fix number formatting fallback when Number.isNaN is unavailable (#30306)
Remove unnecessary Number.isNaN polyfill from number formatting
2026-03-26 10:33:29 +02:00
WendelinandPaul Bottein 50b727393d Add all hardware table (#30312)
* add all hardware table

* copilot review

* Updated tab names

* update localize keys

* Fix translations

---------

Co-authored-by: Paul Bottein <[email protected]>
2026-03-26 09:10:09 +02:00
sir-Unknown 5c6dd2a697 Fix calendar event description not preserving line breaks (#30329)
Add `white-space: pre-line` to the event description style so that
newlines in the calendar event description are rendered correctly
instead of being collapsed into a single line.
2026-03-26 07:01:02 +01:00
Bram Kragten 87758cc228 Merge branch 'rc' into dev 2026-03-25 16:52:28 +01:00
Bram Kragten 60e8b8b505 Bumped version to 20260325.0 2026-03-25 16:51:43 +01:00
Aidan Timson 3c012c30ac Migrate ha-toast to wa-popup instead of wa-popover (#30327) 2026-03-25 16:51:09 +01:00
Paul Bottein 84d234a330 Add support for climate swing horizontal mode in get_states (#30326) 2026-03-25 16:04:49 +01:00
WendelinandPetar Petrov a12543fe74 Add ha-input-docs (#30315)
Co-authored-by: Petar Petrov <[email protected]>
2026-03-25 15:46:28 +01:00
karwosts cc53f977a2 Fix trend and sensor graph when no history (#30323) 2026-03-25 15:37:28 +01:00
Paul Bottein 71541625d7 Add support for infrared domain (#30321) 2026-03-25 13:43:50 +00:00
Norbert Rittel 43da700ccc Clarify "wait_for_triggers" summary to reflect the OR condition (#30320) 2026-03-25 13:41:23 +00:00
Wendelin efbbdbf3e8 Replace search-input-outlined with ha-input-search (#30319) 2026-03-25 14:33:55 +01:00
Bram Kragten eee6f79639 Add mode option to numeric threshold selector (#30311) 2026-03-25 14:04:21 +01:00
Wendelin 9381bbd656 ha-input outlined appearance (#30231)
* refactor: replace search-input-outlined with ha-input-search component across multiple files

* review

* Migrate search-input

* refactor: remove deprecated search-input component

* More outlined search fields

* Review
2026-03-25 11:01:14 +01:00
pefia 2724087290 Fix cast manager listener unsubscribe behavior (#30307) 2026-03-25 10:49:09 +01:00
Wendelin 6bdf1ccd8c Migrate ha-textfields to ha-input in 24 files (#30298)
* migrate ha-textfields to ha-input in 24 files

* Fix import path for ha-input and update attribute syntax in entity-preview-row
2026-03-25 10:28:10 +01:00
Abílio CostaandPetar Petrov 79743c0afa Add search to network visualization graphs (#29908)
* Add search highlight to ZHA graph

* Move logic upstream and extend search to zwave and bluetooth

* Move search down to avoid collisions with graph legend

* Fix mobile; simplify code

* Apply highlights directly on search callback

* Revert "Move search down to avoid collisions with graph legend"

This reverts commit 4578aec9c3.

* Move legend down

* Make search bar shrink to avoid overlapping buttons

* Move search bar to topbar on mobile

* Fix inset

* Fix small controlls position

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-25 09:16:26 +00:00
Paul Bottein 15b1df5a58 Add light toggle button to home area view (#30301) 2026-03-25 09:53:20 +01:00
Paul Bottein 8222d9796c Show related entities warning when deleting helpers (#30302) 2026-03-25 09:52:19 +01:00
Wendelin 3337b414d7 Fix copy button in dev tools (#30313)
Fix copy dev tools entity id
2026-03-25 09:48:58 +01:00
Alex Gustafsson ce90d83c92 ZHA group settings UI improvements, localization (#30251)
* Add device area column to ZHA data table

Add a device area column to the ZHA data table, which most notably adds
the column to the "create [ZigBee] group" view".

The column is only show on wider screens to allow for ordering, whilst
narrower screens will show the area as a subtitle to the device's name.

* Localize the ZHA group data table

* fixup! Add device area column to ZHA data table

* fixup! Localize the ZHA group data table
2026-03-25 09:03:45 +02:00
1f6d0d2e63 Add a period option to todo-list-card (#30151)
* Added a todo-list card option "days_to_show" to filter tasks far in the future (#24020)

* Adjusted min and 0 values as suggested in PR

* Adjusted as suggested in review

* Switched from days_to_show to period (calendar only for now) as suggested

* removed days_to_show from editor UI

* fixed lint error

* Fixed code style with prettier

* fix filtering

* Update filtering period options

* Update src/panels/lovelace/editor/config-elements/hui-todo-list-editor.ts

Co-authored-by: Petar Petrov <[email protected]>

* Apply suggestion from @MindFreeze

Co-authored-by: Petar Petrov <[email protected]>

* prettier/lint

* fix memoization, items without status

* no rolling window

* refresh on date change

* Show dialog on create when using due_date filter

---------

Co-authored-by: cpetry <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-03-25 08:45:10 +02:00
karwosts 0327b02d0b Fix clearing device class in entity registry (#30303) 2026-03-25 08:21:48 +02:00
renovate[bot] 780db9b066 Update Node.js to v24.14.1 (#30309)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-25 08:19:06 +02:00
Paul BotteinandClaude Sonnet 4.6 89755f274d Refactor lovelace view lifecycle to avoid unnecessary DOM rebuilds (#30101)
* Refactor lovelace view lifecycle to avoid unnecessary DOM rebuilds

- Remove `force` flag from `hui-root` that was clearing the entire view
  cache and destroying all cached view DOM on any config change. Views
  now receive updated lovelace in place and handle config changes
  internally.
- Add `_cleanupViewCache` to remove stale cache entries when views are
  added, removed, or reordered.
- Remove `@ll-rebuild` handler from `hui-root`. Cards and badges already
  handle `ll-rebuild` via their `hui-card`/`hui-badge` wrappers. Sections
  now always stop propagation and rebuild locally.
- Add `deepEqual` guard in `hui-view._setConfig` and
  `hui-section._initializeConfig` to skip re-rendering when strategy
  regeneration produces an identical config.
- Simplify `hui-view` refresh flow: remove `_refreshConfig`,
  `_rendered` flag, `strategy-config-changed` event, and
  connected/disconnected callbacks. Registry changes now debounce
  directly into `_initializeConfig`.
- Fix `isStrategy` check in `hui-view._initializeConfig` to use the raw
  config (before strategy expansion) rather than the generated config.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Remove unused type

* Improve viewCache cleanup

* clean up

* Handle custom view re-creation

* Fix custom view loading

---------

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
2026-03-24 17:41:30 +01:00
Wendelin 6ea15f507a Fix possible undefined errors in transformer functions (#30299) 2026-03-24 17:37:24 +01:00
Wendelin c506fa8990 Remove unused ha-textfields (#30296) 2026-03-24 15:45:47 +01:00
Paul BotteinandPetar Petrov 9470863808 Improve sections view spacing and heading card grid options (#30295)
* Improve sections view spacing and heading card grid options

* Remove extra margin in heading section

* Update src/panels/lovelace/views/hui-sections-view.ts

Good catch !

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-24 15:26:05 +02:00
WendelinandPetar Petrov 4bdac1f385 Migrate form/selector components ha-textfield to ha-input (#30294)
* Migrate ha-textfield to ha-input across form components and update related logic

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-24 13:18:09 +00:00
Aidan Timson 5bbfa36228 Support more-info-view query param (#30282)
* Support more-info-view query param

* Remove unintended subview logic and add details view

* Reset childView
2026-03-24 11:26:08 +02:00
Bram Kragten a8070b322c Add numeric threshold selector (#30284)
* wip

* add numeric threshold selector

* clean up

* review optimize
2026-03-24 10:59:07 +02:00
Jan-Philipp Benecke 9cbc44123e Enhance delete entity confirmation dialog with detailed information (#30293) 2026-03-24 09:43:46 +01:00
WendelinandPetar Petrov c8f4c892f9 Migrate ha-multi-textfield, ha-selector-text to ha-input and update to use new input components (#30280)
* Migrate ha-multi-textfield to ha-input-multi and update ha-selector-text to use new input components

* Review

* Update src/components/input/ha-input-multi.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-24 07:04:39 +00:00
Simon LamonandPetar Petrov 40b9f9dccb Gauge card improvements (#30149)
* Gauge card improvements

* Decrease stroke width

* Feedback

* Remove show more, move text to bottom

* Remove _handleMoreInfo method from hui-gauge-card

Removed the _handleMoreInfo method from hui-gauge-card.

* Remove unused fireEvent import from hui-gauge-card

Removed unused import for fireEvent.

* Fix up padding

* Better alignment from previous card

* Decrease padding

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-24 06:56:29 +00:00
Aidan Timson 823c222a55 Fix app info descriptions and metrics (#30287)
* Improve app info descriptions

* Space tokens on rest of files

* Don't display empty value
2026-03-23 18:36:29 +01:00
Paul Bottein 02acd2996c Allow boolean option to section background (#30289) 2026-03-23 18:32:53 +01:00
renovate[bot]andSimon Lamon c462fc0639 Update formatjs monorepo (#30256)
* Update formatjs monorepo

* Fixup convert locale script

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Simon Lamon <[email protected]>
2026-03-23 17:46:08 +01:00
renovate[bot] 903553dab9 Update dependency marked to v17.0.5 (#30286)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-23 16:12:59 +00:00
Paul Bottein 25a1c14523 Refactor light color favorites card feature and button (#30281) 2026-03-23 16:29:48 +01:00
karwosts f03eee6cb2 Fix select-entity-row timeout (#30249)
* Fix select-entity-row timeout

* fix possible undefined exception
2026-03-23 16:07:50 +02:00
Bram Kragten a2a38e1da7 Bumped version to 20260312.1 2026-03-23 12:40:43 +01:00
Petar Petrov 88c063ba2a Fix hasReturnToGrid only checking first grid source in energy distribution card (#30273) 2026-03-23 12:39:36 +01:00
Tom Carpenter 984b50bac7 Fix water/gas total badge unit when sensor value is zero (#30279)
Fix water/gas badge when rate is 0

If there is only one flow rate sensor, and it has a value <=0, the badge would be displayed without a unit because the sensor gets skipped.

Instead of skipping <=0 values, continue to process sensor, but clamp the value to a minimum of 0. This ensures for single sensors we have a unit, and for multiple sensors the chosen unit is consistent even if the first sensor value drops to zero.
2026-03-23 13:36:15 +02:00
Wendelin 09e4355451 Migrate copy-textfield to input-copy (#30276) 2026-03-23 10:59:52 +00:00
Petar Petrov 7ee76538ae Fix trace tree left side unreachable on mobile (#30277) 2026-03-23 09:53:33 +00:00
Tom CarpenterandPetar Petrov eb8b2a9d17 Skip plotting state value on statistic graph if units mismatch (#30214)
* Use isExternalStatistic helper for consistency

* Remove redundant if condition

We have `band  = drawBands && ...`, so there is no point checking if `drawBands` is true inside `if (band && ...)`.

* Skip plotting state value on statistic graph if units mismatch

For example plotting a *F sensor on a *C chart - statistic data will be converted to *C, but the state value will still be in *F so the displayed point is wrong. Similarly if plotting a kW sensor on a W chart, the same is true - statistics get converted to W by recorder, but the state value would still be in kW. In other words the plotted state point is complete nonsense.

If the units of the statistic state don't match the units of the graph, we should not be displaying the value on the graph.

* Remove redundant this.unit check

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-23 10:07:15 +01:00
Wendelin 10e8c2a148 Fix copy-to-clipboard in unsecure context (#30204) 2026-03-23 10:07:15 +01:00
Qusai Ismael e1a8616ab0 Fix missing conversation language picker in new pipeline dialog (#30194) 2026-03-23 10:07:14 +01:00
karwosts ccdd71dd64 Fix tag dialog (#30191) 2026-03-23 10:07:13 +01:00
Petar Petrov d3e1d55686 Fix negative monetary values displayed as positive (#30178) 2026-03-23 10:07:12 +01:00
Tom Carpenter 4f916abcbf Remove duplicate final point in bar statistics-chart (#30175)
For bar charts, we don't need to close out the final segment. All this does is produce a duplicate final bar.
2026-03-23 10:07:11 +01:00
Joakim Sørensen 4548f9daae Fix passing click handler to ha-switch in cloudhooks section (#30166)
Fix passing clickhandler to ha-switch in cloudhooks section
2026-03-23 10:07:10 +01:00
Aidan Timson 4020bcec42 Fix event entity row propagation (#30163)
* Stop event entity row value propagation

* Catch interaction
2026-03-23 10:07:09 +01:00
Joakim Sørensen 22c0035e60 Fix formatting of ha-switch in cloud remote preferences panel (#30143) 2026-03-23 10:07:08 +01:00
Petar Petrov 6b6ad8dd2c Preserve entity unit in gas and water flow rate badges (#30116)
* Preserve entity unit_of_measurement in gas and water flow rate badges

The gas and water total badges on the energy dashboard Now tab previously
converted all flow rate values to L/min and then formatted them as either
L/min or gal/min based on the unit system. This meant entities reporting
in m³/h or other units always displayed incorrectly.

Now the badges preserve the unit_of_measurement from the entities. If all
entities share the same unit, the raw values are summed directly. If they
differ, values are converted through L/min as an intermediate and displayed
in the first entity's unit.

* Extract shared computeTotalFlowRate to energy.ts
2026-03-23 10:07:07 +01:00
Maarten Lakerveld 3bbc3403d6 Validate external and internal URL on network tab (#30267) 2026-03-23 09:01:05 +00:00
Petar Petrov 9979bb13ea Fix hasReturnToGrid only checking first grid source in energy distribution card (#30273) 2026-03-23 08:55:22 +00:00
renovate[bot] 8ac831679d Update dependency @rsdoctor/rspack-plugin to v1.5.5 (#30275)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-23 08:46:07 +00:00
karwosts db05b07997 Use form instead of schema for element-sub-editor (#30210)
* Use form instead of schema for element-sub-editor

* fix after merge dev
2026-03-23 10:28:07 +02:00
Tom Carpenter dba8cefa67 Fix statistics graph card units when using energy collections. (#30263)
* Use same now() time for all entity state values

Otherwise if there is a slight time lag while each statistic is processed, some of the points go missing from the tooltip. There end up being to very closely spaced time points for each different entity.

* Fix initial statistics graph card metadata loading

When using energy collection mode, the metadata for statistic entities was not always being loaded when the charts were first created. This could be seen in the graph units when they had differing unit (e.g. kW and W mixed).
2026-03-23 10:22:23 +02:00
Maarten Lakerveld 6935c55c3c Fix validation hint styling for ha-input (#30266) 2026-03-23 06:52:59 +00:00
renovate[bot] 635a1185a3 Update Yarn to v4.13.0 (#30258)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-23 07:16:43 +01:00
renovate[bot] 585c894c5a Update dependency tar to v7.5.12 (#30269)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-23 07:16:04 +01:00
renovate[bot] f9d052a818 Update dependency jsdom to v29.0.1 (#30268)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-23 07:15:49 +01:00
dependabot[bot] a29132441d Bump release-drafter/release-drafter from 7.0.0 to 7.1.1 (#30270)
Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 7.0.0 to 7.1.1.
- [Release notes](https://github.com/release-drafter/release-drafter/releases)
- [Commits](https://github.com/release-drafter/release-drafter/compare/3a7fb5c85b80b1dda66e1ccb94009adbbd32fce3...139054aeaa9adc52ab36ddf67437541f039b88e2)

---
updated-dependencies:
- dependency-name: release-drafter/release-drafter
  dependency-version: 7.1.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-23 07:15:32 +01:00
dependabot[bot] 479d52bf1d Bump actions/cache from 5.0.3 to 5.0.4 (#30271)
Bumps [actions/cache](https://github.com/actions/cache) from 5.0.3 to 5.0.4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/cdf6c1fa76f9f475f3d7449005a359c84ca0f306...668228422ae6a00e4ad889ee87cd7109ec5666a7)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 5.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-23 07:15:19 +01:00
dependabot[bot] d96d78d6f6 Bump github/codeql-action from 4.32.6 to 4.34.1 (#30272)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.32.6 to 4.34.1.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/0d579ffd059c29b07949a3cce3983f0780820c98...38697555549f1db7851b81482ff19f1fa5c4fedc)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.34.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-23 07:15:00 +01:00
Timothy f80cba341f Add new configuration for current assist current device external link (#29979)
* Add new configuration for current assist current device external link

* Adjust CSS

* Adjust naming
2026-03-22 10:47:05 +01:00
Petar Petrov 77ee966442 Propagate schema changes to existing form editor element (#30200)
* Re-create form editor when schema changes in hui-form-element-editor

When a parent component passes a new schema to hui-form-element-editor
(e.g. with updated disabled flags after an entity change), the internal
hui-form-editor was not rebuilt because loadConfigElement() short-circuits
once the config element exists. This meant dynamic schema changes were
silently ignored.

Override updated() to detect schema changes after initial load, tear down
the stale config element via unloadConfigElement(), and re-set the value
so the normal load path recreates the form with the current schema.

Fixes #29776

* Fix prettier formatting in hui-map-card.ts

Pre-existing formatting issue on dev branch.

* Propagate schema changes to existing form editor element

When the schema property on hui-form-element-editor changes (e.g. because
the selected entity changed and disabled flags need updating), directly
update the schema on the already-created hui-form-editor config element.

Previously, unloadConfigElement() was tried but caused a visible flash
(editor going blank then reappearing), and re-setting value with a spread
object was tried but deepEqual considers it unchanged, short-circuiting
the reload.

The fix is minimal: make _configElement protected in HuiElementEditor so
the subclass can reach it, then in the updated() hook push the new schema
directly onto the existing element — no teardown, no re-creation.
2026-03-22 10:40:31 +01:00
Niklas Wagner 2fec5a497e Add translation support for nested app configuration schemas (#30121) 2026-03-22 10:38:36 +01:00
Sergio ed75d96d3c Clarify Matter iOS version requirement in add-device fallback (#30129)
Improve Matter add-device guidance for older iOS devices
2026-03-22 10:23:02 +01:00
balloob-travelandPaulus Schoutsen 0fac47992b Update cloud promo styling in network settings (#30246)
Update cloud promo styling

Co-authored-by: Paulus Schoutsen <[email protected]>
2026-03-22 08:17:09 +00:00
Wendelin 91a608c4c5 fix ha-input styles (#30225) 2026-03-22 09:13:59 +01:00
renovate[bot] df61953ed4 Update dependency @rspack/core to v1.7.9 (#30243)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-20 20:56:13 +01:00
dependabot[bot] 2cda46b4bb Bump flatted from 3.3.3 to 3.4.1 (#30241)
Bumps [flatted](https://github.com/WebReflection/flatted) from 3.3.3 to 3.4.1.
- [Commits](https://github.com/WebReflection/flatted/compare/v3.3.3...v3.4.1)

---
updated-dependencies:
- dependency-name: flatted
  dependency-version: 3.4.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-20 07:51:41 +02:00
renovate[bot] 037190a393 Update babel monorepo to v7.29.2 (#30238)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-20 06:42:56 +01:00
renovate[bot] ebe0154e32 Update dependency typescript-eslint to v8.57.1 (#30235)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-20 06:42:37 +01:00
renovate[bot] efa73067f6 Update dependency core-js to v3.49.0 (#30236)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-20 06:42:20 +01:00
renovate[bot] fdb40c9d01 Update dependency @babel/helper-define-polyfill-provider to v0.6.8 (#30239)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-20 06:42:06 +01:00
Paul Bottein 5a7ddb4972 Add background color option to dashboard sections (#30228) 2026-03-19 16:55:21 +01:00
Aidan Timson dbe46d3b3f Remove advanced mode usages for apps area (#30232) 2026-03-19 16:31:04 +01:00
Petar Petrov eb43d85439 Convert energy panel to use a dashboard strategy (#30170)
* Convert energy panel to use a dashboard strategy

Move the view-selection logic from ha-panel-energy into a dedicated
energy dashboard strategy, consistent with how home/areas/map dashboards
work. The strategy decides which view strategies (electricity, gas,
water, power, overview) to show based on energy preferences.

Extract shared constants into a separate module to avoid circular
dependencies between the panel and view strategies.

* Remove unused energy collection constants from ha-panel-energy
2026-03-19 16:16:56 +01:00
Aidan Timson 1bbfb79ddb Sort disabled and ignored integrations by name, translate disabled domains (#30230)
* Sort Disabled and Ignored integrations by name

* Localise disabled integration domains
2026-03-19 17:03:30 +02:00
Wendelin cf50db350f Temporarily disable "focus_element" implementation for iOS app (#30226) 2026-03-19 13:51:37 +00:00
Wendelin e04a0ec7dc Prevent time-input to close dialogs, popups and bottom-sheets (#30227) 2026-03-19 13:47:06 +00:00
renovate[bot] e08576a6dc Update dependency sinon to v21.0.3 (#30224)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-19 13:40:50 +00:00
Petar Petrov a7831f86ee Use --ha-box-shadow-l for footer (#30221) 2026-03-19 13:01:23 +01:00
Petar Petrov c66e5b379b Show current entity value in history chart legend (#30222) 2026-03-19 11:16:47 +00:00
Aidan Timson e819c30151 Hide behavior selector if no targets are populated (#30219) 2026-03-19 11:48:18 +01:00
Wendelin e278e33375 date-range-picker with cally (#30193)
* date-range-picker with cally

* fix timePicker

* Review: backdrop transition

* fix comments

* Add formatCallyDateRange

* Refactor date formatting in date range picker and remove unused styles

* time-input without label

* review
2026-03-19 10:30:15 +00:00
renovate[bot] 8313be8e7e Update dependency @rsdoctor/rspack-plugin to v1.5.4 (#30220)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-19 11:44:40 +02:00
Tom CarpenterandPetar Petrov 6d95a59ca0 Skip plotting state value on statistic graph if units mismatch (#30214)
* Use isExternalStatistic helper for consistency

* Remove redundant if condition

We have `band  = drawBands && ...`, so there is no point checking if `drawBands` is true inside `if (band && ...)`.

* Skip plotting state value on statistic graph if units mismatch

For example plotting a *F sensor on a *C chart - statistic data will be converted to *C, but the state value will still be in *F so the displayed point is wrong. Similarly if plotting a kW sensor on a W chart, the same is true - statistics get converted to W by recorder, but the state value would still be in kW. In other words the plotted state point is complete nonsense.

If the units of the statistic state don't match the units of the graph, we should not be displaying the value on the graph.

* Remove redundant this.unit check

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-19 11:33:51 +02:00
Paul BotteinandClaude Opus 4.6 a498ad3d06 Refactor device entities card to use Lit directive (#30138)
* Refactor device entities card to use Lit directive for entity rows

Replace the imperative pattern (shouldUpdate hack, _entityRows array,
_renderEntity pushing elements) with a declarative approach using a
reusable Lit directive and repeat for stable keying.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* Fix function name and padding issue

* Recreate on domain change, otherwise update

* Prettier

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
2026-03-19 09:23:02 +02:00
renovate[bot] c4a2229baa Update formatjs monorepo (#30215)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-19 08:20:34 +02:00
15245af52d Markdown card: add support of actions (#28951)
* add actions

* add actions

* add actions to MarkdownCardConfig

* add "actions_warning" for Markdown

* Add a "warning" label

* process a default handler if none action is defined

* check for config=undefined

* fix attributes

* prettier

* Update src/translations/en.json

Co-authored-by: Norbert Rittel <[email protected]>

* add ripple

* Fix interactive and add missing import for ripple

* Fix translation

---------

Co-authored-by: Norbert Rittel <[email protected]>
Co-authored-by: Paul Bottein <[email protected]>
2026-03-18 17:22:28 +00:00
Wendelin c697735e46 Thread dashboard - replace fab with card (#30212)
Add UI to import Thread credentials
2026-03-18 17:47:39 +02:00
Paul BotteinandPetar Petrov ddec792ae3 Add entity name alias toggle and drag-to-reorder aliases in voice settings (#30201)
* Add entity name alias toggle and drag-to-reorder aliases in voice settings

* Fix reorder

* Update src/panels/config/voice-assistants/entity-voice-settings.ts

Co-authored-by: Petar Petrov <[email protected]>

* Use map instead of repeat

* Improve key

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-18 17:42:54 +02:00
Aidan Timson cfd0e72609 Fix disabled entity ID in helper settings (#30213) 2026-03-18 15:42:19 +00:00
Aidan Timson 8a5bcd67ab Hide behavior selector for single target in triggers and conditions (labs) (#30145) 2026-03-18 16:26:34 +01:00
Paul Bottein a794a80228 Add scrollbar support for cards with fixed grid row height (#30209)
* Add scrollbar support for cards with fixed grid row height

* Fix default sizing

* Add warning for card that doesn't support resizing well

* Remove not used explanation
2026-03-18 16:11:29 +01:00
Bram Kragten 41ed7d2877 Add uom filter to entity selector (#30211) 2026-03-18 16:00:34 +01:00
Jan-Philipp Benecke b0b86e7ba8 Gate blueprint search behind minimum blueprint amount (#30207)
* Gate blueprint search behind minimum blueprint amount

* Remove top padding from search
2026-03-18 15:10:49 +02:00
Paul Bottein e67c4842d4 Add an auto height toggle in card layout editor (#30182)
* Add auto height toggle in grid card editor

* Improve toggle

* Prettier
2026-03-18 13:51:38 +01:00
Petar Petrov d9c39640e0 Preserve entity unit in gas and water flow rate badges (#30116)
* Preserve entity unit_of_measurement in gas and water flow rate badges

The gas and water total badges on the energy dashboard Now tab previously
converted all flow rate values to L/min and then formatted them as either
L/min or gal/min based on the unit system. This meant entities reporting
in m³/h or other units always displayed incorrectly.

Now the badges preserve the unit_of_measurement from the entities. If all
entities share the same unit, the raw values are summed directly. If they
differ, values are converted through L/min as an intermediate and displayed
in the first entity's unit.

* Extract shared computeTotalFlowRate to energy.ts
2026-03-18 13:00:17 +01:00
Wendelin a8478ab346 Fix copy-to-clipboard in unsecure context (#30204) 2026-03-18 11:56:35 +00:00
Petar Petrov 3ac2434b6f Rescale Y-axis on chart zoom via custom AxisProxy filterMode (#30192)
* Rescale Y-axis on chart zoom via custom AxisProxy filterMode

Patch ECharts' AxisProxy.filterData to support a "boundaryFilter" mode
that keeps the nearest data point outside each zoom boundary while
filtering distant points. This lets ECharts natively rescale the Y-axis
to the visible data range without causing line gaps at the zoom edges.

* Add tests for ECharts AxisProxy patch internals

Verify that the ECharts internals our boundaryFilter patch relies on
still exist (filterData, getTargetSeriesModels on AxisProxy prototype),
and test the patch behavior: delegation for other filterModes, early
return for non-matching models, and correct boundary-preserving filtering.

* Update comment
2026-03-18 10:58:51 +00:00
Aidan Timson f2f1044992 Format map card (#30202) 2026-03-18 12:52:06 +02:00
ildar170975andPetar Petrov 53bc66883a Map card editor: add more options (#29759)
* optimize ThemeMode

* add more map card options

* fix a type for label_mode

* enhance EntitySelectorFilter

* fix a type for label_mode

* fix classes for Map card

* add "required" flag

* add more options

* remove leading space

* simplify a bit

* Update src/panels/lovelace/editor/config-elements/hui-map-card-editor.ts

Co-authored-by: Petar Petrov <[email protected]>

* fix labels & simplify _deleteLabelModeOptions()

* move translations to generic

* resolving conflicts

* revert

* remove filterFunc

* use include_entities

* add a missing line

* prettier

* prettier

* Update src/panels/lovelace/editor/config-elements/hui-map-card-editor.ts

Co-authored-by: Petar Petrov <[email protected]>

* simplify _computeLabelCallback()

* Update src/panels/lovelace/editor/config-elements/hui-map-card-editor.ts

Co-authored-by: Petar Petrov <[email protected]>

* set location entiites in firstUpdated()

* add "disabled"

* disable "color" opton for a "zone" entity

* Update src/panels/lovelace/editor/config-elements/hui-map-card-editor.ts

Co-authored-by: Petar Petrov <[email protected]>

* Update src/panels/lovelace/editor/config-elements/hui-map-card-editor.ts

Co-authored-by: Petar Petrov <[email protected]>

* move MapCardMarkerLabelMode to ha-map

* move MapCardMarkerLabelMode to ha-map

* move MapCardMarkerLabelMode to ha-map

* move MAP_CARD_MARKER_LABEL_MODES to ha-map

* little fix

* fix import

* typo in import

* linter

* linter

* rename _disabledOptions -> _shouldDisableOptions

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-18 09:08:45 +00:00
Aidan TimsonandPetar Petrov d795bd1f61 Valve favorites (#30190)
* Setup valve favorites

* Setup card feature

* Fix styles, match covers

* Merge numeric favorites card features

* Merge favorites handlers in more info favorites

* Use correct key

Co-authored-by: Petar Petrov <[email protected]>

* Add translation

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-18 11:03:59 +02:00
Norbert Rittel 869e1d32b3 Replace remaining occurrences of "grid return" with "grid export" (#30199) 2026-03-18 10:53:31 +02:00
Aidan TimsonandCopilot Autofix powered by AI 3370bfa9dd Move Device and Entity triggers and conditions to Generic group (#30185)
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-03-18 09:07:27 +01:00
Paul Bottein b1921d1b66 Use explicit default name in entity name picker and lovelace cards (#30189) 2026-03-18 09:02:04 +01:00
renovate[bot] c2a2b382e9 Update dependency jsdom to v29 (#30198)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-18 08:57:11 +01:00
Qusai Ismael 7d95c2b6cb Fix missing conversation language picker in new pipeline dialog (#30194) 2026-03-18 08:56:04 +01:00
Allen PorterandPetar Petrov 67536a8a64 Display thinking steps and tool calling in the assist dialog (#29680)
Co-authored-by: Petar Petrov <[email protected]>
2026-03-18 08:47:17 +01:00
Joe Julian 3d89ad4f91 calendar: move to "today" daily at midnight (#30177)
calendar: move to today daily at midnight
2026-03-18 08:50:42 +02:00
Paul Bottein 36e08367d9 Use domain-specific label for Edit button in more info dialog (#30195) 2026-03-17 19:07:14 +01:00
karwosts 6e3cf3e42f Fix tag dialog (#30191) 2026-03-17 16:15:35 +01:00
Jan-Philipp Benecke fe53656c7e Enhance create new automation/script dialog with search and adaptive dialog (#30188)
* Enhance create new automation/script dialog with search and adaptive dialog

* Always show tip

* Address review comments

* Use multiTermSearch
2026-03-17 16:11:26 +02:00
Wendelin 14615191f4 Introduce ha-input (#29878) 2026-03-17 14:45:07 +01:00
Christopher Fenner 86ca8ebf71 Change battery border color to energy-battery-out (#30181) 2026-03-17 14:17:35 +02:00
Aidan Timson 16c1db5346 Cover favorites (#29997)
* Make favorites UI reusable

* Setup cover favorites

* Fix

* Make generic

* Remove

* Move

* Add type for keys

* Remove

* Move

* Types

* Types

* Changes for tilt position

* Cleanup

* Add missing options

* Replace cover preset features with favorites features

Editor points to more info instead of allowing cusomisation of feature

* Fix drag

* Remove learn more

* Add domains with favorites shared data

* Support recent additions: reset and copy favorites

* Move favorites logic into new file, futureproof for new domains

* Await all

* Refactor

* Use copy for primary action

* Allow empty lists

* Rename

* Use better ally labels

* Move favorites options above and use divider

* Move

* Use proper DOM types

* Use proper type

* Use proper types

* Cleanup

* Type from param

* Center align label

* Only show labels if both show
2026-03-17 14:14:47 +02:00
Aidan Timson b9568c079e Use ha-scrollbar in add automation item dialog (#30187)
Use ha-scrollbar for add automation item dialog
2026-03-17 13:11:23 +01:00
Norbert Rittel 0f9d90c217 Use "export" and "import" in Grid neutrality gauge card (#30183) 2026-03-17 11:11:31 +00:00
renovate[bot] ad092df9e0 Update dependency @bundle-stats/plugin-webpack-filter to v4.22.0 (#30186)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-17 11:40:02 +01:00
renovate[bot] 484473080e Update dependency lint-staged to v16.4.0 (#30184)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-17 11:27:11 +01:00
Paul Bottein 97dcc62ae7 Simplify entity name computation (#30147)
* WIP: start entity naming cleanup

* Clean device page

* Remove rename device logic

* Remove rename device logic in zwavejs

* Fix tests

* Fix entity name fallback

* Add test

* Fix type name

* Update name field in entity registry editor
2026-03-17 11:11:38 +01:00
Simon Lamon d12d4811b4 Update workbox-build (#30172) 2026-03-17 09:10:56 +00:00
renovate[bot] 3747abe1a9 Update dependency lint-staged to v16.3.4 (#30180)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-17 09:25:05 +01:00
WendelinandPetar Petrov 8541494b3d Migrate date picker to cally calendar-date (#29994)
* Switch date picker to cally calendar-date

* Remove app-datepicker styles from date picker dialog

Clean up unused CSS overrides in ha-dialog-date-picker.

Remove custom properties, focus/body rules, and responsive media
queries for app-datepicker and calendar-date so the component uses
upstream defaults and avoids duplicate styling

* Review

* Apply suggestion from @MindFreeze

Co-authored-by: Petar Petrov <[email protected]>

* Fix date parsing in HaDialogDatePicker to handle ISO string format

* Update src/components/ha-dialog-date-picker.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-17 10:18:18 +02:00
Petar Petrov 2d1e211034 Fix negative monetary values displayed as positive (#30178) 2026-03-17 09:11:15 +01:00
Tom Carpenter 147a21db27 Remove duplicate final point in bar statistics-chart (#30175)
For bar charts, we don't need to close out the final segment. All this does is produce a duplicate final bar.
2026-03-17 08:25:23 +02:00
karwosts e2e5feb8d5 Move loadConfig to common mixin (#30171) 2026-03-16 17:34:41 +02:00
Aidan Timson 619c75ac8b Update apps filtering and styles to show stage and remove advanced mode filters (#30165)
* Remove filter for unstable app stages

* Show stage in app store repository view

* Increase size of cards to accomadate badges

* Add stage to installed apps, update style

* Make "Search" consistent, "Search apps" not needed in this context

* Remove show advanced mode logic for app visibility

* Add margin to .addition

* Remove [deprecated] from app page title also

* Use common helper
2026-03-16 16:12:03 +02:00
Joakim Sørensen 5b09101903 Fix passing click handler to ha-switch in cloudhooks section (#30166)
Fix passing clickhandler to ha-switch in cloudhooks section
2026-03-16 15:27:44 +02:00
Aidan Timson 408efd2e2c Fix event entity row propagation (#30163)
* Stop event entity row value propagation

* Catch interaction
2026-03-16 14:32:50 +02:00
karwostsandPetar Petrov fd0b503a21 Show errors loading automation config (#30158)
* Show errors loading automation config

* Update src/panels/config/automation/ha-automation-editor.ts

Co-authored-by: Petar Petrov <[email protected]>

* prettier

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-16 14:27:15 +02:00
Norbert Rittel 1e9a1eaa04 Fix duplicated "shows" and excessive comma in user-facing string (#30161) 2026-03-16 08:37:32 +01:00
dependabot[bot] b42d52b854 Bump release-drafter/release-drafter from 6.4.0 to 7.0.0 (#30160)
Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 6.4.0 to 7.0.0.
- [Release notes](https://github.com/release-drafter/release-drafter/releases)
- [Commits](https://github.com/release-drafter/release-drafter/compare/6a93d829887aa2e0748befe2e808c66c0ec6e4c7...3a7fb5c85b80b1dda66e1ccb94009adbbd32fce3)

---
updated-dependencies:
- dependency-name: release-drafter/release-drafter
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-16 08:30:45 +02:00
dependabot[bot] 21a5e643ac Bump softprops/action-gh-release from 2.5.0 to 2.6.1 (#30159)
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.5.0 to 2.6.1.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/a06a81a03ee405af7f2048a818ed3f03bbf83c7b...153bb8e04406b158c6c84fc1615b65b24149a1fe)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 2.6.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-16 08:30:00 +02:00
renovate[bot] 52ac052baf Update vitest monorepo to v4.1.0 (#30155)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-15 16:33:02 +01:00
renovate[bot] a13ffa3c35 Update CodeMirror (#30154)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-15 16:22:17 +01:00
Tom Carpenter c51535eb79 Fix Statistic Entity Picker showing no entities/uncaught exception (#30144)
Correct Statistic Picker _getAdditionalItems

This should be a lambda function saved to a property, not a method. Otherwise when called  the "this" is the caller not the statistic picker. This was causing the Statistic Card entity picker to load blank.
2026-03-14 09:16:39 +02:00
renovate[bot] 5ea05768a3 Update dependency terser-webpack-plugin to v5.4.0 (#30148)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-13 18:16:06 +01:00
d10376e9d8 Matter lock manager (#28672)
* Initial implementation of Matter lock pin management and events.

- Implement lock codes
- Implement lock events
- Implement lock schedules and guest codes

* Initial implementation of Matter lock pin management and events.

- Implement lock codes
- Implement lock events
- Implement lock schedules and guest codes

* Initial implementation of Matter lock pin management and events.

- Implement lock codes
- Implement lock events
- Implement lock schedules and guest codes

* - Copilot fixes

* - Requested improvements on how the UI screens render including:
   - Cancel button location
   - Alignment of delete icons and buttons

* Updates to support new PR for backend

* Update as per PR comments

* Fixes to align to new backend design.

* Fixes for user deletion

* Fixes for PR comments

* Delete test/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json

* Remove unused code

* Updates with review feedback

* PR Comments

* Fixed linting error

* Fixes for new dialog changes

* Added debugging for errors, aligning to other areas where this is used.

---------

Co-authored-by: Wendelin <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-03-13 16:20:21 +00:00
Tom Carpenter e21f7baa93 Support Energy Collections in Statistics Graph Card Visual Editor (#29628)
* Add date selection keys to statistics-graph editor

Add support for the `energy_date_selection` and `collection_key` entires in the visual statistics-graph card editor, along with validation of the collection key in the statistics-graph's setConfig.

* Add missing option to stats card editor

Was missing the expand_legend config option in the visual editor.

* Tidy statistics graph editor arrangement

1. Group the various settings cleanly.
2. Auto-hide the collections key if energy date picker selection is disabled
3. Auto-hide days to show if a collection is linked

* Add "auto" option for statistics-chart period

When using the energy date picker option, enable the ability to select a period of "auto" which will enable use of the energy systems automatic period selection function.

* Correct hiding days to show

Should be hidden whenever energy_date_selection is true, regardless of collection key to cope with upgrading existing cards for which no key has been set.

* Hide "auto" period on statistics graph card editor
When not using energy, hide the auto option to avoid confusion.

* Swap date selection and collection key order

This keeps the toggle in a consistent location.

* Remove duplicate config key

There is a title? key now in EnergyCardBaseConfig.

* Correct energy_date_selection translation

* Improve collection key description

* Improve terminology for energy card collection
2026-03-13 18:15:53 +02:00
Aidan Timson 14098e0d7e Remove extra spacing for automation editor content (#30084)
* Remove extra spacing for automation editor content

* Remove extra margin for header

* Restore some padding
2026-03-13 15:53:40 +02:00
Joakim Sørensen bd8c407690 Fix formatting of ha-switch in cloud remote preferences panel (#30143) 2026-03-13 13:47:32 +00:00
Aidan Timson c452acf6cf Prevent scrim close on settings view for more info (#30140)
* Prevent scrim close on settings view for more info

* Inline
2026-03-13 12:59:27 +02:00
Aidan Timson 814106e4aa Prevent scrim close on edit home overview dialog (#30139) 2026-03-13 12:59:01 +02:00
Aidan Timson a2254eb048 Add my link for home overview (#30137)
Add my link for overview
2026-03-13 11:48:33 +01:00
Tom CarpenterandPetar Petrov fa5e0bb0c7 Support Energy Collections in Statistic Card Visual Editor (#29629)
* Improve energy support for statistics card

Rather than setting the period to "energy_date_selection", add an energy_date_selection key to the config to be more consistent. The original configuration option is still supported for backwards compatibility

Update the statistic card visual editor to support energy collection key selection.

* Add statistics card collection key validation

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

* Remove title from EnergyCardBaseConfig

This was added when the energy card visual editors were created, but not all cards using a collection key need a title. Using Omit to remove it seems to lose the extend of LovelaceCardConfig.

Instead add EnergyCardConfig which is EnergyCardBaseConfig with the title field. This is used for a number of cards to allow them to share the same visual editor without having to list out every one.

* Mark Statistic Period calendar.offset as optional

It is already handled in core as an optional key (defaults to 0), and the statistic card/editor was explicitly omiting the key even though it was declaring it as required.

This removes the need for an error masking cast when converting the deprecated PERIOD_ENERGY to STATISTIC_CARD_DEFAULT_PERIOD.

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-13 12:47:37 +02:00
renovate[bot] e8e62a0aa0 Update dependency @codemirror/view to v6.39.17 (#30133)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-13 09:12:15 +00:00
renovate[bot] 4893b631a5 Update dependency @rspack/core to v1.7.8 (#30134)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-13 09:12:08 +00:00
Paul Bottein d851a5bdf3 Fix entities not updated in device page (#30136) 2026-03-13 09:11:11 +00:00
ildar170975 148d01b05b hui-entities-card-row-editor: add margin-bottom for "add-entity" & prevent a clipping (#30123) 2026-03-13 08:38:17 +00:00
renovate[bot] 171875c65c Update dependency lint-staged to v16.3.3 (#30127)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-13 08:35:58 +02:00
renovate[bot] 6a61186507 Update dependency babel-loader to v10.1.1 (#30120)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-13 08:30:13 +02:00
renovate[bot] 1690991726 Update dependency typescript-eslint to v8.57.0 (#30119)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-13 08:29:53 +02:00
renovate[bot] 4904566460 Update dependency barcode-detector to v3.1.1 (#30118)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-13 08:29:28 +02:00
Logan RosenandCopilot b3b8f1a38a Filter ResizeObserver loop errors from dev server overlay (#30125)
The @rspack/dev-server overlay catches ResizeObserver loop errors as
runtime crashes, showing a full-screen error overlay that blocks
development. These errors are benign — they originate from
lit-virtualizer (used by ha-data-table) and simply mean not all
resize observations could be delivered in a single animation frame.

Add a client.overlay.runtimeErrors filter to the dev server config
that suppresses ResizeObserver loop messages while still surfacing
all real runtime errors.

Co-authored-by: Copilot <[email protected]>
2026-03-13 08:28:58 +02:00
Logan RosenandCopilot 3bb870f52a Fix gallery integration card crash from invalid mock hassUrl (#30126)
The gallery mock set hass.auth.data.hassUrl to an empty string, which
caused brandsUrl() to throw when constructing a URL via new URL(base, '').
In production hassUrl is always a valid URL, so the mock now uses
location.origin to match real behavior.

Co-authored-by: Copilot <[email protected]>
2026-03-13 08:27:39 +02:00
Logan RosenandCopilot 95a7b91ea5 Fix media-player mock attrs for gallery seek slider (#30124)
Fix media-player mock state attributes for gallery seek UI

Expose media-player capability and state attributes via entity hooks so gallery music mocks render position bars. Keep the domain-hook model and null state attrs when off to match other mocks.

Co-authored-by: Copilot <[email protected]>
2026-03-13 08:26:44 +02:00
Bram Kragten 9c4aacdb1f Bumped version to 20260312.0 2026-03-12 22:08:30 +01:00
Paul Bottein 3feb40a8f4 Add token for brands url in hassUrl helper (#30111) 2026-03-12 22:07:51 +01:00
Tom Carpenter 7a310812e0 Fix energy dashboard date picker opening direction (#30090)
* Add Opening Direction to Date Picker Config

* Force date picker opening direction on energy dash
2026-03-12 22:07:50 +01:00
Aidan Timson ee77619da3 Fix code editor autocomplete using wa popup (#30081) 2026-03-12 22:07:49 +01:00
Petar Petrov cfa8eb5370 Fix hasReturn check to scan all grid sources in energy view strategy (#30062) 2026-03-12 22:07:48 +01:00
Tom Carpenter d9d2d6aa03 Don't include "null" data point in stat graph (#30058)
When displaying the "now" value on statistics graphs, don't include a "null" data point for sum/change type graphs, just skip entirely.

Otherwise for you get a messy null data point in the tooltip.
2026-03-12 22:07:47 +01:00
Tom Carpenter 1f46f477c7 Add missing webawesome tooltip CSS variable (#30057)
* Correct missing ha-tooltip CSS variable

We were missing a default for the `--wa-tooltip-border-width` variable which meant the arrow from the tooltip disappeared in WA 3.3.1.

* Fix tooltip in ha-slider
2026-03-12 22:07:47 +01:00
Bram Kragten 52667b3266 Add reorder support to area selector (#30056) 2026-03-12 22:07:46 +01:00
Petar Petrov c790d2356c Add back energy distribution card to electricity tab (#30049) 2026-03-12 22:07:44 +01:00
Yosi Levy f24c009dd7 RTL textfield fixes for quick search (#30013)
textfield fixes for quick search
2026-03-12 22:07:44 +01:00
Petar Petrov 8d42395938 Fix stale data point in history-graph cards with sub-hour windows (#29998)
Skip fetching hourly statistics when hours_to_show < 1 since hourly
aggregates produce stale outlier points in sub-hour chart windows
(e.g. hours_to_show: 0.1 or 0.05).

Also fix Date object handling in ha-chart-base downsampling bounds
extraction.
2026-03-12 22:07:42 +01:00
1a6d46a7ff Refactor tooltip CSS tokens to use ha- prefix (#29978)
Co-authored-by: Claude <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2026-03-12 22:07:42 +01:00
Petar Petrov b286b07cfd Fix sensor card graph time axis not progressing when value is unchanged (#29976) 2026-03-12 22:07:41 +01:00
Paul Bottein 1859d35f7b Add arrow and fix footer for vacuum segment mapper (#29975) 2026-03-12 22:07:40 +01:00
Aidan Timson 29b3303f94 Center justify more info controls (sliders, etc) (#30117) 2026-03-12 16:46:31 +01:00
5dc2c51251 Remove Z-Wave Installer panel (#30115)
* Initial plan

* Remove Z-Wave expert panel (installer mode) references

Co-authored-by: AlCalzone <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: AlCalzone <[email protected]>
2026-03-12 16:22:47 +02:00
renovate[bot] 571fccf4a0 Update formatjs monorepo (#30114)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-12 15:27:23 +02:00
8f958147dd Add Visual Editors for Energy Dashboard Cards (#29483)
* Add common API for energy collection keys

These allow so far for:
1. Creating a valid collection key
2. Validating that a collection key is useable
3. Getting a list of all currently active collection keys

Currently the validation/creation is simply checking the prefix. In time this could be extended to add more validation - e.g. sanitising punctuation/spaces/etc.

Cards configured using a visual editor will in the future ican use these APIs to distinguish between collection keys created manually in YAML/internally by HA from those created by the visual editor.

* Create visual editor for energy date selector

Allow creating date selection cards directly from the lovelace card dialog rather than requiring manual creation.

To aid in this, a date selection editor card has been created to allow using the visual editor. This includes options for setting the vertical opening direction, whether comparison is enabled/disabled, and creating a collection key.

To keep things hopefully more accessible to users, the `energy_` prefix for the collection key can be omitted from the text field. It will be added automatically if necessary. The prefix must be added if editing in the YAML editor.

Validation of the collection key is also performed, providing an error message if the key is invalid.

* Allow visual editors only for UI collection keys

Prevent the visual editors from being used if the collection key doesn't have the correct prefix. This is to avoid breaking existing user dashboards that predate the visual editor.

Additionally use the helper in energy dashboard for stripping the UI prefix.

* Create visual editor for sankey cards

Allow creating energy/water/power sankey cards directly from the lovelace card dialog rather than requiring manual creation.

A sankey chart editor card has been created to allow using the visual editor. This includes setting of all common options for sankey cards including layout, groups, and selection of a collection key.

To keep things simple for users, the visual editor displays the collection_key field as a drop-down menu from which all active collection keys may be selected.

* Create visual editor for energy graph cards

Allow creating energy/solar/gas/water usage graph cards directly from the lovelace card dialog rather than requiring manual creation.

A common graph editor card has been created to allow using the visual editor. This provides a basic set of common properties - currently just title and collection key.

To keep things simple for users, the visual editor displays the collection_key field as a drop-down menu from which all active collection keys may be selected.

* Assign visual editor to compare card

This is not assigned to the lovelace card selector as its not strictly a card, but rather an alert. However it might as well be assigned to the visual editor for consistency.

* Add Power Sources Graph

This was missed when adding other graphs. Currently it shares the same editor which means the optional show_legend key cannot yet be set visually. In time this could be updated.

* Update energy card descriptions

Update descriptions and names of cards in the lovelace card selector to be consistent with the energy card documentation.

* Create visual editor for energy device graph cards

Allow creating device and detailed device graph cards directly from the lovelace card dialog rather than requiring manual creation.

* Pass config type to devices schema

Rather than converting to a boolean, pass in the type. This will make expanding easier if future devices cards are added.

* Add missing fields to Energy Graph Card Editor

Add options to set `show_legend` and `link_dashboard` config fields.

* Add energy gauge visual editing

These need no special configuration, so might as well reuse the generic energy graph card editor.

* Add option to ignore onInput for ha-form-string

For the ha-form-string element on e.g. the card editor dialog, it would be useful for some types of input to not send value changed events for incomplete changes.

Currently the form triggers the event whenever a character is typed/deleted by forwarding onInput event. To avoid this where undesireable, add a new optional schema entry to ignore these events, which if defined and true sees updating only in response to the onChange callback.

For the energy date picker, this will avoid unnecessary creation of collection keys and by extension energy API connections when using the visual editor improving efficiency.

* Disable preview of energy cards in card picker
To avoid excess querying of the backend for energy data when loading the card picker dialog.

* Set default energy collection key to dashboard name

This changes the behaviour so that by default any component without a collection key will be grouped with other elements on their dashboard, but not with elements on other dashboards.

* Add stub config for date picker

To auto-populate a default picker configuration, including current dashboard name as the collection key.

* Add Stub Configs for other Energy Cards

Auto-populate the default parameters and the current dashboards default collection key.

* Add isActive Getter to Energy Collection

* Add findEnergyDataCollection

This will look for an existing data collection but will not create a new one if it doesn't exist.

To help with this, move the logic for creating the connection key name into a function shared between the new findEnergyDataCollection and the existing getEnergyDataCollection.

* Convert energyCollectionKeys to a Set

All entries should be unique, so use set behaviour.

* Fix capitalisation in translations

Co-authored-by: Petar Petrov <[email protected]>

* Revert unintentionally committed change

* Revert "Add option to ignore onInput for ha-form-string"

This reverts commit 1cae35db25.

* Remove hiding of collection key prefix

For now keep things simple and show the whole prefix as creation will probably be overhauled in the future.

To assist the user, in the date picker, automatically add the required prefix when the user types into the collection key box.

* Use panelUrl directly for default collection keys

* Update src/translations/en.json

Fix typo

Co-authored-by: Norbert Rittel <[email protected]>

* Ensure energy cards appear at end of card picker

Add a new `sortAtEnd` option which will cause cards with this sort parameter to sink to the bottom of the card picker.

* Remove collection key from stubConfig
Empty is fine, will convert to same default key anyway.

* Make all collection keys text fields
Remove the active energy collection dropdown.

* Revert "Ensure energy cards appear at end of card picker"

This reverts commit 28834aaa55.

* Add (hidden) energy cards to card picker

Merge in changes originally proposed in #23499.

* Resolve Merge Conflicts

* Fix Lint Error

* Update energy card descriptions

Make them consistent with other card descriptions which start with "The <name of card> card shows ...".

* Change Energy Card Descriptions
Fix the descriptions to use `This card` not `The ... card`.

* Change hide_compound_stats Description
Change to 'upstream devices' to match energy config page descriptions.

* Remove superfluous translation
The type field was not intended to be added to the label callback.

* Remove unused collection key exports

* Remove createEnergyCollectionKey

Was helpful when tying into the collection_key field to auto-add the prefix, but so be it.

* Add visual editor to water flow sankey
Can use the same sankey editor as the others. Update the description of energy sankey to better describe what is being displayed and to match the description of water vs water flow sankey.

* Add getStubConfig to water flow sankey

* Add missing water-flow-sankey to validation

Co-authored-by: Petar Petrov <[email protected]>

* Fix Date Picker Collection Key Localise

* Move Collection Key to end of Visual Editor
Downplay its significance - move it to the end of the list of options.

* Fix default collection key check
Intended behaviour was to check that the panel URL was not empty - defaultKey will always be truthy!

* Add Opening Direction to Date Picker Config

* Omit "inline" opening direction

This breaks the visual editor as the date selection window suddenly popus up in the preview and is uncloseable.

* Update src/panels/lovelace/editor/lovelace-cards.ts

Co-authored-by: Petar Petrov <[email protected]>

* Add visual editor for energy-sources-table

The only energy card now missing a visual editor, create the editor for completeness.

* Add name/description for Energy Compare card

* Add preview mode to energy-compare-card

Otherwise it just appears blank in the card and dashboard editors. In preview it will just use the current date for start/end and not provide the dismiss option just to give an impression of how it will look.

* Add type check in energy-graph-card-editor

* Add documentation link for energy-compare-card

* Add documentation links for energy badges

* Fix value lost in dev merge

* Remove dismiss from compare card preview

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
Co-authored-by: Norbert Rittel <[email protected]>
Co-authored-by: karwosts <[email protected]>
Co-authored-by: Simon Lamon <[email protected]>
2026-03-12 15:17:41 +02:00
xtymmms1021 41753e48bf Guard discovered devices flow subscription for non-admin users (#30110)
* Guard discovered devices flow subscription for non-admin users

* Address review feedback on hass non-null assertions
2026-03-12 14:46:59 +02:00
Paul Bottein d496b2a6fe Add token for brands url in hassUrl helper (#30111) 2026-03-12 10:27:43 +00:00
3260c48130 Extract AutomationSortableListMixin to deduplicate automation list components (#29977)
* Initial plan

* Extract shared automation rows logic into AutomationRowsMixin

Create ha-automation-rows-mixin.ts with common list manipulation methods
(moveUp, moveDown, move, itemMoved, itemAdded, itemRemoved, itemChanged,
duplicateItem, insertAfter, handleDragKeydown, stopSortSelection, getKey)
and shared properties (hass, disabled, narrow, optionsInSidebar,
_rowSortSelected, _clipboard).

Refactor ha-automation-trigger, ha-automation-condition,
ha-automation-action, and ha-automation-option to use the mixin,
eliminating significant code duplication.

Co-authored-by: wendevlin <[email protected]>

* Address review feedback: rename to AutomationSortableListMixin, remove _ prefix from protected members, throw in setHighlightedItems

- Rename AutomationRowsMixin to AutomationSortableListMixin
- Rename file to ha-automation-sortable-list-mixin.ts
- Remove _ prefix from all protected methods/properties
- Make setHighlightedItems throw Not implemented error
- Update all 4 component files with new references

Co-authored-by: wendevlin <[email protected]>

* Add missing this.items = items in itemChanged to avoid UI jump

The original _conditionChanged had this.conditions = conditions before
fireEvent to update local state and avoid UI jumps. This was lost during
the mixin extraction.

Co-authored-by: MindFreeze <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: wendevlin <[email protected]>
Co-authored-by: MindFreeze <[email protected]>
2026-03-12 09:19:57 +00:00
Simon Lamon a356c153f8 Demo fixes (#30105) 2026-03-12 08:53:25 +01:00
Matthias de Baat b60dc94196 Add protocol logos (#30104) 2026-03-12 08:52:37 +01:00
Tom CarpenterandPetar Petrov c5cb196aa1 Use whole months for "Last 12 Months" on Energy Date Picker (#30091)
* Make "now-12m" use month boundaries

Currently the "Last 12 Months" date function calculates precisely 12 months from the current day. So today is March 10, then it would retrieve April 11 to March 10.

However logically the name implies whole months - i.e. "now" would be "March", so the last 12 months ought to be Apr 1 to March 31.

* Let energy date picker detect 12 Month range

With now-12m changed to mean whole months rather than partial months, we can make the energy date picker nicely detect and render any month range, and also fix the now button so that it can pick a "now-12m" range.

* Use Short Month for Displayed Range
To avoid making the displayed range too large to fit on small screens.

* Move subMonths into calcDate fn not input

Perform both startOfMonth and subMonths as a custom function in calcDate rather than performing subMonths on the input to avoid any wierd timezone issues.

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-12 07:40:50 +00:00
Josef ZweckandPetar Petrov 5ddb31ce7b Add "cleaning_up" backup stage (#30106)
* Add "cleaning_up" backup stage

* Update ha-backup-overview-progress.ts

Co-authored-by: Petar Petrov <[email protected]>

* prettier

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-12 09:25:24 +02:00
Norbert Rittel 7465c9874c Improve "The … is disabled by …" message in Device info (#30107)
- remove the trailing period as it's shown in a box
- sentence-case "user", "integration" and "config entry"
2026-03-12 09:09:14 +02:00
renovate[bot] bbe81ca8f1 Update dependency tar to v7.5.11 [SECURITY] (#30108)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-12 09:08:31 +02:00
Logan RosenandCopilot 51ecdb0851 Expand ha-slider touch target for volume slider usability (#30109)
Add padding to the #slider element in ha-slider to expand its touch
target to 32px, making sliders easier to interact with on touch devices.

Remove the pointer-events: none workaround on the volume slider in the
media player more-info dialog. This workaround disabled touch interaction
entirely on coarse pointer devices, which is no longer needed now that
the slider has an adequately sized touch target.

Co-authored-by: Copilot <[email protected]>
2026-03-12 07:03:26 +00:00
Matthias de Baat 268c0a60f0 Faster load Zigbee numbers (#30096) 2026-03-11 15:47:41 +00:00
ildar170975 8745cfa1ed Distribution card: fix height & layout settings (#29712)
fix height & fixed_rows
2026-03-11 14:58:47 +01:00
8bcccb5792 Allow trace graph to scroll independently of the step-details tab (#29906)
* Allow trace graph to scroll independently

* Apply independent trace graph scrolling to script trace

Port the independent column scrolling and sticky nav overlay from
ha-automation-trace to ha-script-trace, and add scroll-to-active-node
behavior to hat-script-graph.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Re-encapsulate nav buttons inside hat-script-graph

Move the up/down navigation buttons back into hat-script-graph where they
belong, restoring _previousTrackedNode/_nextTrackedNode as private. Wrap
the graph content in a div.graph-scroll so it scrolls independently while
the button column stays fixed — the same flex-row layout the parent was
using, now self-contained inside the shadow DOM.

This removes the duplicated nav overlay markup and disabled-state logic
from ha-automation-trace and ha-script-trace, and removes the unnecessary
public surface on HatScriptGraph.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Make not-scrollable more specific.

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-03-11 15:08:10 +02:00
Aidan Timson 0844d9c2c0 Highlight linked config entry again (#30095)
* Highlight linked config entry again

* Fix export
2026-03-11 15:05:58 +02:00
karwostsandPetar Petrov 9d3aafe219 Light favorite color card feature (#29995)
* Light favorite color card feature

* rewrite resizeObserver

* code review

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

* Apply suggestion

Co-authored-by: Petar Petrov <[email protected]>

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-11 12:59:01 +00:00
Artur Pragacz 0cf3e34956 Use group entities attribute (#30094)
* Use group entities attribute

* Include min_max

* Remove domain check
2026-03-11 14:54:45 +02:00
Brooke Hatton 7d20b04469 Filter hidden entities in common controls section (#29871)
Filter hidden entities in common controls section strategy

Match filtering behavior of area/room view strategies by excluding entities
marked as hidden (via hidden_by: user/integration/device) from the common
controls section. This ensures consistency across all auto-generated
dashboard strategies and respects user preferences for entity visibility.
2026-03-11 12:10:45 +01:00
Simon Lamon 6f6ba71e61 Redesign gauge card (#29981)
* Redesign gauge card

* Fix calculation

* New design, code needs optimization (ai)
2026-03-11 11:22:44 +02:00
Petar Petrov d61de4d2df Disable smoothMonotone in line graphs (#30093) 2026-03-11 09:01:37 +00:00
Bram Kragten f8dcee6867 Allow to assign a color to a map entity in the map card (#30088)
* Allow to assign a color to a map entity in the map card

* Update en.json
2026-03-11 08:31:12 +02:00
Tom Carpenter 0f975acca1 Show energy date picker previous/next on smaller screens (#30092)
* Fix missed spacing token usage

* Reduce Date Picker Collapse Button Width

Remove unnecessary padding between date icon button and date text and allow next/prev to be shown for 20px narrower screens.

* Reduce calendar icon size for narrow screens

Allows use of screens down to 325px wide before the next/prev buttons are lost.

Given most android screens are >=360px this is a big improvement as before this change the hide limit was 370px.
2026-03-11 08:27:29 +02:00
Tom Carpenter 9e57dacb3c Fix energy dashboard date picker opening direction (#30090)
* Add Opening Direction to Date Picker Config

* Force date picker opening direction on energy dash
2026-03-11 08:12:22 +02:00
Aidan Timson 2650c1c0b2 Fix code editor autocomplete using wa popup (#30081) 2026-03-10 17:20:40 +01:00
Bram KragtenandWendelin 6957e1f4d9 Introduce Lazy context provider (#29988)
Co-authored-by: Wendelin <[email protected]>
2026-03-10 16:19:48 +01:00
Yosi Levy 32be26320d Support for ESC in notification drawer (#29521) 2026-03-10 15:47:35 +01:00
Paul Bottein cdbaa85beb Fix debounce with immediate firing twice on single call (#30082) 2026-03-10 13:39:44 +01:00
Bram Kragten b58fc68ea8 Add warning when importing blueprint from unknown source (#30076) 2026-03-10 09:05:39 +00:00
renovate[bot] 4792659c61 Update dependency @babel/helper-define-polyfill-provider to v0.6.7 (#30075)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-10 08:59:26 +00:00
Paul Bottein eeae66e026 Add default state/numeric_state options to automation triggers and conditions (#30052) 2026-03-10 08:54:00 +00:00
renovate[bot] 60b4b1c4e2 Update dependency eslint to v9.39.4 (#30079) 2026-03-10 07:42:05 +01:00
Aidan Timson 877c5e8d16 Validate min-max with dialog box (#30071)
* Validate min-max for dialog box

* Use check

* Remove redundant call
2026-03-09 17:17:28 +02:00
Josef Zweck 11fd10a011 Report progress for backup upload (#29748)
* Add progress bar for backup uploads

* add sort

* visual fixes

* fix sorting

* react to event

* cleanup

* remove log

* remove fom union type

* different progress bar

* styling fixes

* guard against empty space in other backup states

* cleanup

* xleanup

* add checkmark on completion

* remove progress bar

* remove spinner during upload

* remove spinner, animate

* add subtext

* prettier

* review comments

* linesbreaks
2026-03-09 17:12:54 +02:00
renovate[bot] 623baea59d Update dependency babel-loader to v10.1.0 (#30069)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-09 11:00:53 +00:00
Paul Bottein 052909ea01 Make bar-gauge card feature non-clickable (#30068) 2026-03-09 10:52:09 +00:00
Petar Petrov 5e3c80ef6e Fix hasReturn check to scan all grid sources in energy view strategy (#30062) 2026-03-09 10:51:28 +00:00
Bram Kragten 6e2fdbb396 Add reorder support to area selector (#30056) 2026-03-09 09:24:20 +01:00
Tom Carpenter 5b981062f6 Add missing webawesome tooltip CSS variable (#30057)
* Correct missing ha-tooltip CSS variable

We were missing a default for the `--wa-tooltip-border-width` variable which meant the arrow from the tooltip disappeared in WA 3.3.1.

* Fix tooltip in ha-slider
2026-03-09 09:25:21 +02:00
Tom Carpenter 5a2d7f100a Don't include "null" data point in stat graph (#30058)
When displaying the "now" value on statistics graphs, don't include a "null" data point for sum/change type graphs, just skip entirely.

Otherwise for you get a messy null data point in the tooltip.
2026-03-09 09:02:00 +02:00
dependabot[bot] b62e6c9328 Bump release-drafter/release-drafter from 6.2.0 to 6.4.0 (#30059)
Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 6.2.0 to 6.4.0.
- [Release notes](https://github.com/release-drafter/release-drafter/releases)
- [Commits](https://github.com/release-drafter/release-drafter/compare/6db134d15f3909ccc9eefd369f02bd1e9cffdf97...6a93d829887aa2e0748befe2e808c66c0ec6e4c7)

---
updated-dependencies:
- dependency-name: release-drafter/release-drafter
  dependency-version: 6.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 08:50:31 +02:00
dependabot[bot] 537ab2debb Bump actions/setup-node from 6.2.0 to 6.3.0 (#30061)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6.2.0 to 6.3.0.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/6044e13b5dc448c55e2357c09f80417699197238...53b83947a5a98c8d113130e565377fae1a50d02f)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: 6.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 08:50:00 +02:00
dependabot[bot] 04d31e4ea9 Bump github/codeql-action from 4.32.4 to 4.32.6 (#30060)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.32.4 to 4.32.6.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/89a39a4e59826350b863aa6b6252a07ad50cf83e...0d579ffd059c29b07949a3cce3983f0780820c98)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.32.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 08:49:05 +02:00
renovate[bot] 3d0c7b6aab Update dependency @html-eslint/eslint-plugin to v0.58.1 (#30054)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-08 16:53:13 +01:00
renovate[bot] 87d3d06e79 Update dependency @home-assistant/webawesome to v3.3.1 (#30055)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-08 16:38:56 +01:00
Wendelin 872d1c684f Simplify dialogs (#29848) 2026-03-08 16:27:04 +01:00
renovate[bot] d9d2ebfb9d Update dependency tar to v7.5.10 [SECURITY] (#30002)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-08 08:42:53 +00:00
renovate[bot] e26315c4d2 Update dependency @html-eslint/eslint-plugin to v0.58.0 (#30047)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-08 09:35:44 +01:00
renovate[bot] d9a2e1cbee Update dependency marked to v17.0.4 (#30046)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-08 09:34:54 +01:00
Petar Petrov b7d6652e5c Add back energy distribution card to electricity tab (#30049) 2026-03-08 09:34:28 +01:00
renovate[bot] b188da0b5c Update dependency serve to v14.2.6 (#30030)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-07 10:24:46 +00:00
karwosts 9f87257f41 Support copying light favorites to other lights (#30034) 2026-03-07 11:14:48 +01:00
renovate[bot] f4e409f157 Update dependency sinon to v21.0.2 (#30041)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-07 11:13:53 +01:00
renovate[bot] 44d727763c Update dependency lint-staged to v16.3.2 (#30029)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 19:44:50 +01:00
Petar Petrov 2f87614c4c Fix stale data point in history-graph cards with sub-hour windows (#29998)
Skip fetching hourly statistics when hours_to_show < 1 since hourly
aggregates produce stale outlier points in sub-hour chart windows
(e.g. hours_to_show: 0.1 or 0.05).

Also fix Date object handling in ha-chart-base downsampling bounds
extraction.
2026-03-06 19:42:52 +01:00
Yosi Levy 697a945056 RTL textfield fixes for quick search (#30013)
textfield fixes for quick search
2026-03-06 19:42:21 +01:00
Paul Bottein 67dbacce52 Improve mock for cover, alarm, lock, lawn mower, valve and vacuum (#29999) 2026-03-06 19:41:12 +01:00
renovate[bot] e891ae6bdd Update dependency terser-webpack-plugin to v5.3.17 (#30026)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 19:39:16 +01:00
renovate[bot] a11d1cfecf Update dependency @formatjs/intl-datetimeformat to v7.2.4 (#30021)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 19:38:32 +01:00
renovate[bot] 933bb4a2cc Update dependency fs-extra to v11.3.4 (#30025)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 19:34:52 +01:00
karwosts 1ca1ef3c32 Fix favorite color dragging unintended buttons (#30028) 2026-03-06 19:34:18 +01:00
renovate[bot] f529a349b9 Update dependency @rspack/core to v1.7.7 (#30018)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 10:54:23 +01:00
karwosts b3b35e4299 Menu item to reset light favorite colors (#30004)
reset-light-favorites
2026-03-05 20:46:44 +01:00
Paul Bottein 59364d05ec Improve pull request instructions for AI agents (#30001) 2026-03-05 18:38:25 +01:00
renovate[bot] 6444c0df15 Update CodeMirror (#29987)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-05 17:26:18 +02:00
Aidan Timson 8f704d8c0a Cover tilt presets card feature (#29989) 2026-03-05 17:23:28 +02:00
Petar Petrov aeddeb3bd7 Fix sensor card graph time axis not progressing when value is unchanged (#29976) 2026-03-05 15:13:05 +01:00
Paul Bottein 1377e3a363 Improve light, climate, water heater, humidifier and fan mock (#29980) 2026-03-05 14:11:23 +01:00
e47bf22798 Add click-to-replace interaction for selected targets in ha-target-picker (#29864)
Co-authored-by: timmo001 <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Aidan Timson <[email protected]>
2026-03-05 13:51:33 +01:00
Paul Bottein b3f1ba9433 Simplify icon loading (#29953) 2026-03-05 12:36:36 +01:00
Bram Kragten 829c5ca4df Update ha-device-automation-picker.ts 2026-03-05 10:19:03 +01:00
Aidan TimsonandPetar Petrov fbd4fc6d5f Cover presets card feature (#29959)
* Add cover presets features

* Max 6 items

* Remove tilt preset

* Fix clamping

* Filter

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-03-05 07:31:31 +00:00
7612ec1979 Refactor tooltip CSS tokens to use ha- prefix (#29978)
Co-authored-by: Claude <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2026-03-04 15:02:09 +00:00
Paul Bottein 71a5a1d3b4 Add arrow and fix footer for vacuum segment mapper (#29975) 2026-03-04 14:58:34 +01:00
Wendelin ad91d360f8 Respect safe area top for bottom sheet max height (#29974)
Respect safe area insets for bottom sheet maximum height
2026-03-04 15:45:44 +02:00
Copilotandwendevlin a88f492c05 Create ManualEditorMixin to deduplicate manual-automation-editor and manual-script-editor (#29955)
* Initial plan

* Create ManualEditorMixin to share code between manual-automation-editor and manual-script-editor

Co-authored-by: wendevlin <[email protected]>

* Add PropertyValues type annotation to updated() in manual-script-editor

Co-authored-by: wendevlin <[email protected]>

* Throw not implemented error in renderContent() base method

Co-authored-by: wendevlin <[email protected]>

* Throw not implemented error in handlePaste and saveConfig base methods

Co-authored-by: wendevlin <[email protected]>

* Fix lint:types error: add explicit Promise<void> return type to handlePaste

Co-authored-by: wendevlin <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: wendevlin <[email protected]>
2026-03-04 15:19:22 +02:00
Aidan Timson 0fc85a52a0 Create dedicated app store repositories and registries pages (#29931)
* Update design of app store repositories dialog

* Cleanup

* Move to new page

* Move to new page

* Update label

* Migrate translations

* Add loading state to dialog box

* Create dedicated app store registries page
2026-03-04 15:08:51 +02:00
Tom Carpenter e01dc89a48 Prevent keyboard shortcuts firing in dropdowns (#29972) 2026-03-04 12:32:53 +00:00
Copilotandwendevlin 52c36db5d4 Fix plant status card not respecting sensor display precision (#29968)
Co-authored-by: wendevlin <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-03-04 13:30:51 +01:00
Aidan Timson f217dab8d4 Migrate ha-toast to webawesome popover (#29952)
* Migrate ha-toast to webawesome popover

* Update closed event to new API

* Use component

* Use div

* Fix import
2026-03-04 14:21:18 +02:00
Bram Kragten 5709af57de Bumped version to 20260304.0 2026-03-04 12:42:58 +01:00
Wendelin bb16cc8c00 Open quick search quicker (#29967) 2026-03-04 12:42:26 +01:00
Bram Kragten 17c6dc52a8 Add hass url to brand images (#29961) 2026-03-04 12:42:24 +01:00
Paul Bottein 1b8211db6d Align heading button font-size with other heading entity badge (#29958) 2026-03-04 12:42:22 +01:00
2b2bb77a2b Fix copy to clipboard for wa dialogs (#29951)
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2026-03-04 12:42:21 +01:00
Wendelin 64749350ef ha-bottom-sheet reduce motion support (#29950) 2026-03-04 12:42:20 +01:00
Paul Bottein 043d4eed85 Add label for toggle button in area strategy (#29949) 2026-03-04 12:42:19 +01:00
Paul Bottein 2f2e64bb1d Use max width for dashboard footer (#29947) 2026-03-04 12:39:18 +01:00
Petar Petrov b74b02c09f Use net battery power in power sankey card (#29940) 2026-03-04 12:39:17 +01:00
Wendelin ab4c3a4316 ha-authorize fix rtl check (#29937)
Add RTL direction handling in updated lifecycle method
2026-03-04 12:39:16 +01:00
Wendelin b89b02e044 Open quick search quicker (#29967) 2026-03-04 11:13:13 +01:00
renovate[bot] daff323606 Update dependency lint-staged to v16.3.1 (#29970)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-04 11:35:06 +02:00
Paul Bottein 356bceb1cc Simplify mock entities in demo (#29960)
* Simplify mock entities in demo

* Clean unused file
2026-03-04 11:22:35 +02:00
renovate[bot] acb5af2f41 Update dependency globals to v17.4.0 (#29966)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-04 09:10:02 +00:00
Marcin BauerandWendelin 17314fe62b Add animation duration tokens and button transition update (#29965)
Co-authored-by: Wendelin <[email protected]>
2026-03-04 08:36:37 +00:00
sevorl 3826a69465 Use ha-form for wait_for_trigger timeout (#29944) 2026-03-04 08:48:57 +01:00
Matthias de BaatandAlCalzone a68acdf9dd Update delete Z-Wave device dialog (#29956)
* Update text and spacing

* Update text

* Update src/translations/en.json

Co-authored-by: AlCalzone <[email protected]>

---------

Co-authored-by: AlCalzone <[email protected]>
2026-03-04 08:35:41 +02:00
Paul Bottein bb56bbb1ba Align heading button font-size with other heading entity badge (#29958) 2026-03-04 08:08:22 +02:00
Bram Kragten 76aef60c05 Add hass url to brand images (#29961) 2026-03-03 21:00:43 +01:00
renovate[bot] 23af40743b Update dependency lint-staged to v16.3.0 (#29954)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-03 14:36:48 +00:00
Paul Bottein c4326b4f3a Use max width for dashboard footer (#29947) 2026-03-03 14:57:57 +01:00
Paul Bottein d248f5614f Add label for toggle button in area strategy (#29949) 2026-03-03 13:34:05 +01:00
a4da7b26ea Fix copy to clipboard for wa dialogs (#29951)
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2026-03-03 13:09:30 +01:00
Wendelin 3c49cdf3c0 ha-bottom-sheet reduce motion support (#29950) 2026-03-03 11:06:23 +00:00
Petar Petrov 26af81d1a4 Use net battery power in power sankey card (#29940) 2026-03-03 11:53:54 +01:00
Aidan Timson 2a08f2d79b Add tooltip for config dashboard action button in toolbar (#29948) 2026-03-03 10:33:37 +01:00
Marcin Bauer a5be02b743 Add tooltip for Lovelace dropdown action button in top app bar (#29933) 2026-03-03 09:15:37 +00:00
sevorl 4228871f00 Fix missing slot attribute on wa-divider in automation sidebar action (#29942) 2026-03-03 08:56:33 +00:00
Wendelin 9a7a8fd377 Add reportValidity in ha-form (#29884)
* Add validation for required fields in ha-auth-flow before submission

* Add reportValidity methods to form components for improved validation handling

* Remove async reportValidity funcs

* Review
2026-03-03 09:05:49 +02:00
Wendelin 8b82882e15 ha-authorize fix rtl check (#29937)
Add RTL direction handling in updated lifecycle method
2026-03-02 18:22:06 +01:00
Bram Kragten 15de137591 Bumped version to 20260302.0 2026-03-02 17:08:01 +01:00
Paul Bottein 465c10b945 Fix updates, discovered devices and repairs cards flickering (#29935) 2026-03-02 17:07:10 +01:00
Paul Bottein 457c51cf58 Fix sidebar not closing when reduced motion is enabled (#29934) 2026-03-02 17:07:09 +01:00
Wendelin 640f2b9245 Dialog: Add show event target check (#29927)
Add event phase check in _handleShow and _handleAfterShow methods
2026-03-02 17:07:07 +01:00
Aidan Timson 852caa32be Remove cache to fix re-add repo issue (#29926)
Remove cache to fix readd repo issue
2026-03-02 17:07:06 +01:00
Wendelin 67ccfa0f6e Add error translation for loading energy preferences (#29924) 2026-03-02 17:07:05 +01:00
karwosts c3cc566fe3 Fix distribution card stub error (#29915)
* Fix distribution card stub error

* unit check not required
2026-03-02 17:07:03 +01:00
Paul Bottein 38d02a3f30 Fix control select menu color in ios (#29892) 2026-03-02 17:07:01 +01:00
Bram Kragten ad1d1e2260 Fix overflow for icon buttons (#29891) 2026-03-02 17:07:00 +01:00
Petar Petrov b2eb8ec968 Make hui-sections-view always fill the screen so footer is at the bottom (#29890) 2026-03-02 17:06:59 +01:00
Petar Petrov 7b8884f0fd Fix sensor card graph not updating when value is unchanged (#29889) 2026-03-02 17:06:57 +01:00
Petar Petrov aff1fedc9d Fix monetary device class state display with non-ISO 4217 currency symbols (#29887) 2026-03-02 17:06:56 +01:00
Petar Petrov 8f5059c24a Fix energy compare tooltip showing wrong year (#29885) 2026-03-02 17:06:54 +01:00
Aidan TimsonandBram Kragten 1e72ad1411 Code editor fullscreen in dialogs (#29882)
Co-authored-by: Bram Kragten <[email protected]>
2026-03-02 17:06:53 +01:00
Paul Bottein c9f96bbe69 Add render icon property to ha-control-select-menu (#29881) 2026-03-02 17:06:52 +01:00
Aidan Timson 616c3d4657 Use large width on system log dialogs (#29879) 2026-03-02 17:06:50 +01:00
Robert Resch b1ceece224 Revert "Add vacuum mapping not configured issue" (#29876) 2026-03-02 17:06:49 +01:00
Brandon Chen d695c4c845 Fix YAML content invisible in dark mode for conversation debug result… (#29874) 2026-03-02 17:06:48 +01:00
Petar Petrov fdbeb12622 Migrate Energy date selector to new footer (#29867) 2026-03-02 17:04:41 +01:00
Aidan TimsonandBram Kragten 29ede122a1 Add audits and yaml mode to more info details (#29854)
* Add audits and yaml mode to more info details

* Reset yaml mode on back

* Use mapped array for state entries

* Typo

Co-authored-by: Bram Kragten <[email protected]>

* Memoize

* Rename

* Fix

* Format audits in normal mode

* Refactor, dont pass hass

---------

Co-authored-by: Bram Kragten <[email protected]>
2026-03-02 17:04:40 +01:00
Matthias AlphartandCopilot 519d3d0e53 Fix data-table content bottom margin (#29805)
Co-authored-by: Copilot <[email protected]>
2026-03-02 17:04:39 +01:00
Matthias AlphartandCopilot 2701015eda Fix data-table content bottom margin (#29805)
Co-authored-by: Copilot <[email protected]>
2026-03-02 17:02:31 +01:00
Aidan TimsonandBram Kragten 1991a9e493 Code editor fullscreen in dialogs (#29882)
Co-authored-by: Bram Kragten <[email protected]>
2026-03-02 17:01:13 +01:00
Petar Petrov 2b72c54194 Migrate Energy date selector to new footer (#29867) 2026-03-02 17:00:34 +01:00
Paul Bottein a7cb2fe7a7 Fix updates, discovered devices and repairs cards flickering (#29935) 2026-03-02 13:50:42 +00:00
Paul Bottein 51ea0c8201 Fix sidebar not closing when reduced motion is enabled (#29934) 2026-03-02 13:19:26 +00:00
Wendelin ead7081bc6 Dialog: Add show event target check (#29927)
Add event phase check in _handleShow and _handleAfterShow methods
2026-03-02 11:41:52 +00:00
Wendelin ee982b1899 Add error translation for loading energy preferences (#29924) 2026-03-02 11:49:46 +02:00
Aidan Timson e8b100a39e Remove cache to fix re-add repo issue (#29926)
Remove cache to fix readd repo issue
2026-03-02 11:49:19 +02:00
50c361db62 Add mixin to remove code duplication in automation/script editors (#29842)
* Initial plan

* Changes before error encountered

Co-authored-by: wendevlin <[email protected]>

* Fix mixin: use function-body syntax for decorators, curried generics for type safety

Co-authored-by: wendevlin <[email protected]>

* Simplify automation/script editor mixin signature

* Add shared styles and loading animation to automation/script editor mixin

Co-authored-by: wendevlin <[email protected]>

* Remove underscore prefix from protected members per style guide

Co-authored-by: wendevlin <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: wendevlin <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2026-03-02 11:44:04 +02:00
sevorl e7a8d15a13 Use ha-duration-input for wait_template timeout (#29862) 2026-03-02 09:07:51 +01:00
karwosts fbd0409837 Init ha-form expansion elements to undefined instead of null (#29900)
* Init ha-form expansion elements to undefined instead of null

* revert change to error/warning
2026-03-02 09:29:06 +02:00
karwosts a0d100611f Fix distribution card stub error (#29915)
* Fix distribution card stub error

* unit check not required
2026-03-02 09:06:10 +02:00
dependabot[bot] a969bf1065 Bump actions/upload-artifact from 6.0.0 to 7.0.0 (#29922)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6.0.0 to 7.0.0.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/b7c566a772e6b6bfb58ed0dc250532a479d7789f...bbbca2ddaa5d8feaa63e36b76fdaad77386f024f)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-02 06:10:19 +00:00
renovate[bot] a153330610 Update dependency gulp-zopfli-green to v7 (#29919)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-02 07:06:41 +01:00
renovate[bot] bd2f1ca3a8 Update dependency @html-eslint/eslint-plugin to v0.57.1 (#29905)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-28 20:08:37 +01:00
renovate[bot] 3263034416 Update dependency @codemirror/language to v6.12.2 (#29904)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-28 20:07:43 +01:00
Paul Bottein 82b28b547a Fix control select menu color in ios (#29892) 2026-02-27 17:26:04 +01:00
Bram Kragten 61c2c750b4 Fix overflow for icon buttons (#29891) 2026-02-27 15:44:21 +00:00
Petar Petrov 117690ee70 Fix sensor card graph not updating when value is unchanged (#29889) 2026-02-27 15:41:54 +00:00
Petar Petrov e753de85eb Make hui-sections-view always fill the screen so footer is at the bottom (#29890) 2026-02-27 15:39:21 +00:00
Paul Bottein a240019968 Add render icon property to ha-control-select-menu (#29881) 2026-02-27 16:23:58 +01:00
Petar Petrov 0bdf4b8777 Fix monetary device class state display with non-ISO 4217 currency symbols (#29887) 2026-02-27 14:59:14 +01:00
renovate[bot] 6337828ed8 Update dependency barcode-detector to v3.1.0 (#29886)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-27 15:46:29 +02:00
Aidan TimsonandBram Kragten b8e5af652b Add audits and yaml mode to more info details (#29854)
* Add audits and yaml mode to more info details

* Reset yaml mode on back

* Use mapped array for state entries

* Typo

Co-authored-by: Bram Kragten <[email protected]>

* Memoize

* Rename

* Fix

* Format audits in normal mode

* Refactor, dont pass hass

---------

Co-authored-by: Bram Kragten <[email protected]>
2026-02-27 14:45:55 +01:00
Petar Petrov e4ae29e8b5 Fix energy compare tooltip showing wrong year (#29885) 2026-02-27 14:37:52 +01:00
Aidan Timson 08231dbbb0 Use large width on system log dialogs (#29879) 2026-02-27 12:46:10 +01:00
Paul Bottein 0ca656933d Revert "Add render icon property to ha-control-select-menu"
This reverts commit b23cf8eba4.
2026-02-27 12:21:23 +01:00
Paul Bottein b23cf8eba4 Add render icon property to ha-control-select-menu 2026-02-27 12:20:52 +01:00
Robert Resch 61b546415d Revert "Add vacuum mapping not configured issue" (#29876) 2026-02-27 11:18:49 +01:00
Brandon Chen 4e1b709303 Fix YAML content invisible in dark mode for conversation debug result… (#29874) 2026-02-27 09:11:28 +01:00
renovate[bot] 34e65b302d Update dependency typescript-eslint to v8.56.1 (#29868)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-26 18:08:04 +00:00
renovate[bot] 336d0e1b9d Update dependency @html-eslint/eslint-plugin to v0.57.0 (#29863)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-26 17:25:10 +01:00
Bram Kragten 030a9a492c Bumped version to 20260226.0 2026-02-26 16:56:33 +01:00
Paul Bottein 2685a007e7 Fix scrollbar in 2026.3 (#29865) 2026-02-26 16:55:15 +01:00
Aidan Timson 9ca1cfbf4a Add thread configuration my link (#29861) 2026-02-26 16:55:14 +01:00
Aidan Timson 0793af6846 Add matter configuration my link (#29859) 2026-02-26 16:55:13 +01:00
Wendelin bb7f441d8d Fix quick search icon size (#29858) 2026-02-26 16:55:12 +01:00
Aidan Timson 2813ed7938 Add missing theming variable support to dialog and bottom sheet (#29857) 2026-02-26 16:55:10 +01:00
Wendelin 9ebfa4029b Fix ha-icon-button-toggle selected style (#29856) 2026-02-26 16:55:10 +01:00
Aidan Timson 6190ba18ea Fix esc closing dialogs with prevent scrim close (#29851) 2026-02-26 16:55:09 +01:00
Petar Petrov 81feea1109 Dynamically calculate the date range picker's vertical opening direction (#29850) 2026-02-26 16:55:08 +01:00
Wendelin be430931cc Fix protocols dashboards fab padding (#29847) 2026-02-26 16:55:07 +01:00
Petar Petrov e07194027a Convert Energy Now tiles to badges (#29845) 2026-02-26 16:55:05 +01:00
Paul Bottein 58d4cf8d84 Fix scrollbar in 2026.3 (#29865) 2026-02-26 16:44:12 +01:00
Aidan Timson d3453aff37 Add missing theming variable support to dialog and bottom sheet (#29857) 2026-02-26 16:43:20 +01:00
Aidan Timson 64ff2e414c Add thread configuration my link (#29861) 2026-02-26 15:06:46 +00:00
Wendelin 2ca25c980f Fix quick search icon size (#29858) 2026-02-26 15:59:27 +01:00
Aidan Timson 73d93bc601 Add matter configuration my link (#29859) 2026-02-26 14:41:43 +00:00
Wendelin 5ca6a8aced Fix ha-icon-button-toggle selected style (#29856) 2026-02-26 13:02:12 +00:00
Aidan Timson 7ff4993e0b Fix esc closing dialogs with prevent scrim close (#29851) 2026-02-26 13:20:05 +02:00
Norbert Rittel 4e6fbacccc Remove trailing periods from "Learn more" etc. links / tooltips (#29835) 2026-02-26 10:38:54 +00:00
Petar Petrov 2958d49e36 Convert Energy Now tiles to badges (#29845) 2026-02-26 10:38:01 +00:00
Norbert Rittel 92289dc7ea Improve "Create a new … helper" option in entity picker (#29853) 2026-02-26 10:34:42 +00:00
Petar Petrov f6c1a890e4 Dynamically calculate the date range picker's vertical opening direction (#29850) 2026-02-26 09:33:34 +00:00
Wendelin d06321ed43 Fix protocols dashboards fab padding (#29847) 2026-02-26 10:31:50 +02:00
dependabot[bot] 3c3d8d9974 Bump rollup from 2.79.2 to 2.80.0 (#29841)
Bumps [rollup](https://github.com/rollup/rollup) from 2.79.2 to 2.80.0.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/v2.80.0/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v2.79.2...v2.80.0)

---
updated-dependencies:
- dependency-name: rollup
  dependency-version: 2.80.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-26 08:18:15 +02:00
Paul Bottein 4f39fa482d Only ask to refresh dashboard in edit mode or yaml mode (#29826) 2026-02-26 08:16:21 +02:00
renovate[bot] 5d0fe3236c Update dependency @swc/helpers to v0.5.19 (#29836)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-26 07:07:37 +01:00
renovate[bot] b86142ae50 Update Node.js to v24.14.0 (#29831)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-25 19:25:42 +00:00
renovate[bot] 5d2f3ee5e8 Update dependency tar to v7.5.9 (#29832)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-25 19:24:58 +00:00
AlCalzone e3f7c631a7 Rename "Z-Wave JS" to "Z-Wave" when not referring to the project/org (#29830) 2026-02-25 19:15:16 +00:00
renovate[bot] 49f9d95853 Update dependency vite-tsconfig-paths to v6.1.1 (#29829)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-25 18:53:12 +01:00
renovate[bot] db3d7701b5 Update dependency typescript-eslint to v8.56.0 (#29828)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-25 17:35:36 +00:00
renovate[bot] 3e55acf531 Update dependency @home-assistant/webawesome to v3.2.1-ha.3 (#29810)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-25 18:26:47 +01:00
renovate[bot] f102618d9d Update dependency eslint-plugin-wc to v3.1.0 (#29824)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-25 18:25:06 +01:00
renovate[bot] a3c02b511d Update dependency jsdom to v28.1.0 (#29825)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-25 18:24:38 +01:00
Bram Kragten 74111d248e Fix css minifying (#29827) 2026-02-25 17:53:50 +01:00
Bram Kragten 17d9cd192f Bumped version to 20260225.0 2026-02-25 17:14:36 +01:00
Bram Kragten f8161b3505 Merge branch 'rc' into dev 2026-02-25 17:13:44 +01:00
Franck NijhofandBram Kragten 6070c1907a Adjust brands assets to proxy brand images through local API (#29799)
Co-authored-by: Bram Kragten <[email protected]>
2026-02-25 17:10:38 +01:00
renovate[bot] ce5991582c Update dependency @html-eslint/eslint-plugin to v0.56.0 (#29818)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-25 17:37:34 +02:00
Paul Bottein d17217fc90 Use show in sidebar property instead of checking title (#29815) 2026-02-25 16:37:25 +01:00
renovate[bot] 86b4bd0013 Update dependency eslint-plugin-lit to v2.2.1 (#29821)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-25 17:36:42 +02:00
renovate[bot] 108ba3abd6 Update dependency eslint-plugin-unused-imports to v4.4.1 (#29822)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-25 17:36:12 +02:00
Matthias Alphart d38a2894c4 Remove unused properties in ha-data-table and hass-tabs-subpage-data-table (#29808) 2026-02-25 16:31:39 +01:00
Aidan Timson 4c70376a62 Cleanup old comments (#29823) 2026-02-25 15:24:00 +00:00
Wendelin 8d69bd1401 Fix button active also for icon-buttons (#29820) 2026-02-25 16:21:31 +01:00
renovate[bot] 5dfecd3693 Update dependency @octokit/plugin-retry to v8.1.0 (#29819)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-25 15:09:19 +00:00
Aidan Timson efd51d2234 Rename more info "Attributes" to "Details", add raw state and all available attributes (#29811) 2026-02-25 15:57:27 +01:00
renovate[bot] 668299c16a Update dependency marked to v17.0.3 (#29817)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-25 16:00:51 +02:00
renovate[bot] 5e155a4030 Update dependency glob to v13.0.6 (#29816)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-25 16:00:25 +02:00
gpoitch 809fa10135 Add day of week to energy chart tooltips (#29803)
* Add day of week to energy chart tooltips

* New localization helpers
2026-02-25 13:31:00 +00:00
Petar Petrov 1cbc38f231 Water flow rate sankey chart in Now view (#29804) 2026-02-25 14:18:48 +01:00
renovate[bot] 9ed39bb523 Update dependency @rspack/core to v1.7.6 (#29812)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-25 15:10:38 +02:00
renovate[bot] 4e3d66cf40 Update dependency eslint to v9.39.3 (#29813)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-25 15:10:03 +02:00
renovate[bot] 2eaad79d1c Update dependency @codemirror/view to v6.39.15 (#29807)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-25 12:47:06 +02:00
renovate[bot] afef7a2c0f Update dependency @bundle-stats/plugin-webpack-filter to v4.21.10 (#29806)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-25 12:46:41 +02:00
renovate[bot] 18d5224002 Update dependency @formatjs/intl-datetimeformat to v7.2.2 (#29809)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-25 12:46:08 +02:00
Johan Henkens dbffdfeaca Add cover of device type window to the security dashboard (#29797) 2026-02-25 11:11:13 +01:00
Artur Pragacz 0a4b7917ab Update vacuum segment mapping description (#29802) 2026-02-25 08:38:37 +01:00
Simon Lamon e1524358d9 Remove duplicated buttons (#29798) 2026-02-25 08:22:40 +01:00
Artur Pragacz 8774f9c3fc Add vacuum mapping not configured issue (#29800) 2026-02-25 08:14:38 +01:00
Wendelin f9a9aeacab Fix app panel narrow header safe area top (#29792)
* Enhance narrow property to reflect changes and adjust header padding for safe area

* Remove safe-area-inset-top for narrow iframe

* handle kiosk mode
2026-02-24 20:26:06 +01:00
ildar170975 b798fee116 Data tables: keep "Actions" as the last column (#29364)
* Data tables: keep "Actions" as the last column

* last_fixed -> lastFixed

* last_fixed -> lastFixed

* last_fixed -> lastFixed

* last_fixed -> lastFixed

* last_fixed -> lastFixed

* last_fixed -> lastFixed

* last_fixed -> lastFixed

* last_fixed -> lastFixed

* last_fixed -> lastFixed

* last_fixed -> lastFixed

* simplify

* Update dialog-data-table-settings.ts

* narrow down a column

* blank line added

* narrow dow Assistants a bit more

* remove moveable/hideable for "actions"

* remove moveable/hideable for "actions"

* remove moveable/hideable for "actions"

* remove moveable/hideable for "actions"

* remove moveable/hideable for "actions"

* remove moveable/hideable for "actions"

* remove moveable/hideable for "actions"

* remove moveable/hideable for "actions"
2026-02-24 20:24:53 +01:00
Norbert Rittel b25f731f0f Simplify card descriptions using "This …" instead of repeating the name (#29795)
Simplify card description using "This …" instead of repeating the name
2026-02-24 20:17:05 +01:00
Paul Bottein 26a7372c5e Don't show label for toggle all lights and align individual lights (#29794) 2026-02-24 17:28:53 +01:00
Paul Bottein 70d3409d62 Don't use navigation history when using tabs (#29791) 2026-02-24 18:03:48 +02:00
Wendelin 0711ecddab Handle selector edge case for [] (#29790) 2026-02-24 15:30:29 +00:00
Petar Petrov bcfaa67eba Add power, water and gas current flow rate tile cards (#29788) 2026-02-24 16:01:32 +01:00
1b60e6e04e Reorganize Zigbee settings page (#29671)
Co-authored-by: TheJulianJES <[email protected]>
Co-authored-by: Norbert Rittel <[email protected]>
Co-authored-by: Bram Kragten <[email protected]>
2026-02-24 15:11:36 +01:00
a1a634f6dc Add footer card support to sections view (#29620)
Co-authored-by: Wendelin <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2026-02-24 11:00:50 +00:00
Petar Petrov 55f48fbb56 Add tabs to energy config page (#29689) 2026-02-24 09:43:02 +00:00
Norbert Rittel ca4d66b94c Change second tab to "Electricity" in Energy dashboard (#29787) 2026-02-24 10:13:22 +01:00
Aidan TimsonandBram Kragten 51fd2eedd9 Update gallery with latest adaptive dialog changes (#29672)
* Update gallery with latest adaptive dialog changes

* Update gallery/src/pages/components/ha-adaptive-dialog.ts

Co-authored-by: Bram Kragten <[email protected]>

* Format

---------

Co-authored-by: Bram Kragten <[email protected]>
2026-02-24 06:57:31 +01:00
ildar170975 434a7c2e93 "Numeric state" trigger editor: add a "filter_entity" context to "attribute" selector (#29778)
* add a "filter_entity" context to "attribute" selector

* remove unused variable
2026-02-24 07:55:49 +02:00
Petar PetrovandNorbert Rittel b849fecf0b Add flow rate picker to gas, water, and water device energy dialogs (#29693)
* Add flow rate picker to gas, water, and water device energy dialogs

Add optional flow rate (stat_rate) picker to gas source, water source,
and water device configuration dialogs, matching the pattern used for
power tracking in grid/solar/battery sources and energy devices.

- Add stat_rate to GasSourceTypeEnergyPreference and WaterSourceTypeEnergyPreference
- Collect gas/water stat_rate in getReferencedStatisticIdsPower()
- Add flow rate ha-statistic-picker filtered to volume_flow_rate device class
- Move entity help text to picker helper props for cleaner layout

* Apply suggestions from code review

Co-authored-by: Norbert Rittel <[email protected]>

---------

Co-authored-by: Norbert Rittel <[email protected]>
2026-02-24 06:55:35 +01:00
ildar170975 3a48e1996f hui-entities-card: fix "buttons-header-footer" margin-bottom (#29783)
* fix margin-bottom for hui-buttons-header-footer

* typo
2026-02-24 07:54:50 +02:00
ildar170975 8299386737 ha-entity-attribute-picker: add valueRenderer (#29780)
add valueRenderer
2026-02-24 06:52:10 +01:00
Raphael Hehl 5e58ff476f Re-initialize camera stream when backend finishes starting (#29752) 2026-02-23 16:59:53 +01:00
758d955053 Add configuration to built-in panels (#29572)
Co-authored-by: Norbert Rittel <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-02-23 16:15:54 +01:00
Kevin Stillhammer 1efd5d26f0 Show allow_negative in DurationSelector options (#29775) 2026-02-23 16:02:33 +01:00
Aidan Timson 36979f10cc Fix types for dialog hide events (#29777) 2026-02-23 15:54:36 +01:00
Aidan Timson 812c59fcb4 Add missing back path for protocol config dashboards (#29770) 2026-02-23 15:36:50 +01:00
karwosts 0c34165bcf Disallow moving a section to non-sections view (#29756) 2026-02-23 10:54:11 +00:00
Matthias de BaatandNorbert Rittel 8c2bfbe9ce Reorganize Matter settings (#29708)
Co-authored-by: Norbert Rittel <[email protected]>
2026-02-23 10:31:38 +00:00
Aidan Timson 8f721d74e2 Fix swipe action bubbling up to stacked bottom drawer/sheet (#29768) 2026-02-23 10:26:10 +01:00
dependabot[bot] 63782e6ef3 Bump lodash from 4.17.21 to 4.17.23 (#29767)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-23 10:22:31 +01:00
Marie-Alice BleteandMarie-Alice Blete eaad2295a9 Fix ZHA config dashboard button animation targeting (#29744)
Co-authored-by: Marie-Alice Blete <[email protected]>
2026-02-23 10:18:32 +01:00
Norbert Rittel e74eee3d34 Make all picker strings of Frontend conditions consistent (#29742) 2026-02-23 09:54:14 +01:00
karwosts cc39010839 Fix group more-info names for not-in-registry entities (#29758) 2026-02-23 09:50:55 +01:00
Kevin Stillhammer 7f97425214 Allow to disable seconds in DurationSelector (#29760) 2026-02-23 09:30:04 +01:00
dependabot[bot] 8fac6e63de Bump actions/stale from 10.1.1 to 10.2.0 (#29765)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-23 09:22:29 +01:00
dependabot[bot] 2ac8fe2b21 Bump github/codeql-action from 4.32.3 to 4.32.4 (#29766)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-23 09:22:18 +01:00
Aidan Timson 45ca1b2cdc Fix esc closing all dialogs or sheets (close one after another) (#29732) 2026-02-23 09:13:28 +01:00
Matthias de BaatandPetar Petrov 0667f1e789 Reorganize Bluetooth settings (#29723)
* Reorganize Bluetooth settings

* Additional changes

* Updates adapter page

* Update statuses

* Fix button icon

* Update en.json

Co-authored-by: Petar Petrov <[email protected]>

* Update bluetooth-adapter-info-page.ts

Co-authored-by: Petar Petrov <[email protected]>

* Update text

* Show GATT message and make row clickable

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-02-23 06:59:09 +01:00
Norbert Rittel db49678ccb Make descriptions of Frontend actions consistent with Core (#29740) 2026-02-20 18:03:19 +01:00
Norbert Rittel 2ca7e9f71e Make building block descriptions consistent with new conditions (#29739)
Make building block descriptions consistent with conditions
2026-02-20 18:02:41 +01:00
karwosts 8d883450a8 Add year period to stat graph card editor (#29741)
Add year period to stat graph card
2026-02-20 18:02:07 +01:00
dependabot[bot]andPetar Petrov 2c136e00f5 Bump tar from 7.5.7 to 7.5.8 (#29735)
* Bump tar from 7.5.7 to 7.5.8

Bumps [tar](https://github.com/isaacs/node-tar) from 7.5.7 to 7.5.8.
- [Release notes](https://github.com/isaacs/node-tar/releases)
- [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/isaacs/node-tar/compare/v7.5.7...v7.5.8)

---
updated-dependencies:
- dependency-name: tar
  dependency-version: 7.5.8
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <[email protected]>

* dedupe

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <[email protected]>
2026-02-20 07:05:32 +00:00
RoboMagus 6f82478598 Fix header tab height (#29736)
Fix header tabs to header height
2026-02-20 08:48:43 +02:00
Aidan Timson 1093bd890f Add missing helper to ha-select, remove unused attr (#29729) 2026-02-19 18:54:29 +01:00
Aidan TimsonandCopilot 456c638750 Use ha-scrollbar in config dashboard (#29724)
* Use ha-scrollbar in config dashboard

* Remove padding

Co-authored-by: Copilot <[email protected]>

* Add padding to bottom

---------

Co-authored-by: Copilot <[email protected]>
2026-02-19 18:52:32 +01:00
60ca50deb4 Add a drag handle visual indicator to bottom sheet (#29707)
* Add drag handle to bottom sheet

* Remove locks

* Fix rounded corners

* Restore original functionality, keep visual indicator

* Add padding to combo box

* Apply suggestion from @wendevlin

* Fix prettier

* Shorter height

Co-authored-by: Marcin Bauer <[email protected]>

* Half width

Co-authored-by: Marcin Bauer <[email protected]>

* Restore after rebase

* Reduce space for picker

---------

Co-authored-by: Wendelin <[email protected]>
Co-authored-by: Wendelin <[email protected]>
Co-authored-by: Marcin Bauer <[email protected]>
2026-02-19 14:24:09 +01:00
Matthias de Baat 2064ab4141 Reorganize Z-Wave settings page (#29697)
* Reorganize ZWave settings

* Next iteration

* Made more consistent with Zigbee settings page

* Update text

* Updates on the provisioned devices page

* Add identifier when you have multiple networks

* Update to force remove button

* Update button text

* Update rebuild text

* Update remove foreign device button text
2026-02-19 13:45:35 +02:00
karwosts d34c42e587 Refine supported actions in button heading badge (#29718) 2026-02-19 12:49:30 +02:00
Joakim Sørensen 5da7bf6fba Add repository handling for missing addons in HaConfigAppDashboard (#29722)
* Add repository handling for missing addons in HaConfigAppDashboard

* Implement feedback

* More adjustments

* minor adjustment
2026-02-19 10:36:34 +00:00
Norbert Rittel f05ff58d27 Replace "consumption" with "usage" for battery and grid energy (#29719)
Replace "consumption" with "usage" for battery and grid power
2026-02-19 10:59:47 +02:00
Aidan Timson 7b0a381d93 Use ha-scrollbar with history panel, fix overflow position (#29715)
Use ha-scrollbar with history panel
2026-02-18 18:04:46 +01:00
Aidan Timson 8b38e6d170 Switch dialog device registry detail to adaptive dialog (#29713) 2026-02-18 18:04:05 +01:00
Aidan Timson 6daf0eb469 Use ha-scrollbar with media browser (#29714) 2026-02-18 18:03:26 +01:00
Wendelin 6f8f849af3 Prevent bottom-sheet from closing from child elements (#29716)
Fix handling of after hide event in ha-bottom-sheet component
2026-02-18 16:19:43 +00:00
Aidan Timson cafe0f62c6 Trigger add todo item dialog via search param (#29690)
* Fix scrim closure

* Trigger add todo item dialog via add_item=true search param

* Check supports before opening prompt

* Use in willUpdate

* Add subtitle as context using name of list
2026-02-18 16:28:20 +01:00
WendelinandBram Kragten 721cf46ce5 Migrate ha-icon-button to webawesome (#29622)
* Remove mwc-icon-button dependency and update ha-icon-button to use ha-button component

* --mdc-icon-button-size to --ha-icon-button-size

* Refactor ha-icon-button styles to improve encapsulation and remove redundant CSS rules

* add href functionality

* Migrate a wrapped ha-icon-button to ha-icon-button

* Update slot reference for ha-icon-button in hui-dialog-save-config

* fix overflow trigger

* Review

* fix sub icon buttons

* Fix attribute binding for href and target in ha-icon-button-next

* Fix binding for href and target properties in ha-icon-button

* Update src/layouts/hass-tabs-subpage.ts

Co-authored-by: Bram Kragten <[email protected]>

* Update src/panels/lovelace/editor/hui-dialog-save-config.ts

Co-authored-by: Bram Kragten <[email protected]>

* Update src/panels/lovelace/editor/badge-editor/hui-dialog-edit-badge.ts

Co-authored-by: Bram Kragten <[email protected]>

* Update src/panels/config/labs/ha-config-labs.ts

Co-authored-by: Bram Kragten <[email protected]>

* Fix icon-button slot

* Update src/components/ha-icon-button.ts

Co-authored-by: Bram Kragten <[email protected]>

---------

Co-authored-by: Bram Kragten <[email protected]>
2026-02-18 16:18:28 +01:00
Marcin Bauer 4e087760ab Fix chip order in automation save dialog to match field order (#29710) 2026-02-18 15:18:07 +00:00
Aidan TimsonandWendelin 8fcfd4be84 Move scrolling for dashboards inside view container (#29444)
* Move scrolling for dashboards inside view container

* Use scrollbar styles on host

* Cleanup

* Inline

Co-authored-by: Wendelin <[email protected]>

---------

Co-authored-by: Wendelin <[email protected]>
2026-02-18 16:17:13 +01:00
Wendelin b03680a8ab ha-automation-action-condition use generic-picker (#29702)
Refactor ha-automation-action-condition to use ha-generic-picker and improve condition rendering
2026-02-18 15:14:25 +00:00
ildar170975andPetar Petrov 7ab0622bec cloud-tts-pref: fix for language picker (#29678)
* fix styles to prevent oveflow

* use a new variable to define min-width

* pass a "minWidth" property into ha-language-picker

* use a "minWidth" property for ha-generic-picker

* Update ha-language-picker.ts

* pass empty minWidth

* do not set min-width if empty

* add a style for ha-language-picker

* remove a style for ha-language-picker

* add a style for ha-language-picker

* remove min-width

* add a style for ha-language-picker

* Update src/panels/profile/ha-pick-language-row.ts

Co-authored-by: Petar Petrov <[email protected]>

* add a gap

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-02-18 14:05:41 +00:00
Bram Kragten c5aad44768 Add support for vacuum segment mapping to areas (#29343)
* Add support for vacuum segment mapping to areas

* simplify, use list item

* Update ha-more-info-view-vacuum-segment-mapping.ts

* review

* review

* Update dialog-vacuum-segment-mapping.ts
2026-02-18 14:11:17 +01:00
Icecovery 20ee7e5dc7 Split antimeridian-crossing paths in ha-map (#29694)
* Add option to split antimeridian-crossing path to ha-map

and map card with related editor options

* Remove split antimeridian-crossing option in ha-map

making it the default behavior, as suggested by @karwosts. And remove the option from the map card

* Fix longitudeDifference is zero edge case
2026-02-18 12:08:03 +00:00
Petar PetrovandWendelin 32fdcc708e Fix history timeline showing same color for all zones (#29700)
* Fix history timeline showing same color for all zones

For person and device_tracker entities, zone states (e.g. "Kitchen",
"Office") all resolved to --state-person-active-color because their
zone-specific CSS variables don't exist and the fallback chain always
landed on the generic active color.

Now zone states only check for an explicitly defined CSS variable
(e.g. --state-person-kitchen-color) and otherwise fall through to the
generic color handler which assigns a unique palette color per zone.

Fixes #14705

* Update src/components/chart/timeline-color.ts

Co-authored-by: Wendelin <[email protected]>

---------

Co-authored-by: Wendelin <[email protected]>
2026-02-18 10:45:15 +01:00
Aidan TimsonandWendelin 7dd9b3308e Switch more info dialog to adaptive dialog (#29664)
* Switch more info dialog to adaptive dialog

* Remove old attr

* Fixed height

* Add dialog styles for ha-adaptive-dialog, fixes fixed top

* Lock swipe for moveable components

* Add more components

* Add locked classes

* Refactor

* Revert "Refactor"

This reverts commit 041161715e.

* Merge for loops

* Use events to track slider interaction and prevent bottom sheet closure

* Update src/components/ha-bottom-sheet.ts

* Update src/resources/styles.ts

---------

Co-authored-by: Wendelin <[email protected]>
2026-02-18 08:55:11 +01:00
Aidan Timson 71b870be15 Fix styles for manage zha device dialog (#29684)
* Fix styles for manage zha device dialog

* Prevent scrim close
2026-02-18 09:41:45 +02:00
Simon Lamon f08c5fa03a Assign no-stale to Tasks/Epic/Opportunity issue type (#29698)
* Enhance issue creation restrictions and labeling

Added functionality to restrict Task issue creation to organization members, authorized contributors, and integration code owners. Updated permissions and added a no-stale label for specific issue types.

* Refactor Task issue authorization checks

* Update github-script action and enhance Task issue handling
2026-02-18 09:37:31 +02:00
Wendelin fca408ae23 Upgrade webawesome to version 3.2.1-ha.2 (#29691)
Upgrade webawesome to version 3.2.1-ha.2 and adjust animation durations to 0ms
2026-02-18 08:35:23 +02:00
Aidan Timson f3a814e38a Cleanup dialog default width attrs (#29686) 2026-02-17 20:13:27 +01:00
Aidan TimsonandPetar Petrov 7b0e4651c4 Fix iframe flash for dark theme using transition (#29685)
* Fix iframe flash for light mode using transition

* Use normal duration

Co-authored-by: Petar Petrov <[email protected]>

* Use normal duration

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-02-17 16:53:06 +02:00
Petar Petrov e5fb0e21ec Update animation duration variable names in copilot instructions (#29692)
The old `--ha-animation-base-duration` variable was split into three
separate variables: `--ha-animation-duration-fast` (150ms),
`--ha-animation-duration-normal` (250ms), and
`--ha-animation-duration-slow` (350ms).
2026-02-17 14:42:00 +01:00
Wendelin beb4c3bf8a Fix panel safe area subpage usage (#29688) 2026-02-17 11:24:48 +00:00
Aidan Timson ad41f91c7b Fix lovelace tab overflow fade height (#29687) 2026-02-17 13:15:49 +02:00
Wendelin dc9c20f4ac Fix custom panel size (#29681) 2026-02-17 10:06:51 +00:00
Aidan Timson 776840a527 Add prevent-scrim-close to energy config dialogs (#29682)
Add  prevent-scrim-close to energy config dialogs
2026-02-17 11:39:39 +02:00
Aidan Timson 3568d8281a Add prevent-scrim-close to 3 form dialogs (#29683)
Add prevent-scrim-close to 3 dialogs
2026-02-17 11:39:10 +02:00
Arsène Reymond 5491b6c023 fix: invisible dashboard header section (#29679)
fix: minimum column count to 1
2026-02-17 06:42:10 +00:00
Simon Lamon e60d8f3ca4 Unflex apps (#29675) 2026-02-16 19:38:25 +00:00
ildar170975 aa0df190ed ha-code-editor: use ha-scrollbar class (#29674)
use ha-scrollbar class
2026-02-16 19:34:53 +00:00
Wendelin 7552e91f24 Fix ha-script-field-row styles (#29658)
Refactor ha-script-field-row styles and replace haStyle with rowStyles
2026-02-16 14:53:54 +00:00
Aidan TimsonandBram Kragten 0c61304023 Finish feature parity for dialog and bottom-sheet with adaptive-dialog (#29669)
* Complete feature parity for dialog and bottom-sheet with adaptive-dialog

* Update src/components/ha-bottom-sheet.ts

Co-authored-by: Bram Kragten <[email protected]>

* use render root

Co-authored-by: Bram Kragten <[email protected]>

* Format

---------

Co-authored-by: Bram Kragten <[email protected]>
2026-02-16 15:52:39 +01:00
Petar Petrov c61bc718c2 Move energy CSV download to period selector overflow menu (#29668)
Extract CSV dump logic from ha-panel-energy into a reusable
downloadEnergyData() utility in data/energy.ts, and add a
"Download data" button to the period selector's overflow menu.
This makes the download accessible from both the energy panel
and energy cards on regular dashboards.
2026-02-16 14:44:21 +00:00
ildar170975 2229e851be cloud-remote-pref: migrate "ha-settings-row -> ha-md-list-item" (#29667)
* ha-settings-row -> ha-md-list-item

* remove "narrow"

* remove "narrow"
2026-02-16 15:10:34 +01:00
Wendelin 32d3b854ca Fix dialogs when reduce motion is active. (#29666)
Reduce dialog and animation durations for improved accessibility
2026-02-16 14:58:19 +01:00
karwosts f5dbb89e25 Add conditions to map card (#29614) 2026-02-16 15:38:48 +02:00
Aidan Timson 2ca47fddd3 Use prevent scrim close on settings form/editor dialogs, add cancel as secondary action (#29656)
* Use prevent scrim close on registry dialogs (forms/editors)

* Add to va pipeline

* Add cancel button

* Add cancel button

* Add cancel

* Prevent scrim close, easily closable, undesired effect

* Prevent scrim closure

* Prevent scrim closure

* Delete or cancel, not both

* Remove cancel, 2 actions per dialog

* Prevent scrim closure
2026-02-16 15:37:47 +02:00
YeonJuan ca21658968 Fix invalid attribute values (#29639)
* Fix invalid attribute values

* Update .yarnrc.yml
2026-02-16 15:33:24 +02:00
ildar170975 d8c1fe7f4d ha-formfield: fix typo "inline -> initial" (#29662)
inline -> initial
2026-02-16 13:51:50 +01:00
Aidan Timson a159a84228 Prevent scrim close on lovelace editor dialogs (#29653)
* Prevent scrim close on lovelace editor dialogs

* Prevent other editors
2026-02-16 14:47:48 +02:00
Florian Schweikert 5c95fa65dd Allow to start typing -0 in float field (#29665)
Prevent replacing "-0" with "0" while typing
2026-02-16 12:45:16 +00:00
Aidan Timson 20cde0ef70 Compute shown entity attributes in one place (#29655)
* Compute shown entity attributes in one place

* Remove type assertion

* Unit tests
2026-02-16 12:54:01 +01:00
Wendelin b0d272bc3d Remove generic-picer backdrop background (#29661)
Style: Update backdrop styling for wa-popover in HaGenericPicker
2026-02-16 11:43:01 +00:00
d844c5b894 Make energy config page consistent (#29452)
* Make energy config page consistent

* Update src/translations/en.json

Co-authored-by: Norbert Rittel <[email protected]>

* small tweaks

---------

Co-authored-by: Norbert Rittel <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-02-16 10:52:24 +00:00
Wendelin 2229d42429 Automation editor: Add continue on error UI for actions (#29603)
* Add continue on error functionality to automation actions

* use checkbox icons
2026-02-16 11:01:11 +01:00
Tom Carpenter 2ba0e77e73 Fix Energy Dialog Localisation (#29654)
`localizeBaseKey` was seemingly being set as an attribute not a property, and therefore failing to apply.
2026-02-16 09:58:51 +00:00
e72facdec8 Replace filled help icon with outlined version (#29625)
* Replace filled help icon with outlined version across frontend

Updated help icon from mdiHelpCircle to mdiHelpCircleOutline for
visual consistency across the application. This change affects help
tooltips and icon buttons in configuration panels, dialogs, and
Lovelace editor components.

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* Update src/panels/config/ha-panel-config.ts

Co-authored-by: Bram Kragten <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>
Co-authored-by: Bram Kragten <[email protected]>
2026-02-16 09:38:59 +01:00
Petar Petrov 16bbd84962 Use custom home name in energy flow cards (#29652) 2026-02-16 10:23:13 +02:00
Petar PetrovandNorbert Rittel 010eee76c5 Migrate grid connections to single objects with import/export/power (#29389)
* Migrate grid connections to single objects with import/export/power

* Fix duplicate imports in battery settings dialog

* Update src/translations/en.json

Co-authored-by: Norbert Rittel <[email protected]>

* Update src/translations/en.json

Co-authored-by: Norbert Rittel <[email protected]>

* Remove redundant power grid translation keys from en.json

* Remove redundant power charge and discharge keys from en.json

* Clean up grid keys from en.json

* Rename sell price to export

* add descriptions

* use ValueChangedEvent

* Renamed translationKeyPrefix to localizeBaseKey

* Add clarification to stat_rate in energy preference interfaces

* Add handling for external statistics in energy cost tracking

* Apply suggestion from @NoRi2909

Co-authored-by: Norbert Rittel <[email protected]>

* Update src/translations/en.json

Co-authored-by: Norbert Rittel <[email protected]>

* update comments

* Use ha-dialog instead of ha-wa-dialog

---------

Co-authored-by: Norbert Rittel <[email protected]>
2026-02-16 08:55:07 +01:00
dependabot[bot] c138608445 Bump qs from 6.14.1 to 6.14.2 (#29651)
Bumps [qs](https://github.com/ljharb/qs) from 6.14.1 to 6.14.2.
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.14.1...v6.14.2)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.14.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-16 09:24:02 +02:00
dependabot[bot] 9632251a36 Bump github/codeql-action from 4.32.2 to 4.32.3 (#29650)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.32.2 to 4.32.3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2...9e907b5e64f6b83e7804b09294d44122997950d6)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.32.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-16 09:03:16 +02:00
Petar PetrovandSimon Lamon 17c3699707 Smarter floor/area grouping for energy sankey cards (#29588)
* Smarter floor/area grouping for energy sankey cards

Instead of hiding floors and areas whenever any device has an upstream
parent (included_in_stat), check whether each parent shares the same
area as its children. Only disable grouping when a mismatch is found.

* Allow missing area for parent or child

---------

Co-authored-by: Simon Lamon <[email protected]>
2026-02-15 19:14:55 +00:00
ildar170975 681cbfdbd1 Data tables: "voice assistants" icons alignment fix (#29645)
fix alignment for icons
2026-02-15 14:13:28 +00:00
Aidan TimsonandSimon Lamon 7c6e88ca3f Delete ha-dialog, rename ha-wa-dialog to ha-dialog (#29627)
* Delete ha-dialog

* Rename ha-wa-dialog to ha-dialog

* Rename component

* Rename gallery

* Rename gallery

* Update agents.md

* Rename references

* Rename component

* Format

* Fix

* Fix

* Fix

* Fix typo

* Fix typo

* Fix typo

* Fix typo

* Fix typo

* Fix typos

* Remove duplicate

* Remove

* Remove redundant header

* This should never have been here

* Remove, fixup

* Cleanup

* Remove

* Cleanup

* Give it a name again for gallery sidebar

* Fix invalid action design

* Fix gallery dialog actions to correct spec

---------

Co-authored-by: Simon Lamon <[email protected]>
2026-02-15 11:01:31 +00:00
ildar170975 8ba7ff1705 Data table filters: fix overflow (#29646)
* fix overflow

* fix overflow

* fix overflow

* fix overflow

* fix overflow
2026-02-15 11:51:26 +01:00
karwosts 8727396e63 Virtualize notification drawer (#29640)
* Virtualize notification drawer

* update padding
2026-02-15 11:50:59 +01:00
Tom Carpenter f03a573154 Correct Developer Tools Tab Translation Key (#29642)
Correct Dev Tools Tab Translation Key

Wrong key was selected for the dev tools page title due to caching issue.
2026-02-14 21:04:08 +01:00
Tom Carpenter be8a7e0fa5 Fix Missing Developer Tools Page Title (#29631)
Add panel.developer_tools as an additional translation key for the developer tools in `configSections`. Otherwise the title of the page is simply Settings.
2026-02-14 10:42:12 +01:00
Paul Bottein 67e3eeb45e Fix custom value in picker with sections (#29593) 2026-02-13 16:24:40 +01:00
Aidan TimsonandWendelin 309e60fc4f Migrate other dialogs to wa (#29610)
Co-authored-by: Wendelin <[email protected]>
2026-02-13 16:19:48 +01:00
Aidan Timson 8edfd4d5ad Fix custom paths for navigation picker (#29619)
Fix custom paths for navigation
2026-02-13 15:13:36 +02:00
Aidan TimsonandWendelin 32f69c08a1 Migrate lovelace config dialogs to wa (#29607)
Co-authored-by: Wendelin <[email protected]>
2026-02-13 13:09:42 +00:00
Aidan Timson 4d7d76c9aa Migrate Z-Wave and Zigbee config dialogs to wa (#29583) 2026-02-13 14:03:08 +01:00
Tom Carpenter 9f10bc1371 Correct value update for 'ha-selector-select' elements displaying as radio buttons. (#29612)
* Correct options reset in ha-selector-select

Separate out the handling of resetting for select elements in `ha-selector-select` from the main value changed callback.

This fixes a bug that prevented `ha-selector-select` elements operating in `list` mode from updating their value due to recent changes in the reset logc.

* Split radio changed callback for consistency
2026-02-13 15:02:16 +02:00
Aidan Timson 93a0f37974 Migrate lovelace editor dialogs to wa (#29594) 2026-02-13 13:02:06 +00:00
Tom Carpenter 2ad264beaf Fix hardcoded collection keys in energy dashboard (#29623)
Correct hardcoded collection keys

Some elements in the energy overview strategy, and all in the energy view strategy were using hardcoded literals rather than the assigned collection key.
2026-02-13 14:48:53 +02:00
Aidan TimsonandWendelin 2eec2ded13 Migrate matter config dialogs to wa (#29605)
Co-authored-by: Wendelin <[email protected]>
2026-02-13 13:48:17 +01:00
Aidan Timson eca535dd81 Migrate more info dialog to ha-wa-dialog (#28583) 2026-02-13 13:43:46 +01:00
Aidan Timson 33ba3f20aa Migrate voice assistant config dialogs to wa (#29606) 2026-02-13 13:30:44 +01:00
Paul Bottein a45ef6e019 Light dashboard toggle area (#29363)
* Add toggle lights button on light dashboard

* Use not

* Use group card on desktop
2026-02-13 09:16:13 +02:00
Tom Carpenter b256fc820d Fix compare button bug in energy-period-selector (#29611)
Fix bug in energy-period-selector

When the dropdown item for compare is disabled, the click callback still fires, allowing compare to be selected. So remove the callback for disabled buttons.

Also fix a slight visual bug in the ha-ripple border radius.
2026-02-13 09:02:43 +02:00
Wendelin 67fb7f61c2 Remove ha-divider and replace with wa-divider (#29609)
* Replace ha-divider with wa-divider in onboarding and dashboard components

* Refactor styles in onboarding-welcome component for consistency and responsiveness
2026-02-12 19:03:28 +01:00
1b3ea3d55d Move automation help icons from sections to dialogs (#29584)
Co-authored-by: Claude Sonnet 4.5 (1M context) <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2026-02-12 15:42:44 +00:00
Steven Travers 3f724aba4f Fix kiosk mode not opening sidebar on toggle menu event (#29604) 2026-02-12 09:54:46 -05:00
Aidan Timson 7e225ed8a7 Migrate onboarding dialogs to wa (#29601)
* Migrate onboarding dialog(s) to wa

* Remove hass

* Allow hass to be uninitialised in wa dialog

* Use standard width for overflowing text
2026-02-12 15:35:32 +01:00
Wendelin bd78800d8a Fix ha-dropdown-item selected hover (#29602)
Add hover effect for selected dropdown item
2026-02-12 15:32:35 +01:00
Aidan TimsonandWendelin 13d40993ef Change state card button/input_button to control button (#29367)
Co-authored-by: Wendelin <[email protected]>
2026-02-12 12:41:56 +00:00
Paul BotteinandClaude Opus 4.6 1ad74d46d6 Improve PR template and add AI agent instructions (#29590)
* Improve PR template and add AI agent instructions

Move screenshots section closer to proposed change for better flow, and add instructions in copilot-instructions.md to ensure AI agents use the PR template when creating pull requests.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* Instruct AI agents to not check checklist items on behalf of the user

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* Remind user to add screenshots for UI changes after creating PR

Co-Authored-By: Claude Opus 4.6 <[email protected]>

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
2026-02-12 14:33:54 +02:00
Aidan Timson 4a128c904e Migrate enter code dialog to wa (#29592)
* Move enter code dialog migration to dedicated branch

* Fix

* Make small

* Small
2026-02-12 14:33:12 +02:00
Paul Bottein e414bab746 Improve default dashboard confirmation dialog (#29596) 2026-02-12 12:58:34 +01:00
a354026780 Migrate more "ha-settings-row" to "ha-md-list-item" (#29508)
Co-authored-by: Wendelin <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2026-02-12 09:54:49 +01:00
Matthias Alphart 24014116dc Add missing import in hass-tabs-subpage-data-table (#29591) 2026-02-12 08:49:09 +00:00
Aidan Timson b07b604a20 Migrate zone config dialogs to wa (#29581)
* Migrate config-zone dialog(s) to wa

* Move cancel to new item, only delete if editing
2026-02-12 08:33:48 +00:00
Marcin BauerandClaude Sonnet 4.5 81525a2b14 Hide actions in attributes view (#29580)
* Hide actions in attributes view

Simplify the isDefaultView condition to hide actions when child views are shown in the more-info dialog.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <[email protected]>

* Remove keepHeader option from ChildView interface

Completely removes the keepHeader property which was used to keep the header visible in child views. This simplifies the logic and ensures actions are consistently hidden across all child views, including the attributes view.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 (1M context) <[email protected]>
2026-02-12 09:23:45 +01:00
3b6babe0be Reorganize profile localization settings into dedicated card (#29496)
Co-authored-by: Petar Petrov <[email protected]>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Paul Bottein <[email protected]>
2026-02-12 09:06:10 +01:00
Aidan Timson 432e8fc0d7 Migrate zeroconf discovery info dialog to wa (#29579)
* Migrate config-zeroconf dialog(s) to wa

* Cleanup
2026-02-11 18:06:58 +01:00
Aidan Timson 2e350d24f5 Migrate ssdp config dialogs to wa (#29582)
* Migrate config-ssdp dialog(s) to wa

* Cleanup
2026-02-11 18:01:34 +01:00
Aidan Timson 024e953c89 Migrate thread config dialog to wa (#29578)
* Migrate config-thread dialog(s) to wa

* Cleanup
2026-02-11 17:48:03 +01:00
Aidan Timson c29401a5a5 Migrate tags config dialog to wa (#29577)
* Migrate config-tags dialog(s) to wa

* Prevent scrim close
2026-02-11 17:28:26 +01:00
Aidan Timson f913677dfe Migrate storage config dialogs to wa (#29576)
Migrate config-storage dialog(s) to wa
2026-02-11 17:21:31 +01:00
Aidan TimsonandWendelin 3b3f8f3343 Migrate integrations dialogs to wa (#29567)
Co-authored-by: Wendelin <[email protected]>
2026-02-11 12:48:41 +00:00
Aidan Timson 03917a5e1c Migrate energy config dialogs to wa (#29565)
Migrate config-energy dialog(s) to wa
2026-02-11 13:51:57 +02:00
Paul Bottein 5e3002f739 Align pull request template with core (#29573) 2026-02-11 13:50:18 +02:00
ildar170975 da4395b8b3 Entity card: allow a reversed order for "value" & "unit" (#29407)
* allow a reversed order

* formatEntityStateToParts() does not return "order"

* resolving conflicts

* fixed styles
2026-02-11 12:37:41 +01:00
ildar170975andPaul Bottein 16609053ac ha-fab: fix styles for disabled (#29446)
* Update ha-fab.ts

* fix styles for "disabled"

* fix styles

* do not change opacity

Co-authored-by: Paul Bottein <[email protected]>

* revert & simplify

---------

Co-authored-by: Paul Bottein <[email protected]>
2026-02-11 12:21:22 +01:00
Aidan Timson 7beadb8108 Migrate person and user dialogs to wa (#29569) 2026-02-11 11:07:55 +00:00
Aidan Timson 8ca169fc23 Migrate hardware avaliable dialog to wa (#29566) 2026-02-11 12:07:39 +01:00
Aidan Timson 6502c14fad Migrate logs detail dialog to wa (#29568) 2026-02-11 11:52:19 +01:00
Aidan Timson 3d4b10caab Migrate cloud dialog to wa (#29563) 2026-02-11 11:40:33 +01:00
Aidan Timson 20bfe8b633 Migrate statistics dialogs to wa (#29437)
* Migrate config-developer-tools dialog(s) to wa

* Add space

* Remove duplicate method, fix variant typo

* Restore closeDialog
2026-02-11 12:01:45 +02:00
Aidan Timson c6ecb5f217 Migrate mqtt device info dialog to wa (#29564)
Migrate config-devices dialog(s) to wa
2026-02-11 11:38:17 +02:00
Aidan TimsonandPetar Petrov 938cc6a1a1 Migrate app store dialogs to wa, standardise registry actions (#29542)
* Migrate config-apps dialog(s) to wa

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

* Use standard buttons

* Use back action

* Remove extra close action

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-02-11 11:34:53 +02:00
Wendelin 1d1e05dbdf Migrate from ha-md-select to ha-select (#29551)
* Migrate from ha-md-select to ha-select across multiple components

* Review

* Remove --md-filled-field-content-space
2026-02-11 11:30:10 +02:00
Aidan TimsonandSimon Lamon a1b4923673 Migrate bluetooth device info dialog to wa (#29546)
Co-authored-by: Simon Lamon <[email protected]>
2026-02-11 10:00:16 +01:00
Aidan Timson 823a42f567 Add additional config areas to quick search (#29535)
* Add network discovery browsers to quick search

* Add cloud to quick search

* Add application credentials and mqtt, remove cloud as is a redirect
2026-02-11 09:46:26 +02:00
Aidan Timson 81275a96ff Migrate main calendar dialogs to wa (#29505)
* Migrate calendar dialog(s) to wa

* Remove width (too wide)

* Prevent scrim close
2026-02-11 09:26:11 +02:00
Paul BotteinandClaude 2e372b2f8a Add repairs and updates cards to home dashboard overview (#29552)
* Add repairs and updates cards to home dashboard overview

Add two new cards to the "For You" section of the home dashboard that display
links to repairs and updates when there are active issues or available updates.
Both cards are only visible to admin users and hide when empty.

https://claude.ai/code/session_013NTgs1U9x59uaEJs1smy8i

* Fix navigation and visibility

* Reorder

---------

Co-authored-by: Claude <[email protected]>
2026-02-11 09:15:37 +02:00
sebcaps 541cc7d10b Add Percentage in distribution card tooltip (#29555)
Add Percentage in tooltip
2026-02-11 09:06:56 +02:00
Aidan Timson 678ee7e82a Migrate todo dialog to wa (#29527)
Migrate todo dialog(s) to wa
2026-02-10 20:38:45 +01:00
uptimeZERO_ ee72f4818d Add guard for failed JSON parsing of localStorage entries (#29502)
* Added guard for failed json parsing of selectedTheme key

* deleting corrupted keys and logging
2026-02-10 20:30:28 +01:00
karwosts ccbd9c1f24 Don't show hidden todolists on todo panel (#29510) 2026-02-10 19:21:53 +01:00
ildar170975 84135a9424 hui-entity-editor: fix padding-top for ha-md-list (#29537)
fix padding-top for ha-md-list
2026-02-10 19:17:10 +01:00
Petar Petrov 4ebc334298 Normalize SI unit prefixes in distribution card proportions (#29539)
* Normalize SI unit prefixes in distribution card proportions

* Extract SI prefix normalization to shared utility with tests

Moves normalizeValueBySIPrefix to src/common/number/ so it can be
reused. Replaces the inline method in the distribution card and the
switch statement in getPowerFromState (energy.ts).
2026-02-10 19:16:02 +01:00
Petar Petrov 3c4c3e39e5 Fix storage space calculations to account for reserved system space (#29540) 2026-02-10 19:13:58 +01:00
Aidan Timson 1267003b42 Migrate local backup location dialog to wa (#29543)
Migrate config-backup dialog(s) to wa
2026-02-10 19:11:44 +01:00
Aidan Timson 733359c869 Fix position of 2 extra actions for date picker dialog (#29541)
Fix position of 2 extra actions for date picker
2026-02-10 19:08:55 +01:00
Aidan Timson 50b6e07ae5 Migrate import blueprint dialog to wa (#29544)
* Migrate config-blueprint dialog(s) to wa

* Add vt
2026-02-10 19:00:58 +01:00
Wendelin 1b62a7cff8 Dropdown item add selected prop (#29553)
Refactor dropdown item selection handling to use property binding for selected state
2026-02-10 18:55:38 +01:00
Wendelin c293cf56f6 Migrate from ha-md-menu to ha-dropdown (#29548) 2026-02-10 15:33:49 +00:00
Aidan Timson 2ec6f3615d Use ValueChangedEvent for more CustomEvents (#29547) 2026-02-10 16:26:19 +01:00
Wendelin d3b92059e5 Re-enable autofocus for iOS in ha-wa-dialog (#29534) 2026-02-10 15:09:33 +01:00
ildar170975andPetar Petrov 72e69f6291 Entities card: add “area” for “secondary_info” (#29268)
* add "area/floor" labels for secondary-info for Entities card

* use STRINGS_SEPARATOR_DOT

* add "area/floor" for secondary-info

* add "area/floor" for secondary-info

* add "area/floor" for secondary-info

* use STRINGS_SEPARATOR_DOT

* use STRINGS_SEPARATOR_DOT

* use STRINGS_SEPARATOR_DOT

* add STRINGS_SEPARATOR_DOT

* changed an order & renamed an option

* fixed name for "area with floor"

* chaged an order & renamed an entry

* renamed "area with floor" entry

* add STRINGS_SEPARATOR_DOT

* Delete src/common/strings-separator.ts

* change import

* change import

* change import

* change import

* change import

* fix import

* fix import

* fix import

* remove "area-with-floor"

* remove "area-with-floor"

* remove "area-with-floor"

* remove unneeded comma

* remove "area-with-floor"

* clean up

* typo

* Apply suggestion from @MindFreeze

Co-authored-by: Petar Petrov <[email protected]>

* move area definition into a separate method

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-02-10 16:06:00 +02:00
Aidan Timson 3bff97595f Migrate date picker dialog to wa (#29506) 2026-02-10 14:52:01 +01:00
renovate[bot] 19b1d03cd1 Update Node.js to v24.13.1 (#29538)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-10 13:34:20 +00:00
Petar Petrov f04557688c Use unique SVG mask IDs in graph base to fix rendering on Samsung WebView (#29525)
* Use unique SVG mask IDs in graph base to fix rendering on Samsung WebView

* Remove unused IDs
2026-02-10 14:23:52 +01:00
Matthias de BaatandPetar Petrov d6953ea1bc Make storage charts consistent with lifetime chart (#29526)
* Make storage charts consistent with lifetime chart

* Update src/panels/config/storage/storage-breakdown-chart.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-02-10 13:12:53 +00:00
ildar170975andPetar Petrov 4501db18c7 Entities card editor: fix margin-top for ha-entity-picker (#29536)
* fix margin-top for ha-entity-picker

* Apply suggestion from @MindFreeze

* use ha-space var

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-02-10 13:10:40 +00:00
ildar170975 c68bcc5b32 Entity card: fix unit for monetary (#29406)
* fix unit for monetary

* fix for span

* formatEntityStateToParts() does not return "order"

* get unit from formatEntityStateToParts()

* resolving conflicts

* resolving conflicts

* some styling
2026-02-10 15:09:43 +02:00
Aidan Timson 3753c7d313 Migrate helper dialogs to wa (#29507)
* Migrate config-helpers dialog(s) to wa

* Stop secondary dialogs from automatically closing

* Styles

* Fix initial focus
2026-02-10 14:54:52 +02:00
Aidan Timson 4a2ef18375 Migrate media browser dialog to wa (#29529) 2026-02-10 13:28:48 +01:00
Wendelin 051da41eec Update @home-assistant/webawesome to version 3.2.1-ha.0 (#29533)
update @home-assistant/webawesome to version 3.2.1-ha.0
2026-02-10 13:25:53 +01:00
Aidan Timson 9b1a679f21 Add missing AI tasks item to quick search (#29531) 2026-02-10 13:10:35 +01:00
Aidan Timson 905a0f957c Migrate system information and startup time dialogs to wa (#29532) 2026-02-10 13:08:08 +01:00
Wendelin d9a687b79c Hardware panel imporve chart loading UI (#29528) 2026-02-10 10:42:57 +00:00
karwosts 3b56497134 Hide more info weather forecast when unsupported (#29517) 2026-02-10 09:28:52 +00:00
Paul Bottein ed0ec871ce Don't close automation and script sidebar on save (#29434) 2026-02-10 10:07:31 +01:00
ildar170975 29f5362182 hui-graph-header-footer: add own action handler (#29522)
* add action handler

* set action handler for ":host"
2026-02-10 11:03:31 +02:00
Matthias de BaatandPetar Petrov 5096bab26c Move AI task to its own page and change General into Home information (#29458)
* Move AI task to its own page and change General into Home information

* Fixed unused state properties for form submission states, removed unused imports and obsolete CSS, replaced hardcoded pixel values with spacing tokens, and added error handling for the map component.

* Update src/panels/config/core/ha-config-section-general.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-02-10 06:45:26 +00:00
Yosi Levy ce2892cab9 Various RTL fixes (#29520) 2026-02-10 06:59:18 +01:00
renovate[bot] 57748c15de Update dependency @codemirror/commands to v6.10.2 (#29518)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-10 06:58:46 +01:00
Paul Bottein ecb6a33c86 Add color settings for entity in distribution card (#29436)
* Add color settings for entity in distribution card

* Fix name

* Fix name again...
2026-02-09 16:15:14 +01:00
ildar170975 d34921ff6d state-card-input_number: fix for narrow viewport (#29327)
state-info: fix for narrow viewport
2026-02-09 15:30:40 +01:00
ildar170975andPaul Bottein e6c9e81082 Add formatEntityStateToParts() + use it for hui-entity-card & ha-state-label-badge (#29239)
* add formatEntityStateToParts

* add formatEntityStateToParts

* use formatEntityStateToParts

* add formatEntityStateToParts

* use formatEntityStateToParts

* add formatEntityStateToParts

* add formatEntityStateToParts

* add computeStateDisplayToParts

* update for monetary

* fix a test for monetary

* fixed test for monetary

* do not include "order" into result

* do not include "order" into result

* do not include "order" into result

* do not include "order" into result

* do not include "order" into result

* do not include "order" into result

* do not include "order" into result

* simplify

* ensure less conflicts in future merges

* Refactor monetary computing

---------

Co-authored-by: Paul Bottein <[email protected]>
2026-02-09 15:11:05 +01:00
Petar Petrov aa13c6fa53 Add tests for energy chart functions (#29504) 2026-02-09 15:07:11 +01:00
ildar170975 d47738aa24 developer-tools-debug: migrate "ha-settings-row" to "ha-md-list-item" (#29501)
* ha-settings-row -> ha-md-list-item

* ha-settings-row -> ha-md-list-item

* ha-settings-row -> ha-md-list-item

* background: 0 -> background: none
2026-02-09 14:25:23 +01:00
ildar170975 d473ee1084 User profile: migrate toggle rows "ha-settings-row" to "ha-md-list-item" (#29497)
* ha-settings-row -> ha-md-list-item

* ha-settings-row -> ha-md-list-item

* ha-settings-row -> ha-md-list-item

* ha-settings-row -> ha-md-list-item

* ha-settings-row -> ha-md-list-item

* ha-settings-row -> ha-md-list-item

* ha-settings-row -> ha-md-list-item

* ha-settings-row -> ha-md-list-item

* remove unneeded "narrow"

* add import

* background: 0 -> background: none
2026-02-09 13:52:19 +01:00
Aidan Timson 0372ed932f Migrate new dashboard dialog to wa (#29438)
* Migrate config-dashboard dialog(s) to wa

* Restructure for scrolling
2026-02-09 14:08:04 +02:00
Aidan Timson 2baa044db5 Migrate profile dialogs to wa, refactor LL access token dialog (#29440)
* Migrate profile dialog(s) to wa

* Make sure code is entered before submit is allowed

* Refactor dialog

* Remove unused params

* Pass existing names and validate name is not already used

* Reduce cleanup on show

* Make QR image larger

* max width

* Fix

* Remove extra event fire

* Make params required

* cleanup

* Cleanup

* Fix

* Fix
2026-02-09 12:54:02 +01:00
Wendelin 3d04046bcc Migrate automation picker row to ha-dropdown (#29428)
* Update @home-assistant/webawesome to version 3.2.1 and refactor ha-dropdown integration in automation picker

* review

* revert wa update

* Update @home-assistant/webawesome to version 3.0.0-ha.2 in yarn.lock
2026-02-09 12:35:49 +01:00
Tom CarpenterandPetar Petrov 8e860cb17d Improve energy dashboard monthly/this-quarter chart time axes (#29435)
* Add splitNumber option to monthly ECharts

When there are a small number of bars (<=3) for monthly data, set the splitNumber parameter to force the date x-axis to show whole months.

* Add axis tick fomratting for short months

This ensures that the month format is consistent between 2/3 month and longer ranges.

* Avoid calling getSuggestedMax twice

* Fix another case of power chart cutting off last hour of data

The previous fix only solved the problem for 5-minute data, not hourly or daily. This should solve the issue regardless, and allows the energy chart to have other line-based plots in the future.

* Update other uses of getSuggestedMax()

* Fix statistics-chart Last Period Rendering

1. When appending the "current state" value, if the current time intersects with the final period, we can end up with the chart folding back on itself. This is fixed by ensuring for the final period we push the earlier of the statistic end time and the display end time (which is in turn limited to now).

2. Always close off the last data point at the chart end time. Otherwise for line charts, the final period doesn't get rendered.

* Remove unused monthStyle formatter.

Co-authored-by: Petar Petrov <[email protected]>

* Rename getSuggestedMax function parameter in energy chart

Co-authored-by: Petar Petrov <[email protected]>

* Document magic numbers in montly energy chart

* Make padding a constant for clarity.
* Explain the purpose of splitNumber.

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-02-09 13:05:42 +02:00
Petar Petrov c41d7ff923 Fix history-graph card rendering stale data point on left edge (#29499)
When HistoryStream.processMessage() prunes expired history and preserves
the last expired state as a boundary marker, it updates lu (last_updated)
but not lc (last_changed). Chart components use lc preferentially, so
when lc is present the boundary point gets plotted at the original stale
timestamp far to the left of the visible window. Delete lc from the
boundary state so the chart uses the corrected lu timestamp.
2026-02-09 10:13:06 +01:00
Matthias de Baat c22fc1021a Counter gravity effect on the Matter icon (#29459) 2026-02-09 10:05:06 +01:00
dependabot[bot] 6344233934 Bump github/codeql-action from 4.32.0 to 4.32.2 (#29498)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.32.0 to 4.32.2.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/b20883b0cd1f46c72ae0ba6d1090936928f9fa30...45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.32.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-09 10:22:39 +02:00
ildar170975 23441d593b Data tables: filters: fix a placement for icon & text (#29488)
* fix padding & margin

* fix margin for icon

* fix margin for icon

* fix margin for image

* use ha-space-4

* use --ha-space-4

* use ha-space-1

* use ha-space-4
2026-02-09 08:57:00 +01:00
ildar170975 8393ed5fd4 voice-assistant-brand-icon: fixes for margin & alignment (#29493)
* fix styles

* fix a gap between logos

* fix a gap between logos

* fix right margin for logo

* fix right margin for logo

* show icons in flex

* remove unneeded style

* add right margin for logo
2026-02-09 08:54:45 +01:00
TheJulianJES 09afe9bb51 Fix ZHA dashboard using disabled and ignored config entries (#29494) 2026-02-09 08:18:43 +01:00
Benedikt Johannes fb8d6062c5 Sugestion -> Suggestion (#29490)
* Update en.json

* Update ha-area-picker.ts

* Update ha-label-picker.ts

* Update ha-floor-picker.ts

* Update ha-category-picker.ts
2026-02-09 08:14:15 +01:00
karwosts f93ae58b83 Fix dupl. id error in water-sankey (#29489) 2026-02-08 19:06:37 +01:00
karwosts 7626b26b2d No FAB in calendar-card (#29487) 2026-02-08 19:06:31 +01:00
renovate[bot] a1bf30e501 Update dependency @rsdoctor/rspack-plugin to v1.5.2 (#29481)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-08 08:41:36 +00:00
ildar170975 37a45d1729 voice-assistants-expose-assistant-icon: fix tooltip (#29469)
* fix tooltip

* provide id for tooltip for assistant icon
2026-02-08 09:32:12 +01:00
karwosts 6962a915a3 Fix describe legacy triggers in traces (#29473)
* Fix describe legacy triggers in traces

* remove unnecessary type
2026-02-07 22:05:05 +01:00
renovate[bot] de3e2bcafa Update dependency glob to v13.0.1 (#29462)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-06 21:44:45 +01:00
Matthias de Baat e732280b70 Add safe space at the bottom (#29454)
* Add safe space at the bottom

* Move margin-bottom from ha-config-analytics component to its parent wrapper in ha-config-section-analytics
2026-02-06 17:47:40 +01:00
renovate[bot] 4fb3453f73 Update dependency ua-parser-js to v2.0.9 (#29456)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-06 16:45:18 +00:00
renovate[bot] 0f9cb9c13e Update dependency @rspack/core to v1.7.5 (#29447)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-06 12:23:27 +01:00
7aa235c6af Fix Discord link for designers (#29393)
* Fix Discord link for designers

Updated Discord link for designers to the correct channel.

* Update Discord link for designers in home.markdown

* Update gallery/src/pages/concepts/home.markdown

Co-authored-by: Aidan Timson <[email protected]>

---------

Co-authored-by: Bram Kragten <[email protected]>
Co-authored-by: Aidan Timson <[email protected]>
2026-02-05 21:09:28 +01:00
Aidan Timson e8ddae8189 Migrate join beta dialog to wa (#29439)
Migrate config-updates dialog(s) to wa
2026-02-05 21:06:38 +01:00
Paul Bottein c26e59f19c Fix theme and sidebar on demo (#29433) 2026-02-05 15:49:27 +01:00
Petar Petrov 83aa06cb18 Fix storage apps translation keys (#29432) 2026-02-05 15:43:47 +01:00
Tom Carpenter 9d3d0dac48 Fix energy dashboard date/time tooltip date labelling (#29431)
* Use Suggested Period for Energy Tooltip

Ensure the tooltips for energy charts match energy data grouping by using getSuggestedPeriod rather than hardcoded differenceInDays.

* Make getSuggestedMax return Date()

Currently used in two places - for energy charge ECOption, and for a statistics-graph. In both places a Date is expected rather than a Number. No point converting to a Number with getTime() when they are immediately converted back to a Date.
2026-02-05 15:40:12 +01:00
Aidan Timson 8da1154924 Delete ha-md-dialog (#29421) 2026-02-05 15:35:34 +01:00
Bram Kragten eb588075b8 Use ha-alert for copyright of logo (#29429)
Use ha-alert for copyright of logo
2026-02-05 15:25:54 +01:00
Aidan Timson bdeaf10d74 Migrate remaining backup dialogs dialog to wa (#29419)
Migrate backup dialogs dialog to wa
2026-02-05 15:24:05 +02:00
Aidan Timson bec0d19fc9 Migrate favorite color picker to wa (more info) (#29373)
* Migrate favorite color picker to wa (more info)

* Remove cancel
2026-02-05 13:22:01 +00:00
Aidan Timson 325a7974c2 Migrate pick config entry dialog to wa (#29417) 2026-02-05 13:14:19 +00:00
Darren Griffin fab1fde6e3 Update license text (#29423) 2026-02-05 14:08:18 +01:00
Norbert Rittel 0e9564e676 Make description of Map card consistent (#29420) 2026-02-05 15:06:26 +02:00
Aidan Timson 244eb75049 Migrate cloud support package dialog to wa (#29418) 2026-02-05 15:05:46 +02:00
Aidan Timson 644bb016d6 Migrate download logs dialog to wa (#29416) 2026-02-05 14:53:38 +02:00
Aidan TimsonandPetar Petrov 02dbcf0946 Add context to quick bar, prioritise related entries (#29107)
* Add support for context in quick bar

* Send context from device page

* Use interface

* Prefetch and pass related result to dialog instead of loading on show (load on event call)

* Apply suggestion from @MindFreeze

Co-authored-by: Petar Petrov <[email protected]>

* Add error

Co-authored-by: Petar Petrov <[email protected]>

* Fix

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-02-05 12:48:02 +00:00
Aidan Timson f7df4d8a90 Migrate join media players to wa (more info) (#29374)
* Migrate join media players to wa (more info)

* Fix padding
2026-02-05 14:00:01 +02:00
Aidan Timson e00ced23ee Use ValueChangedEvent instead of CustomEvent (#29399)
* Use ValueChangedEvent with generic type requested

* Add more

* Add

* Add more
2026-02-05 13:55:43 +02:00
Aidan TimsonandPetar Petrov f5cc2104ef Refactor ha-select and ha-dropdown event handlers to use generic event types (#29397)
* Allow HaDropdownSelectEvent to pass the value type

* Fix potential type conflict

* Add clarification of type

* Fix type

* Create new type for ha-select

* Refactor

* Add clearable to only handle undefined when needed

* Value changed event

* Use clearable type

* Remove

* Profile section refactor

* Protocols refactor

* More config refactor

* Entity rows 1

* Remove unrelated

* Remove ValueChangedEvent changes (moved to separate branch)

* Revert

* Add

* Revert unrelated or extra checks

* Restore

* Restore

* Restore

* Update src/components/ha-conversation-agent-picker.ts

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-02-05 13:47:28 +02:00
Tom Carpenter 161dd26b4d Display Selected Year on Energy Date Picker (#29321)
* Show Year on Energy Dashboard Date Picker

When the selected range (start and/or end) is in a different year from the current one, show the year for that date.

* Correct Energy Picker Year Detection

Ensure that when checking if a range is a full year, the endpoints must be in the same calendar year.

Otherwise selecting a 12-month range that spans into two years would be treated as all being a single year.

* Add natural wrapping spans for date range

Encourage the range to wrap nicely if the text is too large for the toolbar.

* Use en dash between date range

The en dash character is usually used for date ranges rather than the
standard hypen

* Fix Now Button Rendering on Resize

Host element needs to be `display:block` no the default `display:inline` for the ResizeObserver to work.

* Remove P tag from date picker range label

Removing the paragraph tag and adding text-align center seems to produce cleaner wrapping of the date range on narrower screens.

* Allow Overriding HA Dialog Header Font Size

For the title and subtitle, variables can not be set in the host to control the font size. This is useful in cases where the heading is used on a narrow card and the title needs to be smaller.

* Add property to manually trigger opening of ha-date-range-picker

For cases where there is a desire to click in regions other than the calendar icon to have the date picker open.

* Add no-padding option to ha-dialog-header

When used within cards already containing padding, the extra padding may be unnecessary.

* Use ha-dialog-header for Energy Period Selector
Place the day/month in the title and the year in the subtitle. This gives a cleaner more consistent look.

* Remove Unnecessary IDs

Came from copy-paste from another example.

* Apply Typing to Date Picker Methods

* Move selector buttons to overflow if too small

When the period selector gets too small to fit everything (very narrow screens, or card in grid), then move the next/previous buttons to the overflow menu.

The now button exists on the overflow menu now too when in narrow mode.

* Change Date Picker openPicker to open()

Makes far more sense as a method not a property.

* Revert Padding Change to ha-dialog-header

* Simplify Energy Selector Overflow Buttons

Improve button labelling to just use index, avoiding possible localisation issues of using the label.

Simplify the interface to remove unnecessary fields.

* Update Button Collapse Width for Picker
Increase to 300px now that padding of dialog header is present.

* Fix Imports in Energy Period Selector

* Fix whitespace

* Properly leverage slots in ha-dialog-header

Make proper use of the actionItems slot for the control buttons to keep them properly contained as the date selector is resized.

* Move clickable date to title/subtitle elements

In moving the control buttons into the actionItems slot, we can no longer use the whole ha-dialog-header element as a clickable region for opening the date selector. Frankly this is not a bad thing as it meant it was not possible to nicely hover/highlight the date.

Instead we now make the title/subtitle clickable elements. This allows adding a nice hover effect and cursor pointer effect.

* Add option to make ha-dialog-header content clickable

* Use clickable dialog header in period selector

This way the whole title area is the hit point rather than the title and subtitle text individually.

* Remove ha-dialog-header from period selector

It's not a dialog, so it makes no sense to use that element. Instead recreate just the necessary parts to make it stylistically simiar. The reality is this is not much extra code, and it should make maintaining easier.

* Revert changes to ha-dialog-header

* Style Date Range as Input Field

* Use ha-ripple Effect

* Remove Unnecessary Tooltip Option

Unused, so remove the extra complexity.

* Remove more unused imports

* Force energy panel picker open direction

Now that the button is on the left, we need it to open to the right to avoid colision with the sidebar. Add the option to force the direction.

* Rename property to openingDirection for consistency
2026-02-05 12:36:10 +02:00
Paul Bottein 29cee99f10 Use consistent name for common controls in home dashboard (#29410) 2026-02-05 08:48:58 +00:00
renovate[bot] 47341e93fc Update dependency jsdom to v28 (#29409)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-05 10:46:54 +02:00
Wendelin cbae7d6e2f Error log card migrate ha-md-menu to ha-dropdown (#29398)
* Migrate from ha-md-menu to ha-dropdown in error log card, scene dashboard, script picker, and refresh tokens card

* Fix setBoot
2026-02-05 10:37:52 +02:00
karwosts ebff35d17f Fix more-info media source select (#29400) 2026-02-04 17:18:49 +01:00
Bram Kragten d98e373f64 Bumped version to 20260128.6 2026-02-04 15:41:09 +01:00
Paul Bottein 649516c9fa Change default icon for blank area if not icon configured (#29394) 2026-02-04 15:40:36 +01:00
Paul Bottein bbc4fb96b2 Load domain translation when integration page load (#29391) 2026-02-04 15:40:35 +01:00
Paul Bottein 0ae639aeb0 Remove old lovelace overview from pickers (#29390) 2026-02-04 15:40:34 +01:00
karwosts 0e7e41065e Don't shrink ha-dropdown checkboxes (#29387) 2026-02-04 15:40:33 +01:00
Paul Bottein 685843f112 Add translations for new overview dialog (#29382) 2026-02-04 15:40:32 +01:00
Paul Bottein 5e1a99d94a Use area icon for area empty state (#29371) 2026-02-04 15:40:31 +01:00
WendelinandAidan Timson aec4a06156 migrate ha-select to ha-dropdown (#29392)
* migrate ha-select to ha-dropdown

* remove ha-menu

* review

* Fix eslint error

---------

Co-authored-by: Aidan Timson <[email protected]>
2026-02-04 13:47:15 +00:00
Dominik Bruhn 917f2b4434 Add tag-id column in tag table (#29383) 2026-02-04 14:35:56 +01:00
Paul Bottein 79ec6b972e Change default icon for blank area if not icon configured (#29394) 2026-02-04 14:33:27 +01:00
Paul Bottein 9e35befa99 Remove old lovelace overview from pickers (#29390) 2026-02-04 12:03:29 +01:00
Paul Bottein 75160d67d3 Load domain translation when integration page load (#29391) 2026-02-04 11:58:27 +01:00
Tom Carpenter b145d09041 Fix Horizontal Scrolling on System Logs Page (#29375) 2026-02-04 08:32:10 +00:00
Aidan TimsonandPetar Petrov f3f7a1e46a Migrate siren advanced controls to wa-dialog (more info) (#29369)
* Migrate siren advanced controls to wa (more info)

* Fix footer

* Update src/dialogs/more-info/components/siren/ha-more-info-siren-advanced-controls.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-02-04 06:45:50 +00:00
Simon Lamon 091315d9a9 Fixup dev container (#29376)
* Fixup dev container

* Fix yarn installation command in bootstrap script

* Fast restart
2026-02-04 08:33:39 +02:00
renovate[bot] 75b830cdf9 Update dependency globals to v17.3.0 (#29385)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-04 08:22:40 +02:00
renovate[bot] e4b8352832 Update formatjs monorepo (#29386)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-04 06:14:54 +01:00
karwosts 4e193187f9 Don't shrink ha-dropdown checkboxes (#29387) 2026-02-04 06:14:39 +01:00
Paul Bottein 5394b3b8cf Add translations for new overview dialog (#29382) 2026-02-03 23:37:24 +01:00
ildar170975 2ab867986a Data tables: standardize columns (#29155)
* Create data-table-columns.ts

* Update data-table-columns.ts

* move a code for columns into separate functions

* move a code for columns into separate functions

* move a code for columns into separate functions

* move a code for columns into separate functions

* move a code for columns into separate functions

* move a code for columns into separate functions

* move a code for columns into separate functions

* move a code for columns into separate functions

* fix a translation key

* move commonly used translations to generic

* remove a translation for another PR

* restore "domain" translation for while

* resolving conflicts

* resolve conflicts

* resolving conflicts

* resolving conflicts

* resolving conflicts

* resolving conflicts

* fix conflicts

* fix conflicts

* fix import

* fix import
2026-02-03 21:37:53 +01:00
renovate[bot] a1c3a6c662 Update babel monorepo to v7.29.0 (#29379)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-03 21:37:34 +01:00
Benedikt Johannes 11296adbd4 Coversation -> Conversation (#29378)
* Coversation -> Conversation

* Update en.json
2026-02-03 20:22:32 +01:00
Paul Bottein 4e04f4284e Use area icon for area empty state (#29371) 2026-02-03 17:58:37 +01:00
Bram Kragten d843349865 Bumped version to 20260128.5 2026-02-03 16:58:01 +01:00
Paul Bottein ec23164aa9 Improve other devices page in home dashboard (#29370) 2026-02-03 16:57:45 +01:00
Paul BotteinandClaude Opus 4.5 e74ef11101 Hide edit and delete actions for YAML dashboards in config (#29368)
YAML dashboards are defined in configuration files and cannot be
modified or deleted through the UI. This change ensures the edit
and delete actions are only shown for storage-mode dashboards.

Co-authored-by: Claude Opus 4.5 <[email protected]>
2026-02-03 16:57:43 +01:00
Paul Bottein a222f6a736 Add missing danger variant in dropdown item (#29359) 2026-02-03 16:57:40 +01:00
Petar Petrov ef3dd16d45 Move dialog scrim to pseudo-element (#29357) 2026-02-03 16:57:39 +01:00
karwosts 5d4e1d205e Fix missing imports in devtools-statistics (#29355) 2026-02-03 16:57:38 +01:00
Darryn Capes-Davis 1ee5ebbe75 Fix CSS minification issue for ha-card (#29354) 2026-02-03 16:57:37 +01:00
Paul Bottein a0cc0d9cca Improve other devices page in home dashboard (#29370) 2026-02-03 15:50:49 +00:00
uptimeZERO_ c925053bb8 Animate app side bar (#29026) 2026-02-03 14:55:10 +00:00
Aidan Timson 22a7aa8f8e Add default view transition to edit badge and card (#29360) 2026-02-03 14:33:20 +00:00
Petar Petrov 3a5f719a3e Fix chart theme colors in Lovelace edit mode (#29361)
When edit mode is toggled, existing cards are moved into edit mode
wrappers. This triggers connectedCallback which was calling _setupChart
synchronously before the browser recalculated CSS inheritance. The
chart would read stale CSS custom properties, resulting in low-contrast
axis labels in dark theme.

Defer _setupChart using afterNextRender to allow the browser to complete
layout and CSS recalculation first. Guard conditions prevent issues with
rapid connect/disconnect cycles.
2026-02-03 16:27:17 +02:00
Aidan Timson 7b7182c147 Migrate state card select/input_select to select menu (#29362)
* Migrate state card input select to select menu

* Sort

* Migrate state card select to select menu
2026-02-03 16:26:41 +02:00
Paul BotteinandClaude Opus 4.5 0eb7229819 Hide edit and delete actions for YAML dashboards in config (#29368)
YAML dashboards are defined in configuration files and cannot be
modified or deleted through the UI. This change ensures the edit
and delete actions are only shown for storage-mode dashboards.

Co-authored-by: Claude Opus 4.5 <[email protected]>
2026-02-03 16:25:40 +02:00
Petar Petrov fcc6f1b5e9 Move dialog scrim to pseudo-element (#29357) 2026-02-03 14:28:51 +01:00
Paul Bottein 19dc2a5865 Add missing danger variant in dropdown item (#29359) 2026-02-03 11:37:42 +00:00
Wendelin ae63530123 Migrate ha-control-select-menu to use ha-dropdown (#29350) 2026-02-03 10:30:51 +00:00
uptimeZERO_ 97e1f47af9 Add transition for more-info-dialog when toggling expand state (#29341) 2026-02-03 09:21:29 +00:00
Paul Bottein 346d916944 Add an disable view transition as it crashes chrome browser when using chrome dev tools (#29339) 2026-02-03 09:10:16 +01:00
KristelandPetar Petrov ab326b3277 Refactor _applyFilters for Scenes and Scripts pages (#29116)
* proper functionnames

* refactor _applyFilters on scenes and script page

* Apply suggestions from code review

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-02-03 07:50:02 +00:00
Tom 55e251c04f Expose target_humidity_step value to climate (#28834)
Add target_humidity_step to climate
2026-02-03 09:34:53 +02:00
Darryn Capes-Davis b902f3e6f5 Fix CSS minification issue for ha-card (#29354) 2026-02-03 09:19:06 +02:00
ildar170975 9daac6c49f Remove "type" where "attribute: false" (#29356)
remove "type" when "attribute: false"
2026-02-03 09:17:33 +02:00
Benedikt Johannes 65ea0c9121 Fix "unamed" -> "unnamed" (potential crash / non registered translation information bug) (#29351)
* Fix typo

* Update home-area-view-strategy.ts

* Update home-other-devices-view-strategy.ts
2026-02-03 05:55:11 +00:00
Denis Shulyaka 505cc698f6 Fallback data flow section label translation (#29352) 2026-02-03 05:54:18 +00:00
karwosts b0f9b31dae Fix missing imports in devtools-statistics (#29355) 2026-02-03 06:45:39 +01:00
Norbert Rittel 2b2966a214 Make explanation of "search command(s)" shortcut consistent (#29345)
Change "search command" to "search commands"
2026-02-02 17:49:45 +01:00
renovate[bot] 558b251e32 Update dependency @codemirror/view to v6.39.12 (#29349)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-02 17:41:06 +01:00
renovate[bot] df28eaa99e Update dependency tar to v7.5.7 [SECURITY] (#29348)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-02 17:40:45 +01:00
Bram Kragten 59d705aa3d Bumped version to 20260128.4 2026-02-02 17:17:24 +01:00
Paul Bottein 332e108dae Fix "Reload resources" menu for YAML resource mode (#29346) 2026-02-02 17:17:17 +01:00
karwosts 3c15b29d0a Entity diagnostic - handle entity not in the registry (#29344) 2026-02-02 17:17:16 +01:00
Wendelin 130c708e23 Fix dropdown width in datatables (#29340) 2026-02-02 17:17:15 +01:00
Paul Bottein 588a14a8a7 Fix type error for missing hass.themes race condition in themes mixin (#29338) 2026-02-02 17:17:14 +01:00
Petar Petrov a1ef6ad266 Remove redundant dialog backdrop color (#29337) 2026-02-02 17:17:13 +01:00
Aidan Timson a6c1f87730 Ensure template renderer overflows on overflow (#29335) 2026-02-02 17:17:12 +01:00
Wendelin 49252a3808 Fix missing ha-md-menu in config/labels (#29334) 2026-02-02 17:17:11 +01:00
Aidan Timson c7877fe38f Show hint only if keyboard shortcuts is enabled (#29332)
Enabled by default, must be explicity disabled
2026-02-02 17:17:10 +01:00
Wendelin e355a61d8f Revert "Fix automation sidebar ui supported check" (#29331) 2026-02-02 17:17:08 +01:00
Linus Rath f2e19e51ce Update untracked consumption threshold to 1W (#29310) 2026-02-02 17:17:07 +01:00
karwosts fd9ab8f561 Use ha-form for condition template (#29301) 2026-02-02 17:17:06 +01:00
Kristel faa1b3c98f bugfix: add eventlistener for exposed-entities-changed to Entities page (#29299) 2026-02-02 17:17:06 +01:00
Aidan Timson acc4a84fc9 Fix scrolling for labs page (#29287) 2026-02-02 17:17:05 +01:00
karwosts 4d723dac37 Fix areas cannot be deleted (#29285) 2026-02-02 17:17:03 +01:00
Aidan Timson f1d4d0ef98 Fix type error for missing hass.config race condition in themes mixin (#29280) 2026-02-02 17:17:02 +01:00
Paul Bottein 88180a2708 Fix demo because of new default panel (#29279) 2026-02-02 17:17:01 +01:00
Aidan Timson 258d87e3d5 Add missing settings nav items for quick search (#29278)
* Add missing repairs quick search item

* Add voice assistants
2026-02-02 17:17:00 +01:00
Wendelin 55f22ba61a Implement fallback for dialog close event in Quick Search (#29260) 2026-02-02 17:16:59 +01:00
Aidan Timson 812f3ca8b9 Change default shortcut tip in Quick Search to mod+k, add tip to settings (#29253) 2026-02-02 17:16:58 +01:00
Marcin BauerandClaude Opus 4.5 7f880d11a0 Keep focus on search field when clicking filter chips (#29249)
Co-authored-by: Claude Opus 4.5 <[email protected]>
2026-02-02 17:16:57 +01:00
Bram Kragten 6b2452c538 Update compress.js 2026-02-02 17:15:44 +01:00
Petar Petrov 40342c9cfd Remove redundant dialog backdrop color (#29337) 2026-02-02 17:12:27 +01:00
Paul Bottein c6573b9c1b Fix "Reload resources" menu for YAML resource mode (#29346) 2026-02-02 16:07:10 +00:00
karwosts 54c46ad362 Entity diagnostic - handle entity not in the registry (#29344) 2026-02-02 17:00:26 +01:00
Wendelin 3376036392 Fix dropdown width in datatables (#29340) 2026-02-02 13:49:54 +00:00
Paul Bottein ff5ecc047a Fix type error for missing hass.themes race condition in themes mixin (#29338) 2026-02-02 13:44:24 +00:00
Jeremy Cook a8393cddd4 Improved HTML presentation table support to ha-markdown, compatible w… (#29108)
Improved HTML presentation table support to ha-markdown, compatible with companion app on android and iOS

- Support valign attribute for vertical alignment (top, middle, bottom, baseline)
- Support border attribute for cell borders (0, 1, 2, 3px)
- Set default styling for presentation tables (no borders, no padding)
- Use CSS variables for customization
- Include future-proof @supports rule for attr() function
- Maintain backward compatibility with existing markdown tables
2026-02-02 15:17:12 +02:00
Tom Carpenter edfc33039b Merge Long Term Statistics for Power Sensors in Energy Dashboard (#29319)
* Merge Long Term Statistics for Power Sensors in Energy Dashboard

When using 5minute data for the power sources chart, data would be missing if the selected range was beyond the short term statistics limit. This change takes data from long term statistics and merges it in to the power sources data if the short term statistics doesn't extend far enough back for the selection.

* Skip for zero-length power statistics

Prevent out of bounds array access if power statistics has no entries.
2026-02-02 15:11:52 +02:00
ildar170975 14f8d982a9 hui-gauge-card-editor: use imported code for actions (#29326)
use imported code for actions
2026-02-02 15:02:22 +02:00
Marcin BauerandClaude Opus 4.5 847a040fa7 Keep focus on search field when clicking filter chips (#29249)
Co-authored-by: Claude Opus 4.5 <[email protected]>
2026-02-02 13:45:54 +01:00
Aidan Timson 8611359481 Ensure template renderer overflows on overflow (#29335) 2026-02-02 12:07:49 +00:00
Kristel f473ebf18c bugfix: add eventlistener for exposed-entities-changed to Entities page (#29299) 2026-02-02 11:32:32 +00:00
Wendelin 9010898742 Fix missing ha-md-menu in config/labels (#29334) 2026-02-02 11:15:33 +00:00
Petar Petrov 1e30394bf3 Append current entity state to history and statistics charts (#29273) 2026-02-02 09:34:50 +00:00
Paulus Schoutsen bca2cb0c1e Conditionally show HTML5 push notifications (#29227) 2026-02-02 09:24:42 +00:00
Aidan Timson 29317eb842 Show hint only if keyboard shortcuts is enabled (#29332)
Enabled by default, must be explicity disabled
2026-02-02 10:59:14 +02:00
Wendelin a8327ef59a Revert "Fix automation sidebar ui supported check" (#29331) 2026-02-02 08:57:19 +00:00
Petar Petrov 01c8832024 Add area dashboard link to navigation picker (#29264) 2026-02-02 09:51:03 +01:00
Linus Rath a8c633e627 Update untracked consumption threshold to 1W (#29310) 2026-02-02 08:16:34 +00:00
Simon Lamon b659671814 Bump codespace to Python 3.14 (#29316) 2026-02-02 09:52:07 +02:00
dependabot[bot] 3060cdf355 Bump github/codeql-action from 4.31.11 to 4.32.0 (#29329)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.31.11 to 4.32.0.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/19b2f06db2b6f5108140aeb04014ef02b648f789...b20883b0cd1f46c72ae0ba6d1090936928f9fa30)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.32.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-02 08:44:06 +02:00
dependabot[bot] 215241df56 Bump actions/cache from 5.0.2 to 5.0.3 (#29328)
Bumps [actions/cache](https://github.com/actions/cache) from 5.0.2 to 5.0.3.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/8b402f58fbc84540c8b491a91e594a4576fec3d7...cdf6c1fa76f9f475f3d7449005a359c84ca0f306)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 5.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-02 08:43:49 +02:00
renovate[bot] f6852894b0 Update dependency @lokalise/node-api to v15.6.1 (#29322)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-02 06:33:24 +01:00
renovate[bot] 86d7205a3a Update dependency @braintree/sanitize-url to v7.1.2 (#29325)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-02 06:33:03 +01:00
Norbert Rittel 9c16ceda71 Also replace "Sensor type" with "Type of power measurement" (#29317)
Replace "Sensor type" with "Type of power measurement"
2026-02-01 10:44:47 +01:00
karwosts 288789a604 Use ha-form for condition template (#29301) 2026-02-01 10:18:27 +01:00
Norbert Rittel 09139d5bec Replace "Power sensor type" with "Type of power measurement" (#29305) 2026-02-01 09:54:56 +01:00
ildar170975 2d90be9af3 ha-config-device-page: fix placement for tooltip (#29302)
fix placement for tooltip
2026-02-01 09:39:08 +01:00
renovate[bot] 1c6464663e Update dependency @rsdoctor/rspack-plugin to v1.5.1 (#29297)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-01 09:37:46 +01:00
renovate[bot] 189f0b9472 Update dependency node-vibrant to v4.0.4 (#29293)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-31 09:04:52 +02:00
renovate[bot] 771f5eaff4 Update dependency @vibrant/color to v4.0.4 (#29292)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-31 08:49:36 +02:00
renovate[bot] a4cb3b5b01 Update dependency globals to v17.2.0 (#29288)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-30 16:51:11 +00:00
Norbert Rittel eb1ae99a1f Replace "home page" with "Overview page" for preferences panel (#29284)
Replace "home page" with "Overview page"
2026-01-30 17:46:34 +01:00
Aidan Timson 655643eb3f Cleanup padding on matter dashboard expansion panel (#29286)
Cleanup padding on matter config expansion panel
2026-01-30 17:43:32 +01:00
Aidan Timson 02eb1e6832 Fix scrolling for labs page (#29287) 2026-01-30 17:41:40 +01:00
karwosts 62f7a2eea1 Fix areas cannot be deleted (#29285) 2026-01-30 14:01:31 +00:00
Aidan Timson a7f9b93018 Fix type error for missing hass.config race condition in themes mixin (#29280) 2026-01-30 12:54:08 +01:00
Paul Bottein 3e7011e2c8 Fix demo because of new default panel (#29279) 2026-01-30 11:48:47 +01:00
Aidan Timson 97f89bd983 Add missing settings nav items for quick search (#29278)
* Add missing repairs quick search item

* Add voice assistants
2026-01-30 12:11:09 +02:00
renovate[bot] 9aedaeabbf Update dependency @rspack/core to v1.7.4 (#29275)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-30 11:58:31 +02:00
Aidan Timson 7e839dc895 Change default shortcut tip in Quick Search to mod+k, add tip to settings (#29253) 2026-01-30 09:48:03 +00:00
Paul Bottein c2cbf8bd21 Bumped version to 20260128.3 2026-01-30 10:31:26 +01:00
Wendelin 224bcece9c Fix multi select in quick search (#29272)
Add item selection state management to QuickBar component
2026-01-30 10:30:33 +01:00
Wendelin dc84b7698f Fix --wa-color-text-normal (#29271)
Update normal text color variable in wa.globals.ts
2026-01-30 10:30:32 +01:00
Wendelin bc22e6a9bd Fix device download diagnostic via overflow (#29269)
fix diagnostic download link handling to simplify URL signing
2026-01-30 10:30:31 +01:00
Simon Lamon d44874783a Remove duplicated text (#29265) 2026-01-30 10:30:30 +01:00
Paul Bottein 8d1bb5c867 Fix default lovelace yaml loading (#29240) 2026-01-30 10:30:29 +01:00
Wendelin 1f6c916d11 Fix multi select in quick search (#29272)
Add item selection state management to QuickBar component
2026-01-30 10:14:32 +01:00
Wendelin 71bd12bb90 Fix --wa-color-text-normal (#29271)
Update normal text color variable in wa.globals.ts
2026-01-30 09:48:52 +02:00
Simon Lamon e741c14482 Remove duplicated text (#29265) 2026-01-30 08:46:18 +01:00
Wendelin a496448ed9 Fix device download diagnostic via overflow (#29269)
fix diagnostic download link handling to simplify URL signing
2026-01-30 09:42:40 +02:00
renovate[bot] c772285358 Update dependency typescript-eslint to v8.54.0 (#29267)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-30 08:13:50 +02:00
renovate[bot] 4fcdd09935 Update dependency @bundle-stats/plugin-webpack-filter to v4.21.9 (#29266)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-30 08:13:30 +02:00
Paul Bottein 157e89e5e7 Fix default lovelace yaml loading (#29240) 2026-01-29 23:26:39 +01:00
Bram Kragten da1b528eee Bumped version to 20260128.2 2026-01-29 18:04:42 +01:00
Paul Bottein 756138408a Remove default title for new dashboards (#29259) 2026-01-29 18:04:09 +01:00
Paul Bottein 3c8f112565 Prevent action in tile container (#29257) 2026-01-29 18:04:08 +01:00
Paul Bottein 2521f3dde4 Fix actions in dashboard overflow menu (#29256) 2026-01-29 18:04:07 +01:00
TheJulianJES 56390aa01a Fix Matter dashboard using disabled and ignored config entries (#29254) 2026-01-29 17:52:32 +01:00
Paul Bottein 9aac5b19da Stop click propagation when clicking item in icon overflow (#29252) 2026-01-29 17:52:31 +01:00
Wendelin 24afc3dc88 Prevent quick search to close from hot keys (#29251) 2026-01-29 17:52:30 +01:00
Paul Bottein 873c7b2947 Remove unused theme option in distribution card (#29250) 2026-01-29 17:52:29 +01:00
Aidan Timson 648db4276b Add protocols to quick search (#29248)
Add protocols to quick search, extract logic and translations
2026-01-29 17:52:28 +01:00
Aidan Timson f86c3e7856 Remove unused "app" item from quick search (#29244) 2026-01-29 17:52:27 +01:00
Aidan Timson 1d0251cc28 Fixes for picker combo box scrolling and selection (#29242) 2026-01-29 17:52:26 +01:00
Wendelin 518cf87847 Fix quick search apps (#29238) 2026-01-29 17:52:25 +01:00
ildar170975 81a9216c44 computeGroupEntitiesState(): fix condition (#29234)
* fix condition

* fix condition

* prettier
2026-01-29 17:52:24 +01:00
Paul Bottein f0e10e0058 Fix default yaml lovelace panel loading (#29230) 2026-01-29 17:52:23 +01:00
Paul Bottein 5df8ea4f07 Add welcome banner for new overview dashboard (#29223) 2026-01-29 17:52:22 +01:00
Aidan Timson 73f081f5cc Add meta+click/enter support to quick search (#29220)
* Allow meta+click event from combobox

* Handle new tab events for navigations

* Add mod+enter support for new tab

* Helper function
2026-01-29 17:52:21 +01:00
Petar Petrov f0d1db1da6 Add non standard power sensor support (#28845)
* Add non standard power sensor support

* remove useless code

* GridPowerSourceInput type for grid power source saving
2026-01-29 17:52:20 +01:00
Wendelin c223f932f3 Implement fallback for dialog close event in Quick Search (#29260) 2026-01-29 17:41:12 +01:00
Wendelin fcd63e7cba Prevent quick search to close from hot keys (#29251) 2026-01-29 17:20:26 +01:00
Paul Bottein c1bab376c8 Remove default title for new dashboards (#29259) 2026-01-29 16:05:44 +00:00
Aidan Timson 01f5df6671 Add protocols to quick search (#29248)
Add protocols to quick search, extract logic and translations
2026-01-29 17:37:09 +02:00
TheJulianJES 241a655765 Fix Matter dashboard using disabled and ignored config entries (#29254) 2026-01-29 15:27:49 +00:00
Paul Bottein 9841a6341a Remove unused theme option in distribution card (#29250) 2026-01-29 15:26:46 +00:00
Paul Bottein 44c917b4b7 Prevent action in tile container (#29257) 2026-01-29 15:25:55 +00:00
uptimeZERO_ bff785ca68 Move theme settings to user settings (#29255) 2026-01-29 15:14:34 +00:00
Paul Bottein 1f15724024 Fix actions in dashboard overflow menu (#29256) 2026-01-29 15:46:10 +01:00
Paul Bottein ceaa3b8c17 Stop click propagation when clicking item in icon overflow (#29252) 2026-01-29 15:16:37 +01:00
Aidan Timson 7ed3ac1e24 Fixes for picker combo box scrolling and selection (#29242) 2026-01-29 15:11:30 +01:00
ildar170975 cfcb649a6f computeGroupEntitiesState(): fix condition (#29234)
* fix condition

* fix condition

* prettier
2026-01-29 15:35:53 +02:00
Aidan Timson ae036f4084 Remove unused "app" item from quick search (#29244) 2026-01-29 12:18:54 +00:00
Wendelin 6cca48e79d Fix quick search apps (#29238) 2026-01-29 11:30:09 +00:00
Paul Bottein feb9ce421d Fix default yaml lovelace panel loading (#29230) 2026-01-28 23:32:46 +01:00
Marcin BauerandClaude Opus 4.5 9639403865 Reorder profile settings to prioritize user preferences (#29202)
Reorganizes the User settings card on the profile page to show more
frequently used settings first:

- Default dashboard
- Customize sidebar
- Advanced mode (admin)
- Entity ID picker (admin)

Then adds a divider followed by localization settings:

- Language, number format, time format, date format, time zone, first weekday

Co-authored-by: Claude Opus 4.5 <[email protected]>
2026-01-28 14:56:45 -05:00
Aidan Timson 8e8cb095b1 Add meta+click/enter support to quick search (#29220)
* Allow meta+click event from combobox

* Handle new tab events for navigations

* Add mod+enter support for new tab

* Helper function
2026-01-28 18:52:15 +01:00
Paul Bottein 60079ce999 Add welcome banner for new overview dashboard (#29223) 2026-01-28 18:46:22 +01:00
Bram Kragten c658eb414b Bumped version to 20260128.1 2026-01-28 17:52:10 +01:00
Bram Kragten bac493b72b dont include brotli compression 2026-01-28 17:50:19 +01:00
Petar Petrov 4f3196adb9 Add non standard power sensor support (#28845)
* Add non standard power sensor support

* remove useless code

* GridPowerSourceInput type for grid power source saving
2026-01-28 18:20:35 +02:00
Bram Kragten 922e8c7752 Merge branch 'rc' into dev 2026-01-28 16:43:29 +01:00
Bram Kragten e63301cd9c Bumped version to 20260128.0 2026-01-28 16:42:45 +01:00
Aidan Timson 29a3d67e48 AI suggestions: Areas (#29090) 2026-01-28 16:35:24 +01:00
Bram Kragten 4c98a7791b Move developer tools panel to config panel (#29221) 2026-01-28 15:31:47 +00:00
Bram Kragten 5a76c3f606 Make addon selector an alias of app selector (#29222) 2026-01-28 15:27:30 +00:00
Steven TraversandBram Kragten 251a4ce5ce Add device database labs feature (#29104)
Co-authored-by: Bram Kragten <[email protected]>
2026-01-28 14:09:17 +01:00
karwostsandPetar Petrov 408735fa77 Live inline template previews (#27557)
* Live inline template previews

* Opt out for markdown, no fullscreen

* flask/flaskOff

* styling

* mdiBug

* Update src/components/ha-selector/ha-selector-template.ts

Co-authored-by: Petar Petrov <[email protected]>

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

* resub on connect

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-01-28 11:57:41 +02:00
Wendelin c0442b5b39 Fix automation sidebar ui supported check (#29219) 2026-01-28 10:52:12 +01:00
ildar170975 c6284987fd ha-filter-domains: set a plural caption (#29153)
* add "domains" / "caption"

* fix caption
2026-01-28 06:38:33 +01:00
Bram Kragten ed618124dc Fix double action handler area card (#29217) 2026-01-28 06:37:48 +01:00
Paul Bottein 3e350b7642 Attempt to make icon fetching and caching more reliable (#29195) 2026-01-27 21:34:19 +01:00
Paul Bottein c66b4e2027 Update top bar title margin on config and dashboard page (#29212) 2026-01-27 21:32:43 +01:00
Paul Bottein 4c25c639af Don't show back button when opening the add integration sub page directly (#29213) 2026-01-27 21:31:59 +01:00
Paul Bottein 0fbde5024e Fix back button in energy panel (#29214) 2026-01-27 21:31:05 +01:00
Paul BotteinandBram Kragten b991a8122b Set home as default dashboard (#28446)
* Set home as default dashboard

* Handle lovelace to home redirect

* Remove special url path for lovelace

* Rename special rules for lovelace dashboard

* Update src/panels/lovelace/ha-panel-lovelace.ts

Co-authored-by: Bram Kragten <[email protected]>

* Handle default config

* Fix default section

* Early check for lovelace panel

---------

Co-authored-by: Bram Kragten <[email protected]>
2026-01-27 17:08:19 +01:00
Jan Čermák c2c4e06915 Add AppSelector following the Add-ons->Apps rename (#29209) 2026-01-27 15:19:51 +00:00
Aidan Timson 91c12605d3 Add timezone selector (#29205)
* Add timezone selector

* Use timezone selector in clock card
2026-01-27 17:10:39 +02:00
Wendelin cddf91cfd0 Replace ha-md-button-menu with ha-dropdown (#29210) 2026-01-27 15:10:32 +00:00
Paul Bottein 6e1999ceb7 Update top bar background color with the same color as config panel (#29208) 2026-01-27 17:01:15 +02:00
Marcin Bauer 3b571d42fa Add find and replace button to code editor toolbar (#28980) 2026-01-27 14:53:50 +00:00
Marcin BauerandClaude Opus 4.5 08ee742233 Move entity attributes to three-dots menu subview (#29186)
Co-authored-by: Claude Opus 4.5 <[email protected]>
2026-01-27 14:07:23 +00:00
Wendelin b3cc88e124 Fix PickerComboBox to not overwrite local selected section (#29206) 2026-01-27 13:41:45 +00:00
Paul BotteinandWendelin 9fe9456f3c Add link to manage discovered devices in add integration dialog (#29188)
* Add link to manage discovered devices in add integration dialog

* Prettier

* Update src/panels/config/integrations/dialog-add-integration.ts

---------

Co-authored-by: Wendelin <[email protected]>
2026-01-27 14:04:33 +01:00
Wendelin 6d1d7690ef Refactor dropdown menus to use ha-dropdown and ha-dropdown-item components (#29204) 2026-01-27 12:36:53 +00:00
Aidan Timson 4a2b7324f7 Fix position of tooltips in sidebar (#29203) 2026-01-27 12:17:15 +00:00
Aidan Timson 15b85d6f19 Move developer tools to settings (admin) area (#29201) 2026-01-27 11:13:09 +00:00
ildar170975andAidan Timson c49115a91e ha-sidebar: exclude some items from scrollable + fade + various fixes (#28747)
Co-authored-by: Aidan Timson <[email protected]>
2026-01-27 09:55:58 +00:00
Aidan Timson efc67a30f3 Migrate currency picker to generic (#29193)
* Migrate currency picker to generic

* Pass required pro
2026-01-27 11:54:28 +02:00
Aidan Timson bf41b3f7e3 Migrate country picker to generic picker (#29190)
* Migrate country picker to generic picker

* Add country code as secondary text

* Pass required prop

* Remove
2026-01-27 11:08:54 +02:00
TomaszandPetar Petrov 30eb50a962 Add color setting for calendar entities (#28882)
* Enhance calendar entity options with color support and update UI components for color selection

* Add loading spinner to calendar components and improve event loading state management

* simplify

* Remove redundant color change check in HuiCalendarCard update logic

* Add color validation utility and update calendar components to use it. color need to be hex strings

* Adds logic to reset the _eventsLoaded state to false when either the card configuration or the entity registry changes, ensuring events are reloaded appropriately.

* remove casting

* Use SubscribeMixin for entity registry subscription

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-01-27 08:54:41 +00:00
Aidan Timson 567e8c51d0 Migrate timezone picker to generic (#29192)
* Migrate timezone picker to generic

* Pass required prop, remove query
2026-01-27 08:29:50 +02:00
renovate[bot] e214c79cd5 Update dependency vite-tsconfig-paths to v6.0.5 (#29198)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-27 08:24:18 +02:00
renovate[bot] c0cae1cead Update dependency @babel/helper-define-polyfill-provider to v0.6.6 (#29197)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-27 08:23:54 +02:00
Petar Petrov 22742eec84 Group small power consumers into Other node instead of hiding (#29185) 2026-01-26 17:05:41 +02:00
Aidan Timson 37d8273e7c Navigation picker: add sections/grouping and related nav paths (#29094)
* Add sections to navigation picker

* Use PANEL_DASHBOARDS to assign system dashboards to the dashboards section

* Clean

* Add context based related section

* Add integration icon for related device

* Add floor and sort

* Consolidate and cleanup

* Reuse type

* Add context check and catch findRelated errors

* Remove floor from set, use area

* Memoize related updates

* Log error

* Remove

* Fix icon path usage
2026-01-26 15:10:09 +02:00
AlCalzone 9ba34869be Display Z-Wave home ID as hexadecimal (#29187) 2026-01-26 11:58:09 +00:00
Petar Petrov 63284b328c Support app param in my links (#29142) 2026-01-26 08:55:42 +00:00
Simon Lamon 9bb9ae6ad6 Fix tooltip (#29169) 2026-01-26 08:44:45 +00:00
Petar Petrov 0377bf378d Fix sizing of the period selector in energy dashboard (#29183) 2026-01-26 08:42:03 +00:00
KristelandPetar Petrov 7e5ecf4007 bugfix: correct assistant column and filtering for entities without unique id (#29039)
* correct assistant column and filtering for entities without unique id

* _fetchExposedEntities with additional guard

* refactor _getExposedEntitySettingsAsOptions for better code readability

* processed review comments

* move _fetchExposedEntities to firstUpdated

* resolve merge conflicts with #29137

* Update src/panels/config/entities/ha-config-entities.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-01-26 07:27:11 +00:00
renovate[bot] e17055bef0 Update dependency globals to v17.1.0 (#29176)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-26 09:01:06 +02:00
renovate[bot] 38f64b0e93 Update vitest monorepo to v4.0.18 (#29175)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-26 09:00:43 +02:00
dependabot[bot] 4ea207d74a Bump release-drafter/release-drafter from 6.1.0 to 6.2.0 (#29180)
Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 6.1.0 to 6.2.0.
- [Release notes](https://github.com/release-drafter/release-drafter/releases)
- [Commits](https://github.com/release-drafter/release-drafter/compare/b1476f6e6eb133afa41ed8589daba6dc69b4d3f5...6db134d15f3909ccc9eefd369f02bd1e9cffdf97)

---
updated-dependencies:
- dependency-name: release-drafter/release-drafter
  dependency-version: 6.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-26 07:27:55 +01:00
dependabot[bot] 04b0db35f6 Bump actions/setup-python from 6.1.0 to 6.2.0 (#29182)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6.1.0 to 6.2.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/83679a892e2d95755f2dac6acb0bfd1e9ac5d548...a309ff8b426b58ec0e2a45f0f869d46889d02405)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: 6.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-26 07:27:39 +01:00
dependabot[bot] 0d22b88f27 Bump github/codeql-action from 4.31.10 to 4.31.11 (#29181)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.31.10 to 4.31.11.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/cdefb33c0f6224e58673d9004f47f7cb3e328b89...19b2f06db2b6f5108140aeb04014ef02b648f789)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.31.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-26 07:27:20 +01:00
dependabot[bot] ddf209bd8d Bump actions/checkout from 6.0.1 to 6.0.2 (#29179)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/8e8c483db84b4bee98b60c0593521ed34d9990e8...de0fac2e4500dabe0009e67214ff5f5447ce83dd)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-26 07:26:51 +01:00
renovate[bot] ce5c1d2a9f Update dependency @rspack/dev-server to v1.2.1 (#29178)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-26 07:26:37 +01:00
Simon Lamon 31168e1342 Cleanup unused hassio backup files (#29170)
Cleanup
2026-01-25 14:13:18 +02:00
renovate[bot] 5b5c671d89 Update dependency core-js to v3.48.0 (#29165)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-25 07:28:16 +02:00
renovate[bot] e6462835e5 Update dependency prettier to v3.8.1 (#29164)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-25 07:27:42 +02:00
renovate[bot] fa08a9801e Update dependency tar to v7.5.6 (#29154)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-24 07:45:27 +01:00
renovate[bot]andPetar Petrov c1d7100e91 Update dependency tar to v7.5.4 [SECURITY] (#29119)
* Update dependency tar to v7.5.4 [SECURITY]

* Update dependency tar to v7.5.4

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <[email protected]>
2026-01-24 05:42:13 +00:00
Paul Bottein 0f1ffaf5ac Remove blue color for header and reduce margin for dashboard view header (#29111)
* Use background color for header color

* Reduce margin above top title in home overview strategy

* Remove dark color (not needed anymore)
2026-01-23 17:42:38 +01:00
Petar Petrov 5ca8fd4095 Fix crash when using invalid visibility condition type (#29150) 2026-01-23 17:34:57 +01:00
renovate[bot] c3277ff8b2 Update dependency @rspack/core to v1.7.3 (#29147)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-23 17:29:10 +01:00
Petar Petrov aac463b34d Update minimum power threshold to 1 W in power sankey (#29148) 2026-01-23 17:28:42 +01:00
ildar170975andPaul Bottein c8471cb623 Refactor processing values w/o unit in "ha-attribute-value" & "hui-attribute-row" (#28540)
* add "hideUnit" to formatEntityAttributeValue()

* add "hideUnit" to formatEntityAttributeValue()

* add "hideUnit" to computeAttributeValueDisplay()

* use formatEntityAttributeValue() with "hideUnit"

* fix logic for "hideUnit" for ha-attribute-value

* prettier

* remove hideUnit from formatEntityAttributeValue()

* revert to the initial code

* revert to the initial code

* revert to the initial code

* use formatEntityAttributeValuePart() to get a value w/o unit

* use formatEntityAttributeValueToParts() instead of formatEntityAttributeValuePart()

* fix a value

* fix name of a const

* Update src/components/ha-attribute-value.ts

Co-authored-by: Paul Bottein <[email protected]>

* Prettier

---------

Co-authored-by: Paul Bottein <[email protected]>
2026-01-23 15:13:24 +00:00
ildar170975 bd33a94749 Add formatEntityAttributeValueToParts() function (and use for Entity card) (#28539) 2026-01-23 08:18:28 +01:00
Simon Lamon 6061f72f3a Fix cast (#29141) 2026-01-23 08:51:01 +02:00
Wendelin de85b08de4 Migrate ha-md-button-menu to ha-dropdown in 6 files (#29137)
Refactor dropdown menus to use ha-dropdown and ha-dropdown-item components

- Replaced ha-md-button-menu and related components with ha-dropdown and ha-dropdown-item in dialog-edit-sidebar, hass-tabs-subpage-data-table, ha-config-devices-dashboard, ha-config-entities.
- Updated event handling to accommodate new dropdown structure.
- Added wa-divider for better visual separation in dropdowns.
- Improved accessibility and usability of dropdown menus across various components.
2026-01-22 20:00:51 +01:00
Paul Bottein 2599804d22 Don't set icon slot in tile card if image url is set (#29140) 2026-01-22 19:23:42 +01:00
renovate[bot] 27e1fc9b91 Update dependency typescript-eslint to v8.53.1 (#29139)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-22 19:11:11 +01:00
ildar170975 ae627a9c66 Data tables: fix sorting for "Assistants" column (#29121)
fix sorting
2026-01-22 18:13:54 +01:00
renovate[bot] 12623c31da Update formatjs monorepo (#29138)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-22 18:13:28 +01:00
Petar Petrov 1ddbf4ba09 Add tap_action and image_tap_action to Area card (#29112)
* Add tap_action and image_tap_action to Area card

* limit actions
2026-01-22 16:05:54 +01:00
Paul Bottein af4d68e2b6 Use translation for media player source and sound mode in more info (#29135) 2026-01-22 14:59:27 +00:00
Wendelin 45b28d382c Remove ha-button-menu component (#29134) 2026-01-22 15:07:02 +01:00
karwosts be007399cc Prevent flashing the energy setup wizard when already configured (#29117) 2026-01-22 12:56:36 +00:00
Paul Bottein 823b4fc4f6 Remove color picker text color (#29133) 2026-01-22 13:49:04 +01:00
Bram Kragten 4e4882b9fa Remove supervisor build (#29132) 2026-01-22 13:30:33 +01:00
Paul Bottein 55c74d7959 Add empty state to Home panel strategies (#29113) 2026-01-22 12:15:27 +00:00
ildar170975andWendelin 3231d46835 ha-label-picker: add color badges (#28977)
Co-authored-by: Wendelin <[email protected]>
2026-01-22 13:04:17 +01:00
Wendelin 0d110cfc7e Migrate all ha-button-menu to ha-dropdown (#29129) 2026-01-22 11:57:37 +00:00
Paul Bottein 936c0cd6aa Open edit area dialog when clicking edit button in area view (#29128) 2026-01-22 11:35:36 +00:00
Wendelin 311cbad8fa Remove download file support checks and related code (#29124) 2026-01-22 12:02:51 +01:00
ildar170975 73a1ce90c3 Data tables: do not show "Assistants" column in "secondary" when narrow (#29120)
fix a column for "narrow"
2026-01-22 09:37:03 +02:00
uptimeZERO_ ea1b7b9dec Media player fixes (#29075)
* aligning ui of dialog and media bar

* refactored media progress logic to be reusable

* updating track times to be consistent with music assistant

* WIP aligning volume slider with music assistant

* migrating to ha-dropdown

* showing volume tooltip on touch devices

* Fixed volume slider going to 100 randomly

* Added scrolling support

* Refactored volume control logic
2026-01-21 20:28:32 +01:00
Paul Bottein fd506d4d72 Add assign area shortcut to home panel (#29082)
* Add assign area shortcut to home panel

* Set empty state for empty other devices page
2026-01-21 17:11:23 +01:00
karwosts a3be09018c Fix add entry button for integrations (#29106) 2026-01-21 16:13:03 +02:00
Wendelin 3364d4f578 Migrate button-menu components to dropdown in 7 files (#29105)
Migrate button-menu components to dropdown in various editors
2026-01-21 15:12:15 +02:00
Paul Bottein 1f04379974 Add button to heading card (#28991)
* Add heading badge button

* Fix look and feel

* Improve editor

* Prettier
2026-01-21 11:38:48 +01:00
Kristel e060c179f6 Refactor ha-automation-picker _applyFilters (#29055) 2026-01-21 10:56:01 +01:00
Wendelin 54b72ce2b8 Migrate button-menu to ha-dropdown 8 files (#29102) 2026-01-21 09:35:25 +00:00
Aidan Timson 5795b8787d Allow helpers area id to fallback to device area if not set (#29093) 2026-01-21 10:22:38 +01:00
Paulus Schoutsen ec742d3342 App store link app panel 2 (#29100)
* Revert "App store to link to app panel"

This reverts commit 415319f69e.

* App store to link to app panel
2026-01-21 06:04:45 +01:00
renovate[bot] e4d6f3c9d7 Update dependency tar to v7.5.3 [SECURITY] (#29045)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-20 17:12:23 +00:00
Paul Bottein 2d496afdbc Add discovered devices to add integration dialog (#29092) 2026-01-20 14:28:29 +00:00
WendelinandClaude Sonnet 4.5 681b60614f Migrate button-menu to ha-dropdown in 9 files (#29089)
Co-authored-by: Claude Sonnet 4.5 <[email protected]>
2026-01-20 14:20:29 +00:00
Petar Petrov 1654a67d30 Refactor area control picker into a separate component (#29080) 2026-01-20 15:04:20 +01:00
renovate[bot] 8f00494d53 Update dependency rspack-manifest-plugin to v5.2.1 (#29091)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-20 15:31:53 +02:00
Joost LekkerkerkerandSimon Lamon d9c7c0422b Allow the main entry type button to be translatable (#28721)
Co-authored-by: Simon Lamon <[email protected]>
2026-01-20 14:25:48 +01:00
Aidan TimsonandNorbert Rittel 2d24447c3c Rename Add-ons to Apps in more areas (#29076)
* Remove add-ons mention in agents file

* Rename user facing form and selector name

* Everything else

* Update more

* Update more

* Update more

* Update more

* Update key

* Update key

* Update keys

* Use translation

* More changes

* Update key

* Backward / Forward compat

* Drop "the"

Co-authored-by: Norbert Rittel <[email protected]>

---------

Co-authored-by: Norbert Rittel <[email protected]>
2026-01-20 13:39:30 +02:00
Paul Bottein 3b8d485ec6 Update log icons (#29084) 2026-01-20 11:40:03 +01:00
WendelinandClaude Sonnet 4.5 4e4a00e3e9 Migrate ha-button-menu to ha-dropdown in 6 files (#29072)
Co-authored-by: Claude Sonnet 4.5 <[email protected]>
2026-01-20 09:29:29 +00:00
Paul Bottein 14f7328f92 Add context to group more info (#29077)
* Add area context in more info group

* Use entity name instead of entry

* Remove filter
2026-01-20 10:26:03 +02:00
Paul Bottein c5ad074dfb Create reusable ha tile container component. (#29038)
* Create reusable component for tile based card

* Fix icon interaction

* Add icon and iconPath props

* Migrate discovered devices card

* Refactor

* Share card style
2026-01-20 08:49:10 +02:00
Paulus Schoutsen 07aa8706ce App store to link to app panel (#29079) 2026-01-20 06:11:56 +01:00
TheJulianJES 1665fa3775 Fix Z-Wave dashboard picker showing disabled config entries (#29078)
* Fix Z-Wave dashboard picker showing disabled config entries

* Fix Z-Wave dashboard picker showing ignored discoveries
2026-01-19 20:08:44 +01:00
Aidan TimsonandWendelin 3be6a87658 Bring scene editor in line with automations and scripts (#29002)
Co-authored-by: Wendelin <[email protected]>
2026-01-19 16:49:54 +01:00
ildar170975 9092de5c28 Entity card: add support of actions (#28949) 2026-01-19 15:13:36 +01:00
Petar PetrovandWendelin e0fc661920 Allow specific entity controls in Area card (#29025)
Co-authored-by: Wendelin <[email protected]>
2026-01-19 14:44:10 +01:00
aaad8e5434 Add distribution card (#28886)
* Add horizontal stacked bar card

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* Refactor to use ha-segmented-bar component

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* Fix spacing when heading is empty

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* Rename card from horizontal-stacked-bar to distribution

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* Fix remaining translation references

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* Add fixed row setting to prevent layout issues

* Add spacing between bar and legend

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* PR review changes

* Improve accessibility and performance

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-01-19 12:46:14 +00:00
Jan Layola 35c668744a Update ha-base-time-input to accept decimal input for seconds (#29058)
* Update ha-base-time-input to accept decimal input for seconds

* Add support for decimal values in time formatting ha-base-time-input
2026-01-19 14:28:08 +02:00
WendelinandClaude Sonnet 4.5 081b0a0222 Migrate ha-button-menu to ha-dropdown in 8 files (#29070)
Migrates the following files from ha-button-menu to ha-dropdown component:
- ha-config-backup-details.ts
- ha-config-areas-dashboard.ts
- ha-config-dashboard.ts
- ha-panel-history.ts
- ha-scene-editor.ts
- ha-config-integrations-dashboard.ts
- thread-config-panel.ts
- ha-panel-developer-tools.ts

Changes:
- Replace ha-button-menu with ha-dropdown
- Replace ha-list-item with ha-dropdown-item
- Change @action event handlers to @wa-select
- Change slot="graphic" to slot="icon" for icons
- Update event handlers from index-based to value-based selection
- Replace <li divider role="separator"> with <wa-divider>
- Update CSS selectors from ha-button-menu to ha-dropdown
- Use type="checkbox" for checkbox dropdown items in integrations dashboard
- Remove unused li[role="separator"] CSS styles

Contributes to #26537

Co-authored-by: Claude Sonnet 4.5 <[email protected]>
2026-01-19 13:11:29 +02:00
829cd96e9b Add apps panel as built-in panel (#28245)
* Add apps panel as built-in panel

* Fix missing translation

* Address cursor comment

* Another cursor fix

* One more cursor fix

* Address PR review comments: localize error messages, fix deprecated method, use spacing tokens (#28246)

* Initial plan

* Address PR review comments: localize error messages, replace substr with substring, use spacing tokens

Co-authored-by: balloob <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: balloob <[email protected]>

* Cursor fix

* Cursor: use willUpdate

* prettier

* Cursor: fix translation placeholder swap

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

* Cursor: clearTimeout

* Cursor: fix race condition

* Update src/translations/en.json

Co-authored-by: Norbert Rittel <[email protected]>

* Apply spacing tokens

---------

Co-authored-by: Copilot <[email protected]>
Co-authored-by: balloob <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
Co-authored-by: Norbert Rittel <[email protected]>
2026-01-19 13:08:15 +02:00
Paulus SchoutsenandPetar Petrov c404e66ee5 Add new app panel (#28214)
* Add ingress panel to Home Assistant

* Better wait until app loaded logic

* Cleaner slug extraction

* Support HA-aware apps integrating more tightly

* Add new file too

* Memoize

* Cursor: use clearTimeout

* Cursor: fix race conditions

* Claude: fixes

* Cursor: fix issues

* Rename hideToolbar to kioskMode

* Hook kiosk mode into native kiosk mode

* Update src/data/route.ts

* Move computeRouteTail to common URL module

* dry refactor

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-01-19 13:08:07 +02:00
Aidan TimsonandWendelin d47d3f9694 Create shared ai task metadata suggestion task (#29012)
Co-authored-by: Wendelin <[email protected]>
2026-01-19 09:42:36 +01:00
dependabot[bot] 622df52167 Bump actions/cache from 5.0.1 to 5.0.2 (#29068)
Bumps [actions/cache](https://github.com/actions/cache) from 5.0.1 to 5.0.2.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/9255dc7a253b0ccc959486e2bca901246202afeb...8b402f58fbc84540c8b491a91e594a4576fec3d7)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 5.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-19 09:44:26 +02:00
dependabot[bot] 20345c3771 Bump actions/setup-node from 6.1.0 to 6.2.0 (#29067)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6.1.0 to 6.2.0.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/395ad3262231945c25e8478fd5baf05154b1d79f...6044e13b5dc448c55e2357c09f80417699197238)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: 6.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-19 09:44:01 +02:00
dependabot[bot] fc7468a43b Bump github/codeql-action from 4.31.9 to 4.31.10 (#29069)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.31.9 to 4.31.10.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/5d4e8d1aca955e8d8589aabd499c5cae939e33c7...cdefb33c0f6224e58673d9004f47f7cb3e328b89)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.31.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-19 09:43:43 +02:00
renovate[bot] c8ab65cde9 Lock file maintenance (#29065)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-19 08:01:36 +02:00
Kristel 001ade24ea Reuse <voice-assistant-brand-icon> (#29046) 2026-01-18 23:55:53 +01:00
karwosts f987cfe91e Use water-heater operation_mode icon translations (#29051) 2026-01-18 23:31:11 +01:00
renovate[bot] 0bc0acebe0 Update formatjs monorepo (#29062)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-18 23:30:07 +01:00
renovate[bot] 2087efca51 Update dependency prettier to v3.8.0 (#29049)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-18 09:57:51 +01:00
renovate[bot] 16a4a07080 Update dependency @rsdoctor/rspack-plugin to v1.5.0 (#29044)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-17 13:26:05 +01:00
renovate[bot] 58eefcb216 Update CodeMirror (#29043)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-17 13:24:01 +01:00
WendelinandClaude Sonnet 4.5 92a36ac687 Migrate ha-button-menu to ha-dropdown in logs and forms (#29036)
Migrate four components from ha-button-menu to ha-dropdown:
- error-log-card: overflow menu with log view switching
- system-log-card: overflow menu for full logs
- ha-filter-categories: category edit/delete actions
- ha-form-optional_actions: add interaction dropdown

Changes:
- Replace ha-button-menu with ha-dropdown
- Replace ha-list-item with ha-dropdown-item
- Update event handlers from @action to @wa-select
- Use value-based selection instead of index-based
- Add proper accessibility labels to trigger buttons

Part of #26537

Co-authored-by: Claude Sonnet 4.5 <[email protected]>
2026-01-16 19:27:14 +01:00
Wendelin 8221ca8971 Add artifact upload step for frontend build in CI workflow (#29034) 2026-01-16 17:30:37 +01:00
Paul Bottein 8f69cbb6c1 Add discovered devices card (#29035) 2026-01-16 17:25:08 +01:00
renovate[bot] 4c111e1a7d Update dependency @codemirror/search to v6.6.0 (#29029)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-16 15:17:31 +02:00
Bram Kragten 956dbb5346 Merge branch 'rc' 2026-01-16 13:36:43 +01:00
Bram Kragten 2b7cd8fe3a Bumped version to 20260107.2 2026-01-16 13:36:27 +01:00
Wendelin dbff31a281 Automation add TCA: fix: prevent multiple dialog closures by tracking closing state (#28978) 2026-01-16 13:36:12 +01:00
Petar Petrov 6572200e8b Respect user-configured grid options for fixed_rows/fixed_columns cards (#28961) 2026-01-16 13:36:11 +01:00
Wendelin 1465515fb8 Fix category-picker unknown check (#28957) 2026-01-16 13:36:09 +01:00
Petar Petrov ddaba99f64 Sanitize names in history card and map card (#28947) 2026-01-16 13:36:08 +01:00
karwosts 1c73bc6f6c Update energy summary visibility condition (#28913)
* Update energy summary visibility condition

* add grid power as special case

* Always show summary when you have powersource
2026-01-16 13:36:07 +01:00
SmartCoder 44870cb3eb Fixed modal visibility issue in settings -> areas -> edit room (#28907)
* Fixed modal visibility issue in settings -> areas -> edit room

* converting both components to use ha-wa-dialog

* removed z-index from ha-wa-dialog

* fixed hardcoded .open in media browser dialog and remove unnecessary z-index CSS variables
2026-01-16 13:36:06 +01:00
Brendan Annable 481a90352b Fix timer restore bug (#28898) 2026-01-16 13:36:05 +01:00
Simon Lamon 9b536b2172 Remove twine and introduce trusted publishing (#27110)
* Remove twine and introduce trusted publishing

* Update release.yaml
2026-01-16 13:36:04 +01:00
Aidan Timson af8659d8ed Migrate automation/script dialogs to ha-wa-dialog (#29030)
* Migrate dialog-automation-save to ha-wa-dialog

* Migrate dialog-automation-mode to ha-wa-dialog

* Migrate dialog-paste-replace to ha-wa-dialog

* Migrate dialog-new-automation to ha-wa-dialog

* Migrate ha-device-automation-dialog to ha-wa-dialog
2026-01-16 13:23:56 +02:00
renovate[bot] c9e1c9e0a3 Update dependency ua-parser-js to v2.0.8 (#29028)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-16 10:14:57 +00:00
renovate[bot] 9d15499953 Update dependency @rspack/core to v1.7.2 (#29027)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-16 10:03:25 +00:00
Wendelin 7d54dd4940 Fix shortcuts ctrl translation (#29024)
* fix: update localization for CTRL key in shortcuts dialog

* fix: update search label in translations for improved clarity
2026-01-16 11:09:34 +02:00
renovate[bot] 8ef717df6e Update dependency typescript-eslint to v8.53.0 (#29019)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-16 11:08:06 +02:00
renovate[bot] 7b4a7403c8 Update babel monorepo to v7.28.6 (#29018)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-16 11:07:40 +02:00
ildar170975andWendelin 22b7c52828 "Voice assistant" column in tables: standardize (#28889)
Co-authored-by: Wendelin <[email protected]>
2026-01-16 09:10:02 +01:00
Remy SharpandWendelin 04dbeb5e84 Fixed dark mode hidden text in debug assistant (#29021)
Co-authored-by: Wendelin <[email protected]>
2026-01-16 08:33:45 +01:00
Simon Lamon db5f823b6b Remove twine and introduce trusted publishing (#27110)
* Remove twine and introduce trusted publishing

* Update release.yaml
2026-01-15 22:50:52 -05:00
uptimeZERO_ 1d241aa49a Truncate long menu item labels in the sidebar (#29005) 2026-01-15 15:41:48 +00:00
Pegasus fece231faf fix: restrict to exact match for data table (#28853) 2026-01-15 15:50:15 +01:00
Aidan Timson fffb3c3a28 Migrate category dialogs to ha-wa-dialog (#29009) 2026-01-15 15:32:43 +01:00
renovate[bot] fe14d436ff Update vitest monorepo to v4.0.17 (#29007)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-15 15:46:10 +02:00
Petar PetrovandWendelin 42e02be928 Add subpage titles in for config panel pages (#28990)
Co-authored-by: Wendelin <[email protected]>
2026-01-15 12:48:33 +01:00
Aydar Gumerbaev 6213b6cd2a Always use fallback for brands URL (#28994) 2026-01-15 11:42:17 +00:00
Aidan Timson cd75c55392 Entity context: voice assistants expose entities (#28992)
* Entity context: voice assistants expose entities

* Load virtualiser

* Refactor filter entities, reduce duplicate renders

* Fix logic
2026-01-15 13:09:38 +02:00
ca325020d7 Add Labs feature note to automation element picker (#28874)
Co-authored-by: Wendelin <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2026-01-15 11:09:11 +00:00
Jeremy Cook 6250402661 Fix vertical-align in markdown tables with presentation role (#29001) 2026-01-15 11:48:43 +01:00
Amit Finkelstein 0bfca79851 Stop dropdown select events from bubbling in automation rows (#28985) 2026-01-15 11:22:23 +01:00
Wendelin 49bddf6139 Automation add TCA: fix: prevent multiple dialog closures by tracking closing state (#28978) 2026-01-15 08:50:55 +01:00
WendelinandSimon Lamon 0daf94e98f Quick bar: new design and area search (#28678)
* Add "Commands" title to quick bar translations in English

* Enhance QuickBar dialog handling and localize commands title

* add nav icons

* Add icons and styles and separate navigation from commands

* handle non admin

* Add areas

* Fix import and shortcuts

* Restructure

* remove area sort

* move keys

* area search keys review

* Fix adaptive dialog slots without header

* Design review

* Review marcin

* Fix safe area bottom

* Fix ios focus

* Make it clearable

---------

Co-authored-by: Simon Lamon <[email protected]>
2026-01-15 09:45:57 +02:00
uptimeZERO_ 00a3237611 Persist theme settings to user profile and allow migration (#28965)
* Moved theme functionality and persistence target

* fixed type mismatch

* using SubscribeMixin

* returning no-op unsub to handle rejection path

* added notification if theme save fails

* using hass instead of state

* renamed theme variable for clarity

* Added toast if theme pref is unavailable

* Always saving theme to localStorage

* Removing localStorage fallback

* Updating local cache when new theme comes from core
2026-01-15 09:40:43 +02:00
StormDev 53deb3f419 Removed uneccessary import in landing-page-network.ts (#29000)
* Removed uneccessary console on landing-page-networks.ts

* Uneccessary import removed in landing-page-networks.ts
2026-01-15 07:26:50 +00:00
Pegasus 6c1c7cead3 Fixes duplicate "Device info" section name when viewing Matter devices. (#28984)
ha-device-info-matter: rename 'Device info' to 'Matter info'

Fixes duplicate "Device info" section name when viewing Matter devices.
The nested expansion panel now displays "Matter info" consistent with
other integrations (e.g., ZHA uses "Zigbee info", Z-Wave uses "Z-Wave info").

Also adds a gallery demo for testing the component.
2026-01-15 09:18:21 +02:00
Jason MadiganandPetar Petrov f8d65cc0ec Make entities on the energy now sankey graph clickable (#28998)
* enhancement: make entities on the energy now sankey graph clickable to show details

Signed-off-by: Jason Madigan <[email protected]>

* add a test

Signed-off-by: Jason Madigan <[email protected]>

* format

---------

Signed-off-by: Jason Madigan <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-01-15 06:44:03 +00:00
Paul Bottein 5be7bad176 Allow to add context to tile card secondary line (#28995) 2026-01-14 19:48:27 +01:00
Paul BotteinandPetar Petrov 0a54a93a39 Use tabs for bluetooth panel (#28824)
Co-authored-by: Petar Petrov <[email protected]>
2026-01-14 14:38:10 +01:00
Petar Petrov 156583aff1 Include the area when duplicating a scene from the scene dashboard (#28955) 2026-01-14 12:28:05 +01:00
Aidan Timson 7572257821 Match expose config dashboard for assistants columns (#28956) 2026-01-14 11:43:56 +01:00
Pegasus 4703cf802f Change border-quiet token values from 80 to 90 (#28976) 2026-01-14 09:28:32 +00:00
ildar170975 55c2315329 ha-label-picker: remove valueRenderer (#28975) 2026-01-14 10:15:39 +01:00
WendelinandPetar Petrov 7d7e95ac55 Improve device automation UI (#28967)
* Improve device automation rows

* Improve device automation type picker

* Update src/panels/config/automation/condition/ha-automation-condition-row.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-01-14 07:06:56 +00:00
ildar170975 6d7694caff ha-label-picker, ha-category-picker: fix icon for "no items available" (#28973)
* remove NO_LABELS

* remove NO_CATEGORIES

* reverted removed icon
2026-01-14 08:42:24 +02:00
calm d7b6243698 Fix tree view heading overlapping Show more button (#28872) (#28968) 2026-01-13 18:34:39 +01:00
calm 73feef9e92 Remove box-shadow from automation dialog "Show more" button (#28945) (#28960) 2026-01-13 17:31:55 +01:00
renovate[bot] 453a546574 Update Node.js to v24.13.0 (#28963)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-13 15:16:03 +00:00
Petar Petrov 52c0e6f1f5 Respect user-configured grid options for fixed_rows/fixed_columns cards (#28961) 2026-01-13 16:24:25 +02:00
Aidan Timson 444f8d87b3 Ignore all node_modules, not just from root dir (#28959) 2026-01-13 13:51:54 +01:00
Pegasus 57a586c3a7 fix: update the z-index of search button mainly for yaml mode (#28878) 2026-01-13 13:41:53 +01:00
Pegasus 1975265e6b Update the Select Option type from any to string per documentation (#28954) 2026-01-13 10:44:02 +01:00
Wendelin 66e6cb8dbc Fix category-picker unknown check (#28957) 2026-01-13 09:39:05 +00:00
Petar Petrov 9ce9d254f8 Picture elements position by click (#28597) 2026-01-13 10:01:07 +01:00
ildar170975anduptimeZERO_ 1beca4bfa6 ha-data-table: issues with "numeric" column (#28916)
Co-authored-by: uptimeZERO_ <[email protected]>
2026-01-13 08:38:15 +00:00
Kristel 82ab29cfc5 Add "Voice assistant" filter to helpers, automations, scenes and scripts pages (#28914) 2026-01-13 08:29:28 +00:00
Simon Lamon 3579c66f71 Update dropdown adjustments (#28294) 2026-01-13 08:54:17 +01:00
ildar170975 c042a8e310 ha-sidebar: remove scrollIntoViewIfNeeded() (#28938)
remove scrollIntoViewIfNeeded()
2026-01-13 07:23:20 +01:00
renovate[bot] 8d2794a4ee Update dependency vite-tsconfig-paths to v6.0.4 (#28952)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-13 07:15:15 +01:00
Paul Bottein 50be1d9345 Use action button text name for empty state card (#28948) 2026-01-12 17:42:01 +01:00
Petar Petrov c551bf03b6 Sanitize names in history card and map card (#28947) 2026-01-12 15:28:32 +00:00
Paul Bottein cd062293fc Add config to empty state card and use it in area empty page (#28946)
* Add config to empty state card and use it in area empty page

* Remove old translations
2026-01-12 16:58:59 +02:00
e89ea47d3a Add Matter status to config dashboard (#28825)
Co-authored-by: Norbert Rittel <[email protected]>
Co-authored-by: Bram Kragten <[email protected]>
2026-01-12 15:45:18 +01:00
SmartCoder 2cd209a6a4 Fixed modal visibility issue in settings -> areas -> edit room (#28907)
* Fixed modal visibility issue in settings -> areas -> edit room

* converting both components to use ha-wa-dialog

* removed z-index from ha-wa-dialog

* fixed hardcoded .open in media browser dialog and remove unnecessary z-index CSS variables
2026-01-12 15:07:56 +02:00
9bbc761736 Fix: Allow dismissing add integration and helper dialogs with escape/click (#28944)
* refactor: polish automation dialog UI and component styles

* Revert "Merge pull request #1 from marcinbauer85/fix/ui-polish-automation-dialog"

This reverts commit c2c47197e2, reversing
changes made to 49bed5e6a6.

* Fix: Allow dismissing add integration and helper dialogs

* Apply suggestions from code review

Co-authored-by: Wendelin <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2026-01-12 13:39:16 +01:00
Daniel O'Connor 9097faa04b Config > Helpers > Add loading filter state from URL (#28924) 2026-01-12 13:38:04 +01:00
SmartCoder fcf844cf1a Fix issue #28896: "Last 12 months" in the Datetime Picker selects last year (#28902)
Summary of the fix:
The Problem:
now-12m was selecting the calendar year (Jan 1st to Dec 31st) instead of the last 12 months from now
It used startOfMonth and endOfMonth, which snap to month boundaries
The Solution:
Changed to match the now-7d and now-30d pattern
Now uses subMonths(today, 12) for start and subMonths(today, 0) (which equals today) for end
This gives exactly the last 12 months (365/366 days) ending at the current time
The Fix:
// Before (WRONG):calcDate(subMonths(today, 12), startOfMonth, ...)  // Jan 1st of 12 months agocalcDate(subMonths(today, 1), endOfMonth, ...)     // Dec 31st of last month// After (CORRECT):calcDate(today, subMonths, hass.locale, hass.config, 12)  // 12 months ago from nowcalcDate(today, subMonths, hass.locale, hass.config, 0)   // now
2026-01-12 11:53:08 +00:00
dcapslock 8808c31e98 Fix ha-card styling of .card-content when not first element but not following .card-header (#28935) 2026-01-12 12:41:14 +01:00
Michael e0a9f5a08a Show also not installable updates on update overview page (#28717)
* add "show not installable option" to update page

* split updates by install feature and show always

* fix

* fix "no update" panel

* use `nothing` instead of empty string

* re-add `outlined` to ha-card

* keep title, use different for not-installable updates
2026-01-12 13:18:53 +02:00
Petar Petrov 56d71c8e54 Use temp & humidity data from attributes in Area card (#28530)
* Use temp & humidity data from attributes in Area card

* Avoid duplicate sensor readings by tracking devices contributing values
2026-01-12 12:01:12 +01:00
karwosts 125ab4c671 Update energy summary visibility condition (#28913)
* Update energy summary visibility condition

* add grid power as special case

* Always show summary when you have powersource
2026-01-12 12:42:16 +02:00
Eduardo Tsen 8014216c45 Fix ha-entity-toggle not restoring old state on exception (#28915) 2026-01-12 10:28:23 +00:00
ildar170975 55ba331489 developer-tools-statistics: alignment for "fix" column (#28942) 2026-01-12 11:25:44 +01:00
karwosts ad2ff672b0 Add configurable confirmation title & button text (#28931) 2026-01-12 10:19:09 +00:00
JLoandClaude Sonnet 4.5 00907ecd17 Add area and device context to media player join dialog (#28926)
* Add area and device context to media player join dialog

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* Add memoization to avoid recomputing display data

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>
2026-01-12 11:08:44 +01:00
Petar Petrov 07d8219136 Add ES5-compatible keyed directive implementation (#28941) 2026-01-12 10:50:38 +01:00
Eduardo Tsen f37241c84c Fix hui-select-entity-row restoring old state (#28918) 2026-01-12 09:43:31 +00:00
SmartCoder 65d046132d Updated entity name to friendly name (#28928) 2026-01-12 10:14:23 +01:00
Simon Lamon 122cf40092 Don't close dialog upon tooltip close (#28927) 2026-01-11 20:23:42 -05:00
SmartCoder 28ed5c86c7 Fix automation row menu icon being pushed off-screen on mobile (#28893)
When entity names are too long, the header text would push the three-dot menu icon off the right edge of the screen, making it inaccessible. This fix ensures the menu icon remains visible by:

- Adding min-width: 0 to the header slot to allow proper flexbox shrinking and text wrapping

- Adding flex-shrink: 0 to the icons container to prevent it from being compressed

The fix uses standard flexbox properties that work universally across all screen sizes, ensuring the menu icon stays visible on both mobile and desktop views.
2026-01-10 15:58:28 +01:00
Kristel 1f99c3d895 Add Voice assistants filter to Entities page (#28854)
* create Assistants filter

* render logo and name

* make the Voice assistants filter work

* integrate cloudStatus

* code clean-up

* remove cloudStatus

* bugfix

* remove console log

* remove cloudstatus

* set ha-list clientHeight to 49px
2026-01-10 12:57:33 +01:00
LG-ThinQ-Integrationandyunseon.park f2293713de Add target_humidity_step to humidifier (#28005)
Co-authored-by: yunseon.park <[email protected]>
2026-01-10 10:12:55 +01:00
Brendan Annable b3f202400c Fix timer restore bug (#28898) 2026-01-10 09:51:19 +01:00
ildar170975 010d87bd0d ha-dialog-automation-save: small improvements & fixes (#28561)
* explictly set line-height for "helper" element

* move "description" to bottom, css tweaks

* revert

* revert, make a helper persistent
2026-01-10 09:40:10 +01:00
karwosts b403b8f09e Implement allow_negative for duration selector (#28909) 2026-01-10 08:58:14 +01:00
Bram Kragten 78d41dfd55 Merge branch 'rc' 2026-01-09 23:28:00 +01:00
Bram Kragten 905435db3e Bumped version to 20260107.1 2026-01-09 23:26:47 +01:00
Yosi Levy ea73fd3f01 Fix for volume scroll in media player (#28891) 2026-01-09 23:26:22 +01:00
Yosi Levy e519a0203e Arrow fixes in media browser (#28890) 2026-01-09 23:26:21 +01:00
Bram Kragten d98ee7e0b5 Add support for choose selector to initial form data (#28876)
* Add support for choose selector to initial form data

* Update compute-initial-ha-form-data.ts
2026-01-09 23:26:20 +01:00
Bram Kragten 6fc8c17909 Fix color palette creation (#28867) 2026-01-09 23:26:19 +01:00
dcapslock 201169c3d8 Fix choose selector active_choice when card editor config changes (#28858) 2026-01-09 23:26:18 +01:00
DAccordandDAccord 303538ac21 Handling empty history (#28852)
Co-authored-by: DAccord <[email protected]>
2026-01-09 23:26:17 +01:00
karwosts b9a3dc795b Duration selector: migrate legacy duration formats (#28880) 2026-01-09 20:30:09 +01:00
Bram Kragten 35dbfdebcf Add support for choose selector to initial form data (#28876)
* Add support for choose selector to initial form data

* Update compute-initial-ha-form-data.ts
2026-01-09 19:57:32 +01:00
renovate[bot] c5e5fb3ace Update formatjs monorepo (#28905)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-09 17:41:54 +00:00
Yosi Levy e649472b20 Arrow fixes in media browser (#28890) 2026-01-09 18:31:25 +01:00
Yosi Levy 3cbb24a4c5 Fix for volume scroll in media player (#28891) 2026-01-09 18:30:45 +01:00
renovate[bot] f92608a9d3 Update dependency @codemirror/view to v6.39.9 (#28903)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-09 18:23:11 +01:00
renovate[bot] 6591cdc5c1 Update dependency @rspack/core to v1.7.1 (#28892)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-09 18:22:51 +01:00
renovate[bot] 0ae1ac367d Update dependency lit-html to v3.3.2 (#28762)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-09 08:32:27 +02:00
renovate[bot] 6d3a1b93e1 Update dependency lit to v3.3.2 (#28761)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-08 21:03:20 +01:00
renovate[bot] 6d7b22a21c Update dependency typescript-eslint to v8.52.0 (#28879)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-08 20:54:45 +01:00
Petar Petrov 784ee22623 Removes duplicate closing tag in ha-auth-form-string (#28883) 2026-01-08 20:53:55 +01:00
Aidan Timson c03654ef8e Fix wa dialog esc behaviour when preventing scrim closure (#28875)
* Fix wa dialog esc behaviour when preventing scrim closure

* Use wa-hide event to prevend closure
2026-01-08 17:10:53 +00:00
Pegasus 826cb3117d Fix: update the id, pan id to capitalize (#28873)
fix: update the id, pan id to capitalize
2026-01-08 12:26:49 +00:00
Aidan Timson f77fa26ffe Fix type error for calendar card (#28869) 2026-01-08 12:57:46 +02:00
Bram Kragten 35e30f9184 Fix color palette creation (#28867) 2026-01-08 10:14:03 +00:00
DAccordandDAccord 7dd3ade678 Handling empty history (#28852)
Co-authored-by: DAccord <[email protected]>
2026-01-08 09:58:38 +00:00
karwosts 6d1e15d11a Add a devtools event listener filter (#28849) 2026-01-08 10:58:24 +01:00
Timothy f5b33922ff Move companion app settings to a dedicated section in the settings (#28830) 2026-01-08 10:36:50 +01:00
dcapslock ceb7baf851 Fix choose selector active_choice when card editor config changes (#28858) 2026-01-08 10:20:42 +01:00
ildar170975 d195fd3244 Views: allow showing both icon & text title (#28690) 2026-01-07 19:03:48 +00:00
renovate[bot] 231cd632d6 Update dependency @bundle-stats/plugin-webpack-filter to v4.21.8 (#28846)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-07 17:23:37 +01:00
Bram Kragten ac88f3ed0b Merge branch 'rc' 2026-01-07 16:32:25 +01:00
Bram Kragten 3c5a6193d0 Bumped version to 20260107.0 2026-01-07 16:32:09 +01:00
Wendelin 5ee4bd63f8 Fix logs provider picker mobile width (#28847) 2026-01-07 16:31:52 +01:00
Wendelin b193929bd9 Throttle unknown value checks in ha-generic-picker (#28842) 2026-01-07 16:31:51 +01:00
Paul Bottein 3bee5c8cd4 Remove ha-combo-box-textfield (#28841) 2026-01-07 16:31:50 +01:00
Paul Bottein 976c74b8da Prefill the field with current value when editing a custom text item (#28840) 2026-01-07 16:31:49 +01:00
Wendelin 3a4a13db21 Improve device picker performance (#28835) 2026-01-07 16:31:48 +01:00
Paul Bottein a2f033dd88 Reduce shadow effect for scrollable fade mixin (#28832) 2026-01-07 16:31:46 +01:00
Bram Kragten a44b94c8df Prevent showing error during loading of statistics picker (#28823) 2026-01-07 16:31:45 +01:00
Wendelin 82d72ea39c Fix logs provider picker mobile width (#28847) 2026-01-07 16:30:49 +01:00
Wendelin 022bebb14f Throttle unknown value checks in ha-generic-picker (#28842) 2026-01-07 16:14:33 +01:00
Paul Bottein 0981ae1b4a Prefill the field with current value when editing a custom text item (#28840) 2026-01-07 15:42:47 +01:00
Paul Bottein 9608824a28 Remove ha-combo-box-textfield (#28841) 2026-01-07 15:39:58 +01:00
Marcin Bauer 33d215533e Add Shift+/ shortcut to shortcuts dialog and use Unicode command character (#28838)
* refactor: polish automation dialog UI and component styles

* Revert "Merge pull request #1 from marcinbauer85/fix/ui-polish-automation-dialog"

This reverts commit c2c47197e2, reversing
changes made to 49bed5e6a6.

* Add shortcuts dialog shortcut and use Unicode command character

* Update shortcut description text
2026-01-07 14:17:18 +00:00
Paul Bottein 5c503ecac0 Reduce shadow effect for scrollable fade mixin (#28832) 2026-01-07 14:16:41 +00:00
Wendelin d114693fed Improve device picker performance (#28835) 2026-01-07 14:28:18 +01:00
KristelandPetar Petrov 7a8cb80413 Add Voice assistant column to data tables (#28785)
* added Voice assistant column to data tables

* remove commented code

* fix column settings

* code review changes

* reuse voice-assistants-expose-assistant-icon

* refactor getEntityVoiceAssistantsKeys

* fix column width

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-01-07 13:15:01 +00:00
Marcin Bauer f5cd234c4b Refactor: Polish automation dialog UI and component styles (#28831)
* refactor: polish automation dialog UI and component styles

* Update ha-automation-row-targets.ts

- added borders to main automation list chips
2026-01-07 09:27:01 +00:00
karwosts 49bed5e6a6 Standardize all energy period calculations (#28827) 2026-01-07 08:46:54 +02:00
Bram Kragten b84a51235d Prevent showing error during loading of statistics picker (#28823) 2026-01-06 17:40:53 +01:00
Bram Kragten 8796830ff9 Bumped version to 20251229.1 2026-01-06 17:18:45 +01:00
Bram Kragten bdff13d5e1 Use target selector to filter references entities (#28822)
* Use target selector to filter references entities

* Update ha-selector-state.ts
2026-01-06 17:18:20 +01:00
Bram Kragten 4346484afc Use single path for thread icon, add KNX, simplify (#28819)
* Use single path for thread icon, simplify

* Add custom path for KNX
2026-01-06 17:18:19 +01:00
Bram Kragten 533694391e Remove iOS focus handling from dialogs (#28818) 2026-01-06 17:18:18 +01:00
Bram Kragten 3adba7aa1f Fix translation loading of choose selector (#28817) 2026-01-06 17:18:17 +01:00
karwosts b60552c025 Fix statistic-graph-card cutoff w/ energy date picker (#28810)
* Fix statistics-graph energy-date mode end-time with 5min statistics

* don't modify date/hour for 5minute graph

* suggestedMax use period instead of days

* go back to string types
2026-01-06 17:18:16 +01:00
Paul Bottein 3011d56101 Show close button when zwave firmware update is finished (#28805) 2026-01-06 17:18:15 +01:00
Aidan Timson c903c0d734 Add option for any state and show translated label for entity state values (#28803)
* Add option for any state

* Use translated labels for value
2026-01-06 17:18:14 +01:00
Aidan TimsonandPaul Bottein 14be390994 Remove duplicate custom items, remove "no matching ..." when allow-custom-value set (#28801)
* Remove duplicate custom items, allow default from picker

* Memoize

* Memoize

* Memoize func

* Don't show no matching item when custom value is allowed

* Remove no items found label now unused

* Cleanup unused translations

* Restore used value

* Remove no items found label now unused

* Remove redundant comment

* Remove searchFn

* Ensure custom value isnt identical

* Fix duplicated value

* Fix duplicated value

* Use additional items for entity state content

* Fix duplicate values

---------

Co-authored-by: Paul Bottein <[email protected]>
2026-01-06 17:18:12 +01:00
Paul Bottein d48019a48e Remove custom value for unknown icon in icon picker (#28800) 2026-01-06 17:18:11 +01:00
Copilotandpiitaya 7b5cbb76ef Display template targets with neutral badge instead of "Unknown area" error (#28799)
* Initial plan

* Add template target display with neutral badge

- Import mdiCodeBraces icon and isTemplate function
- Check if target ID is a template before checking if it exists
- Display grey {} icon with "Template" text for templated targets
- Add "template" translation key to target_summary
- Prevents misleading red "Unknown area" badge for template targets

Co-authored-by: piitaya <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: piitaya <[email protected]>
2026-01-06 17:18:10 +01:00
Paul Bottein c75fab025f Use regular item for bottom padding in combobox (#28798) 2026-01-06 17:18:09 +01:00
karwosts c007206fa0 Fix statistic names w/ energy_date_selection (#28787) 2026-01-06 17:18:08 +01:00
Norbert Rittel ab5b5a4276 A few small spelling fixes in user-facing strings (#28786)
- use correct spelling for "Wi-Fi" trademark
- capitalize "PIN" as abbreviation
- fix spelling of "set up" as verb
- fix sentence-casing
2026-01-06 17:18:07 +01:00
9eb40f8470 Bluetooth panel to support multi adapter (#28763)
* Support multiple adapters in bluetooth panel

* Move connection allocations up

* Make it tabs

* Add icons

* Revert "Add icons"

This reverts commit e338b6e578.

* Revert "Make it tabs"

This reverts commit d1b19d5c3e.

* Fix scanner matching and no active connection slot support

* Update src/panels/config/integrations/integration-panels/bluetooth/bluetooth-config-dashboard.ts

---------

Co-authored-by: Paul Bottein <[email protected]>
Co-authored-by: J. Nick Koston <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-01-06 17:18:06 +01:00
dependabot[bot] bc827d9bf1 Bump qs from 6.14.0 to 6.14.1 (#28760)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-06 17:18:05 +01:00
Simon Lamon 24f5d58691 Make cancel a secondary action in blueprint import (#28754) 2026-01-06 17:18:04 +01:00
Simon Lamon 13505a9104 Fix matter translations (#28752) 2026-01-06 17:18:03 +01:00
Simon Lamon c1d135aa16 Revert lit update (#28751) 2026-01-06 17:18:02 +01:00
Paulus Schoutsen 16d13c3202 Verify bluetooth config entries exist before showing entry (#28745) 2026-01-06 17:18:01 +01:00
Paulus Schoutsen 46b3c34ba1 Hide dashboard controls in kiosk mode (#28742) 2026-01-06 17:18:00 +01:00
Paulus Schoutsen 57a81b9de4 Add config entry picker for Z-Wave JS panel (#28741) 2026-01-06 17:17:58 +01:00
Simon Lamon 69f4f1dbed Provide kioskmode in demo (#28739) 2026-01-06 17:17:57 +01:00
Paulus Schoutsen 355a1aff3f Protocol link updates (#28736)
* Update icons Thread & Insteon

* Remove matter link

* Remove back path from ZHA

* Fix ZHA dashboard config entry
2026-01-06 17:17:56 +01:00
Bram Kragten 602d6a2337 Use target selector to filter references entities (#28822)
* Use target selector to filter references entities

* Update ha-selector-state.ts
2026-01-06 16:16:23 +01:00
Matthias Alphart 6e614cd3f2 Explicitly set ha-wa-dialog content color (#28821) 2026-01-06 16:00:15 +01:00
6793edd68b Bluetooth panel to support multi adapter (#28763)
* Support multiple adapters in bluetooth panel

* Move connection allocations up

* Make it tabs

* Add icons

* Revert "Add icons"

This reverts commit e338b6e578.

* Revert "Make it tabs"

This reverts commit d1b19d5c3e.

* Fix scanner matching and no active connection slot support

* Update src/panels/config/integrations/integration-panels/bluetooth/bluetooth-config-dashboard.ts

---------

Co-authored-by: Paul Bottein <[email protected]>
Co-authored-by: J. Nick Koston <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2026-01-06 16:46:43 +02:00
Bram Kragten ad6e3267c3 Fix translation loading of choose selector (#28817) 2026-01-06 14:24:19 +01:00
Bram Kragten f941117ca4 Remove iOS focus handling from dialogs (#28818) 2026-01-06 13:45:21 +01:00
Bram Kragten aef0bf03e3 Use single path for thread icon, add KNX, simplify (#28819)
* Use single path for thread icon, simplify

* Add custom path for KNX
2026-01-06 12:43:05 +00:00
Simon LamonandPetar Petrov f22f6b74db Remove used from energy usage header (#28775)
* Remove used

* Update src/translations/en.json

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-01-06 11:37:27 +00:00
Aidan TimsonandPaul Bottein 913c4ae24e Remove duplicate custom items, remove "no matching ..." when allow-custom-value set (#28801)
* Remove duplicate custom items, allow default from picker

* Memoize

* Memoize

* Memoize func

* Don't show no matching item when custom value is allowed

* Remove no items found label now unused

* Cleanup unused translations

* Restore used value

* Remove no items found label now unused

* Remove redundant comment

* Remove searchFn

* Ensure custom value isnt identical

* Fix duplicated value

* Fix duplicated value

* Use additional items for entity state content

* Fix duplicate values

---------

Co-authored-by: Paul Bottein <[email protected]>
2026-01-06 11:16:54 +01:00
Matthias AlphartandPetar Petrov 4b7b5fa21a Replace unload event handler for custom panels with pagehide (#28781)
* Replace `unload` event handler for custom panels

* Handle restore from bfcache

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-01-06 09:07:52 +00:00
Norbert Rittel bf6887541b Capitalize counter button labels (#28814)
Capitalized counter button labels
2026-01-06 08:47:51 +02:00
karwosts 26da9f3a37 Fix statistic-graph-card cutoff w/ energy date picker (#28810)
* Fix statistics-graph energy-date mode end-time with 5min statistics

* don't modify date/hour for 5minute graph

* suggestedMax use period instead of days

* go back to string types
2026-01-05 17:28:15 +02:00
Aidan Timson d48520efdf Add option for any state and show translated label for entity state values (#28803)
* Add option for any state

* Use translated labels for value
2026-01-05 16:55:23 +02:00
Aidan TimsonandPetar Petrov d462356122 Reapply "Migrate dialog-device-registry-detail to ha-wa-dialog (#27668)" (#28804)
* Reapply "Migrate dialog-device-registry-detail to ha-wa-dialog (#27668)" (#27716)

This reverts commit 5f75fc5bcb.

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2026-01-05 11:51:12 +00:00
Copilotandpiitaya 9a5cdb0a99 Display template targets with neutral badge instead of "Unknown area" error (#28799)
* Initial plan

* Add template target display with neutral badge

- Import mdiCodeBraces icon and isTemplate function
- Check if target ID is a template before checking if it exists
- Display grey {} icon with "Template" text for templated targets
- Add "template" translation key to target_summary
- Prevents misleading red "Unknown area" badge for template targets

Co-authored-by: piitaya <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: piitaya <[email protected]>
2026-01-05 12:44:58 +01:00
Paul Bottein eaf012d5ff Show close button when zwave firmware update is finished (#28805) 2026-01-05 13:42:55 +02:00
Paul Bottein 19934dad72 Remove custom value for unknown icon in icon picker (#28800) 2026-01-05 10:57:09 +00:00
Paul Bottein 6194f73442 Use regular item for bottom padding in combobox (#28798) 2026-01-05 11:40:54 +01:00
Paul BotteinandClaude Opus 4.5 dbc880fe35 Add warning about running tsc with file arguments (#28797)
Co-authored-by: Claude Opus 4.5 <[email protected]>
2026-01-05 10:08:21 +00:00
karwosts be4e46a3c6 Fix statistic names w/ energy_date_selection (#28787) 2026-01-05 09:51:49 +02:00
renovate[bot]andPetar Petrov 2fce89a689 Update dependency globals to v17 (#28789)
* Update dependency globals to v17

* Add global definitions for audioWorklet in ESLint configuration

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <[email protected]>
2026-01-05 07:11:10 +00:00
renovate[bot] 81d21b0907 Update formatjs monorepo (#28793)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-05 09:04:20 +02:00
dependabot[bot] 65381b1dc5 Bump relative-ci/agent-action from 3.2.1 to 3.2.2 (#28792)
Bumps [relative-ci/agent-action](https://github.com/relative-ci/agent-action) from 3.2.1 to 3.2.2.
- [Release notes](https://github.com/relative-ci/agent-action/releases)
- [Commits](https://github.com/relative-ci/agent-action/compare/c45aaa919ef85620af54242a241ac17a8fa35983...3c681926017930047fc03acaa35cd6a44efcbfc3)

---
updated-dependencies:
- dependency-name: relative-ci/agent-action
  dependency-version: 3.2.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-05 08:51:48 +02:00
Norbert Rittel 7cbede2f6e A few small spelling fixes in user-facing strings (#28786)
- use correct spelling for "Wi-Fi" trademark
- capitalize "PIN" as abbreviation
- fix spelling of "set up" as verb
- fix sentence-casing
2026-01-04 18:07:40 +01:00
renovate[bot] 0a13dddaea Update dependency @rspack/core to v1.7.0 (#28774)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-04 09:12:12 +00:00
renovate[bot] 662be980e8 Update dependency @rspack/dev-server to v1.1.5 (#28773)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-04 10:03:10 +01:00
renovate[bot] 209abf466d Update dependency @codemirror/view to v6.39.8 (#28759)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-02 19:29:57 +01:00
Simon Lamon db9a3bd562 Fix matter translations (#28752) 2026-01-02 11:22:45 +01:00
Paulus Schoutsen 36ecaa6610 Add config entry picker for Z-Wave JS panel (#28741) 2026-01-02 11:20:42 +01:00
Simon Lamon 4f46d0f4a3 Make cancel a secondary action in blueprint import (#28754) 2026-01-02 11:18:37 +01:00
Paulus Schoutsen 42ad47649d Verify bluetooth config entries exist before showing entry (#28745) 2026-01-02 11:18:02 +01:00
dependabot[bot] c62ee6e692 Bump qs from 6.14.0 to 6.14.1 (#28760)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-02 11:16:37 +01:00
Simon Lamon b38c8d7d5f Revert lit update (#28751) 2026-01-02 11:13:09 +01:00
renovate[bot] 83bcc39d5f Update dependency typescript-eslint to v8.51.0 (#28756) 2026-01-02 09:54:41 +01:00
Paulus Schoutsen 8d317d1e2c Hide dashboard controls in kiosk mode (#28742) 2026-01-01 00:36:49 +01:00
Simon Lamon 9acad2e83c Provide kioskmode in demo (#28739) 2025-12-30 22:45:01 +01:00
ildar170975 9099c5a92c Map card editor: add a basic sub-element editor (#28687)
* add subelement editor

* explicit type convertion

* test

* test

* test

* test

* prettier
2025-12-30 20:18:57 +01:00
Paulus Schoutsen 60c4d60d66 Protocol link updates (#28736)
* Update icons Thread & Insteon

* Remove matter link

* Remove back path from ZHA

* Fix ZHA dashboard config entry
2025-12-30 19:54:48 +01:00
sebcaps e8a4cde643 Add energy percentage usage on pie chart view. (#28733)
* showPercent

* unnecessary change
2025-12-30 19:54:35 +01:00
renovate[bot] 148eab31b6 Update dependency jsdom to v27.4.0 (#28726)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-29 19:18:29 +01:00
Franck Nijhof 3a3036c635 20251229.0 (#28727) 2025-12-29 14:34:15 +01:00
Franck Nijhof 9f7683021e Bumped version to 20251229.0 2025-12-29 12:41:19 +00:00
Franck Nijhof 549bd25f5c Merge branch 'master' into dev 2025-12-29 12:38:44 +00:00
Paulus Schoutsen eb74dd541a Show the protocols on the top level of the config section (#28448) 2025-12-29 11:52:20 +01:00
Paulus Schoutsen 4c84c7b54f Add kiosk mode foundation (#28714)
* Add kiosk mode foundation

* last file too
2025-12-29 11:24:24 +01:00
renovate[bot] 3a8f964ebd Update formatjs monorepo (#28724)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-29 05:21:27 +00:00
Christopher Nethercott 211ddcf7a4 Developer Tools: Update both event fire and event listen when clicked. (#28646)
Set the event listen event to one clicked when it isn't currently listening to an event.
2025-12-28 20:40:45 +01:00
renovate[bot] 021e5f5ce0 Update dependency @swc/helpers to v0.5.18 (#28722)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-28 19:03:16 +01:00
Paulus Schoutsen 4398e2d6c2 Remove snow flakes from hot path (#28716) 2025-12-27 20:28:58 +01:00
renovate[bot] e95af3c661 Update dependency @codemirror/view to v6.39.7 (#28713)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-27 19:17:06 +01:00
renovate[bot] 53af746466 Update dependency @lit-labs/observers to v2.1.0 (#28712)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-27 05:51:28 +00:00
renovate[bot] 18103c0e36 Update dependency lit-html to v3.3.2 (#28710)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-27 05:51:18 +00:00
renovate[bot] d6d235d032 Update dependency @lit-labs/motion to v1.1.0 (#28711)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-27 06:41:31 +01:00
renovate[bot] 3761dec700 Update dependency lit to v3.3.2 (#28709)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-27 06:40:45 +01:00
renovate[bot] 606fa41e6e Update dependency @lit/reactive-element to v2.1.2 (#28708)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-27 06:40:32 +01:00
renovate[bot] 0ee37e9544 Update formatjs monorepo (#28706)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-26 20:48:03 +01:00
renovate[bot] b0027b8c18 Update formatjs monorepo (#28704)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-26 16:32:59 +01:00
renovate[bot] a397368e02 Update dependency @codemirror/view to v6.39.6 (#28702)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-26 14:15:09 +00:00
Joep Meindertsma cac89e94df Add history link to statistics graph card (#28500) 2025-12-26 14:06:31 +00:00
Aidan Timson cc2e001990 Migrate area and cropper dialogs to ha-wa-dialog (#28608)
* Migrate area dialog to ha-wa-dialog

* Migrate cropper dialog to wa
2025-12-26 11:40:41 +01:00
renovate[bot] b1e2724aca Update dependency @rsdoctor/rspack-plugin to v1.4.0 (#28701)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-26 10:34:35 +00:00
ildar170975 5a60750841 ha-labels-picker: add a check for undefined label (#28686)
* add a check for undefined label

* simplify fix
2025-12-26 11:24:09 +01:00
ildar170975 94c180d64b state-badge element in Picture elements card: allow to set a "name" option (#28689)
* add "name" to StateBadgeElementConfig

* pass "name" to ha-state-label-badge

* add "name" field
2025-12-26 11:16:31 +01:00
ildar170975 6121f425c4 "Devices" & "Voice assistants expose": fix sort for "-" values (#28692)
* fix sorting for "-" values

* fix sorting for "-" values
2025-12-26 11:06:18 +01:00
renovate[bot] 91028fd0dd Update dependency typescript-eslint to v8.50.1 (#28698)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-26 11:05:21 +01:00
renovate[bot] 082a2c08b9 Update fullcalendar monorepo to v6.1.20 (#28700)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-26 11:05:15 +01:00
renovate[bot] d447dad28d Update CodeMirror (#28697)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-25 18:08:10 +01:00
renovate[bot] 4358ccdff8 Update CodeMirror (#28693)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-25 17:35:28 +02:00
Bram Kragten 8f7dd9b0ef Fix navigation in supervisor panel (#28683) 2025-12-24 13:32:30 +01:00
Paul BotteinandBram Kragten 52db6a16d1 Add other devices view to home dashboard (#28097)
Co-authored-by: Bram Kragten <[email protected]>
2025-12-24 09:38:47 +00:00
karwosts ba213bf11c Don't set history redraw timer when not connected (#28679) 2025-12-24 10:08:35 +01:00
karwosts 5dea6b2c89 Fix a crash when clearing energy statistic (#28680) 2025-12-23 18:38:14 +01:00
Wendelin 97d51094df Add iOS-specific autofocus handling in HaWaDialog (#28607) 2025-12-23 14:43:03 +01:00
Wendelin 0904a1116c Language picker: add search fallback to en (#27818) 2025-12-23 14:41:30 +01:00
Wendelin 282458e645 Automation editor target in row improve configEntry subscription (#28662) 2025-12-23 14:40:55 +01:00
Paul BotteinandWendelin 063c2d776a Improve new color picker (#28663)
Co-authored-by: Wendelin <[email protected]>
2025-12-23 10:36:00 +00:00
Aidan Timson 97e0bc8080 Show icons for ha-tab in desktop views (#28508)
Add icons to tabs
2025-12-22 21:18:54 +01:00
renovate[bot] 21e2c676b8 Update dependency @lokalise/node-api to v15.6.0 (#28668)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-22 20:50:46 +01:00
Paul Bottein 214b8cd5c7 Put favorite at the top for home dashboard (#28665) 2025-12-22 20:50:22 +01:00
renovate[bot] 3bd5481274 Update formatjs monorepo (#28667)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-22 20:39:18 +01:00
Wendelin ac63f991b2 Use generic-picker for log provider select (#28664)
Use generic-picker for log provider switcher
2025-12-22 18:56:22 +01:00
renovate[bot] 97e9129832 Update dependency sinon to v21.0.1 (#28666)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-22 18:02:51 +01:00
dependabot[bot] 704887999b Bump github/codeql-action from 4.31.8 to 4.31.9 (#28659)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.31.8 to 4.31.9.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/1b168cd39490f61582a9beae412bb7057a6b2c4e...5d4e8d1aca955e8d8589aabd499c5cae939e33c7)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.31.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-22 12:19:52 +01:00
ndrwrbgs 3194fe9a30 Add back button to history when coming from history-card title link (#28649) 2025-12-22 09:38:16 +01:00
ndrwrbgs 5ce7308194 Change 'Weekdays' to 'Days of the Week' (#28656) 2025-12-21 21:28:46 +01:00
renovate[bot] f9a9cf0ba0 Update dependency fs-extra to v11.3.3 (#28657)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-21 21:24:12 +01:00
renovate[bot] bf90c6829f Update dependency @lokalise/node-api to v15.5.0 (#28653)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-21 21:23:57 +01:00
karwostsandPetar Petrov 36d4097ff8 Add select-all to media management dialog, design update, migrate to wa (#28595)
* Add select-all to media management dialog, design update

* Update src/components/media-player/dialog-media-manage.ts

Co-authored-by: Petar Petrov <[email protected]>

* remove old styles

* css

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-12-21 21:22:40 +02:00
Aidan Timson 92bf8c3d47 Add missing close icon in adaptive dialog mode (#28461)
* Add missing close icon in adaptive dialog mode

* No need for default text

* Restore
2025-12-21 14:53:10 +00:00
renovate[bot] 4251f3468b Update dependency vite-tsconfig-paths to v6.0.3 (#28652)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-21 14:54:09 +01:00
karwosts a6869e7c14 Use-top-label for statistic picker (#28639) 2025-12-20 18:25:42 +01:00
renovate[bot] bd46c358fb Update dependency @codemirror/commands to v6.10.1 (#28642)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-20 10:59:12 +00:00
renovate[bot] 30b8ea1ae8 Update dependency @rspack/core to v1.6.8 (#28643)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-20 11:53:48 +01:00
renovate[bot] a24dacf50d Update formatjs monorepo (#28641)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-20 11:53:03 +01:00
renovate[bot] 7cbd07e33e Update dependency vite-tsconfig-paths to v6.0.2 (#28640)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-20 08:57:07 +01:00
renovate[bot] c72ad83532 Lock file maintenance (#28621)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-19 19:11:00 +00:00
renovate[bot]andSimon Lamon f2aba45dfe Update formatjs monorepo (major) (#28619)
* Update formatjs monorepo

* Add compiler paths

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Simon Lamon <[email protected]>
2025-12-19 18:58:38 +00:00
Bram Kragten 639c2ce077 Add choose selector (#28624)
* Add choose selector

* add support for translation

* pass required

* Add to gallery
2025-12-19 19:52:31 +01:00
renovate[bot]andSimon Lamon 1bddc02ae0 Update dependency @formatjs/intl-durationformat to v0.8.1 (#28617)
* Update dependency @formatjs/intl-durationformat to v0.8.1

* Add compiler path for polyfill

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Simon Lamon <[email protected]>
2025-12-19 18:33:11 +00:00
Simon ebea5176e2 Add npmMinimalAgeGate to .yarnrc.yml (#28638) 2025-12-19 17:53:57 +00:00
Petar PetrovandBram Kragten 39f550cf9f Fix datetime handling in energy charts (#28345)
* Fix datetime handling in energy charts

* PR comment

* Add detailedDailyData parameter to getSuggestedMax and update getCommonOptions

* refactor

---------

Co-authored-by: Bram Kragten <[email protected]>
2025-12-19 18:47:18 +01:00
Paul BotteinandAidan Timson cdcbd00a92 Remove ha-space-0 (#28635)
* Remove ha-space-0

* Update src/components/ha-sidebar.ts

Co-authored-by: Aidan Timson <[email protected]>

* Fix variable inside calc

* Replace for variables

---------

Co-authored-by: Aidan Timson <[email protected]>
2025-12-19 17:12:28 +01:00
Bram Kragten 5b0bd9d577 Merge branch 'rc' 2025-12-19 17:05:32 +01:00
Bram Kragten d839152fd1 Bumped version to 20251203.3 2025-12-19 17:05:16 +01:00
Petar Petrov 407cb79805 Fix power sources graph ordering with multiple sources (#28549) 2025-12-19 17:04:50 +01:00
karwosts 7817ebe983 Home strategy: don't link non-admin to config pages (#28512) 2025-12-19 17:04:49 +01:00
Wendelin 7e58cedd49 Fix ha-toast z-index (#28491) 2025-12-19 17:04:48 +01:00
Wendelin 06334a039c Fix automation add TCA search icons (#28490)
Fix automation add TCA seach icons
2025-12-19 17:04:47 +01:00
Silas Krause 6e5853a1c0 Support legacy table styles in markdown (#28488)
* Remove unnecessary assist styles

* Fix list styles

* Remove table styles for role="presentation"
2025-12-19 17:04:46 +01:00
Wendelin f4f4520773 Fix target picker area in history/activity (#28474)
* Add max target picker width for history and activity

* Fix target picker  area selection in history and activity
2025-12-19 17:04:45 +01:00
karwosts 94453dfba5 Fix markdown card image sizing (#28449) 2025-12-19 17:04:44 +01:00
renovate[bot] 86cd0e81ad Update vitest monorepo to v4.0.16 (#28636)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-19 15:56:52 +00:00
Aidan TimsonandWendelin 6efe444af3 Use space tokens in more info dialog area (#28627)
Co-authored-by: Wendelin <[email protected]>
2025-12-19 16:12:32 +01:00
Wendelin 09c9665b2f Remove ha-combo-box and vaadin dependencies (#28632) 2025-12-19 15:11:17 +01:00
Paul Bottein 23e394fec9 Always add favorite heading for home overview (#28629) 2025-12-19 11:35:44 +00:00
Wendelin 4b02a11634 Migrate ha-selector-select to use ha-generic-picker component (#28614) 2025-12-19 10:06:20 +00:00
Aidan TimsonandWendelin ed9c00cab5 Migrate entity state picker to generic picker (#28613)
Co-authored-by: Wendelin <[email protected]>
2025-12-19 10:52:39 +01:00
Aidan Timson eaa1fb4107 Add space tokens to developer tools (#28626) 2025-12-19 09:33:53 +00:00
Aidan Timson c0a49b3d0b Migrate floor dialog to webawesome (#28606) 2025-12-19 10:21:55 +01:00
karwosts a7a00228a2 Add a debug tool to capture an entity diagnostic details (#28615) 2025-12-19 09:18:13 +00:00
renovate[bot] c85f7a71b2 Update dependency @rsdoctor/rspack-plugin to v1.3.16 (#28623)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-19 09:11:31 +00:00
renovate[bot]andPaul Bottein c95e914219 Update dependency @types/chromecast-caf-receiver to v6.0.25 (#27189)
* Update dependency @types/chromecast-caf-receiver to v6.0.25

* Fix typings

* Fix messageType type json

* Fix FMP4

* Add doc link

* Fix FMP4

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Paul Bottein <[email protected]>
2025-12-19 10:53:48 +02:00
ildar170975 362a0b96ab ha-labels-picker: remove margin-bottom for ha-chip-set (#28559) 2025-12-19 08:55:21 +01:00
Jan Layola ef984fc438 Trim whitespace from 2FA input before validation (#28616) 2025-12-19 08:48:11 +01:00
renovate[bot] ce9bbc9972 Update dependency typescript-eslint to v8.50.0 (#28618)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-18 19:19:20 +01:00
Aidan Timson a3921f0559 Migrate entity state content picker to generic picker (#28612)
* Migrate entity state content picker to generic picker

* Use similar primary/secondary as name picker

* Remove redundant func

* Memoize func

* Add custom value label

* Format

* Remove

* Remove renderer, use better translation

* Format

* Cleanup import

* Remove search labels where unused

* Merge
2025-12-18 19:12:03 +01:00
Aidan TimsonandWendelin f8ec5d27a4 Migrate entity attribute picker to generic picker (#28611)
Co-authored-by: Wendelin <[email protected]>
2025-12-18 17:03:21 +01:00
WendelinandAidan Timson d679916fa5 Migrate domain selection to use generic picker component (#28605)
* Migrate domain selection to use generic picker component

* Remove unused CSS, add margins

* Space tokens

* Fix validation

---------

Co-authored-by: Aidan Timson <[email protected]>
2025-12-18 13:39:16 +00:00
Aidan TimsonandWendelin 96be4768d3 Migrate entity name picker to generic picker (#28604)
Co-authored-by: Wendelin <[email protected]>
2025-12-18 14:31:29 +01:00
Aidan Timson 6ff3b9f761 Migrate new label dialog to ha-wa-dialog (#28586) 2025-12-18 13:22:07 +01:00
Joakim Plate 9026009842 Let event domain expose attributes in gui (#28486) 2025-12-18 12:43:48 +01:00
Aidan Timson 54398a4784 Fix entity settings row sizing (#28585) 2025-12-18 12:42:29 +01:00
Wendelin fa3cc970ec Migrate Z-Wave JS node configuration to use generic picker component (#28603) 2025-12-18 13:30:24 +02:00
Aidan Timson 1cf0560003 Migrate color picker to generic picker (#28598) 2025-12-18 11:23:25 +01:00
Wendelin 2a4ac15987 Generic-picker: Implement allowCustomValue (#28572)
* Introduce allowCustomValue and remove usage

* Review

* Fix secondary title
2025-12-18 12:19:57 +02:00
Aidan Timson f264eebe49 Remove unused prop in target picker (#28601) 2025-12-18 10:14:42 +00:00
Aidan Timson dae27e091f Migrate config entry picker to new picker syntax (#28600) 2025-12-18 10:10:55 +00:00
Aidan Timson 7ca681e417 Refactor generic pickers (#28570) 2025-12-18 10:53:50 +01:00
ndrwrbgsandWendelin 1adfe63322 Add media query for prefers-reduced-motion in dialog styles (#28593)
Co-authored-by: ndrwrbgs <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2025-12-18 08:18:19 +00:00
Wendelin 119a505a0d Add iOS focus element messaging for ha-generic-picker component (#28569) 2025-12-18 09:18:01 +01:00
renovate[bot] 1f8403f6c1 Update dependency vite-tsconfig-paths to v6 (#28596)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-18 09:19:09 +02:00
Wendelin 7dd7309a47 Migrate addon-picker to generic-picker (#28567) 2025-12-17 16:33:41 +00:00
WendelinandPetar Petrov 736afe2530 Migrate config-entry-picker to generic-picker (#28568)
* Use generic-picker for config-entry-picker

* Apply suggestion from @MindFreeze

Co-authored-by: Petar Petrov <[email protected]>

* Apply suggestion from @MindFreeze

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-12-17 13:49:23 +02:00
Paul Bottein 92980dfddf Show summaries at top on mobile, sidebar on desktop (#28573)
* Use weather tile card and energy summary in home dashboard

* Only use sidebar on desktop

* Hide sidebar on mobile

* Rename widget to summaries

* Improve commonly used

* Feedbacks

* Use key instead of section
2025-12-17 11:45:27 +02:00
karwostsandPetar Petrov 9f3d6e1fea fix read-only fields in config flow expandables (#28579)
* fix read-only fields in config flow expandables

* types

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-12-17 07:29:56 +00:00
ildar170975 9e9adfcc90 ha-data-table: add ellipsis for ".secondary" (#28577)
add ellipsis for ".secondary"
2025-12-17 06:41:07 +01:00
karwosts 9b6ebdfcc0 device selector - add missing disabled & helper (#28576)
* device selector - add missing disabled & helper

* more
2025-12-17 06:39:50 +01:00
Aidan Timson 88faedba65 Migrate ha-icon-picker to generic picker (#27677) 2025-12-16 15:14:44 +00:00
Aidan Timson b125cd5f3e Migrate hui-dialog-select-dashboard to ha-wa-dialog (#28456) 2025-12-16 13:47:50 +01:00
Aidan Timson 3425837de3 Switch energy now chart to watts, format values to W, kW etc (#28555)
* Switch energy now chart to watts

* Add kW

* Scale formatted value based on powers of 1000

1000 W -> 1 kW
W → kW → MW → GW → TW

* Explainers

* Use 3 dp for kW+ and 0 for W

* Add non-integer test
2025-12-16 14:33:45 +02:00
Paul Bottein 24a797e46a Improve shadow and border for energy date picker (#28566)
* Improve shadow and border for energy date picker

* Use variable

* Fix z-index

* Fix margin

* Improve mobile margin
2025-12-16 14:05:47 +02:00
Copilotandpiitaya 4a486ff28b Add fallback for empty cards in sections view (#28565)
* Initial plan

* Add edit-mode class to container in hui-grid-section to enable minimum card height

Co-authored-by: piitaya <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: piitaya <[email protected]>
2025-12-16 10:17:28 +00:00
Clément Notin 6be390a07e Add ignoreLocation option to fuseMultiTerm config (#28557) 2025-12-16 09:44:33 +01:00
Wendelin c93942919b Automation editor show targets within rows (#28510)
* Automation editor show targets within rows

* review

* Fix expandable row icons

* Use state icon instead of state-badge

* Fix target wrap

* Use default font weight for automation rows

* Remove comma from targets in row
2025-12-16 09:42:38 +02:00
ildar170975 ca06269a91 Entity card: remove whitespaces in span (#28562) 2025-12-16 08:18:13 +01:00
ildar170975 b3d7c0b6dc Helpers table: show dashes in "Area" column (#28563) 2025-12-16 08:16:15 +01:00
Paul Bottein e709703f79 Wait for translations before showing home and domain dashboards (#28556) 2025-12-16 08:11:15 +01:00
renovate[bot] fd42614a23 Update dependency eslint to v9.39.2 (#28560)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-16 08:41:38 +02:00
Petar PetrovandPaul Bottein 4050dd0384 Fixed period selector for energy dashboard (#28458)
* Sticky period selector for energy dashboard

* Blur view when date picker is open

* move to hui-root via slot

* fix scrollbar

* Use dialog backdrop and define default

* Set energy selector position to fixed

* format

---------

Co-authored-by: Paul Bottein <[email protected]>
2025-12-15 18:21:46 +01:00
Petar Petrov 9996b1bfea Fix inability to leave scene creation page without saving (#28546) 2025-12-15 16:59:57 +01:00
Petar Petrov 8092340d2a Fix min max issues in statistics chart (#28493) 2025-12-15 15:54:47 +01:00
Petar Petrov 443e205395 Fix power sources graph ordering with multiple sources (#28549) 2025-12-15 15:52:59 +01:00
Wendelin 8c5d0c4b80 Use ha-state-icon for add from target entity icon (#28551) 2025-12-15 15:51:17 +01:00
Paul Bottein 3005f12ef5 Restore navigation header for home, light, security and climate dashboards (#28552) 2025-12-15 15:44:51 +01:00
3bcf530200 Storage space breakdown chart (#28311)
Co-authored-by: Aidan Timson <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2025-12-15 15:10:35 +01:00
ildar170975andPetar Petrov af2fa98666 ha-map: add a variable for marker size (#28536)
* use a new variable for width & height

* use a new variable for width & height

* fix styles & creation of marker

* iconSize -> markerIconSize (for zones)

* Apply suggestion from @MindFreeze

Co-authored-by: Petar Petrov <[email protected]>

* format

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-12-15 13:01:27 +00:00
renovate[bot]andPetar Petrov 8f335668db Update Node.js to v24 (#27687)
* Update Node.js to v24

* fix test

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <[email protected]>
2025-12-15 14:56:48 +02:00
Aidan Timson 51acd271ea Add duplicate voice assistant action (#28511) 2025-12-15 13:12:57 +01:00
dependabot[bot] 830e9b5089 Bump dessant/lock-threads from 5.0.1 to 6.0.0 (#28545)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 11:12:59 +00:00
dependabot[bot] b13cb84baf Bump actions/upload-artifact from 5.0.0 to 6.0.0 (#28542)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 11:12:33 +00:00
renovate[bot] f8df7f37ea Update dependency @codemirror/view to v6.39.4 (#28548)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-15 12:32:35 +02:00
Aidan Timson 54e4f4e60a Attempt to ensure view transitions are always ran (#28547) 2025-12-15 11:24:50 +01:00
ildar170975andAidan Timson 81cb483163 Generic picker: show a label for area, category, language (#28236)
Co-authored-by: Aidan Timson <[email protected]>
2025-12-15 08:54:12 +00:00
dependabot[bot] eb5b14ea00 Bump actions/cache from 4.3.0 to 5.0.1 (#28543)
Bumps [actions/cache](https://github.com/actions/cache) from 4.3.0 to 5.0.1.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/0057852bfaa89a56745cba8c7296529d2fc39830...9255dc7a253b0ccc959486e2bca901246202afeb)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 5.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 08:20:03 +02:00
renovate[bot] b221fbb387 Update dependency @rsdoctor/rspack-plugin to v1.3.15 (#28541)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-15 06:11:43 +00:00
dependabot[bot] 3033bfb1fb Bump github/codeql-action from 4.31.7 to 4.31.8 (#28544)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.31.7 to 4.31.8.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/cf1bb45a277cb3c205638b2cd5c984db1c46a412...1b168cd39490f61582a9beae412bb7057a6b2c4e)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.31.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 08:11:38 +02:00
karwosts 8db967eb2f Fix navigate action after confirm (#28535)
Fix navigate on confirm
2025-12-15 08:11:20 +02:00
renovate[bot] 10af86cc02 Update dependency terser-webpack-plugin to v5.3.16 (#28537)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-15 08:03:40 +02:00
renovate[bot] dfc7116819 Update dependency @codemirror/view to v6.39.3 (#28533)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-14 15:56:09 +01:00
ildar170975 685c642bfc hui-map-card: add firstUpdated() with _getMapEntities() (#28526)
add firstUpdated() with _getMapEntities()
2025-12-13 17:15:57 +02:00
renovate[bot] 2e547937b8 Update dependency @rsdoctor/rspack-plugin to v1.3.13 (#28532)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-13 16:32:52 +02:00
Michael Bisbjerg e3e01c327a Fix trace download truncation with Jinja comments (#28519) 2025-12-13 09:50:42 +02:00
renovate[bot] abd706fed0 Update dependency @codemirror/view to v6.39.2 (#28522)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-13 07:59:22 +01:00
renovate[bot] 3bd45dd29b Update dependency ua-parser-js to v2.0.7 (#28516)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-12 15:34:04 +01:00
renovate[bot] 206f067d2b Update dependency @rspack/core to v1.6.7 (#28518)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-12 15:31:53 +01:00
renovate[bot] caefa7530a Update dependency @codemirror/view to v6.39.1 (#28520)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-12 15:31:26 +01:00
Aidan Timson de142e33a1 Use entity picker for heading card entities editor (#28463)
* Use entity picker for heading card entities editor

* Use space tokens

* Pass index

* Lint

* Set undefined

* Iterate

* Spread

* Fixes

* Fixes
2025-12-12 09:30:07 +02:00
karwosts 5d4c3ebfcd Home strategy: don't link non-admin to config pages (#28512) 2025-12-12 07:23:37 +01:00
renovate[bot] eb910c5ac5 Update dependency typescript-eslint to v8.49.0 (#28515)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-12 07:23:10 +01:00
renovate[bot] 72726a2e0f Update dependency @codemirror/view to v6.39.0 (#28514)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-12 07:22:53 +01:00
Aidan Timson 253b49871e Allow deletion of disabled helper entities via overflow menu (#28498)
* Allow deletion of disabled entities

* Still check if editable
2025-12-11 16:12:33 +02:00
Aidan Timson 6306890922 Add entities to device page overflow menu (#28497) 2025-12-11 16:07:04 +02:00
renovate[bot] fee16ed4e4 Update dependency jsdom to v27.3.0 (#28504)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 16:01:40 +02:00
karwosts 055f6c82fb Fix labels in entity picker create entity (#28503) 2025-12-11 15:55:15 +02:00
Paul Bottein 0c1627c69a Fix area and floor picker search (#28494) 2025-12-11 14:16:17 +02:00
Aidan Timson 780c03ece8 Add .cursor to gitignore (#28496) 2025-12-11 14:14:27 +02:00
Silas Krause 62dc66abd8 Support legacy table styles in markdown (#28488)
* Remove unnecessary assist styles

* Fix list styles

* Remove table styles for role="presentation"
2025-12-11 14:10:26 +02:00
Wendelin 08aaee754e Fix automation add TCA search icons (#28490)
Fix automation add TCA seach icons
2025-12-11 13:48:41 +02:00
Aidan Timson bba400443e Fix mobile touch edit card click after saving card (#28484) 2025-12-11 10:17:52 +01:00
Wendelin a7a937e197 Fix ha-toast z-index (#28491) 2025-12-11 09:14:12 +00:00
karwosts 2a97913520 Pass hass to ha-yaml-editors (and others) (#28485) 2025-12-11 08:31:42 +01:00
Wendelin 9f16ce7341 Fix picker initial sort and reorganize picker data (#28476) 2025-12-11 08:28:45 +01:00
Aidan Timson 3e20e9b388 Wait for custom dashboards to load in profile settings before rendering select (#28482)
Wait for custom dashboards to load before rendering select
2025-12-10 18:06:42 +01:00
Wendelin 6891eb9ff8 Fix target picker area in history/activity (#28474)
* Add max target picker width for history and activity

* Fix target picker  area selection in history and activity
2025-12-10 17:59:35 +02:00
Wendelin f649b3783d fix service-picker search keys (#28481)
Update SEARCH_KEYS to include search_labels prefix for consistency
2025-12-10 16:59:23 +01:00
Wendelin c46f67d572 Fix automation add tca item search (#28483) 2025-12-10 15:34:52 +00:00
Wendelin 86acfa67dd Add unchecked icon support to ha-dropdown-item component (#28299) 2025-12-10 16:08:45 +01:00
dcapslock 3c5c19270f Allow for badges to be connectedWhileHidden and for hui-badge to respond to badge-visibility-changed event (#28399)
* Allow for badges to be connectedWhileHidden and for hui-badge to respond to badge-visibility-changed event

* Update after environment prettier update
2025-12-10 15:23:53 +01:00
karwosts 6db7817032 Hide energy usage chips when no title is set (#28464) 2025-12-10 10:16:34 +02:00
Aidan Timson 05ca8253f0 Update HaGenericPicker unknown value check to handle null and empty strings (#28462) 2025-12-09 15:53:28 +01:00
Aidan Timson 071161e82d Add area to helpers table (#28460) 2025-12-09 14:05:54 +00:00
Wendelin 9cd38c7128 Multi term search sort by search score (#28353) 2025-12-09 14:48:57 +01:00
Wendelin 6322c19a45 Generic picker warn unknown selected item (#28372)
* Add unknown item text localization to various pickers

* Review
2025-12-09 14:24:30 +02:00
karwosts 74b51b77fe Fix markdown card image sizing (#28449) 2025-12-09 13:15:12 +01:00
Wendelin b80481b53e Generic picker: scroll to selected value on open (#28457) 2025-12-09 12:27:56 +01:00
Aidan Timson 2ce1eaf8c6 Revert "Add basic view transitions between tab UIs (#28374)" (#28451) 2025-12-09 13:18:51 +02:00
Aidan Timson 4030ce3f88 Migrate dialog-upload-backup to ha-wa-dialog (#28444)
* Migrate dialog-upload-backup.ts from ha-md-dialog to ha-wa-dialog

* Remove custom css, space tokens

* Restore
2025-12-09 09:32:28 +02:00
Aidan Timson 41cabde393 Migrate dialog-download-decrypted-backup to ha-wa-dialog (#28442)
* Migrate dialog-download-decrypted-backup.ts from ha-md-dialog to ha-wa-dialog

* Fixes from other migrations
2025-12-09 09:28:44 +02:00
Aidan TimsonandPetar Petrov 47d1fdf673 Migrate change/show backup encryption key to ha-wa-dialog (#28428)
* Migrate dialog-change-backup-encryption-key.ts from ha-md-dialog to ha-wa-dialog

* Remove open render nothing, remove custom css size

* Migrate show backup key

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-12-09 07:24:43 +00:00
Aidan Timson e59e83fffe Migrate dialog-areas-floors-order to ha-wa-dialog (#28424)
* Migrate dialog-areas-floors-order.ts from ha-md-dialog to ha-wa-dialog

* Fix saving

* Remove render nothing if dialog false

* Remove custom width
2025-12-09 09:12:29 +02:00
Aidan Timson b896b78876 Migrate labs dialogs to ha-wa-dialog (#28429)
* Migrate dialog-labs-preview-feature-enable.ts from ha-md-dialog to ha-wa-dialog

* Migrate dialog-labs-progress.ts from ha-md-dialog to ha-wa-dialog

* Restore

* Remove use of slots

* Fix

* Remove header
2025-12-09 08:55:28 +02:00
6e180c9fb4 Migrate ha-button-menu to ha-dropdown in 3 files (#28337)
* Initial plan

* Migrate ha-button-menu to ha-dropdown in 3 files

- Migrate ha-config-logs.ts: Replace ha-button-menu with ha-dropdown for log provider selection
- Migrate ha-qr-scanner.ts: Replace ha-button-menu with ha-dropdown for camera selection
- Migrate ha-data-table-labels.ts: Replace ha-button-menu with ha-dropdown for overflow labels

Following the migration pattern from PR #28293

Co-authored-by: wendevlin <[email protected]>

* Fix ha-data-table-labels migration to use proper @wa-select pattern

- Add HaDropdownItem type import
- Use @wa-show instead of @click for menu opening
- Use @wa-select for item selection with proper event handler
- Update comment to reference ha-dropdown instead of ha-button-menu

Co-authored-by: wendevlin <[email protected]>

* Fixes

* Remove unused code

* Remove unused styles

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: wendevlin <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2025-12-08 21:30:35 +01:00
Paul Bottein 0ce0247a2c 20251203.2 (#28443) 2025-12-08 17:30:04 +01:00
Paul Bottein ce8cabbad9 Bumped version to 20251203.2 2025-12-08 17:29:01 +01:00
karwosts 0802841606 More unsafe description_placeholders fixes (#28416) 2025-12-08 17:28:52 +01:00
Nils Schönwald cb93e1b741 Update snowflake to 6 sides (#28406) 2025-12-08 17:28:51 +01:00
dcapslockandPetar Petrov 30c383a2fc Energy strategies to refresh energy collection which allows to be used in custom dashboards (#28400)
* Energy strategies to refresh energy collection which allows to be used in custom dashboards

* Update src/panels/energy/strategies/energy-overview-view-strategy.ts

Co-authored-by: Petar Petrov <[email protected]>

* Only refresh if no prefs

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-12-08 17:28:50 +01:00
karwosts 73ee235fef Fix for undefined description_placeholders (#28395)
Another fix for undefined description_placeholders
2025-12-08 17:28:49 +01:00
Aidan TimsonandPetar Petrov b50daecdec Create an adaptive dialog and bottom sheet component, migrate restart (#28344)
* Create a switchable dialog and bottom sheet component

* Migrate dialog restart

* Fix close action

* Docstring

* Rename type

* Rename func

* Document

* Remove flex, use flex

* Cleanup docstring

* Update bodyScrolled

* Cleanup

* Remove

* Rename to ha-adaptive-dialog

* Cleanup

* Format

* Fix forwarding of slots

* Fix style

* listenMediaQuery, simplify and remove double scroll handling

* Add slotted footer to bottom sheet for compat

* Add block-mode-change to stop mode switches for forms etc.

* Document block-mode-change

* Update gallery

* Fix gallery doc for wa-dialog (caught by agent review)

* Update src/components/ha-adaptive-dialog.ts

Co-authored-by: Petar Petrov <[email protected]>

* Cleanup

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-12-08 17:32:31 +02:00
Aidan Timson f5bd0816a8 Fix more info entity settings bottom fade (#28437)
* Use space tokens

* Fix settings bottom fade issue

* Space token

* Restore
2025-12-08 16:05:49 +02:00
Aidan Timson b6d1e65044 Migrate dialog-edit-sidebar to ha-wa-dialog, fix dialog padding (#28426)
* Migrate dialog-edit-sidebar.ts from ha-md-dialog to ha-wa-dialog

* Format

* Fix wa dialog padding impl

* Remove custom size

* Use space tokens

* Remove render nothing

* Fix default top padding
2025-12-08 14:47:10 +02:00
Aidan Timson e2312e52e3 Remove z-index from scrollable fades (#28434) 2025-12-08 14:33:30 +02:00
renovate[bot] 46a6da33d9 Update dependency terser-webpack-plugin to v5.3.15 (#28436)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-08 14:32:39 +02:00
Aidan Timson e7b0b9a090 Add basic view transitions between tab UIs (#28374)
* Add basic view transitions between tab UIs

* Remove debug

* Add to debug navigation action
2025-12-08 14:22:05 +02:00
Petar Petrov 63ffc3b7f9 Restrict row resizing for stack and entities cards (#28422)
* Restrict row resizing for stack and entities cards

* Fix disabled state for grid layout slider
2025-12-08 12:53:37 +02:00
Nils Schönwald ebfceae38c Update snowflake to 6 sides (#28406) 2025-12-08 09:16:55 +00:00
Aidan Timson cccfc1716b Add scrollable fade mixin to bottom sheet, picker combo box (#28347)
* Add scrollable fade mixin to ha-bottom-sheet

* Wrap picker combobox (used inside of sheet with virtualizer)
2025-12-08 08:58:19 +02:00
dcapslockandPetar Petrov 6abf0dfcb9 Energy strategies to refresh energy collection which allows to be used in custom dashboards (#28400)
* Energy strategies to refresh energy collection which allows to be used in custom dashboards

* Update src/panels/energy/strategies/energy-overview-view-strategy.ts

Co-authored-by: Petar Petrov <[email protected]>

* Only refresh if no prefs

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-12-08 08:17:19 +02:00
dependabot[bot] 9d2404763f Bump home-assistant/wheels from 2025.11.0 to 2025.12.0 (#28421)
Bumps [home-assistant/wheels](https://github.com/home-assistant/wheels) from 2025.11.0 to 2025.12.0.
- [Release notes](https://github.com/home-assistant/wheels/releases)
- [Commits](https://github.com/home-assistant/wheels/compare/2025.11.0...2025.12.0)

---
updated-dependencies:
- dependency-name: home-assistant/wheels
  dependency-version: 2025.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 06:11:02 +00:00
dependabot[bot] 6c84c9b44e Bump github/codeql-action from 4.31.5 to 4.31.7 (#28417)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.31.5 to 4.31.7.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/fdbfb4d2750291e159f0156def62b853c2798ca2...cf1bb45a277cb3c205638b2cd5c984db1c46a412)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.31.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 06:10:48 +00:00
dependabot[bot] edb2172bdd Bump actions/checkout from 6.0.0 to 6.0.1 (#28419)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.0 to 6.0.1.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/1af3b93b6815bc44a9784bd300feb67ff0d1eeb3...8e8c483db84b4bee98b60c0593521ed34d9990e8)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 06:10:44 +00:00
dependabot[bot] 067e7645ac Bump actions/stale from 10.1.0 to 10.1.1 (#28420)
Bumps [actions/stale](https://github.com/actions/stale) from 10.1.0 to 10.1.1.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/5f858e3efba33a5ca4407a664cc011ad407f2008...997185467fa4f803885201cee163a9f38240193d)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: 10.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 06:10:35 +00:00
dependabot[bot] c3e4af3db8 Bump actions/setup-node from 6.0.0 to 6.1.0 (#28418)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6.0.0 to 6.1.0.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/2028fbc5c25fe9cf00d9f06a71cc4710d4507903...395ad3262231945c25e8478fd5baf05154b1d79f)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 06:10:25 +00:00
karwosts f44be2d3b9 More unsafe description_placeholders fixes (#28416) 2025-12-08 08:05:35 +02:00
karwosts cff7ed9b05 Fix for undefined description_placeholders (#28395)
Another fix for undefined description_placeholders
2025-12-07 09:21:08 +02:00
Norbert Rittel c4e5f1dba6 Fix wording for use with both energy and power sensors (#28392) 2025-12-06 13:41:56 +00:00
Bram Kragten d1011d691f Handle search params changed after first updated for dashboards and … (#28375)
handle search params changed after first updated for dashboards and integrations
2025-12-06 13:45:44 +02:00
renovate[bot] 7dda8c36bc Update dependency prettier to v3.7.4 (#28388)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-06 09:32:57 +01:00
Paul Bottein 31603ea7b2 20251203.1 (#28383) 2025-12-05 20:53:17 +01:00
Paul Bottein 17c1043cfc Bumped version to 20251203.1 2025-12-05 20:51:48 +01:00
Timothy da255dce40 Add add to button in more info topbar for non admin users (#28365) 2025-12-05 20:51:20 +01:00
Paul Bottein 0c68072f8f Use non-admin endpoint to subscribe to one lab feature (#28352) 2025-12-05 20:51:19 +01:00
Petar Petrov d197fd8f76 Fix calendar card not showing different colors for multiple calendars (#28338) 2025-12-05 20:51:18 +01:00
Paul Bottein a961a87872 Move reorder areas and floors to floor overflow (#28335) 2025-12-05 20:51:17 +01:00
Petar Petrov cc96c707b9 Fix markdown sections and styling (#28333) 2025-12-05 20:51:16 +01:00
Petar Petrov 4b73713f2a Fix gauge severity using entity state instead of attribute value (#28331) 2025-12-05 20:51:15 +01:00
Petar Petrov c001102f15 Append current state to power-sources-graph (#28330) 2025-12-05 20:51:14 +01:00
Preet Patel c1e5e0bfcb Fix energy dashboard redirect for device-consumption-only configs (#28322)
When users configure energy with only device consumption (no
grid/solar/battery/gas/water sources), the dashboard would redirect
to /config/energy instead of displaying. This occurred because
_generateLovelaceConfig() returned an empty views array.

The fix adds hasDeviceConsumption check and includes ENERGY_VIEW
when device consumption is configured, since energy-view-strategy
already supports device consumption cards.
2025-12-05 20:51:13 +01:00
Bram Kragten a1412e90fd Add more info to the energy demo (#28316)
* Add more info to the energy demo

* Also add battery power
2025-12-05 20:51:12 +01:00
Petar Petrov f6f40c1679 Always show energy-sources-table in overview (#28315) 2025-12-05 20:48:59 +01:00
renovate[bot] 45b2376616 Update vitest monorepo to v4.0.15 (#28379)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-05 17:51:51 +01:00
Paul Bottein 2f70a82d02 Use non-admin endpoint to subscribe to one lab feature (#28352) 2025-12-05 17:34:22 +01:00
Aidan TimsonandWendelin 00868b2450 Add scrollable fade to more info dialog (#28314)
* Add scrollable fade to more info dialog

* Introduce scroll threshold (default 4px, more info 24px)

* Docstrings

* Remove getter for numeric values in mixin

* Update src/dialogs/more-info/ha-more-info-dialog.ts

Co-authored-by: Wendelin <[email protected]>

* Fix lint

---------

Co-authored-by: Wendelin <[email protected]>
2025-12-05 15:43:47 +01:00
Timothy e573a726aa Add add to button in more info topbar for non admin users (#28365) 2025-12-05 15:05:50 +01:00
Petar Petrov ef82bc2abb Fix calendar card not showing different colors for multiple calendars (#28338) 2025-12-05 13:39:51 +01:00
renovate[bot] 92e3864f63 Update dependency typescript-eslint to v8.48.1 (#28371)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-05 13:17:53 +01:00
renovate[bot] a4af975bb3 Update dependency @rspack/core to v1.6.6 (#28370)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-05 13:17:47 +01:00
Aidan Timson 025ffd7b56 Revert "Fix underflowing text in ha-settings-row (#28339)" (#28369) 2025-12-05 11:50:37 +00:00
Jan-Philipp Benecke 3ea4a28931 Fix underflowing text in ha-settings-row (#28339) 2025-12-05 09:08:42 +00:00
Benjamin 3b092b834e Filter out hidden entities in map configuration (#28320) 2025-12-05 08:44:07 +01:00
Aidan Timson ed8ccbe12c Add scrollable fade mixin to ha-wa-dialog (#28346) 2025-12-05 08:43:43 +01:00
karwosts 420f88f73a Fix incorrect water & gas price hints (#28357)
* Fix incorrect water price hint

* Gas
2025-12-05 08:44:23 +02:00
karwosts 086aa5fa28 Delete stop response variable on empty (#28362) 2025-12-05 08:38:39 +02:00
renovate[bot] cca4cc512b Update dependency @rsdoctor/rspack-plugin to v1.3.12 (#28350)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-04 14:54:27 +00:00
Petar Petrov 8eb65f327a Append current state to power-sources-graph (#28330) 2025-12-04 10:18:48 +01:00
Petar Petrov f3495feacb Fix markdown sections and styling (#28333) 2025-12-04 10:15:11 +01:00
Petar Petrov 2161bcfa3f Fix gauge severity using entity state instead of attribute value (#28331) 2025-12-04 10:13:41 +01:00
Paul Bottein 1400398422 Move reorder areas and floors to floor overflow (#28335) 2025-12-04 10:58:27 +02:00
Preet Patel 506d466c03 Fix energy dashboard redirect for device-consumption-only configs (#28322)
When users configure energy with only device consumption (no
grid/solar/battery/gas/water sources), the dashboard would redirect
to /config/energy instead of displaying. This occurred because
_generateLovelaceConfig() returned an empty views array.

The fix adds hasDeviceConsumption check and includes ENERGY_VIEW
when device consumption is configured, since energy-view-strategy
already supports device consumption cards.
2025-12-04 06:38:43 +00:00
Bram Kragten 46735c72ed Add more info to the energy demo (#28316)
* Add more info to the energy demo

* Also add battery power
2025-12-03 20:46:59 +01:00
c43d41053b Migrate ha-button-menu to ha-dropdown in 4 files (#28300)
Co-authored-by: wendevlin <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Wendelin <[email protected]>
Co-authored-by: uptimeZERO_ <[email protected]>
2025-12-03 16:43:07 +00:00
Petar Petrov 844d53a0ba Always show energy-sources-table in overview (#28315) 2025-12-03 17:18:07 +01:00
Bram Kragten d77bebe96b Bumped version to 20251203.0 2025-12-03 15:38:49 +01:00
Bram Kragten 1260af0b45 Fix add matter device my link (#28313) 2025-12-03 15:36:05 +01:00
Petar Petrov 1d37eec411 Fix label filter losing selections when searching (#28312) 2025-12-03 15:36:04 +01:00
Bram Kragten 5a52f83358 Fix sticky headers in TCA dialog when target is selected (#28310) 2025-12-03 15:36:03 +01:00
Aidan Timson 60724eb952 Add subscribeLabFeature function (#28309)
* Add subscribe to lab feature function

* Add docstrings to exported functions
2025-12-03 15:36:02 +01:00
Aidan Timson de5778079e Add small rotation to snowflakes (#28308) 2025-12-03 15:36:01 +01:00
Wendelin f3710650f2 Hide disabled devices in automation target tree (#28307) 2025-12-03 15:36:00 +01:00
Paul Bottein feb35dbc4f Use svg for snowflakes (#28306) 2025-12-03 15:35:59 +01:00
Paul Bottein ee9e101fa6 Rename unassigned areas to other areas (#28305) 2025-12-03 15:35:58 +01:00
Paul Bottein 24b16360a6 Use core area sorting everywhere (#28304) 2025-12-03 15:35:57 +01:00
Wendelin 109c81a00d Revert "Migrate updates dropdown to ha-dropdown" (#28303)
Revert "Migrate updates dropdown to ha-dropdown (#28039)"

This reverts commit ba9bab38c9.
2025-12-03 15:35:56 +01:00
Wendelin eaa1ddbf61 Fix filtering of floors in getAreasAndFloorsItems function (#28302) 2025-12-03 15:35:55 +01:00
Paul Bottein b11cb57a1e Always set ha-wa-dialog position to fixed (#28301) 2025-12-03 15:35:55 +01:00
Petar Petrov 87b5f58779 Add Y-axis label formatter to energy charts (#28298) 2025-12-03 15:35:53 +01:00
Petar Petrov 8dac53c672 Fix binary sensor history timeline not rendering properly (#28297) 2025-12-03 15:35:52 +01:00
Petar Petrov d0966bf35a Hide empty System message in assist debug view (#28296) 2025-12-03 15:35:51 +01:00
Paul Bottein 6ba4fc0808 Handle not existing panels in dashboard config (#28292) 2025-12-03 15:35:50 +01:00
ildar170975andPetar Petrov bd582ff816 computeLovelaceEntityName(): allow "number" names to be processed (#28231)
* allow "number" names to be processed

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-12-03 15:35:49 +01:00
Bram Kragten 1c8b78eae9 Bumped version to 20251203.0 2025-12-03 15:31:03 +01:00
Bram Kragten a918e878fa Fix add matter device my link (#28313) 2025-12-03 15:30:26 +01:00
Petar Petrov ebc354bf55 Fix label filter losing selections when searching (#28312) 2025-12-03 15:29:48 +01:00
WendelinanduptimeZERO_ 98a1f5ca3a Use ha-dropdown for automations/scripts (#28293)
Co-authored-by: uptimeZERO_ <[email protected]>
2025-12-03 13:33:48 +00:00
Bram Kragten 48015ab312 Fix sticky headers in TCA dialog when target is selected (#28310) 2025-12-03 14:24:29 +01:00
Aidan Timson 09515b1937 Add subscribeLabFeature function (#28309)
* Add subscribe to lab feature function

* Add docstrings to exported functions
2025-12-03 14:16:09 +01:00
Aidan Timson 5a40627676 Add small rotation to snowflakes (#28308) 2025-12-03 14:12:08 +01:00
Wendelin cd34447603 Hide disabled devices in automation target tree (#28307) 2025-12-03 14:02:25 +01:00
Paul Bottein 803fabbf64 Use svg for snowflakes (#28306) 2025-12-03 11:46:07 +00:00
Paul Bottein 78c4dc48d0 Rename unassigned areas to other areas (#28305) 2025-12-03 12:42:14 +01:00
Paul Bottein 147600ea43 Use core area sorting everywhere (#28304) 2025-12-03 12:28:55 +01:00
Wendelin 2f91f0dd15 Revert "Migrate updates dropdown to ha-dropdown" (#28303)
Revert "Migrate updates dropdown to ha-dropdown (#28039)"

This reverts commit ba9bab38c9.
2025-12-03 12:27:39 +01:00
ildar170975andPetar Petrov 3fa330acfb computeLovelaceEntityName(): allow "number" names to be processed (#28231)
* allow "number" names to be processed

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-12-03 10:40:29 +00:00
Paul Bottein e0a6b671ce Always set ha-wa-dialog position to fixed (#28301) 2025-12-03 10:11:54 +00:00
Wendelin d6edd150a8 Fix filtering of floors in getAreasAndFloorsItems function (#28302) 2025-12-03 10:45:18 +01:00
Petar Petrov 2c00889921 Add Y-axis label formatter to energy charts (#28298) 2025-12-03 10:33:00 +01:00
Petar Petrov 0447d87f18 Hide empty System message in assist debug view (#28296) 2025-12-03 10:29:07 +01:00
Petar Petrov d7e18b0520 Fix binary sensor history timeline not rendering properly (#28297) 2025-12-03 10:18:32 +01:00
Luca Félix e7254b1587 feat: round_temperature on weather forecast card (#28103)
* feat: round_temperature on weather forecast card

* fix: use round util function

* refactor: applied comments from review
2025-12-03 10:02:25 +02:00
renovate[bot] 8681a7d450 Update dependency prettier to v3.7.3 (#28295)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-03 07:19:24 +01:00
Paul Bottein fff12acb6b Handle not existing panels in dashboard config (#28292) 2025-12-02 17:23:09 +01:00
Bram Kragten d34bf83da0 Bumped version to 20251202.0 2025-12-02 16:02:32 +01:00
Wendelin b0cfb31bf3 Automation add TCA: fix narrow subtitles & icons (#28291) 2025-12-02 16:02:25 +01:00
Wendelin 6c39e5d2c5 Use history to manage back button click in automations add TCA (#28289) 2025-12-02 16:02:24 +01:00
Paul Bottein 7b51e71092 Only show current weather in home overview (#28288) 2025-12-02 16:02:23 +01:00
Paul Bottein 8a82483685 Fix container alignment in section view (#28287) 2025-12-02 16:02:23 +01:00
Bram Kragten bb691fa7a2 fix paste in add tca dialog (#28286) 2025-12-02 16:02:22 +01:00
Petar Petrov 2232db9c0f Update Energy dashboard layout (#28283) 2025-12-02 16:02:21 +01:00
Petar Petrov 5375665dc6 Fix index value for grid return in power sankey card (#28281) 2025-12-02 16:02:20 +01:00
Silas Krause 480122f40a Revert custom markdown styles (#28277) 2025-12-02 16:02:18 +01:00
karwosts ee5c54030a Safer lookup of description_placeholders when service is invalid (#28273) 2025-12-02 16:02:17 +01:00
Paul Bottein b73f50e864 Add dialog to reorder areas and floors (#28272) 2025-12-02 16:02:16 +01:00
eringerli b9836073b7 fix stacking of multiple power sources (#28243) 2025-12-02 16:02:15 +01:00
Petar Petrov 3d327ed628 Update Energy dashboard layout (#28283) 2025-12-02 16:01:17 +01:00
Wendelin 0d51648de1 Use history to manage back button click in automations add TCA (#28289) 2025-12-02 15:43:13 +01:00
Wendelin c5642c15b8 Automation add TCA: fix narrow subtitles & icons (#28291) 2025-12-02 14:17:55 +00:00
Paul Bottein 7f885010de Add dialog to reorder areas and floors (#28272) 2025-12-02 15:12:36 +01:00
Paul Bottein 356d51f974 Only show current weather in home overview (#28288) 2025-12-02 15:38:34 +02:00
Dave TandPetar Petrov 38a907e51e Separate action field YAML examples (#27218)
* Comma separate field examples if it is a list

* Remove prettier ignore and json.stringify all examples

* Use YAML format

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-12-02 13:34:25 +00:00
Bram Kragten 87c0b1d887 fix paste in add tca dialog (#28286) 2025-12-02 14:30:16 +01:00
Paul Bottein 0f195015b7 Fix container alignment in section view (#28287) 2025-12-02 15:29:11 +02:00
Petar Petrov 17a976af67 Fix index value for grid return in power sankey card (#28281) 2025-12-02 14:47:15 +02:00
Aidan Timson a41a7e822a Remove placeholder for non device area picker in entity settings (#28285)
Remove placeholder for non device area picker
2025-12-02 11:52:02 +00:00
dependabot[bot] 5473bf56c6 Bump express from 4.21.2 to 4.22.1 (#28280)
Bumps [express](https://github.com/expressjs/express) from 4.21.2 to 4.22.1.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/v4.22.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.21.2...v4.22.1)

---
updated-dependencies:
- dependency-name: express
  dependency-version: 4.22.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-02 08:17:59 +02:00
karwosts 029eba7ab8 Safer lookup of description_placeholders when service is invalid (#28273) 2025-12-02 08:08:36 +02:00
Silas Krause 824a3f288d Revert custom markdown styles (#28277) 2025-12-02 08:07:45 +02:00
renovate[bot] fdd89c05d3 Update dependency prettier to v3.7.2 (#28276)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-02 08:06:30 +02:00
Bram Kragten a40512e0b5 Bumped version to 20251201.0 2025-12-01 16:35:54 +01:00
Paul Bottein b2122570fb Clean reference to floor compare (#28269)
Fix floor compare
2025-12-01 16:35:34 +01:00
Paul BotteinandPetar Petrov 885f9333d2 Add helper for floor level (#28268)
* Add helper for floor level

* Update src/translations/en.json

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-12-01 16:35:33 +01:00
Aidan Timson f812e7e9fb Match more-info-update backup preferences (#28266) 2025-12-01 16:35:32 +01:00
Wendelin 64dad39f6e Fix automation trigger ha icon (#28265) 2025-12-01 16:35:31 +01:00
Simon Lamon df0fb423ed Include background in light, climate and security views (#28264)
* Include background

* Remove background key

* Add imports
2025-12-01 16:35:30 +01:00
Wendelin 4c3156f290 Respect system area sort in automation target tree (#28263) 2025-12-01 16:35:29 +01:00
Petar Petrov ecdf374902 Reduce the duration of init animation for charts to 500ms (#28262)
Reduce the duration of init animation for charts
2025-12-01 16:35:29 +01:00
Aidan Timson 3e924e0cde Add missing key for labs to show in quick bar (#28261) 2025-12-01 16:35:27 +01:00
Bram Kragten 6fb71e12c8 Use name instead of description_configured for triggers and conditions (#28260) 2025-12-01 16:35:27 +01:00
Wendelin 6138aa5489 Fix ha-bottom-sheet closed event (#28257) 2025-12-01 16:35:26 +01:00
Aidan Timson 61e865d3a6 Fix 1px padding for subpage titles (#28256) 2025-12-01 16:35:24 +01:00
Aidan Timson febcbf6242 Make labs toolbar icon use default color (#28255) 2025-12-01 16:35:23 +01:00
Petar Petrov 6a2fac6a9e Fix refresh in energy panel subviews (#28252) 2025-12-01 16:35:22 +01:00
karwosts b60c5467fc Add water devices to energy data download (#28242) 2025-12-01 16:35:21 +01:00
Petar Petrov ecd563406e Add power view and restructure energy dashboard layout (#28240) 2025-12-01 16:35:19 +01:00
Silas Krause d5b66315e2 Fix markdown rendering for cached html (#28229)
* Render markdown table in wrapper.

* Fix markdown styles

* Fix formatting

* fix rendering for cache
2025-12-01 16:35:18 +01:00
karwosts 5b1719fc6e Add missing helper to language selector (#28218) 2025-12-01 16:35:17 +01:00
Silas Krause add22cf2e9 Fix markdown styles regression (#28202)
* Render markdown table in wrapper.

* Fix markdown styles

* Fix formatting
2025-12-01 16:35:16 +01:00
Paul Bottein 21509191fa Fix ha icon size (#28201) 2025-12-01 16:35:15 +01:00
Paul Bottein 1a73cccf0d Fix safe area for sidebar section views in Android (#28194) 2025-12-01 16:35:14 +01:00
Aidan Timson 407d68250a Fix ha-wa-dialog fullscreen and make alerts not fullscreen (#28175) 2025-12-01 16:35:13 +01:00
Paul Bottein c33cb7fff9 Clean reference to floor compare (#28269)
Fix floor compare
2025-12-01 16:47:09 +02:00
Paul BotteinandPetar Petrov de53ad8dce Add helper for floor level (#28268)
* Add helper for floor level

* Update src/translations/en.json

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-12-01 15:43:57 +01:00
Simon Lamon 2dec7490b6 Include background in light, climate and security views (#28264)
* Include background

* Remove background key

* Add imports
2025-12-01 16:20:50 +02:00
Aidan Timson 6ed4bd5ce8 Match more-info-update backup preferences (#28266) 2025-12-01 15:51:31 +02:00
Petar Petrov 4e899c56ed Reduce the duration of init animation for charts to 500ms (#28262)
Reduce the duration of init animation for charts
2025-12-01 15:43:20 +02:00
Petar Petrov 53c20a0493 Add power view and restructure energy dashboard layout (#28240) 2025-12-01 14:16:11 +01:00
Wendelin be2d6e9212 Fix automation trigger ha icon (#28265) 2025-12-01 13:05:36 +00:00
Wendelin 915442c571 Respect system area sort in automation target tree (#28263) 2025-12-01 14:01:06 +01:00
Aidan Timson de6ebc2d0a Add missing key for labs to show in quick bar (#28261) 2025-12-01 12:26:41 +00:00
Bram Kragten bcb12fa062 Use name instead of description_configured for triggers and conditions (#28260) 2025-12-01 13:19:19 +01:00
Aidan Timson 078915743d Make labs toolbar icon use default color (#28255) 2025-12-01 12:08:25 +01:00
Petar Petrov 54c524127f Fix refresh in energy panel subviews (#28252) 2025-12-01 12:07:45 +01:00
Wendelin 334e1c35e1 Fix ha-bottom-sheet closed event (#28257) 2025-12-01 12:04:15 +01:00
Aidan Timson 528c7727e2 Fix 1px padding for subpage titles (#28256) 2025-12-01 12:03:38 +01:00
Aidan Timson d1043e33df Fix subpage layout icon alignment (#28254) 2025-12-01 09:54:25 +00:00
dependabot[bot] b088f2c0e5 Bump home-assistant/wheels from 2025.10.0 to 2025.11.0 (#28251)
Bumps [home-assistant/wheels](https://github.com/home-assistant/wheels) from 2025.10.0 to 2025.11.0.
- [Release notes](https://github.com/home-assistant/wheels/releases)
- [Commits](https://github.com/home-assistant/wheels/compare/2025.10.0...2025.11.0)

---
updated-dependencies:
- dependency-name: home-assistant/wheels
  dependency-version: 2025.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 08:53:24 +02:00
dependabot[bot] b33f407493 Bump relative-ci/agent-action from 3.2.0 to 3.2.1 (#28250)
Bumps [relative-ci/agent-action](https://github.com/relative-ci/agent-action) from 3.2.0 to 3.2.1.
- [Release notes](https://github.com/relative-ci/agent-action/releases)
- [Commits](https://github.com/relative-ci/agent-action/compare/feb19ddc698445db27401f1490f6ac182da0816f...c45aaa919ef85620af54242a241ac17a8fa35983)

---
updated-dependencies:
- dependency-name: relative-ci/agent-action
  dependency-version: 3.2.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 08:48:44 +02:00
dependabot[bot] 502d76b316 Bump actions/setup-python from 6.0.0 to 6.1.0 (#28249)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6.0.0 to 6.1.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/e797f83bcb11b83ae66e0230d6156d7c80228e7c...83679a892e2d95755f2dac6acb0bfd1e9ac5d548)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 08:48:24 +02:00
dependabot[bot] 1ddc07c215 Bump softprops/action-gh-release from 2.4.2 to 2.5.0 (#28248)
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.4.2 to 2.5.0.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/5be0e66d93ac7ed76da52eca8bb058f665c3a5fe...a06a81a03ee405af7f2048a818ed3f03bbf83c7b)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 2.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 08:47:32 +02:00
dependabot[bot] a611a5fc4e Bump github/codeql-action from 4.31.4 to 4.31.5 (#28247)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.31.4 to 4.31.5.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/e12f0178983d466f2f6028f5cc7a6d786fd97f4b...fdbfb4d2750291e159f0156def62b853c2798ca2)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.31.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 08:46:51 +02:00
eringerli c13bece6d0 fix stacking of multiple power sources (#28243) 2025-12-01 06:25:47 +00:00
Paulus Schoutsen 28a89ff9e6 Add custom element decorators instead of customElements.define (#28235)
* Add custom element decorators instead of customElements.define

* Ignore

* prettier
2025-12-01 06:38:31 +01:00
karwosts 81b5ddec9d Add water devices to energy data download (#28242) 2025-11-30 16:00:14 +01:00
renovate[bot]andPetar Petrov ce86aabe32 Update dependency prettier to v3.7.1 (#28239)
* Update dependency prettier to v3.7.1

* format

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <[email protected]>
2025-11-30 13:33:41 +00:00
Silas Krause a8910bcbe4 Fix markdown rendering for cached html (#28229)
* Render markdown table in wrapper.

* Fix markdown styles

* Fix formatting

* fix rendering for cache
2025-11-30 15:21:39 +02:00
ildar170975 0e4cf9f62d ha-picker-field: change left padding to align with other controls (#28217)
change --md-list-item-leading-space & --md-list-item-trailing-space
2025-11-29 14:00:27 +02:00
renovate[bot] 506635d649 Update vaadinWebComponents monorepo to v24.9.6 (#28225)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-29 11:44:28 +00:00
karwosts 27e24ee49b Add missing helper to language selector (#28218) 2025-11-29 12:35:04 +01:00
renovate[bot] bcd712b48c Update vitest monorepo to v4.0.14 (#28215)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-28 20:23:38 +01:00
renovate[bot] 461ef9b916 Update dependency @rspack/core to v1.6.5 (#28207)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-28 11:14:57 +01:00
renovate[bot] b794989daa Update dependency @bundle-stats/plugin-webpack-filter to v4.21.7 (#28205)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-28 08:29:33 +02:00
Silas Krause 6727ffaae0 Fix markdown styles regression (#28202)
* Render markdown table in wrapper.

* Fix markdown styles

* Fix formatting
2025-11-28 08:28:57 +02:00
Paul Bottein 4df8501b20 Fix ha icon size (#28201) 2025-11-27 22:54:44 +01:00
Aidan Timson 539d0e443f Fix ha-wa-dialog fullscreen and make alerts not fullscreen (#28175) 2025-11-27 22:01:30 +01:00
renovate[bot] 9c9d274b5c Update dependency typescript-eslint to v8.48.0 (#28196)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-27 19:20:07 +01:00
Paul Bottein d6e6bc0e80 Fix safe area for sidebar section views in Android (#28194) 2025-11-27 19:46:56 +02:00
ildar170975andPetar Petrov 530a70b168 Automations, scripts, scenes: add a tooltip for relative time (#28158)
* add a tooltip for last_triggered

* add a tooltip for last_triggered

* add a tooltip for last_activated

* Apply suggestions from code review

* Apply suggestion from @MindFreeze

Co-authored-by: Petar Petrov <[email protected]>

* Apply suggestion from @MindFreeze

Co-authored-by: Petar Petrov <[email protected]>

* Apply suggestion from @MindFreeze

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-11-27 19:44:11 +02:00
Bram Kragten 38b7bd18bb Bumped version to 20251127.0 2025-11-27 17:06:57 +01:00
Wendelin a00e944a35 Add TCA by target sort like item collections (#28192) 2025-11-27 17:06:30 +01:00
Petar Petrov 481569804e Fix water sankey calculation to include total supply from sources (#28191) 2025-11-27 17:06:29 +01:00
Paul Bottein a1d7e270ff Add hint to reorder areas and floors (#28189) 2025-11-27 17:06:28 +01:00
WendelinandPetar Petrov 225ccf1d2f Fix lab automations icons and sidebar width (#28184)
Co-authored-by: Petar Petrov <[email protected]>
2025-11-27 17:06:27 +01:00
Wendelin 4a5e1f9f3f "Add TCA" dialog desktop height to 800px (#28182) 2025-11-27 17:06:26 +01:00
Wendelin b27b7210fd Show hidden entities in target tree (#28181)
* Show hidden entities in target tree

* Fix types
2025-11-27 17:06:25 +01:00
Petar Petrov acd5181449 Fix sankey chart resizing (#28180) 2025-11-27 17:06:24 +01:00
Bram Kragten b6b2d03a80 Always store token when using develop and serve (#28179) 2025-11-27 17:06:22 +01:00
Paul Bottein 7aee2b7cb7 Fix labs back button (#28174) 2025-11-27 17:06:21 +01:00
Paul Bottein df1914cb7a Fix disabled dashboard picker when no custom dashboard (#28172) 2025-11-27 17:06:20 +01:00
Paul Bottein 6706d5904d Fix box shadow for sidebar tabs (#28170) 2025-11-27 17:06:19 +01:00
Wendelin 221aefd764 Fix automation add TCA autofocus (#28168)
Fix automation add tca autofocus
2025-11-27 17:06:18 +01:00
Paul Bottein 670057e8e6 Restore sidebar view when clicking back (#28167) 2025-11-27 17:06:17 +01:00
Wendelin 427e46201c Fix add condition default tab and blank styles (#28166) 2025-11-27 17:06:16 +01:00
Petar Petrov fd1240f335 Refactor power sankey hierarchy to handle devices with not power sensor (#28164) 2025-11-27 17:06:15 +01:00
Petar Petrov aa7670cb59 Disable axis pointer on the energy devices bar chart to fix refresh issues on touch devices (#28163) 2025-11-27 17:06:14 +01:00
Petar Petrov 468139229c Handle grouping by floor and area in power sankey card (#28162) 2025-11-27 17:06:13 +01:00
Simon Lamon 39752f0e3f Don't show more info for untracked consumption (#28151) 2025-11-27 17:06:12 +01:00
Petar Petrov 4d850d067f Replace gauges with energy usage graph in energy overview (#28150) 2025-11-27 17:06:10 +01:00
Paul Bottein bcae64df88 Use hui-root for panel energy (#28149)
* Use hui-root for panel energy

* Review feedback

* Set empty prefs
2025-11-27 17:06:09 +01:00
Iván Pereira 690fd5a061 Fix hide sidebar tooltip on touchend events (#28042)
* fix: hide sidebar tooltip on touchend events

* Add a comment recommended by Copilot

* Clear timeouts id in disconnectedCallback
2025-11-27 17:06:08 +01:00
Wendelin 23137500f8 Add TCA by target sort like item collections (#28192) 2025-11-27 17:03:27 +01:00
WendelinandPetar Petrov 63e7ed21a4 Fix lab automations icons and sidebar width (#28184)
Co-authored-by: Petar Petrov <[email protected]>
2025-11-27 16:57:42 +01:00
Petar Petrov 92611f46f4 Fix water sankey calculation to include total supply from sources (#28191) 2025-11-27 16:44:56 +01:00
Bram Kragten 9bc896241d Always store token when using develop and serve (#28179) 2025-11-27 16:43:36 +01:00
Paul Bottein 2baafe620c Add hint to reorder areas and floors (#28189) 2025-11-27 16:32:23 +01:00
Wendelin ce52bbaf8c Show hidden entities in target tree (#28181)
* Show hidden entities in target tree

* Fix types
2025-11-27 15:44:50 +02:00
Wendelin 0b4b8d9082 "Add TCA" dialog desktop height to 800px (#28182) 2025-11-27 14:42:18 +01:00
Petar Petrov bddbb773b7 Fix sankey chart resizing (#28180) 2025-11-27 15:41:46 +02:00
Paul Bottein d52e1e8835 Use hui-root for panel energy (#28149)
* Use hui-root for panel energy

* Review feedback

* Set empty prefs
2025-11-27 15:35:36 +02:00
Petar Petrov 0a9dccfd19 Refactor power sankey hierarchy to handle devices with not power sensor (#28164) 2025-11-27 12:21:55 +01:00
Petar Petrov bfd78670cc Disable axis pointer on the energy devices bar chart to fix refresh issues on touch devices (#28163) 2025-11-27 12:20:06 +01:00
Petar Petrov 11276af1a0 Handle grouping by floor and area in power sankey card (#28162) 2025-11-27 12:19:42 +01:00
Paul Bottein d7be46c00b Fix box shadow for sidebar tabs (#28170) 2025-11-27 12:19:15 +01:00
Paul Bottein 94f32ce242 Fix disabled dashboard picker when no custom dashboard (#28172) 2025-11-27 12:18:48 +01:00
Wendelin ef3e8186bc Fix add condition default tab and blank styles (#28166) 2025-11-27 12:18:21 +01:00
Paul Bottein 50fcf622aa Fix labs back button (#28174) 2025-11-27 12:42:55 +02:00
Paul Bottein 77c2444be8 Restore sidebar view when clicking back (#28167) 2025-11-27 12:42:36 +02:00
Wendelin e5cb26cd3d Fix automation add TCA autofocus (#28168)
Fix automation add tca autofocus
2025-11-27 11:28:18 +01:00
Simon Lamon 2896519bfd Don't show more info for untracked consumption (#28151) 2025-11-27 09:55:23 +02:00
ildar170975 0b6e35eb53 Data tables: make sorting direction 2-state instead of 3-state (#28160)
* sorting is 2-state

* sorting is 2-state

* sorting is 2-state
2025-11-27 09:54:38 +02:00
Iván Pereira e80a855f87 Fix hide sidebar tooltip on touchend events (#28042)
* fix: hide sidebar tooltip on touchend events

* Add a comment recommended by Copilot

* Clear timeouts id in disconnectedCallback
2025-11-27 09:03:23 +02:00
dependabot[bot] 7c88cf4e30 Bump node-forge from 1.3.1 to 1.3.2 (#28157)
Bumps [node-forge](https://github.com/digitalbazaar/forge) from 1.3.1 to 1.3.2.
- [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/v1.3.1...v1.3.2)

---
updated-dependencies:
- dependency-name: node-forge
  dependency-version: 1.3.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-27 06:49:09 +01:00
Petar Petrov 9001cd3e65 Replace gauges with energy usage graph in energy overview (#28150) 2025-11-26 17:37:18 +01:00
renovate[bot] ca8923d8f4 Update dependency glob to v13 (#28135)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 18:13:05 +02:00
Bram Kragten ac56c6df9a Bumped version to 20251126.0 2025-11-26 16:11:20 +01:00
Bram Kragten e7e4407a09 Merge branch 'rc' into dev 2025-11-26 16:10:48 +01:00
Wendelin 3f0c9538bd Remove SubscribeMixin from automation and Z-Wave JS dialog components (#28146) 2025-11-26 15:05:47 +00:00
Bram Kragten 5c3ccbfdad Remove hard coded mqtt trigger, and migrate to new format (#28143) 2025-11-26 14:56:26 +00:00
Bram Kragten 9710142c47 Resubscribe to descriptions when labs feat changes (#28145) 2025-11-26 15:54:31 +01:00
Petar Petrov 57640d17cd Add show_only_totals option to energy sources table (#28147) 2025-11-26 15:49:14 +01:00
Wendelin b5d93e7515 Remove chains of new conditions (#28140) 2025-11-26 15:09:40 +01:00
Steven TraversandWendelin ca9b29d82a Show encryption key in actions for esphome device (#28080)
Co-authored-by: Wendelin <[email protected]>
2025-11-26 13:43:58 +00:00
Bram Kragten 51efa4f61f Set defaults for platform triggers and conditions (#28138) 2025-11-26 14:05:39 +01:00
Bram Kragten a6c71719d1 Only show section title when it has content (#28141) 2025-11-26 12:56:55 +00:00
Bram Kragten 44aa15809a Add helper and other category for triggers and conditons (#28139) 2025-11-26 13:41:59 +01:00
Wendelin 0f99fcd58c Add automation action by target (#28136) 2025-11-26 13:33:27 +01:00
renovate[bot] 0ff1b92fde Update Yarn to v4.12.0 (#28134)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 13:02:35 +01:00
renovate[bot] 98c9e0f2e4 Update workbox monorepo to v7.4.0 (#28133)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 13:02:29 +01:00
Wendelin 493d650e15 Automation editor: Add trigger/condition/action from target (#28031) 2025-11-26 12:36:14 +01:00
Aidan Timson c4e1ff0276 Restore canOverrideAlphanumericInput checks in quick bar (#28132) 2025-11-26 12:32:59 +01:00
Petar PetrovandClaude c8f5910d98 Add Water view strategy (#28130)
Co-authored-by: Claude <[email protected]>
2025-11-26 12:27:57 +01:00
Paul Bottein 0ae49c7c3e Remove unused sidebar translations (#28131) 2025-11-26 12:27:20 +01:00
WendelinandBram Kragten d961aaace4 Fix default language in assists pipeline detail (#28125)
Co-authored-by: Bram Kragten <[email protected]>
2025-11-26 12:26:56 +01:00
renovate[bot] bd6bc25874 Update dependency typescript-eslint to v8.47.0 (#28129)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 12:55:26 +02:00
renovate[bot] a45b07ea23 Update dependency rspack-manifest-plugin to v5.2.0 (#28128)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 12:55:07 +02:00
Paul Bottein f7c446b257 Fix panel energy wizard (#28111)
* Fix panel energy wizard

* Rename
2025-11-26 12:24:04 +02:00
Paul Bottein 71a29aa97d Add sidebar to home dashboard (#28084) 2025-11-26 09:58:31 +01:00
Jan BouwhuisandSimon Lamon ae3a405a7b Add support for service action description placeholders (#27636)
Co-authored-by: Simon Lamon <[email protected]>
2025-11-26 09:54:30 +01:00
Aidan Timson ebbcad812a Migrate generic dialog-box to ha-wa-dialog (#27669) 2025-11-26 08:51:51 +00:00
renovate[bot] d35a12d7e8 Update dependency core-js to v3.47.0 (#28124)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 10:47:14 +02:00
renovate[bot] 67e6dba85c Update vitest monorepo to v4.0.13 (#28123)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 10:46:34 +02:00
Petar Petrov fb666a7553 Fix sankey diagram passthrough ordering (#28012) 2025-11-26 09:45:32 +01:00
Petar Petrov d767afb1e1 Show source table in energy overview only if cost is configured (#28061) 2025-11-26 09:43:32 +01:00
Petar Petrov eb6191ab3a Refactor color handling to use CSS variables (#28021) 2025-11-26 09:42:50 +01:00
ildar170975 7fe9ae22f0 Hide shortcuts for a mobile client (#27905)
* hide shortcuts for mobile

* hide shortcuts for mobile

* prettier

* prettier

* prettier

* prettier

* revert to original

* revert to original

* revert for showQuickBar()

* prettier
2025-11-26 10:41:29 +02:00
Petar Petrov e3a1e5e0e3 Fix vertical alignment of ha-label content (#28013) 2025-11-26 08:37:42 +00:00
renovate[bot] 01b8a5e01a Update dependency jsdom to v27.2.0 (#28122)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 06:16:34 +00:00
renovate[bot] a8ab035793 Update dependency color-name to v2.1.0 (#28120)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 06:16:29 +00:00
renovate[bot] b36795ad3d Update dependency marked to v17.0.1 (#28121)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 06:16:04 +00:00
renovate[bot] ff0e173cfd Update dependency @lokalise/node-api to v15.4.0 (#28119)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 07:08:29 +01:00
renovate[bot] 11883525c2 Update CodeMirror (#28117)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 07:08:12 +01:00
renovate[bot] f89f364add Update dependency lint-staged to v16.2.7 (#28116)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 07:07:55 +01:00
renovate[bot] 56391e32f2 Update dependency hls.js to v1.6.15 (#28114)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 07:07:37 +01:00
renovate[bot] b7f0f62949 Update dependency barcode-detector to v3.0.8 (#28113)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 07:07:20 +01:00
Petar Petrov b143421886 Add water sankey card (#27929)
* Add support for downstream water meters in energy dashboard

* Add water sankey card
2025-11-25 16:57:10 +00:00
renovate[bot] 4736a974ec Update dependency @rspack/core to v1.6.4 (#28107)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-25 16:45:27 +00:00
Paul Bottein 2c80f459c2 Remove experimental dashboard strategies (#28109) 2025-11-25 17:40:17 +01:00
Paul Bottein 688369f994 Fix undo redo with views with no path set (#28110) 2025-11-25 18:39:45 +02:00
renovate[bot] 4e0167c012 Update dependency @rsdoctor/rspack-plugin to v1.3.11 (#28106)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-25 17:36:17 +01:00
Aidan Timson b3769343ea Use space tokens in device page (#28108) 2025-11-25 16:19:36 +00:00
Petar Petrov 967f4a227c Add support for downstream water meters in energy dashboard (#27833) 2025-11-25 17:18:13 +01:00
Wendelin 4c45b9786c Fix labs progress cancel (#28105) 2025-11-25 16:16:37 +00:00
karwosts 23bc874f63 Don't suggest entity autocomplete for actions (#28052) 2025-11-25 17:08:41 +01:00
Paul Bottein 14e1bdb586 Rename home dashboard path and strategy name (#28104) 2025-11-25 17:03:58 +01:00
Jan-Philipp Benecke fe50c1212a Add undo/redo functionality to dashboard editor (#27259)
* Add undo/redo functionality to dashboard editor

* Use controller and move toast to undo stack

* Store location and navigate to view

* Await and catch errors

* Process code review
2025-11-25 16:09:13 +02:00
Petar Petrov c01fbf5f47 Revert "Use entity name for activity/logbook renderer" (#28098) 2025-11-25 13:24:51 +01:00
Aidan Timson 5c8da28b61 Standardise scrollable area fade (#28074)
* Extract fade CSS into shared file

* Switch to linear gradient instead of box shadow

* Refactor

* Refactor

* Scrollbar

* Fix

* Create mixin

* Move styles into mixin

* Dont replace mixin styles

* Reuse bar-box-shadow

* Move position
2025-11-25 13:04:08 +02:00
Rahul Harpal bbb3c0208b Remove defaultHidden property from area configuration in automation, scene, and script pickers (#28096) 2025-11-25 10:55:12 +00:00
Aidan Timson 82a3db39fe Use entity name for activity/logbook renderer (#28083) 2025-11-25 12:46:57 +02:00
Paul BotteinandBram Kragten 254857b53f Improve sidebar and dashboard management logic (#28019)
Co-authored-by: Bram Kragten <[email protected]>
2025-11-25 10:39:07 +00:00
Simon Lamon 1648be6b83 Rename DialogLovelaceDashboardConfigureStrategy (#28092) 2025-11-25 12:22:18 +02:00
Jan LayolaandPetar Petrov c4c774c217 Add total consumption to energy usage graph card (#28086)
* Add total consumption to energy usage graph card

* Add "used" suffix to energy usage graph card total

* Apply code review feedback

* Update src/panels/lovelace/cards/energy/hui-energy-usage-graph-card.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-11-25 10:18:29 +00:00
Bram KragtenandPetar Petrov 6a0aab2088 Add dynamic condition support (#28058)
Co-authored-by: Petar Petrov <[email protected]>
2025-11-25 11:17:53 +01:00
Aidan TimsonandPetar Petrov 5a5593ec5b Add labels to device info card on device/service/hub page (#28082)
* Fix typo

* Add labels to device info card

* Lock

* Use token

* Add same class

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

* Match codebase style

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-11-25 08:47:35 +02:00
Paulus Schoutsen 2d39afdeac Render full chat log in voice debug (#27678) 2025-11-24 22:19:09 -05:00
Paul Bottein 974ac31277 Winter is coming (#28036)
* Winter is coming

* Set max to 30 on mobile

* Change storage key

* Use core

* Add browser level switch for winter mode

* Simplify logic
2025-11-24 22:11:38 +01:00
Petar Petrov 47e98d532d Fix energy distribution card not advancing to next day (#28081) 2025-11-24 20:44:22 +01:00
Jan Bouwhuis 2efc513221 Bump home-assistant-js-websocket to 9.6.0 (#28091) 2025-11-24 20:25:33 +01:00
Aidan Timson 5d820e3046 Fix color of dialog header and expansion panel (#28087) 2025-11-24 17:57:10 +01:00
Wendelin c3cff3bcd3 Fix add to list item (#28073)
* Fix add to list item

* Remove unused css
2025-11-24 17:55:53 +02:00
Bram KragtenandPetar Petrov e65a8a6b66 Add device database toggle to analytics (#27948)
Co-authored-by: Petar Petrov <[email protected]>
2025-11-24 16:30:26 +01:00
Aidan Timson 318452d6f6 Reset automation sidebar width on double click (#28076) 2025-11-24 14:37:11 +01:00
Wendelin 6890823c31 Make login button full width (#28072) 2025-11-24 10:49:13 +01:00
Simon LamonandPetar Petrov ba9bab38c9 Migrate updates dropdown to ha-dropdown (#28039)
* Migrate upgrade dropdown

* Apply suggestion from @MindFreeze

* Update src/panels/config/core/ha-config-section-updates.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-11-24 09:06:55 +00:00
Wendelin 085b3884af Fix add to selected action (#28062) 2025-11-24 11:01:58 +02:00
Simon LamonandPetar Petrov a9c816ed9c Migrate analytics dropdown to ha-dropdown (#28038)
* Migrate analytics dropdown

* Apply suggestion from @MindFreeze

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-11-24 08:52:22 +00:00
c3201eecf3 Show blueprint usage count in overview (#28054)
* Show blueprint usage count in overview

* feat(blueprint): add usage count functionality and update table rendering

* feat(blueprint): enhance usage count display with interactive chip

* fix(blueprint): convert _handleUsageClick to an arrow function for consistent context binding

* Update src/panels/config/blueprint/ha-blueprint-overview.ts

Co-authored-by: Copilot <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
Co-authored-by: Copilot <[email protected]>
2025-11-24 07:07:04 +00:00
dependabot[bot] bd67a3b90a Bump actions/checkout from 5.0.0 to 6.0.0 (#28056) 2025-11-24 07:28:51 +01:00
dependabot[bot] e59ab45e60 Bump github/codeql-action from 4.31.3 to 4.31.4 (#28057) 2025-11-24 07:13:43 +01:00
Franck NijhofandClaude 4674384f7d Allow deleting helpers directly from helpers panel (#28044)
* Allow deleting helpers directly from helpers panel

* Fix error handling in helper deletion logic

Address review feedback by improving the logic in _deleteHelper:
- Throw error when entity is not found in registry or component not loaded
- Move return statement outside of nested condition to ensure proper control flow
- Prevent fallthrough to config entry deletion for old-style helpers

Addresses review comment from @MindFreeze

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>

---------

Co-authored-by: Claude <[email protected]>
2025-11-23 15:20:20 +01:00
steinmn 2e7c95a8cc Translate dashboard panel url error message (#27306)
* Translate dashboard panel url error message

* Use backend provided translations
2025-11-23 14:54:21 +01:00
Simon Lamon 9630b175a1 Remove open from ha-dropdown (#28037) 2025-11-22 14:30:06 +02:00
Petar Petrov be319503f7 Update color scheme in ZHA network visualization (#28032) 2025-11-21 19:09:37 +01:00
Paul Bottein 9b1fe28018 Rename defaultPanel to default_panel (#28035) 2025-11-21 16:24:34 +01:00
Paul Bottein 0595f722f3 Add basic editor to edit favorites entities for home panel (#28028)
* Add basic editor to edit favorites entities for home panel

* Rename favorites

* Rename favorites

* Feedbacks
2025-11-21 16:19:39 +02:00
Petar Petrov 1c0315854a Hide echarts toolbox better (#28030) 2025-11-21 14:52:20 +02:00
Bram Kragten ccc48d158a Bumped version to 20251105.1 2025-11-21 13:50:20 +01:00
Bram KragtenandPetar Petrov b11e787f09 Dont add store token for external auth flows (#28026)
* Dont add store token for external auth flows

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-11-21 13:50:04 +01:00
renovate[bot] cdb6562de8 Update dependency js-yaml to v4.1.1 [SECURITY] (#27955)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-21 13:48:48 +01:00
karwosts d8e8c9aa02 Fix media image on dashboard-level background (#27934) 2025-11-21 13:48:10 +01:00
Petar Petrov be392be1e6 Increase ZHA reconfiguration dialog width for details view (#27909) 2025-11-21 13:44:41 +01:00
Petar Petrov 10dc432445 Fix entity name in statistics chart (#27896) 2025-11-21 13:44:40 +01:00
Wendelin 19187f887d Fix target picker for entity_id: none (#27893)
Fix notFound condition to exclude 'none' in ha-target-picker-item-row
2025-11-21 13:44:40 +01:00
Petar Petrov dc76a42aaa Smooth sensor card more when "Show more detail" is disabled (#27891)
* Smooth sensor card more when "Show more detail" is disabled

* Set minimum sample points to 10
2025-11-21 13:44:38 +01:00
Wendelin 1f2b8047a6 Use ha-ripple in ha-md-list-item (#27889) 2025-11-21 13:44:38 +01:00
Petar Petrov e8c9ed0528 Dynamic total energy for pie chart (#27883) 2025-11-21 13:44:37 +01:00
Petar Petrov c7ae78c02f Fix chart label outline color (#27882) 2025-11-21 13:44:36 +01:00
karwosts dc8f1211e6 Fix entity editor with non-existant entity (#27875) 2025-11-21 13:44:35 +01:00
Yuksel Beyti 5c25a63ea5 Fix malformed HTML tags in backup backups component (#27872) 2025-11-21 13:44:34 +01:00
Paul Bottein c1787ab994 Fix backup download and delete actions (#27851) 2025-11-21 13:44:33 +01:00
Paul Bottein 6fea535fdc Fix OHF logo theme (#27830) 2025-11-21 13:44:32 +01:00
Wendelin e8cee84380 Fix floor details area picker (#27827) 2025-11-21 13:44:31 +01:00
Wendelin b4613edeb7 Target picker row check if not found entity isn't "all" (#27826)
Target picker row check if not found entity isn't all
2025-11-21 13:44:30 +01:00
WendelinandPetar Petrov a8b6e5aa3d Add trigger/condition/action dialog: select single search result with enter key (#27825)
* Add trigger/condition/action dialog: select single search result with enter key

* Update src/panels/config/automation/add-automation-element-dialog.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-11-21 13:44:29 +01:00
Jan Bouwhuis e842193cd6 Fix index for service action translation in service action dialog (#27824) 2025-11-21 13:44:28 +01:00
Bram Kragten bb0813333d Fix landing page build (#27817) 2025-11-21 13:44:27 +01:00
Petar Petrov ab4c6f80f4 Disable graph resize animation for general resizing (#27816) 2025-11-21 13:44:26 +01:00
Bram KragtenandPetar Petrov 3b73d7c298 Dont add store token for external auth flows (#28026)
* Dont add store token for external auth flows

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-11-21 12:01:02 +00:00
Aidan Timson 2955cb4956 Make use of documentationUrl over hardcoded docs links (#28022)
Make use of documentationUrl over hardcoded docs link
2025-11-21 13:43:46 +02:00
c679e312a0 Add delete option to reauth cards on integrations dashboard (#28020)
* Add delete option to reauth cards on integrations dashboard

Users can now delete config entries directly from the reauth card that appears at the top of the integrations dashboard, instead of having to scroll down to find the original integration card.

The delete option:
- Appears in the three-dot menu on reauth cards
- Shows a confirmation dialog before deletion
- Handles application credentials cleanup
- Shows restart notifications when required
- Uses the same styling and localization as the integration entry delete

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>

* Apply suggestions from code review

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2025-11-21 13:39:01 +02:00
Aidan Timson 37e12a83be Fix scene review switch action overflow issue (#28024)
* Fix scene review switch action overflow issue

* Be more specific
2025-11-21 10:33:49 +00:00
Aidan Timson 755c6dbb93 Add design tokens to labs feature (#28023) 2025-11-21 11:21:33 +01:00
Silas KrauseandPetar Petrov 4a90331ac7 Add markdown support for assist messages (#27957)
* Add markdown support for assist messages

* Improve styles

* Refactor code

* Fix white space

* Move code

* Make css compiler happy

* Wait for render to complete before scrolling

* Revert changes

* Refactor ha-markdown to render in chunks

* Refactor and adapt scroll logic

* Fix imports

* Update styles

* Render into renderRoot

* Fix query selector

* Fix broken image style

* Implement PR feedback

* Remove unnecessary css

* Fix cache issue

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-11-21 08:03:47 +00:00
Aidan TimsonandPetar Petrov 7b264ae338 Standardise fixed top ha-dialog usages and fix safe areas (#27997)
* Add default padding

* Use vars

* Restore

* Use container padding

* Move fixed top styles to shared styles

* Use fixed styles and adjust for safe areas on media browse dialog

* Use vars

* Reduce

* Reuse

* Add to strategy editor dialog

* Reuse for editors

* Reuse for media manager

* Remove redundant code

* Reuse for quick bar

* Add

* Use vars

* Fix

* Fix

* Adjust for safe area

* Fix

* Fix

* Default

* Fix

* Extra space at bottom

* Remove override

* Remove

* Fix

* Fix

* Remove

* Fix

* Fix

* Use y inset

Co-authored-by: Petar Petrov <[email protected]>

* Format

* Update src/components/media-player/dialog-media-player-browse.ts

* Format

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-11-21 08:24:14 +02:00
bb5fefce2b Introduce Home Assistant Labs (#27989)
Co-authored-by: Claude <[email protected]>
Co-authored-by: Bram Kragten <[email protected]>
2025-11-20 21:22:14 +01:00
Aidan Timson 5703de9616 Update LLM instructions to recent codebase changes (#28017)
* Update dialog instructions

* Add button styling and dialog sizing

* Document spacing tokens

* Format

* Explicit spacing token documentation

* View transitions

* Add vt notes

* Keyboard shortcuts

* Tooltip

* Link to the gallery for guidelines

* Add AGENTS.md symlink for newer tools

* Use more sane spacing tokens
2025-11-20 17:59:56 +00:00
Petar Petrov eee2c1e8fd Add power graphs in energy view (#28010) 2025-11-20 18:45:04 +01:00
Petar Petrov d4c1642ccc Fix network graph panning (#28015) 2025-11-20 18:37:33 +01:00
Aidan Timson 0d693e692a Update dialogs to use space tokens (#28018) 2025-11-20 18:35:08 +01:00
Aidan Timson c6091971b6 Fix overflowing content issue in states view (#28009) 2025-11-20 12:32:32 +00:00
hanwg 60229ceba0 Add markdown to parameter descriptions for actions (#27944)
add markdown to parameter descriptions for actions
2025-11-20 08:39:27 +02:00
Paul Bottein e45b631e27 Allow to reorder areas and floors (#27986)
* Add websocket commands

* Add area reordering

* Reorder floors

* Order areas and floors everywhere

* Use right area order in area floor picker

* Add error handling

* Refactor
2025-11-19 16:01:02 +01:00
Petar Petrov ea798cda90 Bump glob to 12.0.0 (#27999) 2025-11-19 15:18:15 +01:00
Petar Petrov 259f4421db Add detail option to trend card feature (#27993) 2025-11-19 15:17:03 +01:00
Paul BotteinandPetar Petrov 1ac3cf199f Save default panel at user and system level (#27899)
* Save default panel in user data

* Change logic for default panel

* Fix types

* Fix typings

* Fix user and local storage

* Use user data and system data

* Update url path and update dashboard settings

* Fix tests

* Wait for panels and user/system data to be loaded

* Update comment

* Update comment

* Set empty object instead of null

* Update comment

* Feedbacks

* Apply suggestions from code review

* format

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-11-19 15:03:20 +01:00
Aidan Timson 8d96679cc3 Swap to margins for narrow safe areas in ha-md-dialog (#27994)
Swap to margins for narrow layouts and safe areas
2025-11-19 15:56:10 +02:00
karwosts ba9c7f3012 Expose location for calendar events (#27983)
* Expose location for calendar events

* from review
2025-11-19 15:40:19 +02:00
Petar Petrov f8923ed648 Split Energy panel into overview and electricity view (#27534) 2025-11-19 14:11:27 +01:00
Petar Petrov 20d0548d33 Add min/max options to bar gauge feature (#27933) 2025-11-19 11:20:06 +01:00
Aidan Timson 04aaae20f5 Create keyboard shortcuts helper (tinykeys) (#27176) 2025-11-19 11:19:01 +01:00
karwosts 852dbbeee0 Fix keyboard for integration page overflow menus (#27991) 2025-11-19 08:44:51 +02:00
Ezra Freedman d57367f62e Fix selection state not updating after item deletion (#27972)
* Fix selection state not updating after item deletion

* only update selected list if script is found
2025-11-19 08:20:12 +02:00
Petar Petrov 47a107dd85 Add Power Sankey card (#27966) 2025-11-18 19:52:52 +01:00
renovate[bot] 3573e823e4 Update Yarn to v4.11.0 (#27978)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-18 17:05:36 +00:00
Ingolf Becker 1a8319a3ab Create mobile column gap variable in hui-sections-view (#27949)
Update mobile column gap variable in hui-sections-view
2025-11-18 14:56:28 +02:00
dependabot[bot] ac23ce6300 Bump glob from 11.0.3 to 11.1.0 (#27976)
Bumps [glob](https://github.com/isaacs/node-glob) from 11.0.3 to 11.1.0.
- [Changelog](https://github.com/isaacs/node-glob/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/node-glob/compare/v11.0.3...v11.1.0)

---
updated-dependencies:
- dependency-name: glob
  dependency-version: 11.1.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-18 06:27:19 +01:00
karwostsandPetar Petrov fc38365958 Fix keyboard for ha-date-input (#27968)
* Fix keyboard for ha-date-input

* Update src/components/ha-date-input.ts

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-11-17 14:22:36 +00:00
koostamasandPetar Petrov b93bf3bc4b Remote stream playing in picture-in-picture fix (#27958)
* Remote stream playing in picture-in-picture fix

* Update src/components/ha-hls-player.ts

Co-authored-by: Petar Petrov <[email protected]>

* Update src/components/ha-web-rtc-player.ts

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-11-17 15:44:24 +02:00
Raad Altaie 869ab6ffc4 disable browser autofill on search inputs (#27963) 2025-11-17 12:58:40 +00:00
dependabot[bot] effba9b918 Bump github/codeql-action from 4.31.2 to 4.31.3 (#27965) 2025-11-17 07:19:27 +01:00
Yosi Levy c848673b1f Various RTL fixes (#27886) 2025-11-16 14:42:09 +02:00
renovate[bot] 074095d3dc Update dependency js-yaml to v4.1.1 [SECURITY] (#27955)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-15 15:42:16 +02:00
Aidan Timson 1bd1e015ff Migrate dialog-lovelace-resource-detail to ha-wa-dialog (#27939) 2025-11-14 08:32:41 +02:00
Aidan Timson 7588490419 Migrate dialog-config-entry-system-options to ha-wa-dialog (#27938) 2025-11-14 08:27:17 +02:00
Petar Petrov 2e80a3ddab Add configurable chart modes in energy devices graph card (#27937) 2025-11-14 08:16:36 +02:00
Bram Kragten 332694549c Add support for triggers.yaml (#27379) 2025-11-13 23:31:40 +01:00
karwosts 396ddef722 Expose completed timestamp for TodoItem (#27943) 2025-11-13 22:40:56 +01:00
Aidan Timson d02804449a Merge media selectors for index.html.template (#27941) 2025-11-13 22:33:30 +01:00
Simon Lamon 4ab24cdc72 Rspack: Deprecated layers (#27942) 2025-11-13 22:32:37 +01:00
Aidan Timson 81c27090d2 Create withViewTransition wrapper function (#27918)
* Create withViewTransition wrapper function

* Add missing space

* Remove function, check for view transition, add param

* Document
2025-11-13 17:32:15 +02:00
karwosts 09bdfd3ad7 Fix incorrect (Disabled) string in trigger (#27935) 2025-11-13 14:36:05 +00:00
karwosts 97e49f751c Fix media image on dashboard-level background (#27934) 2025-11-13 15:43:27 +02:00
Aidan Timson e0d241a2db Move unimplemented base animations to theme styles (#27920) 2025-11-13 15:37:13 +02:00
83e065ae98 Power sources chart (#27501)
* Add power configuration to Energy dashboard

* update translation

* Update src/translations/en.json

Co-authored-by: Norbert Rittel <[email protected]>

* Update src/panels/config/energy/dialogs/dialog-energy-grid-flow-settings.ts

Co-authored-by: Aidan Timson <[email protected]>

* Power graph card

* Single stat for bidirectional power

* Rename power graph to power sources graph

* remove debug code

* tweak

* update translations

* remove unused code

* Separate grid power from energy

* update translation

* update translation

* update data format

* Apply suggestions from code review

Co-authored-by: Aidan Timson <[email protected]>

* Renamed stat_power to stat_rate

* translation tweak

* rename to stat_rate

* Add a line depicting used power

* Typescript improvements

* Add comment

---------

Co-authored-by: Norbert Rittel <[email protected]>
Co-authored-by: Aidan Timson <[email protected]>
2025-11-13 09:26:49 +00:00
Paulus Schoutsen a6ee670682 Fix bad minification (#27926) 2025-11-12 23:29:58 -05:00
Wendelin c457f92826 Upgrade WA to 3.0.0 (#27919) 2025-11-12 17:39:56 +01:00
karwosts c73bd96a1f Fix fields without selectors (#27917) 2025-11-12 17:26:48 +02:00
Wendelin 711f8e2fc3 Fix ha-dropdown and add shadow tokens (#27916)
* Fix dropdown select handle in refresh tokens

* Use semantic shadows for dropdown

* Fix token names
2025-11-12 16:52:05 +02:00
Aidan Timson 91a0066544 Add dashboard time visibility condition (#27790)
* Add time-based conditional visibility for cards

* Move clearTimeout outside of scheduleUpdate

* Add time string validation

* Add time string validation

* Remove runtime validation as config shouldnt allow bad values

* Fix for midnight crossing

* Cap timeout to 32-bit signed integer

* Add listener tests

* Additional tests

* Format
2025-11-12 15:55:59 +02:00
Aidan Timson aee7b8b8d4 Setup base animation styles, add fade out to launch screen (#27829)
* Setup base animation styles

* Add fade out to launch screen

* Cleanup

* Set opacity before removing element

* Remove

* Final

* Use computed duration for timeout

* Add skip animation prop

* Swap

* Use common function and fix issue
2025-11-12 11:54:53 +02:00
Aidan TimsonandPetar Petrov d38d770e1a Refactor ConditionalListenerMixin and extract shared utilities (#27858)
* Refactor ConditionalListenerMixin and extract shared utilities

* Remove

* Use proper type

Co-authored-by: Petar Petrov <[email protected]>

* Import

* Fix typing

* Docstrings

* Use generic types and refactor visibility handling

* Fix function signature and handle other keys separately

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-11-12 09:50:38 +00:00
Petar Petrov 0036679553 Fix target picker displaying blank (#27910) 2025-11-12 09:49:37 +01:00
2b85108242 Introduce ha-dropdown (#27417)
Co-authored-by: Wendelin <[email protected]>
Co-authored-by: Wendelin <[email protected]>
2025-11-12 09:23:31 +01:00
c74320cb82 Add power configuration to Energy dashboard (#27373)
Co-authored-by: Norbert Rittel <[email protected]>
Co-authored-by: Aidan Timson <[email protected]>
2025-11-12 09:21:52 +01:00
renovate[bot] 8ebe6e24d2 Update dependency marked to v17 (#27885)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-12 09:24:17 +02:00
Paul Bottein d3182da587 Create dedicated panel for home dashboard (#27861)
* Create dedicated panel for home dashboard

* Don't use state if only one view

* Prettier

* Use hui-root

* Add alert for edit mode

* Remove no edit

* Add home panel to dashboard list
2025-11-12 09:09:46 +02:00
Petar Petrov 41fbc5e44b Increase ZHA reconfiguration dialog width for details view (#27909) 2025-11-11 20:07:10 +01:00
Tobias Bieniek 3fea41eb0e Add scenes category to home dashboard area views (#27712)
This is similar to the "Automations" category that was added in 52eb3d8, but for "Scenes" this time. It is positioned after the other summary sections.
2025-11-11 11:19:02 +02:00
ildar170975 9a627bdea7 Data tables: remove unneeded "direction: asc" lines (#27903)
* remove unneeded "direction: asc"

* remove unneeded "direction: asc"

* remove unneeded "direction: asc"
2025-11-11 08:14:03 +02:00
Norbert Rittel d9a67f603d Fix grammar in new_automation_setup_failed_text (#27898)
* Fix grammar in `new_automation_setup_failed_text`

* Remove excessive comma
2025-11-10 18:48:26 +01:00
WendelinandPetar Petrov 5f37f8c0ab Use generic picker for target-picker (#27850)
Co-authored-by: Petar Petrov <[email protected]>
2025-11-10 17:15:16 +01:00
Petar Petrov f222702abf Fix entity name in statistics chart (#27896) 2025-11-10 15:08:33 +01:00
2107b7c267 Fix doubled tooltips on timeline charts for mobile devices (#27888)
* Initial plan

* Fix doubled date popups in timeline charts on mobile

Co-authored-by: MindFreeze <[email protected]>

* Add comment explaining triggerTooltip fix

* Actual fix

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: MindFreeze <[email protected]>
Co-authored-by: Petar Petrov <[email protected]>
2025-11-10 14:31:30 +01:00
Petar Petrov 1c05afebd7 Smooth sensor card more when "Show more detail" is disabled (#27891)
* Smooth sensor card more when "Show more detail" is disabled

* Set minimum sample points to 10
2025-11-10 14:23:26 +01:00
Paul Bottein 7179bb2d26 Assume default visible true for panels (#27894) 2025-11-10 15:04:14 +02:00
Wendelin 95cf1fdcf7 Fix target picker for entity_id: none (#27893)
Fix notFound condition to exclude 'none' in ha-target-picker-item-row
2025-11-10 12:23:16 +00:00
renovate[bot] 9617956cc6 Update vitest monorepo to v4.0.8 (#27892)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-10 14:15:36 +02:00
karwosts 65df464731 Fix entity editor with non-existant entity (#27875) 2025-11-10 14:09:44 +02:00
Wendelin bd4e9a3d05 Use ha-ripple in ha-md-list-item (#27889) 2025-11-10 14:04:30 +02:00
ildar170975 963fc13a99 relative_time: increase thresholds (#27870)
* increase thresholds

* restored for days & hours
2025-11-10 12:58:13 +02:00
renovate[bot] ff614918d4 Update vaadinWebComponents monorepo to v24.9.5 (#27884)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-10 12:55:03 +02:00
ildar170975 48aa5fb970 hui-generic-entity-row: add tooltips for relative-time (#27871)
* add tooltips for relative-rime

* lint

* fix import

* prettier

* move a call of uid() to a private property

* some test change
2025-11-10 12:54:26 +02:00
ildar170975andPetar Petrov 190af65756 Display tooltips for labels (#27613)
* add a description fo ha-label

* add a description fo ha-label

* add a description fo ha-label

* add a description fo ha-label

* add a description fo ha-label

* add a description fo ha-label

* add a description fo ha-label

* add a description for ha-label

* add ha-tooltip for ha-input-chip

* add ha-tooltip

* replace() -> replaceAll()

* replace() -> replaceAll()

* prettier

* fix styles to enlarge an "active tooltip area"

* additional check for null for "description"

* simplify a check for description

* simplify a check for description

* simplify a check for description

* simplify a check for description

* simplify a check for description

* simplify a check for description

* simplify a check for description

* simplify a check for description

* simplify a check for description

* call uid() in constructor

* fix a check for null

* attempting to bypass insecure randomness

* move a call of uid() into constructor

* uid generation tweak

* Apply suggestions from code review

* prettier

* simplify

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-11-10 10:04:31 +00:00
Petar Petrov 76911e0e0d Dynamic total energy for pie chart (#27883) 2025-11-10 10:20:26 +01:00
Petar Petrov b8ec7c2e72 Fix chart label outline color (#27882) 2025-11-10 08:53:18 +01:00
dependabot[bot] 10e20c2272 Bump softprops/action-gh-release from 2.4.1 to 2.4.2 (#27879) 2025-11-09 22:14:19 -08:00
dependabot[bot] 2ec05aac2f Bump relative-ci/agent-action from 3.1.0 to 3.2.0 (#27880) 2025-11-09 22:12:30 -08:00
renovate[bot] 61fbe5b53c Update dependency marked to v16.4.2 (#27877)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-10 06:57:39 +01:00
Yuksel Beyti 5f3f1c7139 Fix malformed HTML tags in backup backups component (#27872) 2025-11-09 13:56:43 +02:00
ildar170975 48f37b1b1e "Expand" tooltips: remove a trailing dot (#27869)
remove trailing dot
2025-11-09 09:00:28 +01:00
karwosts 9091df9db5 Fix sequence action copy-paste (#27652) 2025-11-08 15:50:38 +01:00
renovate[bot] 1cd7a1cd78 Update dependency @rsdoctor/rspack-plugin to v1.3.8 (#27867)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-08 13:48:08 +01:00
renovate[bot] ae5c7026b9 Update dependency @rspack/core to v1.6.1 (#27864)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-08 13:16:38 +01:00
renovate[bot] 3900f3995a Update vitest monorepo to v4.0.7 (#27862)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-08 13:16:16 +01:00
Paul Bottein 237f974ee8 Only show panel with default visible flag in sidebar (#27838) 2025-11-08 13:15:43 +01:00
Paul Bottein b2ec4b7d2c Fix backup download and delete actions (#27851) 2025-11-07 13:43:00 +02:00
Aidan TimsonandPetar Petrov b4c83d7877 Migrate dialog-repairs-issue to ha-wa-dialog (#27667)
* Migrate dialog-repairs-issue to ha-wa-dialog

* Allow for custom slots for header title and subtitle, using boolean to enable

* Fix typing

* Cleanup

* Refactor header slot logic

* [workaround] pass aria attributes to dialog

* Update src/components/ha-wa-dialog.ts

Co-authored-by: Petar Petrov <[email protected]>

* Remove unused (by wa) aira attrs

* Fix imports

* Revert "Remove unused (by wa) aira attrs"

This reverts commit ce97bebce40d34135b587c31efdf832e5e262ca8.

* Remove workaround

* Remove

* Format

* Fix subtitle margin

* Use spacing token

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-11-07 13:42:07 +02:00
Paul Bottein 22c53b6859 Add area context in zha, zwave and bluetooth graph (#27849)
* Add area context in zha, zwave and bluetooth graph

* Fix undefined device

* Fix typing

* Add context to find area
2025-11-07 13:34:44 +02:00
Paul Bottein 750b1e5e16 Avoid cropping in base graph (#27848)
* Avoid cropping in base graph

* Add bottom margin
2025-11-07 11:25:35 +01:00
Aidan Timson 5801ce944c Refactor dashboard conditional listeners to use mixin (#27837)
* Update media query to new APIs

* Refactor conditional rendering

* Cleanup

* Restore original functionality

* Restore

* Reduce

* Reduce

* Reduce

* Restore legacy code while we still support them

* Clear conditional listeners before setting up again
2025-11-07 12:22:16 +02:00
Petar Petrov 79ad9dbf44 Disable graph resize animation for general resizing (#27816) 2025-11-07 08:34:42 +01:00
Wendelin 9814533d47 Add service titles to automation action sidebar (#27831)
* Add service titles to automation action sidebar

* Add split limit
2025-11-07 07:27:21 +00:00
renovate[bot] bdb6c684c0 Update dependency eslint to v9.39.1 (#27846)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-07 08:38:42 +02:00
renovate[bot] 0046167f5c Update dependency typescript-eslint to v8.46.3 (#27842)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-07 08:38:21 +02:00
renovate[bot] 5266f0d761 Update dependency @bundle-stats/plugin-webpack-filter to v4.21.6 (#27841)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-07 08:37:35 +02:00
Jan Bouwhuis cc5c0d04c4 Fix index for service action translation in service action dialog (#27824) 2025-11-06 15:15:52 +01:00
Wendelin 7f3d5f557f Target picker row check if not found entity isn't "all" (#27826)
Target picker row check if not found entity isn't all
2025-11-06 15:15:09 +01:00
WendelinandPetar Petrov 9b48cd7737 Add trigger/condition/action dialog: select single search result with enter key (#27825)
* Add trigger/condition/action dialog: select single search result with enter key

* Update src/panels/config/automation/add-automation-element-dialog.ts

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-11-06 13:46:53 +00:00
Aidan Timson 11c6f6ec78 Update @home-assistant/webawesome to 3.0.0-beta.6.ha.7 (#27834) 2025-11-06 15:33:10 +02:00
Wendelin cb0f59b26d Fix floor details area picker (#27827) 2025-11-06 12:42:30 +02:00
Paul Bottein c89fc35578 Fix OHF logo theme (#27830) 2025-11-06 12:39:52 +02:00
Timothy f03cd9c239 Add Add entity to feature for external_app (#26346)
* Add Add entity to feature for external_app

* Update icon from plus to plusboxmultiple

* Apply suggestion on the name

* Add missing shouldHandleRequestSelectedEvent that caused duplicate

* WIP

* Rework the logic to match the agreed design

* Rename property

* Apply PR comments

* Apply prettier

* Merge MessageWithAnswer

* Apply PR comments
2025-11-06 08:25:05 +00:00
karwosts 19a4e37933 Fix incorrect unit displayed in energy grid flow settings (#27822) 2025-11-06 08:46:19 +02:00
Bram Kragten 76514babd5 Fix landing page build (#27817) 2025-11-05 16:13:48 +01:00
Timothy b6abbdafb8 All external config properties could be undefined (#27803)
All external config attributes could be undefined
2025-11-05 16:57:51 +02:00
Bram Kragten 89796e425a Bumped version to 20251105.0 2025-11-05 15:26:35 +01:00
Wendelin 9c42c8bbc4 Add fallback icon for domain template (#27814) 2025-11-05 15:25:54 +01:00
Wendelin 616237caee Fix target picker with empty sections (#27813) 2025-11-05 15:25:53 +01:00
Wendelin 2d36a0d37f Add trigger/condition/action dialog - Show device group always on top (#27812)
add automation element dialog Device always on top
2025-11-05 15:25:52 +01:00
Wendelin 1ec432a20f Change add trigger/condition/action dialog title (#27811)
Change add dialog title
2025-11-05 15:25:51 +01:00
Wendelin afd91b2261 Fix auth language picker styles (#27805) 2025-11-05 15:25:50 +01:00
Paul BotteinandWendelin cdfb7f914f Fix target picker in logbook card editor (#27804)
Co-authored-by: Wendelin <[email protected]>
2025-11-05 15:24:49 +01:00
Wendelin 33b0897522 Add trigger/condition/action dialog: fix empty elements in search results (#27802) 2025-11-05 15:16:14 +01:00
Wendelin 5f0cf1b522 Add condition/action dialog: blocks title (#27801) 2025-11-05 15:16:13 +01:00
Wendelin afb2ad95a4 Fix target picker in card editor (#27800) 2025-11-05 15:16:12 +01:00
Jan-Philipp Benecke 27beab3133 Fix z-index for target picker item row icon (#27798) 2025-11-05 15:16:10 +01:00
Wendelin 435c82489b Fix assist conversation language picker (#27764) 2025-11-05 15:16:09 +01:00
Wendelin d35e6c0092 Add fallback icon for domain template (#27814) 2025-11-05 15:14:41 +01:00
Wendelin 5c2ee54dec Fix target picker with empty sections (#27813) 2025-11-05 13:56:58 +00:00
Wendelin 1dfca76c81 Fix assist conversation language picker (#27764) 2025-11-05 14:48:18 +01:00
Wendelin fd7f028fbf Change add trigger/condition/action dialog title (#27811)
Change add dialog title
2025-11-05 15:31:25 +02:00
Wendelin 3f7283b1af Add trigger/condition/action dialog - Show device group always on top (#27812)
add automation element dialog Device always on top
2025-11-05 15:27:53 +02:00
Paul BotteinandWendelin d35323ac52 Fix target picker in logbook card editor (#27804)
Co-authored-by: Wendelin <[email protected]>
2025-11-05 11:57:34 +00:00
Wendelin 06475382e8 Fix auth language picker styles (#27805) 2025-11-05 10:54:36 +01:00
Wendelin b60dd7f15d Add condition/action dialog: blocks title (#27801) 2025-11-05 10:47:46 +01:00
Wendelin b77e65fabd Add trigger/condition/action dialog: fix empty elements in search results (#27802) 2025-11-05 10:47:20 +01:00
Wendelin cea691a04e Fix target picker in card editor (#27800) 2025-11-05 10:03:56 +01:00
Jan-Philipp Benecke 50df2a34cd Fix z-index for target picker item row icon (#27798) 2025-11-05 08:33:11 +01:00
Aidan Timson e6c0a84994 Add hide background option to iframe card (#27792)
* Add hide background option to iframe card

* Fix

* Add helper
2025-11-05 08:07:43 +02:00
Bram Kragten 3ba6bf272e Bumped version to 20251104.0 2025-11-04 18:21:11 +01:00
Paul Bottein eec99b2fa3 Rename safety panel to security panel (#27796) 2025-11-04 18:20:10 +01:00
Bram Kragten d23e45e410 Handle unknown items in target picker (#27795)
* Handle unknown items in target picker

* Update ha-target-picker-item-row.ts

* update colors

* fallback to domain icons
2025-11-04 18:19:02 +01:00
Paul Bottein 3c82d12609 Auto refresh summary dashboard when registries changed (#27794) 2025-11-04 18:17:46 +01:00
Paul Bottein 15d67997e7 Don't show summary card if summary dashboards are empty (#27788)
Don't show summary card if summary dashboard are empty
2025-11-04 18:16:37 +01:00
Paul Bottein a6dfcb3100 Fix tooltip hide delay (#27786) 2025-11-04 18:16:37 +01:00
karwosts 26c2369228 Fix sankey with external statistics devices (#27784) 2025-11-04 18:16:35 +01:00
Paul Bottein 2eed446492 Display entities without area in summary dashboard (#27777)
* Add support for no area, no floor and no device in entity filter

* Display entities without area in summary dashboard
2025-11-04 18:16:34 +01:00
WendelinandBram Kragten 7ebdeab6b2 Fix-labels-yaml-helper (#27776)
Co-authored-by: Bram Kragten <[email protected]>
2025-11-04 18:16:33 +01:00
Tobias Bieniek 0c35278f51 Hide media players summary when no entities exist (#27642) 2025-11-04 18:16:32 +01:00
Bram Kragten b03fa4bdc5 Handle unknown items in target picker (#27795)
* Handle unknown items in target picker

* Update ha-target-picker-item-row.ts

* update colors

* fallback to domain icons
2025-11-04 18:02:56 +01:00
Paul Bottein 058cecc124 Auto refresh summary dashboard when registries changed (#27794) 2025-11-04 16:41:27 +00:00
Paul Bottein a5f058a7eb Rename safety panel to security panel (#27796) 2025-11-04 17:23:06 +01:00
Paul Bottein 655c2ff3c2 Don't show summary card if summary dashboards are empty (#27788)
Don't show summary card if summary dashboard are empty
2025-11-04 13:40:53 +02:00
Tobias Bieniek e1b0a3e737 Hide media players summary when no entities exist (#27642) 2025-11-04 11:44:12 +01:00
Paul Bottein d59d436080 Display entities without area in summary dashboard (#27777)
* Add support for no area, no floor and no device in entity filter

* Display entities without area in summary dashboard
2025-11-04 12:10:18 +02:00
WendelinandBram Kragten 0fe0bf12f2 Fix-labels-yaml-helper (#27776)
Co-authored-by: Bram Kragten <[email protected]>
2025-11-04 09:01:36 +00:00
Paul Bottein f5a3877f47 Fix tooltip hide delay (#27786) 2025-11-04 09:45:26 +01:00
renovate[bot] 31d04f5338 Update dependency globals to v16.5.0 (#27785)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 08:49:20 +02:00
karwosts 4f7d223aa7 Fix sankey with external statistics devices (#27784) 2025-11-04 08:22:36 +02:00
renovate[bot] 484c60073d Update dependency @octokit/rest to v22.0.1 (#27779)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 06:33:20 +01:00
renovate[bot] 0e1ab1a60c Update dependency hls.js to v1.6.14 (#27780)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 06:33:05 +01:00
Bram Kragten 561122f03d Bumped version to 20251103.0 2025-11-03 16:34:11 +01:00
Petar Petrov 95311be034 Apply theme variables to pi charts (#27773) 2025-11-03 16:34:07 +01:00
Wendelin 1eda44a102 Fix selected element text color (#27771) 2025-11-03 16:32:51 +01:00
Petar Petrov d76781eb91 Fix for Y axis label formatting in history graph (#27770) 2025-11-03 16:32:50 +01:00
Petar Petrov 82d44e051f Fix sensor card graph in Safari (#27768) 2025-11-03 16:32:49 +01:00
Aidan Timson fdc9f5a3b7 Use supervisor endpoint for downloading logs (when avaliable) (#27765) 2025-11-03 16:32:47 +01:00
Paul Bottein ee6c82aba9 Don't show tooltip on overflow menu in dashboard toolbar (#27763) 2025-11-03 16:32:46 +01:00
Paul Bottein 11d3f5c2ba Fix suggest cards dialog for sections view (#27762) 2025-11-03 16:32:45 +01:00
Aarni Koskela feb68ce373 Add support for PM4 sensor state (#27754) 2025-11-03 16:32:44 +01:00
Simon Lamon 7f9a9de157 Move label translations to ui.dialog (#27752) 2025-11-03 16:32:43 +01:00
Simon LamonandBram Kragten 8e1b6a3d3b Fixes in backup overflow (#27745)
Co-authored-by: Bram Kragten <[email protected]>
2025-11-03 16:32:41 +01:00
Jan-Philipp Benecke 6e6e5a53e2 Fix button text overflow (#27744) 2025-11-03 16:32:41 +01:00
Petar Petrov cef11e0c18 Apply theme variables to pi charts (#27773) 2025-11-03 16:27:09 +01:00
Simon LamonandBram Kragten 55e75e80d2 Fixes in backup overflow (#27745)
Co-authored-by: Bram Kragten <[email protected]>
2025-11-03 16:26:42 +01:00
Petar Petrov 126a78ec8a Fix sensor card graph in Safari (#27768) 2025-11-03 16:00:06 +01:00
Petar Petrov 063af39f0f Fix for Y axis label formatting in history graph (#27770) 2025-11-03 15:59:46 +01:00
Wendelin 132c4c8201 Revert "Show action description in sidebar header using describeAction" (#27772) 2025-11-03 15:59:03 +01:00
Aidan Timson 4c08e960f1 Use supervisor endpoint for downloading logs (when avaliable) (#27765) 2025-11-03 15:58:29 +01:00
Wendelin a8020256de Fix selected element text color (#27771) 2025-11-03 16:57:01 +02:00
Petar Petrov 2ea57c33ae Remove dynamic eventDisplay in calendar (#27767) 2025-11-03 16:33:11 +02:00
Paul Bottein db1408666c Don't show tooltip on overflow menu in dashboard toolbar (#27763) 2025-11-03 14:30:04 +01:00
renovate[bot] 260288a061 Update vitest monorepo to v4.0.6 (#27766)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-03 15:14:01 +02:00
Ezra Freedman 45fd685913 Fix display of multi-day events on calendar card view (#27730)
* Fix calendar card multi-day events not spanning in month view

* not used for fix
2025-11-03 15:03:16 +02:00
Ezra Freedman 896d76b218 Fix calendar all-day toggle date normalization (#27701) 2025-11-03 14:55:20 +02:00
Petar Petrov cec24117dc Auto update statistics graph in more-info (#27760) 2025-11-03 14:02:15 +02:00
Aidan TimsonandPaul Bottein 34006d268b Translate voice assistant pipeline debugger (#27721)
* Translate voice assistant pipeline debugger

* Update src/panels/config/voice-assistants/debug/assist-render-pipeline-run.ts

Co-authored-by: Paul Bottein <[email protected]>

* Typo

* Use keys in render functions

---------

Co-authored-by: Paul Bottein <[email protected]>
2025-11-03 11:47:38 +01:00
renovate[bot] 54c03d91df Update dependency @rsdoctor/rspack-plugin to v1.3.7 (#27761)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-03 11:08:23 +02:00
Paul Bottein 52a56a1c4e Fix suggest cards dialog for sections view (#27762) 2025-11-03 09:56:52 +01:00
CopilotandMindFreeze e49feeb4aa Show action description in sidebar header using describeAction (#27516)
Co-authored-by: MindFreeze <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2025-11-03 08:58:57 +01:00
Simon Lamon a0c30e433a Move label translations to ui.dialog (#27752) 2025-11-03 08:20:12 +02:00
renovate[bot] 354ce027eb Update dependency jsdom to v27.1.0 (#27759)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-03 08:15:46 +02:00
dependabot[bot] 5c224a942d Bump github/codeql-action from 4.31.0 to 4.31.2 (#27758)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.31.0 to 4.31.2.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/4e94bd11f71e507f7f87df81788dff88d1dacbfb...0499de31b99561a6d14a36a5f662c2a54f91beee)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.31.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-03 08:15:00 +02:00
renovate[bot] 0efa4f81d4 Update octokit monorepo to v8.0.3 (#27757)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-03 08:14:39 +02:00
Aarni Koskela 3ad2f35f29 Add support for PM4 sensor state (#27754) 2025-11-02 16:54:40 +00:00
renovate[bot] 7a21d5f7bc Update dependency @rspack/core to v1.6.0 (#27753)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-02 17:48:11 +01:00
Wesley Vos 33226587e6 Fix translation keys of energy-compare card (#27747) 2025-11-01 19:03:42 +02:00
Jan-Philipp Benecke bd2673f311 Use progress ring for updates on config dashboard (#27731)
* Use progress ring for updates on config dashboard

* Prcoess code review
2025-11-01 18:57:25 +02:00
renovate[bot] cecadde497 Update vitest monorepo to v4.0.5 (#27748)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-01 18:56:23 +02:00
Jan-Philipp Benecke 494b8811d0 Fix button text overflow (#27744) 2025-11-01 10:38:33 +01:00
renovate[bot] 4e0a49b3da Update vaadinWebComponents monorepo to v24.9.4 (#27738)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-31 19:50:31 +02:00
renovate[bot] 3145fed5dc Update dependency @material/web to v2.4.1 (#27729)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-31 06:57:37 +01:00
renovate[bot] 3dd040fdc7 Update dependency tar to v7.5.2 [SECURITY] (#27728)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-31 06:57:08 +01:00
Bram Kragten 0408734ec5 Bumped version to 20251029.1 2025-10-30 18:19:31 +01:00
Paul Bottein 317519fc08 Revert "Fix entities card size and add grid contstraints" (#27725) 2025-10-30 18:18:27 +01:00
Paul Bottein 843d79eab4 Don't show tooltip for ha button menu in top bar (#27723) 2025-10-30 18:18:26 +01:00
Paul Bottein 165a757f06 Revert entity naming in target picker chips (#27722) 2025-10-30 18:18:25 +01:00
Aidan Timson ea8b730142 Revert "Migrate dialog-device-registry-detail to ha-wa-dialog (#27668)" (#27716)
This reverts commit 2a8d935601.
2025-10-30 18:18:24 +01:00
Paul Bottein e88c97d625 Use entity naming in more cards (#27714)
* Use entity naming in more cards

* Migrate statistic card

* Fix localize
2025-10-30 18:18:23 +01:00
Aidan Timson 7560988b76 Trend feature: make sure content is centered when loading (#27708)
* Make sure content is centered when loading

* Restore from test
2025-10-30 18:18:22 +01:00
Aidan Timson eecd8077b6 Calendar card height: account for title and stop overflow (#27707) 2025-10-30 18:18:21 +01:00
Paul Bottein cbab5c3f7b Restore trigger id in overflow menu for trigger (#27702) 2025-10-30 18:18:20 +01:00
Paul Bottein a5d27c8bb8 Only clear from and to trigger in state trigger (#27700) 2025-10-30 18:18:19 +01:00
Paul Bottein a6a340b5db Only display add button if at least one entity is selected in entities picker (#27699) 2025-10-30 18:18:18 +01:00
Paul Bottein e3abe9736c Don't show tooltip for ha button menu in top bar (#27723) 2025-10-30 18:17:38 +01:00
Paul Bottein fe41e72774 Revert "Fix entities card size and add grid contstraints" (#27725) 2025-10-30 18:16:49 +01:00
Paul Bottein 7078ef52d4 Use entity naming in more cards (#27714)
* Use entity naming in more cards

* Migrate statistic card

* Fix localize
2025-10-30 16:58:52 +01:00
Paul Bottein f1c9802ee3 Revert entity naming in target picker chips (#27722) 2025-10-30 16:24:09 +01:00
Aidan Timson 35697e3f94 Calendar card height: account for title and stop overflow (#27707) 2025-10-30 14:47:27 +00:00
renovate[bot] 8ea7ad3026 Update vitest monorepo to v4.0.4 (#27720)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-30 15:59:03 +02:00
renovate[bot] 73747fbedc Update dependency @rsdoctor/rspack-plugin to v1.3.6 (#27719)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-30 13:57:36 +00:00
Aidan Timson aaa92bd354 Assist pipelines: allow user to stop TTS audio test (#27710)
* Allow user to stop TTS audio test

* Change button color on state

* Use getter over state
2025-10-30 15:35:19 +02:00
Aidan Timson 5f75fc5bcb Revert "Migrate dialog-device-registry-detail to ha-wa-dialog (#27668)" (#27716)
This reverts commit 2a8d935601.
2025-10-30 12:12:23 +00:00
karwosts 5fa44548c3 Add a state filter to logbook card (#27685)
* Add a state filter to logbook card

* types
2025-10-30 12:23:29 +02:00
Aidan Timson 1945c11621 Trend feature: make sure content is centered when loading (#27708)
* Make sure content is centered when loading

* Restore from test
2025-10-30 09:43:04 +01:00
renovate[bot] 930575d292 Update dependency @rsdoctor/rspack-plugin to v1.3.5 (#27706)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-30 06:02:18 +00:00
Paul Bottein 0147dbab00 Restore trigger id in overflow menu for trigger (#27702) 2025-10-30 04:26:25 +02:00
Paul Bottein 13ace24b83 Only display add button if at least one entity is selected in entities picker (#27699) 2025-10-29 17:05:34 +01:00
Paul Bottein 616333591a Only clear from and to trigger in state trigger (#27700) 2025-10-29 17:02:02 +01:00
Bram Kragten 8f5875c30f Merge branch 'rc' into dev 2025-10-29 16:20:58 +01:00
Bram Kragten 517cd49f35 Bumped version to 20251029.0 2025-10-29 16:19:23 +01:00
Petar PetrovandPaul Bottein 25d9fc94b2 Add legend to energy pie chart (#27697)
* Add legend to energy pie chart

* Update src/components/chart/ha-chart-base.ts

Co-authored-by: Paul Bottein <[email protected]>

* resize fix

* some fixes

---------

Co-authored-by: Paul Bottein <[email protected]>
2025-10-29 14:50:57 +00:00
Ezra Freedman 7b188759e3 Fix todo item date picker displaying previous day (#27698) 2025-10-29 14:21:34 +00:00
Paul BotteinandBram Kragten 76772d1098 Default card name to friendly name (#27696)
Co-authored-by: Bram Kragten <[email protected]>
2025-10-29 13:41:45 +00:00
Paul Bottein 6052745ca0 Add floor icon to every home dashboard views (#27695) 2025-10-29 13:36:28 +01:00
Paul Bottein 89b9780345 Revert "Default entity name to friendly name"
This reverts commit a607edca96.
2025-10-29 13:02:55 +01:00
Paul Bottein a607edca96 Default entity name to friendly name 2025-10-29 13:02:14 +01:00
Tobias Bieniek 52eb3d8063 Add automations category to home dashboard area views (#27641) 2025-10-29 12:21:17 +01:00
renovate[bot] 1361fc36bf Update dependency @lezer/highlight to v1.2.3 (#27691)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-29 10:44:54 +00:00
Tobias Bieniek 505ef2bd11 home dashboard: Allow users to choose weather entity if they have more than one (#27643) 2025-10-29 11:36:05 +01:00
Petar Petrov c0cc66c1ab Fix next flow config flow showing an empty dialog (#27682) 2025-10-29 09:53:14 +01:00
ildar170975 7cfbc521c7 Dev tools -> Templates: max-height fix for cm-editor (#27461) 2025-10-29 09:52:45 +01:00
Ezra Freedman e064ce56cc Fix calendar all day date display (#27689) 2025-10-29 09:42:50 +01:00
renovate[bot] 8d688aa3a9 Update Node.js to v22.21.1 (#27686)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-28 19:46:07 +00:00
Aidan TimsonandPetar Petrov d122483449 Fix entities card size and add grid contstraints (#27684)
* Add grid card options

* Allow overflow

* Use ha-scrollbar

* Use title/header for min rows calculation

Co-authored-by: Petar Petrov <[email protected]>

* Format

* Remove entities length check

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-10-28 20:35:55 +01:00
Aidan Timson f17bbc3f79 Fix activity card height and add constraints for grid layout (#27683)
* Fix logbook height

* Add grid option constraints

* Reverse
2025-10-28 17:02:50 +02:00
karwosts c88f8fcce0 Shift stats in history by 1 hour (#27633) 2025-10-28 15:53:22 +02:00
Tobias Bieniek 8efabde916 Add floor icons to home dashboard headings (#27639)
* Add floor icons to home dashboard headings

This displays floor icons next to floor names in the home dashboard to provide visual consistency with the areas overview dashboard. The icons use either the custom floor icon if configured, or fall back to level-based default icons (e.g., `mdi:home-floor-0`, `mdi:home-floor-1`).

* Remove floor icon fallback from home dashboard headings

as requested in https://github.com/home-assistant/frontend/pull/27639#issuecomment-3452048655
2025-10-28 15:50:50 +02:00
Niklas Wagner e821e1ec83 Allow selecting multiple states in trigger condition (#27455)
* Allow selecting multiple states in trigger condition

* Make from/to select exlusive to each other

* Simplify code

* fix: returning correct type

* Remove unnecessary any type
2025-10-28 15:43:34 +02:00
WendelinandPaul Bottein dc7516da94 Bottom-sheet swipe to close (#27537)
* WIP new add automation element

* WIP new add dialog

* revert merge

* Add tabs

* fix height

* Add max-height

* Add keybindings and blocks search separation

* Fix device translation

* add swipe to close for bottom sheet

* fix translations, scroll issues, RTL

* update target picker selector

* Fix bottom sheet padding

* Simplify scroll lock

* Simplify scroll lock

* Improve swipe gesture

* Fix methods

* Fix race condition

---------

Co-authored-by: Paul Bottein <[email protected]>
2025-10-28 13:47:11 +02:00
Aidan Timson a545a377a7 Fix typos and improve grammar on ha-dialogs design docs (#27681) 2025-10-28 12:38:47 +01:00
Aidan TimsonandPetar Petrov 3634dbcbbf Add media player volume buttons card feature (#27624)
* Add media player volume buttons card feature

* Sort import

* Add uom

* Update src/panels/lovelace/card-features/hui-media-player-volume-buttons-card-feature.ts

Co-authored-by: Petar Petrov <[email protected]>

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-10-28 13:29:56 +02:00
renovate[bot] 75af4f939e Update vitest monorepo to v4.0.3 (#27673)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-27 14:42:03 +00:00
WendelinandBram Kragten 453a2ac7f3 Use generic picker for language picker (#27631)
Co-authored-by: Bram Kragten <[email protected]>
2025-10-27 14:02:13 +00:00
karwosts 8fbd0226fc Media selector for view backgrounds (#27544)
* Media selector for view backgrounds

* Bring back preview image
2025-10-27 15:26:20 +02:00
Aidan Timson 2a8d935601 Migrate dialog-device-registry-detail to ha-wa-dialog (#27668) 2025-10-27 14:30:22 +02:00
Aidan Timson a6328fb6d7 Use space tokens in ha-more-info-dialog (#27666) 2025-10-27 13:44:49 +02:00
Aidan Timson a78b61006f Use space tokens in ha-automation-row (#27665) 2025-10-27 13:40:37 +02:00
Aidan Timson d506aa23b6 Use space tokens in ha-markdown (#27664) 2025-10-27 13:40:04 +02:00
Aidan Timson 48b4df43ab Use space tokens in ha-quick-bar (#27663) 2025-10-27 13:39:41 +02:00
Aidan Timson 8cdcd9cb55 Use space tokens in ha-card (#27662) 2025-10-27 13:38:36 +02:00
ildar170975 a1e2ac1d99 Label picker/selector: add a decription to a list (#27635)
add a decription to getLabels()
2025-10-27 11:11:53 +02:00
Simon Lamon 8ecddbc42c Adjust primary action buttons for create/update category/area dialogs (#27651)
Adjust primary action buttons
2025-10-27 10:52:02 +02:00
dependabot[bot] 6f70ef52a5 Bump actions/upload-artifact from 4.6.2 to 5.0.0 (#27660)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.6.2 to 5.0.0.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/ea165f8d65b6e75b540449e92b4886f43607fa02...330a01c490aca151604b8cf639adc76d48f6c5d4)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-27 10:49:12 +02:00
renovate[bot] 7dff02d7c8 Update dependency @types/sortablejs to v1.15.9 (#27659)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-27 06:35:59 +00:00
Simon Lamon 8bbd7a6a06 Add min and max values for hardware graphs (#27649) 2025-10-27 08:31:24 +02:00
karwosts 5c73a06f76 Regenerate service-picker valueRenderer on localize update (#27640)
* Regenerate service-picker valueRenderer on localize update

* memoize services
2025-10-27 08:30:17 +02:00
Simon Lamon 9943dae82c Adjust line height in weather card (#27653) 2025-10-27 08:29:17 +02:00
renovate[bot] 70bf049df0 Update babel monorepo to v7.28.5 (#27655)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-27 08:28:29 +02:00
renovate[bot] f9d9fbb7f0 Update vitest monorepo to v4.0.2 (#27656)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-27 08:28:00 +02:00
dependabot[bot] 9cb84d3f37 Bump github/codeql-action from 4.30.9 to 4.31.0 (#27661)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.30.9 to 4.31.0.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/16140ae1a102900babc80a33c44059580f687047...4e94bd11f71e507f7f87df81788dff88d1dacbfb)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.31.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-27 08:27:30 +02:00
renovate[bot] c1bcf27cf8 Update dependency @types/qrcode to v1.5.6 (#27658)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-27 08:26:41 +02:00
renovate[bot] 164ec2a9b5 Update vitest monorepo to v4 (major) (#27638)
Update vitest monorepo to v4

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-26 15:34:28 +01:00
renovate[bot] 20001a551c Update CodeMirror (#27647)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-26 15:28:28 +01:00
renovate[bot] b7f85bf733 Update dependency @rsdoctor/rspack-plugin to v1.3.4 (#27648)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-26 15:28:00 +01:00
renovate[bot] b303e9441b Update dependency lint-staged to v16.2.6 (#27644)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-26 07:19:35 +02:00
ildar170975 8f4bd0f620 Fix horiz spacings in ha-select (#27634)
* fix horiz paddings

* prettier

* prettier
2025-10-25 13:37:25 +03:00
Petar Petrov 596346bf59 Improve label layout for pie chart on mobile (#27632) 2025-10-24 16:34:38 +02:00
Paul Bottein 769cea92aa Don't force ratio for area picture (#27630) 2025-10-24 16:12:14 +03:00
Wendelin f825016514 Add color and icon defaults for config labels table (#27622)
* Add color and icon defaults for config labels table

* use space vars
2025-10-24 14:00:06 +02:00
Aidan Timson c6fd45bd6a Use space tokens in card features editor (#27625) 2025-10-24 13:34:10 +02:00
Aidan Timson 6c4f4af75c Use space tokens in tile card (#27626) 2025-10-24 13:33:54 +02:00
Aidan Timson cd5c3ef2f6 Use space tokens in area card (#27627) 2025-10-24 13:33:39 +02:00
dependabot[bot] 636a6fa02e Bump vite from 7.1.6 to 7.1.12 (#27628)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 7.1.6 to 7.1.12.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v7.1.12/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.1.12/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 7.1.12
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-24 13:17:37 +02:00
WendelinandPaul Bottein 21b83426d6 Migrate generic-picker to new design (#27594)
* WIP new combo box

* Use new combo box for generic picker

* Fix esc close and clean up

* Fix empty search list item

* Fix picker usages

* Improve labels picker

* Patch WA to make esc on popover work correctly

* Apply suggestion from @piitaya

Co-authored-by: Paul Bottein <[email protected]>

* Fix NO_MATCHING_ITEMS_FOUND_ID

* Fix possible undefined boolean props

---------

Co-authored-by: Paul Bottein <[email protected]>
2025-10-24 12:52:56 +02:00
WendelinandAidan Timson c139ec22f9 Use space vars (#27623)
Co-authored-by: Aidan Timson <[email protected]>
2025-10-24 09:43:49 +00:00
ildar170975 a6ef3a26da Fix padding for "search-input-outlined" in filters (#27621) 2025-10-24 09:41:50 +00:00
Wendelin 221ca56121 Add automation element dialog: fix blocks only search result (#27618)
Fix exact block search
2025-10-24 11:25:39 +03:00
ildar170975 4e6e3629a8 target picker: use slugify() for tooltips (#27619) 2025-10-24 08:59:14 +01:00
ildar170975 fe94ae0243 ha-media-player-browse: use slugify() for tooltips (#27617) 2025-10-24 09:18:10 +02:00
WendelinandPetar Petrov 8a1a22d4bd New design for automation add trigger/condition/action dialog (#27529)
* WIP new add automation element

* WIP new add dialog

* revert merge

* Add tabs

* fix height

* Add max-height

* Add keybindings and blocks search separation

* Fix device translation

* fix translations, scroll issues, RTL

---------

Co-authored-by: Petar Petrov <[email protected]>
2025-10-24 05:53:19 +00:00
renovate[bot] 153a578986 Update dependency typescript-eslint to v8.46.2 (#27610)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-23 21:18:34 +02:00
renovate[bot] 04bb10d0a2 Update dependency lint-staged to v16.2.5 (#27609)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-23 21:18:20 +02:00
Bram Kragten 35e52de2c1 Handle service description might be undefined (#27606) 2025-10-23 21:15:43 +02:00
Petar Petrov b0862fddaa Fix resizing in pie chart (#27608) 2025-10-23 17:39:43 +03:00
Wendelin 77735f5310 Fix automation sidebar editor rerendering (#27607) 2025-10-23 16:06:53 +02:00
Wendelin e388756533 ha-wa-dialog show header border on scroll (#27605) 2025-10-23 15:55:46 +02:00
Wendelin e9ca9bb781 Target picker fix entities count for labels (#27603) 2025-10-23 15:53:48 +02:00
Tobias Bieniek e48918442c Invert floor sort order to match physical layout (#27580) 2025-10-23 15:39:58 +02:00
Wendelin 52f37f41f0 Revert "Sidebar profile picture fix alignment in RTL languages" (#27604) 2025-10-23 14:31:59 +01:00
Paul Bottein 4687006fec Add description support to fields in object selector (#27602)
* Add description support to fields in object selector

* Use object

* Rename helper to description
2025-10-23 12:23:28 +00:00
Paul Bottein aca4ca3066 Align state content picker with entity name picker (#27530)
* Align state content picker with entity name picker

* Fix state content property
2025-10-23 15:16:56 +03:00
Wendelin 3a2c00622a Sidebar profile picture fix alignment in RTL languages (#27578)
* Fix floor entities count

* Fix rtl profile picture
2025-10-23 15:09:15 +03:00
Paul Bottein 3e749ec085 20251001.4 (#27458) 2025-10-11 14:42:36 +02:00
Paul Bottein ee2ec00069 Bumped version to 20251001.4 2025-10-11 14:41:59 +02:00
Paul Bottein 0aa2941868 Fix unresolved merge conflict in core style 2025-10-11 14:41:42 +02:00
Paul Bottein 46cd1d5156 20251001.3 (#27457) 2025-10-11 14:28:02 +02:00
Paul Bottein 07a5c41fd4 Bumped version to 20251001.3 2025-10-11 14:27:11 +02:00
Paul Bottein 4ad3c553d5 Adjust yarn updates for rc (#27456) 2025-10-11 14:26:10 +02:00
Simon Lamon d40cc448a5 Adjust yarn updates for rc 2025-10-11 12:08:06 +00:00
Bram Kragten e2f3f9d348 Merge branch 'rc' 2025-10-10 11:36:56 +02:00
Bram Kragten 98d44950f8 Bumped version to 20251001.2 2025-10-10 11:36:46 +02:00
Paul Bottein 8ae9edb1ef Fix ha dialog default size (#27415)
* Don't hardcode width height on mobile for all dialogs

* Don't set min width on desktop
2025-10-10 11:35:45 +02:00
Paul Bottein 84c4396c13 Add tooltip instead of title for 'add' button (#27399) 2025-10-10 11:35:44 +02:00
Bram Kragten 2b937a30e3 Merge branch 'rc' 2025-10-10 10:38:43 +02:00
Bram Kragten b7815bfd86 Bumped version to 20251001.1 2025-10-10 10:38:26 +02:00
Wendelin d94fa03411 Fix ha-button keyboard focus (#27437) 2025-10-10 10:38:08 +02:00
Petar Petrov 0a7007ef9e Escape device names in energy dashboard (#27425) 2025-10-10 10:31:09 +02:00
Paul Bottein dd12136dee Use right variable for content color in tooltip (#27400) 2025-10-10 10:31:08 +02:00
Wendelin 6e2f89fe3d Fix android tap highlight border radius (#27382) 2025-10-10 10:31:07 +02:00
Jan-Philipp Benecke 092085b9af Fix media player more info title calculations (#27360) 2025-10-10 10:31:06 +02:00
Paulus Schoutsen 1c06eb8661 Add ESPHome to discovery sources (#27327) 2025-10-10 10:31:05 +02:00
Jan-Philipp Benecke c7e87b06b5 Fix formatting of position slider tooltip in media player more info (#27326) 2025-10-10 10:31:04 +02:00
Jan-Philipp Benecke 38c738c199 Add "media_stop" action to media player controls in more info (#27325) 2025-10-10 10:31:03 +02:00
Wendelin e899587307 Fix mobile ha-dialog height in Browser (#27298)
Enhance dialog responsiveness by adjusting min/max height to use svh units
2025-10-10 10:31:02 +02:00
Jan-Philipp Benecke c9feb0b75f Add color tokens for slider thumb and indicator (#27295) 2025-10-10 10:31:00 +02:00
Jan-Philipp Benecke 10718c35d1 Make ha-slider not depend on font sizes (#27294) 2025-10-10 10:30:59 +02:00
Wendelin 4dc6a37bad Fix automation editor safe area (#27292) 2025-10-10 10:30:59 +02:00
Jan-Philipp Benecke ac49fc7aba Support redo on Shift+CMD+Z (#27287)
* Support redo on Shift+CMD+Z

* Update redo shortcut for macOS to CMD+Shift+Z
2025-10-10 10:30:57 +02:00
Paul Bottein e4f008800b Align bottom sheet border radius with resizable bottom sheet (#27280) 2025-10-10 10:30:56 +02:00
Bram Kragten 0b0ffd7bab Merge branch 'rc' 2025-10-01 08:58:47 +02:00
Bram Kragten dfa77526a2 Bumped version to 20251001.0 2025-10-01 08:58:30 +02:00
Bram Kragten 9a3bd6c613 Fix intl polyfill loading (#27261) 2025-10-01 08:55:19 +02:00
Wendelin 1161de5746 Update WA to fix tab group scrolling (#27255) 2025-10-01 08:51:12 +02:00
Jan-Philipp Benecke 9df8e20391 Use local entity picture if available in media player more info (#27252) 2025-10-01 08:51:11 +02:00
Petar Petrov 11047a9c95 Make "loading next step" look like progress step in config flows (#27234) 2025-10-01 08:51:10 +02:00
Jan-Philipp Benecke 18fa66f61c Adjust media player cover image sizes in more info for smaller screens (#27232)
Adjust media player cover image sizes for smaller screens
2025-10-01 08:51:09 +02:00
Simon Lamon 758a048f34 Set explicit netlify version to fix workflows (#27229)
netlify set explicit version for fix
2025-10-01 08:51:08 +02:00
Jan-Philipp Benecke ee0fc360b0 Add custom color token for control color (#27227) 2025-10-01 08:51:07 +02:00
Jan-Philipp Benecke 4012f95ec1 Add tooltips for undo/redo in automation & script editors (#27224) 2025-10-01 08:51:06 +02:00
Paul Bottein 0336ce4606 20250926.0 (#27213) 2025-09-26 15:39:29 +02:00
Paul Bottein 9ba36ab7e2 Bumped version to 20250926.0 2025-09-26 15:38:51 +02:00
Paul Bottein fe7a08a1b0 Don't display negative durations in media player more info (#27212)
Don't display negative value in media player more info
2025-09-26 15:38:21 +02:00
Paul Bottein 87a8f9cedc Fix slider ticks support for number selector (#27211) 2025-09-26 15:38:21 +02:00
Paul Bottein 01df7e20ca Fix try tts dialog max width (#27208) 2025-09-26 15:38:20 +02:00
Jan-Philipp Benecke d181219522 Refactor media player slider to use slot for position and duration display (#27205)
* Refactor media player slider to use slot for position and duration display

* Fix variable naming
2025-09-26 15:38:19 +02:00
karwosts 6ae24b8135 Add validation issues to energy diagnostic (#27203) 2025-09-26 15:38:18 +02:00
karwosts 8e009f24f9 Add dropdown mode to water heater operation feature (#27201) 2025-09-26 15:38:17 +02:00
Simon Lamon 53031f44ac Fix typos in media player more info (#27198) 2025-09-26 15:38:16 +02:00
Jan-Philipp Benecke af5a988457 Round seconds in media player more info before formatting (#27196) 2025-09-26 15:38:15 +02:00
Paul Bottein bab0391a19 20250925.1 (#27191) 2025-09-25 17:57:22 +02:00
Paul Bottein 444123c47e Bumped version to 20250925.1 2025-09-25 17:56:13 +02:00
Paul Bottein f123d34046 Revert "Update dependency @types/chromecast-caf-receiver to v6.0.24" (#27188) 2025-09-25 17:53:59 +02:00
Paul Bottein 1b40f99f68 Fix storage bar not displayed (#27183) 2025-09-25 17:50:52 +02:00
Paul Bottein b314b3ed2b Fix analytics switches (#27181) 2025-09-25 17:50:51 +02:00
Paul Bottein 59b8932969 Add icon option to common controls section strategy (#27180) 2025-09-25 17:50:50 +02:00
Wendelin 107af753ec Reduce default tab padding in tab-group (#27173) 2025-09-25 17:50:49 +02:00
Paul Bottein 1f0acb3046 Disabled config badge (#27172)
* Add disabled option for badge

* Add disabled to struct
2025-09-25 17:50:48 +02:00
Paul Bottein 431e533929 20250925.0 (#27170) 2025-09-25 10:48:30 +02:00
Paul Bottein 02c845cbc6 Bumped version to 20250925.0 2025-09-25 10:47:41 +02:00
Paul Bottein 628111ed20 Bumped version to 20250924.1 2025-09-25 10:46:44 +02:00
Paul Bottein e825a9c02f Smooth animation of the sidebar resizing handle (#27166) 2025-09-25 10:46:36 +02:00
Paul Bottein 7a35bddf36 Fix safe padding for bottom sheet and add scroll lock (#27165) 2025-09-25 10:46:35 +02:00
Norbert Rittel ad69270af8 Use "Add (person)" instead of "New person" / "Create" (#27161)
* Update dialog-person-detail.ts

* Update en.json
2025-09-25 10:46:34 +02:00
Paulus Schoutsen 404edf9483 Avoid invalid entities in common controls (#27158) 2025-09-25 10:46:33 +02:00
Paul Bottein a166b4e9b6 Do not show error message when action has no response in dev tools (#27156) 2025-09-25 10:46:32 +02:00
Paul Bottein 7a285f11db 20250924.0 (#27155) 2025-09-24 17:15:37 +02:00
3143 changed files with 433132 additions and 143635 deletions

No files matched your search

@@ -0,0 +1,106 @@
---
name: ha-frontend-components
description: Home Assistant frontend component patterns. Use when implementing or reviewing dialogs, ha-form, ha-alert, keyboard shortcuts, tooltips, panels, Lovelace cards, or ha-button usage.
---
# HA Frontend Components
Use this skill when creating or reviewing Home Assistant UI components and common interaction patterns.
Cross-load `ha-frontend-events` when component work includes event listener typing, custom event dispatch, or event-map declarations.
## Dialogs
Open dialogs through the fire-event pattern:
```ts
fireEvent(this, "show-dialog", {
dialogTag: "dialog-example",
dialogImport: () => import("./dialog-example"),
dialogParams: { title: "Example", data: someData },
});
```
Dialog implementation requirements:
- Use `ha-dialog`.
- Use `DialogMixin`, which implements `HassDialogNext<T>`, for new dialogs. See `src/dialogs/dialog-mixin.ts`.
- Read dialog parameters from the mixin's `params` property and render the dialog open. Return `nothing` while required parameters are absent.
- Call the mixin's `closeDialog()` to close a new dialog. The mixin handles the `closed` event, fires `dialog-closed`, and removes the host element.
- Existing dialogs may implement the legacy `HassDialog<T>` interface from `src/dialogs/make-dialog-manager.ts`.
- Preserve the existing `showDialog()`, open-state, and close-event lifecycle when maintaining a legacy dialog; do not copy that lifecycle into a `DialogMixin` dialog.
- Use `header-title` and `header-subtitle` for simple header text.
- Use slots when standard header attributes are not enough.
- Use `ha-dialog-footer` with `primaryAction` and `secondaryAction` slots.
- Add `autofocus` to the first focusable element, such as `<ha-form autofocus>`, and forward it internally if needed.
Use standard dialog widths: `small`, `medium`, `large`, or `full`. Avoid custom dialog sizing unless there is a clear product need.
## Buttons
`ha-button` wraps the Web Awesome button in `src/components/ha-button.ts`.
Axes:
- `variant`: `brand`, `neutral`, `danger`, `warning`, `success`.
- `appearance`: `accent`, `filled`, `outlined`, `plain`.
- `size`: `xs`, `s`, `m`, `l`, `xl`.
Common usage:
- Use `appearance="filled"` for primary emphasis when needed.
- Use `appearance="plain"` for cancel and dismiss actions.
- Use `variant="danger"` for destructive actions.
- Place primary actions in `slot="primaryAction"` and secondary actions in `slot="secondaryAction"`.
## Forms
`ha-form` is schema-driven with `HaFormSchema[]` and supports common selectors for entities, devices, areas, targets, numbers, booleans, time, actions, text, objects, selects, icons, media, and location.
Use `computeLabel`, `computeError`, and `computeHelper` for translated labels, validation, and helper text.
```ts
<ha-form
.hass=${this.hass}
.data=${this._data}
.schema=${this._schema}
.error=${this._errors}
.computeLabel=${(schema) => this._localize(`ui.panel.${schema.name}`)}
@value-changed=${this._valueChanged}
></ha-form>
```
## Alerts
Use `ha-alert` for user-visible status messaging.
- Alert types: `error`, `warning`, `info`, `success`.
- Useful properties: `title`, `alert-type`, `dismissable`, `narrow`.
- Slots: `icon` for custom leading icon, `action` for custom action content.
- Content is announced by screen readers when dynamically displayed.
```ts
html`
<ha-alert alert-type="error">${this._localize("ui.example.error")}</ha-alert>
<ha-alert alert-type="warning" .title=${this._localize("ui.example.warning")}>
${this._localize("ui.example.description")}
</ha-alert>
<ha-alert alert-type="success" dismissable>
${this._localize("ui.example.success")}
</ha-alert>
`;
```
## Shortcuts And Tooltips
Use `ShortcutManager` from `src/common/keyboard/shortcuts.ts` for keyboard shortcuts. It blocks shortcuts in input fields, can prevent shortcuts during text selection, and supports character and KeyCode shortcuts for non-latin keyboards. See `src/state/quick-bar-mixin.ts` for global shortcut examples.
Use `ha-tooltip` from `src/components/ha-tooltip.ts` for contextual hover help. See `src/components/ha-label.ts` for an example.
## Panels And Lovelace Cards
Panels commonly extend `SubscribeMixin(LitElement)` and receive route and narrow-layout properties.
Lovelace cards should implement `LovelaceCard`, validate config in `setConfig()`, handle loading, error, unavailable, and missing-entity states, and add a configuration editor when needed.
Cards are user-story surfaces. Support different households, entity types, responsive layouts, and accessible interaction states.
@@ -0,0 +1,96 @@
---
name: ha-frontend-contexts
description: Home Assistant frontend Lit context and hass migration guidance. Use when adding or changing component state access, replacing hass reads, consuming entity or registry contexts, or reviewing rerender behavior.
---
# HA Frontend Contexts
Use this skill when a component reads Home Assistant state, registries, localization, services, config, UI data, connection state, or API helpers.
## Goal
Move leaf components away from the broad `hass: HomeAssistant` object. Broad `hass` access rerenders components for unrelated changes, hides the data a component depends on, and makes tests harder to mock.
Container components may keep `hass` when they own it and feed providers. Leaf components should consume the narrowest context that covers their reads.
## Core Files
- Context definitions: `src/data/context/index.ts`
- `consume` decorator, `ContextSubscriptionController`, and `consumeContext` / `ContextController` for reactive controllers: `src/common/decorators/consume.ts` (use instead of `@lit/context`'s `consume` and `ContextConsumer`, enforced by ESLint)
- Entity-scoped consume helpers: `src/common/decorators/consume-context-entry.ts`
- Transform decorator: `src/common/decorators/transform.ts`
- Canonical migration example: `src/panels/lovelace/cards/hui-button-card.ts`
- Providers are wired by `contextMixin` on `HassBaseEl`; consumers do not wire providers manually.
## Context Selection
| Context | Replaces |
| -------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `statesContext` | `hass.states` |
| `entitiesContext`, `devicesContext`, `areasContext`, `floorsContext` | `hass.entities`, `hass.devices`, `hass.areas`, `hass.floors` |
| `registriesContext` | all four registries together |
| `servicesContext` | `hass.services` |
| `internationalizationContext` | `hass.localize`, `hass.locale`, `hass.language` |
| `formattersContext` | entity and attribute formatters |
| `configContext` | `hass.config`, `hass.user`, `hass.auth`, `hass.userData` |
| `connectionContext` | `hass.connection`, `hass.connected`, `hass.debugConnection`, `hass.hassUrl` |
| `apiContext` | `hass.callService`, `hass.callApi`, `hass.callApiRaw`, `hass.callWS`, `hass.sendWS`, `hass.fetchWithAuth` |
| `uiContext` | themes, selected theme, panels, sidebar, and UI state |
| `narrowViewportContext` | narrow-layout boolean |
Lazy contexts subscribe on first consumer and tear down after the last consumer: `labelsContext`, `fullEntitiesContext`, `configEntriesContext`, `manifestsContext`, `triggerDescriptionsContext`, and `conditionDescriptionsContext`.
The single-field contexts such as `localizeContext`, `themesContext`, and `userContext` are deprecated. Use grouped contexts instead.
## Consumption Patterns
Import `consume` from `src/common/decorators/consume`, not from `@lit/context`. The `@lit/context` version forces a host update on every context change, so every consumed field rerenders the component, even without `@state()`, and `@transform` cannot skip anything. Our `consume` leaves update scheduling to the field:
- `@state()` plus `@consume`: rerenders when the context value changes.
- `@state()` plus `@consume` plus `@transform`: rerenders only when the transformed value changes.
- `@consume` alone: the field stays current but never triggers a render. Use this for values only read in event handlers or callbacks, such as `apiContext`, or for data read on demand, such as picker item callbacks.
In reactive controllers, extend `ContextController` and decorate fields with `consumeContext({ context, subscribe, transform })` from the same file. `transform` stores one part of the context value, and `contextUpdated()` runs only when that part changes. `@state()` and `@transform` do not work on controller fields; call `host.requestUpdate()` when the host needs to rerender. Example: `src/data/service-info-controller.ts`.
For lazily created subscriptions, use `ContextSubscriptionController` from the same file instead of `@lit/context`'s `ContextConsumer`, which also forces a host update. Its callback must store the value in a reactive field or call `host.requestUpdate()` itself when the host needs to rerender.
Use entity-scoped helpers when the component watches an entity ID held on the host:
```ts
@state() @consumeEntityState({ entityIdPath: ["_config", "entity"] })
private _stateObj?: HassEntity;
@state() @consumeEntityRegistryEntry({ entityIdPath: ["_config", "entity"] })
private _entity?: EntityRegistryDisplayEntry;
@state() @consumeLocalize()
private _localize!: LocalizeFunc;
```
Use `consumeEntityStates` when the host property contains one or more entity IDs. It filters missing entities and preserves the previous record when none of the selected entities changed.
```ts
@state() @consumeEntityStates({ entityIdPath: ["_config", "entities"] })
private _stateObjs?: Record<string, HassEntity>;
```
For a single field from a grouped context, pair `@consume` with `@transform`:
```ts
@state()
@consume({ context: uiContext, subscribe: true })
@transform<HomeAssistantUI, Themes>({ transformer: ({ themes }) => themes })
private _themes!: Themes;
```
Use `@transform` with `watch` when the transformer depends on a host property, such as a computed entity ID. `consumeEntityState` and `consumeEntityStates` only watch the first path segment.
To consume a whole group untransformed, omit `@transform` and type the field as `ContextType<typeof statesContext>` or the matching context type.
## Review Checklist
- The component consumes the narrowest context needed for the data it reads.
- A broad `hass` property is kept only when the component is a container or external API requires it.
- Entity-scoped reads use the consume helpers rather than ad hoc context transforms.
- Context fields read during render or `willUpdate` are marked `@state()` so updates trigger rendering. Fields only read outside the render cycle are left without `@state()`.
- Tests and mocks only provide the data the component actually consumes.
+65
View File
@@ -0,0 +1,65 @@
---
name: ha-frontend-demo
description: Home Assistant standalone demo structure, configurations, URL navigation, mocked APIs, shared demo stubs used by gallery, and verification. Use when changing files under demo/, changing gallery consumers of demo/src/stubs/, or running and validating the demo.
---
# HA Frontend Demo
Use this skill for standalone demo work and changes to shared demo stubs consumed by the gallery. Follow the persistent repository guidance in `AGENTS.md` and load matching specialist skills alongside this skill, especially `ha-frontend-testing` when running or validating the demo.
## Purpose
The demo is the full Home Assistant frontend running against a mocked backend and is published at <https://demo.home-assistant.io>. It needs no Home Assistant server, which makes it the easiest way to load the real UI in a browser, for example to take screenshots.
## Running The Demo
Run commands from the repository root:
```bash
pnpm dev:demo # Development server on http://localhost:8090
pnpm dev:demo --background # Detached; also supports --status/--stop/--logs
```
Use the E2E workflows documented in `ha-frontend-testing` when validating the demo.
## Opening A Specific Demo
The demo contains multiple demo configurations. Select one directly with the `demo` query parameter, for example `http://localhost:8090/?demo=<slug>`. The valid slugs are defined in `demoConfigs` in `demo/src/configs/demo-configs.ts`, so "the second demo" means the slug of the second entry in that list. An unknown slug falls back to the default, which is the first entry.
## Opening A Specific Page
The demo build uses hash-based routing: the frontend path goes in the URL hash, and the `demo` query parameter goes before the `#`. The URL format is:
```text
http://localhost:8090/?demo=<slug>#/<path>
```
Useful paths:
- `/lovelace/0`: The selected demo's dashboard, also the default when no hash is given.
- `/energy`: The energy dashboard. Its tabs are views: `/energy/overview` (Summary), `/energy/electricity`, `/energy/gas`, `/energy/water`, and `/energy/now`.
- `/map`, `/history`, `/todo`, `/config`: Other sidebar panels.
For example, the water tab of the energy dashboard of the second demo is:
```text
http://localhost:8090/?demo=<second slug>#/energy/water
```
## Structure
- `demo/src/ha-demo.ts`: Root element that sets up all backend mocks.
- `demo/src/configs/<slug>/`: One directory per demo configuration, containing entities, dashboard, and theme data.
- `demo/src/configs/demo-configs.ts`: Registry of demo configurations and URL slug handling.
- `demo/src/stubs/`: Mocked WebSocket and REST APIs.
- `demo/script/develop_demo`, `demo/script/build_demo`: Development server and static build wrappers.
## Shared Gallery Stubs
`demo/src/stubs/` is shared, not demo-private: gallery pages import from it directly. Before changing or removing anything a stub does, search for its callers across `demo/src/` and `gallery/src/`, then check the affected gallery pages as well as the demo.
The two consumers use a stub differently, so demo behavior does not predict gallery behavior. A gallery page calls stubs against the `hass` from `provideHass`, where `hass.config` is the shared `demoConfig` object. A stub that mutates `hass.config` in place is therefore visible to the page. `demo/src/ha-demo.ts` copies `components` into a new array before the stubs run, so the same mutation never reaches the demo. A change can look correct in the demo while quietly breaking a gallery page.
## Verification
Load `ha-frontend-testing` and use its demo and gallery workflows. Validate both consumers when changing shared stubs. Documentation-only changes do not require code tests unless examples or commands change.
+105
View File
@@ -0,0 +1,105 @@
---
name: ha-frontend-events
description: Home Assistant frontend event patterns. Use when typing event handlers, using HASSDomEvent types, dispatching with fireEvent, or declaring HASSDomEvents and event maps.
---
# HA Frontend Events
Use this skill when implementing or reviewing event listeners and custom event contracts. Cross-load `ha-frontend-components` when the work also involves dialogs, forms, alerts, shortcuts, tooltips, panels, Lovelace cards, or buttons.
## Event Handling
Use the event types from `src/common/dom/fire_event.ts` instead of plain `Event`, generic `CustomEvent`, or element casts when they express the handler contract:
- Use `HASSDomCurrentTargetEvent<T>` to read the element on which the listener was registered through `ev.currentTarget`.
- Use `HASSDomTargetEvent<T>` only to read the element that originated the event through `ev.target`.
- Use `HASSDomEvent<T>` to read a custom event payload through `ev.detail`.
- Use `ValueChangedEvent<T>` from `src/types.ts` for the standard `value-changed` event.
- Prefer an event type exported by the component being listened to, such as `HaSelectSelectEvent<T, Clearable>` or `HaDropdownSelectEvent<TValue, TData>`, over reconstructing its detail type.
- Use `ActionHandlerEvent` from `src/data/lovelace/action_handler.ts` for Lovelace tap, hold, and double-tap handlers.
Import event and element types with `import type`:
```ts
import type {
HASSDomCurrentTargetEvent,
HASSDomEvent,
HASSDomTargetEvent,
} from "../common/dom/fire_event";
import type { HaCheckbox } from "../components/ha-checkbox";
import type { HaEntityPicker } from "../components/entity/ha-entity-picker";
import type { HaRadioGroup } from "../components/radio/ha-radio-group";
import type { ValueChangedEvent } from "../types";
```
Type the handler so the selected property can be read directly. Do not cast `ev.currentTarget` or assign it to a single-use variable:
```ts
private _scopeChanged(ev: HASSDomCurrentTargetEvent<HaRadioGroup>): void {
this._scope = ev.currentTarget.value;
}
private _checkedChanged(ev: HASSDomTargetEvent<HaCheckbox>): void {
this._checked = ev.target.checked;
}
private _valueChanged(ev: ValueChangedEvent<string>): void {
this._value = ev.detail.value;
}
private _itemSelected(ev: HASSDomEvent<{ id: string }>): void {
this._selectedId = ev.detail.id;
}
```
Use intersections when a handler needs more than one facet of an event. Keep the native event type when the handler reads native fields such as `key`, modifier keys, `dataTransfer`, or focus relationships:
```ts
private _entityChanged(
ev: ValueChangedEvent<string> & HASSDomCurrentTargetEvent<HaEntityPicker>
): void {
ev.currentTarget.value = ev.detail.value;
}
private _keyDown(
ev: KeyboardEvent & HASSDomCurrentTargetEvent<HTMLInputElement>
): void {
if (ev.key === "Enter") {
this._submit(ev.currentTarget.value);
}
}
```
Dispatch Home Assistant component events with `fireEvent()` instead of constructing `Event` or `CustomEvent` directly. Register the event name and detail type by augmenting `HASSDomEvents`; use `undefined` when an event has no detail. `fireEvent()` constrains event names and supplied detail, and events bubble and cross shadow boundaries by default:
```ts
fireEvent(this, "item-selected", { id: item.id });
fireEvent(this, "refresh-requested");
```
When an event is already registered, derive handler and listener types from its registration rather than repeating the payload shape:
```ts
private _itemSelected(
ev: HASSDomEvent<HASSDomEvents["item-selected"]>
): void {
this._selectedId = ev.detail.id;
}
```
`HASSDomEvents` types `fireEvent()` calls. Augment `HTMLElementEventMap` for typed listeners on HTML elements, or `GlobalEventHandlersEventMap` when the event is handled on global event targets.
In component files, prefer placing global event declarations after the class at the bottom of the file. Preserve the existing placement when editing established files; foundational type, helper, and mixin files commonly keep declarations near the top before their consumers.
```ts
declare global {
interface HASSDomEvents {
"item-selected": { id: string };
"refresh-requested": undefined;
}
interface HTMLElementEventMap {
"item-selected": HASSDomEvent<HASSDomEvents["item-selected"]>;
}
}
```
+128
View File
@@ -0,0 +1,128 @@
---
name: ha-frontend-gallery
description: Home Assistant frontend gallery structure, pages, demos, content, and verification. Use when changing files under gallery/, including gallery markdown, TypeScript demos, sidebar entries, mock data, page generation, or gallery builds.
---
# HA Frontend Gallery
Use this skill for all work under `gallery/`. Follow the persistent repository guidance in `AGENTS.md` and load the matching specialist skills alongside this gallery-specific guidance.
## Quick Reference
Run commands from the repository root unless noted otherwise:
```bash
gallery/script/develop_gallery # Start the gallery development server
gallery/script/build_gallery # Build the static gallery
pnpm lint # ESLint, Prettier, TypeScript, and Lit checks
pnpm lint:types # TypeScript compiler, without file arguments
```
Never run `pnpm lint:types` or `tsc` with file arguments. File arguments make `tsc` ignore `tsconfig.json` and can emit `.js` files into `src/`.
## Purpose
The gallery is a developer and designer reference for Home Assistant frontend UI patterns. It documents component APIs, shows realistic Lovelace and more-info states, captures brand and copy guidance, and provides reproducible demos that are safe to inspect outside a running Home Assistant instance.
- Prefer demonstrating real production components from `src/` instead of creating gallery-only replacements.
- Keep fake state, sample data, and demo-only helpers inside `gallery/`.
- Do not move gallery stubs or demo data into production code unless a production feature explicitly needs them.
- Do not hand-edit generated output under `gallery/build/` or `gallery/dist/`.
## Structure
- `gallery/sidebar.js`: Defines gallery sections, headers, and explicit page ordering.
- `gallery/script/develop_gallery`: Wrapper for the `develop-gallery` gulp task.
- `gallery/script/build_gallery`: Wrapper for the `build-gallery` gulp task.
- `gallery/src/entrypoint.js`: Creates the `<ha-gallery>` shell.
- `gallery/src/ha-gallery.ts`: Renders the drawer, page routing, markdown descriptions, demos, edit links, and RTL toggle.
- `gallery/src/html/index.html.template`: HTML template used by the gallery build.
- `gallery/src/pages/<category>/<page>.markdown`: Optional page description and frontmatter.
- `gallery/src/pages/<category>/<page>.ts`: Optional live demo module for the same page ID.
- `gallery/src/components/`: Gallery-only demo wrappers like `demo-card`, `demo-cards`, `demo-more-info`, and `page-description`.
- `gallery/src/data/`: Fake `hass`, demo states, mock traces, and reusable sample data.
- `gallery/public/`: Static assets copied into the gallery output.
## Page Model
Gallery pages are generated by `gather-gallery-pages` in `build-scripts/gulp/gallery.js`.
- A page ID is the path under `gallery/src/pages/` without the extension, like `components/ha-button`.
- A `.markdown` file and a `.ts` file with the same page ID become one gallery page.
- A page may have only markdown, only a TypeScript demo, or both.
- Markdown can contain YAML frontmatter with `title` and optional `subtitle`.
- Markdown that contains only frontmatter contributes metadata without rendering a description block.
- TypeScript demo modules are dynamically imported for side effects when the page is opened.
- A demo module must define a custom element named `demo-${category}-${page}` with slashes replaced by hyphens, like `demo-components-ha-button` for `components/ha-button`.
- `gallery/src/ha-gallery.ts` renders that element with `dynamicElement()` based on the current page ID.
## Sidebar
Use `gallery/sidebar.js` when a page needs a visible section, section header, or deterministic ordering.
- `category` must match the first directory name under `gallery/src/pages/`.
- `header` is the section label shown in the drawer.
- `pages` is optional. When present, listed pages keep that exact order.
- Pages in a category that are not listed are appended alphabetically after the listed pages.
- New categories without a sidebar entry are appended by the generator with their category name as the header.
- If a listed page does not exist, the generator logs an error during `gather-gallery-pages`.
### Subsections
A section can group its pages under named subsections instead of one flat list. Use this for large categories where related pages should sit together.
- `subsections` is an array of `{ header, pages }`. It is mutually exclusive with a flat `pages` array on the same group.
- Each subsection `header` is a non-collapsible label rendered inside the section's expansion panel; the section stays the only collapsible level.
- Listed pages keep their per-subsection order.
- Any pages found in the category but not listed in a subsection are collected into a generated `Other` subsection, appended alphabetically. The `Other` subsection is omitted when there are no leftovers.
- A listed page that does not exist still logs an error during `gather-gallery-pages`.
- Use sentence case for subsection headers and follow the content standards below.
## Markdown Pages
Use markdown pages for explanations, design guidance, API notes, and copy standards.
- Start with frontmatter when the page needs a title or subtitle.
- Use sentence case for titles, headings, labels, and UI copy.
- Put the live example before the reference API when that makes the page easier to scan.
- Use fenced code blocks with a language tag for copyable examples.
- Keep examples short and focused on the behavior being documented.
- Prefer real component names and attributes over prose-only descriptions.
- Use Home Assistant terminology from `ha-frontend-user-facing-text`.
- For remove/delete and add/create wording, follow `gallery/src/pages/misc/remove-delete-add-create.markdown`.
Gallery markdown is documentation content and is not localized with `localize`. If demo code creates production UI strings, follow the localization and copy guidance in `ha-frontend-user-facing-text`.
## Demo Components
Use TypeScript demo pages for interactive or stateful examples.
- Import production components from `src/` using the correct relative path from the demo file.
- Import reusable gallery helpers from `gallery/src/components/` when they already model the pattern.
- Use `demo-card` and `demo-cards` for Lovelace card examples that render YAML card configs.
- Use `demo-more-info` and `demo-more-infos` for more-info dialog examples.
- Use shared mock data from `gallery/src/data/` instead of repeating large fake state objects inline.
- Show meaningful states, such as loading, unavailable, empty, error, active, inactive, and disabled when relevant.
- Check responsive behavior and the gallery RTL toggle when layout or direction-sensitive UI changes.
- Keep unavoidable casts or loose demo parsing local to the demo helper or demo page.
The gallery ESLint config allows `console` for gallery diagnostics. Do not copy that exception into production frontend code.
## Content Standards
Follow the detailed copy standards in `ha-frontend-user-facing-text`: use American English, sentence case, active voice, inclusive language, direct user-focused wording, and consistent Home Assistant terminology.
- Use `Home Assistant` in full, not `HA` or `HASS`.
- Use `integration` instead of `component` for product concepts.
- Use `Remove` for reversible disassociation and `Delete` for permanent deletion.
- Use `Add` for existing items and `Create` for something made from scratch.
- Avoid Latin abbreviations like `e.g.` and `i.e.` in prose.
- Avoid stitching sentence fragments together in production UI examples.
## Verification
- For markdown, sidebar, and page-generation changes, run `gallery/script/build_gallery`.
- For TypeScript demo or gallery shell changes, run the smallest relevant check plus `pnpm lint` when practical.
- For type checking, run `pnpm lint:types` without file arguments.
- For visual changes, run `gallery/script/develop_gallery` and check the affected page on desktop, narrow viewport, and RTL when relevant.
- If verification is skipped, state which command was skipped and why.
+39
View File
@@ -0,0 +1,39 @@
---
name: ha-frontend-lit
description: Home Assistant frontend Lit conventions. Use when working with reactive properties, internal state, DOM queries, lifecycle methods, or render-derived state.
---
# HA Frontend Lit
Use this skill when implementing or reviewing Lit component state, DOM access, lifecycle methods, or rendering behavior. Cross-load `ha-frontend-types` for Home Assistant data contracts, assertions, and lifecycle parameter types.
## Reactive Fields
This project currently uses Lit's TypeScript experimental decorators with `useDefineForClassFields: false`. Match existing declarations and do not introduce standard-decorator `accessor` syntax unless the project changes decorator mode.
- Use `@property()` for public reactive API and `@state()` for private reactive state.
- Prefer inferred types for initialized reactive fields when inference preserves the intended type; annotate when widening or an external contract requires it.
## DOM Queries
Prefer Lit's `@query()` or `@queryAll()` decorators for fixed selectors in the component's render root.
- Type the decorated field with the narrowest useful DOM or component interface.
- Keep the field optional when it may be absent at the point of access, including conditional rendering or pre-render lifecycle access.
- Use a definite assignment assertion only when every call site runs after the node is guaranteed to exist.
- The optional second argument to `@query()`, as in `@query("#target", true)`, caches the first query result. Use it only when later renders cannot replace the queried node.
- Use a direct query when the selector is dynamic or the target is outside the component's render root. Before querying a child, consider whether the required value belongs in parent state or data flow.
## Render-Derived State
- Prefer render-local values for inexpensive structures used only by that render.
- Assign a render-local value once when repeated evaluation is non-trivial or a local name improves clarity.
- Keep purely presentational derivations in `render()`. Use stored state or `willUpdate()` when the value must participate in lifecycle work, reflection, CSS, or non-render consumers.
- Use `memoizeOne` for pure, argument-derived transforms when stable input identity avoids meaningful repeated work. Keep inputs explicit and limited, and do not add caching without a credible benefit over computing the value directly.
## References
- [Reactive properties](https://lit.dev/docs/components/properties/)
- [Decorators](https://lit.dev/docs/components/decorators/)
- [Shadow DOM queries](https://lit.dev/docs/components/shadow-dom/#query)
- [Reactive update cycle](https://lit.dev/docs/components/lifecycle/)
+127
View File
@@ -0,0 +1,127 @@
---
name: ha-frontend-review
description: Home Assistant frontend PR and review guidance, including implementation quality, existing review feedback, established design patterns, and the authority of UI/UX evidence. Use when reviewing frontend changes, preparing a PR, checking recurring review issues, or applying the PR template.
---
# HA Frontend Review
Use this skill when reviewing Home Assistant frontend changes or preparing a pull request.
## Review Preparation
1. Establish the review scope from the diff and the behavior changed by it.
2. Before identifying findings, use the [project skill catalogue](../../../AGENTS.md#project-skills) to load every matching companion's `SKILL.md`. Follow applicable companion references in those skills as well; this review skill supplies the workflow, and companions supply the domain-specific criteria.
3. Apply all loaded guidance within that scope. Report only problems introduced or worsened by the changeset, anchored to changed lines. Read surrounding code to understand affected behavior, not to generate unrelated cleanup or migration requests.
## Pull Request Body
When creating a pull request, use `.github/PULL_REQUEST_TEMPLATE.md` as the body.
- Do not omit, reorder, or rewrite template sections.
- Check the appropriate "Type of change" box based on the actual change.
- Do not check checklist items on behalf of the user.
- If the PR includes UI changes, remind the user to add screenshots or a short video.
- Explain what the change does for users, not only implementation details.
- Use Markdown.
## Pre-Submission Checklist
- `pnpm lint` passes when practical for the scope.
- `pnpm test` or focused relevant tests are green when practical for the scope.
- Each test added by the change protects real logic, not the look of a component.
- User-facing text is localized and follows `ha-frontend-user-facing-text` guidance.
- Components handle loading, error, unavailable, and missing-entity states.
- Entity existence is checked before property access.
- Event listeners and subscriptions are cleaned up.
- UI is accessible to screen readers and keyboard users.
## Recurring Review Issues
Scope and public surface:
- Keep changes independently reviewable and limited to the requested area.
- Prefer existing Home Assistant helpers, Lit primitives, and component seams over parallel implementations.
- Challenge new public properties and optional feature surface when transient options or existing seams meet the requirement with less lifecycle and consistency cost.
Stateful and asynchronous UI:
- Review transitions in both directions, not only individual rendered states.
- When controls reappear, restore valid defaults instead of retaining state that was only valid while they were hidden.
- Establish immutable dirty-state baselines before asynchronous work, guard against stale responses, and preserve unsaved state in mounted editors.
- Determine an action's current meaning before applying dirty-state checks, especially when an action can change between Save and Close.
Readiness and invalidation:
- Treat readiness as the first displayable terminal result, including stable empty and error states.
- Register child readiness before resolving the parent, do not treat fallback work as terminal, and replay readiness correctly for cached or reused panels.
- Ensure every value read by memoized output participates in its invalidation.
Repository-owned contracts:
- Consult the public [frontend developer documentation](https://developers.home-assistant.io/docs/frontend/) for documented architecture, data flow, design, and development workflows.
- For new leaf components, load `ha-frontend-contexts` and verify they consume narrow contexts instead of introducing a broad `hass` property; containers and external APIs may still require `hass`.
- Verify backend assumptions against the owning Core, Supervisor, or WebSocket implementation, and component assumptions against the exported component contract.
- Prefer canonical repository helpers and test setup over duplicate local implementations.
- Promote AI-review concerns into durable guidance only when supported by code evidence, reproduced behavior, an accepted corrective commit, or human-maintainer validation.
User experience and accessibility:
- Forms need proper labels, helper text, and validation feedback.
- Form markup should not cause password managers to identify fields incorrectly.
- Clickable areas should be large enough for touch interaction.
- Hover, active, disabled, loading, and focus states should be clear.
Dialog and modal patterns:
- Multi-step operations should show progress.
- Dialog state should survive background operations correctly.
- Cancel and close buttons should behave consistently.
- Defaults should be helpful without blocking user override.
Component design patterns:
- Terminology should be consistent. Use words like "Join" or "Apply" instead of "Group" when that better matches the user action.
- Visual hierarchy should use appropriate font sizes, weights, and spacing ratios.
- Components should align to the design grid.
- Badges and indicators should be placed consistently.
Code quality:
- Null and undefined paths should be handled explicitly.
- Potentially undefined array and object access should be guarded.
- Event handlers, timers, observers, and subscriptions should be cleaned up.
Configuration and props:
- Make configuration fields optional when sensible.
- Provide reasonable defaults.
- Keep APIs extensible without adding speculative abstractions.
- Validate configuration before applying changes.
## UI/UX Evidence
For user-facing changes, establish the existing design context as part of frontend review:
- Treat an applicable gallery specification as the authoritative repository source for the documented component or interaction. Inspect its written guidance and demos when present.
- Note relevant production designs, approved designs, and shared `ha-*` components so the implementation can also be compared with established frontend behaviour.
- Require the applicable gallery documentation or demo to change when the implementation intentionally changes behaviour documented there.
- Prefer an established input layout or appropriate shared component over a raw input or ad hoc control.
- Treat explicit UI/UX approval, current repository guidance, and direct human or workflow instructions as stronger evidence than inference.
- Treat linked tasks as evidence of the problem and stated requirements, not automatic UI/UX approval.
- When the direction remains uncertain, search frontend pull requests that carry or previously carried **Needs UX**. Inspect their label history, comments, and reviews rather than relying on the current label alone.
- Judge relevant feedback by its content and surrounding discussion. When GitHub provides `author_association`, prioritise feedback marked `MEMBER`.
- Prefer recent feedback about similar interactions or components. Label removal can show that a workflow gate moved on, but does not prove approval without the surrounding discussion.
- Summarise the applicable guidance instead of maintaining a reviewer list or treating one historical decision as a permanent rule.
## Review Flow
- Before reviewing a pull request, read its existing comments, reviews, and threads, including their status, resolver, and Copilot resolution reason when available.
- Prioritise substantive human feedback, especially from authors marked `MEMBER`, and validate agent-generated feedback against the code and repository guidance.
- Do not duplicate unresolved findings as new inline comments; reference any that still need action in the review summary. Treat resolved feedback as closed only when the resolution reason or surrounding discussion supports that outcome; otherwise validate it against the current code before suppressing it. Respect **Won't fix** and **Incorrect** reasons.
- When a later commit addresses an unresolved thread, note in the review summary that it looks addressed, linking the thread and the commit, so it can be resolved. Do not report it as still open.
- Identify behavioral regressions, bugs, accessibility issues, and missing tests that `ha-frontend-testing` calls for first.
- Do not ask for new tests on visual components. If the visuals clearly changed and the PR has no screenshots or videos, suggest adding them instead.
- When the change adds something repository guidance rules out, such as a rendering test, open the comment with the removal ("Remove this test file") and cite the guidance in one sentence. Do not critique how the unwanted code is written, as that reads as a request to fix it.
- Record the applicable UI/UX evidence for user-facing changes, whether or not further input is needed.
- Keep style-only comments secondary unless they affect maintainability or user experience.
- Prefer small, direct fixes over large refactors during review follow-up.
@@ -0,0 +1,78 @@
---
name: ha-frontend-styling
description: Home Assistant frontend styling, theming, spacing, responsive layout, RTL, and View Transitions guidance. Use when editing CSS, layout, motion, or visual component structure.
---
# HA Frontend Styling
Use this skill when editing CSS, layout, visual hierarchy, theme integration, responsive behavior, RTL support, or view transitions.
## Theme And Layout Basics
- Use Home Assistant CSS custom properties instead of hardcoded colors.
- Use `--ha-space-*` spacing tokens instead of hardcoded spacing where possible.
- Keep components mobile-first and enhance for desktop.
- Keep layouts RTL-safe. Prefer logical properties when they fit.
- Prefer `ha-*` components and current Web Awesome wrappers.
- Avoid adding new legacy Material Web Components (`mwc-*`).
- Scope styles to the component. Do not rely on global styles for component internals.
Spacing tokens are defined in `src/resources/theme/core.globals.ts`. The scale runs from `--ha-space-1` at 4px through `--ha-space-20` at 80px in 4px increments. Common values are `--ha-space-2` at 8px, `--ha-space-4` at 16px, and `--ha-space-8` at 32px.
```ts
static get styles() {
return css`
:host {
padding: var(--ha-space-4);
color: var(--primary-text-color);
background-color: var(--card-background-color);
}
.content {
gap: var(--ha-space-2);
}
@media (max-width: 600px) {
:host {
padding: var(--ha-space-2);
}
}
`;
}
```
## Interaction States
- Make touch targets large enough for mobile.
- Provide clear hover, active, focus, disabled, loading, error, and unavailable states.
- Preserve keyboard navigation and visible focus indicators.
- Maintain WCAG AA contrast for text and essential UI affordances.
## View Transitions
Use the View Transitions API only for meaningful continuity between DOM states.
Core resources:
- Utility wrapper: `src/common/util/view-transition.ts`, `withViewTransition()`.
- Launch-screen fade example: `src/util/launch-screen.ts`.
- Animation keyframes: `src/resources/theme/animations.globals.ts`.
- Animation duration tokens: `src/resources/theme/core.globals.ts`.
Implementation rules:
- Use `withViewTransition()` for fallback behavior.
- Keep transitions simple. Subtle fades and crossfades usually work best.
- Use `--ha-animation-duration-fast`, `--ha-animation-duration-normal`, or `--ha-animation-duration-slow` for timing.
- Ensure each `view-transition-name` is unique at any given time.
- Remember only one view transition can run at a time.
- View transitions operate at document level and do not work inside Shadow DOM style isolation. For web components, set `view-transition-name` on `:host` or use document-level transitions.
- The root gets `view-transition-name: root` by default. Target `::view-transition-group(root)` to customize the default page transition.
## Review Checklist
- Styling uses theme variables and spacing tokens where practical.
- Layout is mobile-first and RTL-safe.
- Component styles are scoped.
- Interactive states are clear and accessible.
- Motion is subtle, tokenized, and respects reduced-motion behavior through existing globals.
+100
View File
@@ -0,0 +1,100 @@
---
name: ha-frontend-testing
description: Home Assistant frontend testing and validation workflow. Use when adding or updating tests, running lint, TypeScript checks, Vitest, Playwright e2e suites, dev servers, or chart-data benchmarks.
---
# HA Frontend Testing
Use this skill when choosing or running validation for frontend changes.
## Test Helpers
- Before adding or changing tests, inspect the relevant suite's existing helpers and fixtures. Reuse them instead of duplicating setup, test data, navigation, interactions, waits, or assertions.
- When the same test flow appears more than once, move it into the closest suite-local helper with a focused interface.
- Keep one-off test behaviour in the test unless a helper makes the intent materially clearer. Do not hide the behaviour under test behind broad, configurable abstractions.
## Core Commands
```bash
pnpm lint # ESLint + Prettier + TypeScript + Lit
pnpm format # Auto-fix ESLint + Prettier
pnpm lint:types # TypeScript compiler, run without file arguments
pnpm test # Vitest
pnpm build # Full production build
pnpm dev # App dev server
pnpm dev:serve # Local serving dev server
```
Never run `tsc` or `pnpm lint:types` with file arguments. File arguments make `tsc` ignore `tsconfig.json` and can emit `.js` files into `src/`.
For focused type feedback on one file, use editor diagnostics instead of a file-scoped `tsc` command.
## Production Builds
Production builds support foreground and managed background execution:
```bash
pnpm build # Full foreground build
pnpm build --background # Full managed background build
pnpm build --modern # Modern frontend_latest bundle only
pnpm build --modern --background # Modern managed background build
pnpm build --status
pnpm build --logs [--follow]
pnpm build --stop
```
Use `pnpm build --modern --background` for production bundle-size or browser performance comparisons that only need modern browser output. It runs the normal metadata and static preparation, minifies and compresses the modern `frontend_latest` bundle and shared static assets, and generates modern-only entry pages and service workers. It deliberately skips the legacy bundle and its service worker.
Do not pass `--help`, `--background`, or `--modern` to `script/build_frontend`; that raw script does not parse arguments and always starts the full foreground build. Use `pnpm build` for managed builds. App builds and development servers keep exclusive ownership of `hass_frontend/` for their lifetime.
Managed app, demo, gallery, and E2E app workflows share one lifetime lock, so only one build or development server can run at a time.
## When To Add Tests
- Write tests for code that computes something: data processing, utilities, config validation, and strategies.
- Do not write rendering tests. This includes views, panels, and components whose text, styles, slots, or option defaults are checked, or that only put context and helper data into a template.
- Do not try to cover every scenario, especially for behaviour that changes often.
- If you are not sure a test is useful, describe it and what it would catch, and let the user decide.
- Tests never talk to a real Home Assistant. Replace `callWS`, `callApi`, and the connection with fakes.
## Dev Servers
`pnpm dev` builds and watches the app, served by a running Home Assistant core configured through `development_repo`.
`pnpm dev:serve` also serves locally and supports `-c` for the core URL and `-p` for the port. The default is 8124, or 8123 in a devcontainer.
Dev server commands support `--background`, `--status`, `--stop`, and `--logs [--follow]`. `pnpm dev`, `pnpm dev:serve`, `pnpm dev:demo`, and `pnpm dev:gallery` also support `--fetch-translations`; this runs translation fetching, including first-time GitHub device authentication, under the workflow lock before starting the watcher. It works in foreground and background modes. Prefer managed background mode while iterating so the watcher stays available across test runs without occupying the terminal. `pnpm dev` and `pnpm dev:serve` share one managed process slot because both write the app output.
## Playwright E2E
Each suite has its own dev server port. Playwright reuses an existing server locally when its configured URL responds; otherwise it performs a slow full build. When a development watcher is being reused, rspack recompiles on save and reruns should not need a restart.
Start the relevant suite server, then run that suite:
| Suite | Background server | Test command |
| ------- | -------------------------------------------- | ----------------------- |
| App | `pnpm test:e2e:app:dev --background` on 8095 | `pnpm test:e2e:app` |
| Demo | `pnpm dev:demo --background` on 8090 | `pnpm test:e2e:demo` |
| Gallery | `pnpm dev:gallery --background` on 8100 | `pnpm test:e2e:gallery` |
The custom development wrappers use `/__ha_dev_status` to identify and manage their own suites. Playwright server reuse checks the configured URL instead. Wrapper start and stop operations are idempotent for a matching suite and reject an unrelated process occupying the port.
Local runs against a watched development server do not always match CI's clean build artifacts, environment, sharding, or worker configuration. Use background servers for the fast iteration loop, but confirm the relevant CI jobs complete successfully before considering E2E changes verified.
Use `-g "<title>" --project=chromium` to narrow a run. `pnpm test:e2e` runs suites sequentially when managed servers are unavailable to prevent cold builds racing over shared generated assets. Run suites directly; piping through output truncation hides progress and failures.
The app suite uses a stripped-down harness for e2e. Demo and gallery use their normal dev servers.
## Benchmarks
For chart data transforms such as history, statistics, energy, and downsampling, read and follow the complete workflow in `test/benchmarks/README.md` before making benchmark or optimization changes.
That workflow owns the baseline, noise analysis, guardrails, acceptance thresholds, and reporting requirements. In particular, optimizations must keep output bit-identical; never update snapshots or modify fixtures to make an optimization pass.
## Verification Selection
- Documentation-only change: no code test required unless examples or commands changed.
- Type-only or utility change: run focused Vitest if available, then `pnpm lint:types` if practical.
- Lit component change: run relevant tests plus lint or typecheck depending on scope.
- E2E-sensitive flow: start the relevant e2e dev server and run the narrow Playwright suite.
- Broad refactor: run `pnpm lint` and relevant test suites when practical.
+44
View File
@@ -0,0 +1,44 @@
---
name: ha-frontend-types
description: Home Assistant frontend TypeScript conventions. Use when defining or reviewing backend data contracts, optional schemas, shared types, assertions, or Lit lifecycle types.
---
# HA Frontend Types
Use this skill for Home Assistant-specific TypeScript contracts and type choices.
## Home Assistant Data Contracts
Verify data contracts against the source that owns them, such as Home Assistant Core, Supervisor, a WebSocket handler, or an exported component type. Do not shape a type around assumptions made by its current frontend consumers.
- Match required, optional, nullable, and defaulted fields to the producer and runtime contract. Preserve optional configuration fields when omission is supported and has defined behavior.
- Use distinct request and response types when their wire shapes differ.
- When changing a shared contract, check affected consumers, tests, fixtures, and mocks.
## Reuse Home Assistant Contracts
- Reuse the canonical Home Assistant type when one exists. Define shared contract types in the data or API module that owns them.
- Reuse types exported by components and helpers rather than reconstructing their payloads. For event types, follow `ha-frontend-events`.
- When one domain contract is used across modules, define and export it from the module that owns that contract.
Prefer an existing owning contract. Introduce a frontend-specific type when the frontend shape or boundary genuinely differs.
## Assertions
Prefer accurate types and runtime narrowing. Use assertions or TypeScript suppressions at boundaries where the runtime invariant is understood but cannot be expressed cleanly; keep them narrow and explain non-obvious invariants.
## Lit Lifecycle Types
For Lit lifecycle methods that receive changed properties, use `PropertyValues<this>` when the method only needs public reactive properties:
```ts
protected willUpdate(changedProperties: PropertyValues<this>) {
// ...
}
```
Use unparameterized `PropertyValues` when the method inspects private or protected reactive properties, which are not keys of `this`. Do not add assertions solely to retain `PropertyValues<this>`.
## Enforced Baseline
Use `import type` for type-only imports. This is enforced by the repository ESLint configuration.
@@ -0,0 +1,98 @@
---
name: ha-frontend-user-facing-text
description: Home Assistant frontend copy, localization, terminology, and user-facing text guidance. Use when adding or reviewing labels, buttons, dialogs, errors, translations, or UI strings.
---
# HA Frontend User-Facing Text
Use this skill for all user-facing text, translations, labels, buttons, dialog copy, errors, helper text, and review comments about wording.
## Localization
- All user-facing text must be translatable.
- Add translation keys to `src/translations/en.json` when introducing new strings.
- Use the localization system instead of inline user-visible strings.
- Prefer complete localized strings with placeholders over concatenating translated fragments.
- Give translators enough context through key naming and placeholders.
```ts
this._localize("ui.panel.config.updates.updates_refreshed", {
count: 5,
});
```
## Voice And Style
- Use American English.
- Use a friendly, informational tone.
- Address users directly with "you" and "your" when appropriate.
- Be inclusive, objective, and non-discriminatory.
- Be concise and clear.
- Use active voice.
- Avoid jargon where a familiar home automation term works.
- Always write "Home Assistant" in full. Do not use "HA" or "HASS" in user-facing copy.
- Spell out terms when possible.
- Use sentence case for titles, headings, buttons, labels, and UI elements.
- Use the Oxford comma in lists.
- Prefer "like" over "e.g." and "for example" over "i.e.".
- Avoid all caps for emphasis. Use wording, bold, or italics instead.
- Write for both technical and non-technical users.
Sentence case examples:
- Use: "Create new automation"
- Avoid: "Create New Automation"
- Use: "Device settings"
- Avoid: "Device Settings"
## Terminology
Use "integration" instead of "component" for user-facing product language unless referring to a frontend component in developer context.
Technical product terms are lowercase in prose: automation, entity, device, service.
## Delete, Remove, Create, Add
Use "Remove" for actions that can be restored or reapplied:
- Removing a user's permission.
- Removing a user from a group.
- Removing links between items.
- Removing a widget from a dashboard.
- Removing an item from a cart.
Use "Delete" for permanent, non-recoverable actions:
- Deleting a field.
- Deleting a value in a field.
- Deleting a task.
- Deleting a group.
- Deleting a permission.
- Deleting a calendar event.
Use "Add" for already-existing items:
- Adding a permission to a user.
- Adding a user to a group.
- Adding links between items.
- Adding a widget to a dashboard.
- Adding an item to a cart.
Use "Create" for something made from scratch:
- Creating a new field.
- Creating a new task.
- Creating a new group.
- Creating a new permission.
- Creating a new calendar event.
Create pairs with Delete. Add pairs with Remove.
## Review Checklist
- Text is localized.
- Copy uses sentence case.
- "Home Assistant" is written in full.
- Delete/Remove and Create/Add match recoverability and object lifecycle.
- Placeholders are used instead of string concatenation.
- The wording is concise and understandable without implementation knowledge.
@@ -0,0 +1,44 @@
---
name: ha-frontend-ux-readiness
description: Home Assistant frontend UI/UX readiness routing for new cards, badges, screens, and interaction patterns. Use it with `ha-frontend-review` to decide whether frontend review is enough or further UI/UX input is needed. Skip it for PRs already carrying Needs UX and for fixes or technical details that preserve an established experience.
---
# HA Frontend UI/UX Readiness
Use the design context and evidence gathered through `ha-frontend-review` to decide whether a change's UI/UX direction is settled and whether further UI/UX review should be recommended or is explicitly required. This skill routes the result; it does not repeat or replace implementation, accessibility, or frontend quality review.
## Early Exit
If the PR already carries the **Needs UX** label, reviewers have already decided to ask designers or UX reviewers for guidance. Do not use this skill to make that recommendation again.
## Triage
1. Apply `ha-frontend-review` and record its UI/UX evidence.
- Include the applicable gallery specification, production or approved designs, shared `ha-*` components, task requirements, historical feedback, and direct instructions.
- Keep the implementation review separate from this readiness decision.
2. Classify the user-facing decision.
- Existing-feature fixes and technical details normally remain with frontend review when they preserve the established experience.
- New cards, badges, screens, and interaction patterns normally need this readiness check.
3. Decide whether the evidence gathered during frontend review settles the direction.
- Frontend maintainer guidance, explicit UI/UX approval, current guidance, an established pattern, or a task that settles the material visual and interaction choices can settle the direction.
- Insufficient or conflicting evidence leaves the direction unresolved.
4. Select exactly one route below and state which frontend-review evidence supports it.
## Routes
- **Frontend review sufficient:** The change preserves the established experience, or the evidence settles the material visual and interaction choices. Cite that evidence and continue with `ha-frontend-review`.
- **UI/UX review recommended:** A new user experience has material design choices that remain unresolved. Identify the decision that needs input and recommend UI/UX review.
- **UI/UX review required:** A workflow rule or direct human instruction explicitly requires UI/UX review. Cite that evidence. A new design, task link, or lack of evidence is not enough on its own.
Frontend maintainer guidance, explicit UI/UX approval, established patterns, and task requirements inform the route. A task can settle requirements without settling the UI/UX. Recommend UI/UX review when important design choices remain unresolved.
## Reporting
Keep the result concise and use this structure:
- **Route:** Frontend review sufficient, UI/UX review recommended, or UI/UX review required
- **Established patterns:** relevant gallery specifications, production designs, and shared `ha-*` components for the next reviewer to compare
- **Supporting evidence:** approval, guidance, established patterns, task requirements, direct instructions, or the evidence gap or conflict
- **Next action:** the review action implied by the route
Separate whether the UI/UX direction is settled from whether the implementation is correct.
+40 -24
View File
@@ -1,36 +1,52 @@
[modern]
# Modern builds target recent browsers supporting the latest features to minimize transpilation, polyfills, etc.
# It is served to browsers meeting the following requirements:
# - released in the last year + current alpha/beta versions
# - Firefox extended support release (ESR)
# - with global utilization at or above 0.5%
# - released in the last 2 years + current alpha/beta versions
# - exclude dead browsers (no security maintenance for 2+ years)
# - exclude KaiOS, QQ, and UC browsers due to lack of sufficient feature support data
# - exclude QQ, and UC browsers due to lack of sufficient feature support data
unreleased versions
last 1 year
Firefox ESR
>= 0.5%
last 2 years
not dead
not KaiOS > 0
not QQAndroid > 0
not UCAndroid > 0
[legacy]
# Legacy builds are served when modern requirements are not met and support browsers:
# - released in the last 7 years + current alpha/beta versionss
# - with global utilization at or above 0.05%
# - exclude dead browsers (no security maintenance for 2+ years)
# - exclude Opera Mini which does not support web sockets
unreleased versions
last 7 years
>= 0.05%
not dead
not op_mini all
# Legacy builds are served when modern requirements are not met.
# Floors are pinned explicitly (not usage-based) so the support policy is
# deliberate and does not drift with global usage statistics, which do not
# represent old tablets and wall displays used as Home Assistant dashboards:
# - iOS/Safari >= 12: iPad Air 1 / mini 2 / mini 3 (last supported iOS).
# Older iPads (iPad 2/3/mini 1 on iOS 9.3, iPad 4 on iOS 10.3) cannot run
# the app: their engines lack custom elements, shadow DOM, and/or CSS grid.
# - Chrome >= 59: Fire OS 5 tablets (Fire 7/HD 8/HD 10 through ~2017) have
# their system WebView pinned at Chromium 59 and commonly run Fully Kiosk;
# also covers old kiosk browsers and no-longer-updating webviews above it.
# - Edge >= 79: all Chromium-based Edge. Costs nothing (above the Chrome
# floor); mainly catches Edge 109 on Windows 7/8.1 and update-frozen
# enterprise installs, whose engines can run the legacy build fine.
# - Firefox >= 94: the zero-cost floor, not a chased population — pinning it
# adds no babel transforms, core-js modules, or Lightning CSS prefixes to
# the output. Mozilla-supported Firefox (incl. current ESR) always matches
# [modern]; Firefox on old OSes is not supported (use Chrome 109 instead).
# If Firefox ever becomes the pin forcing extra output, raise it first.
# - Samsung >= 9: Samsung Internet on old Galaxy tablets
Chrome >= 59
ChromeAndroid >= 59
Edge >= 79
Firefox >= 94
FirefoxAndroid >= 94
iOS >= 12
Safari >= 12
Samsung >= 9
[legacy-sw]
# Same as legacy plus supports service workers
unreleased versions
last 7 years
>= 0.05% and supports serviceworkers
not dead
not op_mini all
# Same as legacy, restricted to browsers that support service workers
# (currently resolves to the same set; guards the service worker build if the legacy floor ever drops below them)
Chrome >= 59 and supports serviceworkers
ChromeAndroid >= 59 and supports serviceworkers
Edge >= 79 and supports serviceworkers
Firefox >= 94 and supports serviceworkers
FirefoxAndroid >= 94 and supports serviceworkers
iOS >= 12 and supports serviceworkers
Safari >= 12 and supports serviceworkers
Samsung >= 9 and supports serviceworkers
+1
View File
@@ -0,0 +1 @@
../.agents/skills
+1 -1
View File
@@ -1,4 +1,4 @@
FROM mcr.microsoft.com/devcontainers/python:1-3.13
FROM mcr.microsoft.com/devcontainers/python:3.14
ENV \
DEBIAN_FRONTEND=noninteractive \
+1 -1
View File
@@ -67,7 +67,7 @@ DO NOT DELETE ANY TEXT from this template! Otherwise, your issue may be closed w
<!--
If your issue is about how an entity is shown in the UI, please add the state
and attributes for all situations with a screenshot of the UI.
You can find this information at `/developer-tools/state`
You can find this information at `/config/tools/state`
-->
```yaml
+17 -2
View File
@@ -7,13 +7,17 @@ body:
value: |
Make sure you are running the [latest version of Home Assistant][releases] before reporting an issue.
Please read our [issue reporting guide][reporting-issues] before submitting a report.
If you have a feature or enhancement request for the frontend, please [start a discussion][fr] instead of creating an issue.
**Please do not report issues for custom cards.**
[fr]: https://github.com/orgs/home-assistant/discussions
[releases]: https://github.com/home-assistant/home-assistant/releases
[reporting-issues]: https://www.home-assistant.io/help/reporting_issues/
- type: checkboxes
id: checklist
attributes:
label: Checklist
description: Please verify that you've followed these steps
@@ -30,18 +34,21 @@ body:
value: |
## The problem
- type: textarea
id: problem
validations:
required: true
attributes:
label: Describe the issue you are experiencing
description: Provide a clear and concise description of what the bug is.
- type: textarea
id: expected_behavior
validations:
required: true
attributes:
label: Describe the behavior you expected
description: Describe what you expected to happen or it should look/behave.
- type: textarea
id: steps_to_reproduce
validations:
required: true
attributes:
@@ -59,6 +66,7 @@ body:
value: |
## Environment
- type: input
id: core_version
validations:
required: true
attributes:
@@ -67,18 +75,21 @@ body:
description: >
Can be found in: [Settings -> About](https://my.home-assistant.io/redirect/info/).
- type: input
id: last_working_version
attributes:
label: What was the last working version of Home Assistant Core?
placeholder: core-
description: >
If known, otherwise leave blank.
- type: input
id: browser
attributes:
label: In which browser are you experiencing the issue?
placeholder: Google Chrome 88.0.4324.150
description: >
Provide the full name and don't forget to add the version!
- type: input
id: os
attributes:
label: Which operating system are you using to run this browser?
placeholder: macOS Big Sur (1.11)
@@ -90,14 +101,16 @@ body:
# Details
- type: textarea
id: entity_state
attributes:
label: State of relevant entities
description: >
If your issue is about how an entity is shown in the UI, please add the
state and attributes for all situations. You can find this information
at Developer Tools -> States.
state and attributes for all situations. You can find this
information in the Details view of the More info dialog.
render: txt
- type: textarea
id: configuration
attributes:
label: Problem-relevant frontend configuration
description: >
@@ -107,6 +120,7 @@ body:
passwords, private URLs and other credentials.
render: yaml
- type: textarea
id: javascript_errors
attributes:
label: JavaScript errors shown in your browser console/inspector
description: >
@@ -114,6 +128,7 @@ body:
browser console/inspector please provide them.
render: txt
- type: textarea
id: additional_information
attributes:
label: Additional information
description: >
+3
View File
@@ -3,6 +3,9 @@ contact_links:
- name: Request a feature for the UI / Dashboards
url: https://github.com/orgs/home-assistant/discussions
about: Request a new feature for the Home Assistant frontend.
- name: Discuss UI or UX design
url: https://github.com/OpenHomeFoundation/ux-design/discussions
about: Share design feedback and discuss visual or UX changes with the design team.
- name: Report a bug that is NOT related to the UI / Dashboards
url: https://github.com/home-assistant/core/issues
about: This is the issue tracker for our frontend. Please report other issues in the backend ("core") repository.
+42 -12
View File
@@ -21,6 +21,14 @@
-->
## Screenshots
<!--
If your PR includes visual changes, please add screenshots or a short video
showing the before and after. This helps reviewers understand the impact of
your changes.
Note: Remove this section if this PR has no visual changes.
-->
## Type of change
<!--
What type of change does your PR introduce to the Home Assistant frontend?
@@ -35,16 +43,6 @@
- [ ] Breaking change (fix/feature causing existing functionality to break)
- [ ] Code quality improvements to existing code or addition of tests
## Example configuration
<!--
Supplying a configuration snippet, makes it easier for a maintainer to test
your PR.
-->
```yaml
```
## Additional information
<!--
Details are important, and help maintainers processing your PR.
@@ -54,6 +52,8 @@
- This PR fixes or closes issue: fixes #
- This PR is related to issue or discussion:
- Link to documentation pull request:
- Link to developer documentation pull request:
- Link to backend pull request:
## Checklist
<!--
@@ -61,18 +61,48 @@
creating the PR. If you're unsure about any of them, don't hesitate to ask.
We're here to help! This is simply a reminder of what we are going to look
for before merging your code.
AI tools are welcome, but contributors are responsible for *fully*
understanding the code before submitting a PR.
-->
- [ ] I understand the code I am submitting and can explain how it works.
- [ ] The code change is tested and works locally.
- [ ] There is no commented out code in this PR.
- [ ] Tests have been added to verify that the new code works.
- [ ] I have followed the [perfect PR recommendations][perfect-pr]
- [ ] Any generated code has been carefully reviewed for correctness and compliance with project standards.
If user exposed functionality or configuration variables are added/changed:
- [ ] Documentation added/updated for [www.home-assistant.io][docs-repository]
<!--
Thank you for contributing <3
This project is very active and we have a high turnover of pull requests.
Unfortunately, the number of incoming pull requests is higher than what our
reviewers can review and merge so there is a long backlog of pull requests
waiting for review. You can help here!
By reviewing another pull request, you will help raise the code quality of
that pull request and the final review will be faster. This way the general
pace of pull request reviews will go up and your wait time will go down.
When picking a pull request to review, try to choose one that hasn't yet
been reviewed.
Thanks for helping out!
-->
To help with the load of incoming pull requests:
- [ ] I have reviewed two other [open pull requests][prs] in this repository.
[prs]: https://github.com/home-assistant/frontend/pulls?q=is%3Aopen+is%3Apr+-author%3A%40me+-draft%3Atrue+sort%3Acreated-desc+review%3Anone+-status%3Afailure
<!--
Thank you for contributing <3
Below, some useful links you could explore:
-->
[docs-repository]: https://github.com/home-assistant/home-assistant.io
[perfect-pr]: https://developers.home-assistant.io/docs/review-process/#creating-the-perfect-pr
+27
View File
@@ -0,0 +1,27 @@
name: Build frontend target
description: Run a gulp build target
inputs:
target:
description: gulp target to run
required: true
github-token:
description: GitHub token for fetching nightly translations; omit to build English-only
default: ""
is-test:
description: Set IS_TEST for the build (skips source maps and compression)
default: "false"
rspack-cache:
description: rspack persistent cache mode ("readwrite", "readonly", or "" to disable)
default: ""
runs:
using: composite
steps:
- name: Build ${{ inputs.target }}
shell: bash
run: ./node_modules/.bin/gulp ${{ inputs.target }}
env:
GITHUB_TOKEN: ${{ inputs.github-token }}
IS_TEST: ${{ inputs.is-test }}
RSPACK_CACHE: ${{ inputs.rspack-cache }}
+52
View File
@@ -0,0 +1,52 @@
name: Deploy to Netlify
description: Deploy a directory to Netlify (production when alias is empty, otherwise to the alias)
inputs:
dir:
description: Directory to deploy
required: true
alias:
description: Deploy alias; leave empty to deploy to production
default: ""
auth-token:
description: NETLIFY_AUTH_TOKEN
required: true
site-id:
description: NETLIFY_SITE_ID
required: true
outputs:
netlify_url:
description: The deployed URL
value: ${{ steps.deploy.outputs.netlify_url }}
unique_deploy_url:
description: The unique hash-based deployment URL for this specific build
value: ${{ steps.deploy.outputs.unique_deploy_url }}
runs:
using: composite
steps:
- name: Deploy to Netlify
id: deploy
shell: bash
env:
DIR: ${{ inputs.dir }}
ALIAS: ${{ inputs.alias }}
NETLIFY_AUTH_TOKEN: ${{ inputs.auth-token }}
NETLIFY_SITE_ID: ${{ inputs.site-id }}
run: |
# Execute the deployment
if [ -n "$ALIAS" ]; then
npx -y netlify-cli deploy --dir="$DIR" --alias "$ALIAS" --json > deploy_output.json
else
npx -y netlify-cli deploy --dir="$DIR" --prod --json > deploy_output.json
fi
# Collect the urls from the deployment output
NETLIFY_URL=$(jq -r '.url // .deploy_url' deploy_output.json)
SITE_NAME=$(jq -r '.site_name' deploy_output.json)
DEPLOY_ID=$(jq -r '.deploy_id' deploy_output.json)
UNIQUE_URL="https://${DEPLOY_ID}--${SITE_NAME}.netlify.app"
echo "netlify_url=$NETLIFY_URL" >> "$GITHUB_OUTPUT"
echo "unique_deploy_url=$UNIQUE_URL" >> "$GITHUB_OUTPUT"
@@ -0,0 +1,41 @@
name: Prepare dependencies
description: Install and cache the complete dependency tree
inputs:
node-modules-cache-key:
description: Prefix for the shared node_modules cache key
default: node-modules-v1
runs:
using: composite
steps:
- name: Check for complete dependency tree
id: dependencies
continue-on-error: true
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
node_modules
~/.local/share/pnpm/store
key: >-
${{ inputs.node-modules-cache-key }}-${{ runner.os }}-${{ runner.arch }}-${{
hashFiles('.nvmrc', 'package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml', 'patches/**') }}
lookup-only: true
- name: Setup Node and install
if: steps.dependencies.outputs.cache-hit != 'true'
uses: ./.github/actions/setup
with:
cache: false
- name: Save complete dependency tree
if: steps.dependencies.outputs.cache-hit != 'true'
continue-on-error: true
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
node_modules
~/.local/share/pnpm/store
key: >-
${{ inputs.node-modules-cache-key }}-${{ runner.os }}-${{ runner.arch }}-${{
hashFiles('.nvmrc', 'package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml', 'patches/**') }}
+62
View File
@@ -0,0 +1,62 @@
name: Setup Node and install
description: Set up Node from .nvmrc and install pnpm dependencies
inputs:
immutable:
description: Pass --frozen-lockfile to pnpm install
default: "true"
cache:
description: Cache the pnpm store
default: "true"
node-modules-cache:
description: Restore the exact shared node_modules cache before installing
default: "false"
node-modules-cache-key:
description: Prefix for the shared node_modules cache key
default: node-modules-v1
runs:
using: composite
steps:
# The pnpm store is cached with node_modules because `pnpm licenses`
# (used by the license file generation) reads package metadata from it.
- name: Restore complete dependency tree
id: dependency-cache
if: inputs.node-modules-cache == 'true'
continue-on-error: true
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
node_modules
~/.local/share/pnpm/store
key: >-
${{ inputs.node-modules-cache-key }}-${{ runner.os }}-${{ runner.arch }}-${{
hashFiles('.nvmrc', 'package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml', 'patches/**') }}
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: ".nvmrc"
- name: Enable Corepack
shell: bash
run: corepack enable
- name: Get pnpm store directory
id: pnpm-store
if: inputs.cache == 'true' && (inputs.node-modules-cache != 'true' || steps.dependency-cache.outputs.cache-hit != 'true')
shell: bash
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
- name: Cache pnpm store
if: steps.pnpm-store.outputs.path
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ${{ steps.pnpm-store.outputs.path }}
key: pnpm-store-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: pnpm-store-${{ runner.os }}-${{ runner.arch }}-
- name: Install dependencies
if: inputs.node-modules-cache != 'true' || steps.dependency-cache.outputs.cache-hit != 'true'
shell: bash
run: pnpm install ${{ inputs.immutable == 'true' && '--frozen-lockfile' || '--no-frozen-lockfile' }}
-596
View File
@@ -1,596 +0,0 @@
# GitHub Copilot & Claude Code Instructions
You are an assistant helping with development of the Home Assistant frontend. The frontend is built using Lit-based Web Components and TypeScript, providing a responsive and performant interface for home automation control.
## Table of Contents
- [Quick Reference](#quick-reference)
- [Core Architecture](#core-architecture)
- [Development Standards](#development-standards)
- [Component Library](#component-library)
- [Common Patterns](#common-patterns)
- [Text and Copy Guidelines](#text-and-copy-guidelines)
- [Development Workflow](#development-workflow)
- [Review Guidelines](#review-guidelines)
## Quick Reference
### Essential Commands
```bash
yarn lint # ESLint + Prettier + TypeScript + Lit
yarn format # Auto-fix ESLint + Prettier
yarn lint:types # TypeScript compiler
yarn test # Vitest
script/develop # Development server
```
### Component Prefixes
- `ha-` - Home Assistant components
- `hui-` - Lovelace UI components
- `dialog-` - Dialog components
### Import Patterns
```typescript
import type { HomeAssistant } from "../types";
import { fireEvent } from "../common/dom/fire_event";
import { showAlertDialog } from "../dialogs/generic/show-alert-dialog";
```
## Core Architecture
The Home Assistant frontend is a modern web application that:
- Uses Web Components (custom elements) built with Lit framework
- Is written entirely in TypeScript with strict type checking
- Communicates with the backend via WebSocket API
- Provides comprehensive theming and internationalization
## Development Standards
### Code Quality Requirements
**Linting and Formatting (Enforced by Tools)**
- ESLint config extends Airbnb, TypeScript strict, Lit, Web Components, Accessibility
- Prettier with ES5 trailing commas enforced
- No console statements (`no-console: "error"`) - use proper logging
- Import organization: No unused imports, consistent type imports
**Naming Conventions**
- PascalCase for types and classes
- camelCase for variables, methods
- Private methods require leading underscore
- Public methods forbid leading underscore
### TypeScript Usage
- **Always use strict TypeScript**: Enable all strict flags, avoid `any` types
- **Proper type imports**: Use `import type` for type-only imports
- **Define interfaces**: Create proper interfaces for data structures
- **Type component properties**: All Lit properties must be properly typed
- **No unused variables**: Prefix with `_` if intentionally unused
- **Consistent imports**: Use `@typescript-eslint/consistent-type-imports`
```typescript
// Good
import type { HomeAssistant } from "../types";
interface EntityConfig {
entity: string;
name?: string;
}
@property({ type: Object })
hass!: HomeAssistant;
// Bad
@property()
hass: any;
```
### Web Components with Lit
- **Use Lit 3.x patterns**: Follow modern Lit practices
- **Extend appropriate base classes**: Use `LitElement`, `SubscribeMixin`, or other mixins as needed
- **Define custom element names**: Use `ha-` prefix for components
```typescript
@customElement("ha-my-component")
export class HaMyComponent extends LitElement {
@property({ attribute: false })
hass!: HomeAssistant;
@state()
private _config?: MyComponentConfig;
static get styles() {
return css`
:host {
display: block;
}
`;
}
render() {
return html`<div>Content</div>`;
}
}
```
### Component Guidelines
- **Use composition**: Prefer composition over inheritance
- **Lazy load panels**: Heavy panels should be dynamically imported
- **Optimize renders**: Use `@state()` for internal state, `@property()` for public API
- **Handle loading states**: Always show appropriate loading indicators
- **Support themes**: Use CSS custom properties from theme
### Data Management
- **Use WebSocket API**: All backend communication via home-assistant-js-websocket
- **Cache appropriately**: Use collections and caching for frequently accessed data
- **Handle errors gracefully**: All API calls should have error handling
- **Update real-time**: Subscribe to state changes for live updates
```typescript
// Good
try {
const result = await fetchEntityRegistry(this.hass.connection);
this._processResult(result);
} catch (err) {
showAlertDialog(this, {
text: `Failed to load: ${err.message}`,
});
}
```
### Styling Guidelines
- **Use CSS custom properties**: Leverage the theme system
- **Mobile-first responsive**: Design for mobile, enhance for desktop
- **Follow Material Design**: Use Material Web Components where appropriate
- **Support RTL**: Ensure all layouts work in RTL languages
```typescript
static get styles() {
return css`
:host {
--spacing: 16px;
padding: var(--spacing);
color: var(--primary-text-color);
background-color: var(--card-background-color);
}
@media (max-width: 600px) {
:host {
--spacing: 8px;
}
}
`;
}
```
### Performance Best Practices
- **Code split**: Split code at the panel/dialog level
- **Lazy load**: Use dynamic imports for heavy components
- **Optimize bundle**: Keep initial bundle size minimal
- **Use virtual scrolling**: For long lists, implement virtual scrolling
- **Memoize computations**: Cache expensive calculations
### Testing Requirements
- **Write tests**: Add tests for data processing and utilities
- **Test with Vitest**: Use the established test framework
- **Mock appropriately**: Mock WebSocket connections and API calls
- **Test accessibility**: Ensure components are accessible
## Component Library
### Dialog Components
**Available Dialog Types:**
- `ha-md-dialog` - Preferred for new code (Material Design 3)
- `ha-dialog` - Legacy component still widely used
**Opening Dialogs (Fire Event Pattern - Recommended):**
```typescript
fireEvent(this, "show-dialog", {
dialogTag: "dialog-example",
dialogImport: () => import("./dialog-example"),
dialogParams: { title: "Example", data: someData },
});
```
**Dialog Implementation Requirements:**
- Implement `HassDialog<T>` interface
- Use `createCloseHeading()` for standard headers
- Import `haStyleDialog` for consistent styling
- Return `nothing` when no params (loading state)
- Fire `dialog-closed` event when closing
- Add `dialogInitialFocus` for accessibility
````
### Form Component (ha-form)
- Schema-driven using `HaFormSchema[]`
- Supports entity, device, area, target, number, boolean, time, action, text, object, select, icon, media, location selectors
- Built-in validation with error display
- Use `dialogInitialFocus` in dialogs
- Use `computeLabel`, `computeError`, `computeHelper` for translations
```typescript
<ha-form
.hass=${this.hass}
.data=${this._data}
.schema=${this._schema}
.error=${this._errors}
.computeLabel=${(schema) => this.hass.localize(`ui.panel.${schema.name}`)}
@value-changed=${this._valueChanged}
></ha-form>
````
### Alert Component (ha-alert)
- Types: `error`, `warning`, `info`, `success`
- Properties: `title`, `alert-type`, `dismissable`, `icon`, `action`, `rtl`
- Content announced by screen readers when dynamically displayed
```html
<ha-alert alert-type="error">Error message</ha-alert>
<ha-alert alert-type="warning" title="Warning">Description</ha-alert>
<ha-alert alert-type="success" dismissable>Success message</ha-alert>
```
## Common Patterns
### Creating a Panel
```typescript
@customElement("ha-panel-myfeature")
export class HaPanelMyFeature extends SubscribeMixin(LitElement) {
@property({ attribute: false })
hass!: HomeAssistant;
@property({ type: Boolean, reflect: true })
narrow!: boolean;
@property()
route!: Route;
hassSubscribe() {
return [
subscribeEntityRegistry(this.hass.connection, (entities) => {
this._entities = entities;
}),
];
}
}
```
### Creating a Dialog
```typescript
@customElement("dialog-my-feature")
export class DialogMyFeature
extends LitElement
implements HassDialog<MyDialogParams>
{
@property({ attribute: false })
hass!: HomeAssistant;
@state()
private _params?: MyDialogParams;
public async showDialog(params: MyDialogParams): Promise<void> {
this._params = params;
}
public closeDialog(): void {
this._params = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
protected render() {
if (!this._params) {
return nothing;
}
return html`
<ha-dialog
open
@closed=${this.closeDialog}
.heading=${createCloseHeading(this.hass, this._params.title)}
>
<!-- Dialog content -->
<ha-button
appearance="plain"
@click=${this.closeDialog}
slot="secondaryAction"
>
${this.hass.localize("ui.common.cancel")}
</ha-button>
<ha-button @click=${this._submit} slot="primaryAction">
${this.hass.localize("ui.common.save")}
</ha-button>
</ha-dialog>
`;
}
static styles = [haStyleDialog, css``];
}
```
### Dialog Design Guidelines
- Max width: 560px (Alert/confirmation: 320px fixed width)
- Close X-icon on top left (all screen sizes)
- Submit button grouped with cancel at bottom right
- Keep button labels short: "Save", "Delete", "Enable"
- Destructive actions use red warning button
- Always use a title (best practice)
- Strive for minimalism
#### Creating a Lovelace Card
**Purpose**: Cards allow users to tell different stories about their house (based on gallery)
```typescript
@customElement("hui-my-card")
export class HuiMyCard extends LitElement implements LovelaceCard {
@property({ attribute: false })
hass!: HomeAssistant;
@state()
private _config?: MyCardConfig;
public setConfig(config: MyCardConfig): void {
if (!config.entity) {
throw new Error("Entity required");
}
this._config = config;
}
public getCardSize(): number {
return 3; // Height in grid units
}
// Optional: Editor for card configuration
public static getConfigElement(): LovelaceCardEditor {
return document.createElement("hui-my-card-editor");
}
// Optional: Stub config for card picker
public static getStubConfig(): object {
return { entity: "" };
}
}
```
**Card Guidelines:**
- Cards are highly customizable for different households
- Implement `LovelaceCard` interface with `setConfig()` and `getCardSize()`
- Use proper error handling in `setConfig()`
- Consider all possible states (loading, error, unavailable)
- Support different entity types and states
- Follow responsive design principles
- Add configuration editor when needed
### Internationalization
- **Use localize**: Always use the localization system
- **Add translation keys**: Add keys to src/translations/en.json
- **Support placeholders**: Use proper placeholder syntax
```typescript
this.hass.localize("ui.panel.config.updates.update_available", {
count: 5,
});
```
### Accessibility
- **ARIA labels**: Add appropriate ARIA labels
- **Keyboard navigation**: Ensure all interactions work with keyboard
- **Screen reader support**: Test with screen readers
- **Color contrast**: Meet WCAG AA standards
## Development Workflow
### Setup and Commands
1. **Setup**: `script/setup` - Install dependencies
2. **Develop**: `script/develop` - Development server
3. **Lint**: `yarn lint` - Run all linting before committing
4. **Test**: `yarn test` - Add and run tests
5. **Build**: `script/build_frontend` - Test production build
### Common Pitfalls to Avoid
- Don't use `querySelector` - Use refs or component properties
- Don't manipulate DOM directly - Let Lit handle rendering
- Don't use global styles - Scope styles to components
- Don't block the main thread - Use web workers for heavy computation
- Don't ignore TypeScript errors - Fix all type issues
### Security Best Practices
- Sanitize HTML - Never use `unsafeHTML` with user content
- Validate inputs - Always validate user inputs
- Use HTTPS - All external resources must use HTTPS
- CSP compliance - Ensure code works with Content Security Policy
### Text and Copy Guidelines
#### Terminology Standards
**Delete vs Remove** (Based on gallery/src/pages/Text/remove-delete-add-create.markdown)
- **Use "Remove"** for actions that can be restored or reapplied:
- Removing a user's permission
- Removing a user from a group
- Removing links between items
- Removing a widget from dashboard
- Removing an item from a cart
- **Use "Delete"** for permanent, non-recoverable actions:
- Deleting a field
- Deleting a value in a field
- Deleting a task
- Deleting a group
- Deleting a permission
- Deleting a calendar event
**Create vs Add** (Create pairs with Delete, Add pairs with Remove)
- **Use "Add"** for already-existing items:
- Adding a permission to a user
- Adding a user to a group
- Adding links between items
- Adding a widget to dashboard
- Adding an item to a cart
- **Use "Create"** for something made from scratch:
- Creating a new field
- Creating a new task
- Creating a new group
- Creating a new permission
- Creating a new calendar event
#### Writing Style (Consistent with Home Assistant Documentation)
- **Use American English**: Standard spelling and terminology
- **Friendly, informational tone**: Be inspiring, personal, comforting, engaging
- **Address users directly**: Use "you" and "your"
- **Be inclusive**: Objective, non-discriminatory language
- **Be concise**: Use clear, direct language
- **Be consistent**: Follow established terminology patterns
- **Use active voice**: "Delete the automation" not "The automation should be deleted"
- **Avoid jargon**: Use terms familiar to home automation users
#### Language Standards
- **Always use "Home Assistant"** in full, never "HA" or "HASS"
- **Avoid abbreviations**: Spell out terms when possible
- **Use sentence case everywhere**: Titles, headings, buttons, labels, UI elements
- ✅ "Create new automation"
- ❌ "Create New Automation"
- ✅ "Device settings"
- ❌ "Device Settings"
- **Oxford comma**: Use in lists (item 1, item 2, and item 3)
- **Replace Latin terms**: Use "like" instead of "e.g.", "for example" instead of "i.e."
- **Avoid CAPS for emphasis**: Use bold or italics instead
- **Write for all skill levels**: Both technical and non-technical users
#### Key Terminology
- **"add-on"** (hyphenated, not "addon")
- **"integration"** (preferred over "component")
- **Technical terms**: Use lowercase (automation, entity, device, service)
#### Translation Considerations
- **Add translation keys**: All user-facing text must be translatable
- **Use placeholders**: Support dynamic content in translations
- **Keep context**: Provide enough context for translators
```typescript
// Good
this.hass.localize("ui.panel.config.automation.delete_confirm", {
name: automation.alias,
});
// Bad - hardcoded text
("Are you sure you want to delete this automation?");
```
### Common Review Issues (From PR Analysis)
#### User Experience and Accessibility
- **Form validation**: Always provide proper field labels and validation feedback
- **Form accessibility**: Prevent password managers from incorrectly identifying fields
- **Loading states**: Show clear progress indicators during async operations
- **Error handling**: Display meaningful error messages when operations fail
- **Mobile responsiveness**: Ensure components work well on small screens
- **Hit targets**: Make clickable areas large enough for touch interaction
- **Visual feedback**: Provide clear indication of interactive states
#### Dialog and Modal Patterns
- **Dialog width constraints**: Respect minimum and maximum width requirements
- **Interview progress**: Show clear progress for multi-step operations
- **State persistence**: Handle dialog state properly during background operations
- **Cancel behavior**: Ensure cancel/close buttons work consistently
- **Form prefilling**: Use smart defaults but allow user override
#### Component Design Patterns
- **Terminology consistency**: Use "Join"/"Apply" instead of "Group" when appropriate
- **Visual hierarchy**: Ensure proper font sizes and spacing ratios
- **Grid alignment**: Components should align to the design grid system
- **Badge placement**: Position badges and indicators consistently
- **Color theming**: Respect theme variables and design system colors
#### Code Quality Issues
- **Null checking**: Always check if entities exist before accessing properties
- **TypeScript safety**: Handle potentially undefined array/object access
- **Import organization**: Remove unused imports and use proper type imports
- **Event handling**: Properly subscribe and unsubscribe from events
- **Memory leaks**: Clean up subscriptions and event listeners
#### Configuration and Props
- **Optional parameters**: Make configuration fields optional when sensible
- **Smart defaults**: Provide reasonable default values
- **Future extensibility**: Design APIs that can be extended later
- **Validation**: Validate configuration before applying changes
## Review Guidelines
### Core Requirements Checklist
- [ ] TypeScript strict mode passes (`yarn lint:types`)
- [ ] No ESLint errors or warnings (`yarn lint:eslint`)
- [ ] Prettier formatting applied (`yarn lint:prettier`)
- [ ] Lit analyzer passes (`yarn lint:lit`)
- [ ] Component follows Lit best practices
- [ ] Proper error handling implemented
- [ ] Loading states handled
- [ ] Mobile responsive
- [ ] Theme variables used
- [ ] Translations added
- [ ] Accessible to screen readers
- [ ] Tests added (where applicable)
- [ ] No console statements (use proper logging)
- [ ] Unused imports removed
- [ ] Proper naming conventions
### Text and Copy Checklist
- [ ] Follows terminology guidelines (Delete vs Remove, Create vs Add)
- [ ] Localization keys added for all user-facing text
- [ ] Uses "Home Assistant" (never "HA" or "HASS")
- [ ] Sentence case for ALL text (titles, headings, buttons, labels)
- [ ] American English spelling
- [ ] Friendly, informational tone
- [ ] Avoids abbreviations and jargon
- [ ] Correct terminology (add-on not addon, integration not component)
### Component-Specific Checks
- [ ] Dialogs implement HassDialog interface
- [ ] Dialog styling uses haStyleDialog
- [ ] Dialog accessibility includes dialogInitialFocus
- [ ] ha-alert used correctly for messages
- [ ] ha-form uses proper schema structure
- [ ] Components handle all states (loading, error, unavailable)
- [ ] Entity existence checked before property access
- [ ] Event subscriptions properly cleaned up
+1
View File
@@ -0,0 +1 @@
../AGENTS.md
-11
View File
@@ -1,11 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: weekly
time: "06:00"
open-pull-requests-limit: 10
labels:
- Dependencies
- GitHub Actions
+49 -5
View File
@@ -1,3 +1,21 @@
Agents:
- changed-files:
- any-glob-to-any-file:
- "**/AGENTS.md"
- "**/CLAUDE.md"
- "**/GEMINI.md"
- .agents/**
- .claude/**
- .github/agents/**
- .github/copilot-instructions.md
- .github/hooks/**
- .github/instructions/**
- .github/plugin.json
- .github/plugin/**
- .github/prompts/**
- .github/skills/**
- .github/workflows/copilot-setup-steps.yml
Build:
- changed-files:
- any-glob-to-any-file:
@@ -30,9 +48,9 @@ Dependencies:
- any-glob-to-all-files:
- package.json
- renovate.json
- yarn.lock
- .yarn/**
- .yarnrc.yml
- pnpm-lock.yaml
- pnpm-workspace.yaml
- patches/**
- .nvmrc
# Dependabot and Renovate branches always match (i.e. compatibility tweaks by members considered minor)
- head-branch:
@@ -42,10 +60,36 @@ Dependencies:
GitHub Actions:
- changed-files:
- any-glob-to-any-file:
- .github/actions/**
- .github/workflows/**
- .github/*.yml
Supervisor:
"Tests: E2E":
- changed-files:
- any-glob-to-any-file:
- hassio/src/**
- test/e2e/**
"Tests: App":
- changed-files:
- any-glob-to-any-file:
- test/e2e/app.spec.ts
- test/e2e/app/**
- test/e2e/playwright.app.config.ts
"Tests: Demo":
- changed-files:
- any-glob-to-any-file:
- test/e2e/demo.spec.ts
- test/e2e/playwright.demo.config.ts
"Tests: Design":
- changed-files:
- any-glob-to-any-file:
- test/e2e/gallery.spec.ts
- test/e2e/playwright.gallery.config.ts
"Tests: Unit":
- changed-files:
- any-glob-to-any-file:
- test/*.ts
- "test/!(e2e)/**"
+289
View File
@@ -0,0 +1,289 @@
#!/usr/bin/env node
// Checks npm registry metadata for the direct dependencies in package.json:
// deprecation, source repository and provenance. On pull requests only newly
// added packages are checked, and a deprecated one fails the check. Scheduled
// and manual runs report on every direct dependency without failing. Invoked
// from the `npm-metadata` job in .github/workflows/dependency-review.yaml via
// actions/github-script:
//
// const { default: checkNpmMetadata } =
// await import(`${process.env.GITHUB_WORKSPACE}/.github/scripts/check-npm-metadata.mts`);
// await checkNpmMetadata({ github, context, core });
import type { Octokit } from "@octokit/rest";
import type {
Context,
Core,
GitHubScriptArgs,
PullRequestPayload,
} from "./github-script.d.ts";
import { withRetry } from "./github-retry.mts";
// Scheduled and manual runs have no pull request
type Payload = Partial<PullRequestPayload>;
type Section =
| "dependencies"
| "devDependencies"
| "optionalDependencies"
| "peerDependencies";
type PackageJson = Partial<Record<Section, Record<string, string>>>;
interface Dependency {
name: string;
// The package npm installs, which differs from name for npm: aliases
registryName: string;
version: string;
section: Section;
}
// The fields read from a version document on registry.npmjs.org
interface NpmManifest {
deprecated?: string;
repository?: string | { url?: string };
dist?: { attestations?: object };
}
interface Result {
name: string;
version: string;
section: Section;
skipped?: string;
deprecated?: string;
repository?: string;
provenance?: boolean;
}
const SECTIONS: Section[] = [
"dependencies",
"devDependencies",
"optionalDependencies",
"peerDependencies",
];
const EXACT_VERSION = /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/;
const NPM_ALIAS = /^npm:((?:@[^/]+\/)?[^@]+)@(.+)$/;
const CONCURRENCY = 8;
// Returns undefined when the registry reports 404, and throws on any other
// failure so a registry outage fails the job instead of skipping the check.
const fetchJson = async <T,>(url: string): Promise<T | undefined> => {
const response = await fetch(url);
if (response.status === 404) {
return undefined;
}
if (!response.ok) {
throw new Error(
`Request to ${url} failed: ${response.status} ${response.statusText}`
);
}
return JSON.parse(await response.text());
};
const readPackageJson = async (
github: Octokit,
context: Context<Payload>,
ref: string
): Promise<PackageJson> => {
const { data } = await withRetry(`package.json lookup at ${ref}`, () =>
github.rest.repos.getContent({
...context.repo,
path: "package.json",
ref,
mediaType: { format: "raw" },
})
);
// The raw media type returns the file contents as a string, but Octokit
// types the response as the JSON form
if (typeof data !== "string") {
throw new Error("Expected raw package.json contents");
}
return JSON.parse(data);
};
const listDependencies = (pkg: PackageJson): Dependency[] =>
SECTIONS.flatMap((section) =>
Object.entries(pkg[section] ?? {}).map(([name, spec]) => {
// npm: aliases install another package, e.g. npm:[email protected]
const alias = spec.match(NPM_ALIAS);
return {
name,
registryName: alias?.[1] ?? name,
version: alias?.[2] ?? spec,
section,
};
})
);
const repositoryUrl = (repository: NpmManifest["repository"]) => {
const url = typeof repository === "string" ? repository : repository?.url;
return url?.replace(/^git\+/, "").replace(/\.git$/, "");
};
const checkPackage = async ({
name,
registryName,
version,
section,
}: Dependency): Promise<Result> => {
const result = {
name: registryName === name ? name : `${name} (npm:${registryName})`,
version,
section,
};
if (!EXACT_VERSION.test(version)) {
return { ...result, skipped: "not an exact version" };
}
const manifest = await fetchJson<NpmManifest>(
`https://registry.npmjs.org/${encodeURIComponent(registryName)}/${version}`
);
if (!manifest) {
return { ...result, skipped: "not found on the npm registry" };
}
return {
...result,
deprecated: manifest.deprecated,
repository: repositoryUrl(manifest.repository),
provenance: Boolean(manifest.dist?.attestations),
};
};
const checkAll = async (dependencies: Dependency[]) => {
const results: Result[] = [];
for (let i = 0; i < dependencies.length; i += CONCURRENCY) {
results.push(
// eslint-disable-next-line no-await-in-loop
...(await Promise.all(
dependencies.slice(i, i + CONCURRENCY).map(checkPackage)
))
);
}
return results;
};
const writeSummary = async (core: Core, heading: string, results: Result[]) => {
await core.summary
.addHeading(heading, 2)
.addTable([
[
"Package",
"Version",
"Section",
"Deprecated",
"Provenance",
"Repository",
].map((data) => ({ data, header: true })),
...results.map((result) =>
result.skipped
? [
result.name,
result.version,
result.section,
`skipped: ${result.skipped}`,
"-",
"-",
]
: [
result.name,
result.version,
result.section,
result.deprecated ? "yes" : "no",
result.provenance ? "yes" : "no",
result.repository ?? "none",
]
),
])
.write();
};
export default async function checkNpmMetadata({
github,
context,
core,
}: GitHubScriptArgs<Payload>) {
const pr = context.payload.pull_request;
if (!pr) {
const pkg = await readPackageJson(github, context, context.sha);
const results = await checkAll(listDependencies(pkg));
const flagged = (result: Result) =>
Number(
Boolean(result.skipped || result.deprecated || !result.repository)
);
results.sort(
(a, b) => flagged(b) - flagged(a) || a.name.localeCompare(b.name)
);
await writeSummary(core, "Direct dependencies", results);
return;
}
const [base, head] = await Promise.all([
readPackageJson(github, context, pr.base.sha),
readPackageJson(github, context, pr.head.sha),
]);
// Compare the packages npm installs, so pointing an npm: alias at another
// package counts as new, but moving a package between sections does not
const existing = new Set(
listDependencies(base).map(({ registryName }) => registryName)
);
const added = listDependencies(head).filter(
({ registryName }) => !existing.has(registryName)
);
if (added.length === 0) {
core.info("No new dependencies");
return;
}
const results = await checkAll(added);
const annotation = { file: "package.json" };
for (const result of results) {
const label = `${result.name}@${result.version}`;
if (result.skipped) {
core.warning(`${label}: ${result.skipped}, not checked`, annotation);
continue;
}
if (result.deprecated) {
core.error(`${label} is deprecated: ${result.deprecated}`, annotation);
}
if (!result.repository) {
core.warning(`${label} has no source repository`, annotation);
}
if (!result.provenance) {
core.notice(`${label} was published without provenance`, annotation);
}
}
await writeSummary(core, "New dependencies", results);
if (results.some((result) => result.deprecated)) {
core.setFailed("New dependencies must not be deprecated on npm");
}
}
@@ -0,0 +1,220 @@
#!/usr/bin/env node
// Checks that a pull request follows the contribution standards: it must use the
// PR template, tick exactly one "Type of change" option, and describe the change.
// Labels and comments the PR when it does not, and fails the check so it blocks
// merging. Invoked from the `check` job in .github/workflows/pull-request-standards.yaml
// via actions/github-script:
//
// const { default: checkStandards } =
// await import(`${process.env.GITHUB_WORKSPACE}/.github/scripts/check-pull-request-standards.mts`);
// await checkStandards({ github, context, core });
import type {
GitHubScriptArgs,
PullRequestPayload,
} from "./github-script.d.ts";
import { withRetry } from "./github-retry.mts";
export default async function checkPullRequestStandards({
github,
context,
core,
}: GitHubScriptArgs<PullRequestPayload>) {
const pr = context.payload.pull_request;
// Exempt bots (Copilot agent, dependabot), drafts, and maintainers.
if (pr.user.type === "Bot") {
core.info(`Skipping bot author: ${pr.user.login}`);
return;
}
if (pr.draft) {
core.info("Skipping draft pull request");
return;
}
try {
await withRetry("organization membership check", () =>
github.rest.orgs.checkMembershipForUser({
org: "home-assistant",
username: pr.user.login,
})
);
core.info(`Skipping organization member: ${pr.user.login}`);
return;
} catch (_error) {
core.info(
`${pr.user.login} is not an organization member, checking standards`
);
}
const label = "Needs Template";
const marker = "<!-- pr-standards-check -->";
const { owner, repo } = context.repo;
const issue_number = pr.number;
let body = pr.body || "";
let previous;
do {
previous = body;
body = body.replace(/<!--[\s\S]*?-->/g, "");
} while (body !== previous);
const normalized = body.toLowerCase();
// Ignore 404s from mutations that race manual edits or cancelled runs.
const ignoreMissing = async <T,>(fn: () => Promise<T>) => {
try {
await fn();
} catch (error) {
if (
typeof error === "object" &&
error !== null &&
"status" in error &&
error.status === 404
) {
core.info("Target already removed, nothing to do");
return;
}
throw error;
}
};
// Hide/restore our comment via GraphQL (REST cannot minimize).
const setMinimized = async (subjectId: string, minimized: boolean) => {
const mutation = minimized
? `mutation($id: ID!) {
minimizeComment(input: { subjectId: $id, classifier: RESOLVED }) {
clientMutationId
}
}`
: `mutation($id: ID!) {
unminimizeComment(input: { subjectId: $id }) {
clientMutationId
}
}`;
try {
await withRetry(`comment ${minimized ? "minimize" : "restore"}`, () =>
github.graphql(mutation, { id: subjectId })
);
} catch (error) {
core.info(
`Could not ${minimized ? "minimize" : "restore"} comment: ${error instanceof Error ? error.message : error}`
);
}
};
// Content of a "## <name>" section, or null when the heading is absent.
const section = (name: string) => {
const match = body.match(
new RegExp(`##\\s${name}([\\s\\S]*?)(?=\\n##\\s|$)`, "i")
);
return match ? match[1] : null;
};
const problems = [];
const requiredHeadings = [
"## proposed change",
"## type of change",
"## checklist",
];
if (requiredHeadings.some((h) => !normalized.includes(h))) {
problems.push(
"Use the pull request template without removing its sections."
);
}
const typeOfChange = section("type of change");
if (typeOfChange !== null) {
const ticked = (typeOfChange.match(/-\s*\[[xX]\]/g) || []).length;
if (ticked !== 1) {
problems.push('Select exactly one option under "Type of change".');
}
}
const proposedChange = section("proposed change");
if (proposedChange !== null && proposedChange.trim().length === 0) {
problems.push('Describe your changes under "Proposed change".');
}
const isValid = problems.length === 0;
const comments = await withRetry("comment list", () =>
github.paginate(github.rest.issues.listComments, {
owner,
repo,
issue_number,
per_page: 100,
})
);
const existing = comments.find((c) => c.body?.includes(marker));
const hasLabel = pr.labels.some((l) => l.name === label);
if (isValid) {
core.info("Pull request standards met");
if (hasLabel) {
await ignoreMissing(() =>
withRetry("label removal", () =>
github.rest.issues.removeLabel({
owner,
repo,
issue_number,
name: label,
})
)
);
}
if (existing) {
await setMinimized(existing.node_id, true);
}
return;
}
core.info(`Pull request standards not met:\n- ${problems.join("\n- ")}`);
if (!hasLabel) {
await withRetry("label addition", () =>
github.rest.issues.addLabels({
owner,
repo,
issue_number,
labels: [label],
})
);
}
const message =
`${marker}\n` +
`Hey @${pr.user.login}!\n\n` +
`Thank you for your contribution! To help reviewers, please update ` +
`this pull request to follow our pull request standards:\n\n` +
problems.map((p) => `- ${p}`).join("\n") +
`\n\n` +
`Please complete the ` +
`[PR template](https://github.com/home-assistant/frontend/blob/dev/.github/PULL_REQUEST_TEMPLATE.md?plain=1) ` +
`and see the [developer docs](https://developers.home-assistant.io/docs/review-process) ` +
`for more on creating a great pull request (see point 6).`;
if (existing) {
await withRetry("comment update", () =>
github.rest.issues.updateComment({
owner,
repo,
comment_id: existing.id,
body: message,
})
);
await setMinimized(existing.node_id, false);
} else {
// Not retried, as a retry after GitHub created the comment would post it twice
await github.rest.issues.createComment({
owner,
repo,
issue_number,
body: message,
});
}
// Fail this check so it can block the PR from being merged
core.setFailed(`Pull request standards not met:\n- ${problems.join("\n- ")}`);
}
@@ -0,0 +1,68 @@
#!/usr/bin/env node
// Restricts Task issues to organization members: closes and labels the issue with
// an explanatory comment when the author is not an org member. Invoked from the
// `check-authorization` job in .github/workflows/restrict-task-creation.yaml via
// actions/github-script:
//
// const { default: checkTaskAuthorization } =
// await import(`${process.env.GITHUB_WORKSPACE}/.github/scripts/check-task-authorization.mts`);
// await checkTaskAuthorization({ github, context, core });
import type { GitHubScriptArgs, IssuePayload } from "./github-script.d.ts";
import { withRetry } from "./github-retry.mts";
export default async function checkTaskAuthorization({
github,
context,
core,
}: GitHubScriptArgs<IssuePayload>) {
const issueAuthor = context.payload.issue.user.login;
// Check if user is an organization member
try {
await withRetry("organization membership check", () =>
github.rest.orgs.checkMembershipForUser({
org: "home-assistant",
username: issueAuthor,
})
);
core.info(`✅ ${issueAuthor} is an organization member`);
return; // Authorized
} catch (_error) {
core.info(`❌ ${issueAuthor} is not authorized to create Task issues`);
}
// Close the issue with a comment. Not retried, as a retry after GitHub
// created the comment would post it twice.
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body:
`Hi @${issueAuthor}, thank you for your contribution!\n\n` +
`Task issues are restricted to Open Home Foundation staff and authorized contributors.\n\n` +
`If you would like to:\n` +
`- Report a bug: Please use the [bug report form](https://github.com/home-assistant/frontend/issues/new?template=bug_report.yml)\n` +
`- Request a feature: Please submit to [Feature Requests](https://github.com/orgs/home-assistant/discussions)\n\n` +
`If you believe you should have access to create Task issues, please contact the maintainers.`,
});
await withRetry("issue close", () =>
github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
state: "closed",
})
);
// Add a label to indicate this was auto-closed
await withRetry("auto-closed label", () =>
github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: ["auto-closed"],
})
);
}
+69
View File
@@ -0,0 +1,69 @@
// Retries GitHub API requests with jittered exponential backoff. Shared by the
// workflow scripts in this directory, test/e2e/post-report-comment.mjs and the
// fetch-nightly-translations gulp task. Only wrap requests that are safe to
// repeat: a create that fails after GitHub has applied it would run twice.
//
// This replaces @octokit/plugin-retry, which only retries HTTP error statuses
// on a fixed 1s, 4s, 9s delay with no jitter or logging. GitHub can also
// answer 200 with briefly stale data, such as the nightly translations lookup
// returning an old run with no artifact, and the plugin cannot retry that.
// github-script also leaves its built-in retries off by default.
const RETRIES = 3;
const BASE_DELAY = 1000; // ms
const MAX_DELAY = 10000; // ms
const TRANSIENT_STATUSES = new Set([408, 429, 500, 502, 503, 504]);
// Throw from a request to retry a response GitHub may answer differently on
// the next attempt, such as briefly stale data
export class RetryableError extends Error {}
// Octokit reports network failures as status 500
const isRetryable = (err: unknown) => {
if (err instanceof RetryableError) {
return true;
}
if (!(err instanceof Error) || !("status" in err)) {
return false;
}
const status = Number(err.status);
return (
TRANSIENT_STATUSES.has(status) ||
(status === 403 && /rate limit/i.test(err.message))
);
};
export async function withRetry<T>(
label: string,
request: () => Promise<T>
): Promise<T> {
for (let attempt = 1; ; attempt++) {
try {
// eslint-disable-next-line no-await-in-loop
return await request();
} catch (err) {
if (attempt > RETRIES || !isRetryable(err)) {
throw err;
}
const delay =
Math.min(BASE_DELAY * 2 ** (attempt - 1), MAX_DELAY) *
(0.8 + Math.random() * 0.4);
// eslint-disable-next-line no-console
console.log(
`Retrying ${label} after ${(delay / 1000).toFixed(1)}s (attempt ${attempt}/${RETRIES}): ${err instanceof Error ? err.message : err}`
);
// eslint-disable-next-line no-await-in-loop
await new Promise((resolve) => {
setTimeout(resolve, delay);
});
}
}
}
+61
View File
@@ -0,0 +1,61 @@
// The arguments actions/github-script passes to the scripts in this directory,
// limited to the parts they use.
import type { Octokit } from "@octokit/rest";
export type SummaryTableCell = string | { data: string; header?: boolean };
export interface Summary {
addHeading(text: string, level?: number): Summary;
addRaw(text: string): Summary;
addTable(rows: SummaryTableCell[][]): Summary;
write(): Promise<Summary>;
}
export interface AnnotationProperties {
file?: string;
}
export interface Core {
info(message: string): void;
notice(message: string, properties?: AnnotationProperties): void;
warning(message: string, properties?: AnnotationProperties): void;
error(message: string, properties?: AnnotationProperties): void;
setFailed(message: string): void;
summary: Summary;
}
export interface User {
login: string;
type: string;
}
export interface PullRequestPayload {
pull_request: {
number: number;
body: string | null;
draft: boolean;
user: User;
labels: { name: string }[];
base: { sha: string };
head: { sha: string };
};
}
export interface IssuePayload {
issue: {
user: User;
};
}
export interface Context<Payload> {
sha: string;
repo: { owner: string; repo: string };
issue: { owner: string; repo: string; number: number };
payload: Payload;
}
export interface GitHubScriptArgs<Payload> {
github: Octokit;
context: Context<Payload>;
core: Core;
}
+19
View File
@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "ES2024",
"lib": ["ES2024"],
"module": "NodeNext",
"moduleResolution": "NodeNext",
// actions/github-script imports these directly, relying on Node's type stripping
"erasableSyntaxOnly": true,
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"skipLibCheck": true,
"types": ["node"]
},
"include": ["*.mts", "*.d.ts"]
}
+42
View File
@@ -0,0 +1,42 @@
name: Lint workflow files
on:
push:
branches:
- dev
- master
paths:
- ".github/actions/**"
- ".github/workflows/**"
pull_request:
branches:
- dev
- master
paths:
- ".github/actions/**"
- ".github/workflows/**"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
actionlint:
name: Check workflow files
runs-on: ubuntu-latest
env:
# renovate: datasource=github-releases depName=rhysd/actionlint
ACTIONLINT_VERSION: 1.7.12
steps:
- name: Check out files from GitHub
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Run actionlint
run: |
curl -sSfL "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz" \
| tar -xz actionlint
./actionlint -color
+34 -38
View File
@@ -8,6 +8,9 @@ on:
branches:
- master
permissions:
contents: read
env:
NODE_OPTIONS: --max_old_space_size=6144
@@ -15,69 +18,62 @@ jobs:
deploy_dev:
runs-on: ubuntu-latest
name: Deploy Development
if: github.event_name != 'push'
if: github.repository == 'home-assistant/frontend' && github.event_name != 'push'
environment:
name: Cast Development
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
url: ${{ steps.deploy.outputs.netlify_url }}
steps:
- name: Check out files from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: dev
persist-credentials: false
- name: Setup Node
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version-file: ".nvmrc"
cache: yarn
- name: Install dependencies
run: yarn install --immutable
- name: Setup Node and install
uses: ./.github/actions/setup
- name: Build Cast
run: ./node_modules/.bin/gulp build-cast
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
uses: ./.github/actions/build
with:
target: build-cast
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy to Netlify
id: deploy
run: |
npx -y [email protected] deploy --dir=cast/dist --alias dev
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_CAST_SITE_ID }}
uses: ./.github/actions/netlify-deploy
with:
dir: cast/dist
alias: dev
auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }}
site-id: ${{ secrets.NETLIFY_CAST_SITE_ID }}
deploy_master:
runs-on: ubuntu-latest
name: Deploy Production
if: github.event_name == 'push'
if: github.repository == 'home-assistant/frontend' && github.event_name == 'push'
environment:
name: Cast Production
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
url: ${{ steps.deploy.outputs.netlify_url }}
steps:
- name: Check out files from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: master
persist-credentials: false
- name: Setup Node
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version-file: ".nvmrc"
cache: yarn
- name: Install dependencies
run: yarn install --immutable
- name: Setup Node and install
uses: ./.github/actions/setup
- name: Build Cast
run: ./node_modules/.bin/gulp build-cast
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
uses: ./.github/actions/build
with:
target: build-cast
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy to Netlify
id: deploy
run: |
npx -y [email protected] deploy --dir=cast/dist --prod
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_CAST_SITE_ID }}
uses: ./.github/actions/netlify-deploy
with:
dir: cast/dist
auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }}
site-id: ${{ secrets.NETLIFY_CAST_SITE_ID }}
+88 -58
View File
@@ -1,6 +1,7 @@
name: CI
on:
workflow_dispatch:
push:
branches:
- dev
@@ -12,32 +13,48 @@ on:
env:
NODE_OPTIONS: --max_old_space_size=6144
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
lint:
name: Lint and check format
prepare-dependencies:
name: Prepare dependencies
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Node
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
node-version-file: ".nvmrc"
cache: yarn
- name: Install dependencies
run: yarn install --immutable
persist-credentials: false
- name: Prepare dependencies
uses: ./.github/actions/prepare-dependencies
lint:
name: Lint and check format
needs: prepare-dependencies
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Node with shared dependencies
uses: ./.github/actions/setup
with:
node-modules-cache: true
- name: Check for duplicate dependencies
run: yarn dedupe --check
run: pnpm dedupe --check
- name: Build resources
id: build_resources
run: ./node_modules/.bin/gulp gen-icons-json build-translations build-locale-data gather-gallery-pages
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Setup lint cache
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
node_modules/.cache/prettier
@@ -46,75 +63,88 @@ jobs:
key: lint-${{ github.sha }}
restore-keys: lint-
- name: Run eslint
run: yarn run lint:eslint --quiet
run: pnpm run lint:eslint --quiet
- name: Run tsc
run: yarn run lint:types
if: ${{ !cancelled() && steps.build_resources.outcome == 'success' }}
run: pnpm run lint:types
- name: Run lit-analyzer
run: yarn run lint:lit --quiet
if: ${{ !cancelled() && steps.build_resources.outcome == 'success' }}
run: pnpm run lint:lit --quiet
- name: Run prettier
run: yarn run lint:prettier
if: ${{ !cancelled() && steps.build_resources.outcome == 'success' }}
run: pnpm run lint:prettier
- name: Check dependency licenses
if: ${{ !cancelled() && steps.build_resources.outcome == 'success' }}
run: pnpm run lint:licenses
- name: Check the bundled map sprite sheet
if: ${{ !cancelled() }}
run: ./node_modules/.bin/gulp check-map-sprites
test:
name: Run tests
needs: prepare-dependencies
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Node
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
node-version-file: ".nvmrc"
cache: yarn
- name: Install dependencies
run: yarn install --immutable
persist-credentials: false
- name: Setup Node with shared dependencies
uses: ./.github/actions/setup
with:
node-modules-cache: true
- name: Build resources
run: ./node_modules/.bin/gulp gen-icons-json build-translations build-locale-data
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Run Tests
run: yarn run test
run: pnpm run test
build:
name: Build frontend
needs: [lint, test]
needs:
- lint
- test
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Node
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
node-version-file: ".nvmrc"
cache: yarn
- name: Install dependencies
run: yarn install --immutable
persist-credentials: false
- name: Setup Node with shared dependencies
uses: ./.github/actions/setup
with:
node-modules-cache: true
# Read-only reuse of the rspack cache written by the nightly (see
# nightly.yaml). rspack itself decides what is still valid (version +
# buildDependencies + node_modules snapshot), so the GHA key just restores
# the latest nightly cache; no fingerprint, and no save step (CI never
# writes the shared cache).
- name: Restore rspack cache
continue-on-error: true
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: .rspack-cache
key: rspack-cache-${{ runner.os }}-${{ github.run_id }}
restore-keys: |
rspack-cache-${{ runner.os }}-
- name: Build Application
run: ./node_modules/.bin/gulp build-app
env:
IS_TEST: "true"
uses: ./.github/actions/build
with:
target: build-app
github-token: ${{ secrets.GITHUB_TOKEN }}
is-test: true
rspack-cache: readonly
- name: Upload bundle stats
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: frontend-bundle-stats
path: build/stats/*.json
if-no-files-found: error
supervisor:
name: Build supervisor
needs: [lint, test]
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Node
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
- name: Check entrypoint bundle size budget
run: pnpm run check-bundlesize
- name: Upload frontend build
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
node-version-file: ".nvmrc"
cache: yarn
- name: Install dependencies
run: yarn install --immutable
- name: Build Application
run: ./node_modules/.bin/gulp build-hassio
env:
IS_TEST: "true"
- name: Upload bundle stats
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: supervisor-bundle-stats
path: build/stats/*.json
name: frontend-build
path: hass_frontend/
if-no-files-found: error
retention-days: 7
+43
View File
@@ -0,0 +1,43 @@
name: "CodeQL"
on:
push:
branches:
- dev
- master
pull_request:
# The branches below must be a subset of the branches above
branches:
- dev
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
timeout-minutes: 360
permissions:
contents: read # To check out the repository
security-events: write # To upload CodeQL results
steps:
- name: Check out code from GitHub
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Initialize CodeQL
uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
with:
languages: javascript-typescript
build-mode: none
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
with:
category: "/language:javascript-typescript"
-60
View File
@@ -1,60 +0,0 @@
name: "CodeQL"
on:
push:
branches: [dev, master]
pull_request:
# The branches below must be a subset of the branches above
branches: [dev]
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Override automatic language detection by changing the below list
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
language: ["javascript"]
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@16140ae1a102900babc80a33c44059580f687047 # v4.30.9
with:
languages: ${{ matrix.language }}
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@16140ae1a102900babc80a33c44059580f687047 # v4.30.9
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@16140ae1a102900babc80a33c44059580f687047 # v4.30.9
+34
View File
@@ -0,0 +1,34 @@
name: Copilot Setup Steps
on:
workflow_dispatch:
push:
paths:
- .github/workflows/copilot-setup-steps.yml
pull_request:
paths:
- .github/workflows/copilot-setup-steps.yml
env:
NODE_OPTIONS: --max_old_space_size=6144
jobs:
copilot-setup-steps:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check out files from GitHub
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Node and install
uses: ./.github/actions/setup
with:
node-modules-cache: true
- name: Skip fetching nightly translations
run: echo "SKIP_FETCH_NIGHTLY_TRANSLATIONS=1" >> "$GITHUB_ENV"
- name: Build resources
run: ./node_modules/.bin/gulp gen-icons-json build-translations build-locale-data gather-gallery-pages
+33 -38
View File
@@ -9,6 +9,9 @@ on:
- dev
- master
permissions:
contents: read
env:
NODE_OPTIONS: --max_old_space_size=6144
@@ -16,69 +19,61 @@ jobs:
deploy_dev:
runs-on: ubuntu-latest
name: Demo Development
if: github.event_name != 'push' || github.ref_name != 'master'
if: github.repository == 'home-assistant/frontend' && (github.event_name != 'push' || github.ref_name != 'master')
environment:
name: Demo Development
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
url: ${{ steps.deploy.outputs.unique_deploy_url }}
steps:
- name: Check out files from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: dev
persist-credentials: false
- name: Setup Node
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version-file: ".nvmrc"
cache: yarn
- name: Install dependencies
run: yarn install --immutable
- name: Setup Node and install
uses: ./.github/actions/setup
- name: Build Demo
run: ./node_modules/.bin/gulp build-demo
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
uses: ./.github/actions/build
with:
target: build-demo
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy to Netlify
id: deploy
run: |
npx -y [email protected] deploy --dir=demo/dist --prod
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_DEMO_DEV_SITE_ID }}
uses: ./.github/actions/netlify-deploy
with:
dir: demo/dist
auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }}
site-id: ${{ secrets.NETLIFY_DEMO_DEV_SITE_ID }}
deploy_master:
runs-on: ubuntu-latest
name: Demo Production
if: github.event_name == 'push' && github.ref_name == 'master'
if: github.repository == 'home-assistant/frontend' && github.event_name == 'push' && github.ref_name == 'master'
environment:
name: Demo Production
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
url: ${{ steps.deploy.outputs.netlify_url }}
steps:
- name: Check out files from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: master
persist-credentials: false
- name: Setup Node
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version-file: ".nvmrc"
cache: yarn
- name: Install dependencies
run: yarn install --immutable
- name: Setup Node and install
uses: ./.github/actions/setup
- name: Build Demo
run: ./node_modules/.bin/gulp build-demo
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
uses: ./.github/actions/build
with:
target: build-demo
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy to Netlify
id: deploy
run: |
npx -y [email protected] deploy --dir=demo/dist --prod
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_DEMO_SITE_ID }}
uses: ./.github/actions/netlify-deploy
with:
dir: demo/dist
auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }}
site-id: ${{ secrets.NETLIFY_DEMO_SITE_ID }}
+55
View File
@@ -0,0 +1,55 @@
name: Dependency review
on:
pull_request:
branches:
- dev
paths:
- package.json
- pnpm-lock.yaml
- pnpm-workspace.yaml
schedule:
- cron: "0 6 1 * *" # Monthly report on all direct dependencies
workflow_dispatch:
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
dependency-review:
name: Review dependency changes
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: read # To compare the dependency graph between base and head
steps:
- name: Dependency review
uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
with:
license-check: false # Covered by pnpm lint:licenses
fail-on-severity: high
show-openssf-scorecard: true
warn-on-openssf-scorecard-level: 3
npm-metadata:
name: Check npm metadata
runs-on: ubuntu-latest
permissions:
contents: read # To read package.json
steps:
- name: Check out workflow scripts
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
sparse-checkout: .github/scripts
- name: Check npm metadata
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { default: checkNpmMetadata } = await import(
`${process.env.GITHUB_WORKSPACE}/.github/scripts/check-npm-metadata.mts`
);
await checkNpmMetadata({ github, context, core });
+18 -17
View File
@@ -5,37 +5,38 @@ on:
schedule:
- cron: "0 0 * * *"
permissions:
contents: read
env:
NODE_OPTIONS: --max_old_space_size=6144
jobs:
deploy:
if: github.repository == 'home-assistant/frontend'
runs-on: ubuntu-latest
environment:
name: Design
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
url: ${{ steps.deploy.outputs.netlify_url }}
steps:
- name: Check out files from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Node
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
node-version-file: ".nvmrc"
cache: yarn
persist-credentials: false
- name: Install dependencies
run: yarn install --immutable
- name: Setup Node and install
uses: ./.github/actions/setup
- name: Build Gallery
run: ./node_modules/.bin/gulp build-gallery
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
uses: ./.github/actions/build
with:
target: build-gallery
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy to Netlify
id: deploy
run: |
npx -y [email protected] deploy --dir=gallery/dist --prod
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_GALLERY_SITE_ID }}
uses: ./.github/actions/netlify-deploy
with:
dir: gallery/dist
auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }}
site-id: ${{ secrets.NETLIFY_GALLERY_SITE_ID }}
+18 -20
View File
@@ -10,6 +10,9 @@ on:
branches:
- dev
permissions:
contents: read
env:
NODE_OPTIONS: --max_old_space_size=6144
@@ -21,32 +24,27 @@ jobs:
if: github.repository == 'home-assistant/frontend' && contains(github.event.pull_request.labels.*.name, 'needs design preview')
steps:
- name: Check out files from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Node
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
node-version-file: ".nvmrc"
cache: yarn
persist-credentials: false
- name: Install dependencies
run: yarn install --immutable
- name: Setup Node and install
uses: ./.github/actions/setup
- name: Build Gallery
run: ./node_modules/.bin/gulp build-gallery
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
uses: ./.github/actions/build
with:
target: build-gallery
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy preview to Netlify
id: deploy
run: |
npx -y [email protected] deploy --dir=gallery/dist --alias "deploy-preview-${{ github.event.number }}" \
--json > deploy_output.json
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_GALLERY_SITE_ID }}
uses: ./.github/actions/netlify-deploy
with:
dir: gallery/dist
alias: deploy-preview-${{ github.event.number }}
auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }}
site-id: ${{ secrets.NETLIFY_GALLERY_SITE_ID }}
- name: Generate summary
run: |
NETLIFY_LIVE_URL=$(jq -r '.deploy_url' deploy_output.json)
echo "$NETLIFY_LIVE_URL" >> "$GITHUB_STEP_SUMMARY"
run: echo "${{ steps.deploy.outputs.netlify_url }}" >> "$GITHUB_STEP_SUMMARY"
+396
View File
@@ -0,0 +1,396 @@
name: E2E Tests
on:
push:
branches:
- dev
- master
pull_request:
branches:
- dev
- master
workflow_dispatch:
env:
NODE_OPTIONS: --max_old_space_size=6144
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
prepare-dependencies:
name: Prepare dependencies
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Prepare dependencies
uses: ./.github/actions/prepare-dependencies
prepare-container-dependencies:
name: Prepare container dependencies
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.63.0-noble
options: --user 1001
defaults:
run:
shell: bash
steps:
- name: Check out files from GitHub
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Prepare dependencies
uses: ./.github/actions/prepare-dependencies
with:
node-modules-cache-key: node-modules-container-v1
# ── Build the demo once and share it across test jobs via artifact ──────────
build-demo:
name: Build demo
needs: prepare-dependencies
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Node with shared dependencies
uses: ./.github/actions/setup
with:
node-modules-cache: true
- name: Build demo
uses: ./.github/actions/build
with:
target: build-demo-e2e
github-token: ${{ secrets.GITHUB_TOKEN }}
is-test: true
- name: Upload demo build
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: demo-dist
path: demo/dist/
if-no-files-found: error
retention-days: 3
# ── Build the e2e test app and share it via artifact ────────────────────────
build-e2e-test-app:
name: Build e2e test app
needs: prepare-dependencies
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Node with shared dependencies
uses: ./.github/actions/setup
with:
node-modules-cache: true
- name: Build e2e test app
uses: ./.github/actions/build
with:
target: build-e2e-test-app-e2e
github-token: ${{ secrets.GITHUB_TOKEN }}
is-test: true
- name: Upload e2e test app build
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: e2e-test-app-dist
path: test/e2e/app/dist/
if-no-files-found: error
retention-days: 3
# ── Build the gallery and share it via artifact ─────────────────────────────
build-gallery:
name: Build gallery
needs: prepare-dependencies
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Node with shared dependencies
uses: ./.github/actions/setup
with:
node-modules-cache: true
- name: Build gallery
uses: ./.github/actions/build
with:
target: build-gallery
github-token: ${{ secrets.GITHUB_TOKEN }}
is-test: true
- name: Upload gallery build
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: gallery-dist
path: gallery/dist/
if-no-files-found: error
retention-days: 3
# ── Run Playwright tests against Chromium ──────────────────────────────────
e2e-demo:
name: E2E demo (${{ matrix.shardIndex }}/${{ matrix.shardTotal }})
needs:
- build-demo
- prepare-container-dependencies
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.63.0-noble
options: --user 1001 --ipc=host
defaults:
run:
shell: bash
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
shardIndex:
- 1
- 2
shardTotal:
- 2
steps:
- name: Check out files from GitHub
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Node with shared dependencies
uses: ./.github/actions/setup
with:
node-modules-cache: true
node-modules-cache-key: node-modules-container-v1
- name: Download demo build
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: demo-dist
path: demo/dist/
- name: Run Playwright demo tests
run: pnpm run test:e2e:demo --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
timeout-minutes: 15
- name: Upload demo blob report
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: always()
with:
name: blob-report-demo-${{ matrix.shardIndex }}
path: test/e2e/reports/demo/
if-no-files-found: warn
retention-days: 3
e2e-app:
name: E2E app (${{ matrix.shardIndex }}/${{ matrix.shardTotal }})
needs:
- build-e2e-test-app
- prepare-container-dependencies
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.63.0-noble
options: --user 1001 --ipc=host
defaults:
run:
shell: bash
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
shardIndex:
- 1
- 2
- 3
- 4
shardTotal:
- 4
steps:
- name: Check out files from GitHub
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Node with shared dependencies
uses: ./.github/actions/setup
with:
node-modules-cache: true
node-modules-cache-key: node-modules-container-v1
- name: Download e2e test app build
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: e2e-test-app-dist
path: test/e2e/app/dist/
- name: Run Playwright app tests
run: pnpm run test:e2e:app --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
timeout-minutes: 15
- name: Upload app blob report
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: always()
with:
name: blob-report-app-${{ matrix.shardIndex }}
path: test/e2e/reports/app/
if-no-files-found: warn
retention-days: 3
e2e-gallery:
name: E2E gallery (${{ matrix.shardIndex }}/${{ matrix.shardTotal }})
needs:
- build-gallery
- prepare-container-dependencies
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.63.0-noble
options: --user 1001 --ipc=host
defaults:
run:
shell: bash
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
shardIndex:
- 1
- 2
- 3
- 4
shardTotal:
- 4
steps:
- name: Check out files from GitHub
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Node with shared dependencies
uses: ./.github/actions/setup
with:
node-modules-cache: true
node-modules-cache-key: node-modules-container-v1
- name: Download gallery build
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: gallery-dist
path: gallery/dist/
- name: Run Playwright gallery tests
run: pnpm run test:e2e:gallery --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
timeout-minutes: 15
- name: Upload gallery blob report
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: always()
with:
name: blob-report-gallery-${{ matrix.shardIndex }}
path: test/e2e/reports/gallery/
if-no-files-found: warn
retention-days: 3
report:
name: Report
needs:
- e2e-demo
- e2e-app
- e2e-gallery
runs-on: ubuntu-latest
if: ${{ always() }}
permissions:
contents: read
pull-requests: write
steps:
- name: Check out files from GitHub
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Node with shared dependencies
uses: ./.github/actions/setup
with:
node-modules-cache: true
- name: Download demo blob reports
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
continue-on-error: true
with:
pattern: blob-report-demo-*
path: test/e2e/reports/demo/
- name: Download app blob reports
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
continue-on-error: true
with:
pattern: blob-report-app-*
path: test/e2e/reports/app/
- name: Download gallery blob reports
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
continue-on-error: true
with:
pattern: blob-report-gallery-*
path: test/e2e/reports/gallery/
- name: Stage blobs for merge
run: node test/e2e/collect-blob-reports.mjs
- name: Merge blob reports
run: npx playwright merge-reports -c test/e2e/playwright.merge.config.ts test/e2e/reports/blob
- name: Upload merged HTML report
id: upload-report
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: playwright-report
path: test/e2e/reports/combined/
retention-days: 14
- name: Post report to PR
if: >-
github.event_name == 'pull_request' &&
(needs.e2e-demo.result == 'failure' ||
needs.e2e-app.result == 'failure' ||
needs.e2e-gallery.result == 'failure')
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { default: postReportComment } = await import(
`${process.env.GITHUB_WORKSPACE}/test/e2e/post-report-comment.mjs`
);
await postReportComment({ github, context, core });
- name: Check suite results
run: |
failed=0
for suite in \
"demo:${{ needs.e2e-demo.result }}" \
"app:${{ needs.e2e-app.result }}" \
"gallery:${{ needs.e2e-gallery.result }}"; do
name="${suite%%:*}"
result="${suite#*:}"
echo "E2E ${name}: ${result}"
if [ "$result" != "success" ]; then
failed=1
fi
done
exit "$failed"
+2 -2
View File
@@ -1,6 +1,6 @@
name: "Pull Request Labeler"
on: pull_request_target
on: pull_request_target # zizmor: ignore[dangerous-triggers] -- safe: only runs actions/labeler, no PR code checkout
jobs:
triage:
@@ -10,6 +10,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Apply labels
uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1
uses: actions/labeler@bf12e9b00b37c5c0ca2b87b79b2daf7891dbda13 # v7.0.0
with:
sync-labels: true
@@ -5,17 +5,20 @@ on:
schedule:
- cron: "0 * * * *"
permissions:
issues: write
pull-requests: write
jobs:
lock:
if: github.repository == 'home-assistant/frontend'
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5.0.1
- uses: dessant/lock-threads@89ae32b08ed1a541efecbab17912962a5e38981c # v6.0.2
with:
github-token: ${{ github.token }}
process-only: "issues, prs"
issue-lock-inactive-days: "30"
issue-exclude-created-before: "2020-10-01T00:00:00Z"
issue-inactive-days: "30"
issue-lock-reason: ""
pr-lock-inactive-days: "1"
pr-exclude-created-before: "2020-11-01T00:00:00Z"
pr-inactive-days: "1"
pr-lock-reason: ""
+102 -29
View File
@@ -6,7 +6,7 @@ on:
- cron: "0 1 * * *"
env:
PYTHON_VERSION: "3.13"
PYTHON_VERSION: "3.14"
NODE_OPTIONS: --max_old_space_size=6144
permissions:
@@ -14,57 +14,130 @@ permissions:
jobs:
nightly:
if: github.repository == 'home-assistant/frontend'
name: Nightly
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout the repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Setup Node
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
- name: Setup Node and install
uses: ./.github/actions/setup
with:
node-version-file: ".nvmrc"
cache: yarn
immutable: false
- name: Install dependencies
run: yarn install
- name: Download translations
run: ./script/translations_download
env:
LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }}
# The wheel only builds the app (build-app), which does not merge
# backend translations. Skipping the whole-project backend export (as
# the release does) keeps this off the build's critical path; the full
# translations artifact is produced in parallel by the job below.
SKIP_BACKEND_TRANSLATIONS: "1"
- name: Bump version
run: script/version_bump.js nightly
# Warm the shared compression cache so releases reuse it (see release.yaml).
- name: Restore compression cache
id: compress-cache
continue-on-error: true
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: .compress-cache
key: compress-cache-${{ runner.os }}-${{ github.run_id }}-${{ github.run_attempt }}
restore-keys: |
compress-cache-${{ runner.os }}-
# The nightly writes the rspack persistent cache; CI reads it read-only
# (see ci.yaml). rspack invalidates internally (version + buildDependencies
# + node_modules snapshot), so the cache rolls forward daily and a single
# dependency bump keeps most of it warm instead of dropping the lineage.
- name: Restore rspack cache
id: rspack-cache
continue-on-error: true
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: .rspack-cache
key: rspack-cache-${{ runner.os }}-${{ github.run_id }}-${{ github.run_attempt }}
restore-keys: |
rspack-cache-${{ runner.os }}-
- name: Build nightly Python wheels
env:
COMPRESS_CACHE_DIR: ${{ github.workspace }}/.compress-cache
RSPACK_CACHE: readwrite
run: |
pip install build
pnpm install --frozen-lockfile
export SKIP_FETCH_NIGHTLY_TRANSLATIONS=1
script/build_frontend
rm -rf dist home_assistant_frontend.egg-info
python3 -m build
# Not gated on the restore steps: a transient restore failure (they are
# continue-on-error) must not stop us persisting a freshly built cache.
- name: Save compression cache
if: success()
continue-on-error: true
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: .compress-cache
key: compress-cache-${{ runner.os }}-${{ github.run_id }}-${{ github.run_attempt }}
- name: Save rspack cache
if: success()
continue-on-error: true
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: .rspack-cache
key: rspack-cache-${{ runner.os }}-${{ github.run_id }}-${{ github.run_attempt }}
- name: Upload build artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: wheels
path: dist/home_assistant_frontend*.whl
if-no-files-found: error
# The full translations (including the slow backend/core export) are only
# needed for the uploaded artifact, not the wheel, so they are downloaded in
# parallel here instead of blocking the build above.
translations:
if: github.repository == 'home-assistant/frontend'
name: Translations
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Node and install
uses: ./.github/actions/setup
with:
immutable: false
- name: Download translations
run: ./script/translations_download
env:
LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }}
- name: Bump version
run: script/version_bump.js nightly
- name: Build nightly Python wheels
run: |
pip install build
yarn install
export SKIP_FETCH_NIGHTLY_TRANSLATIONS=1
script/build_frontend
rm -rf dist home_assistant_frontend.egg-info
python3 -m build
- name: Archive translations
run: tar -czvf translations.tar.gz translations
- name: Upload build artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: wheels
path: dist/home_assistant_frontend*.whl
if-no-files-found: error
- name: Upload translations
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: translations
path: translations.tar.gz
@@ -0,0 +1,38 @@
name: Pull request standards
on:
pull_request_target: # zizmor: ignore[dangerous-triggers] -- safe: reads PR metadata from event payload only, checks out base repo scripts only, never PR head code
types:
- opened
- edited
- reopened
- ready_for_review
branches:
- dev
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
check:
name: Check pull request follows contribution standards
runs-on: ubuntu-latest
permissions:
pull-requests: write # To label and comment on pull requests
steps:
- name: Check out workflow scripts
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
sparse-checkout: .github/scripts
- name: Check pull request standards
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { default: checkStandards } = await import(
`${process.env.GITHUB_WORKSPACE}/.github/scripts/check-pull-request-standards.mts`
);
await checkStandards({ github, context, core });
+25 -11
View File
@@ -1,25 +1,39 @@
name: RelativeCI
on:
# zizmor: ignore[dangerous-triggers] -- safe: only downloads artifacts, no PR code checkout
workflow_run:
workflows: [CI]
types:
- completed
permissions:
contents: read
actions: read
jobs:
upload:
name: Upload stats
if: ${{ github.event.workflow_run.conclusion == 'success' }}
strategy:
matrix:
bundle: [frontend, supervisor]
build: [modern, legacy]
upload-frontend-modern:
name: Upload stats (frontend/modern)
if: ${{ github.repository == 'home-assistant/frontend' && github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
steps:
- name: Send bundle stats and build information to RelativeCI
uses: relative-ci/agent-action@8504826a02078b05756e4c07e380023cc2c4274a # v3.1.0
uses: relative-ci/agent-action@fcf45416581928e8dd62eded78ce98c78e5149f8 # v3.2.3
with:
key: ${{ secrets[format('RELATIVE_CI_KEY_{0}_{1}', matrix.bundle, matrix.build)] }}
key: ${{ secrets.RELATIVE_CI_KEY_frontend_modern }}
token: ${{ github.token }}
artifactName: ${{ format('{0}-bundle-stats', matrix.bundle) }}
webpackStatsFile: ${{ format('{0}-{1}.json', matrix.bundle, matrix.build) }}
artifactName: frontend-bundle-stats
webpackStatsFile: frontend-modern.json
upload-frontend-legacy:
name: Upload stats (frontend/legacy)
if: ${{ github.repository == 'home-assistant/frontend' && github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
steps:
- name: Send bundle stats and build information to RelativeCI
uses: relative-ci/agent-action@fcf45416581928e8dd62eded78ce98c78e5149f8 # v3.2.3
with:
key: ${{ secrets.RELATIVE_CI_KEY_frontend_legacy }}
token: ${{ github.token }}
artifactName: frontend-bundle-stats
webpackStatsFile: frontend-legacy.json
+2 -1
View File
@@ -10,6 +10,7 @@ permissions:
jobs:
update_release_draft:
if: github.repository == 'home-assistant/frontend'
permissions:
# write permission for contents is required to create a github release
contents: write
@@ -18,6 +19,6 @@ jobs:
pull-requests: read
runs-on: ubuntu-latest
steps:
- uses: release-drafter/release-drafter@b1476f6e6eb133afa41ed8589daba6dc69b4d3f5 # v6.1.0
- uses: release-drafter/release-drafter@34d80673e067bdc0c24568d3af899c216adcfaa9 # v7.7.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+91 -64
View File
@@ -6,7 +6,7 @@ on:
- published
env:
PYTHON_VERSION: "3.13"
PYTHON_VERSION: "3.14"
NODE_OPTIONS: --max_old_space_size=6144
# Set default workflow permissions
@@ -19,47 +19,81 @@ jobs:
release:
name: Release
runs-on: ubuntu-latest
environment: pypi
permissions:
contents: write # Required to upload release assets
id-token: write # For "Trusted Publisher" to PyPi
if: github.repository_owner == 'home-assistant'
steps:
- name: Checkout the repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Verify version
uses: home-assistant/actions/helpers/verify-version@master
uses: home-assistant/actions/helpers/verify-version@06749dd8c0b54f350bc69c8752456cee498808a3 # master
- name: Setup Node
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
- name: Setup Node and install
uses: ./.github/actions/setup
with:
node-version-file: ".nvmrc"
cache: yarn
- name: Install dependencies
run: yarn install
immutable: false
cache: false
- name: Download Translations
run: ./script/translations_download
env:
LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }}
# The app fetches core (backend) translations live from HA, so the
# release build does not need Lokalise's backend project.
SKIP_BACKEND_TRANSLATIONS: "1"
# Restore the content-addressed compression cache. Unchanged chunks and
# static assets are then reused instead of re-run through brotli/zopfli.
- name: Restore compression cache
id: compress-cache
continue-on-error: true
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: .compress-cache
key: compress-cache-${{ runner.os }}-${{ github.run_id }}-${{ github.run_attempt }}
restore-keys: |
compress-cache-${{ runner.os }}-
- name: Build and release package
env:
COMPRESS_CACHE_DIR: ${{ github.workspace }}/.compress-cache
run: |
python3 -m pip install twine build
export TWINE_USERNAME="__token__"
export TWINE_PASSWORD="${{ secrets.TWINE_TOKEN }}"
python3 -m pip install build
export SKIP_FETCH_NIGHTLY_TRANSLATIONS=1
script/release
- name: Upload release assets
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090 # v2.4.1
# The build keeps the cache under its size budget, so saving stays bounded.
# A unique key always writes; restore-keys picks the newest on the next
# run. Not gated on the restore step: a transient restore failure (it is
# continue-on-error) must not stop us persisting a freshly built cache.
- name: Save compression cache
if: success()
continue-on-error: true
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
files: |
dist/*.whl
dist/*.tar.gz
path: .compress-cache
key: compress-cache-${{ runner.os }}-${{ github.run_id }}-${{ github.run_attempt }}
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
with:
skip-existing: true
- name: Upload release assets
env:
GH_TOKEN: ${{ github.token }}
TAG_NAME: ${{ github.event.release.tag_name }}
run: gh release upload "$TAG_NAME" dist/*.whl dist/*.tar.gz --clobber
wheels-init:
name: Init wheels build
@@ -67,17 +101,34 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Generate requirements.txt
env:
GITHUB_REF: ${{ github.ref }}
run: |
# Sleep to give pypi time to populate the new version across mirrors
sleep 240
version=$(echo "${{ github.ref }}" | awk -F"/" '{print $NF}' )
version=$(echo "$GITHUB_REF" | awk -F"/" '{print $NF}' )
# Wait for the exact wheel to appear on the simple index (the surface
# the wheels build's pip uses). The JSON API can report a version as
# available before it propagates here, which fails the wheels build.
wheel="home_assistant_frontend-${version}-py3-none-any.whl"
echo "Waiting for $wheel to appear on the PyPI simple index..."
for i in $(seq 1 30); do
if curl -sf "https://pypi.org/simple/home-assistant-frontend/" | grep -qF "$wheel"; then
echo "Package is available on the PyPI simple index!"
break
fi
if [ "$i" = "30" ]; then
echo "Timed out waiting for package to appear on PyPI"
exit 1
fi
echo "Not available yet, retrying in 30 seconds... ($i/30)"
sleep 30
done
echo "home-assistant-frontend==$version" > ./requirements.txt
# home-assistant/wheels doesn't support SHA pinning
- name: Build wheels
uses: home-assistant/wheels@2025.10.0
uses: home-assistant/wheels@9e17ab1ed5c4c79d8b61e29fa63de25ca2710716 # 2026.07.0
with:
abi: cp313
abi: cp314
tag: musllinux_1_2
arch: amd64
wheels-key: ${{ secrets.WHEELS_KEY }}
@@ -85,58 +136,34 @@ jobs:
release-landing-page:
name: Release landing-page frontend
if: github.event.release.prerelease == false
if: github.repository == 'home-assistant/frontend' && github.event.release.prerelease == false
runs-on: ubuntu-latest
permissions:
contents: write # Required to upload release assets
steps:
- name: Checkout the repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Node
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
node-version-file: ".nvmrc"
cache: yarn
- name: Install dependencies
run: yarn install
persist-credentials: false
- name: Setup Node and install
uses: ./.github/actions/setup
with:
immutable: false
cache: false
- name: Download Translations
run: ./script/translations_download
env:
LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }}
# The landing-page build does not merge backend translations.
SKIP_BACKEND_TRANSLATIONS: "1"
- name: Build landing-page
run: landing-page/script/build_landing_page
- name: Tar folder
run: tar -czf landing-page/home_assistant_frontend_landingpage-${{ github.event.release.tag_name }}.tar.gz -C landing-page/dist .
- name: Upload release asset
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090 # v2.4.1
with:
files: landing-page/home_assistant_frontend_landingpage-${{ github.event.release.tag_name }}.tar.gz
release-supervisor:
name: Release supervisor frontend
if: github.event.release.prerelease == false
runs-on: ubuntu-latest
permissions:
contents: write # Required to upload release assets
steps:
- name: Checkout the repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Node
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version-file: ".nvmrc"
cache: yarn
- name: Install dependencies
run: yarn install
- name: Download Translations
run: ./script/translations_download
env:
LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }}
- name: Build supervisor
run: hassio/script/build_hassio
- name: Tar folder
run: tar -czf hassio/home_assistant_frontend_supervisor-${{ github.event.release.tag_name }}.tar.gz -C hassio/build .
TAG_NAME: ${{ github.event.release.tag_name }}
run: tar -czf "landing-page/home_assistant_frontend_landingpage-${TAG_NAME}.tar.gz" -C landing-page/dist .
- name: Upload release asset
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090 # v2.4.1
with:
files: hassio/home_assistant_frontend_supervisor-${{ github.event.release.tag_name }}.tar.gz
env:
GH_TOKEN: ${{ github.token }}
TAG_NAME: ${{ github.event.release.tag_name }}
run: gh release upload "$TAG_NAME" "landing-page/home_assistant_frontend_landingpage-${TAG_NAME}.tar.gz" --clobber
@@ -0,0 +1,67 @@
name: Restrict task creation
# yamllint disable-line rule:truthy
on:
issues:
types: [opened]
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.event.issue.number }}
jobs:
add-no-stale:
name: Add no-stale label
runs-on: ubuntu-latest
permissions:
contents: read # To check out workflow scripts
issues: write # To add labels to issues
if: >-
github.event.issue.type.name == 'Task'
|| github.event.issue.type.name == 'Epic'
|| github.event.issue.type.name == 'Opportunity'
steps:
- name: Check out workflow scripts
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
sparse-checkout: .github/scripts
- name: Add no-stale label
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { withRetry } = await import(
`${process.env.GITHUB_WORKSPACE}/.github/scripts/github-retry.mts`
);
await withRetry("no-stale label", () =>
github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: ['no-stale']
})
);
check-authorization:
name: Check authorization
runs-on: ubuntu-latest
permissions:
contents: read # To check out workflow scripts
issues: write # To comment on, label, and close issues
# Only run if this is a Task issue type (from the issue form)
if: github.event.issue.type.name == 'Task'
steps:
- name: Check out workflow scripts
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
sparse-checkout: .github/scripts
- name: Check if user is authorized
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { default: checkTaskAuthorization } = await import(
`${process.env.GITHUB_WORKSPACE}/.github/scripts/check-task-authorization.mts`
);
await checkTaskAuthorization({ github, context, core });
@@ -1,58 +0,0 @@
name: Restrict task creation
# yamllint disable-line rule:truthy
on:
issues:
types: [opened]
jobs:
check-authorization:
runs-on: ubuntu-latest
# Only run if this is a Task issue type (from the issue form)
if: github.event.issue.type.name == 'Task'
steps:
- name: Check if user is authorized
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
script: |
const issueAuthor = context.payload.issue.user.login;
// Check if user is an organization member
try {
await github.rest.orgs.checkMembershipForUser({
org: 'home-assistant',
username: issueAuthor
});
console.log(`✅ ${issueAuthor} is an organization member`);
return; // Authorized
} catch (error) {
console.log(`❌ ${issueAuthor} is not authorized to create Task issues`);
}
// Close the issue with a comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `Hi @${issueAuthor}, thank you for your contribution!\n\n` +
`Task issues are restricted to Open Home Foundation staff and authorized contributors.\n\n` +
`If you would like to:\n` +
`- Report a bug: Please use the [bug report form](https://github.com/home-assistant/frontend/issues/new?template=bug_report.yml)\n` +
`- Request a feature: Please submit to [Feature Requests](https://github.com/orgs/home-assistant/discussions)\n\n` +
`If you believe you should have access to create Task issues, please contact the maintainers.`
});
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
state: 'closed'
});
// Add a label to indicate this was auto-closed
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: ['auto-closed']
});
@@ -5,12 +5,18 @@ on:
schedule:
- cron: "0 * * * *"
permissions:
actions: write
issues: write
pull-requests: write
jobs:
stale:
if: github.repository == 'home-assistant/frontend'
runs-on: ubuntu-latest
steps:
- name: 90 days stale policy
uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0
uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 90
@@ -0,0 +1,48 @@
name: Sync device class constants
# Mirrors the device class constants for Home Assistant Core's into the
# build-time default in src/data/device_classes.ts and opens a PR
# when it drifts. Reads homeassistant/generated/device_classes.json from core.
on:
workflow_dispatch:
schedule:
- cron: "0 4 * * *" # Daily, 04:00 UTC
permissions:
contents: read
jobs:
sync:
if: github.repository == 'home-assistant/frontend'
name: Sync
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout the repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Node and install
uses: ./.github/actions/setup
- name: Regenerate device class constants
run: ./script/gen_device_classes
- name: Format
run: pnpm exec prettier --write src/data/device_classes.ts
- name: Create pull request
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
with:
branch: chore/sync-device-classes
commit-message: Update device class constants
title: Update device class constants
body: |
Regenerated `DOMAIN_DEVICE_CLASSES` from Home Assistant Core's
`homeassistant/generated/device_classes.json`.
Automated by `.github/workflows/sync-device-classes.yaml`.
@@ -0,0 +1,49 @@
name: Sync sensor entity constants
# Mirrors Home Assistant Core's numeric `SensorDeviceClass`, `SensorStateClass`,
# units and related device and state classes arrays into the
# build-time default in src/data/sensor_entity_constants.ts and opens a PR
# when it drifts. Reads homeassistant/generated/sensor.json from core.
on:
workflow_dispatch:
schedule:
- cron: "0 4 * * *" # Daily, 04:00 UTC
permissions:
contents: read
jobs:
sync:
if: github.repository == 'home-assistant/frontend'
name: Sync
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout the repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Node and install
uses: ./.github/actions/setup
- name: Regenerate sensor entity constants
run: ./script/gen_sensor_entity_constants
- name: Format
run: pnpm exec prettier --write src/data/sensor_entity_constants.ts
- name: Create pull request
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
with:
branch: chore/sync-sensor-entity-constants
commit-message: Update sensor entity constants
title: Update sensor entity constants
body: |
Regenerated the sensor entity constants from Home Assistant Core's
`homeassistant/generated/sensor.json`.
Automated by `.github/workflows/sync-sensor-entity-constants.yaml`.
+11 -4
View File
@@ -6,17 +6,24 @@ on:
branches:
- dev
paths:
- .github/workflows/translations.yaml
- src/translations/en.json
permissions:
contents: read
jobs:
upload:
name: Upload
if: github.repository == 'home-assistant/frontend'
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Upload Translations
run: |
export LOKALISE_TOKEN="${{ secrets.LOKALISE_TOKEN }}"
./script/translations_upload_base
run: ./script/translations_upload_base
env:
LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }}
+22 -11
View File
@@ -6,18 +6,15 @@ build/
dist/
/hass_frontend/
/translations/
/.compress-cache/
/.rspack-cache/
# Composite action source, not build output
!/.github/actions/build/
# yarn
.yarn/*
!.yarn/patches
!.yarn/releases
!.yarn/plugins
!.yarn/sdks
!.yarn/versions
.pnp.*
/node_modules/
yarn-error.log
# Node
node_modules/
npm-debug.log
.pnpm-store/
# Python stuff
*.py[cod]
@@ -54,6 +51,20 @@ src/cast/dev_const.ts
# test coverage
test/coverage/
# Playwright e2e output
test/e2e/reports/
test/e2e/test-results/
# E2E test app build output
test/e2e/app/dist/
# MCP server
.playwright-mcp/
# AI tooling
.claude
.claude/*
!.claude/skills
.cursor
.opencode
.serena
test/benchmarks/results/
+1 -1
View File
@@ -1 +1 @@
yarn run lint-staged --relative
pnpm exec lint-staged --relative
+1 -1
View File
@@ -1 +1 @@
22.21.0
24.21.0
+3 -1
View File
@@ -1,4 +1,6 @@
CLA.md
CODE_OF_CONDUCT.md
LICENSE.md
PULL_REQUEST_TEMPLATE.md
PULL_REQUEST_TEMPLATE.md
public/static/map/sprites/*.json
pnpm-lock.yaml
-55
View File
@@ -73,37 +73,6 @@
"instanceLimit": 1
}
},
{
"label": "Develop Supervisor panel",
"type": "gulp",
"task": "develop-hassio",
"problemMatcher": {
"owner": "ha-build",
"source": "ha-build",
"fileLocation": "absolute",
"severity": "error",
"pattern": [
{
"regexp": "(SyntaxError): (.+): (.+) \\((\\d+):(\\d+)\\)",
"severity": 1,
"file": 2,
"message": 3,
"line": 4,
"column": 5
}
],
"background": {
"activeOnStart": true,
"beginsPattern": "Changes detected. Starting compilation",
"endsPattern": "Build done @"
}
},
"isBackground": true,
"group": "build",
"runOptions": {
"instanceLimit": 1
}
},
{
"label": "Develop Gallery",
"type": "gulp",
@@ -246,20 +215,6 @@
"instanceLimit": 1
}
},
{
"label": "Run HA Core for Supervisor in devcontainer",
"type": "shell",
"command": "SUPERVISOR=${input:supervisorHost} SUPERVISOR_TOKEN=${input:supervisorToken} script/core",
"isBackground": true,
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [],
"runOptions": {
"instanceLimit": 1
}
},
{
"label": "Setup and fetch nightly translations",
"type": "gulp",
@@ -268,16 +223,6 @@
}
],
"inputs": [
{
"id": "supervisorHost",
"type": "promptString",
"description": "The IP of the Supervisor host running the Remote API proxy add-on"
},
{
"id": "supervisorToken",
"type": "promptString",
"description": "The token for the Remote API proxy add-on"
},
{
"id": "coreUrl",
"type": "promptString",
@@ -1,13 +0,0 @@
diff --git a/dist/leaflet.draw.js b/dist/leaflet.draw.js
index 71aeb33b49192dac65f869795716fc3e34969b7e..9be93575809b224c3100fbb9cca72de4bce3faf4 100644
--- a/dist/leaflet.draw.js
+++ b/dist/leaflet.draw.js
@@ -5,6 +5,7 @@
https://github.com/Leaflet/Leaflet.draw
http://leafletjs.com
*/
+var radius;
!function(t,e,i){function o(t,e){for(;(t=t.parentElement)&&!t.classList.contains(e););return t}L.drawVersion="1.0.4",L.Draw={},L.drawLocal={draw:{toolbar:{actions:{title:"Cancel drawing",text:"Cancel"},finish:{title:"Finish drawing",text:"Finish"},undo:{title:"Delete last point drawn",text:"Delete last point"},buttons:{polyline:"Draw a polyline",polygon:"Draw a polygon",rectangle:"Draw a rectangle",circle:"Draw a circle",marker:"Draw a marker",circlemarker:"Draw a circlemarker"}},handlers:{circle:{tooltip:{start:"Click and drag to draw circle."},radius:"Radius"},circlemarker:{tooltip:{start:"Click map to place circle marker."}},marker:{tooltip:{start:"Click map to place marker."}},polygon:{tooltip:{start:"Click to start drawing shape.",cont:"Click to continue drawing shape.",end:"Click first point to close this shape."}},polyline:{error:"<strong>Error:</strong> shape edges cannot cross!",tooltip:{start:"Click to start drawing line.",cont:"Click to continue drawing line.",end:"Click last point to finish line."}},rectangle:{tooltip:{start:"Click and drag to draw rectangle."}},simpleshape:{tooltip:{end:"Release mouse to finish drawing."}}}},edit:{toolbar:{actions:{save:{title:"Save changes",text:"Save"},cancel:{title:"Cancel editing, discards all changes",text:"Cancel"},clearAll:{title:"Clear all layers",text:"Clear All"}},buttons:{edit:"Edit layers",editDisabled:"No layers to edit",remove:"Delete layers",removeDisabled:"No layers to delete"}},handlers:{edit:{tooltip:{text:"Drag handles or markers to edit features.",subtext:"Click cancel to undo changes."}},remove:{tooltip:{text:"Click on a feature to remove."}}}}},L.Draw.Event={},L.Draw.Event.CREATED="draw:created",L.Draw.Event.EDITED="draw:edited",L.Draw.Event.DELETED="draw:deleted",L.Draw.Event.DRAWSTART="draw:drawstart",L.Draw.Event.DRAWSTOP="draw:drawstop",L.Draw.Event.DRAWVERTEX="draw:drawvertex",L.Draw.Event.EDITSTART="draw:editstart",L.Draw.Event.EDITMOVE="draw:editmove",L.Draw.Event.EDITRESIZE="draw:editresize",L.Draw.Event.EDITVERTEX="draw:editvertex",L.Draw.Event.EDITSTOP="draw:editstop",L.Draw.Event.DELETESTART="draw:deletestart",L.Draw.Event.DELETESTOP="draw:deletestop",L.Draw.Event.TOOLBAROPENED="draw:toolbaropened",L.Draw.Event.TOOLBARCLOSED="draw:toolbarclosed",L.Draw.Event.MARKERCONTEXT="draw:markercontext",L.Draw=L.Draw||{},L.Draw.Feature=L.Handler.extend({initialize:function(t,e){this._map=t,this._container=t._container,this._overlayPane=t._panes.overlayPane,this._popupPane=t._panes.popupPane,e&&e.shapeOptions&&(e.shapeOptions=L.Util.extend({},this.options.shapeOptions,e.shapeOptions)),L.setOptions(this,e);var i=L.version.split(".");1===parseInt(i[0],10)&&parseInt(i[1],10)>=2?L.Draw.Feature.include(L.Evented.prototype):L.Draw.Feature.include(L.Mixin.Events)},enable:function(){this._enabled||(L.Handler.prototype.enable.call(this),this.fire("enabled",{handler:this.type}),this._map.fire(L.Draw.Event.DRAWSTART,{layerType:this.type}))},disable:function(){this._enabled&&(L.Handler.prototype.disable.call(this),this._map.fire(L.Draw.Event.DRAWSTOP,{layerType:this.type}),this.fire("disabled",{handler:this.type}))},addHooks:function(){var t=this._map;t&&(L.DomUtil.disableTextSelection(),t.getContainer().focus(),this._tooltip=new L.Draw.Tooltip(this._map),L.DomEvent.on(this._container,"keyup",this._cancelDrawing,this))},removeHooks:function(){this._map&&(L.DomUtil.enableTextSelection(),this._tooltip.dispose(),this._tooltip=null,L.DomEvent.off(this._container,"keyup",this._cancelDrawing,this))},setOptions:function(t){L.setOptions(this,t)},_fireCreatedEvent:function(t){this._map.fire(L.Draw.Event.CREATED,{layer:t,layerType:this.type})},_cancelDrawing:function(t){27===t.keyCode&&(this._map.fire("draw:canceled",{layerType:this.type}),this.disable())}}),L.Draw.Polyline=L.Draw.Feature.extend({statics:{TYPE:"polyline"},Poly:L.Polyline,options:{allowIntersection:!0,repeatMode:!1,drawError:{color:"#b00b00",timeout:2500},icon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon"}),touchIcon:new L.DivIcon({iconSize:new L.Point(20,20),className:"leaflet-div-icon leaflet-editing-icon leaflet-touch-icon"}),guidelineDistance:20,maxGuideLineLength:4e3,shapeOptions:{stroke:!0,color:"#3388ff",weight:4,opacity:.5,fill:!1,clickable:!0},metric:!0,feet:!0,nautic:!1,showLength:!0,zIndexOffset:2e3,factor:1,maxPoints:0},initialize:function(t,e){L.Browser.touch&&(this.options.icon=this.options.touchIcon),this.options.drawError.message=L.drawLocal.draw.handlers.polyline.error,e&&e.drawError&&(e.drawError=L.Util.extend({},this.options.drawError,e.drawError)),this.type=L.Draw.Polyline.TYPE,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._markers=[],this._markerGroup=new L.LayerGroup,this._map.addLayer(this._markerGroup),this._poly=new L.Polyline([],this.options.shapeOptions),this._tooltip.updateContent(this._getTooltipText()),this._mouseMarker||(this._mouseM Line truncated
className:"leaflet-div-icon leaflet-editing-icon leaflet-edit-resize"}),touchMoveIcon:new L.DivIcon({iconSize:new L.Point(20,20),className:"leaflet-div-icon leaflet-editing-icon leaflet-edit-move leaflet-touch-icon"}),touchResizeIcon:new L.DivIcon({iconSize:new L.Point(20,20),className:"leaflet-div-icon leaflet-editing-icon leaflet-edit-resize leaflet-touch-icon"})},initialize:function(t,e){L.Browser.touch&&(this.options.moveIcon=this.options.touchMoveIcon,this.options.resizeIcon=this.options.touchResizeIcon),this._shape=t,L.Util.setOptions(this,e)},addHooks:function(){var t=this._shape;this._shape._map&&(this._map=this._shape._map,t.setStyle(t.options.editing),t._map&&(this._map=t._map,this._markerGroup||this._initMarkers(),this._map.addLayer(this._markerGroup)))},removeHooks:function(){var t=this._shape;if(t.setStyle(t.options.original),t._map){this._unbindMarker(this._moveMarker);for(var e=0,i=this._resizeMarkers.length;e<i;e++)this._unbindMarker(this._resizeMarkers[e]);this._resizeMarkers=null,this._map.removeLayer(this._markerGroup),delete this._markerGroup}this._map=null},updateMarkers:function(){this._markerGroup.clearLayers(),this._initMarkers()},_initMarkers:function(){this._markerGroup||(this._markerGroup=new L.LayerGroup),this._createMoveMarker(),this._createResizeMarker()},_createMoveMarker:function(){},_createResizeMarker:function(){},_createMarker:function(t,e){var i=new L.Marker.Touch(t,{draggable:!0,icon:e,zIndexOffset:10});return this._bindMarker(i),this._markerGroup.addLayer(i),i},_bindMarker:function(t){t.on("dragstart",this._onMarkerDragStart,this).on("drag",this._onMarkerDrag,this).on("dragend",this._onMarkerDragEnd,this).on("touchstart",this._onTouchStart,this).on("touchmove",this._onTouchMove,this).on("MSPointerMove",this._onTouchMove,this).on("touchend",this._onTouchEnd,this).on("MSPointerUp",this._onTouchEnd,this)},_unbindMarker:function(t){t.off("dragstart",this._onMarkerDragStart,this).off("drag",this._onMarkerDrag,this).off("dragend",this._onMarkerDragEnd,this).off("touchstart",this._onTouchStart,this).off("touchmove",this._onTouchMove,this).off("MSPointerMove",this._onTouchMove,this).off("touchend",this._onTouchEnd,this).off("MSPointerUp",this._onTouchEnd,this)},_onMarkerDragStart:function(t){t.target.setOpacity(0),this._shape.fire("editstart")},_fireEdit:function(){this._shape.edited=!0,this._shape.fire("edit")},_onMarkerDrag:function(t){var e=t.target,i=e.getLatLng();e===this._moveMarker?this._move(i):this._resize(i),this._shape.redraw(),this._shape.fire("editdrag")},_onMarkerDragEnd:function(t){t.target.setOpacity(1),this._fireEdit()},_onTouchStart:function(t){if(L.Edit.SimpleShape.prototype._onMarkerDragStart.call(this,t),"function"==typeof this._getCorners){var e=this._getCorners(),i=t.target,o=i._cornerIndex;i.setOpacity(0),this._oppositeCorner=e[(o+2)%4],this._toggleCornerMarkers(0,o)}this._shape.fire("editstart")},_onTouchMove:function(t){var e=this._map.mouseEventToLayerPoint(t.originalEvent.touches[0]),i=this._map.layerPointToLatLng(e);return t.target===this._moveMarker?this._move(i):this._resize(i),this._shape.redraw(),!1},_onTouchEnd:function(t){t.target.setOpacity(1),this.updateMarkers(),this._fireEdit()},_move:function(){},_resize:function(){}}),L.Edit=L.Edit||{},L.Edit.Rectangle=L.Edit.SimpleShape.extend({_createMoveMarker:function(){var t=this._shape.getBounds(),e=t.getCenter();this._moveMarker=this._createMarker(e,this.options.moveIcon)},_createResizeMarker:function(){var t=this._getCorners();this._resizeMarkers=[];for(var e=0,i=t.length;e<i;e++)this._resizeMarkers.push(this._createMarker(t[e],this.options.resizeIcon)),this._resizeMarkers[e]._cornerIndex=e},_onMarkerDragStart:function(t){L.Edit.SimpleShape.prototype._onMarkerDragStart.call(this,t);var e=this._getCorners(),i=t.target,o=i._cornerIndex;this._oppositeCorner=e[(o+2)%4],this._toggleCornerMarkers(0,o)},_onMarkerDragEnd:function(t){var e,i,o=t.target;o===this._moveMarker&&(e=this._shape.getBounds(),i=e.getCenter(),o.setLatLng(i)),this._toggleCornerMarkers(1),this._repositionCornerMarkers(),L.Edit.SimpleShape.prototype._onMarkerDragEnd.call(this,t)},_move:function(t){for(var e,i=this._shape._defaultShape?this._shape._defaultShape():this._shape.getLatLngs(),o=this._shape.getBounds(),a=o.getCenter(),n=[],s=0,r=i.length;s<r;s++)e=[i[s].lat-a.lat,i[s].lng-a.lng],n.push([t.lat+e[0],t.lng+e[1]]);this._shape.setLatLngs(n),this._repositionCornerMarkers(),this._map.fire(L.Draw.Event.EDITMOVE,{layer:this._shape})},_resize:function(t){var e;this._shape.setBounds(L.latLngBounds(t,this._oppositeCorner)),e=this._shape.getBounds(),this._moveMarker.setLatLng(e.getCenter()),this._map.fire(L.Draw.Event.EDITRESIZE,{layer:this._shape})},_getCorners:function(){var t=this._shape.getBounds();return[t.getNorthWest(),t.getNorthEast(),t.getSouthEast(),t.getSouthWest()]},_toggleCornerMarkers:function(t){for(var e=0,i=this._resizeMarkers.length;e<i;e++)this._resizeMarkers[e].setOpacity(t)},_repositionCornerMarkers:function(){for( Line truncated
this._selectedPathOptions&&(e instanceof L.Marker?this._toggleMarkerHighlight(e):(e.setStyle(e.options.previousOptions),delete e.options.previousOptions)),e instanceof L.Marker?(e.dragging.disable(),e.off("dragend",this._onMarkerDragEnd,this).off("touchmove",this._onTouchMove,this).off("MSPointerMove",this._onTouchMove,this).off("touchend",this._onMarkerDragEnd,this).off("MSPointerUp",this._onMarkerDragEnd,this)):e.editing.disable()},_onMouseMove:function(t){this._tooltip.updatePosition(t.latlng)},_onMarkerDragEnd:function(t){var e=t.target;e.edited=!0,this._map.fire(L.Draw.Event.EDITMOVE,{layer:e})},_onTouchMove:function(t){var e=t.originalEvent.changedTouches[0],i=this._map.mouseEventToLayerPoint(e),o=this._map.layerPointToLatLng(i);t.target.setLatLng(o)},_hasAvailableLayers:function(){return 0!==this._featureGroup.getLayers().length}}),L.EditToolbar.Delete=L.Handler.extend({statics:{TYPE:"remove"},initialize:function(t,e){if(L.Handler.prototype.initialize.call(this,t),L.Util.setOptions(this,e),this._deletableLayers=this.options.featureGroup,!(this._deletableLayers instanceof L.FeatureGroup))throw new Error("options.featureGroup must be a L.FeatureGroup");this.type=L.EditToolbar.Delete.TYPE;var i=L.version.split(".");1===parseInt(i[0],10)&&parseInt(i[1],10)>=2?L.EditToolbar.Delete.include(L.Evented.prototype):L.EditToolbar.Delete.include(L.Mixin.Events)},enable:function(){!this._enabled&&this._hasAvailableLayers()&&(this.fire("enabled",{handler:this.type}),this._map.fire(L.Draw.Event.DELETESTART,{handler:this.type}),L.Handler.prototype.enable.call(this),this._deletableLayers.on("layeradd",this._enableLayerDelete,this).on("layerremove",this._disableLayerDelete,this))},disable:function(){this._enabled&&(this._deletableLayers.off("layeradd",this._enableLayerDelete,this).off("layerremove",this._disableLayerDelete,this),L.Handler.prototype.disable.call(this),this._map.fire(L.Draw.Event.DELETESTOP,{handler:this.type}),this.fire("disabled",{handler:this.type}))},addHooks:function(){var t=this._map;t&&(t.getContainer().focus(),this._deletableLayers.eachLayer(this._enableLayerDelete,this),this._deletedLayers=new L.LayerGroup,this._tooltip=new L.Draw.Tooltip(this._map),this._tooltip.updateContent({text:L.drawLocal.edit.handlers.remove.tooltip.text}),this._map.on("mousemove",this._onMouseMove,this))},removeHooks:function(){this._map&&(this._deletableLayers.eachLayer(this._disableLayerDelete,this),this._deletedLayers=null,this._tooltip.dispose(),this._tooltip=null,this._map.off("mousemove",this._onMouseMove,this))},revertLayers:function(){this._deletedLayers.eachLayer(function(t){this._deletableLayers.addLayer(t),t.fire("revert-deleted",{layer:t})},this)},save:function(){this._map.fire(L.Draw.Event.DELETED,{layers:this._deletedLayers})},removeAllLayers:function(){this._deletableLayers.eachLayer(function(t){this._removeLayer({layer:t})},this),this.save()},_enableLayerDelete:function(t){(t.layer||t.target||t).on("click",this._removeLayer,this)},_disableLayerDelete:function(t){var e=t.layer||t.target||t;e.off("click",this._removeLayer,this),this._deletedLayers.removeLayer(e)},_removeLayer:function(t){var e=t.layer||t.target||t;this._deletableLayers.removeLayer(e),this._deletedLayers.addLayer(e),e.fire("deleted")},_onMouseMove:function(t){this._tooltip.updatePosition(t.latlng)},_hasAvailableLayers:function(){return 0!==this._deletableLayers.getLayers().length}})}(window,document);
\ No newline at end of file
-942
View File
@@ -1,942 +0,0 @@
#!/usr/bin/env node
/* eslint-disable */
//prettier-ignore
(()=>{var DGe=Object.create;var dU=Object.defineProperty;var PGe=Object.getOwnPropertyDescriptor;var bGe=Object.getOwnPropertyNames;var xGe=Object.getPrototypeOf,kGe=Object.prototype.hasOwnProperty;var Ie=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,r)=>(typeof require<"u"?require:e)[r]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var Ze=(t,e)=>()=>(t&&(e=t(t=0)),e);var _=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),Vt=(t,e)=>{for(var r in e)dU(t,r,{get:e[r],enumerable:!0})},QGe=(t,e,r,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of bGe(e))!kGe.call(t,a)&&a!==r&&dU(t,a,{get:()=>e[a],enumerable:!(s=PGe(e,a))||s.enumerable});return t};var ut=(t,e,r)=>(r=t!=null?DGe(xGe(t)):{},QGe(e||!t||!t.__esModule?dU(r,"default",{value:t,enumerable:!0}):r,t));var fi={};Vt(fi,{SAFE_TIME:()=>HX,S_IFDIR:()=>Jb,S_IFLNK:()=>Kb,S_IFMT:()=>Mf,S_IFREG:()=>N2});var Mf,Jb,N2,Kb,HX,jX=Ze(()=>{Mf=61440,Jb=16384,N2=32768,Kb=40960,HX=456789e3});var or={};Vt(or,{EBADF:()=>Mo,EBUSY:()=>RGe,EEXIST:()=>MGe,EINVAL:()=>FGe,EISDIR:()=>LGe,ENOENT:()=>NGe,ENOSYS:()=>TGe,ENOTDIR:()=>OGe,ENOTEMPTY:()=>_Ge,EOPNOTSUPP:()=>HGe,EROFS:()=>UGe,ERR_DIR_CLOSED:()=>mU});function Cc(t,e){return Object.assign(new Error(`${t}: ${e}`),{code:t})}function RGe(t){return Cc("EBUSY",t)}function TGe(t,e){return Cc("ENOSYS",`${t}, ${e}`)}function FGe(t){return Cc("EINVAL",`invalid argument, ${t}`)}function Mo(t){return Cc("EBADF",`bad file descriptor, ${t}`)}function NGe(t){return Cc("ENOENT",`no such file or directory, ${t}`)}function OGe(t){return Cc("ENOTDIR",`not a directory, ${t}`)}function LGe(t){return Cc("EISDIR",`illegal operation on a directory, ${t}`)}function MGe(t){return Cc("EEXIST",`file already exists, ${t}`)}function UGe(t){return Cc("EROFS",`read-only filesystem, ${t}`)}function _Ge(t){return Cc("ENOTEMPTY",`directory not empty, ${t}`)}function HGe(t){return Cc("EOPNOTSUPP",`operation not supported, ${t}`)}function mU(){return Cc("ERR_DIR_CLOSED","Directory handle was closed")}var zb=Ze(()=>{});var $a={};Vt($a,{BigIntStatsEntry:()=>iE,DEFAULT_MODE:()=>IU,DirEntry:()=>yU,StatEntry:()=>nE,areStatsEqual:()=>CU,clearStats:()=>Zb,convertToBigIntStats:()=>GGe,makeDefaultStats:()=>GX,makeEmptyStats:()=>jGe});function GX(){return new nE}function jGe(){return Zb(GX())}function Zb(t){for(let e in t)if(Object.hasOwn(t,e)){let r=t[e];typeof r=="number"?t[e]=0:typeof r=="bigint"?t[e]=BigInt(0):EU.types.isDate(r)&&(t[e]=new Date(0))}return t}function GGe(t){let e=new iE;for(let r in t)if(Object.hasOwn(t,r)){let s=t[r];typeof s=="number"?e[r]=BigInt(s):EU.types.isDate(s)&&(e[r]=new Date(s))}return e.atimeNs=e.atimeMs*BigInt(1e6),e.mtimeNs=e.mtimeMs*BigInt(1e6),e.ctimeNs=e.ctimeMs*BigInt(1e6),e.birthtimeNs=e.birthtimeMs*BigInt(1e6),e}function CU(t,e){if(t.atimeMs!==e.atimeMs||t.birthtimeMs!==e.birthtimeMs||t.blksize!==e.blksize||t.blocks!==e.blocks||t.ctimeMs!==e.ctimeMs||t.dev!==e.dev||t.gid!==e.gid||t.ino!==e.ino||t.isBlockDevice()!==e.isBlockDevice()||t.isCharacterDevice()!==e.isCharacterDevice()||t.isDirectory()!==e.isDirectory()||t.isFIFO()!==e.isFIFO()||t.isFile()!==e.isFile()||t.isSocket()!==e.isSocket()||t.isSymbolicLink()!==e.isSymbolicLink()||t.mode!==e.mode||t.mtimeMs!==e.mtimeMs||t.nlink!==e.nlink||t.rdev!==e.rdev||t.size!==e.size||t.uid!==e.uid)return!1;let r=t,s=e;return!(r.atimeNs!==s.atimeNs||r.mtimeNs!==s.mtimeNs||r.ctimeNs!==s.ctimeNs||r.birthtimeNs!==s.birthtimeNs)}var EU,IU,yU,nE,iE,wU=Ze(()=>{EU=ut(Ie("util")),IU=33188,yU=class{constructor(){this.name="";this.path="";this.mode=0}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&61440)===16384}isFIFO(){return!1}isFile(){return(this.mode&61440)===32768}isSocket(){return!1}isSymbolicLink(){return(this.mode&61440)===40960}},nE=class{constructor(){this.uid=0;this.gid=0;this.size=0;this.blksize=0;this.atimeMs=0;this.mtimeMs=0;this.ctimeMs=0;this.birthtimeMs=0;this.atime=new Date(0);this.mtime=new Date(0);this.ctime=new Date(0);this.birthtime=new Date(0);this.dev=0;this.ino=0;this.mode=IU;this.nlink=1;this.rdev=0;this.blocks=1}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&61440)===16384}isFIFO(){return!1}isFile(){return(this.mode&61440)===32768}isSocket(){return!1}isSymbolicLink(){return(this.mode&61440)===40960}},iE=class{constructor(){this.uid=BigInt(0);this.gid=BigInt(0);this.size=BigInt(0);this.blksize=BigInt(0);this.atimeMs=BigInt(0);this.mtimeMs=BigInt(0);this.ctimeMs=BigInt(0);this.birthtimeMs=BigInt(0);this.atimeNs=BigInt(0);this.mtimeNs=BigInt(0);this.ctimeNs=BigInt(0);this.birthtimeNs=BigInt(0);this.atime=new Date(0);this.mtime=new Date(0);this.ctime=new Date(0);this.birthtime=new Date(0);this.dev=BigInt(0);this.ino=BigInt(0);this.mode=BigInt(IU);this.nlink=BigInt(1);this.rdev=BigInt(0);this.blocks=BigInt(1)}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){reLine truncated
`).length,s=e.length-r;return r>s?`\r
`:`
`}function Ed(t,e){return e.replace(/\r?\n/g,rqe(t))}var XX,$X,mp,Uf,Id=Ze(()=>{XX=Ie("crypto"),$X=Ie("os");SU();el();mp=class{constructor(e){this.pathUtils=e}async*genTraversePromise(e,{stableSort:r=!1}={}){let s=[e];for(;s.length>0;){let a=s.shift();if((await this.lstatPromise(a)).isDirectory()){let c=await this.readdirPromise(a);if(r)for(let f of c.sort())s.push(this.pathUtils.join(a,f));else throw new Error("Not supported")}else yield a}}async checksumFilePromise(e,{algorithm:r="sha512"}={}){let s=await this.openPromise(e,"r");try{let n=Buffer.allocUnsafeSlow(65536),c=(0,XX.createHash)(r),f=0;for(;(f=await this.readPromise(s,n,0,65536))!==0;)c.update(f===65536?n:n.slice(0,f));return c.digest("hex")}finally{await this.closePromise(s)}}async removePromise(e,{recursive:r=!0,maxRetries:s=5}={}){let a;try{a=await this.lstatPromise(e)}catch(n){if(n.code==="ENOENT")return;throw n}if(a.isDirectory()){if(r){let n=await this.readdirPromise(e);await Promise.all(n.map(c=>this.removePromise(this.pathUtils.resolve(e,c))))}for(let n=0;n<=s;n++)try{await this.rmdirPromise(e);break}catch(c){if(c.code!=="EBUSY"&&c.code!=="ENOTEMPTY")throw c;n<s&&await new Promise(f=>setTimeout(f,n*100))}}else await this.unlinkPromise(e)}removeSync(e,{recursive:r=!0}={}){let s;try{s=this.lstatSync(e)}catch(a){if(a.code==="ENOENT")return;throw a}if(s.isDirectory()){if(r)for(let a of this.readdirSync(e))this.removeSync(this.pathUtils.resolve(e,a));this.rmdirSync(e)}else this.unlinkSync(e)}async mkdirpPromise(e,{chmod:r,utimes:s}={}){if(e=this.resolve(e),e===this.pathUtils.dirname(e))return;let a=e.split(this.pathUtils.sep),n;for(let c=2;c<=a.length;++c){let f=a.slice(0,c).join(this.pathUtils.sep);if(!this.existsSync(f)){try{await this.mkdirPromise(f)}catch(p){if(p.code==="EEXIST")continue;throw p}if(n??=f,r!=null&&await this.chmodPromise(f,r),s!=null)await this.utimesPromise(f,s[0],s[1]);else{let p=await this.statPromise(this.pathUtils.dirname(f));await this.utimesPromise(f,p.atime,p.mtime)}}}return n}mkdirpSync(e,{chmod:r,utimes:s}={}){if(e=this.resolve(e),e===this.pathUtils.dirname(e))return;let a=e.split(this.pathUtils.sep),n;for(let c=2;c<=a.length;++c){let f=a.slice(0,c).join(this.pathUtils.sep);if(!this.existsSync(f)){try{this.mkdirSync(f)}catch(p){if(p.code==="EEXIST")continue;throw p}if(n??=f,r!=null&&this.chmodSync(f,r),s!=null)this.utimesSync(f,s[0],s[1]);else{let p=this.statSync(this.pathUtils.dirname(f));this.utimesSync(f,p.atime,p.mtime)}}}return n}async copyPromise(e,r,{baseFs:s=this,overwrite:a=!0,stableSort:n=!1,stableTime:c=!1,linkStrategy:f=null}={}){return await YX(this,e,s,r,{overwrite:a,stableSort:n,stableTime:c,linkStrategy:f})}copySync(e,r,{baseFs:s=this,overwrite:a=!0}={}){let n=s.lstatSync(r),c=this.existsSync(e);if(n.isDirectory()){this.mkdirpSync(e);let p=s.readdirSync(r);for(let h of p)this.copySync(this.pathUtils.join(e,h),s.pathUtils.join(r,h),{baseFs:s,overwrite:a})}else if(n.isFile()){if(!c||a){c&&this.removeSync(e);let p=s.readFileSync(r);this.writeFileSync(e,p)}}else if(n.isSymbolicLink()){if(!c||a){c&&this.removeSync(e);let p=s.readlinkSync(r);this.symlinkSync(Xb(this.pathUtils,p),e)}}else throw new Error(`Unsupported file type (file: ${r}, mode: 0o${n.mode.toString(8).padStart(6,"0")})`);let f=n.mode&511;this.chmodSync(e,f)}async changeFilePromise(e,r,s={}){return Buffer.isBuffer(r)?this.changeFileBufferPromise(e,r,s):this.changeFileTextPromise(e,r,s)}async changeFileBufferPromise(e,r,{mode:s}={}){let a=Buffer.alloc(0);try{a=await this.readFilePromise(e)}catch{}Buffer.compare(a,r)!==0&&await this.writeFilePromise(e,r,{mode:s})}async changeFileTextPromise(e,r,{automaticNewlines:s,mode:a}={}){let n="";try{n=await this.readFilePromise(e,"utf8")}catch{}let c=s?Ed(n,r):r;n!==c&&await this.writeFilePromise(e,c,{mode:a})}changeFileSync(e,r,s={}){return Buffer.isBuffer(r)?this.changeFileBufferSync(e,r,s):this.changeFileTextSync(e,r,s)}changeFileBufferSync(e,r,{mode:s}={}){let a=Buffer.alloc(0);try{a=this.readFileSync(e)}catch{}Buffer.compare(a,r)!==0&&this.writeFileSync(e,r,{mode:s})}changeFileTextSync(e,r,{automaticNewlines:s=!1,mode:a}={}){let n="";try{n=this.readFileSync(e,"utf8")}catch{}let c=s?Ed(n,r):r;n!==c&&this.writeFileSync(e,c,{mode:a})}async movePromise(e,r){try{await this.renamePromise(e,r)}catch(s){if(s.code==="EXDEV")await this.copyPromise(r,e),await this.removePromise(e);else throw s}}moveSync(e,r){try{this.renameSync(e,r)}catch(s){if(s.code==="EXDEV")this.copySync(r,e),this.removeSync(e);else throw s}}async lockPromise(e,r){let s=`${e}.flock`,a=1e3/60,n=Date.now(),c=null,f=async()=>{let p;try{[p]=await this.readJsonPromise(s)}catch{return Date.now()-n<500}try{return process.kill(p,0),!0}catch{return!1}};for(;c===null;)try{c=await this.openPromise(s,"wx")}catch(p){if(p.code==="EEXIST"){if(!await f())try{await this.unlinkPromise(s);continue}catch{}if(Date.now()-n<60*1e3)await new Promise(h=>setTimeout(h,a));else throw new Error(`Couldn't acquire a lock in a reasonable time (via ${s})`)}else throw Line truncated
`)}writeJsonSync(e,r,{compact:s=!1}={}){let a=s?0:2;return this.writeFileSync(e,`${JSON.stringify(r,null,a)}
`)}async preserveTimePromise(e,r){let s=await this.lstatPromise(e),a=await r();typeof a<"u"&&(e=a),await this.lutimesPromise(e,s.atime,s.mtime)}async preserveTimeSync(e,r){let s=this.lstatSync(e),a=r();typeof a<"u"&&(e=a),this.lutimesSync(e,s.atime,s.mtime)}},Uf=class extends mp{constructor(){super(J)}}});var _s,yp=Ze(()=>{Id();_s=class extends mp{getExtractHint(e){return this.baseFs.getExtractHint(e)}resolve(e){return this.mapFromBase(this.baseFs.resolve(this.mapToBase(e)))}getRealPath(){return this.mapFromBase(this.baseFs.getRealPath())}async openPromise(e,r,s){return this.baseFs.openPromise(this.mapToBase(e),r,s)}openSync(e,r,s){return this.baseFs.openSync(this.mapToBase(e),r,s)}async opendirPromise(e,r){return Object.assign(await this.baseFs.opendirPromise(this.mapToBase(e),r),{path:e})}opendirSync(e,r){return Object.assign(this.baseFs.opendirSync(this.mapToBase(e),r),{path:e})}async readPromise(e,r,s,a,n){return await this.baseFs.readPromise(e,r,s,a,n)}readSync(e,r,s,a,n){return this.baseFs.readSync(e,r,s,a,n)}async writePromise(e,r,s,a,n){return typeof r=="string"?await this.baseFs.writePromise(e,r,s):await this.baseFs.writePromise(e,r,s,a,n)}writeSync(e,r,s,a,n){return typeof r=="string"?this.baseFs.writeSync(e,r,s):this.baseFs.writeSync(e,r,s,a,n)}async closePromise(e){return this.baseFs.closePromise(e)}closeSync(e){this.baseFs.closeSync(e)}createReadStream(e,r){return this.baseFs.createReadStream(e!==null?this.mapToBase(e):e,r)}createWriteStream(e,r){return this.baseFs.createWriteStream(e!==null?this.mapToBase(e):e,r)}async realpathPromise(e){return this.mapFromBase(await this.baseFs.realpathPromise(this.mapToBase(e)))}realpathSync(e){return this.mapFromBase(this.baseFs.realpathSync(this.mapToBase(e)))}async existsPromise(e){return this.baseFs.existsPromise(this.mapToBase(e))}existsSync(e){return this.baseFs.existsSync(this.mapToBase(e))}accessSync(e,r){return this.baseFs.accessSync(this.mapToBase(e),r)}async accessPromise(e,r){return this.baseFs.accessPromise(this.mapToBase(e),r)}async statPromise(e,r){return this.baseFs.statPromise(this.mapToBase(e),r)}statSync(e,r){return this.baseFs.statSync(this.mapToBase(e),r)}async fstatPromise(e,r){return this.baseFs.fstatPromise(e,r)}fstatSync(e,r){return this.baseFs.fstatSync(e,r)}lstatPromise(e,r){return this.baseFs.lstatPromise(this.mapToBase(e),r)}lstatSync(e,r){return this.baseFs.lstatSync(this.mapToBase(e),r)}async fchmodPromise(e,r){return this.baseFs.fchmodPromise(e,r)}fchmodSync(e,r){return this.baseFs.fchmodSync(e,r)}async chmodPromise(e,r){return this.baseFs.chmodPromise(this.mapToBase(e),r)}chmodSync(e,r){return this.baseFs.chmodSync(this.mapToBase(e),r)}async fchownPromise(e,r,s){return this.baseFs.fchownPromise(e,r,s)}fchownSync(e,r,s){return this.baseFs.fchownSync(e,r,s)}async chownPromise(e,r,s){return this.baseFs.chownPromise(this.mapToBase(e),r,s)}chownSync(e,r,s){return this.baseFs.chownSync(this.mapToBase(e),r,s)}async renamePromise(e,r){return this.baseFs.renamePromise(this.mapToBase(e),this.mapToBase(r))}renameSync(e,r){return this.baseFs.renameSync(this.mapToBase(e),this.mapToBase(r))}async copyFilePromise(e,r,s=0){return this.baseFs.copyFilePromise(this.mapToBase(e),this.mapToBase(r),s)}copyFileSync(e,r,s=0){return this.baseFs.copyFileSync(this.mapToBase(e),this.mapToBase(r),s)}async appendFilePromise(e,r,s){return this.baseFs.appendFilePromise(this.fsMapToBase(e),r,s)}appendFileSync(e,r,s){return this.baseFs.appendFileSync(this.fsMapToBase(e),r,s)}async writeFilePromise(e,r,s){return this.baseFs.writeFilePromise(this.fsMapToBase(e),r,s)}writeFileSync(e,r,s){return this.baseFs.writeFileSync(this.fsMapToBase(e),r,s)}async unlinkPromise(e){return this.baseFs.unlinkPromise(this.mapToBase(e))}unlinkSync(e){return this.baseFs.unlinkSync(this.mapToBase(e))}async utimesPromise(e,r,s){return this.baseFs.utimesPromise(this.mapToBase(e),r,s)}utimesSync(e,r,s){return this.baseFs.utimesSync(this.mapToBase(e),r,s)}async lutimesPromise(e,r,s){return this.baseFs.lutimesPromise(this.mapToBase(e),r,s)}lutimesSync(e,r,s){return this.baseFs.lutimesSync(this.mapToBase(e),r,s)}async mkdirPromise(e,r){return this.baseFs.mkdirPromise(this.mapToBase(e),r)}mkdirSync(e,r){return this.baseFs.mkdirSync(this.mapToBase(e),r)}async rmdirPromise(e,r){return this.baseFs.rmdirPromise(this.mapToBase(e),r)}rmdirSync(e,r){return this.baseFs.rmdirSync(this.mapToBase(e),r)}async rmPromise(e,r){return this.baseFs.rmPromise(this.mapToBase(e),r)}rmSync(e,r){return this.baseFs.rmSync(this.mapToBase(e),r)}async linkPromise(e,r){return this.baseFs.linkPromise(this.mapToBase(e),this.mapToBase(r))}linkSync(e,r){return this.baseFs.linkSync(this.mapToBase(e),this.mapToBase(r))}async symlinkPromise(e,r,s){let a=this.mapToBase(r);if(this.pathUtils.isAbsolute(e))return this.baseFs.symlinkPromise(this.mapToBase(e),a,s);let n=this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(r),e)),c=this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(a),n);return this.baseFs.symlinkP Line truncated
`,RA=ur(`\\
`,!1),TA=function(){return""},oa="\\",aa=ur("\\",!1),FA=/^[\\$"`]/,gr=Ki(["\\","$",'"',"`"],!1,!1),Bo=function(O){return O},Me="\\a",cu=ur("\\a",!1),Cr=function(){return"a"},pf="\\b",NA=ur("\\b",!1),OA=function(){return"\b"},uu=/^[Ee]/,fu=Ki(["E","e"],!1,!1),oc=function(){return"\x1B"},ve="\\f",Nt=ur("\\f",!1),ac=function(){return"\f"},Oi="\\n",no=ur("\\n",!1),Tt=function(){return`
`},xn="\\r",la=ur("\\r",!1),ji=function(){return"\r"},Li="\\t",Na=ur("\\t",!1),dn=function(){return" "},Kn="\\v",Au=ur("\\v",!1),yh=function(){return"\v"},Oa=/^[\\'"?]/,La=Ki(["\\","'",'"',"?"],!1,!1),Ma=function(O){return String.fromCharCode(parseInt(O,16))},$e="\\x",Ua=ur("\\x",!1),hf="\\u",lc=ur("\\u",!1),wn="\\U",ca=ur("\\U",!1),LA=function(O){return String.fromCodePoint(parseInt(O,16))},MA=/^[0-7]/,ua=Ki([["0","7"]],!1,!1),Bl=/^[0-9a-fA-f]/,Mt=Ki([["0","9"],["a","f"],["A","f"]],!1,!1),kn=yf(),fa="{}",Ha=ur("{}",!1),rs=function(){return"{}"},cc="-",pu=ur("-",!1),uc="+",ja=ur("+",!1),Mi=".",Is=ur(".",!1),vl=function(O,K,re){return{type:"number",value:(O==="-"?-1:1)*parseFloat(K.join("")+"."+re.join(""))}},gf=function(O,K){return{type:"number",value:(O==="-"?-1:1)*parseInt(K.join(""))}},fc=function(O){return{type:"variable",...O}},wi=function(O){return{type:"variable",name:O}},Qn=function(O){return O},Ac="*",Ke=ur("*",!1),st="/",St=ur("/",!1),lr=function(O,K,re){return{type:K==="*"?"multiplication":"division",right:re}},te=function(O,K){return K.reduce((re,de)=>({left:re,...de}),O)},Ee=function(O,K,re){return{type:K==="+"?"addition":"subtraction",right:re}},Oe="$((",dt=ur("$((",!1),Et="))",Pt=ur("))",!1),tr=function(O){return O},An="$(",li=ur("$(",!1),Gi=function(O){return O},Rn="${",Ga=ur("${",!1),my=":-",X1=ur(":-",!1),vo=function(O,K){return{name:O,defaultValue:K}},yy=":-}",Eh=ur(":-}",!1),$1=function(O){return{name:O,defaultValue:[]}},So=":+",Ih=ur(":+",!1),Ch=function(O,K){return{name:O,alternativeValue:K}},hu=":+}",wh=ur(":+}",!1),Fg=function(O){return{name:O,alternativeValue:[]}},Ng=function(O){return{name:O}},Og="$",Ey=ur("$",!1),df=function(O){return e.isGlobPattern(O)},Do=function(O){return O},Sl=/^[a-zA-Z0-9_]/,Bh=Ki([["a","z"],["A","Z"],["0","9"],"_"],!1,!1),Lg=function(){return By()},Dl=/^[$@*?#a-zA-Z0-9_\-]/,Pl=Ki(["$","@","*","?","#",["a","z"],["A","Z"],["0","9"],"_","-"],!1,!1),Iy=/^[()}<>$|&; \t"']/,UA=Ki(["(",")","}","<",">","$","|","&",";"," "," ",'"',"'"],!1,!1),Cy=/^[<>&; \t"']/,wy=Ki(["<",">","&",";"," "," ",'"',"'"],!1,!1),_A=/^[ \t]/,HA=Ki([" "," "],!1,!1),Y=0,xt=0,jA=[{line:1,column:1}],Po=0,mf=[],yt=0,gu;if("startRule"in e){if(!(e.startRule in s))throw new Error(`Can't start parsing from rule "`+e.startRule+'".');a=s[e.startRule]}function By(){return t.substring(xt,Y)}function Mg(){return Ef(xt,Y)}function e2(O,K){throw K=K!==void 0?K:Ef(xt,Y),GA([Ug(O)],t.substring(xt,Y),K)}function vh(O,K){throw K=K!==void 0?K:Ef(xt,Y),di(O,K)}function ur(O,K){return{type:"literal",text:O,ignoreCase:K}}function Ki(O,K,re){return{type:"class",parts:O,inverted:K,ignoreCase:re}}function yf(){return{type:"any"}}function qa(){return{type:"end"}}function Ug(O){return{type:"other",description:O}}function du(O){var K=jA[O],re;if(K)return K;for(re=O-1;!jA[re];)re--;for(K=jA[re],K={line:K.line,column:K.column};re<O;)t.charCodeAt(re)===10?(K.line++,K.column=1):K.column++,re++;return jA[O]=K,K}function Ef(O,K){var re=du(O),de=du(K);return{start:{offset:O,line:re.line,column:re.column},end:{offset:K,line:de.line,column:de.column}}}function wt(O){Y<Po||(Y>Po&&(Po=Y,mf=[]),mf.push(O))}function di(O,K){return new Bd(O,null,null,K)}function GA(O,K,re){return new Bd(Bd.buildMessage(O,K),O,K,re)}function Wa(){var O,K,re;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();return K!==r?(re=Aa(),re===r&&(re=null),re!==r?(xt=O,K=n(re),O=K):(Y=O,O=r)):(Y=O,O=r),O}function Aa(){var O,K,re,de,Je;if(O=Y,K=Sh(),K!==r){for(re=[],de=kt();de!==r;)re.push(de),de=kt();re!==r?(de=_g(),de!==r?(Je=Ya(),Je===r&&(Je=null),Je!==r?(xt=O,K=c(K,de,Je),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r)}else Y=O,O=r;if(O===r)if(O=Y,K=Sh(),K!==r){for(re=[],de=kt();de!==r;)re.push(de),de=kt();re!==r?(de=_g(),de===r&&(de=null),de!==r?(xt=O,K=f(K,de),O=K):(Y=O,O=r)):(Y=O,O=r)}else Y=O,O=r;return O}function Ya(){var O,K,re,de,Je;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r)if(re=Aa(),re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();de!==r?(xt=O,K=p(re),O=K):(Y=O,O=r)}else Y=O,O=r;else Y=O,O=r;return O}function _g(){var O;return t.charCodeAt(Y)===59?(O=h,Y++):(O=r,yt===0&&wt(E)),O===r&&(t.charCodeAt(Y)===38?(O=C,Y++):(O=r,yt===0&&wt(S))),O}function Sh(){var O,K,re;return O=Y,K=qA(),K!==r?(re=Hg(),re===r&&(re=null),re!==r?(xt=O,K=b(K,re),O=K):(Y=O,O=r)):(Y=O,O=r),O}function Hg(){var O,K,re,de,Je,At,dr;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r)if(re=vy(),re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();if(de!==r)if(Je=Sh(),Je!==r){for(At=[],dr=kt();dr!==r;)At.push(dr),dr=kt();At!==r?(xt=O,K=I(re,Je),O=K):(Y=O,O=r)}else Y=O,O=r;else Y=O,O=r}else Y=O,O=r;else Y=O,O=r;return O}function vy(){var O;return t.substr(Y,2)===T?(O=T,Y+=2):(O=r,yt===0&&wt(N)),O===r&&(t.substr(Y,2)===U?(O=U,Y+=2):(O=r,yt===0&&wt(W))),O}function qA(){var O,K,re;return O=Y,K=If(),K!==r?(re=jg(),re===r&&(re=null),re!==r?(xt=O,K=ee(K,re),O=K):(Y=O,O=r)):(Y=O,O=r),O}function jg(){var O,K,re,de,Je,At,dr;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r)Line truncated
`,"\\n"],["\r","\\r"],[" ","\\t"],["\v","\\v"],["\0","\\0"]]),Nqe=new Map([["\\","\\\\"],["$","\\$"],['"','\\"'],...Array.from(dee,([t,e])=>[t,`"$'${e}'"`])]),mee=t=>dee.get(t)??`\\x${t.charCodeAt(0).toString(16).padStart(2,"0")}`,Oqe=t=>Nqe.get(t)??`"$'${mee(t)}'"`});var Iee=_((Wkt,Eee)=>{"use strict";function Lqe(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function Sd(t,e,r,s){this.message=t,this.expected=e,this.found=r,this.location=s,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,Sd)}Lqe(Sd,Error);Sd.buildMessage=function(t,e){var r={literal:function(h){return'"'+a(h.text)+'"'},class:function(h){var E="",C;for(C=0;C<h.parts.length;C++)E+=h.parts[C]instanceof Array?n(h.parts[C][0])+"-"+n(h.parts[C][1]):n(h.parts[C]);return"["+(h.inverted?"^":"")+E+"]"},any:function(h){return"any character"},end:function(h){return"end of input"},other:function(h){return h.description}};function s(h){return h.charCodeAt(0).toString(16).toUpperCase()}function a(h){return h.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\0/g,"\\0").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/[\x00-\x0F]/g,function(E){return"\\x0"+s(E)}).replace(/[\x10-\x1F\x7F-\x9F]/g,function(E){return"\\x"+s(E)})}function n(h){return h.replace(/\\/g,"\\\\").replace(/\]/g,"\\]").replace(/\^/g,"\\^").replace(/-/g,"\\-").replace(/\0/g,"\\0").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/[\x00-\x0F]/g,function(E){return"\\x0"+s(E)}).replace(/[\x10-\x1F\x7F-\x9F]/g,function(E){return"\\x"+s(E)})}function c(h){return r[h.type](h)}function f(h){var E=new Array(h.length),C,S;for(C=0;C<h.length;C++)E[C]=c(h[C]);if(E.sort(),E.length>0){for(C=1,S=1;C<E.length;C++)E[C-1]!==E[C]&&(E[S]=E[C],S++);E.length=S}switch(E.length){case 1:return E[0];case 2:return E[0]+" or "+E[1];default:return E.slice(0,-1).join(", ")+", or "+E[E.length-1]}}function p(h){return h?'"'+a(h)+'"':"end of input"}return"Expected "+f(t)+" but "+p(e)+" found."};function Mqe(t,e){e=e!==void 0?e:{};var r={},s={resolution:Ne},a=Ne,n="/",c=ye("/",!1),f=function(Ue,x){return{from:Ue,descriptor:x}},p=function(Ue){return{descriptor:Ue}},h="@",E=ye("@",!1),C=function(Ue,x){return{fullName:Ue,description:x}},S=function(Ue){return{fullName:Ue}},b=function(){return Be()},I=/^[^\/@]/,T=Ae(["/","@"],!0,!1),N=/^[^\/]/,U=Ae(["/"],!0,!1),W=0,ee=0,ie=[{line:1,column:1}],ue=0,le=[],me=0,pe;if("startRule"in e){if(!(e.startRule in s))throw new Error(`Can't start parsing from rule "`+e.startRule+'".');a=s[e.startRule]}function Be(){return t.substring(ee,W)}function Ce(){return mt(ee,W)}function g(Ue,x){throw x=x!==void 0?x:mt(ee,W),Fe([De(Ue)],t.substring(ee,W),x)}function we(Ue,x){throw x=x!==void 0?x:mt(ee,W),rt(Ue,x)}function ye(Ue,x){return{type:"literal",text:Ue,ignoreCase:x}}function Ae(Ue,x,w){return{type:"class",parts:Ue,inverted:x,ignoreCase:w}}function se(){return{type:"any"}}function X(){return{type:"end"}}function De(Ue){return{type:"other",description:Ue}}function Te(Ue){var x=ie[Ue],w;if(x)return x;for(w=Ue-1;!ie[w];)w--;for(x=ie[w],x={line:x.line,column:x.column};w<Ue;)t.charCodeAt(w)===10?(x.line++,x.column=1):x.column++,w++;return ie[Ue]=x,x}function mt(Ue,x){var w=Te(Ue),P=Te(x);return{start:{offset:Ue,line:w.line,column:w.column},end:{offset:x,line:P.line,column:P.column}}}function j(Ue){W<ue||(W>ue&&(ue=W,le=[]),le.push(Ue))}function rt(Ue,x){return new Sd(Ue,null,null,x)}function Fe(Ue,x,w){return new Sd(Sd.buildMessage(Ue,x),Ue,x,w)}function Ne(){var Ue,x,w,P;return Ue=W,x=be(),x!==r?(t.charCodeAt(W)===47?(w=n,W++):(w=r,me===0&&j(c)),w!==r?(P=be(),P!==r?(ee=Ue,x=f(x,P),Ue=x):(W=Ue,Ue=r)):(W=Ue,Ue=r)):(W=Ue,Ue=r),Ue===r&&(Ue=W,x=be(),x!==r&&(ee=Ue,x=p(x)),Ue=x),Ue}function be(){var Ue,x,w,P;return Ue=W,x=Ve(),x!==r?(t.charCodeAt(W)===64?(w=h,W++):(w=r,me===0&&j(E)),w!==r?(P=it(),P!==r?(ee=Ue,x=C(x,P),Ue=x):(W=Ue,Ue=r)):(W=Ue,Ue=r)):(W=Ue,Ue=r),Ue===r&&(Ue=W,x=Ve(),x!==r&&(ee=Ue,x=S(x)),Ue=x),Ue}function Ve(){var Ue,x,w,P,y;return Ue=W,t.charCodeAt(W)===64?(x=h,W++):(x=r,me===0&&j(E)),x!==r?(w=ke(),w!==r?(t.charCodeAt(W)===47?(P=n,W++):(P=r,me===0&&j(c)),P!==r?(y=ke(),y!==r?(ee=Ue,x=b(),Ue=x):(W=Ue,Ue=r)):(W=Ue,Ue=r)):(W=Ue,Ue=r)):(W=Ue,Ue=r),Ue===r&&(Ue=W,x=ke(),x!==r&&(ee=Ue,x=b()),Ue=x),Ue}function ke(){var Ue,x,w;if(Ue=W,x=[],I.test(t.charAt(W))?(w=t.charAt(W),W++):(w=r,me===0&&j(T)),w!==r)for(;w!==r;)x.push(w),I.test(t.charAt(W))?(w=t.charAt(W),W++):(w=r,me===0&&j(T));else x=r;return x!==r&&(ee=Ue,x=b()),Ue=x,Ue}function it(){var Ue,x,w;if(Ue=W,x=[],N.test(t.charAt(W))?(w=t.charAt(W),W++):(w=r,me===0&&j(U)),w!==r)for(;w!==r;)x.push(w),N.test(t.charAt(W))?(w=t.charAt(W),W++):(w=r,me===0&&j(U));else x=r;return x!==r&&(ee=Ue,x=b()),Ue=x,Ue}if(pe=a(),pe!==r&&W===t.length)return pe;throw pe!==r&&W<t.length&&j(X()),Fe(le,ue<t.length?t.charAt(ue):null,ue<t.length?mt(ue,ue+1):mt(ue,ue))}Eee.exports={SyntaxError:Sd,parse:Mqe}});function px(t){let e=t.match(/^\*{1,Line truncated
\x85\u2028\u2029`.indexOf(this.buffer.charAt(a-1))===-1;)if(a-=1,this.position-a>r/2-1){s=" ... ",a+=5;break}for(n="",c=this.position;c<this.buffer.length&&`\0\r
\x85\u2028\u2029`.indexOf(this.buffer.charAt(c))===-1;)if(c+=1,c-this.position>r/2-1){n=" ... ",c-=5;break}return f=this.buffer.slice(a,c),See.repeat(" ",e)+s+f+n+`
`+See.repeat(" ",e+this.position-a+s.length)+"^"};WU.prototype.toString=function(e){var r,s="";return this.name&&(s+='in "'+this.name+'" '),s+="at line "+(this.line+1)+", column "+(this.column+1),e||(r=this.getSnippet(),r&&(s+=`:
`+r)),s};Dee.exports=WU});var Ss=_((zkt,xee)=>{"use strict";var bee=pE(),qqe=["kind","resolve","construct","instanceOf","predicate","represent","defaultStyle","styleAliases"],Wqe=["scalar","sequence","mapping"];function Yqe(t){var e={};return t!==null&&Object.keys(t).forEach(function(r){t[r].forEach(function(s){e[String(s)]=r})}),e}function Vqe(t,e){if(e=e||{},Object.keys(e).forEach(function(r){if(qqe.indexOf(r)===-1)throw new bee('Unknown option "'+r+'" is met in definition of "'+t+'" YAML type.')}),this.tag=t,this.kind=e.kind||null,this.resolve=e.resolve||function(){return!0},this.construct=e.construct||function(r){return r},this.instanceOf=e.instanceOf||null,this.predicate=e.predicate||null,this.represent=e.represent||null,this.defaultStyle=e.defaultStyle||null,this.styleAliases=Yqe(e.styleAliases||null),Wqe.indexOf(this.kind)===-1)throw new bee('Unknown kind "'+this.kind+'" is specified for "'+t+'" YAML type.')}xee.exports=Vqe});var bd=_((Zkt,Qee)=>{"use strict";var kee=Pd(),gx=pE(),Jqe=Ss();function YU(t,e,r){var s=[];return t.include.forEach(function(a){r=YU(a,e,r)}),t[e].forEach(function(a){r.forEach(function(n,c){n.tag===a.tag&&n.kind===a.kind&&s.push(c)}),r.push(a)}),r.filter(function(a,n){return s.indexOf(n)===-1})}function Kqe(){var t={scalar:{},sequence:{},mapping:{},fallback:{}},e,r;function s(a){t[a.kind][a.tag]=t.fallback[a.tag]=a}for(e=0,r=arguments.length;e<r;e+=1)arguments[e].forEach(s);return t}function hE(t){this.include=t.include||[],this.implicit=t.implicit||[],this.explicit=t.explicit||[],this.implicit.forEach(function(e){if(e.loadKind&&e.loadKind!=="scalar")throw new gx("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.")}),this.compiledImplicit=YU(this,"implicit",[]),this.compiledExplicit=YU(this,"explicit",[]),this.compiledTypeMap=Kqe(this.compiledImplicit,this.compiledExplicit)}hE.DEFAULT=null;hE.create=function(){var e,r;switch(arguments.length){case 1:e=hE.DEFAULT,r=arguments[0];break;case 2:e=arguments[0],r=arguments[1];break;default:throw new gx("Wrong number of arguments for Schema.create function")}if(e=kee.toArray(e),r=kee.toArray(r),!e.every(function(s){return s instanceof hE}))throw new gx("Specified list of super schemas (or a single Schema object) contains a non-Schema object.");if(!r.every(function(s){return s instanceof Jqe}))throw new gx("Specified list of YAML types (or a single Type object) contains a non-Type object.");return new hE({include:e,explicit:r})};Qee.exports=hE});var Tee=_((Xkt,Ree)=>{"use strict";var zqe=Ss();Ree.exports=new zqe("tag:yaml.org,2002:str",{kind:"scalar",construct:function(t){return t!==null?t:""}})});var Nee=_(($kt,Fee)=>{"use strict";var Zqe=Ss();Fee.exports=new Zqe("tag:yaml.org,2002:seq",{kind:"sequence",construct:function(t){return t!==null?t:[]}})});var Lee=_((eQt,Oee)=>{"use strict";var Xqe=Ss();Oee.exports=new Xqe("tag:yaml.org,2002:map",{kind:"mapping",construct:function(t){return t!==null?t:{}}})});var dx=_((tQt,Mee)=>{"use strict";var $qe=bd();Mee.exports=new $qe({explicit:[Tee(),Nee(),Lee()]})});var _ee=_((rQt,Uee)=>{"use strict";var e5e=Ss();function t5e(t){if(t===null)return!0;var e=t.length;return e===1&&t==="~"||e===4&&(t==="null"||t==="Null"||t==="NULL")}function r5e(){return null}function n5e(t){return t===null}Uee.exports=new e5e("tag:yaml.org,2002:null",{kind:"scalar",resolve:t5e,construct:r5e,predicate:n5e,represent:{canonical:function(){return"~"},lowercase:function(){return"null"},uppercase:function(){return"NULL"},camelcase:function(){return"Null"}},defaultStyle:"lowercase"})});var jee=_((nQt,Hee)=>{"use strict";var i5e=Ss();function s5e(t){if(t===null)return!1;var e=t.length;return e===4&&(t==="true"||t==="True"||t==="TRUE")||e===5&&(t==="false"||t==="False"||t==="FALSE")}function o5e(t){return t==="true"||t==="True"||t==="TRUE"}function a5e(t){return Object.prototype.toString.call(t)==="[object Boolean]"}Hee.exports=new i5e("tag:yaml.org,2002:bool",{kind:"scalar",resolve:s5e,construct:o5e,predicate:a5e,represent:{lowercase:function(t){return t?"true":"false"},uppercase:function(t){return t?"TRUE":"FALSE"},camelcase:function(t){return t?"True":"False"}},defaultStyle:"lowercase"})});var qee=_((iQt,Gee)=>{"use strict";var l5e=Pd(),c5e=Ss();function u5e(t){return 48<=t&&t<=57||65<=t&&t<=70||97<=t&&t<=102}function f5e(t){return 48<=t&&t<=55}function A5e(t){return 48<=t&&t<=57}function p5e(t){if(t===null)return!1;var e=t.length,r=0,s=!1,a;if(!e)return!1;if(a=t[r],(a==="-"||a==="+")&&(a=t[++r]),a==="0"){if(r+1===e)return!0;if(a=t[++r],a==="b"){for(r++;r<e;r++)if(a=t[r],a!=="_"){if(a!=="0"&&a!=="1")return!1;s=!0}return s&&a!=="_"}if(a==="x"){for(r++;r<e;r++)if(a=t[r],a!=="_"){if(!u5e(t.charCodeAt(r)))return!1;s=!0}return s&&a!=="_"}for(;r<e;r++)if(a=t[r],a!=="_"){if(!f5e(t.charCodeAt(r)))return!1;s=!0}return s&&a!=="_"}if(a==="_")return!1;for(;r<e;r++)if(a=t[r],a!=="_"){if(a===":")break;if(!A5e(t.charCodeAt(r)))return!1;s=!0}return!s||a==="_"?!1:a!==":"?!0:/^( Line truncated
\r`;function R5e(t){if(t===null)return!1;var e,r,s=0,a=t.length,n=KU;for(r=0;r<a;r++)if(e=n.indexOf(t.charAt(r)),!(e>64)){if(e<0)return!1;s+=6}return s%8===0}function T5e(t){var e,r,s=t.replace(/[\r\n=]/g,""),a=s.length,n=KU,c=0,f=[];for(e=0;e<a;e++)e%4===0&&e&&(f.push(c>>16&255),f.push(c>>8&255),f.push(c&255)),c=c<<6|n.indexOf(s.charAt(e));return r=a%4*6,r===0?(f.push(c>>16&255),f.push(c>>8&255),f.push(c&255)):r===18?(f.push(c>>10&255),f.push(c>>2&255)):r===12&&f.push(c>>4&255),xd?xd.from?xd.from(f):new xd(f):f}function F5e(t){var e="",r=0,s,a,n=t.length,c=KU;for(s=0;s<n;s++)s%3===0&&s&&(e+=c[r>>18&63],e+=c[r>>12&63],e+=c[r>>6&63],e+=c[r&63]),r=(r<<8)+t[s];return a=n%3,a===0?(e+=c[r>>18&63],e+=c[r>>12&63],e+=c[r>>6&63],e+=c[r&63]):a===2?(e+=c[r>>10&63],e+=c[r>>4&63],e+=c[r<<2&63],e+=c[64]):a===1&&(e+=c[r>>2&63],e+=c[r<<4&63],e+=c[64],e+=c[64]),e}function N5e(t){return xd&&xd.isBuffer(t)}nte.exports=new Q5e("tag:yaml.org,2002:binary",{kind:"scalar",resolve:R5e,construct:T5e,predicate:N5e,represent:F5e})});var ote=_((AQt,ste)=>{"use strict";var O5e=Ss(),L5e=Object.prototype.hasOwnProperty,M5e=Object.prototype.toString;function U5e(t){if(t===null)return!0;var e=[],r,s,a,n,c,f=t;for(r=0,s=f.length;r<s;r+=1){if(a=f[r],c=!1,M5e.call(a)!=="[object Object]")return!1;for(n in a)if(L5e.call(a,n))if(!c)c=!0;else return!1;if(!c)return!1;if(e.indexOf(n)===-1)e.push(n);else return!1}return!0}function _5e(t){return t!==null?t:[]}ste.exports=new O5e("tag:yaml.org,2002:omap",{kind:"sequence",resolve:U5e,construct:_5e})});var lte=_((pQt,ate)=>{"use strict";var H5e=Ss(),j5e=Object.prototype.toString;function G5e(t){if(t===null)return!0;var e,r,s,a,n,c=t;for(n=new Array(c.length),e=0,r=c.length;e<r;e+=1){if(s=c[e],j5e.call(s)!=="[object Object]"||(a=Object.keys(s),a.length!==1))return!1;n[e]=[a[0],s[a[0]]]}return!0}function q5e(t){if(t===null)return[];var e,r,s,a,n,c=t;for(n=new Array(c.length),e=0,r=c.length;e<r;e+=1)s=c[e],a=Object.keys(s),n[e]=[a[0],s[a[0]]];return n}ate.exports=new H5e("tag:yaml.org,2002:pairs",{kind:"sequence",resolve:G5e,construct:q5e})});var ute=_((hQt,cte)=>{"use strict";var W5e=Ss(),Y5e=Object.prototype.hasOwnProperty;function V5e(t){if(t===null)return!0;var e,r=t;for(e in r)if(Y5e.call(r,e)&&r[e]!==null)return!1;return!0}function J5e(t){return t!==null?t:{}}cte.exports=new W5e("tag:yaml.org,2002:set",{kind:"mapping",resolve:V5e,construct:J5e})});var gE=_((gQt,fte)=>{"use strict";var K5e=bd();fte.exports=new K5e({include:[JU()],implicit:[$ee(),tte()],explicit:[ite(),ote(),lte(),ute()]})});var pte=_((dQt,Ate)=>{"use strict";var z5e=Ss();function Z5e(){return!0}function X5e(){}function $5e(){return""}function e9e(t){return typeof t>"u"}Ate.exports=new z5e("tag:yaml.org,2002:js/undefined",{kind:"scalar",resolve:Z5e,construct:X5e,predicate:e9e,represent:$5e})});var gte=_((mQt,hte)=>{"use strict";var t9e=Ss();function r9e(t){if(t===null||t.length===0)return!1;var e=t,r=/\/([gim]*)$/.exec(t),s="";return!(e[0]==="/"&&(r&&(s=r[1]),s.length>3||e[e.length-s.length-1]!=="/"))}function n9e(t){var e=t,r=/\/([gim]*)$/.exec(t),s="";return e[0]==="/"&&(r&&(s=r[1]),e=e.slice(1,e.length-s.length-1)),new RegExp(e,s)}function i9e(t){var e="/"+t.source+"/";return t.global&&(e+="g"),t.multiline&&(e+="m"),t.ignoreCase&&(e+="i"),e}function s9e(t){return Object.prototype.toString.call(t)==="[object RegExp]"}hte.exports=new t9e("tag:yaml.org,2002:js/regexp",{kind:"scalar",resolve:r9e,construct:n9e,predicate:s9e,represent:i9e})});var yte=_((yQt,mte)=>{"use strict";var mx;try{dte=Ie,mx=dte("esprima")}catch{typeof window<"u"&&(mx=window.esprima)}var dte,o9e=Ss();function a9e(t){if(t===null)return!1;try{var e="("+t+")",r=mx.parse(e,{range:!0});return!(r.type!=="Program"||r.body.length!==1||r.body[0].type!=="ExpressionStatement"||r.body[0].expression.type!=="ArrowFunctionExpression"&&r.body[0].expression.type!=="FunctionExpression")}catch{return!1}}function l9e(t){var e="("+t+")",r=mx.parse(e,{range:!0}),s=[],a;if(r.type!=="Program"||r.body.length!==1||r.body[0].type!=="ExpressionStatement"||r.body[0].expression.type!=="ArrowFunctionExpression"&&r.body[0].expression.type!=="FunctionExpression")throw new Error("Failed to resolve function");return r.body[0].expression.params.forEach(function(n){s.push(n.name)}),a=r.body[0].expression.body.range,r.body[0].expression.body.type==="BlockStatement"?new Function(s,e.slice(a[0]+1,a[1]-1)):new Function(s,"return "+e.slice(a[0],a[1]))}function c9e(t){return t.toString()}function u9e(t){return Object.prototype.toString.call(t)==="[object Function]"}mte.exports=new o9e("tag:yaml.org,2002:js/function",{kind:"scalar",resolve:a9e,construct:l9e,predicate:u9e,represent:c9e})});var G2=_((IQt,Ite)=>{"use strict";var Ete=bd();Ite.exports=Ete.DEFAULT=new Ete({include:[gE()],explicit:[pte(),gte(),yte()]})});var Ute=_((CQt,q2)=>{"use strict";var Ip=Pd(),Pte=pE(),f9e=Pee(),bte=gE(),A9e=G2(),i0=Object.prototype.hasOwnProperty,yx=1,xte=2,kte=3,Ex=4,zU=1,p9e=2,Cte=3,h9e=/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84 Line truncated
`:t===118?"\v":t===102?"\f":t===114?"\r":t===101?"\x1B":t===32?" ":t===34?'"':t===47?"/":t===92?"\\":t===78?"\x85":t===95?"\xA0":t===76?"\u2028":t===80?"\u2029":""}function I9e(t){return t<=65535?String.fromCharCode(t):String.fromCharCode((t-65536>>10)+55296,(t-65536&1023)+56320)}var Tte=new Array(256),Fte=new Array(256);for(kd=0;kd<256;kd++)Tte[kd]=Bte(kd)?1:0,Fte[kd]=Bte(kd);var kd;function C9e(t,e){this.input=t,this.filename=e.filename||null,this.schema=e.schema||A9e,this.onWarning=e.onWarning||null,this.legacy=e.legacy||!1,this.json=e.json||!1,this.listener=e.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=t.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.documents=[]}function Nte(t,e){return new Pte(e,new f9e(t.filename,t.input,t.position,t.line,t.position-t.lineStart))}function Tr(t,e){throw Nte(t,e)}function Ix(t,e){t.onWarning&&t.onWarning.call(null,Nte(t,e))}var vte={YAML:function(e,r,s){var a,n,c;e.version!==null&&Tr(e,"duplication of %YAML directive"),s.length!==1&&Tr(e,"YAML directive accepts exactly one argument"),a=/^([0-9]+)\.([0-9]+)$/.exec(s[0]),a===null&&Tr(e,"ill-formed argument of the YAML directive"),n=parseInt(a[1],10),c=parseInt(a[2],10),n!==1&&Tr(e,"unacceptable YAML version of the document"),e.version=s[0],e.checkLineBreaks=c<2,c!==1&&c!==2&&Ix(e,"unsupported YAML version of the document")},TAG:function(e,r,s){var a,n;s.length!==2&&Tr(e,"TAG directive accepts exactly two arguments"),a=s[0],n=s[1],Qte.test(a)||Tr(e,"ill-formed tag handle (first argument) of the TAG directive"),i0.call(e.tagMap,a)&&Tr(e,'there is a previously declared suffix for "'+a+'" tag handle'),Rte.test(n)||Tr(e,"ill-formed tag prefix (second argument) of the TAG directive"),e.tagMap[a]=n}};function n0(t,e,r,s){var a,n,c,f;if(e<r){if(f=t.input.slice(e,r),s)for(a=0,n=f.length;a<n;a+=1)c=f.charCodeAt(a),c===9||32<=c&&c<=1114111||Tr(t,"expected valid JSON character");else h9e.test(f)&&Tr(t,"the stream contains non-printable characters");t.result+=f}}function Ste(t,e,r,s){var a,n,c,f;for(Ip.isObject(r)||Tr(t,"cannot merge mappings; the provided source object is unacceptable"),a=Object.keys(r),c=0,f=a.length;c<f;c+=1)n=a[c],i0.call(e,n)||(e[n]=r[n],s[n]=!0)}function mE(t,e,r,s,a,n,c,f){var p,h;if(Array.isArray(a))for(a=Array.prototype.slice.call(a),p=0,h=a.length;p<h;p+=1)Array.isArray(a[p])&&Tr(t,"nested arrays are not supported inside keys"),typeof a=="object"&&wte(a[p])==="[object Object]"&&(a[p]="[object Object]");if(typeof a=="object"&&wte(a)==="[object Object]"&&(a="[object Object]"),a=String(a),e===null&&(e={}),s==="tag:yaml.org,2002:merge")if(Array.isArray(n))for(p=0,h=n.length;p<h;p+=1)Ste(t,e,n[p],r);else Ste(t,e,n,r);else!t.json&&!i0.call(r,a)&&i0.call(e,a)&&(t.line=c||t.line,t.position=f||t.position,Tr(t,"duplicated mapping key")),e[a]=n,delete r[a];return e}function ZU(t){var e;e=t.input.charCodeAt(t.position),e===10?t.position++:e===13?(t.position++,t.input.charCodeAt(t.position)===10&&t.position++):Tr(t,"a line break is expected"),t.line+=1,t.lineStart=t.position}function os(t,e,r){for(var s=0,a=t.input.charCodeAt(t.position);a!==0;){for(;Qd(a);)a=t.input.charCodeAt(++t.position);if(e&&a===35)do a=t.input.charCodeAt(++t.position);while(a!==10&&a!==13&&a!==0);if(jf(a))for(ZU(t),a=t.input.charCodeAt(t.position),s++,t.lineIndent=0;a===32;)t.lineIndent++,a=t.input.charCodeAt(++t.position);else break}return r!==-1&&s!==0&&t.lineIndent<r&&Ix(t,"deficient indentation"),s}function Cx(t){var e=t.position,r;return r=t.input.charCodeAt(e),!!((r===45||r===46)&&r===t.input.charCodeAt(e+1)&&r===t.input.charCodeAt(e+2)&&(e+=3,r=t.input.charCodeAt(e),r===0||rl(r)))}function XU(t,e){e===1?t.result+=" ":e>1&&(t.result+=Ip.repeat(`
`,e-1))}function w9e(t,e,r){var s,a,n,c,f,p,h,E,C=t.kind,S=t.result,b;if(b=t.input.charCodeAt(t.position),rl(b)||dE(b)||b===35||b===38||b===42||b===33||b===124||b===62||b===39||b===34||b===37||b===64||b===96||(b===63||b===45)&&(a=t.input.charCodeAt(t.position+1),rl(a)||r&&dE(a)))return!1;for(t.kind="scalar",t.result="",n=c=t.position,f=!1;b!==0;){if(b===58){if(a=t.input.charCodeAt(t.position+1),rl(a)||r&&dE(a))break}else if(b===35){if(s=t.input.charCodeAt(t.position-1),rl(s))break}else{if(t.position===t.lineStart&&Cx(t)||r&&dE(b))break;if(jf(b))if(p=t.line,h=t.lineStart,E=t.lineIndent,os(t,!1,-1),t.lineIndent>=e){f=!0,b=t.input.charCodeAt(t.position);continue}else{t.position=c,t.line=p,t.lineStart=h,t.lineIndent=E;break}}f&&(n0(t,n,c,!1),XU(t,t.line-p),n=c=t.position,f=!1),Qd(b)||(c=t.position+1),b=t.input.charCodeAt(++t.position)}return n0(t,n,c,!1),t.result?!0:(t.kind=C,t.result=S,!1)}function B9e(t,e){var r,s,a;if(r=t.input.charCodeAt(t.position),r!==39)return!1;for(t.kind="scalar",t.result="",t.position++,s=a=t.position;(r=t.input.charCodeAt(t.position))!==0;)if(r===39)if(n0(t,s,t.position,!0),r=t.input.charCodeAt(++t.position),r===39)s=t.position,t.position++,a=t.position;else return!0;else jf(r)?(n0(t,s,a,!0),XU(t,os(t,!1,e)),s=a=t.position):t.position===t.lineStart&&Cx(t)?Tr(t,"unexpected end of the document within a single quoted scalar"):(t.position++,a=t.position);Tr(t,"unexpected end of the stream within a single quoted scalar")}function v9e(t,e){var r,s,a,n,c,f;if(f=t.input.charCodeAt(t.position),f!==34)return!1;for(t.kind="scalar",t.result="",t.position++,r=s=t.position;(f=t.input.charCodeAt(t.position))!==0;){if(f===34)return n0(t,r,t.position,!0),t.position++,!0;if(f===92){if(n0(t,r,t.position,!0),f=t.input.charCodeAt(++t.position),jf(f))os(t,!1,e);else if(f<256&&Tte[f])t.result+=Fte[f],t.position++;else if((c=y9e(f))>0){for(a=c,n=0;a>0;a--)f=t.input.charCodeAt(++t.position),(c=m9e(f))>=0?n=(n<<4)+c:Tr(t,"expected hexadecimal character");t.result+=I9e(n),t.position++}else Tr(t,"unknown escape sequence");r=s=t.position}else jf(f)?(n0(t,r,s,!0),XU(t,os(t,!1,e)),r=s=t.position):t.position===t.lineStart&&Cx(t)?Tr(t,"unexpected end of the document within a double quoted scalar"):(t.position++,s=t.position)}Tr(t,"unexpected end of the stream within a double quoted scalar")}function S9e(t,e){var r=!0,s,a=t.tag,n,c=t.anchor,f,p,h,E,C,S={},b,I,T,N;if(N=t.input.charCodeAt(t.position),N===91)p=93,C=!1,n=[];else if(N===123)p=125,C=!0,n={};else return!1;for(t.anchor!==null&&(t.anchorMap[t.anchor]=n),N=t.input.charCodeAt(++t.position);N!==0;){if(os(t,!0,e),N=t.input.charCodeAt(t.position),N===p)return t.position++,t.tag=a,t.anchor=c,t.kind=C?"mapping":"sequence",t.result=n,!0;r||Tr(t,"missed comma between flow collection entries"),I=b=T=null,h=E=!1,N===63&&(f=t.input.charCodeAt(t.position+1),rl(f)&&(h=E=!0,t.position++,os(t,!0,e))),s=t.line,yE(t,e,yx,!1,!0),I=t.tag,b=t.result,os(t,!0,e),N=t.input.charCodeAt(t.position),(E||t.line===s)&&N===58&&(h=!0,N=t.input.charCodeAt(++t.position),os(t,!0,e),yE(t,e,yx,!1,!0),T=t.result),C?mE(t,n,S,I,b,T):h?n.push(mE(t,null,S,I,b,T)):n.push(b),os(t,!0,e),N=t.input.charCodeAt(t.position),N===44?(r=!0,N=t.input.charCodeAt(++t.position)):r=!1}Tr(t,"unexpected end of the stream within a flow collection")}function D9e(t,e){var r,s,a=zU,n=!1,c=!1,f=e,p=0,h=!1,E,C;if(C=t.input.charCodeAt(t.position),C===124)s=!1;else if(C===62)s=!0;else return!1;for(t.kind="scalar",t.result="";C!==0;)if(C=t.input.charCodeAt(++t.position),C===43||C===45)zU===a?a=C===43?Cte:p9e:Tr(t,"repeat of a chomping mode identifier");else if((E=E9e(C))>=0)E===0?Tr(t,"bad explicit indentation width of a block scalar; it cannot be less than one"):c?Tr(t,"repeat of an indentation width identifier"):(f=e+E-1,c=!0);else break;if(Qd(C)){do C=t.input.charCodeAt(++t.position);while(Qd(C));if(C===35)do C=t.input.charCodeAt(++t.position);while(!jf(C)&&C!==0)}for(;C!==0;){for(ZU(t),t.lineIndent=0,C=t.input.charCodeAt(t.position);(!c||t.lineIndent<f)&&C===32;)t.lineIndent++,C=t.input.charCodeAt(++t.position);if(!c&&t.lineIndent>f&&(f=t.lineIndent),jf(C)){p++;continue}if(t.lineIndent<f){a===Cte?t.result+=Ip.repeat(`
`,n?1+p:p):a===zU&&n&&(t.result+=`
`);break}for(s?Qd(C)?(h=!0,t.result+=Ip.repeat(`
`,n?1+p:p)):h?(h=!1,t.result+=Ip.repeat(`
`,p+1)):p===0?n&&(t.result+=" "):t.result+=Ip.repeat(`
`,p):t.result+=Ip.repeat(`
`,n?1+p:p),n=!0,c=!0,p=0,r=t.position;!jf(C)&&C!==0;)C=t.input.charCodeAt(++t.position);n0(t,r,t.position,!1)}return!0}function Dte(t,e){var r,s=t.tag,a=t.anchor,n=[],c,f=!1,p;for(t.anchor!==null&&(t.anchorMap[t.anchor]=n),p=t.input.charCodeAt(t.position);p!==0&&!(p!==45||(c=t.input.charCodeAt(t.position+1),!rl(c)));){if(f=!0,t.position++,os(t,!0,-1)&&t.lineIndent<=e){n.push(null),p=t.input.charCodeAt(t.position);continue}if(r=t.line,yE(t,e,kte,!1,!0),n.push(t.result),os(t,!0,-1),p=t.input.charCodeAt(t.position),(t.line===r||t.lineIndent>e)&&p!==0)Tr(t,"bad indentation of a sequence entry");else if(t.lineIndent<e)break}return f?(t.tag=s,t.anchor=a,t.kind="sequence",t.result=n,!0):!1}function P9e(t,e,r){var s,a,n,c,f=t.tag,p=t.anchor,h={},E={},C=null,S=null,b=null,I=!1,T=!1,N;for(t.anchor!==null&&(t.anchorMap[t.anchor]=h),N=t.input.charCodeAt(t.position);N!==0;){if(s=t.input.charCodeAt(t.position+1),n=t.line,c=t.position,(N===63||N===58)&&rl(s))N===63?(I&&(mE(t,h,E,C,S,null),C=S=b=null),T=!0,I=!0,a=!0):I?(I=!1,a=!0):Tr(t,"incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line"),t.position+=1,N=s;else if(yE(t,r,xte,!1,!0))if(t.line===n){for(N=t.input.charCodeAt(t.position);Qd(N);)N=t.input.charCodeAt(++t.position);if(N===58)N=t.input.charCodeAt(++t.position),rl(N)||Tr(t,"a whitespace character is expected after the key-value separator within a block mapping"),I&&(mE(t,h,E,C,S,null),C=S=b=null),T=!0,I=!1,a=!1,C=t.tag,S=t.result;else if(T)Tr(t,"can not read an implicit mapping pair; a colon is missed");else return t.tag=f,t.anchor=p,!0}else if(T)Tr(t,"can not read a block mapping entry; a multiline key may not be an implicit key");else return t.tag=f,t.anchor=p,!0;else break;if((t.line===n||t.lineIndent>e)&&(yE(t,e,Ex,!0,a)&&(I?S=t.result:b=t.result),I||(mE(t,h,E,C,S,b,n,c),C=S=b=null),os(t,!0,-1),N=t.input.charCodeAt(t.position)),t.lineIndent>e&&N!==0)Tr(t,"bad indentation of a mapping entry");else if(t.lineIndent<e)break}return I&&mE(t,h,E,C,S,null),T&&(t.tag=f,t.anchor=p,t.kind="mapping",t.result=h),T}function b9e(t){var e,r=!1,s=!1,a,n,c;if(c=t.input.charCodeAt(t.position),c!==33)return!1;if(t.tag!==null&&Tr(t,"duplication of a tag property"),c=t.input.charCodeAt(++t.position),c===60?(r=!0,c=t.input.charCodeAt(++t.position)):c===33?(s=!0,a="!!",c=t.input.charCodeAt(++t.position)):a="!",e=t.position,r){do c=t.input.charCodeAt(++t.position);while(c!==0&&c!==62);t.position<t.length?(n=t.input.slice(e,t.position),c=t.input.charCodeAt(++t.position)):Tr(t,"unexpected end of the stream within a verbatim tag")}else{for(;c!==0&&!rl(c);)c===33&&(s?Tr(t,"tag suffix cannot contain exclamation marks"):(a=t.input.slice(e-1,t.position+1),Qte.test(a)||Tr(t,"named tag handle cannot contain such characters"),s=!0,e=t.position+1)),c=t.input.charCodeAt(++t.position);n=t.input.slice(e,t.position),d9e.test(n)&&Tr(t,"tag suffix cannot contain flow indicator characters")}return n&&!Rte.test(n)&&Tr(t,"tag name cannot contain such characters: "+n),r?t.tag=n:i0.call(t.tagMap,a)?t.tag=t.tagMap[a]+n:a==="!"?t.tag="!"+n:a==="!!"?t.tag="tag:yaml.org,2002:"+n:Tr(t,'undeclared tag handle "'+a+'"'),!0}function x9e(t){var e,r;if(r=t.input.charCodeAt(t.position),r!==38)return!1;for(t.anchor!==null&&Tr(t,"duplication of an anchor property"),r=t.input.charCodeAt(++t.position),e=t.position;r!==0&&!rl(r)&&!dE(r);)r=t.input.charCodeAt(++t.position);return t.position===e&&Tr(t,"name of an anchor node must contain at least one character"),t.anchor=t.input.slice(e,t.position),!0}function k9e(t){var e,r,s;if(s=t.input.charCodeAt(t.position),s!==42)return!1;for(s=t.input.charCodeAt(++t.position),e=t.position;s!==0&&!rl(s)&&!dE(s);)s=t.input.charCodeAt(++t.position);return t.position===e&&Tr(t,"name of an alias node must contain at least one character"),r=t.input.slice(e,t.position),i0.call(t.anchorMap,r)||Tr(t,'unidentified alias "'+r+'"'),t.result=t.anchorMap[r],os(t,!0,-1),!0}function yE(t,e,r,s,a){var n,c,f,p=1,h=!1,E=!1,C,S,b,I,T;if(t.listener!==null&&t.listener("open",t),t.tag=null,t.anchor=null,t.kind=null,t.result=null,n=c=f=Ex===r||kte===r,s&&os(t,!0,-1)&&(h=!0,t.lineIndent>e?p=1:t.lineIndent===e?p=0:t.lineIndent<e&&(p=-1)),p===1)for(;b9e(t)||x9e(t);)os(t,!0,-1)?(h=!0,f=n,t.lineIndent>e?p=1:t.lineIndent===e?p=0:t.lineIndent<e&&(p=-1)):f=!1;if(f&&(f=h||a),(p===1||Ex===r)&&(yx===r||xte===r?I=e:I=e+1,T=t.position-t.lineStart,p===1?f&&(Dte(t,T)||P9e(t,T,I))||S9e(t,I)?E=!0:(c&&D9e(t,I)||B9e(t,I)||v9e(t,I)?E=!0:k9e(t)?(E=!0,(t.tag!==null||t.anchor!==null)&&Tr(t,"alias node should not have any properties")):w9e(t,I,yx===r)&&(E=!0,t.tag===null&&(t.tag="?")),t.anchor!==null&&(t.anchorMap[t.anchor]=t.result)):p===0&&(E=f&&Dte(t,T))),t.tag!==null&&t.tag!=="!")if(t.tag==="?"){for(t.result!==null&&t.kind!=="scalar"&&Tr(t,'unacceptable node kind for !<?> tag; it should be "scalar", not "'+t.kind+'"'),C=0,S=t.implicitTypes.length;C<S;C+=1)if(b=t.implicitTypes[C],b.resolve(t.result)){t.result=b.construct(t.result),t. Line truncated
`),t.charCodeAt(0)===65279&&(t=t.slice(1)));var r=new C9e(t,e),s=t.indexOf("\0");for(s!==-1&&(r.position=s,Tr(r,"null byte is not allowed in input")),r.input+="\0";r.input.charCodeAt(r.position)===32;)r.lineIndent+=1,r.position+=1;for(;r.position<r.length-1;)Q9e(r);return r.documents}function Lte(t,e,r){e!==null&&typeof e=="object"&&typeof r>"u"&&(r=e,e=null);var s=Ote(t,r);if(typeof e!="function")return s;for(var a=0,n=s.length;a<n;a+=1)e(s[a])}function Mte(t,e){var r=Ote(t,e);if(r.length!==0){if(r.length===1)return r[0];throw new Pte("expected a single document in the stream, but found more")}}function R9e(t,e,r){return typeof e=="object"&&e!==null&&typeof r>"u"&&(r=e,e=null),Lte(t,e,Ip.extend({schema:bte},r))}function T9e(t,e){return Mte(t,Ip.extend({schema:bte},e))}q2.exports.loadAll=Lte;q2.exports.load=Mte;q2.exports.safeLoadAll=R9e;q2.exports.safeLoad=T9e});var lre=_((wQt,r_)=>{"use strict";var Y2=Pd(),V2=pE(),F9e=G2(),N9e=gE(),Vte=Object.prototype.toString,Jte=Object.prototype.hasOwnProperty,O9e=9,W2=10,L9e=13,M9e=32,U9e=33,_9e=34,Kte=35,H9e=37,j9e=38,G9e=39,q9e=42,zte=44,W9e=45,Zte=58,Y9e=61,V9e=62,J9e=63,K9e=64,Xte=91,$te=93,z9e=96,ere=123,Z9e=124,tre=125,_o={};_o[0]="\\0";_o[7]="\\a";_o[8]="\\b";_o[9]="\\t";_o[10]="\\n";_o[11]="\\v";_o[12]="\\f";_o[13]="\\r";_o[27]="\\e";_o[34]='\\"';_o[92]="\\\\";_o[133]="\\N";_o[160]="\\_";_o[8232]="\\L";_o[8233]="\\P";var X9e=["y","Y","yes","Yes","YES","on","On","ON","n","N","no","No","NO","off","Off","OFF"];function $9e(t,e){var r,s,a,n,c,f,p;if(e===null)return{};for(r={},s=Object.keys(e),a=0,n=s.length;a<n;a+=1)c=s[a],f=String(e[c]),c.slice(0,2)==="!!"&&(c="tag:yaml.org,2002:"+c.slice(2)),p=t.compiledTypeMap.fallback[c],p&&Jte.call(p.styleAliases,f)&&(f=p.styleAliases[f]),r[c]=f;return r}function _te(t){var e,r,s;if(e=t.toString(16).toUpperCase(),t<=255)r="x",s=2;else if(t<=65535)r="u",s=4;else if(t<=4294967295)r="U",s=8;else throw new V2("code point within a string may not be greater than 0xFFFFFFFF");return"\\"+r+Y2.repeat("0",s-e.length)+e}function eWe(t){this.schema=t.schema||F9e,this.indent=Math.max(1,t.indent||2),this.noArrayIndent=t.noArrayIndent||!1,this.skipInvalid=t.skipInvalid||!1,this.flowLevel=Y2.isNothing(t.flowLevel)?-1:t.flowLevel,this.styleMap=$9e(this.schema,t.styles||null),this.sortKeys=t.sortKeys||!1,this.lineWidth=t.lineWidth||80,this.noRefs=t.noRefs||!1,this.noCompatMode=t.noCompatMode||!1,this.condenseFlow=t.condenseFlow||!1,this.implicitTypes=this.schema.compiledImplicit,this.explicitTypes=this.schema.compiledExplicit,this.tag=null,this.result="",this.duplicates=[],this.usedDuplicates=null}function Hte(t,e){for(var r=Y2.repeat(" ",e),s=0,a=-1,n="",c,f=t.length;s<f;)a=t.indexOf(`
`,s),a===-1?(c=t.slice(s),s=f):(c=t.slice(s,a+1),s=a+1),c.length&&c!==`
`&&(n+=r),n+=c;return n}function $U(t,e){return`
`+Y2.repeat(" ",t.indent*e)}function tWe(t,e){var r,s,a;for(r=0,s=t.implicitTypes.length;r<s;r+=1)if(a=t.implicitTypes[r],a.resolve(e))return!0;return!1}function t_(t){return t===M9e||t===O9e}function EE(t){return 32<=t&&t<=126||161<=t&&t<=55295&&t!==8232&&t!==8233||57344<=t&&t<=65533&&t!==65279||65536<=t&&t<=1114111}function rWe(t){return EE(t)&&!t_(t)&&t!==65279&&t!==L9e&&t!==W2}function jte(t,e){return EE(t)&&t!==65279&&t!==zte&&t!==Xte&&t!==$te&&t!==ere&&t!==tre&&t!==Zte&&(t!==Kte||e&&rWe(e))}function nWe(t){return EE(t)&&t!==65279&&!t_(t)&&t!==W9e&&t!==J9e&&t!==Zte&&t!==zte&&t!==Xte&&t!==$te&&t!==ere&&t!==tre&&t!==Kte&&t!==j9e&&t!==q9e&&t!==U9e&&t!==Z9e&&t!==Y9e&&t!==V9e&&t!==G9e&&t!==_9e&&t!==H9e&&t!==K9e&&t!==z9e}function rre(t){var e=/^\n* /;return e.test(t)}var nre=1,ire=2,sre=3,ore=4,wx=5;function iWe(t,e,r,s,a){var n,c,f,p=!1,h=!1,E=s!==-1,C=-1,S=nWe(t.charCodeAt(0))&&!t_(t.charCodeAt(t.length-1));if(e)for(n=0;n<t.length;n++){if(c=t.charCodeAt(n),!EE(c))return wx;f=n>0?t.charCodeAt(n-1):null,S=S&&jte(c,f)}else{for(n=0;n<t.length;n++){if(c=t.charCodeAt(n),c===W2)p=!0,E&&(h=h||n-C-1>s&&t[C+1]!==" ",C=n);else if(!EE(c))return wx;f=n>0?t.charCodeAt(n-1):null,S=S&&jte(c,f)}h=h||E&&n-C-1>s&&t[C+1]!==" "}return!p&&!h?S&&!a(t)?nre:ire:r>9&&rre(t)?wx:h?ore:sre}function sWe(t,e,r,s){t.dump=function(){if(e.length===0)return"''";if(!t.noCompatMode&&X9e.indexOf(e)!==-1)return"'"+e+"'";var a=t.indent*Math.max(1,r),n=t.lineWidth===-1?-1:Math.max(Math.min(t.lineWidth,40),t.lineWidth-a),c=s||t.flowLevel>-1&&r>=t.flowLevel;function f(p){return tWe(t,p)}switch(iWe(e,c,t.indent,n,f)){case nre:return e;case ire:return"'"+e.replace(/'/g,"''")+"'";case sre:return"|"+Gte(e,t.indent)+qte(Hte(e,a));case ore:return">"+Gte(e,t.indent)+qte(Hte(oWe(e,n),a));case wx:return'"'+aWe(e,n)+'"';default:throw new V2("impossible error: invalid scalar style")}}()}function Gte(t,e){var r=rre(t)?String(e):"",s=t[t.length-1]===`
`,a=s&&(t[t.length-2]===`
`||t===`
`),n=a?"+":s?"":"-";return r+n+`
`}function qte(t){return t[t.length-1]===`
`?t.slice(0,-1):t}function oWe(t,e){for(var r=/(\n+)([^\n]*)/g,s=function(){var h=t.indexOf(`
`);return h=h!==-1?h:t.length,r.lastIndex=h,Wte(t.slice(0,h),e)}(),a=t[0]===`
`||t[0]===" ",n,c;c=r.exec(t);){var f=c[1],p=c[2];n=p[0]===" ",s+=f+(!a&&!n&&p!==""?`
`:"")+Wte(p,e),a=n}return s}function Wte(t,e){if(t===""||t[0]===" ")return t;for(var r=/ [^ ]/g,s,a=0,n,c=0,f=0,p="";s=r.exec(t);)f=s.index,f-a>e&&(n=c>a?c:f,p+=`
`+t.slice(a,n),a=n+1),c=f;return p+=`
`,t.length-a>e&&c>a?p+=t.slice(a,c)+`
`+t.slice(c+1):p+=t.slice(a),p.slice(1)}function aWe(t){for(var e="",r,s,a,n=0;n<t.length;n++){if(r=t.charCodeAt(n),r>=55296&&r<=56319&&(s=t.charCodeAt(n+1),s>=56320&&s<=57343)){e+=_te((r-55296)*1024+s-56320+65536),n++;continue}a=_o[r],e+=!a&&EE(r)?t[n]:a||_te(r)}return e}function lWe(t,e,r){var s="",a=t.tag,n,c;for(n=0,c=r.length;n<c;n+=1)Rd(t,e,r[n],!1,!1)&&(n!==0&&(s+=","+(t.condenseFlow?"":" ")),s+=t.dump);t.tag=a,t.dump="["+s+"]"}function cWe(t,e,r,s){var a="",n=t.tag,c,f;for(c=0,f=r.length;c<f;c+=1)Rd(t,e+1,r[c],!0,!0)&&((!s||c!==0)&&(a+=$U(t,e)),t.dump&&W2===t.dump.charCodeAt(0)?a+="-":a+="- ",a+=t.dump);t.tag=n,t.dump=a||"[]"}function uWe(t,e,r){var s="",a=t.tag,n=Object.keys(r),c,f,p,h,E;for(c=0,f=n.length;c<f;c+=1)E="",c!==0&&(E+=", "),t.condenseFlow&&(E+='"'),p=n[c],h=r[p],Rd(t,e,p,!1,!1)&&(t.dump.length>1024&&(E+="? "),E+=t.dump+(t.condenseFlow?'"':"")+":"+(t.condenseFlow?"":" "),Rd(t,e,h,!1,!1)&&(E+=t.dump,s+=E));t.tag=a,t.dump="{"+s+"}"}function fWe(t,e,r,s){var a="",n=t.tag,c=Object.keys(r),f,p,h,E,C,S;if(t.sortKeys===!0)c.sort();else if(typeof t.sortKeys=="function")c.sort(t.sortKeys);else if(t.sortKeys)throw new V2("sortKeys must be a boolean or a function");for(f=0,p=c.length;f<p;f+=1)S="",(!s||f!==0)&&(S+=$U(t,e)),h=c[f],E=r[h],Rd(t,e+1,h,!0,!0,!0)&&(C=t.tag!==null&&t.tag!=="?"||t.dump&&t.dump.length>1024,C&&(t.dump&&W2===t.dump.charCodeAt(0)?S+="?":S+="? "),S+=t.dump,C&&(S+=$U(t,e)),Rd(t,e+1,E,!0,C)&&(t.dump&&W2===t.dump.charCodeAt(0)?S+=":":S+=": ",S+=t.dump,a+=S));t.tag=n,t.dump=a||"{}"}function Yte(t,e,r){var s,a,n,c,f,p;for(a=r?t.explicitTypes:t.implicitTypes,n=0,c=a.length;n<c;n+=1)if(f=a[n],(f.instanceOf||f.predicate)&&(!f.instanceOf||typeof e=="object"&&e instanceof f.instanceOf)&&(!f.predicate||f.predicate(e))){if(t.tag=r?f.tag:"?",f.represent){if(p=t.styleMap[f.tag]||f.defaultStyle,Vte.call(f.represent)==="[object Function]")s=f.represent(e,p);else if(Jte.call(f.represent,p))s=f.represent[p](e,p);else throw new V2("!<"+f.tag+'> tag resolver accepts not "'+p+'" style');t.dump=s}return!0}return!1}function Rd(t,e,r,s,a,n){t.tag=null,t.dump=r,Yte(t,r,!1)||Yte(t,r,!0);var c=Vte.call(t.dump);s&&(s=t.flowLevel<0||t.flowLevel>e);var f=c==="[object Object]"||c==="[object Array]",p,h;if(f&&(p=t.duplicates.indexOf(r),h=p!==-1),(t.tag!==null&&t.tag!=="?"||h||t.indent!==2&&e>0)&&(a=!1),h&&t.usedDuplicates[p])t.dump="*ref_"+p;else{if(f&&h&&!t.usedDuplicates[p]&&(t.usedDuplicates[p]=!0),c==="[object Object]")s&&Object.keys(t.dump).length!==0?(fWe(t,e,t.dump,a),h&&(t.dump="&ref_"+p+t.dump)):(uWe(t,e,t.dump),h&&(t.dump="&ref_"+p+" "+t.dump));else if(c==="[object Array]"){var E=t.noArrayIndent&&e>0?e-1:e;s&&t.dump.length!==0?(cWe(t,E,t.dump,a),h&&(t.dump="&ref_"+p+t.dump)):(lWe(t,E,t.dump),h&&(t.dump="&ref_"+p+" "+t.dump))}else if(c==="[object String]")t.tag!=="?"&&sWe(t,t.dump,e,n);else{if(t.skipInvalid)return!1;throw new V2("unacceptable kind of an object to dump "+c)}t.tag!==null&&t.tag!=="?"&&(t.dump="!<"+t.tag+"> "+t.dump)}return!0}function AWe(t,e){var r=[],s=[],a,n;for(e_(t,r,s),a=0,n=s.length;a<n;a+=1)e.duplicates.push(r[s[a]]);e.usedDuplicates=new Array(n)}function e_(t,e,r){var s,a,n;if(t!==null&&typeof t=="object")if(a=e.indexOf(t),a!==-1)r.indexOf(a)===-1&&r.push(a);else if(e.push(t),Array.isArray(t))for(a=0,n=t.length;a<n;a+=1)e_(t[a],e,r);else for(s=Object.keys(t),a=0,n=s.length;a<n;a+=1)e_(t[s[a]],e,r)}function are(t,e){e=e||{};var r=new eWe(e);return r.noRefs||AWe(t,r),Rd(r,0,t,!0,!0)?r.dump+`
`:""}function pWe(t,e){return are(t,Y2.extend({schema:N9e},e))}r_.exports.dump=are;r_.exports.safeDump=pWe});var ure=_((BQt,qi)=>{"use strict";var Bx=Ute(),cre=lre();function vx(t){return function(){throw new Error("Function "+t+" is deprecated and cannot be used.")}}qi.exports.Type=Ss();qi.exports.Schema=bd();qi.exports.FAILSAFE_SCHEMA=dx();qi.exports.JSON_SCHEMA=VU();qi.exports.CORE_SCHEMA=JU();qi.exports.DEFAULT_SAFE_SCHEMA=gE();qi.exports.DEFAULT_FULL_SCHEMA=G2();qi.exports.load=Bx.load;qi.exports.loadAll=Bx.loadAll;qi.exports.safeLoad=Bx.safeLoad;qi.exports.safeLoadAll=Bx.safeLoadAll;qi.exports.dump=cre.dump;qi.exports.safeDump=cre.safeDump;qi.exports.YAMLException=pE();qi.exports.MINIMAL_SCHEMA=dx();qi.exports.SAFE_SCHEMA=gE();qi.exports.DEFAULT_SCHEMA=G2();qi.exports.scan=vx("scan");qi.exports.parse=vx("parse");qi.exports.compose=vx("compose");qi.exports.addConstructor=vx("addConstructor")});var Are=_((vQt,fre)=>{"use strict";var hWe=ure();fre.exports=hWe});var hre=_((SQt,pre)=>{"use strict";function gWe(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function Td(t,e,r,s){this.message=t,this.expected=e,this.found=r,this.location=s,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,Td)}gWe(Td,Error);Td.buildMessage=function(t,e){var r={literal:function(h){return'"'+a(h.text)+'"'},class:function(h){var E="",C;for(C=0;C<h.parts.length;C++)E+=h.parts[C]instanceof Array?n(h.parts[C][0])+"-"+n(h.parts[C][1]):n(h.parts[C]);return"["+(h.inverted?"^":"")+E+"]"},any:function(h){return"any character"},end:function(h){return"end of input"},other:function(h){return h.description}};function s(h){return h.charCodeAt(0).toString(16).toUpperCase()}function a(h){return h.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\0/g,"\\0").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/[\x00-\x0F]/g,function(E){return"\\x0"+s(E)}).replace(/[\x10-\x1F\x7F-\x9F]/g,function(E){return"\\x"+s(E)})}function n(h){return h.replace(/\\/g,"\\\\").replace(/\]/g,"\\]").replace(/\^/g,"\\^").replace(/-/g,"\\-").replace(/\0/g,"\\0").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/[\x00-\x0F]/g,function(E){return"\\x0"+s(E)}).replace(/[\x10-\x1F\x7F-\x9F]/g,function(E){return"\\x"+s(E)})}function c(h){return r[h.type](h)}function f(h){var E=new Array(h.length),C,S;for(C=0;C<h.length;C++)E[C]=c(h[C]);if(E.sort(),E.length>0){for(C=1,S=1;C<E.length;C++)E[C-1]!==E[C]&&(E[S]=E[C],S++);E.length=S}switch(E.length){case 1:return E[0];case 2:return E[0]+" or "+E[1];default:return E.slice(0,-1).join(", ")+", or "+E[E.length-1]}}function p(h){return h?'"'+a(h)+'"':"end of input"}return"Expected "+f(t)+" but "+p(e)+" found."};function dWe(t,e){e=e!==void 0?e:{};var r={},s={Start:lc},a=lc,n=function(te){return[].concat(...te)},c="-",f=dn("-",!1),p=function(te){return te},h=function(te){return Object.assign({},...te)},E="#",C=dn("#",!1),S=Au(),b=function(){return{}},I=":",T=dn(":",!1),N=function(te,Ee){return{[te]:Ee}},U=",",W=dn(",",!1),ee=function(te,Ee){return Ee},ie=function(te,Ee,Oe){return Object.assign({},...[te].concat(Ee).map(dt=>({[dt]:Oe})))},ue=function(te){return te},le=function(te){return te},me=Oa("correct indentation"),pe=" ",Be=dn(" ",!1),Ce=function(te){return te.length===lr*St},g=function(te){return te.length===(lr+1)*St},we=function(){return lr++,!0},ye=function(){return lr--,!0},Ae=function(){return la()},se=Oa("pseudostring"),X=/^[^\r\n\t ?:,\][{}#&*!|>'"%@`\-]/,De=Kn(["\r",`
`," "," ","?",":",",","]","[","{","}","#","&","*","!","|",">","'",'"',"%","@","`","-"],!0,!1),Te=/^[^\r\n\t ,\][{}:#"']/,mt=Kn(["\r",`
`," "," ",",","]","[","{","}",":","#",'"',"'"],!0,!1),j=function(){return la().replace(/^ *| *$/g,"")},rt="--",Fe=dn("--",!1),Ne=/^[a-zA-Z\/0-9]/,be=Kn([["a","z"],["A","Z"],"/",["0","9"]],!1,!1),Ve=/^[^\r\n\t :,]/,ke=Kn(["\r",`
`," "," ",":",","],!0,!1),it="null",Ue=dn("null",!1),x=function(){return null},w="true",P=dn("true",!1),y=function(){return!0},F="false",z=dn("false",!1),Z=function(){return!1},$=Oa("string"),oe='"',xe=dn('"',!1),Re=function(){return""},lt=function(te){return te},Ct=function(te){return te.join("")},qt=/^[^"\\\0-\x1F\x7F]/,ir=Kn(['"',"\\",["\0",""],"\x7F"],!0,!1),bt='\\"',gn=dn('\\"',!1),br=function(){return'"'},Ir="\\\\",Or=dn("\\\\",!1),nn=function(){return"\\"},ai="\\/",Io=dn("\\/",!1),ts=function(){return"/"},$s="\\b",Co=dn("\\b",!1),Hi=function(){return"\b"},eo="\\f",wo=dn("\\f",!1),QA=function(){return"\f"},Af="\\n",dh=dn("\\n",!1),mh=function(){return`
`},to="\\r",jn=dn("\\r",!1),Rs=function(){return"\r"},ro="\\t",ou=dn("\\t",!1),au=function(){return" "},lu="\\u",RA=dn("\\u",!1),TA=function(te,Ee,Oe,dt){return String.fromCharCode(parseInt(`0x${te}${Ee}${Oe}${dt}`))},oa=/^[0-9a-fA-F]/,aa=Kn([["0","9"],["a","f"],["A","F"]],!1,!1),FA=Oa("blank space"),gr=/^[ \t]/,Bo=Kn([" "," "],!1,!1),Me=Oa("white space"),cu=/^[ \t\n\r]/,Cr=Kn([" "," ",`
`,"\r"],!1,!1),pf=`\r
`,NA=dn(`\r
`,!1),OA=`
`,uu=dn(`
`,!1),fu="\r",oc=dn("\r",!1),ve=0,Nt=0,ac=[{line:1,column:1}],Oi=0,no=[],Tt=0,xn;if("startRule"in e){if(!(e.startRule in s))throw new Error(`Can't start parsing from rule "`+e.startRule+'".');a=s[e.startRule]}function la(){return t.substring(Nt,ve)}function ji(){return Ma(Nt,ve)}function Li(te,Ee){throw Ee=Ee!==void 0?Ee:Ma(Nt,ve),hf([Oa(te)],t.substring(Nt,ve),Ee)}function Na(te,Ee){throw Ee=Ee!==void 0?Ee:Ma(Nt,ve),Ua(te,Ee)}function dn(te,Ee){return{type:"literal",text:te,ignoreCase:Ee}}function Kn(te,Ee,Oe){return{type:"class",parts:te,inverted:Ee,ignoreCase:Oe}}function Au(){return{type:"any"}}function yh(){return{type:"end"}}function Oa(te){return{type:"other",description:te}}function La(te){var Ee=ac[te],Oe;if(Ee)return Ee;for(Oe=te-1;!ac[Oe];)Oe--;for(Ee=ac[Oe],Ee={line:Ee.line,column:Ee.column};Oe<te;)t.charCodeAt(Oe)===10?(Ee.line++,Ee.column=1):Ee.column++,Oe++;return ac[te]=Ee,Ee}function Ma(te,Ee){var Oe=La(te),dt=La(Ee);return{start:{offset:te,line:Oe.line,column:Oe.column},end:{offset:Ee,line:dt.line,column:dt.column}}}function $e(te){ve<Oi||(ve>Oi&&(Oi=ve,no=[]),no.push(te))}function Ua(te,Ee){return new Td(te,null,null,Ee)}function hf(te,Ee,Oe){return new Td(Td.buildMessage(te,Ee),te,Ee,Oe)}function lc(){var te;return te=LA(),te}function wn(){var te,Ee,Oe;for(te=ve,Ee=[],Oe=ca();Oe!==r;)Ee.push(Oe),Oe=ca();return Ee!==r&&(Nt=te,Ee=n(Ee)),te=Ee,te}function ca(){var te,Ee,Oe,dt,Et;return te=ve,Ee=Bl(),Ee!==r?(t.charCodeAt(ve)===45?(Oe=c,ve++):(Oe=r,Tt===0&&$e(f)),Oe!==r?(dt=Qn(),dt!==r?(Et=ua(),Et!==r?(Nt=te,Ee=p(Et),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r),te}function LA(){var te,Ee,Oe;for(te=ve,Ee=[],Oe=MA();Oe!==r;)Ee.push(Oe),Oe=MA();return Ee!==r&&(Nt=te,Ee=h(Ee)),te=Ee,te}function MA(){var te,Ee,Oe,dt,Et,Pt,tr,An,li;if(te=ve,Ee=Qn(),Ee===r&&(Ee=null),Ee!==r){if(Oe=ve,t.charCodeAt(ve)===35?(dt=E,ve++):(dt=r,Tt===0&&$e(C)),dt!==r){if(Et=[],Pt=ve,tr=ve,Tt++,An=st(),Tt--,An===r?tr=void 0:(ve=tr,tr=r),tr!==r?(t.length>ve?(An=t.charAt(ve),ve++):(An=r,Tt===0&&$e(S)),An!==r?(tr=[tr,An],Pt=tr):(ve=Pt,Pt=r)):(ve=Pt,Pt=r),Pt!==r)for(;Pt!==r;)Et.push(Pt),Pt=ve,tr=ve,Tt++,An=st(),Tt--,An===r?tr=void 0:(ve=tr,tr=r),tr!==r?(t.length>ve?(An=t.charAt(ve),ve++):(An=r,Tt===0&&$e(S)),An!==r?(tr=[tr,An],Pt=tr):(ve=Pt,Pt=r)):(ve=Pt,Pt=r);else Et=r;Et!==r?(dt=[dt,Et],Oe=dt):(ve=Oe,Oe=r)}else ve=Oe,Oe=r;if(Oe===r&&(Oe=null),Oe!==r){if(dt=[],Et=Ke(),Et!==r)for(;Et!==r;)dt.push(Et),Et=Ke();else dt=r;dt!==r?(Nt=te,Ee=b(),te=Ee):(ve=te,te=r)}else ve=te,te=r}else ve=te,te=r;if(te===r&&(te=ve,Ee=Bl(),Ee!==r?(Oe=Ha(),Oe!==r?(dt=Qn(),dt===r&&(dt=null),dt!==r?(t.charCodeAt(ve)===58?(Et=I,ve++):(Et=r,Tt===0&&$e(T)),Et!==r?(Pt=Qn(),Pt===r&&(Pt=null),Pt!==r?(tr=ua(),tr!==r?(Nt=te,Ee=N(Oe,tr),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r),te===r&&(te=ve,Ee=Bl(),Ee!==r?(Oe=rs(),Oe!==r?(dt=Qn(),dt===r&&(dt=null),dt!==r?(t.charCodeAt(ve)===58?(Et=I,ve++):(Et=r,Tt===0&&$e(T)),Et!==r?(Pt=Qn(),Pt===r&&(Pt=null),Pt!==r?(tr=ua(),tr!==r?(Nt=te,Ee=N(Oe,tr),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r),te===r))){if(te=ve,Ee=Bl(),Ee!==r)if(Oe=rs(),Oe!==r)if(dt=Qn(),dt!==r)if(Et=pu(),Et!==r){if(Pt=[],tr=Ke(),tr!==r)for(;tr!==r;)Pt.push(tr),tr=Ke();else Pt=r;Pt!==r?(Nt=te,Ee=N(Oe,Et),te=Ee):(ve=te,te=r)}else ve=te,te=r;else ve=te,te=r;else ve=te,te=r;else ve=te,te=r;if(te===r)if(te=ve,Ee=Bl(),Ee!==r)if(Oe=rs(),Oe!==r){if(dt=[],Et=ve,Pt=Qn(),Pt===r&&(Pt=null),Pt!==r?(t.charCodeAt(ve)===44?(tr=U,ve++):(tr=r,Tt===0&&$e(W)),tr!==r?(An=Qn(),An===r&&(An=null),An!==r?(li=rs(),li!==r?(Nt=Et,Pt=ee(Oe,li),Et=Pt):(ve=Et,Et=r)):(ve=Et,Et=r)):(ve=Et,Et=r)):(ve=Et,Et=r),Et!==r)for(;Et!==r;)dt.push(Et),Et=ve,Pt=Qn(),Pt===r&&(Pt=null),Pt!==r?(t.charCodeAt(ve)===44?(tr=U,ve++):(tr=r,Tt===0&&$e(W)),tr!==r?(An=Qn(),An===r&&(An=null),An!==r?(li=rs(),li!==r?(Nt=Et,Pt=ee(Oe,li),Et=Pt):(ve=Et,Et=r)):(ve=Et,Et=r)):(ve=Et,Et=r)):(ve=Et,Et=r);else dt=r;dt!==r?(Et=Qn(),Et===r&&(Et=null),Et!==r?(t.charCodeAt(ve)===58?(Pt=I,ve++):(Pt=r,Tt===0&&$e(T)),Pt!==r?(tr=Qn(),tr===r&&(tr=null),tr!==r?(An=ua(),An!==r?(Nt=te,Ee=ie(Oe,dt,An),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)}else ve=te,te=r;else ve=te,te=r}return te}function ua(){var te,Ee,Oe,dt,Et,Pt,tr;if(te=ve,Ee=ve,Tt++,Oe=ve,dt=st(),dt!==r?(Et=Mt(),Et!==r?(t.charCodeAt(ve)===45?(Pt=c,ve++):(Pt=r,Tt===0&&$e(f)),Pt!==r?(tr=Qn(),tr!==r?(dt=[dt,Et,Pt,tr],Oe=dt):(ve=Oe,Oe=r)):(ve=Oe,Oe=r)):(ve=Oe,Oe=r)):(ve=Oe,Oe=r),Tt--,Oe!==r?(ve=Ee,Ee=void 0):Ee=r,Ee!==r?(Oe=Ke(),Oe!==r?(dt=kn(),dt!==r?(Et=wn(),Et!==r?(Pt=fa(),Pt!==r?(Nt=te,Ee=ue(Et),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r),te===r&&(te=ve,Ee=st(),Ee!==r?(Oe=kn(),Oe!==r?(dt=LA(),dt!==r?(Et=fa(),Et!==r?(Nt=te,Ee=ue(dt),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r),te===r))if(te=ve,Ee=cc(),Ee!==r){if(Oe=[],dt=Ke(),dt!==r)for(;dt!==r;)Oe.push(dt),dt=Ke();else Oe=r;Oe!==r?(Nt=te,EeLine truncated
`;if(typeof t=="number"||typeof t=="boolean")return`${t.toString()}
`;if(typeof t=="string")return`${dre(t)}
`;if(Array.isArray(t)){if(t.length===0)return`[]
`;let s=" ".repeat(e);return`
${t.map(n=>`${s}- ${n_(n,e+1,!1)}`).join("")}`}if(typeof t=="object"&&t){let[s,a]=t instanceof Sx?[t.data,!1]:[t,!0],n=" ".repeat(e),c=Object.keys(s);a&&c.sort((p,h)=>{let E=gre.indexOf(p),C=gre.indexOf(h);return E===-1&&C===-1?p<h?-1:p>h?1:0:E!==-1&&C===-1?-1:E===-1&&C!==-1?1:E-C});let f=c.filter(p=>!yre(s[p])).map((p,h)=>{let E=s[p],C=dre(p),S=n_(E,e+1,!0),b=h>0||r?n:"",I=C.length>1024?`? ${C}
${b}:`:`${C}:`,T=S.startsWith(`
`)?S:` ${S}`;return`${b}${I}${T}`}).join(e===0?`
`:"")||`
`;return r?`
${f}`:`${f}`}throw new Error(`Unsupported value type (${t})`)}function nl(t){try{let e=n_(t,0,!1);return e!==`
`?e:""}catch(e){throw e.location&&(e.message=e.message.replace(/(\.)?$/,` (line ${e.location.start.line}, column ${e.location.start.column})$1`)),e}}function yWe(t){return t.endsWith(`
`)||(t+=`
`),(0,mre.parse)(t)}function IWe(t){if(EWe.test(t))return yWe(t);let e=(0,Dx.safeLoad)(t,{schema:Dx.FAILSAFE_SCHEMA,json:!0});if(e==null)return{};if(typeof e!="object")throw new Error(`Expected an indexed object, got a ${typeof e} instead. Does your file follow Yaml's rules?`);if(Array.isArray(e))throw new Error("Expected an indexed object, got an array instead. Does your file follow Yaml's rules?");return e}function as(t){return IWe(t)}var Dx,mre,mWe,gre,Sx,EWe,Ere=Ze(()=>{Dx=ut(Are()),mre=ut(hre()),mWe=/^(?![-?:,\][{}#&*!|>'"%@` \t\r\n]).([ \t]*(?![,\][{}:# \t\r\n]).)*$/,gre=["__metadata","version","resolution","dependencies","peerDependencies","dependenciesMeta","peerDependenciesMeta","binaries"],Sx=class{constructor(e){this.data=e}};nl.PreserveOrdering=Sx;EWe=/^(#.*(\r?\n))*?#\s+yarn\s+lockfile\s+v1\r?\n/i});var J2={};Vt(J2,{parseResolution:()=>px,parseShell:()=>ux,parseSyml:()=>as,stringifyArgument:()=>GU,stringifyArgumentSegment:()=>qU,stringifyArithmeticExpression:()=>Ax,stringifyCommand:()=>jU,stringifyCommandChain:()=>AE,stringifyCommandChainThen:()=>HU,stringifyCommandLine:()=>fx,stringifyCommandLineThen:()=>_U,stringifyEnvSegment:()=>cx,stringifyRedirectArgument:()=>H2,stringifyResolution:()=>hx,stringifyShell:()=>fE,stringifyShellLine:()=>fE,stringifySyml:()=>nl,stringifyValueArgument:()=>vd});var wc=Ze(()=>{yee();wee();Ere()});var Cre=_((kQt,i_)=>{"use strict";var CWe=t=>{let e=!1,r=!1,s=!1;for(let a=0;a<t.length;a++){let n=t[a];e&&/[a-zA-Z]/.test(n)&&n.toUpperCase()===n?(t=t.slice(0,a)+"-"+t.slice(a),e=!1,s=r,r=!0,a++):r&&s&&/[a-zA-Z]/.test(n)&&n.toLowerCase()===n?(t=t.slice(0,a-1)+"-"+t.slice(a-1),s=r,r=!1,e=!0):(e=n.toLowerCase()===n&&n.toUpperCase()!==n,s=r,r=n.toUpperCase()===n&&n.toLowerCase()!==n)}return t},Ire=(t,e)=>{if(!(typeof t=="string"||Array.isArray(t)))throw new TypeError("Expected the input to be `string | string[]`");e=Object.assign({pascalCase:!1},e);let r=a=>e.pascalCase?a.charAt(0).toUpperCase()+a.slice(1):a;return Array.isArray(t)?t=t.map(a=>a.trim()).filter(a=>a.length).join("-"):t=t.trim(),t.length===0?"":t.length===1?e.pascalCase?t.toUpperCase():t.toLowerCase():(t!==t.toLowerCase()&&(t=CWe(t)),t=t.replace(/^[_.\- ]+/,"").toLowerCase().replace(/[_.\- ]+(\w|$)/g,(a,n)=>n.toUpperCase()).replace(/\d+(\w|$)/g,a=>a.toUpperCase()),r(t))};i_.exports=Ire;i_.exports.default=Ire});var wre=_((QQt,wWe)=>{wWe.exports=[{name:"Agola CI",constant:"AGOLA",env:"AGOLA_GIT_REF",pr:"AGOLA_PULL_REQUEST_ID"},{name:"Appcircle",constant:"APPCIRCLE",env:"AC_APPCIRCLE"},{name:"AppVeyor",constant:"APPVEYOR",env:"APPVEYOR",pr:"APPVEYOR_PULL_REQUEST_NUMBER"},{name:"AWS CodeBuild",constant:"CODEBUILD",env:"CODEBUILD_BUILD_ARN"},{name:"Azure Pipelines",constant:"AZURE_PIPELINES",env:"TF_BUILD",pr:{BUILD_REASON:"PullRequest"}},{name:"Bamboo",constant:"BAMBOO",env:"bamboo_planKey"},{name:"Bitbucket Pipelines",constant:"BITBUCKET",env:"BITBUCKET_COMMIT",pr:"BITBUCKET_PR_ID"},{name:"Bitrise",constant:"BITRISE",env:"BITRISE_IO",pr:"BITRISE_PULL_REQUEST"},{name:"Buddy",constant:"BUDDY",env:"BUDDY_WORKSPACE_ID",pr:"BUDDY_EXECUTION_PULL_REQUEST_ID"},{name:"Buildkite",constant:"BUILDKITE",env:"BUILDKITE",pr:{env:"BUILDKITE_PULL_REQUEST",ne:"false"}},{name:"CircleCI",constant:"CIRCLE",env:"CIRCLECI",pr:"CIRCLE_PULL_REQUEST"},{name:"Cirrus CI",constant:"CIRRUS",env:"CIRRUS_CI",pr:"CIRRUS_PR"},{name:"Codefresh",constant:"CODEFRESH",env:"CF_BUILD_ID",pr:{any:["CF_PULL_REQUEST_NUMBER","CF_PULL_REQUEST_ID"]}},{name:"Codemagic",constant:"CODEMAGIC",env:"CM_BUILD_ID",pr:"CM_PULL_REQUEST"},{name:"Codeship",constant:"CODESHIP",env:{CI_NAME:"codeship"}},{name:"Drone",constant:"DRONE",env:"DRONE",pr:{DRONE_BUILD_EVENT:"pull_request"}},{name:"dsari",constant:"DSARI",env:"DSARI"},{name:"Earthly",constant:"EARTHLY",env:"EARTHLY_CI"},{name:"Expo Application Services",constant:"EAS",env:"EAS_BUILD"},{name:"Gerrit",constant:"GERRIT",env:"GERRIT_PROJECT"},{name:"Gitea Actions",constant:"GITEA_ACTIONS",env:"GITEA_ACTIONS"},{name:"GitHub Actions",constant:"GITHUB_ACTIONS",env:"GITHUB_ACTIONS",pr:{GITHUB_EVENT_NAME:"pull_request"}},{name:"GitLab CI",constant:"GITLAB",env:"GITLAB_CI",pr:"CI_MERGE_REQUEST_ID"},{name:"GoCD",constant:"GOCD",env:"GO_PIPELINE_LABEL"},{name:"Google Cloud Build",constant:"GOOGLE_CLOUD_BUILD",env:"BUILDER_OUTPUT"},{name:"Harness CI",constant:"HARNESS",env:"HARNESS_BUILD_ID"},{name:"Heroku",constant:"HEROKU",env:{env:"NODE",includes:"/app/.heroku/node/bin/node"}},{name:"Hudson",constant:"HUDSON",env:"HUDSON_URL"},{name:"Jenkins",constant:"JENKINS",env:["JENKINS_URL","BUILD_ID"],pr:{any:["ghprbPullId","CHANGE_ID"]}},{name:"LayerCI",constant:"LAYERCI",env:"LAYERCI",pr:"LAYERCI_PULL_REQUEST"},{name:"Magnum CI",constant:"MAGNUM",env:"MAGNUM"},{name:"Netlify CI",constant:"NETLIFY",env:"NETLIFY",pr:{env:"PULL_REQUEST",ne:"false"}},{name:"Nevercode",constant:"NEVERCODE",env:"NEVERCODE",pr:{env:"NEVERCODE_PULL_REQUEST",ne:"false"}},{name:"Prow",constant:"PROW",env:"PROW_JOB_ID"},{name:"ReleaseHub",constant:"RELEASEH Line truncated
${this.candidates.map(({usage:a})=>`$ ${a}`).join(`
`)}`}else if(this.candidates.length===1){let[{usage:s}]=this.candidates;this.message=`Command not found; did you mean:
$ ${s}
${l_(e)}`}else this.message=`Command not found; did you mean one of:
${this.candidates.map(({usage:s},a)=>`${`${a}.`.padStart(4)} ${s}`).join(`
`)}
${l_(e)}`}},xx=class extends Error{constructor(e,r){super(),this.input=e,this.usages=r,this.clipanion={type:"none"},this.name="AmbiguousSyntaxError",this.message=`Cannot find which to pick amongst the following alternatives:
${this.usages.map((s,a)=>`${`${a}.`.padStart(4)} ${s}`).join(`
`)}
${l_(e)}`}},l_=t=>`While running ${t.filter(e=>e!==ei.EndOfInput&&e!==ei.EndOfPartialInput).map(e=>{let r=JSON.stringify(e);return e.match(/\s/)||e.length===0||r!==`"${e}"`?r:e}).join(" ")}`});function BWe(t){let e=t.split(`
`),r=e.filter(a=>a.match(/\S/)),s=r.length>0?r.reduce((a,n)=>Math.min(a,n.length-n.trimStart().length),Number.MAX_VALUE):0;return e.map(a=>a.slice(s).trimRight()).join(`
`)}function Ho(t,{format:e,paragraphs:r}){return t=t.replace(/\r\n?/g,`
`),t=BWe(t),t=t.replace(/^\n+|\n+$/g,""),t=t.replace(/^(\s*)-([^\n]*?)\n+/gm,`$1-$2
`),t=t.replace(/\n(\n)?\n*/g,(s,a)=>a||" "),r&&(t=t.split(/\n/).map(s=>{let a=s.match(/^\s*[*-][\t ]+(.*)/);if(!a)return s.match(/(.{1,80})(?: |$)/g).join(`
`);let n=s.length-s.trimStart().length;return a[1].match(new RegExp(`(.{1,${78-n}})(?: |$)`,"g")).map((c,f)=>" ".repeat(n)+(f===0?"- ":" ")+c).join(`
`)}).join(`
`)),t=t.replace(/(`+)((?:.|[\n])*?)\1/g,(s,a,n)=>e.code(a+n+a)),t=t.replace(/(\*\*)((?:.|[\n])*?)\1/g,(s,a,n)=>e.bold(a+n+a)),t?`${t}
`:""}var c_,Dre,Pre,u_=Ze(()=>{c_=Array(80).fill("\u2501");for(let t=0;t<=24;++t)c_[c_.length-t]=`\x1B[38;5;${232+t}m\u2501`;Dre={header:t=>`\x1B[1m\u2501\u2501\u2501 ${t}${t.length<75?` ${c_.slice(t.length+5).join("")}`:":"}\x1B[0m`,bold:t=>`\x1B[1m${t}\x1B[22m`,error:t=>`\x1B[31m\x1B[1m${t}\x1B[22m\x1B[39m`,code:t=>`\x1B[36m${t}\x1B[39m`},Pre={header:t=>t,bold:t=>t,error:t=>t,code:t=>t}});function ya(t){return{...t,[K2]:!0}}function Gf(t,e){return typeof t>"u"?[t,e]:typeof t=="object"&&t!==null&&!Array.isArray(t)?[void 0,t]:[t,e]}function Qx(t,{mergeName:e=!1}={}){let r=t.match(/^([^:]+): (.*)$/m);if(!r)return"validation failed";let[,s,a]=r;return e&&(a=a[0].toLowerCase()+a.slice(1)),a=s!=="."||!e?`${s.replace(/^\.(\[|$)/,"$1")}: ${a}`:`: ${a}`,a}function z2(t,e){return e.length===1?new nt(`${t}${Qx(e[0],{mergeName:!0})}`):new nt(`${t}:
${e.map(r=>`
- ${Qx(r)}`).join("")}`)}function Od(t,e,r){if(typeof r>"u")return e;let s=[],a=[],n=f=>{let p=e;return e=f,n.bind(null,p)};if(!r(e,{errors:s,coercions:a,coercion:n}))throw z2(`Invalid value for ${t}`,s);for(let[,f]of a)f();return e}var K2,Cp=Ze(()=>{kx();K2=Symbol("clipanion/isOption")});var Ea={};Vt(Ea,{KeyRelationship:()=>qf,TypeAssertionError:()=>o0,applyCascade:()=>$2,as:()=>jWe,assert:()=>UWe,assertWithErrors:()=>_We,cascade:()=>Nx,fn:()=>GWe,hasAtLeastOneKey:()=>m_,hasExactLength:()=>Rre,hasForbiddenKeys:()=>lYe,hasKeyRelationship:()=>tB,hasMaxLength:()=>WWe,hasMinLength:()=>qWe,hasMutuallyExclusiveKeys:()=>cYe,hasRequiredKeys:()=>aYe,hasUniqueItems:()=>YWe,isArray:()=>Rx,isAtLeast:()=>g_,isAtMost:()=>KWe,isBase64:()=>nYe,isBoolean:()=>QWe,isDate:()=>TWe,isDict:()=>OWe,isEnum:()=>fo,isHexColor:()=>rYe,isISO8601:()=>tYe,isInExclusiveRange:()=>ZWe,isInInclusiveRange:()=>zWe,isInstanceOf:()=>MWe,isInteger:()=>d_,isJSON:()=>iYe,isLiteral:()=>xre,isLowerCase:()=>XWe,isMap:()=>NWe,isNegative:()=>VWe,isNullable:()=>oYe,isNumber:()=>p_,isObject:()=>kre,isOneOf:()=>h_,isOptional:()=>sYe,isPartial:()=>LWe,isPayload:()=>RWe,isPositive:()=>JWe,isRecord:()=>Fx,isSet:()=>FWe,isString:()=>wE,isTuple:()=>Tx,isUUID4:()=>eYe,isUnknown:()=>A_,isUpperCase:()=>$We,makeTrait:()=>Qre,makeValidator:()=>Wr,matchesRegExp:()=>X2,softAssert:()=>HWe});function ti(t){return t===null?"null":t===void 0?"undefined":t===""?"an empty string":typeof t=="symbol"?`<${t.toString()}>`:Array.isArray(t)?"an array":JSON.stringify(t)}function CE(t,e){if(t.length===0)return"nothing";if(t.length===1)return ti(t[0]);let r=t.slice(0,-1),s=t[t.length-1],a=t.length>2?`, ${e} `:` ${e} `;return`${r.map(n=>ti(n)).join(", ")}${a}${ti(s)}`}function s0(t,e){var r,s,a;return typeof e=="number"?`${(r=t?.p)!==null&&r!==void 0?r:"."}[${e}]`:vWe.test(e)?`${(s=t?.p)!==null&&s!==void 0?s:""}.${e}`:`${(a=t?.p)!==null&&a!==void 0?a:"."}[${JSON.stringify(e)}]`}function f_(t,e,r){return t===1?e:r}function mr({errors:t,p:e}={},r){return t?.push(`${e??"."}: ${r}`),!1}function xWe(t,e){return r=>{t[e]=r}}function Wf(t,e){return r=>{let s=t[e];return t[e]=r,Wf(t,e).bind(null,s)}}function Z2(t,e,r){let s=()=>(t(r()),a),a=()=>(t(e),s);return s}function A_(){return Wr({test:(t,e)=>!0})}function xre(t){return Wr({test:(e,r)=>e!==t?mr(r,`Expected ${ti(t)} (got ${ti(e)})`):!0})}function wE(){return Wr({test:(t,e)=>typeof t!="string"?mr(e,`Expected a string (got ${ti(t)})`):!0})}function fo(t){let e=Array.isArray(t)?t:Object.values(t),r=e.every(a=>typeof a=="string"||typeof a=="number"),s=new Set(e);return s.size===1?xre([...s][0]):Wr({test:(a,n)=>s.has(a)?!0:r?mr(n,`Expected one of ${CE(e,"or")} (got ${ti(a)})`):mr(n,`Expected a valid enumeration value (got ${ti(a)})`)})}function QWe(){return Wr({test:(t,e)=>{var r;if(typeof t!="boolean"){if(typeof e?.coercions<"u"){if(typeof e?.coercion>"u")return mr(e,"Unbound coercion result");let s=kWe.get(t);if(typeof s<"u")return e.coercions.push([(r=e.p)!==null&&r!==void 0?r:".",e.coercion.bind(null,s)]),!0}return mr(e,`Expected a boolean (got ${ti(t)})`)}return!0}})}function p_(){return Wr({test:(t,e)=>{var r;if(typeof t!="number"){if(typeof e?.coercions<"u"){if(typeof e?.coercion>"u")return mr(e,"Unbound coercion result");let s;if(typeof t=="string"){let a;try{a=JSON.parse(t)}catch{}if(typeof a=="number")if(JSON.stringify(a)===t)s=a;else return mr(e,`Received a number that can't be safely represented by the runtime (${t})`)}if(typeof s<"u")return e.coercions.push([(r=e.p)!==null&&r!==void 0?r:".",e.coercion.bind(null,s)]),!0}return mr(e,`Expected a number (got ${ti(t)})`)}return!0}})}function RWe(t){return Wr({test:(e,r)=>{var s;if(typeof r?.coercions>"u")return mr(r,"The isPayload predicate can only be used with coercion enabled");if(typeof r.coercion>"u")return mr(r,"Unbound coercion result");if(typeof e!="string")return mr(r,`Expected a string (got ${ti(e)})`);let a;try{a=JSON.parse(e)}catch{return mr(r,`Expected a JSON string (got ${ti(e)})`)}let n={value:a};return t(a,Object.assign(Object.assign({},r),{coercion:Wf(n,"value")}))?(r.coercions.push([(s=r.p)!==null&&s!==void 0?s:".",r.coercion.bind(null,n.value)]),!0):!1}})}function TWe(){return Wr({test:(t,e)=>{var r;if(!(t instanceof Date)){if(typeof e?.coercions<"u"){if(typeof e?.coercion>"u")return mr(e,"Unbound coercion result");let s;if(typeof t=="string"&&bre.test(t))s=new Date(t);else{let a;if(typeof t=="string"){let n;try{n=JSON.parse(t)}catch{}typeof n=="number"&&(a=n)}else typeof t=="number"&&(a=t);if(typeof a<"u")if(Number.isSafeInteger(a)||!Number.isSafeInteger(a*1e3))s=new Date(a*1e3);else return mr(e,`Received a timestamp that can't be safely represented by the runtime (${t})`)}if(typeof s<"u")return e.coercions.push([(r=e.p)!==null&&r!==void 0?r:".",e.coercion.bind(null,s)]),!0}return mr(e,`Expected a date (got ${ti(t)})`)}return!0}})}function Rx(t,{delimiter:e}={}){return Wr({test:(r,s)=>{var a;let n=r;if(typeof r=="string"&&typeof e<"u"&&typeof s?.coercions<"u"){iLine truncated
`;for(let s of e)r+=`
- ${s}`}super(r)}};eB={missing:(t,e)=>t.has(e),undefined:(t,e,r)=>t.has(e)&&typeof r[e]<"u",nil:(t,e,r)=>t.has(e)&&r[e]!=null,falsy:(t,e,r)=>t.has(e)&&!!r[e]};(function(t){t.Forbids="Forbids",t.Requires="Requires"})(qf||(qf={}));uYe={[qf.Forbids]:{expect:!1,message:"forbids using"},[qf.Requires]:{expect:!0,message:"requires using"}}});var ot,a0=Ze(()=>{Cp();ot=class{constructor(){this.help=!1}static Usage(e){return e}async catch(e){throw e}async validateAndExecute(){let r=this.constructor.schema;if(Array.isArray(r)){let{isDict:a,isUnknown:n,applyCascade:c}=await Promise.resolve().then(()=>(Ul(),Ea)),f=c(a(n()),r),p=[],h=[];if(!f(this,{errors:p,coercions:h}))throw z2("Invalid option schema",p);for(let[,C]of h)C()}else if(r!=null)throw new Error("Invalid command schema");let s=await this.execute();return typeof s<"u"?s:0}};ot.isOption=K2;ot.Default=[]});function il(t){a_&&console.log(t)}function Fre(){let t={nodes:[]};for(let e=0;e<En.CustomNode;++e)t.nodes.push(_l());return t}function fYe(t){let e=Fre(),r=[],s=e.nodes.length;for(let a of t){r.push(s);for(let n=0;n<a.nodes.length;++n)Ore(n)||e.nodes.push(EYe(a.nodes[n],s));s+=a.nodes.length-En.CustomNode+1}for(let a of r)BE(e,En.InitialNode,a);return e}function Ou(t,e){return t.nodes.push(e),t.nodes.length-1}function AYe(t){let e=new Set,r=s=>{if(e.has(s))return;e.add(s);let a=t.nodes[s];for(let c of Object.values(a.statics))for(let{to:f}of c)r(f);for(let[,{to:c}]of a.dynamics)r(c);for(let{to:c}of a.shortcuts)r(c);let n=new Set(a.shortcuts.map(({to:c})=>c));for(;a.shortcuts.length>0;){let{to:c}=a.shortcuts.shift(),f=t.nodes[c];for(let[p,h]of Object.entries(f.statics)){let E=Object.prototype.hasOwnProperty.call(a.statics,p)?a.statics[p]:a.statics[p]=[];for(let C of h)E.some(({to:S})=>C.to===S)||E.push(C)}for(let[p,h]of f.dynamics)a.dynamics.some(([E,{to:C}])=>p===E&&h.to===C)||a.dynamics.push([p,h]);for(let p of f.shortcuts)n.has(p.to)||(a.shortcuts.push(p),n.add(p.to))}};r(En.InitialNode)}function pYe(t,{prefix:e=""}={}){if(a_){il(`${e}Nodes are:`);for(let r=0;r<t.nodes.length;++r)il(`${e} ${r}: ${JSON.stringify(t.nodes[r])}`)}}function hYe(t,e,r=!1){il(`Running a vm on ${JSON.stringify(e)}`);let s=[{node:En.InitialNode,state:{candidateUsage:null,requiredOptions:[],errorMessage:null,ignoreOptions:!1,options:[],path:[],positionals:[],remainder:null,selectedIndex:null,partial:!1,tokens:[]}}];pYe(t,{prefix:" "});let a=[ei.StartOfInput,...e];for(let n=0;n<a.length;++n){let c=a[n],f=c===ei.EndOfInput||c===ei.EndOfPartialInput,p=n-1;il(` Processing ${JSON.stringify(c)}`);let h=[];for(let{node:E,state:C}of s){il(` Current node is ${E}`);let S=t.nodes[E];if(E===En.ErrorNode){h.push({node:E,state:C});continue}console.assert(S.shortcuts.length===0,"Shortcuts should have been eliminated by now");let b=Object.prototype.hasOwnProperty.call(S.statics,c);if(!r||n<a.length-1||b)if(b){let I=S.statics[c];for(let{to:T,reducer:N}of I)h.push({node:T,state:typeof N<"u"?Ox(E_,N,C,c,p):C}),il(` Static transition to ${T} found`)}else il(" No static transition found");else{let I=!1;for(let T of Object.keys(S.statics))if(T.startsWith(c)){if(c===T)for(let{to:N,reducer:U}of S.statics[T])h.push({node:N,state:typeof U<"u"?Ox(E_,U,C,c,p):C}),il(` Static transition to ${N} found`);else for(let{to:N}of S.statics[T])h.push({node:N,state:{...C,remainder:T.slice(c.length)}}),il(` Static transition to ${N} found (partial match)`);I=!0}I||il(" No partial static transition found")}if(!f)for(let[I,{to:T,reducer:N}]of S.dynamics)Ox(IYe,I,C,c,p)&&(h.push({node:T,state:typeof N<"u"?Ox(E_,N,C,c,p):C}),il(` Dynamic transition to ${T} found (via ${I})`))}if(h.length===0&&f&&e.length===1)return[{node:En.InitialNode,state:Tre}];if(h.length===0)throw new IE(e,s.filter(({node:E})=>E!==En.ErrorNode).map(({state:E})=>({usage:E.candidateUsage,reason:null})));if(h.every(({node:E})=>E===En.ErrorNode))throw new IE(e,h.map(({state:E})=>({usage:E.candidateUsage,reason:E.errorMessage})));s=dYe(h)}if(s.length>0){il(" Results:");for(let n of s)il(` - ${n.node} -> ${JSON.stringify(n.state)}`)}else il(" No results");return s}function gYe(t,e,{endToken:r=ei.EndOfInput}={}){let s=hYe(t,[...e,r]);return mYe(e,s.map(({state:a})=>a))}function dYe(t){let e=0;for(let{state:r}of t)r.path.length>e&&(e=r.path.length);return t.filter(({state:r})=>r.path.length===e)}function mYe(t,e){let r=e.filter(S=>S.selectedIndex!==null),s=r.filter(S=>!S.partial);if(s.length>0&&(r=s),r.length===0)throw new Error;let a=r.filter(S=>S.selectedIndex===Nd||S.requiredOptions.every(b=>b.some(I=>S.options.find(T=>T.name===I))));if(a.length===0)throw new IE(t,r.map(S=>({usage:S.candidateUsage,reason:null})));let n=0;for(let S of a)S.path.length>n&&(n=S.path.length);let c=a.filter(S=>S.path.length===n),f=S=>S.positionals.filter(({extra:b})=>!b).length+S.options.length,p=c.map(S=>({state:S,positionalCount:f(S)})),h=0;for(let{positionalCount:S}of p)S>h&&(h=S);let E=p.filter(({positionalCount:S})=>S===h).map(({state:S Line truncated
`),this.context.stdout.write(`
`);let r=0;for(let s of this.commands)this.context.stdout.write(this.cli.usage(this.contexts[s].commandClass,{prefix:`${r++}. `.padStart(5)}));this.context.stdout.write(`
`),this.context.stdout.write(`Run again with -h=<index> to see the longer details of any of those commands.
`)}}}});async function qre(...t){let{resolvedOptions:e,resolvedCommandClasses:r,resolvedArgv:s,resolvedContext:a}=Yre(t);return Ca.from(r,e).runExit(s,a)}async function Wre(...t){let{resolvedOptions:e,resolvedCommandClasses:r,resolvedArgv:s,resolvedContext:a}=Yre(t);return Ca.from(r,e).run(s,a)}function Yre(t){let e,r,s,a;switch(typeof process<"u"&&typeof process.argv<"u"&&(s=process.argv.slice(2)),t.length){case 1:r=t[0];break;case 2:t[0]&&t[0].prototype instanceof ot||Array.isArray(t[0])?(r=t[0],Array.isArray(t[1])?s=t[1]:a=t[1]):(e=t[0],r=t[1]);break;case 3:Array.isArray(t[2])?(e=t[0],r=t[1],s=t[2]):t[0]&&t[0].prototype instanceof ot||Array.isArray(t[0])?(r=t[0],s=t[1],a=t[2]):(e=t[0],r=t[1],a=t[2]);break;default:e=t[0],r=t[1],s=t[2],a=t[3];break}if(typeof s>"u")throw new Error("The argv parameter must be provided when running Clipanion outside of a Node context");return{resolvedOptions:e,resolvedCommandClasses:r,resolvedArgv:s,resolvedContext:a}}function Gre(t){return t()}var jre,Ca,Vre=Ze(()=>{bx();Mx();u_();_re();a0();Hre();jre=Symbol("clipanion/errorCommand");Ca=class t{constructor({binaryLabel:e,binaryName:r="...",binaryVersion:s,enableCapture:a=!1,enableColors:n}={}){this.registrations=new Map,this.builder=new Lx({binaryName:r}),this.binaryLabel=e,this.binaryName=r,this.binaryVersion=s,this.enableCapture=a,this.enableColors=n}static from(e,r={}){let s=new t(r),a=Array.isArray(e)?e:[e];for(let n of a)s.register(n);return s}register(e){var r;let s=new Map,a=new e;for(let p in a){let h=a[p];typeof h=="object"&&h!==null&&h[ot.isOption]&&s.set(p,h)}let n=this.builder.command(),c=n.cliIndex,f=(r=e.paths)!==null&&r!==void 0?r:a.paths;if(typeof f<"u")for(let p of f)n.addPath(p);this.registrations.set(e,{specs:s,builder:n,index:c});for(let[p,{definition:h}]of s.entries())h(n,p);n.setContext({commandClass:e})}process(e,r){let{input:s,context:a,partial:n}=typeof e=="object"&&Array.isArray(e)?{input:e,context:r}:e,{contexts:c,process:f}=this.builder.compile(),p=f(s,{partial:n}),h={...t.defaultContext,...a};switch(p.selectedIndex){case Nd:{let E=_x.from(p,c);return E.context=h,E.tokens=p.tokens,E}default:{let{commandClass:E}=c[p.selectedIndex],C=this.registrations.get(E);if(typeof C>"u")throw new Error("Assertion failed: Expected the command class to have been registered.");let S=new E;S.context=h,S.tokens=p.tokens,S.path=p.path;try{for(let[b,{transformer:I}]of C.specs.entries())S[b]=I(C.builder,b,p,h);return S}catch(b){throw b[jre]=S,b}}break}}async run(e,r){var s,a;let n,c={...t.defaultContext,...r},f=(s=this.enableColors)!==null&&s!==void 0?s:c.colorDepth>1;if(!Array.isArray(e))n=e;else try{n=this.process(e,c)}catch(E){return c.stdout.write(this.error(E,{colored:f})),1}if(n.help)return c.stdout.write(this.usage(n,{colored:f,detailed:!0})),0;n.context=c,n.cli={binaryLabel:this.binaryLabel,binaryName:this.binaryName,binaryVersion:this.binaryVersion,enableCapture:this.enableCapture,enableColors:this.enableColors,definitions:()=>this.definitions(),definition:E=>this.definition(E),error:(E,C)=>this.error(E,C),format:E=>this.format(E),process:(E,C)=>this.process(E,{...c,...C}),run:(E,C)=>this.run(E,{...c,...C}),usage:(E,C)=>this.usage(E,C)};let p=this.enableCapture&&(a=Ure(c))!==null&&a!==void 0?a:Gre,h;try{h=await p(()=>n.validateAndExecute().catch(E=>n.catch(E).then(()=>0)))}catch(E){return c.stdout.write(this.error(E,{colored:f,command:n})),1}return h}async runExit(e,r){process.exitCode=await this.run(e,r)}definition(e,{colored:r=!1}={}){if(!e.usage)return null;let{usage:s}=this.getUsageByRegistration(e,{detailed:!1}),{usage:a,options:n}=this.getUsageByRegistration(e,{detailed:!0,inlineOptions:!1}),c=typeof e.usage.category<"u"?Ho(e.usage.category,{format:this.format(r),paragraphs:!1}):void 0,f=typeof e.usage.description<"u"?Ho(e.usage.description,{format:this.format(r),paragraphs:!1}):void 0,p=typeof e.usage.details<"u"?Ho(e.usage.details,{format:this.format(r),paragraphs:!0}):void 0,h=typeof e.usage.examples<"u"?e.usage.examples.map(([E,C])=>[Ho(E,{format:this.format(r),paragraphs:!1}),C.replace(/\$0/g,this.binaryName)]):void 0;return{path:s,usage:a,category:c,description:f,details:p,examples:h,options:n}}definitions({colored:e=!1}={}){let r=[];for(let s of this.registrations.keys()){let a=this.definition(s,{colored:e});a&&r.push(a)}return r}usage(e=null,{colored:r,detailed:s=!1,prefix:a="$ "}={}){var n;if(e===null){for(let p of this.registrations.keys()){let h=p.paths,E=typeof p.usage<"u";if(!h||h.length===0||h.length===1&&h[0].length===0||((n=h?.some(b=>b.length===0))!==null&&n!==void 0?n:!1))if(e){e=null;break}else e=p;else if(E){e=null;continue}}e&&(s=!0)}let c=e!==null&&e instanceof ot?e.constructor:e,f="";if(c)if(s){let{description:p="",details:h="",examples:E=[]}=c.usage||{};p!==""&&(f+=Ho(p,{format:this.format(r),paragraphs:!1}).replace(/^./,b=>b.toUpperCase()),f+=`
`),(h!==""||E.length>0)&&(f+=`${this.format(r).header("Usage")}
`,f+=`
`);let{usage:C,options:S}=this.getUsageByRegistration(c,{inlineOptions:!1});if(f+=`${this.format(r).bold(a)}${C}
`,S.length>0){f+=`
`,f+=`${this.format(r).header("Options")}
`;let b=S.reduce((I,T)=>Math.max(I,T.definition.length),0);f+=`
`;for(let{definition:I,description:T}of S)f+=` ${this.format(r).bold(I.padEnd(b))} ${Ho(T,{format:this.format(r),paragraphs:!1})}`}if(h!==""&&(f+=`
`,f+=`${this.format(r).header("Details")}
`,f+=`
`,f+=Ho(h,{format:this.format(r),paragraphs:!0})),E.length>0){f+=`
`,f+=`${this.format(r).header("Examples")}
`;for(let[b,I]of E)f+=`
`,f+=Ho(b,{format:this.format(r),paragraphs:!1}),f+=`${I.replace(/^/m,` ${this.format(r).bold(a)}`).replace(/\$0/g,this.binaryName)}
`}}else{let{usage:p}=this.getUsageByRegistration(c);f+=`${this.format(r).bold(a)}${p}
`}else{let p=new Map;for(let[S,{index:b}]of this.registrations.entries()){if(typeof S.usage>"u")continue;let I=typeof S.usage.category<"u"?Ho(S.usage.category,{format:this.format(r),paragraphs:!1}):null,T=p.get(I);typeof T>"u"&&p.set(I,T=[]);let{usage:N}=this.getUsageByIndex(b);T.push({commandClass:S,usage:N})}let h=Array.from(p.keys()).sort((S,b)=>S===null?-1:b===null?1:S.localeCompare(b,"en",{usage:"sort",caseFirst:"upper"})),E=typeof this.binaryLabel<"u",C=typeof this.binaryVersion<"u";E||C?(E&&C?f+=`${this.format(r).header(`${this.binaryLabel} - ${this.binaryVersion}`)}
`:E?f+=`${this.format(r).header(`${this.binaryLabel}`)}
`:f+=`${this.format(r).header(`${this.binaryVersion}`)}
`,f+=` ${this.format(r).bold(a)}${this.binaryName} <command>
`):f+=`${this.format(r).bold(a)}${this.binaryName} <command>
`;for(let S of h){let b=p.get(S).slice().sort((T,N)=>T.usage.localeCompare(N.usage,"en",{usage:"sort",caseFirst:"upper"})),I=S!==null?S.trim():"General commands";f+=`
`,f+=`${this.format(r).header(`${I}`)}
`;for(let{commandClass:T,usage:N}of b){let U=T.usage.description||"undocumented";f+=`
`,f+=` ${this.format(r).bold(N)}
`,f+=` ${Ho(U,{format:this.format(r),paragraphs:!1})}`}}f+=`
`,f+=Ho("You can also print more details about any of these commands by calling them with the `-h,--help` flag right after the command name.",{format:this.format(r),paragraphs:!0})}return f}error(e,r){var s,{colored:a,command:n=(s=e[jre])!==null&&s!==void 0?s:null}=r===void 0?{}:r;(!e||typeof e!="object"||!("stack"in e))&&(e=new Error(`Execution failed with a non-error rejection (rejected value: ${JSON.stringify(e)})`));let c="",f=e.name.replace(/([a-z])([A-Z])/g,"$1 $2");f==="Error"&&(f="Internal Error"),c+=`${this.format(a).error(f)}: ${e.message}
`;let p=e.clipanion;return typeof p<"u"?p.type==="usage"&&(c+=`
`,c+=this.usage(n)):e.stack&&(c+=`${e.stack.replace(/^.*\n/,"")}
`),c}format(e){var r;return((r=e??this.enableColors)!==null&&r!==void 0?r:t.defaultContext.colorDepth>1)?Dre:Pre}getUsageByRegistration(e,r){let s=this.registrations.get(e);if(typeof s>"u")throw new Error("Assertion failed: Unregistered command");return this.getUsageByIndex(s.index,r)}getUsageByIndex(e,r){return this.builder.getBuilderByIndex(e).usage(r)}};Ca.defaultContext={env:process.env,stdin:process.stdin,stdout:process.stdout,stderr:process.stderr,colorDepth:Mre()}});var rB,Jre=Ze(()=>{a0();rB=class extends ot{async execute(){this.context.stdout.write(`${JSON.stringify(this.cli.definitions(),null,2)}
`)}};rB.paths=[["--clipanion=definitions"]]});var nB,Kre=Ze(()=>{a0();nB=class extends ot{async execute(){this.context.stdout.write(this.cli.usage())}};nB.paths=[["-h"],["--help"]]});function Hx(t={}){return ya({definition(e,r){var s;e.addProxy({name:(s=t.name)!==null&&s!==void 0?s:r,required:t.required})},transformer(e,r,s){return s.positionals.map(({value:a})=>a)}})}var C_=Ze(()=>{Cp()});var iB,zre=Ze(()=>{a0();C_();iB=class extends ot{constructor(){super(...arguments),this.args=Hx()}async execute(){this.context.stdout.write(`${JSON.stringify(this.cli.process(this.args).tokens,null,2)}
`)}};iB.paths=[["--clipanion=tokens"]]});var sB,Zre=Ze(()=>{a0();sB=class extends ot{async execute(){var e;this.context.stdout.write(`${(e=this.cli.binaryVersion)!==null&&e!==void 0?e:"<unknown>"}
`)}};sB.paths=[["-v"],["--version"]]});var w_={};Vt(w_,{DefinitionsCommand:()=>rB,HelpCommand:()=>nB,TokensCommand:()=>iB,VersionCommand:()=>sB});var Xre=Ze(()=>{Jre();Kre();zre();Zre()});function $re(t,e,r){let[s,a]=Gf(e,r??{}),{arity:n=1}=a,c=t.split(","),f=new Set(c);return ya({definition(p){p.addOption({names:c,arity:n,hidden:a?.hidden,description:a?.description,required:a.required})},transformer(p,h,E){let C,S=typeof s<"u"?[...s]:void 0;for(let{name:b,value:I}of E.options)f.has(b)&&(C=b,S=S??[],S.push(I));return typeof S<"u"?Od(C??h,S,a.validator):S}})}var ene=Ze(()=>{Cp()});function tne(t,e,r){let[s,a]=Gf(e,r??{}),n=t.split(","),c=new Set(n);return ya({definition(f){f.addOption({names:n,allowBinding:!1,arity:0,hidden:a.hidden,description:a.description,required:a.required})},transformer(f,p,h){let E=s;for(let{name:C,value:S}of h.options)c.has(C)&&(E=S);return E}})}var rne=Ze(()=>{Cp()});function nne(t,e,r){let[s,a]=Gf(e,r??{}),n=t.split(","),c=new Set(n);return ya({definition(f){f.addOption({names:n,allowBinding:!1,arity:0,hidden:a.hidden,description:a.description,required:a.required})},transformer(f,p,h){let E=s;for(let{name:C,value:S}of h.options)c.has(C)&&(E??(E=0),S?E+=1:E=0);return E}})}var ine=Ze(()=>{Cp()});function sne(t={}){return ya({definition(e,r){var s;e.addRest({name:(s=t.name)!==null&&s!==void 0?s:r,required:t.required})},transformer(e,r,s){let a=c=>{let f=s.positionals[c];return f.extra===Hl||f.extra===!1&&c<e.arity.leading.length},n=0;for(;n<s.positionals.length&&a(n);)n+=1;return s.positionals.splice(0,n).map(({value:c})=>c)}})}var one=Ze(()=>{Mx();Cp()});function CYe(t,e,r){let[s,a]=Gf(e,r??{}),{arity:n=1}=a,c=t.split(","),f=new Set(c);return ya({definition(p){p.addOption({names:c,arity:a.tolerateBoolean?0:n,hidden:a.hidden,description:a.description,required:a.required})},transformer(p,h,E,C){let S,b=s;typeof a.env<"u"&&C.env[a.env]&&(S=a.env,b=C.env[a.env]);for(let{name:I,value:T}of E.options)f.has(I)&&(S=I,b=T);return typeof b=="string"?Od(S??h,b,a.validator):b}})}function wYe(t={}){let{required:e=!0}=t;return ya({definition(r,s){var a;r.addPositional({name:(a=t.name)!==null&&a!==void 0?a:s,required:t.required})},transformer(r,s,a){var n;for(let c=0;c<a.positionals.length;++c){if(a.positionals[c].extra===Hl||e&&a.positionals[c].extra===!0||!e&&a.positionals[c].extra===!1)continue;let[f]=a.positionals.splice(c,1);return Od((n=t.name)!==null&&n!==void 0?n:s,f.value,t.validator)}}})}function ane(t,...e){return typeof t=="string"?CYe(t,...e):wYe(t)}var lne=Ze(()=>{Mx();Cp()});var ge={};Vt(ge,{Array:()=>$re,Boolean:()=>tne,Counter:()=>nne,Proxy:()=>Hx,Rest:()=>sne,String:()=>ane,applyValidator:()=>Od,cleanValidationError:()=>Qx,formatError:()=>z2,isOptionSymbol:()=>K2,makeCommandOption:()=>ya,rerouteArguments:()=>Gf});var cne=Ze(()=>{Cp();C_();ene();rne();ine();one();lne()});var oB={};Vt(oB,{Builtins:()=>w_,Cli:()=>Ca,Command:()=>ot,Option:()=>ge,UsageError:()=>nt,formatMarkdownish:()=>Ho,run:()=>Wre,runExit:()=>qre});var Yt=Ze(()=>{kx();u_();a0();Vre();Xre();cne()});var une=_((MRt,BYe)=>{BYe.exports={name:"dotenv",version:"16.3.1",description:"Loads environment variables from .env file",main:"lib/main.js",types:"lib/main.d.ts",exports:{".":{types:"./lib/main.d.ts",require:"./lib/main.js",default:"./lib/main.js"},"./config":"./config.js","./config.js":"./config.js","./lib/env-options":"./lib/env-options.js","./lib/env-options.js":"./lib/env-options.js","./lib/cli-options":"./lib/cli-options.js","./lib/cli-options.js":"./lib/cli-options.js","./package.json":"./package.json"},scripts:{"dts-check":"tsc --project tests/types/tsconfig.json",lint:"standard","lint-readme":"standard-markdown",pretest:"npm run lint && npm run dts-check",test:"tap tests/*.js --100 -Rspec",prerelease:"npm test",release:"standard-version"},repository:{type:"git",url:"git://github.com/motdotla/dotenv.git"},funding:"https://github.com/motdotla/dotenv?sponsor=1",keywords:["dotenv","env",".env","environment","variables","config","settings"],readmeFilename:"README.md",license:"BSD-2-Clause",devDependencies:{"@definitelytyped/dtslint":"^0.0.133","@types/node":"^18.11.3",decache:"^4.6.1",sinon:"^14.0.1",standard:"^17.0.0","standard-markdown":"^7.1.0","standard-version":"^9.5.0",tap:"^16.3.0",tar:"^6.1.11",typescript:"^4.8.4"},engines:{node:">=12"},browser:{fs:!1}}});var hne=_((URt,wp)=>{var fne=Ie("fs"),v_=Ie("path"),vYe=Ie("os"),SYe=Ie("crypto"),DYe=une(),S_=DYe.version,PYe=/(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;function bYe(t){let e={},r=t.toString();r=r.replace(/\r\n?/mg,`
`);let s;for(;(s=PYe.exec(r))!=null;){let a=s[1],n=s[2]||"";n=n.trim();let c=n[0];n=n.replace(/^(['"`])([\s\S]*)\1$/mg,"$2"),c==='"'&&(n=n.replace(/\\n/g,`
`),n=n.replace(/\\r/g,"\r")),e[a]=n}return e}function xYe(t){let e=pne(t),r=js.configDotenv({path:e});if(!r.parsed)throw new Error(`MISSING_DATA: Cannot parse ${e} for an unknown reason`);let s=Ane(t).split(","),a=s.length,n;for(let c=0;c<a;c++)try{let f=s[c].trim(),p=RYe(r,f);n=js.decrypt(p.ciphertext,p.key);break}catch(f){if(c+1>=a)throw f}return js.parse(n)}function kYe(t){console.log(`[dotenv@${S_}][INFO] ${t}`)}function QYe(t){console.log(`[dotenv@${S_}][WARN] ${t}`)}function B_(t){console.log(`[dotenv@${S_}][DEBUG] ${t}`)}function Ane(t){return t&&t.DOTENV_KEY&&t.DOTENV_KEY.length>0?t.DOTENV_KEY:process.env.DOTENV_KEY&&process.env.DOTENV_KEY.length>0?process.env.DOTENV_KEY:""}function RYe(t,e){let r;try{r=new URL(e)}catch(f){throw f.code==="ERR_INVALID_URL"?new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:[email protected]/vault/.env.vault?environment=development"):f}let s=r.password;if(!s)throw new Error("INVALID_DOTENV_KEY: Missing key part");let a=r.searchParams.get("environment");if(!a)throw new Error("INVALID_DOTENV_KEY: Missing environment part");let n=`DOTENV_VAULT_${a.toUpperCase()}`,c=t.parsed[n];if(!c)throw new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${n} in your .env.vault file.`);return{ciphertext:c,key:s}}function pne(t){let e=v_.resolve(process.cwd(),".env");return t&&t.path&&t.path.length>0&&(e=t.path),e.endsWith(".vault")?e:`${e}.vault`}function TYe(t){return t[0]==="~"?v_.join(vYe.homedir(),t.slice(1)):t}function FYe(t){kYe("Loading env from encrypted .env.vault");let e=js._parseVault(t),r=process.env;return t&&t.processEnv!=null&&(r=t.processEnv),js.populate(r,e,t),{parsed:e}}function NYe(t){let e=v_.resolve(process.cwd(),".env"),r="utf8",s=!!(t&&t.debug);t&&(t.path!=null&&(e=TYe(t.path)),t.encoding!=null&&(r=t.encoding));try{let a=js.parse(fne.readFileSync(e,{encoding:r})),n=process.env;return t&&t.processEnv!=null&&(n=t.processEnv),js.populate(n,a,t),{parsed:a}}catch(a){return s&&B_(`Failed to load ${e} ${a.message}`),{error:a}}}function OYe(t){let e=pne(t);return Ane(t).length===0?js.configDotenv(t):fne.existsSync(e)?js._configVault(t):(QYe(`You set DOTENV_KEY but you are missing a .env.vault file at ${e}. Did you forget to build it?`),js.configDotenv(t))}function LYe(t,e){let r=Buffer.from(e.slice(-64),"hex"),s=Buffer.from(t,"base64"),a=s.slice(0,12),n=s.slice(-16);s=s.slice(12,-16);try{let c=SYe.createDecipheriv("aes-256-gcm",r,a);return c.setAuthTag(n),`${c.update(s)}${c.final()}`}catch(c){let f=c instanceof RangeError,p=c.message==="Invalid key length",h=c.message==="Unsupported state or unable to authenticate data";if(f||p){let E="INVALID_DOTENV_KEY: It must be 64 characters long (or more)";throw new Error(E)}else if(h){let E="DECRYPTION_FAILED: Please check your DOTENV_KEY";throw new Error(E)}else throw console.error("Error: ",c.code),console.error("Error: ",c.message),c}}function MYe(t,e,r={}){let s=!!(r&&r.debug),a=!!(r&&r.override);if(typeof e!="object")throw new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");for(let n of Object.keys(e))Object.prototype.hasOwnProperty.call(t,n)?(a===!0&&(t[n]=e[n]),s&&B_(a===!0?`"${n}" is already defined and WAS overwritten`:`"${n}" is already defined and was NOT overwritten`)):t[n]=e[n]}var js={configDotenv:NYe,_configVault:FYe,_parseVault:xYe,config:OYe,decrypt:LYe,parse:bYe,populate:MYe};wp.exports.configDotenv=js.configDotenv;wp.exports._configVault=js._configVault;wp.exports._parseVault=js._parseVault;wp.exports.config=js.config;wp.exports.decrypt=js.decrypt;wp.exports.parse=js.parse;wp.exports.populate=js.populate;wp.exports=js});var dne=_((_Rt,gne)=>{"use strict";gne.exports=(t,...e)=>new Promise(r=>{r(t(...e))})});var Ld=_((HRt,D_)=>{"use strict";var UYe=dne(),mne=t=>{if(t<1)throw new TypeError("Expected `concurrency` to be a number from 1 and up");let e=[],r=0,s=()=>{r--,e.length>0&&e.shift()()},a=(f,p,...h)=>{r++;let E=UYe(f,...h);p(E),E.then(s,s)},n=(f,p,...h)=>{r<t?a(f,p,...h):e.push(a.bind(null,f,p,...h))},c=(f,...p)=>new Promise(h=>n(f,h,...p));return Object.defineProperties(c,{activeCount:{get:()=>r},pendingCount:{get:()=>e.length}}),c};D_.exports=mne;D_.exports.default=mne});function Yf(t){return`YN${t.toString(10).padStart(4,"0")}`}function jx(t){let e=Number(t.slice(2));if(typeof Br[e]>"u")throw new Error(`Unknown message name: "${t}"`);return e}var Br,Gx=Ze(()=>{Br=(Me=>(Me[Me.UNNAMED=0]="UNNAMED",Me[Me.EXCEPTION=1]="EXCEPTION",Me[Me.MISSING_PEER_DEPENDENCY=2]="MISSING_PEER_DEPENDENCY",Me[Me.CYCLIC_DEPENDENCIES=3]="CYCLIC_DEPENDENCIES",Me[Me.DISABLED_BUILD_SCRIPTS=4]="DISABLED_BUILD_SCRIPTS",Me[Me.BUILD_DISABLED=5]="BUILD_DISABLED",Me[Me.SOFT_LINK_BUILD=6]="SOFT_LINK_BUILD",Me[Me.MUST_BUILD=7]="MUST_BUILD",Me[Me.MUST_REBUILD=8]="MUST_REBUILD",Me[Me.BUILD_FAILED=9]="BUILD_FAILED",Me[Me.RESOLVER_NOT_FOUND=10]="RESOLVER_NOT_FOUND",Me[Me.FETCHER_NOT_FOUND=11]="FETCHER_NOT_FOUND",Me[Me.LINKER_NOT_FOUND=12]="LINKER_NOT_FO Line truncated
`,"\r","(",")","!","|","&","^"],!0,!1),le=function($){return e.queryPattern.test($)},me=function($){return e.checkFn($)},pe=ke("whitespace"),Be=/^[ \t\n\r]/,Ce=Ne([" "," ",`
`,"\r"],!1,!1),g=0,we=0,ye=[{line:1,column:1}],Ae=0,se=[],X=0,De;if("startRule"in e){if(!(e.startRule in s))throw new Error(`Can't start parsing from rule "`+e.startRule+'".');a=s[e.startRule]}function Te(){return t.substring(we,g)}function mt(){return Ue(we,g)}function j($,oe){throw oe=oe!==void 0?oe:Ue(we,g),P([ke($)],t.substring(we,g),oe)}function rt($,oe){throw oe=oe!==void 0?oe:Ue(we,g),w($,oe)}function Fe($,oe){return{type:"literal",text:$,ignoreCase:oe}}function Ne($,oe,xe){return{type:"class",parts:$,inverted:oe,ignoreCase:xe}}function be(){return{type:"any"}}function Ve(){return{type:"end"}}function ke($){return{type:"other",description:$}}function it($){var oe=ye[$],xe;if(oe)return oe;for(xe=$-1;!ye[xe];)xe--;for(oe=ye[xe],oe={line:oe.line,column:oe.column};xe<$;)t.charCodeAt(xe)===10?(oe.line++,oe.column=1):oe.column++,xe++;return ye[$]=oe,oe}function Ue($,oe){var xe=it($),Re=it(oe);return{start:{offset:$,line:xe.line,column:xe.column},end:{offset:oe,line:Re.line,column:Re.column}}}function x($){g<Ae||(g>Ae&&(Ae=g,se=[]),se.push($))}function w($,oe){return new jd($,null,null,oe)}function P($,oe,xe){return new jd(jd.buildMessage($,oe),$,oe,xe)}function y(){var $,oe,xe,Re,lt,Ct,qt,ir;if($=g,oe=F(),oe!==r){for(xe=[],Re=g,lt=Z(),lt!==r?(t.charCodeAt(g)===124?(Ct=n,g++):(Ct=r,X===0&&x(c)),Ct===r&&(t.charCodeAt(g)===38?(Ct=f,g++):(Ct=r,X===0&&x(p)),Ct===r&&(t.charCodeAt(g)===94?(Ct=h,g++):(Ct=r,X===0&&x(E)))),Ct!==r?(qt=Z(),qt!==r?(ir=F(),ir!==r?(lt=[lt,Ct,qt,ir],Re=lt):(g=Re,Re=r)):(g=Re,Re=r)):(g=Re,Re=r)):(g=Re,Re=r);Re!==r;)xe.push(Re),Re=g,lt=Z(),lt!==r?(t.charCodeAt(g)===124?(Ct=n,g++):(Ct=r,X===0&&x(c)),Ct===r&&(t.charCodeAt(g)===38?(Ct=f,g++):(Ct=r,X===0&&x(p)),Ct===r&&(t.charCodeAt(g)===94?(Ct=h,g++):(Ct=r,X===0&&x(E)))),Ct!==r?(qt=Z(),qt!==r?(ir=F(),ir!==r?(lt=[lt,Ct,qt,ir],Re=lt):(g=Re,Re=r)):(g=Re,Re=r)):(g=Re,Re=r)):(g=Re,Re=r);xe!==r?(we=$,oe=C(oe,xe),$=oe):(g=$,$=r)}else g=$,$=r;return $}function F(){var $,oe,xe,Re,lt,Ct;return $=g,t.charCodeAt(g)===33?(oe=S,g++):(oe=r,X===0&&x(b)),oe!==r?(xe=F(),xe!==r?(we=$,oe=I(xe),$=oe):(g=$,$=r)):(g=$,$=r),$===r&&($=g,t.charCodeAt(g)===40?(oe=T,g++):(oe=r,X===0&&x(N)),oe!==r?(xe=Z(),xe!==r?(Re=y(),Re!==r?(lt=Z(),lt!==r?(t.charCodeAt(g)===41?(Ct=U,g++):(Ct=r,X===0&&x(W)),Ct!==r?(we=$,oe=ee(Re),$=oe):(g=$,$=r)):(g=$,$=r)):(g=$,$=r)):(g=$,$=r)):(g=$,$=r),$===r&&($=z())),$}function z(){var $,oe,xe,Re,lt;if($=g,oe=Z(),oe!==r){if(xe=g,Re=[],ie.test(t.charAt(g))?(lt=t.charAt(g),g++):(lt=r,X===0&&x(ue)),lt!==r)for(;lt!==r;)Re.push(lt),ie.test(t.charAt(g))?(lt=t.charAt(g),g++):(lt=r,X===0&&x(ue));else Re=r;Re!==r?xe=t.substring(xe,g):xe=Re,xe!==r?(we=g,Re=le(xe),Re?Re=void 0:Re=r,Re!==r?(we=$,oe=me(xe),$=oe):(g=$,$=r)):(g=$,$=r)}else g=$,$=r;return $}function Z(){var $,oe;for(X++,$=[],Be.test(t.charAt(g))?(oe=t.charAt(g),g++):(oe=r,X===0&&x(Ce));oe!==r;)$.push(oe),Be.test(t.charAt(g))?(oe=t.charAt(g),g++):(oe=r,X===0&&x(Ce));return X--,$===r&&(oe=r,X===0&&x(pe)),$}if(De=a(),De!==r&&g===t.length)return De;throw De!==r&&g<t.length&&x(Ve()),P(se,Ae<t.length?t.charAt(Ae):null,Ae<t.length?Ue(Ae,Ae+1):Ue(Ae,Ae))}hse.exports={SyntaxError:jd,parse:MJe}});var dse=_(rk=>{var{parse:UJe}=gse();rk.makeParser=(t=/[a-z]+/)=>(e,r)=>UJe(e,{queryPattern:t,checkFn:r});rk.parse=rk.makeParser()});var yse=_((LTt,mse)=>{"use strict";mse.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightLine truncated
`:`
`)+r,a=s+1,s=t.indexOf(`
`,a)}while(s!==-1);return n+=t.substr(a),n};Nse.exports={stringReplaceAll:XJe,stringEncaseCRLFWithFirstIndex:$Je}});var Hse=_((WTt,_se)=>{"use strict";var eKe=/(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi,Lse=/(?:^|\.)(\w+)(?:\(([^)]*)\))?/g,tKe=/^(['"])((?:\\.|(?!\1)[^\\])*)\1$/,rKe=/\\(u(?:[a-f\d]{4}|{[a-f\d]{1,6}})|x[a-f\d]{2}|.)|([^\\])/gi,nKe=new Map([["n",`
`],["r","\r"],["t"," "],["b","\b"],["f","\f"],["v","\v"],["0","\0"],["\\","\\"],["e","\x1B"],["a","\x07"]]);function Use(t){let e=t[0]==="u",r=t[1]==="{";return e&&!r&&t.length===5||t[0]==="x"&&t.length===3?String.fromCharCode(parseInt(t.slice(1),16)):e&&r?String.fromCodePoint(parseInt(t.slice(2,-1),16)):nKe.get(t)||t}function iKe(t,e){let r=[],s=e.trim().split(/\s*,\s*/g),a;for(let n of s){let c=Number(n);if(!Number.isNaN(c))r.push(c);else if(a=n.match(tKe))r.push(a[2].replace(rKe,(f,p,h)=>p?Use(p):h));else throw new Error(`Invalid Chalk template style argument: ${n} (in style '${t}')`)}return r}function sKe(t){Lse.lastIndex=0;let e=[],r;for(;(r=Lse.exec(t))!==null;){let s=r[1];if(r[2]){let a=iKe(s,r[2]);e.push([s].concat(a))}else e.push([s])}return e}function Mse(t,e){let r={};for(let a of e)for(let n of a.styles)r[n[0]]=a.inverse?null:n.slice(1);let s=t;for(let[a,n]of Object.entries(r))if(Array.isArray(n)){if(!(a in s))throw new Error(`Unknown Chalk style: ${a}`);s=n.length>0?s[a](...n):s[a]}return s}_se.exports=(t,e)=>{let r=[],s=[],a=[];if(e.replace(eKe,(n,c,f,p,h,E)=>{if(c)a.push(Use(c));else if(p){let C=a.join("");a=[],s.push(r.length===0?C:Mse(t,r)(C)),r.push({inverse:f,styles:sKe(p)})}else if(h){if(r.length===0)throw new Error("Found extraneous } in Chalk template literal");s.push(Mse(t,r)(a.join(""))),a=[],r.pop()}else a.push(E)}),s.push(a.join("")),r.length>0){let n=`Chalk template literal is missing ${r.length} closing bracket${r.length===1?"":"s"} (\`}\`)`;throw new Error(n)}return s.join("")}});var RE=_((YTt,Vse)=>{"use strict";var mB=sk(),{stdout:e4,stderr:t4}=Fse(),{stringReplaceAll:oKe,stringEncaseCRLFWithFirstIndex:aKe}=Ose(),{isArray:ok}=Array,Gse=["ansi","ansi","ansi256","ansi16m"],QE=Object.create(null),lKe=(t,e={})=>{if(e.level&&!(Number.isInteger(e.level)&&e.level>=0&&e.level<=3))throw new Error("The `level` option should be an integer from 0 to 3");let r=e4?e4.level:0;t.level=e.level===void 0?r:e.level},r4=class{constructor(e){return qse(e)}},qse=t=>{let e={};return lKe(e,t),e.template=(...r)=>Yse(e.template,...r),Object.setPrototypeOf(e,ak.prototype),Object.setPrototypeOf(e.template,e),e.template.constructor=()=>{throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.")},e.template.Instance=r4,e.template};function ak(t){return qse(t)}for(let[t,e]of Object.entries(mB))QE[t]={get(){let r=lk(this,n4(e.open,e.close,this._styler),this._isEmpty);return Object.defineProperty(this,t,{value:r}),r}};QE.visible={get(){let t=lk(this,this._styler,!0);return Object.defineProperty(this,"visible",{value:t}),t}};var Wse=["rgb","hex","keyword","hsl","hsv","hwb","ansi","ansi256"];for(let t of Wse)QE[t]={get(){let{level:e}=this;return function(...r){let s=n4(mB.color[Gse[e]][t](...r),mB.color.close,this._styler);return lk(this,s,this._isEmpty)}}};for(let t of Wse){let e="bg"+t[0].toUpperCase()+t.slice(1);QE[e]={get(){let{level:r}=this;return function(...s){let a=n4(mB.bgColor[Gse[r]][t](...s),mB.bgColor.close,this._styler);return lk(this,a,this._isEmpty)}}}}var cKe=Object.defineProperties(()=>{},{...QE,level:{enumerable:!0,get(){return this._generator.level},set(t){this._generator.level=t}}}),n4=(t,e,r)=>{let s,a;return r===void 0?(s=t,a=e):(s=r.openAll+t,a=e+r.closeAll),{open:t,close:e,openAll:s,closeAll:a,parent:r}},lk=(t,e,r)=>{let s=(...a)=>ok(a[0])&&ok(a[0].raw)?jse(s,Yse(s,...a)):jse(s,a.length===1?""+a[0]:a.join(" "));return Object.setPrototypeOf(s,cKe),s._generator=t,s._styler=e,s._isEmpty=r,s},jse=(t,e)=>{if(t.level<=0||!e)return t._isEmpty?"":e;let r=t._styler;if(r===void 0)return e;let{openAll:s,closeAll:a}=r;if(e.indexOf("\x1B")!==-1)for(;r!==void 0;)e=oKe(e,r.close,r.open),r=r.parent;let n=e.indexOf(`
`);return n!==-1&&(e=aKe(e,a,s,n)),s+e+a},$_,Yse=(t,...e)=>{let[r]=e;if(!ok(r)||!ok(r.raw))return e.join(" ");let s=e.slice(1),a=[r.raw[0]];for(let n=1;n<r.length;n++)a.push(String(s[n-1]).replace(/[{}\\]/g,"\\$&"),String(r.raw[n]));return $_===void 0&&($_=Hse()),$_(t,a.join(""))};Object.defineProperties(ak.prototype,QE);var ck=ak();ck.supportsColor=e4;ck.stderr=ak({level:t4?t4.level:0});ck.stderr.supportsColor=t4;Vse.exports=ck});var uk=_(Dc=>{"use strict";Dc.isInteger=t=>typeof t=="number"?Number.isInteger(t):typeof t=="string"&&t.trim()!==""?Number.isInteger(Number(t)):!1;Dc.find=(t,e)=>t.nodes.find(r=>r.type===e);Dc.exceedsLimit=(t,e,r=1,s)=>s===!1||!Dc.isInteger(t)||!Dc.isInteger(e)?!1:(Number(e)-Number(t))/Number(r)>=s;Dc.escapeNode=(t,e=0,r)=>{let s=t.nodes[e];s&&(r&&s.type===r||s.type==="open"||s.type==="close")&&s.escaped!==!0&&(s.value="\\"+s.value,s.escaped=!0)};Dc.encloseBrace=t=>t.type!=="brace"||t.commas>>0+t.ranges>>0?!1:(t.invalid=!0,!0);Dc.isInvalidBrace=t=>t.type!=="brace"?!1:t.invalid===!0||t.dollar?!0:!(t.commas>>0+t.ranges>>0)||t.open!==!0||t.close!==!0?(t.invalid=!0,!0):!1;Dc.isOpenOrClose=t=>t.type==="open"||t.type==="close"?!0:t.open===!0||t.close===!0;Dc.reduce=t=>t.reduce((e,r)=>(r.type==="text"&&e.push(r.value),r.type==="range"&&(r.type="text"),e),[]);Dc.flatten=(...t)=>{let e=[],r=s=>{for(let a=0;a<s.length;a++){let n=s[a];Array.isArray(n)?r(n,e):n!==void 0&&e.push(n)}return e};return r(t),e}});var fk=_((JTt,Kse)=>{"use strict";var Jse=uk();Kse.exports=(t,e={})=>{let r=(s,a={})=>{let n=e.escapeInvalid&&Jse.isInvalidBrace(a),c=s.invalid===!0&&e.escapeInvalid===!0,f="";if(s.value)return(n||c)&&Jse.isOpenOrClose(s)?"\\"+s.value:s.value;if(s.value)return s.value;if(s.nodes)for(let p of s.nodes)f+=r(p);return f};return r(t)}});var Zse=_((KTt,zse)=>{"use strict";zse.exports=function(t){return typeof t=="number"?t-t===0:typeof t=="string"&&t.trim()!==""?Number.isFinite?Number.isFinite(+t):isFinite(+t):!1}});var ooe=_((zTt,soe)=>{"use strict";var Xse=Zse(),Gd=(t,e,r)=>{if(Xse(t)===!1)throw new TypeError("toRegexRange: expected the first argument to be a number");if(e===void 0||t===e)return String(t);if(Xse(e)===!1)throw new TypeError("toRegexRange: expected the second argument to be a number.");let s={relaxZeros:!0,...r};typeof s.strictZeros=="boolean"&&(s.relaxZeros=s.strictZeros===!1);let a=String(s.relaxZeros),n=String(s.shorthand),c=String(s.capture),f=String(s.wrap),p=t+":"+e+"="+a+n+c+f;if(Gd.cache.hasOwnProperty(p))return Gd.cache[p].result;let h=Math.min(t,e),E=Math.max(t,e);if(Math.abs(h-E)===1){let T=t+"|"+e;return s.capture?`(${T})`:s.wrap===!1?T:`(?:${T})`}let C=ioe(t)||ioe(e),S={min:t,max:e,a:h,b:E},b=[],I=[];if(C&&(S.isPadded=C,S.maxLen=String(S.max).length),h<0){let T=E<0?Math.abs(E):1;I=$se(T,Math.abs(h),S,s),h=S.a=0}return E>=0&&(b=$se(h,E,S,s)),S.negatives=I,S.positives=b,S.result=uKe(I,b,s),s.capture===!0?S.result=`(${S.result})`:s.wrap!==!1&&b.length+I.length>1&&(S.result=`(?:${S.result})`),Gd.cache[p]=S,S.result};function uKe(t,e,r){let s=i4(t,e,"-",!1,r)||[],a=i4(e,t,"",!1,r)||[],n=i4(t,e,"-?",!0,r)||[];return s.concat(n).concat(a).join("|")}function fKe(t,e){let r=1,s=1,a=toe(t,r),n=new Set([e]);for(;t<=a&&a<=e;)n.add(a),r+=1,a=toe(t,r);for(a=roe(e+1,s)-1;t<a&&a<=e;)n.add(a),s+=1,a=roe(e+1,s)-1;return n=[...n],n.sort(hKe),n}function AKe(t,e,r){if(t===e)return{pattern:t,count:[],digits:0};let s=pKe(t,e),a=s.length,n="",c=0;for(let f=0;f<a;f++){let[p,h]=s[f];p===h?n+=p:p!=="0"||h!=="9"?n+=gKe(p,h,r):c++}return c&&(n+=r.shorthand===!0?"\\d":"[0-9]"),{pattern:n,count:[c],digits:a}}function $se(t,e,r,s){let a=fKe(t,e),n=[],c=t,f;for(let p=0;p<a.length;p++){let h=a[p],E=AKe(String(c),String(h),s),C="";if(!r.isPadded&&f&&f.pattern===E.pattern){f.count.length>1&&f.count.pop(),f.count.push(E.count[0]),f.string=f.pattern+noe(f.count),c=h+1;continue}r.isPadded&&(C=dKe(h,r,s)),E.string=C+E.pattern+noe(E.count),n.push(E),c=h+1,f=E}return n}function i4(t,e,r,s,a){let n=[];for(let c of t){let{string:f}=c;!s&&!eoe(e,"string",f)&&n.push(r+f),s&&eoe(e,"string",f)&&n.push(r+f)}return n}function pKe(t,e){let r=[];for(let s=0;s<t.length;s++)r.push([t[s],e[s]]);return r}function hKe(t,e){return t>e?1:e>t?-1:0}function eoe(t,e,r){return t.some(s=>s[e]===r)}function toe(t,e){return Number(String(t).slice(0,-e)+"9".repeat(e))}function roe(t,e){return t-t%Math.pow(10,e)}function noe(t){let[e=0,r=""]=t;return r||e>1?`{${e+(r?","+r:"")}}`:""}function gKe(t,e,r){return`[${t}${e-t===1?"":"-"}${e}]`}function ioe(t){return/^-?(0+)\d/.test(t)}function dKe(t,e,r){if(!e.isPadded)return t;let s=Math.abs(e.maxLen-String(t).length),a=r.relaxZeros!==!1;switch(s){case 0:return"";case 1:return a?"0?":"0";case 2:return a?"0{0,2}":"00";default:return a?`0{0,${s}}`:`0{${s}}`}}Gd.cache={};Gd.clearCache=()=>Gd.cache={};soe.exports=Gd});var a4=_((ZTt,hoe)=>{"use strict";var mKe=Ie("util"),coe=ooe(),aoe=t=>t!==null&&typeof t=="object"&&!Array.isArray(t),yKe=t=>e=>t===!0?Number(e):String(e),s4=t=>typeof t=="numb Line truncated
`,CHAR_NO_BREAK_SPACE:"\xA0",CHAR_PERCENT:"%",CHAR_PLUS:"+",CHAR_QUESTION_MARK:"?",CHAR_RIGHT_ANGLE_BRACKET:">",CHAR_RIGHT_CURLY_BRACE:"}",CHAR_RIGHT_SQUARE_BRACKET:"]",CHAR_SEMICOLON:";",CHAR_SINGLE_QUOTE:"'",CHAR_SPACE:" ",CHAR_TAB:" ",CHAR_UNDERSCORE:"_",CHAR_VERTICAL_LINE:"|",CHAR_ZERO_WIDTH_NOBREAK_SPACE:"\uFEFF"}});var Poe=_((tFt,Doe)=>{"use strict";var xKe=fk(),{MAX_LENGTH:Boe,CHAR_BACKSLASH:l4,CHAR_BACKTICK:kKe,CHAR_COMMA:QKe,CHAR_DOT:RKe,CHAR_LEFT_PARENTHESES:TKe,CHAR_RIGHT_PARENTHESES:FKe,CHAR_LEFT_CURLY_BRACE:NKe,CHAR_RIGHT_CURLY_BRACE:OKe,CHAR_LEFT_SQUARE_BRACKET:voe,CHAR_RIGHT_SQUARE_BRACKET:Soe,CHAR_DOUBLE_QUOTE:LKe,CHAR_SINGLE_QUOTE:MKe,CHAR_NO_BREAK_SPACE:UKe,CHAR_ZERO_WIDTH_NOBREAK_SPACE:_Ke}=woe(),HKe=(t,e={})=>{if(typeof t!="string")throw new TypeError("Expected a string");let r=e||{},s=typeof r.maxLength=="number"?Math.min(Boe,r.maxLength):Boe;if(t.length>s)throw new SyntaxError(`Input length (${t.length}), exceeds max characters (${s})`);let a={type:"root",input:t,nodes:[]},n=[a],c=a,f=a,p=0,h=t.length,E=0,C=0,S,b={},I=()=>t[E++],T=N=>{if(N.type==="text"&&f.type==="dot"&&(f.type="text"),f&&f.type==="text"&&N.type==="text"){f.value+=N.value;return}return c.nodes.push(N),N.parent=c,N.prev=f,f=N,N};for(T({type:"bos"});E<h;)if(c=n[n.length-1],S=I(),!(S===_Ke||S===UKe)){if(S===l4){T({type:"text",value:(e.keepEscaping?S:"")+I()});continue}if(S===Soe){T({type:"text",value:"\\"+S});continue}if(S===voe){p++;let N=!0,U;for(;E<h&&(U=I());){if(S+=U,U===voe){p++;continue}if(U===l4){S+=I();continue}if(U===Soe&&(p--,p===0))break}T({type:"text",value:S});continue}if(S===TKe){c=T({type:"paren",nodes:[]}),n.push(c),T({type:"text",value:S});continue}if(S===FKe){if(c.type!=="paren"){T({type:"text",value:S});continue}c=n.pop(),T({type:"text",value:S}),c=n[n.length-1];continue}if(S===LKe||S===MKe||S===kKe){let N=S,U;for(e.keepQuotes!==!0&&(S="");E<h&&(U=I());){if(U===l4){S+=U+I();continue}if(U===N){e.keepQuotes===!0&&(S+=U);break}S+=U}T({type:"text",value:S});continue}if(S===NKe){C++;let U={type:"brace",open:!0,close:!1,dollar:f.value&&f.value.slice(-1)==="$"||c.dollar===!0,depth:C,commas:0,ranges:0,nodes:[]};c=T(U),n.push(c),T({type:"open",value:S});continue}if(S===OKe){if(c.type!=="brace"){T({type:"text",value:S});continue}let N="close";c=n.pop(),c.close=!0,T({type:N,value:S}),C--,c=n[n.length-1];continue}if(S===QKe&&C>0){if(c.ranges>0){c.ranges=0;let N=c.nodes.shift();c.nodes=[N,{type:"text",value:xKe(c)}]}T({type:"comma",value:S}),c.commas++;continue}if(S===RKe&&C>0&&c.commas===0){let N=c.nodes;if(C===0||N.length===0){T({type:"text",value:S});continue}if(f.type==="dot"){if(c.range=[],f.value+=S,f.type="range",c.nodes.length!==3&&c.nodes.length!==5){c.invalid=!0,c.ranges=0,f.type="text";continue}c.ranges++,c.args=[];continue}if(f.type==="range"){N.pop();let U=N[N.length-1];U.value+=f.value+S,f=U,c.ranges--;continue}T({type:"dot",value:S});continue}T({type:"text",value:S})}do if(c=n.pop(),c.type!=="root"){c.nodes.forEach(W=>{W.nodes||(W.type==="open"&&(W.isOpen=!0),W.type==="close"&&(W.isClose=!0),W.nodes||(W.type="text"),W.invalid=!0)});let N=n[n.length-1],U=N.nodes.indexOf(c);N.nodes.splice(U,1,...c.nodes)}while(n.length>0);return T({type:"eos"}),a};Doe.exports=HKe});var koe=_((rFt,xoe)=>{"use strict";var boe=fk(),jKe=moe(),GKe=Ioe(),qKe=Poe(),jl=(t,e={})=>{let r=[];if(Array.isArray(t))for(let s of t){let a=jl.create(s,e);Array.isArray(a)?r.push(...a):r.push(a)}else r=[].concat(jl.create(t,e));return e&&e.expand===!0&&e.nodupes===!0&&(r=[...new Set(r)]),r};jl.parse=(t,e={})=>qKe(t,e);jl.stringify=(t,e={})=>boe(typeof t=="string"?jl.parse(t,e):t,e);jl.compile=(t,e={})=>(typeof t=="string"&&(t=jl.parse(t,e)),jKe(t,e));jl.expand=(t,e={})=>{typeof t=="string"&&(t=jl.parse(t,e));let r=GKe(t,e);return e.noempty===!0&&(r=r.filter(Boolean)),e.nodupes===!0&&(r=[...new Set(r)]),r};jl.create=(t,e={})=>t===""||t.length<3?[t]:e.expand!==!0?jl.compile(t,e):jl.expand(t,e);xoe.exports=jl});var EB=_((nFt,Noe)=>{"use strict";var WKe=Ie("path"),Vf="\\\\/",Qoe=`[^${Vf}]`,Dp="\\.",YKe="\\+",VKe="\\?",pk="\\/",JKe="(?=.)",Roe="[^/]",c4=`(?:${pk}|$)`,Toe=`(?:^|${pk})`,u4=`${Dp}{1,2}${c4}`,KKe=`(?!${Dp})`,zKe=`(?!${Toe}${u4})`,ZKe=`(?!${Dp}{0,1}${c4})`,XKe=`(?!${u4})`,$Ke=`[^.${pk}]`,eze=`${Roe}*?`,Foe={DOT_LITERAL:Dp,PLUS_LITERAL:YKe,QMARK_LITERAL:VKe,SLASH_LITERAL:pk,ONE_CHAR:JKe,QMARK:Roe,END_ANCHOR:c4,DOTS_SLASH:u4,NO_DOT:KKe,NO_DOTS:zKe,NO_DOT_SLASH:ZKe,NO_DOTS_SLASH:XKe,QMARK_NO_DOT:$Ke,STAR:eze,START_ANCHOR:Toe},tze={...Foe,SLASH_LITERAL:`[${Vf}]`,QMARK:Qoe,STAR:`${Qoe}*?`,DOTS_SLASH:`${Dp}{1,2}(?:[${Vf}]|$)`,NO_DOT:`(?!${Dp})`,NO_DOTS:`(?!(?:^|[${Vf}])${Dp}{1,2}(?:[${Vf}]|$))`,NO_DOT_SLASH:`(?!${Dp}{0,1}(?:[${Vf}]|$))`,NO_DOTS_SLASH:`(?!${Dp}{1,2}(?:[${Vf}]|$))`,QMARK_NO_DOT:`[^.${Vf}]`,START_ANCHOR:`(?:^|[${Vf}])`,END_ANCHOR:`(?:[${Vf}]|$)`},rze={alnum:"a-zA-Z0-9",alpha:"a-zA-Z",ascii:"\\x00-\\x7F",blank:" \\t",cntrl:"\\x00-\\x1F\\x7F",digit:"0-9",graph:"\\x21-\\x7E",lower:"a-z",print:"\\x20-\\x7E ",punct:"\\-!\"#$%&' Line truncated
`),f!==-1){let p=a+c.substring(0,f);c=c.substring(f+1),a="",e!==null?this.reportInfo(null,`${e} ${p}`):this.reportInfo(null,p)}while(f!==-1);a+=c}),r.on("end",()=>{let n=s.end();n!==""&&(e!==null?this.reportInfo(null,`${e} ${n}`):this.reportInfo(null,n))}),r}}});var aI,Q8=Ze(()=>{Rc();Wo();aI=class{constructor(e){this.fetchers=e}supports(e,r){return!!this.tryFetcher(e,r)}getLocalPath(e,r){return this.getFetcher(e,r).getLocalPath(e,r)}async fetch(e,r){return await this.getFetcher(e,r).fetch(e,r)}tryFetcher(e,r){let s=this.fetchers.find(a=>a.supports(e,r));return s||null}getFetcher(e,r){let s=this.fetchers.find(a=>a.supports(e,r));if(!s)throw new jt(11,`${Yr(r.project.configuration,e)} isn't supported by any available fetcher`);return s}}});var rm,R8=Ze(()=>{Wo();rm=class{constructor(e){this.resolvers=e.filter(r=>r)}supportsDescriptor(e,r){return!!this.tryResolverByDescriptor(e,r)}supportsLocator(e,r){return!!this.tryResolverByLocator(e,r)}shouldPersistResolution(e,r){return this.getResolverByLocator(e,r).shouldPersistResolution(e,r)}bindDescriptor(e,r,s){return this.getResolverByDescriptor(e,s).bindDescriptor(e,r,s)}getResolutionDependencies(e,r){return this.getResolverByDescriptor(e,r).getResolutionDependencies(e,r)}async getCandidates(e,r,s){return await this.getResolverByDescriptor(e,s).getCandidates(e,r,s)}async getSatisfying(e,r,s,a){return this.getResolverByDescriptor(e,a).getSatisfying(e,r,s,a)}async resolve(e,r){return await this.getResolverByLocator(e,r).resolve(e,r)}tryResolverByDescriptor(e,r){let s=this.resolvers.find(a=>a.supportsDescriptor(e,r));return s||null}getResolverByDescriptor(e,r){let s=this.resolvers.find(a=>a.supportsDescriptor(e,r));if(!s)throw new Error(`${ni(r.project.configuration,e)} isn't supported by any available resolver`);return s}tryResolverByLocator(e,r){let s=this.resolvers.find(a=>a.supportsLocator(e,r));return s||null}getResolverByLocator(e,r){let s=this.resolvers.find(a=>a.supportsLocator(e,r));if(!s)throw new Error(`${Yr(r.project.configuration,e)} isn't supported by any available resolver`);return s}}});var lI,T8=Ze(()=>{Dt();Wo();lI=class{supports(e){return!!e.reference.startsWith("virtual:")}getLocalPath(e,r){let s=e.reference.indexOf("#");if(s===-1)throw new Error("Invalid virtual package reference");let a=e.reference.slice(s+1),n=Ws(e,a);return r.fetcher.getLocalPath(n,r)}async fetch(e,r){let s=e.reference.indexOf("#");if(s===-1)throw new Error("Invalid virtual package reference");let a=e.reference.slice(s+1),n=Ws(e,a),c=await r.fetcher.fetch(n,r);return await this.ensureVirtualLink(e,c,r)}getLocatorFilename(e){return nI(e)}async ensureVirtualLink(e,r,s){let a=r.packageFs.getRealPath(),n=s.project.configuration.get("virtualFolder"),c=this.getLocatorFilename(e),f=uo.makeVirtualPath(n,c,a),p=new _f(f,{baseFs:r.packageFs,pathUtils:J});return{...r,packageFs:p}}}});var TQ,fue=Ze(()=>{TQ=class t{static{this.protocol="virtual:"}static isVirtualDescriptor(e){return!!e.range.startsWith(t.protocol)}static isVirtualLocator(e){return!!e.reference.startsWith(t.protocol)}supportsDescriptor(e,r){return t.isVirtualDescriptor(e)}supportsLocator(e,r){return t.isVirtualLocator(e)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,s){throw new Error('Assertion failed: calling "bindDescriptor" on a virtual descriptor is unsupported')}getResolutionDependencies(e,r){throw new Error('Assertion failed: calling "getResolutionDependencies" on a virtual descriptor is unsupported')}async getCandidates(e,r,s){throw new Error('Assertion failed: calling "getCandidates" on a virtual descriptor is unsupported')}async getSatisfying(e,r,s,a){throw new Error('Assertion failed: calling "getSatisfying" on a virtual descriptor is unsupported')}async resolve(e,r){throw new Error('Assertion failed: calling "resolve" on a virtual locator is unsupported')}}});var cI,F8=Ze(()=>{Dt();tm();cI=class{supports(e){return!!e.reference.startsWith(Ei.protocol)}getLocalPath(e,r){return this.getWorkspace(e,r).cwd}async fetch(e,r){let s=this.getWorkspace(e,r).cwd;return{packageFs:new Sn(s),prefixPath:vt.dot,localPath:s}}getWorkspace(e,r){return r.project.getWorkspaceByCwd(e.reference.slice(Ei.protocol.length))}}});function WB(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function Aue(t){return typeof t>"u"?3:WB(t)?0:Array.isArray(t)?1:2}function L8(t,e){return Object.hasOwn(t,e)}function uet(t){return WB(t)&&L8(t,"onConflict")&&typeof t.onConflict=="string"}function fet(t){if(typeof t>"u")return{onConflict:"default",value:t};if(!uet(t))return{onConflict:"default",value:t};if(L8(t,"value"))return t;let{onConflict:e,...r}=t;return{onConflict:e,value:r}}function pue(t,e){let r=WB(t)&&L8(t,e)?t[e]:void 0;return fet(r)}function uI(t,e){return[t,e,hue]}function M8(t){return Array.isArray(t)?t[2]===hue:!1}function N8(t,e){if(WB(t)){let r={};for(let s of Object.keys(t))r[s]=N8(t[s],e);return uI(e,r)}return Array.isArray(t)?uI(e,t.map(r=>N8(r,e))):uI(e,t)}function O8(t,e,r,s,a){let n,c=[],f=a,p=0;for(let E=a-Line truncated
Please report this to https://github.com/szmarczak/http2-wrapper/`);I(T)}return}s[0].resolve(b);return}}if(c in this.queue){if(f in this.queue[c]){this.queue[c][f].listeners.push(...s),this._tryToCreateNewSession(c,f);return}}else this.queue[c]={};let p=()=>{c in this.queue&&this.queue[c][f]===h&&(delete this.queue[c][f],Object.keys(this.queue[c]).length===0&&delete this.queue[c])},h=()=>{let E=`${f}:${c}`,C=!1;try{let S=xtt.connect(e,{createConnection:this.createConnection,settings:this.settings,session:this.tlsSessionCache.get(E),...r});S[ba]=0,S[gI]=!1;let b=()=>S[ba]<S.remoteSettings.maxConcurrentStreams,I=!0;S.socket.once("session",N=>{this.tlsSessionCache.set(E,N)}),S.once("error",N=>{for(let{reject:U}of s)U(N);this.tlsSessionCache.delete(E)}),S.setTimeout(this.timeout,()=>{S.destroy()}),S.once("close",()=>{if(C){I&&this._freeSessionsCount--,this._sessionsCount--;let N=this.sessions[c];N.splice(N.indexOf(S),1),N.length===0&&delete this.sessions[c]}else{let N=new Error("Session closed without receiving a SETTINGS frame");N.code="HTTP2WRAPPER_NOSETTINGS";for(let{reject:U}of s)U(N);p()}this._tryToCreateNewSession(c,f)});let T=()=>{if(!(!(c in this.queue)||!b())){for(let N of S[Tc])if(N in this.queue[c]){let{listeners:U}=this.queue[c][N];for(;U.length!==0&&b();)U.shift().resolve(S);let W=this.queue[c];if(W[N].listeners.length===0&&(delete W[N],Object.keys(W).length===0)){delete this.queue[c];break}if(!b())break}}};S.on("origin",()=>{S[Tc]=S.originSet,b()&&(T(),yH(this.sessions[c],S))}),S.once("remoteSettings",()=>{if(S.ref(),S.unref(),this._sessionsCount++,h.destroyed){let N=new Error("Agent has been destroyed");for(let U of s)U.reject(N);S.destroy();return}S[Tc]=S.originSet;{let N=this.sessions;if(c in N){let U=N[c];U.splice(Rtt(U,S,Ttt),0,S)}else N[c]=[S]}this._freeSessionsCount+=1,C=!0,this.emit("session",S),T(),p(),S[ba]===0&&this._freeSessionsCount>this.maxFreeSessions&&S.close(),s.length!==0&&(this.getSession(f,r,s),s.length=0),S.on("remoteSettings",()=>{T(),yH(this.sessions[c],S)})}),S[Cfe]=S.request,S.request=(N,U)=>{if(S[gI])throw new Error("The session is gracefully closing. No new streams are allowed.");let W=S[Cfe](N,U);return S.ref(),++S[ba],S[ba]===S.remoteSettings.maxConcurrentStreams&&this._freeSessionsCount--,W.once("close",()=>{if(I=b(),--S[ba],!S.destroyed&&!S.closed&&(Ftt(this.sessions[c],S),b()&&!S.closed)){I||(this._freeSessionsCount++,I=!0);let ee=S[ba]===0;ee&&S.unref(),ee&&(this._freeSessionsCount>this.maxFreeSessions||S[gI])?S.close():(yH(this.sessions[c],S),T())}}),W}}catch(S){for(let b of s)b.reject(S);p()}};h.listeners=s,h.completed=!1,h.destroyed=!1,this.queue[c][f]=h,this._tryToCreateNewSession(c,f)})}request(e,r,s,a){return new Promise((n,c)=>{this.getSession(e,r,[{reject:c,resolve:f=>{try{n(f.request(s,a))}catch(p){c(p)}}}])})}createConnection(e,r){return t.connect(e,r)}static connect(e,r){r.ALPNProtocols=["h2"];let s=e.port||443,a=e.hostname||e.host;return typeof r.servername>"u"&&(r.servername=a),btt.connect(s,a,r)}closeFreeSessions(){for(let e of Object.values(this.sessions))for(let r of e)r[ba]===0&&r.close()}destroy(e){for(let r of Object.values(this.sessions))for(let s of r)s.destroy(e);for(let r of Object.values(this.queue))for(let s of Object.values(r))s.destroyed=!0;this.queue={}}get freeSessions(){return wfe({agent:this,isFree:!0})}get busySessions(){return wfe({agent:this,isFree:!1})}};im.kCurrentStreamsCount=ba;im.kGracefullyClosing=gI;vfe.exports={Agent:im,globalAgent:new im}});var CH=_((LMt,Sfe)=>{"use strict";var{Readable:Ntt}=Ie("stream"),IH=class extends Ntt{constructor(e,r){super({highWaterMark:r,autoDestroy:!1}),this.statusCode=null,this.statusMessage="",this.httpVersion="2.0",this.httpVersionMajor=2,this.httpVersionMinor=0,this.headers={},this.trailers={},this.req=null,this.aborted=!1,this.complete=!1,this.upgrade=null,this.rawHeaders=[],this.rawTrailers=[],this.socket=e,this.connection=e,this._dumped=!1}_destroy(e){this.req._request.destroy(e)}setTimeout(e,r){return this.req.setTimeout(e,r),this}_dump(){this._dumped||(this._dumped=!0,this.removeAllListeners("data"),this.resume())}_read(){this.req&&this.req._request.resume()}};Sfe.exports=IH});var wH=_((MMt,Dfe)=>{"use strict";Dfe.exports=t=>{let e={protocol:t.protocol,hostname:typeof t.hostname=="string"&&t.hostname.startsWith("[")?t.hostname.slice(1,-1):t.hostname,host:t.host,hash:t.hash,search:t.search,pathname:t.pathname,href:t.href,path:`${t.pathname||""}${t.search||""}`};return typeof t.port=="string"&&t.port.length!==0&&(e.port=Number(t.port)),(t.username||t.password)&&(e.auth=`${t.username||""}:${t.password||""}`),e}});var bfe=_((UMt,Pfe)=>{"use strict";Pfe.exports=(t,e,r)=>{for(let s of r)t.on(s,(...a)=>e.emit(s,...a))}});var kfe=_((_Mt,xfe)=>{"use strict";xfe.exports=t=>{switch(t){case":method":case":scheme":case":authority":case":path":return!0;default:return!1}}});var Rfe=_((jMt,Qfe)=>{"use strict";var dI=(t,e,r)=>{Qfe.exports[e]=class extends t{constructor(...a){super(typeof r=="string"?r: Line truncated
`).reverse(),f=r.stack.slice(r.stack.indexOf(r.message)+r.message.length).split(`
`).reverse();for(;f.length!==0&&f[0]===c[0];)c.shift();this.stack=`${this.stack.slice(0,n)}${c.reverse().join(`
`)}${f.reverse().join(`
`)}`}}};Ln.RequestError=us;var eR=class extends us{constructor(e){super(`Redirected ${e.options.maxRedirects} times. Aborting.`,{},e),this.name="MaxRedirectsError"}};Ln.MaxRedirectsError=eR;var tR=class extends us{constructor(e){super(`Response code ${e.statusCode} (${e.statusMessage})`,{},e.request),this.name="HTTPError"}};Ln.HTTPError=tR;var rR=class extends us{constructor(e,r){super(e.message,e,r),this.name="CacheError"}};Ln.CacheError=rR;var nR=class extends us{constructor(e,r){super(e.message,e,r),this.name="UploadError"}};Ln.UploadError=nR;var iR=class extends us{constructor(e,r,s){super(e.message,e,s),this.name="TimeoutError",this.event=e.event,this.timings=r}};Ln.TimeoutError=iR;var tv=class extends us{constructor(e,r){super(e.message,e,r),this.name="ReadError"}};Ln.ReadError=tv;var sR=class extends us{constructor(e){super(`Unsupported protocol "${e.url.protocol}"`,{},e),this.name="UnsupportedProtocolError"}};Ln.UnsupportedProtocolError=sR;var jrt=["socket","connect","continue","information","upgrade","timeout"],oR=class extends hAe.Duplex{constructor(e,r={},s){super({autoDestroy:!1,highWaterMark:0}),this[yI]=0,this[II]=0,this.requestInitialized=!1,this[ZQ]=new Set,this.redirects=[],this[CI]=!1,this[XQ]=!1,this[ev]=[],this.retryCount=0,this._progressCallbacks=[];let a=()=>this._unlockWrite(),n=()=>this._lockWrite();this.on("pipe",h=>{h.prependListener("data",a),h.on("data",n),h.prependListener("end",a),h.on("end",n)}),this.on("unpipe",h=>{h.off("data",a),h.off("data",n),h.off("end",a),h.off("end",n)}),this.on("pipe",h=>{h instanceof YH.IncomingMessage&&(this.options.headers={...h.headers,...this.options.headers})});let{json:c,body:f,form:p}=r;if((c||f||p)&&this._lockWrite(),Ln.kIsNormalizedAlready in r)this.options=r;else try{this.options=this.constructor.normalizeArguments(e,r,s)}catch(h){at.default.nodeStream(r.body)&&r.body.destroy(),this.destroy(h);return}(async()=>{var h;try{this.options.body instanceof Crt.ReadStream&&await Urt(this.options.body);let{url:E}=this.options;if(!E)throw new TypeError("Missing `url` property");if(this.requestUrl=E.toString(),decodeURI(this.requestUrl),await this._finalizeBody(),await this._makeRequest(),this.destroyed){(h=this[po])===null||h===void 0||h.destroy();return}for(let C of this[ev])C();this[ev].length=0,this.requestInitialized=!0}catch(E){if(E instanceof us){this._beforeError(E);return}this.destroyed||this.destroy(E)}})()}static normalizeArguments(e,r,s){var a,n,c,f,p;let h=r;if(at.default.object(e)&&!at.default.urlInstance(e))r={...s,...e,...r};else{if(e&&r&&r.url!==void 0)throw new TypeError("The `url` option is mutually exclusive with the `input` argument");r={...s,...r},e!==void 0&&(r.url=e),at.default.urlInstance(r.url)&&(r.url=new w0.URL(r.url.toString()))}if(r.cache===!1&&(r.cache=void 0),r.dnsCache===!1&&(r.dnsCache=void 0),at.assert.any([at.default.string,at.default.undefined],r.method),at.assert.any([at.default.object,at.default.undefined],r.headers),at.assert.any([at.default.string,at.default.urlInstance,at.default.undefined],r.prefixUrl),at.assert.any([at.default.object,at.default.undefined],r.cookieJar),at.assert.any([at.default.object,at.default.string,at.default.undefined],r.searchParams),at.assert.any([at.default.object,at.default.string,at.default.undefined],r.cache),at.assert.any([at.default.object,at.default.number,at.default.undefined],r.timeout),at.assert.any([at.default.object,at.default.undefined],r.context),at.assert.any([at.default.object,at.default.undefined],r.hooks),at.assert.any([at.default.boolean,at.default.undefined],r.decompress),at.assert.any([at.default.boolean,at.default.undefined],r.ignoreInvalidCookies),at.assert.any([at.default.boolean,at.default.undefined],r.followRedirect),at.assert.any([at.default.number,at.default.undefined],r.maxRedirects),at.assert.any([at.default.boolean,at.default.undefined],r.throwHttpErrors),at.assert.any([at.default.boolean,at.default.undefined],r.http2),at.assert.any([at.default.boolean,at.default.undefined],r.allowGetBody),at.assert.any([at.default.string,at.default.undefined],r.localAddress),at.assert.any([IAe.isDnsLookupIpVersion,at.default.undefined],r.dnsLookupIpVersion),at.assert.any([at.default.object,at.default.undefined],r.https),at.assert.any([at.default.boolean,at.default.undefined],r.rejectUnauthorized),r.https&&(at.assert.any([at.default.boolean,at.default.undefined],r.https.rejectUnauthorized),at.assert.any([at.default.function_,at.default.undefined],r.https.checkServerIdentity),at.assert.any([at.default.string,at.default.object,at.default.array,at.default.undefined],r.https.certificateAuthority),at.assert.any([at.default.string,at.default.object,at.default.array,at.default.undefined],r.https.key),at.assert.any([at.default.string,at.default.object,at.default.array,at.default.undefined],r.https.certificate),at.assert.any([at.default.string,at.default.undefined],r.https.passphrase),at.assert.any([at.default.string,at.default.buffer,at.default.array,at.default.undefined],r.httpLine truncated
`)[3];return Pnt(e)}function cj(){return typeof pR.default.availableParallelism<"u"?pR.default.availableParallelism():Math.max(1,pR.default.cpus().length)}var pR,Int,XAe,Cnt,wnt,$Ae,epe,Snt,Dnt,hR=Ze(()=>{Dt();pR=ut(Ie("os"));gR();bc();Int=Number(process.versions.node.split(".")[0]),XAe=new Map([["darwin","open"],["linux","xdg-open"],["win32","explorer.exe"]]).get(process.platform),Cnt=typeof XAe<"u"?async t=>{try{return await uj(XAe,[t],{cwd:J.cwd()}),!0}catch{return!1}}:void 0,wnt="/usr/bin/ldd";Snt=/^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|\/|[a-z]:\\|\\\\).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,Dnt=/\((\S*)(?::(\d+))(?::(\d+))\)/});function gj(t,e,r,s,a){let n=YB(r);if(s.isArray||s.type==="ANY"&&Array.isArray(n))return Array.isArray(n)?n.map((c,f)=>fj(t,`${e}[${f}]`,c,s,a)):String(n).split(/,/).map(c=>fj(t,e,c,s,a));if(Array.isArray(n))throw new Error(`Non-array configuration settings "${e}" cannot be an array`);return fj(t,e,r,s,a)}function fj(t,e,r,s,a){let n=YB(r);switch(s.type){case"ANY":return FQ(n);case"SHAPE":return Rnt(t,e,r,s,a);case"MAP":return Tnt(t,e,r,s,a)}if(n===null&&!s.isNullable&&s.default!==null)throw new Error(`Non-nullable configuration settings "${e}" cannot be set to null`);if(s.values?.includes(n))return n;let f=(()=>{if(s.type==="BOOLEAN"&&typeof n!="string")return kB(n);if(typeof n!="string")throw new Error(`Expected configuration setting "${e}" to be a string, got ${typeof n}`);let p=Vk(n,{env:t.env});switch(s.type){case"ABSOLUTE_PATH":{let h=a,E=U8(r);return E&&E[0]!=="<"&&(h=J.dirname(E)),J.resolve(h,fe.toPortablePath(p))}case"LOCATOR_LOOSE":return Qp(p,!1);case"NUMBER":return parseInt(p);case"LOCATOR":return Qp(p);case"BOOLEAN":return kB(p);default:return p}})();if(s.values&&!s.values.includes(f))throw new Error(`Invalid value, expected one of ${s.values.join(", ")}`);return f}function Rnt(t,e,r,s,a){let n=YB(r);if(typeof n!="object"||Array.isArray(n))throw new nt(`Object configuration settings "${e}" must be an object`);let c=dj(t,s,{ignoreArrays:!0});if(n===null)return c;for(let[f,p]of Object.entries(n)){let h=`${e}.${f}`;if(!s.properties[f])throw new nt(`Unrecognized configuration settings found: ${e}.${f} - run "yarn config" to see the list of settings supported in Yarn`);c.set(f,gj(t,h,p,s.properties[f],a))}return c}function Tnt(t,e,r,s,a){let n=YB(r),c=new Map;if(typeof n!="object"||Array.isArray(n))throw new nt(`Map configuration settings "${e}" must be an object`);if(n===null)return c;for(let[f,p]of Object.entries(n)){let h=s.normalizeKeys?s.normalizeKeys(f):f,E=`${e}['${h}']`,C=s.valueDefinition;c.set(h,gj(t,E,p,C,a))}return c}function dj(t,e,{ignoreArrays:r=!1}={}){switch(e.type){case"SHAPE":{if(e.isArray&&!r)return[];let s=new Map;for(let[a,n]of Object.entries(e.properties))s.set(a,dj(t,n));return s}case"MAP":return e.isArray&&!r?[]:new Map;case"ABSOLUTE_PATH":return e.default===null?null:t.projectCwd===null?Array.isArray(e.default)?e.default.map(s=>J.normalize(s)):J.isAbsolute(e.default)?J.normalize(e.default):e.isNullable?null:void 0:Array.isArray(e.default)?e.default.map(s=>J.resolve(t.projectCwd,s)):J.resolve(t.projectCwd,e.default);default:return e.default}}function mR(t,e,r){if(e.type==="SECRET"&&typeof t=="string"&&r.hideSecrets)return Qnt;if(e.type==="ABSOLUTE_PATH"&&typeof t=="string"&&r.getNativePaths)return fe.fromPortablePath(t);if(e.isArray&&Array.isArray(t)){let s=[];for(let a of t)s.push(mR(a,e,r));return s}if(e.type==="MAP"&&t instanceof Map){if(t.size===0)return;let s=new Map;for(let[a,n]of t.entries()){let c=mR(n,e.valueDefinition,r);typeof c<"u"&&s.set(a,c)}return s}if(e.type==="SHAPE"&&t instanceof Map){if(t.size===0)return;let s=new Map;for(let[a,n]of t.entries()){let c=e.properties[a],f=mR(n,c,r);typeof f<"u"&&s.set(a,f)}return s}return t}function Fnt(){let t={};for(let[e,r]of Object.entries(process.env))e=e.toLowerCase(),e.startsWith(yR)&&(e=(0,rpe.default)(e.slice(yR.length)),t[e]=r);return t}function pj(){let t=`${yR}rc_filename`;for(let[e,r]of Object.entries(process.env))if(e.toLowerCase()===t&&typeof r=="string")return r;return hj}async function tpe(t){try{return await ce.readFilePromise(t)}catch{return Buffer.of()}}async function Nnt(t,e){return Buffer.compare(...await Promise.all([tpe(t),tpe(e)]))===0}async function Ont(t,e){let[r,s]=await Promise.all([ce.statPromise(t),ce.statPromise(e)]);return r.dev===s.dev&&r.ino===s.ino}async function Mnt({configuration:t,selfPath:e}){let r=t.get("yarnPath");return t.get("ignorePath")||r===null||r===e||await Lnt(r,e)?null:r}var rpe,Lp,npe,ipe,spe,Aj,xnt,ov,knt,Mp,yR,hj,Qnt,wI,ope,ER,dR,Lnt,ze,av=Ze(()=>{Dt();wc();rpe=ut(Cre()),Lp=ut(Fd());Yt();npe=ut(hne()),ipe=Ie("module"),spe=ut(Ld()),Aj=Ie("stream");$ce();oI();Q8();R8();T8();fue();F8();tm();due();OQ();xc();I0();AR();bc();hR();Tp();Wo();xnt=function(){if(!Lp.GITHUB_ACTIONS||!process.env.GITHUB_EVENT_PATH)return!1;let t=fe.toPortablePath(process.env.GITHUB_EVENT_PATH),e;try{e=ce.readJsonSync(t)}catch{retu Line truncated
`);return{stdout:n,stderr:c}}makeResolver(){let e=[];for(let r of this.plugins.values())for(let s of r.resolvers||[])e.push(new s);return new rm([new TQ,new Ei,...e])}makeFetcher(){let e=[];for(let r of this.plugins.values())for(let s of r.fetchers||[])e.push(new s);return new aI([new lI,new cI,...e])}getLinkers(){let e=[];for(let r of this.plugins.values())for(let s of r.linkers||[])e.push(new s);return e}getSupportedArchitectures(){let e=sv(),r=this.get("supportedArchitectures"),s=r.get("os");s!==null&&(s=s.map(c=>c==="current"?e.os:c));let a=r.get("cpu");a!==null&&(a=a.map(c=>c==="current"?e.cpu:c));let n=r.get("libc");return n!==null&&(n=Wl(n,c=>c==="current"?e.libc??Wl.skip:c)),{os:s,cpu:a,libc:n}}isInteractive({interactive:e,stdout:r}){return r.isTTY?e??this.get("preferInteractive"):!1}async getPackageExtensions(){if(this.packageExtensions!==null)return this.packageExtensions;this.packageExtensions=new Map;let e=this.packageExtensions,r=(s,a,{userProvided:n=!1}={})=>{if(!cl(s.range))throw new Error("Only semver ranges are allowed as keys for the packageExtensions setting");let c=new Ut;c.load(a,{yamlCompatibilityMode:!0});let f=xB(e,s.identHash),p=[];f.push([s.range,p]);let h={status:"inactive",userProvided:n,parentDescriptor:s};for(let E of c.dependencies.values())p.push({...h,type:"Dependency",descriptor:E});for(let E of c.peerDependencies.values())p.push({...h,type:"PeerDependency",descriptor:E});for(let[E,C]of c.peerDependenciesMeta)for(let[S,b]of Object.entries(C))p.push({...h,type:"PeerDependencyMeta",selector:E,key:S,value:b})};await this.triggerHook(s=>s.registerPackageExtensions,this,r);for(let[s,a]of this.get("packageExtensions"))r(C0(s,!0),Yk(a),{userProvided:!0});return e}normalizeLocator(e){return cl(e.reference)?Ws(e,`${this.get("defaultProtocol")}${e.reference}`):Mp.test(e.reference)?Ws(e,`${this.get("defaultProtocol")}${e.reference}`):e}normalizeDependency(e){return cl(e.range)?On(e,`${this.get("defaultProtocol")}${e.range}`):Mp.test(e.range)?On(e,`${this.get("defaultProtocol")}${e.range}`):e}normalizeDependencyMap(e){return new Map([...e].map(([r,s])=>[r,this.normalizeDependency(s)]))}normalizePackage(e,{packageExtensions:r}){let s=LB(e),a=r.get(e.identHash);if(typeof a<"u"){let c=e.version;if(c!==null){for(let[f,p]of a)if(Xf(c,f))for(let h of p)switch(h.status==="inactive"&&(h.status="redundant"),h.type){case"Dependency":typeof s.dependencies.get(h.descriptor.identHash)>"u"&&(h.status="active",s.dependencies.set(h.descriptor.identHash,this.normalizeDependency(h.descriptor)));break;case"PeerDependency":typeof s.peerDependencies.get(h.descriptor.identHash)>"u"&&(h.status="active",s.peerDependencies.set(h.descriptor.identHash,h.descriptor));break;case"PeerDependencyMeta":{let E=s.peerDependenciesMeta.get(h.selector);(typeof E>"u"||!Object.hasOwn(E,h.key)||E[h.key]!==h.value)&&(h.status="active",Yl(s.peerDependenciesMeta,h.selector,()=>({}))[h.key]=h.value)}break;default:H4(h)}}}let n=c=>c.scope?`${c.scope}__${c.name}`:`${c.name}`;for(let c of s.peerDependenciesMeta.keys()){let f=Sa(c);s.peerDependencies.has(f.identHash)||s.peerDependencies.set(f.identHash,On(f,"*"))}for(let c of s.peerDependencies.values()){if(c.scope==="types")continue;let f=n(c),p=Da("types",f),h=un(p);s.peerDependencies.has(p.identHash)||s.peerDependenciesMeta.has(h)||s.dependencies.has(p.identHash)||(s.peerDependencies.set(p.identHash,On(p,"*")),s.peerDependenciesMeta.set(h,{optional:!0}))}return s.dependencies=new Map(qs(s.dependencies,([,c])=>al(c))),s.peerDependencies=new Map(qs(s.peerDependencies,([,c])=>al(c))),s}getLimit(e){return Yl(this.limits,e,()=>(0,spe.default)(this.get(e)))}async triggerHook(e,...r){for(let s of this.plugins.values()){let a=s.hooks;if(!a)continue;let n=e(a);n&&await n(...r)}}async triggerMultipleHooks(e,r){for(let s of r)await this.triggerHook(e,...s)}async reduceHook(e,r,...s){let a=r;for(let n of this.plugins.values()){let c=n.hooks;if(!c)continue;let f=e(c);f&&(a=await f(a,...s))}return a}async firstHook(e,...r){for(let s of this.plugins.values()){let a=s.hooks;if(!a)continue;let n=e(a);if(!n)continue;let c=await n(...r);if(typeof c<"u")return c}return null}}});var qr={};Vt(qr,{EndStrategy:()=>Ij,ExecError:()=>IR,PipeError:()=>lv,execvp:()=>uj,pipevp:()=>Wu});function om(t){return t!==null&&typeof t.fd=="number"}function mj(){}function yj(){for(let t of am)t.kill()}async function Wu(t,e,{cwd:r,env:s=process.env,strict:a=!1,stdin:n=null,stdout:c,stderr:f,end:p=2}){let h=["pipe","pipe","pipe"];n===null?h[0]="ignore":om(n)&&(h[0]=n),om(c)&&(h[1]=c),om(f)&&(h[2]=f);let E=(0,Ej.default)(t,e,{cwd:fe.fromPortablePath(r),env:{...s,PWD:fe.fromPortablePath(r)},stdio:h});am.add(E),am.size===1&&(process.on("SIGINT",mj),process.on("SIGTERM",yj)),!om(n)&&n!==null&&n.pipe(E.stdin),om(c)||E.stdout.pipe(c,{end:!1}),om(f)||E.stderr.pipe(f,{end:!1});let C=()=>{for(let S of new Set([c,f]))om(S)||S.end()};return new Promise((S,b)=>{E.on("error",I=>{am.delete(E),am.size===0&&(process.off("SIGINT",mj),pro Line truncated
This command will run a command using Yarn's portable shell.
Make sure to escape glob patterns, redirections, and other features that might be expanded by your own shell.
Note: To escape something from Yarn's shell, you might have to escape it twice, the first time from your own shell.
Note: Don't use this command in Yarn scripts, as Yarn's shell is automatically used.
For a list of features, visit: https://github.com/yarnpkg/berry/blob/master/packages/yarnpkg-shell/README.md.
`,examples:[["Run a simple command","$0 echo Hello"],["Run a command with a glob pattern","$0 echo '*.js'"],["Run a command with a redirection","$0 echo Hello World '>' hello.txt"],["Run a command with an escaped glob pattern (The double escape is needed in Unix shells)",`$0 echo '"*.js"'`],["Run a command with a variable (Double quotes are needed in Unix shells, to prevent them from expanding the variable)",'$0 "GREETING=Hello echo $GREETING World"']]}}async execute(){let r=this.args.length>0?`${this.commandName} ${this.args.join(" ")}`:this.commandName;return await vI(r,[],{cwd:fe.toPortablePath(this.cwd),stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})}}});var Vl,Bpe=Ze(()=>{Vl=class extends Error{constructor(e){super(e),this.name="ShellError"}}});var PR={};Vt(PR,{fastGlobOptions:()=>Dpe,isBraceExpansion:()=>Fj,isGlobPattern:()=>Wnt,match:()=>Ynt,micromatchOptions:()=>DR});function Wnt(t){if(!SR.default.scan(t,DR).isGlob)return!1;try{SR.default.parse(t,DR)}catch{return!1}return!0}function Ynt(t,{cwd:e,baseFs:r}){return(0,vpe.default)(t,{...Dpe,cwd:fe.fromPortablePath(e),fs:ax(Spe.default,new t0(r))})}function Fj(t){return SR.default.scan(t,DR).isBrace}var vpe,Spe,SR,DR,Dpe,Ppe=Ze(()=>{Dt();vpe=ut(wQ()),Spe=ut(Ie("fs")),SR=ut(Go()),DR={strictBrackets:!0},Dpe={onlyDirectories:!1,onlyFiles:!1}});function Nj(){}function Oj(){for(let t of cm)t.kill()}function Qpe(t,e,r,s){return a=>{let n=a[0]instanceof tA.Transform?"pipe":a[0],c=a[1]instanceof tA.Transform?"pipe":a[1],f=a[2]instanceof tA.Transform?"pipe":a[2],p=(0,xpe.default)(t,e,{...s,stdio:[n,c,f]});return cm.add(p),cm.size===1&&(process.on("SIGINT",Nj),process.on("SIGTERM",Oj)),a[0]instanceof tA.Transform&&a[0].pipe(p.stdin),a[1]instanceof tA.Transform&&p.stdout.pipe(a[1],{end:!1}),a[2]instanceof tA.Transform&&p.stderr.pipe(a[2],{end:!1}),{stdin:p.stdin,promise:new Promise(h=>{p.on("error",E=>{switch(cm.delete(p),cm.size===0&&(process.off("SIGINT",Nj),process.off("SIGTERM",Oj)),E.code){case"ENOENT":a[2].write(`command not found: ${t}
`),h(127);break;case"EACCES":a[2].write(`permission denied: ${t}
`),h(128);break;default:a[2].write(`uncaught error: ${E.message}
`),h(1);break}}),p.on("close",E=>{cm.delete(p),cm.size===0&&(process.off("SIGINT",Nj),process.off("SIGTERM",Oj)),h(E!==null?E:129)})})}}}function Rpe(t){return e=>{let r=e[0]==="pipe"?new tA.PassThrough:e[0];return{stdin:r,promise:Promise.resolve().then(()=>t({stdin:r,stdout:e[1],stderr:e[2]}))}}}function bR(t,e){return Mj.start(t,e)}function bpe(t,e=null){let r=new tA.PassThrough,s=new kpe.StringDecoder,a="";return r.on("data",n=>{let c=s.write(n),f;do if(f=c.indexOf(`
`),f!==-1){let p=a+c.substring(0,f);c=c.substring(f+1),a="",t(e!==null?`${e} ${p}`:p)}while(f!==-1);a+=c}),r.on("end",()=>{let n=s.end();n!==""&&t(e!==null?`${e} ${n}`:n)}),r}function Tpe(t,{prefix:e}){return{stdout:bpe(r=>t.stdout.write(`${r}
`),t.stdout.isTTY?e:null),stderr:bpe(r=>t.stderr.write(`${r}
`),t.stderr.isTTY?e:null)}}var xpe,tA,kpe,cm,Oc,Lj,Mj,Uj=Ze(()=>{xpe=ut(UU()),tA=Ie("stream"),kpe=Ie("string_decoder"),cm=new Set;Oc=class{constructor(e){this.stream=e}close(){}get(){return this.stream}},Lj=class{constructor(){this.stream=null}close(){if(this.stream===null)throw new Error("Assertion failed: No stream attached");this.stream.end()}attach(e){this.stream=e}get(){if(this.stream===null)throw new Error("Assertion failed: No stream attached");return this.stream}},Mj=class t{constructor(e,r){this.stdin=null;this.stdout=null;this.stderr=null;this.pipe=null;this.ancestor=e,this.implementation=r}static start(e,{stdin:r,stdout:s,stderr:a}){let n=new t(null,e);return n.stdin=r,n.stdout=s,n.stderr=a,n}pipeTo(e,r=1){let s=new t(this,e),a=new Lj;return s.pipe=a,s.stdout=this.stdout,s.stderr=this.stderr,(r&1)===1?this.stdout=a:this.ancestor!==null&&(this.stderr=this.ancestor.stdout),(r&2)===2?this.stderr=a:this.ancestor!==null&&(this.stderr=this.ancestor.stderr),s}async exec(){let e=["ignore","ignore","ignore"];if(this.pipe)e[0]="pipe";else{if(this.stdin===null)throw new Error("Assertion failed: No input stream registered");e[0]=this.stdin.get()}let r;if(this.stdout===null)throw new Error("Assertion failed: No output stream registered");r=this.stdout,e[1]=r.get();let s;if(this.stderr===null)throw new Error("Assertion failed: No error stream registered");s=this.stderr,e[2]=s.get();let a=this.implementation(e);return this.pipe&&this.pipe.attach(a.stdin),await a.promise.then(n=>(r.close(),s.close(),n))}async run(){let e=[];for(let s=this;s;s=s.ancestor)e.push(s.exec());return(await Promise.all(e))[0]}}});var mv={};Vt(mv,{EntryCommand:()=>Av,ShellError:()=>Vl,execute:()=>vI,globUtils:()=>PR});function Fpe(t,e,r){let s=new Jl.PassThrough({autoDestroy:!0});switch(t){case 0:(e&1)===1&&r.stdin.pipe(s,{end:!1}),(e&2)===2&&r.stdin instanceof Jl.Writable&&s.pipe(r.stdin,{end:!1});break;case 1:(e&1)===1&&r.stdout.pipe(s,{end:!1}),(e&2)===2&&s.pipe(r.stdout,{end:!1});break;case 2:(e&1)===1&&r.stderr.pipe(s,{end:!1}),(e&2)===2&&s.pipe(r.stderr,{end:!1});break;default:throw new Vl(`Bad file descriptor: "${t}"`)}return s}function kR(t,e={}){let r={...t,...e};return r.environment={...t.environment,...e.environment},r.variables={...t.variables,...e.variables},r}async function Jnt(t,e,r){let s=[],a=new Jl.PassThrough;return a.on("data",n=>s.push(n)),await QR(t,e,kR(r,{stdout:a})),Buffer.concat(s).toString().replace(/[\r\n]+$/,"")}async function Npe(t,e,r){let s=t.map(async n=>{let c=await um(n.args,e,r);return{name:n.name,value:c.join(" ")}});return(await Promise.all(s)).reduce((n,c)=>(n[c.name]=c.value,n),{})}function xR(t){return t.match(/[^ \r\n\t]+/g)||[]}async function Hpe(t,e,r,s,a=s){switch(t.name){case"$":s(String(process.pid));break;case"#":s(String(e.args.length));break;case"@":if(t.quoted)for(let n of e.args)a(n);else for(let n of e.args){let c=xR(n);for(let f=0;f<c.length-1;++f)a(c[f]);s(c[c.length-1])}break;case"*":{let n=e.args.join(" ");if(t.quoted)s(n);else for(let c of xR(n))a(c)}break;case"PPID":s(String(process.ppid));break;case"RANDOM":s(String(Math.floor(Math.random()*32768)));break;default:{let n=parseInt(t.name,10),c,f=Number.isFinite(n);if(f?n>=0&&n<e.args.length&&(c=e.args[n]):Object.hasOwn(r.variables,t.name)?c=r.variables[t.name]:Object.hasOwn(r.environment,t.name)&&(c=r.environment[t.name]),typeof c<"u"&&t.alternativeValue?c=(await um(t.alternativeValue,e,r)).join(" "):typeof c>"u"&&(t.defaultValue?c=(await um(t.defaultValue,e,r)).join(" "):t.alternativeValue&&(c="")),typeof c>"u")throw f?new Vl(`Unbound argument #${n}`):new Vl(`Unbound variable "${t.name}"`);if(t.quoted)s(c);else{let p=xR(c);for(let E=0;E<p.length-1;++E)a(p[E]);let h=p[p.length-1];typeof h<"u"&&s(h)}}break}}async function hv(t,e,r){if(t.type==="number"){if(Number.isInteger(t.value))return t.value;throw new Error(`Invalid number: "${t.value}", only integers are allowed`)}else if(t.type==="variable"){let s=[];await Hpe({...t,quoted:!0},e,r,n=>s.push(n));let a=Number(s.join(" "));return Number.isNaN(a)?hv({type:"variable",name:s.join(" ")},e,r):hv({type:"number",value:a},e,r)}else return Knt[t.type](await hv(t.left,e,r),await hv(t.right,e,r))}async function um(t,e,r){let s=new Map,a=[],n=[],c=E=>{n.push(E)},f=()=>{n.length>0&&a.push(n.join("")),n=[]},p=E=>{c(E),f()},h=(E,C,S)=>{let b=JSON.stringify({type:E,fd:C}),I=s.get(b);typeof I>"u"&&s.set(b,I=[]),I.push(S)};for(let E of t){let C=!1;switch(E.type){case"redirection":{let S=await um(E.args,e,r);for(let b of S)h(E.subtype,E.fd,b)}break;case"argument":for(let S of E.segments)switch(S.type){case"text":c(S.text);break;case"glob":c(S.pattern),C=!0;break;case"shell":{let b=await Jnt(S.shell,e,r);if(S.quoted)c(b);else{let I=xR(b);for(let T=0;T<I.length-1;++T)p(I[T]);c(I[I.length-1])}}break;case"variable":await Hpe(S,e,r,c,p);break;case"arithmetic":c(String(await hv(S.arithmetic,e,r)));break}break}if(f(),C){let S=a.pop();if(typeof S>"u")throw new Error("Assertion failed: Expected a glob pa Line truncated
`)).finally(()=>{r.stdout.isTTY&&r.stdout.write(`Job ${p}, '${c(AE(t))}' has ended
`)})),0}return await Lpe(t,e,r)}async function $nt(t,e,r,{background:s=!1}={}){let a,n=f=>{a=f,r.variables["?"]=String(f)},c=async f=>{try{return await Xnt(f.chain,e,r,{background:s&&typeof f.then>"u"})}catch(p){if(!(p instanceof Vl))throw p;return r.stderr.write(`${p.message}
`),1}};for(n(await c(t));t.then;){if(r.exitCode!==null)return r.exitCode;switch(t.then.type){case"&&":a===0&&n(await c(t.then.line));break;case"||":a!==0&&n(await c(t.then.line));break;default:throw new Error(`Assertion failed: Unsupported command type: "${t.then.type}"`)}t=t.then.line}return a}async function QR(t,e,r){let s=r.backgroundJobs;r.backgroundJobs=[];let a=0;for(let{command:n,type:c}of t){if(a=await $nt(n,e,r,{background:c==="&"}),r.exitCode!==null)return r.exitCode;r.variables["?"]=String(a)}return await Promise.all(r.backgroundJobs),r.backgroundJobs=s,a}function jpe(t){switch(t.type){case"variable":return t.name==="@"||t.name==="#"||t.name==="*"||Number.isFinite(parseInt(t.name,10))||"defaultValue"in t&&!!t.defaultValue&&t.defaultValue.some(e=>dv(e))||"alternativeValue"in t&&!!t.alternativeValue&&t.alternativeValue.some(e=>dv(e));case"arithmetic":return _j(t.arithmetic);case"shell":return Hj(t.shell);default:return!1}}function dv(t){switch(t.type){case"redirection":return t.args.some(e=>dv(e));case"argument":return t.segments.some(e=>jpe(e));default:throw new Error(`Assertion failed: Unsupported argument type: "${t.type}"`)}}function _j(t){switch(t.type){case"variable":return jpe(t);case"number":return!1;default:return _j(t.left)||_j(t.right)}}function Hj(t){return t.some(({command:e})=>{for(;e;){let r=e.chain;for(;r;){let s;switch(r.type){case"subshell":s=Hj(r.subshell);break;case"command":s=r.envs.some(a=>a.args.some(n=>dv(n)))||r.args.some(a=>dv(a));break}if(s)return!0;if(!r.then)break;r=r.then.chain}if(!e.then)break;e=e.then.line}return!1})}async function vI(t,e=[],{baseFs:r=new Yn,builtins:s={},cwd:a=fe.toPortablePath(process.cwd()),env:n=process.env,stdin:c=process.stdin,stdout:f=process.stdout,stderr:p=process.stderr,variables:h={},glob:E=PR}={}){let C={};for(let[I,T]of Object.entries(n))typeof T<"u"&&(C[I]=T);let S=new Map(Vnt);for(let[I,T]of Object.entries(s))S.set(I,T);c===null&&(c=new Jl.PassThrough,c.end());let b=ux(t,E);if(!Hj(b)&&b.length>0&&e.length>0){let{command:I}=b[b.length-1];for(;I.then;)I=I.then.line;let T=I.chain;for(;T.then;)T=T.then.chain;T.type==="command"&&(T.args=T.args.concat(e.map(N=>({type:"argument",segments:[{type:"text",text:N}]}))))}return await QR(b,{args:e,baseFs:r,builtins:S,initialStdin:c,initialStdout:f,initialStderr:p,glob:E},{cwd:a,environment:C,exitCode:null,procedures:{},stdin:c,stdout:f,stderr:p,variables:Object.assign({},h,{"?":0}),nextBackgroundJobIndex:1,backgroundJobs:[]})}var Mpe,Upe,Jl,_pe,Vnt,Knt,pv=Ze(()=>{Dt();wc();Mpe=ut(RE()),Upe=Ie("os"),Jl=Ie("stream"),_pe=Ie("timers/promises");wpe();Bpe();Ppe();Uj();Uj();Vnt=new Map([["cd",async([t=(0,Upe.homedir)(),...e],r,s)=>{let a=J.resolve(s.cwd,fe.toPortablePath(t));if(!(await r.baseFs.statPromise(a).catch(c=>{throw c.code==="ENOENT"?new Vl(`cd: no such file or directory: ${t}`):c})).isDirectory())throw new Vl(`cd: not a directory: ${t}`);return s.cwd=a,0}],["pwd",async(t,e,r)=>(r.stdout.write(`${fe.fromPortablePath(r.cwd)}
`),0)],[":",async(t,e,r)=>0],["true",async(t,e,r)=>0],["false",async(t,e,r)=>1],["exit",async([t,...e],r,s)=>s.exitCode=parseInt(t??s.variables["?"],10)],["echo",async(t,e,r)=>(r.stdout.write(`${t.join(" ")}
`),0)],["sleep",async([t],e,r)=>{if(typeof t>"u")throw new Vl("sleep: missing operand");let s=Number(t);if(Number.isNaN(s))throw new Vl(`sleep: invalid time interval '${t}'`);return await(0,_pe.setTimeout)(1e3*s,0)}],["unset",async(t,e,r)=>{for(let s of t)delete r.environment[s],delete r.variables[s];return 0}],["__ysh_run_procedure",async(t,e,r)=>{let s=r.procedures[t[0]];return await bR(s,{stdin:new Oc(r.stdin),stdout:new Oc(r.stdout),stderr:new Oc(r.stderr)}).run()}],["__ysh_set_redirects",async(t,e,r)=>{let s=r.stdin,a=r.stdout,n=r.stderr,c=[],f=[],p=[],h=0;for(;t[h]!=="--";){let C=t[h++],{type:S,fd:b}=JSON.parse(C),I=W=>{switch(b){case null:case 0:c.push(W);break;default:throw new Error(`Unsupported file descriptor: "${b}"`)}},T=W=>{switch(b){case null:case 1:f.push(W);break;case 2:p.push(W);break;default:throw new Error(`Unsupported file descriptor: "${b}"`)}},N=Number(t[h++]),U=h+N;for(let W=h;W<U;++h,++W)switch(S){case"<":I(()=>e.baseFs.createReadStream(J.resolve(r.cwd,fe.toPortablePath(t[W]))));break;case"<<<":I(()=>{let ee=new Jl.PassThrough;return process.nextTick(()=>{ee.write(`${t[W]}
`),ee.end()}),ee});break;case"<&":I(()=>Fpe(Number(t[W]),1,r));break;case">":case">>":{let ee=J.resolve(r.cwd,fe.toPortablePath(t[W]));T(ee==="/dev/null"?new Jl.Writable({autoDestroy:!0,emitClose:!0,write(ie,ue,le){setImmediate(le)}}):e.baseFs.createWriteStream(ee,S===">>"?{flags:"a"}:void 0))}break;case">&":T(Fpe(Number(t[W]),2,r));break;default:throw new Error(`Assertion failed: Unsupported redirection type: "${S}"`)}}if(c.length>0){let C=new Jl.PassThrough;s=C;let S=b=>{if(b===c.length)C.end();else{let I=c[b]();I.pipe(C,{end:!1}),I.on("end",()=>{S(b+1)})}};S(0)}if(f.length>0){let C=new Jl.PassThrough;a=C;for(let S of f)C.pipe(S)}if(p.length>0){let C=new Jl.PassThrough;n=C;for(let S of p)C.pipe(S)}let E=await bR(gv(t.slice(h+1),e,r),{stdin:new Oc(s),stdout:new Oc(a),stderr:new Oc(n)}).run();return await Promise.all(f.map(C=>new Promise((S,b)=>{C.on("error",I=>{b(I)}),C.on("close",()=>{S()}),C.end()}))),await Promise.all(p.map(C=>new Promise((S,b)=>{C.on("error",I=>{b(I)}),C.on("close",()=>{S()}),C.end()}))),E}]]);Knt={addition:(t,e)=>t+e,subtraction:(t,e)=>t-e,multiplication:(t,e)=>t*e,division:(t,e)=>Math.trunc(t/e)}});var Gpe=_((d4t,RR)=>{function eit(){var t=0,e=1,r=2,s=3,a=4,n=5,c=6,f=7,p=8,h=9,E=10,C=11,S=12,b=13,I=14,T=15,N=16,U=17,W=0,ee=1,ie=2,ue=3,le=4;function me(g,we){return 55296<=g.charCodeAt(we)&&g.charCodeAt(we)<=56319&&56320<=g.charCodeAt(we+1)&&g.charCodeAt(we+1)<=57343}function pe(g,we){we===void 0&&(we=0);var ye=g.charCodeAt(we);if(55296<=ye&&ye<=56319&&we<g.length-1){var Ae=ye,se=g.charCodeAt(we+1);return 56320<=se&&se<=57343?(Ae-55296)*1024+(se-56320)+65536:Ae}if(56320<=ye&&ye<=57343&&we>=1){var Ae=g.charCodeAt(we-1),se=ye;return 55296<=Ae&&Ae<=56319?(Ae-55296)*1024+(se-56320)+65536:se}return ye}function Be(g,we,ye){var Ae=[g].concat(we).concat([ye]),se=Ae[Ae.length-2],X=ye,De=Ae.lastIndexOf(I);if(De>1&&Ae.slice(1,De).every(function(j){return j==s})&&[s,b,U].indexOf(g)==-1)return ie;var Te=Ae.lastIndexOf(a);if(Te>0&&Ae.slice(1,Te).every(function(j){return j==a})&&[S,a].indexOf(se)==-1)return Ae.filter(function(j){return j==a}).length%2==1?ue:le;if(se==t&&X==e)return W;if(se==r||se==t||se==e)return X==I&&we.every(function(j){return j==s})?ie:ee;if(X==r||X==t||X==e)return ee;if(se==c&&(X==c||X==f||X==h||X==E))return W;if((se==h||se==f)&&(X==f||X==p))return W;if((se==E||se==p)&&X==p)return W;if(X==s||X==T)return W;if(X==n)return W;if(se==S)return W;var mt=Ae.indexOf(s)!=-1?Ae.lastIndexOf(s)-1:Ae.length-2;return[b,U].indexOf(Ae[mt])!=-1&&Ae.slice(mt+1,-1).every(function(j){return j==s})&&X==I||se==T&&[N,U].indexOf(X)!=-1?W:we.indexOf(a)!=-1?ie:se==a&&X==a?W:ee}this.nextBreak=function(g,we){if(we===void 0&&(we=0),we<0)return 0;if(we>=g.length-1)return g.length;for(var ye=Ce(pe(g,we)),Ae=[],se=we+1;se<g.length;se++)if(!me(g,se-1)){var X=Ce(pe(g,se));if(Be(ye,Ae,X))return se;Ae.push(X)}return g.length},this.splitGraphemes=function(g){for(var we=[],ye=0,Ae;(Ae=this.nextBreak(g,ye))<g.length;)we.push(g.slice(ye,Ae)),ye=Ae;return ye<g.length&&we.push(g.slice(ye)),we},this.iterateGraphemes=function(g){var we=0,ye={next:function(){var Ae,se;return(se=this.nextBreak(g,we))<g.length?(Ae=g.slice(we,se),we=se,{value:Ae,done:!1}):we<g.length?(Ae=g.slice(we),we=g.length,{value:Ae,done:!1}):{value:void 0,done:!0}}.bind(this)};return typeof Symbol<"u"&&Symbol.iterator&&(ye[Symbol.iterator]=function(){return ye}),ye},this.countGraphemes=function(g){for(var we=0,ye=0,Ae;(Ae=this.nextBreak(g,ye))<g.length;)ye=Ae,we++;return ye<g.length&&we++,we};function Ce(g){return 1536<=g&&g<=1541||g==1757||g==1807||g==2274||g==3406||g==69821||70082<=g&&g<=70083||g==72250||72326<=g&&g<=72329||g==73030?S:g==13?t:g==10?e:0<=g&&g<=9||11<=g&&g<=12||14<=g&&g<=31||127<=g&&g<=159||g==173||g==1564||g==6158||g==8203||8206<=g&&g<=8207||g==8232||g==8233||8234<=g&&g<=8238||8288<=g&&g<=8292||g==8293||8294<=g&&g<=8303||55296<=g&&g<=57343||g==65279||65520<=g&&g<=65528||65529<=g&&g<=65531||113824<=g&&g<=113827||119155<=g&&g<=119162||g==917504||g==917505||917506<=g&&g<=917535||917632<=g&&g<=917759||918e3<=g&&g<=921599?r:768<=g&&g<=879||1155<=g&&g<=1159||1160<=g&&g<=1161||1425<=g&&g<=1469||g==1471||1473<=g&&g<=1474||1476<=g&&g<=1477||g==1479||1552<=g&&g<=1562||1611<=g&&g<=1631||g==1648||1750<=g&&g<=1756||1759<=g&&g<=1764||1767<=g&&g<=1768||1770<=g&&g<=1773||g==1809||1840<=g&&g<=1866||1958<=g&&g<=1968||2027<=g&&g<=2035||2070<=g&&g<=2073||2075<=g&&g<=2083||2085<=g&&g<=2087||2089<=g&&g<=2093||2137<=g&&g<=2139||2260<=g&&g<=2273||2275<=g&&g<=2306||g==2362||g==2364||2369<=g&&g<=2376||g==2381||2385<=g&&g<=2391||2402<=g&&g<=2403||g==2433||g==2492||g==2494||2497<=g&&g<=2500||g==2509||g==2519||2530<=g&&g<=2531||2561<=g&&g<=2562||g==2620||2625<=g&&g<=2626||2631<=g&&g<=2632||2635<=g&&g<=2637||g==2641||2672<=g&&g<=2673||g==2677||2689<=g&&g<=2690||g==2748||2753<=g&&g<=2757||2759<=g&&g<=2760||g==2765||2786<=g&&g<=2787||2810<=g&&g<=2815||g==2817||g==2876||g==2878||g==2879||2881<=g&&g<=2884||g==2893||g==2902||g==2903||2914<=g&&g<=2915||g==2946||g==3006|| Line truncated
`,end:t=>`::endgroup::
`}:FR.default.TRAVIS?{start:t=>`travis_fold:start:${t}
`,end:t=>`travis_fold:end:${t}
`}:FR.default.GITLAB?{start:t=>`section_start:${Math.floor(Date.now()/1e3)}:${t.toLowerCase().replace(/\W+/g,"_")}[collapsed=true]\r\x1B[0K${t}
`,end:t=>`section_end:${Math.floor(Date.now()/1e3)}:${t.toLowerCase().replace(/\W+/g,"_")}\r\x1B[0K`}:null,zpe=D0!==null,Jpe=new Date,iit=["iTerm.app","Apple_Terminal","WarpTerminal","vscode"].includes(process.env.TERM_PROGRAM)||!!process.env.WT_SESSION,sit=t=>t,NR=sit({patrick:{date:[17,3],chars:["\u{1F340}","\u{1F331}"],size:40},simba:{date:[19,7],chars:["\u{1F981}","\u{1F334}"],size:40},jack:{date:[31,10],chars:["\u{1F383}","\u{1F987}"],size:40},hogsfather:{date:[31,12],chars:["\u{1F389}","\u{1F384}"],size:40},default:{chars:["=","-"],size:80}}),oit=iit&&Object.keys(NR).find(t=>{let e=NR[t];return!(e.date&&(e.date[0]!==Jpe.getDate()||e.date[1]!==Jpe.getMonth()+1))})||"default";Ot=class extends Ao{constructor({configuration:r,stdout:s,json:a=!1,forceSectionAlignment:n=!1,includeNames:c=!0,includePrefix:f=!0,includeFooter:p=!0,includeLogs:h=!a,includeInfos:E=h,includeWarnings:C=h}){super();this.uncommitted=new Set;this.warningCount=0;this.errorCount=0;this.timerFooter=[];this.startTime=Date.now();this.indent=0;this.level=0;this.progress=new Map;this.progressTime=0;this.progressFrame=0;this.progressTimeout=null;this.progressStyle=null;this.progressMaxScaledSize=null;if(TB(this,{configuration:r}),this.configuration=r,this.forceSectionAlignment=n,this.includeNames=c,this.includePrefix=f,this.includeFooter=p,this.includeInfos=E,this.includeWarnings=C,this.json=a,this.stdout=s,r.get("enableProgressBars")&&!a&&s.isTTY&&s.columns>22){let S=r.get("progressBarStyle")||oit;if(!Object.hasOwn(NR,S))throw new Error("Assertion failed: Invalid progress bar style");this.progressStyle=NR[S];let b=Math.min(this.getRecommendedLength(),80);this.progressMaxScaledSize=Math.floor(this.progressStyle.size*b/80)}}static async start(r,s){let a=new this(r),n=process.emitWarning;process.emitWarning=(c,f)=>{if(typeof c!="string"){let h=c;c=h.message,f=f??h.name}let p=typeof f<"u"?`${f}: ${c}`:c;a.reportWarning(0,p)},r.includeVersion&&a.reportInfo(0,zd(r.configuration,`Yarn ${fn}`,2));try{await s(a)}catch(c){a.reportExceptionOnce(c)}finally{await a.finalize(),process.emitWarning=n}return a}hasErrors(){return this.errorCount>0}exitCode(){return this.hasErrors()?1:0}getRecommendedLength(){let s=this.progressStyle!==null?this.stdout.columns-1:super.getRecommendedLength();return Math.max(40,s-12-this.indent*2)}startSectionSync({reportHeader:r,reportFooter:s,skipIfEmpty:a},n){let c={committed:!1,action:()=>{r?.()}};a?this.uncommitted.add(c):(c.action(),c.committed=!0);let f=Date.now();try{return n()}catch(p){throw this.reportExceptionOnce(p),p}finally{let p=Date.now();this.uncommitted.delete(c),c.committed&&s?.(p-f)}}async startSectionPromise({reportHeader:r,reportFooter:s,skipIfEmpty:a},n){let c={committed:!1,action:()=>{r?.()}};a?this.uncommitted.add(c):(c.action(),c.committed=!0);let f=Date.now();try{return await n()}catch(p){throw this.reportExceptionOnce(p),p}finally{let p=Date.now();this.uncommitted.delete(c),c.committed&&s?.(p-f)}}startTimerImpl(r,s,a){return{cb:typeof s=="function"?s:a,reportHeader:()=>{this.level+=1,this.reportInfo(null,`\u250C ${r}`),this.indent+=1,D0!==null&&!this.json&&this.includeInfos&&this.stdout.write(D0.start(r))},reportFooter:f=>{if(this.indent-=1,D0!==null&&!this.json&&this.includeInfos){this.stdout.write(D0.end(r));for(let p of this.timerFooter)p()}this.configuration.get("enableTimers")&&f>200?this.reportInfo(null,`\u2514 Completed in ${Ht(this.configuration,f,ht.DURATION)}`):this.reportInfo(null,"\u2514 Completed"),this.level-=1},skipIfEmpty:(typeof s=="function"?{}:s).skipIfEmpty}}startTimerSync(r,s,a){let{cb:n,...c}=this.startTimerImpl(r,s,a);return this.startSectionSync(c,n)}async startTimerPromise(r,s,a){let{cb:n,...c}=this.startTimerImpl(r,s,a);return this.startSectionPromise(c,n)}reportSeparator(){this.indent===0?this.writeLine(""):this.reportInfo(null,"")}reportInfo(r,s){if(!this.includeInfos)return;this.commit();let a=this.formatNameWithHyperlink(r),n=a?`${a}: `:"",c=`${this.formatPrefix(n,"blueBright")}${s}`;this.json?this.reportJson({type:"info",name:r,displayName:this.formatName(r),indent:this.formatIndent(),data:s}):this.writeLine(c)}reportWarning(r,s){if(this.warningCount+=1,!this.includeWarnings)return;this.commit();let a=this.formatNameWithHyperlink(r),n=a?`${a}: `:"";this.json?this.reportJson({type:"warning",name:r,displayName:this.formatName(r),indent:this.formatIndent(),data:s}):this.writeLine(`${this.formatPrefix(n,"yellowBright")}${s}`)}reportError(r,s){this.errorCount+=1,this.timerFooter.push(()=>this.reportErrorImpl(r,s)),this.reportErrorImpl(r,s)}reportErrorImpl(r,s){this.commit();let a=this.formatNameWithHyperlink(r),n=a?`${a}: `:"";this.json?this.reportJson({type:"error",name:r,displayName:this.formatName(r),indent:this.formatIndent(),data:s}):this.writeLine(`${this.formatPrefix(n,"redBright")}${s}`,{truncate:!1})}reportFold(r,s){if(!D0)return;let a=`${D0.start(r)}${s}${D0.end(r)}`;this.timerFooter.push(()=>this.stdout.write(a))}reportProgress(r){if(this.progressStyle===null)ret Line truncated
`),this.writeProgress()}writeLines(r,{truncate:s}={}){this.clearProgress({delta:r.length});for(let a of r)this.stdout.write(`${this.truncate(a,{truncate:s})}
`);this.writeProgress()}commit(){let r=this.uncommitted;this.uncommitted=new Set;for(let s of r)s.committed=!0,s.action()}clearProgress({delta:r=0,clear:s=!1}){this.progressStyle!==null&&this.progress.size+r>0&&(this.stdout.write(`\x1B[${this.progress.size+r}A`),(r>0||s)&&this.stdout.write("\x1B[0J"))}writeProgress(){if(this.progressStyle===null||(this.progressTimeout!==null&&clearTimeout(this.progressTimeout),this.progressTimeout=null,this.progress.size===0))return;let r=Date.now();r-this.progressTime>Vpe&&(this.progressFrame=(this.progressFrame+1)%Ype.length,this.progressTime=r);let s=Ype[this.progressFrame];for(let a of this.progress.values()){let n="";if(typeof a.lastScaledSize<"u"){let h=this.progressStyle.chars[0].repeat(a.lastScaledSize),E=this.progressStyle.chars[1].repeat(this.progressMaxScaledSize-a.lastScaledSize);n=` ${h}${E}`}let c=this.formatName(null),f=c?`${c}: `:"",p=a.definition.title?` ${a.definition.title}`:"";this.stdout.write(`${Ht(this.configuration,"\u27A4","blueBright")} ${f}${s}${n}${p}
`)}this.progressTimeout=setTimeout(()=>{this.refreshProgress({force:!0})},Vpe)}refreshProgress({delta:r=0,force:s=!1}={}){let a=!1,n=!1;if(s||this.progress.size===0)a=!0;else for(let c of this.progress.values()){let f=typeof c.definition.progress<"u"?Math.trunc(this.progressMaxScaledSize*c.definition.progress):void 0,p=c.lastScaledSize;c.lastScaledSize=f;let h=c.lastTitle;if(c.lastTitle=c.definition.title,f!==p||(n=h!==c.definition.title)){a=!0;break}}a&&(this.clearProgress({delta:r,clear:n}),this.writeProgress())}truncate(r,{truncate:s}={}){return this.progressStyle===null&&(s=!1),typeof s>"u"&&(s=this.configuration.get("preferTruncatedLines")),s&&(r=(0,Kpe.default)(r,0,this.stdout.columns-1)),r}formatName(r){return this.includeNames?Zpe(r,{configuration:this.configuration,json:this.json}):""}formatPrefix(r,s){return this.includePrefix?`${Ht(this.configuration,"\u27A4",s)} ${r}${this.formatIndent()}`:""}formatNameWithHyperlink(r){return this.includeNames?jj(r,{configuration:this.configuration,json:this.json}):""}formatIndent(){return this.level>0||!this.forceSectionAlignment?"\u2502 ".repeat(this.indent):`${nit} `}}});var In={};Vt(In,{PackageManager:()=>$pe,detectPackageManager:()=>ehe,executePackageAccessibleBinary:()=>she,executePackageScript:()=>OR,executePackageShellcode:()=>Gj,executeWorkspaceAccessibleBinary:()=>pit,executeWorkspaceLifecycleScript:()=>nhe,executeWorkspaceScript:()=>rhe,getPackageAccessibleBinaries:()=>LR,getWorkspaceAccessibleBinaries:()=>ihe,hasPackageScript:()=>uit,hasWorkspaceScript:()=>qj,isNodeScript:()=>Wj,makeScriptEnv:()=>Iv,maybeExecuteWorkspaceLifecycleScript:()=>Ait,prepareExternalProject:()=>cit});async function P0(t,e,r,s=[]){if(process.platform==="win32"){let a=`@goto #_undefined_# 2>NUL || @title %COMSPEC% & @setlocal & @"${r}" ${s.map(n=>`"${n.replace('"','""')}"`).join(" ")} %*`;await ce.writeFilePromise(J.format({dir:t,name:e,ext:".cmd"}),a)}await ce.writeFilePromise(J.join(t,e),`#!/bin/sh
exec "${r}" ${s.map(a=>`'${a.replace(/'/g,`'"'"'`)}'`).join(" ")} "$@"
`,{mode:493})}async function ehe(t){let e=await Ut.tryFind(t);if(e?.packageManager){let s=bQ(e.packageManager);if(s?.name){let a=`found ${JSON.stringify({packageManager:e.packageManager})} in manifest`,[n]=s.reference.split(".");switch(s.name){case"yarn":return{packageManagerField:!0,packageManager:Number(n)===1?"Yarn Classic":"Yarn",reason:a};case"npm":return{packageManagerField:!0,packageManager:"npm",reason:a};case"pnpm":return{packageManagerField:!0,packageManager:"pnpm",reason:a}}}}let r;try{r=await ce.readFilePromise(J.join(t,Er.lockfile),"utf8")}catch{}return r!==void 0?r.match(/^__metadata:$/m)?{packageManager:"Yarn",reason:'"__metadata" key found in yarn.lock'}:{packageManager:"Yarn Classic",reason:'"__metadata" key not found in yarn.lock, must be a Yarn classic lockfile'}:ce.existsSync(J.join(t,"package-lock.json"))?{packageManager:"npm",reason:`found npm's "package-lock.json" lockfile`}:ce.existsSync(J.join(t,"pnpm-lock.yaml"))?{packageManager:"pnpm",reason:`found pnpm's "pnpm-lock.yaml" lockfile`}:null}async function Iv({project:t,locator:e,binFolder:r,ignoreCorepack:s,lifecycleScript:a,baseEnv:n=t?.configuration.env??process.env}){let c={};for(let[E,C]of Object.entries(n))typeof C<"u"&&(c[E.toLowerCase()!=="path"?E:"PATH"]=C);let f=fe.fromPortablePath(r);c.BERRY_BIN_FOLDER=fe.fromPortablePath(f);let p=process.env.COREPACK_ROOT&&!s?fe.join(process.env.COREPACK_ROOT,"dist/yarn.js"):process.argv[1];if(await Promise.all([P0(r,"node",process.execPath),...fn!==null?[P0(r,"run",process.execPath,[p,"run"]),P0(r,"yarn",process.execPath,[p]),P0(r,"yarnpkg",process.execPath,[p]),P0(r,"node-gyp",process.execPath,[p,"run","--top-level","node-gyp"])]:[]]),t&&(c.INIT_CWD=fe.fromPortablePath(t.configuration.startingCwd),c.PROJECT_CWD=fe.fromPortablePath(t.cwd)),c.PATH=c.PATH?`${f}${fe.delimiter}${c.PATH}`:`${f}`,c.npm_execpath=`${f}${fe.sep}yarn`,c.npm_node_execpath=`${f}${fe.sep}node`,e){if(!t)throw new Error("Assertion failed: Missing project");let E=t.tryWorkspaceByLocator(e),C=E?E.manifest.version??"":t.storedPackages.get(e.locatorHash).version??"";c.npm_package_name=un(e),c.npm_package_version=C;let S;if(E)S=E.cwd;else{let b=t.storedPackages.get(e.locatorHash);if(!b)throw new Error(`Package for ${Yr(t.configuration,e)} not found in the project`);let I=t.configuration.getLinkers(),T={project:t,report:new Ot({stdout:new b0.PassThrough,configuration:t.configuration})},N=I.find(U=>U.supportsPackage(b,T));if(!N)throw new Error(`The package ${Yr(t.configuration,b)} isn't supported by any of the available linkers`);S=await N.findPackageLocation(b,T)}c.npm_package_json=fe.fromPortablePath(J.join(S,Er.manifest))}let h=fn!==null?`yarn/${fn}`:`yarn/${bp("@yarnpkg/core").version}-core`;return c.npm_config_user_agent=`${h} npm/? node/${process.version} ${process.platform} ${process.arch}`,a&&(c.npm_lifecycle_event=a),t&&await t.configuration.triggerHook(E=>E.setupScriptEnvironment,t,c,async(E,C,S)=>await P0(r,E,C,S)),c}async function cit(t,e,{configuration:r,report:s,workspace:a=null,locator:n=null}){await lit(async()=>{await ce.mktempPromise(async c=>{let f=J.join(c,"pack.log"),p=null,{stdout:h,stderr:E}=r.getSubprocessStreams(f,{prefix:fe.fromPortablePath(t),report:s}),C=n&&Gu(n)?rI(n):n,S=C?ll(C):"an external project";h.write(`Packing ${S} from sources
`);let b=await ehe(t),I;b!==null?(h.write(`Using ${b.packageManager} for bootstrap. Reason: ${b.reason}
`),I=b.packageManager):(h.write(`No package manager configuration detected; defaulting to Yarn
`),I="Yarn");let T=I==="Yarn"&&!b?.packageManagerField;await ce.mktempPromise(async N=>{let U=await Iv({binFolder:N,ignoreCorepack:T,baseEnv:{...process.env,COREPACK_ENABLE_AUTO_PIN:"0"}}),ee=new Map([["Yarn Classic",async()=>{let ue=a!==null?["workspace",a]:[],le=J.join(t,Er.manifest),me=await ce.readFilePromise(le),pe=await Wu(process.execPath,[process.argv[1],"set","version","classic","--only-if-needed","--yarn-path"],{cwd:t,env:U,stdin:p,stdout:h,stderr:E,end:1});if(pe.code!==0)return pe.code;await ce.writeFilePromise(le,me),await ce.appendFilePromise(J.join(t,".npmignore"),`/.yarn
`),h.write(`
`),delete U.NODE_ENV;let Be=await Wu("yarn",["install"],{cwd:t,env:U,stdin:p,stdout:h,stderr:E,end:1});if(Be.code!==0)return Be.code;h.write(`
`);let Ce=await Wu("yarn",[...ue,"pack","--filename",fe.fromPortablePath(e)],{cwd:t,env:U,stdin:p,stdout:h,stderr:E});return Ce.code!==0?Ce.code:0}],["Yarn",async()=>{let ue=a!==null?["workspace",a]:[];U.YARN_ENABLE_INLINE_BUILDS="1";let le=J.join(t,Er.lockfile);await ce.existsPromise(le)||await ce.writeFilePromise(le,"");let me=await Wu("yarn",[...ue,"pack","--install-if-needed","--filename",fe.fromPortablePath(e)],{cwd:t,env:U,stdin:p,stdout:h,stderr:E});return me.code!==0?me.code:0}],["npm",async()=>{if(a!==null){let we=new b0.PassThrough,ye=WE(we);we.pipe(h,{end:!1});let Ae=await Wu("npm",["--version"],{cwd:t,env:U,stdin:p,stdout:we,stderr:E,end:0});if(we.end(),Ae.code!==0)return h.end(),E.end(),Ae.code;let se=(await ye).toString().trim();if(!Xf(se,">=7.x")){let X=Da(null,"npm"),De=On(X,se),Te=On(X,">=7.x");throw new Error(`Workspaces aren't supported by ${ni(r,De)}; please upgrade to ${ni(r,Te)} (npm has been detected as the primary package manager for ${Ht(r,t,ht.PATH)})`)}}let ue=a!==null?["--workspace",a]:[];delete U.npm_config_user_agent,delete U.npm_config_production,delete U.NPM_CONFIG_PRODUCTION,delete U.NODE_ENV;let le=await Wu("npm",["install","--legacy-peer-deps"],{cwd:t,env:U,stdin:p,stdout:h,stderr:E,end:1});if(le.code!==0)return le.code;let me=new b0.PassThrough,pe=WE(me);me.pipe(h);let Be=await Wu("npm",["pack","--silent",...ue],{cwd:t,env:U,stdin:p,stdout:me,stderr:E});if(Be.code!==0)return Be.code;let Ce=(await pe).toString().trim().replace(/^.*\n/s,""),g=J.resolve(t,fe.toPortablePath(Ce));return await ce.renamePromise(g,e),0}]]).get(I);if(typeof ee>"u")throw new Error("Assertion failed: Unsupported workflow");let ie=await ee();if(!(ie===0||typeof ie>"u"))throw ce.detachTemp(c),new jt(58,`Packing the package failed (exit code ${ie}, logs can be found here: ${Ht(r,f,ht.PATH)})`)})})})}async function uit(t,e,{project:r}){let s=r.tryWorkspaceByLocator(t);if(s!==null)return qj(s,e);let a=r.storedPackages.get(t.locatorHash);if(!a)throw new Error(`Package for ${Yr(r.configuration,t)} not found in the project`);return await $f.openPromise(async n=>{let c=r.configuration,f=r.configuration.getLinkers(),p={project:r,report:new Ot({stdout:new b0.PassThrough,configuration:c})},h=f.find(b=>b.supportsPackage(a,p));if(!h)throw new Error(`The package ${Yr(r.configuration,a)} isn't supported by any of the available linkers`);let E=await h.findPackageLocation(a,p),C=new Sn(E,{baseFs:n});return(await Ut.find(vt.dot,{baseFs:C})).scripts.has(e)})}async function OR(t,e,r,{cwd:s,project:a,stdin:n,stdout:c,stderr:f}){return await ce.mktempPromise(async p=>{let{manifest:h,env:E,cwd:C}=await the(t,{project:a,binFolder:p,cwd:s,lifecycleScript:e}),S=h.scripts.get(e);if(typeof S>"u")return 1;let b=async()=>await vI(S,r,{cwd:C,env:E,stdin:n,stdout:c,stderr:f});return await(await a.configuration.reduceHook(T=>T.wrapScriptExecution,b,a,t,e,{script:S,args:r,cwd:C,env:E,stdin:n,stdout:c,stderr:f}))()})}async function Gj(t,e,r,{cwd:s,project:a,stdin:n,stdout:c,stderr:f}){return await ce.mktempPromise(async p=>{let{env:h,cwd:E}=await the(t,{project:a,binFolder:p,cwd:s});return await vI(e,r,{cwd:E,env:h,stdin:n,stdout:c,stderr:f})})}async function fit(t,{binFolder:e,cwd:r,lifecycleScript:s}){let a=await Iv({project:t.project,locator:t.anchoredLocator,binFolder:e,lifecycleScript:s});return await Yj(e,await ihe(t)),typeof r>"u"&&(r=J.dirname(await ce.realpathPromise(J.join(t.cwd,"package.json")))),{manifest:t.manifest,binFolder:e,env:a,cwd:r}}async function the(t,{project:e,binFolder:r,cwd:s,lifecycleScript:a}){let n=e.tryWorkspaceByLocator(t);if(n!==null)return fit(n,{binFolder:r,cwd:s,lifecycleScript:a});let c=e.storedPackages.get(t.locatorHash);if(!c)throw new Error(`Package for ${Yr(e.configuration,t)} not found in the project`);return await $f.openPromise(async f=>{let p=e.configuration,h=e.configuration.getLinkers(),E={project:e,report:new Ot({stdout:new b0.PassThrough,configuration:p})},C=h.find(N=>N.supportsPackage(c,E));if(!C)throw new Error(`The package ${Yr(e.configuration,c)} isn't supported by any of the available linkers`);let S=await Iv({project:e,locator:t,binFolder:r,lifecycleScript:a});await Yj(r,await LR(t,{project:e}));let b=await C.findPackageLocation(c,E),I=new Sn(b,{baseFs:f}),T=await Ut.find(vt.dot,{baseFs:I});return typeof s>"u"&&(s=b),{manifest:T,binFolder:r,env:S,cwd:s}})}async function rhe(t,e,r,{cwd:s,stdin:a,stdout:n,stderr:c}){return await OR(t.anchoredLocator,e,r,{cwd:s,project:t.project,stdin:a,stdout:n,stderr:c})}function qj(t,e){return t.manifest.scripts.has(e)}async function nhe(t,e,{cwd:r,report:s}){let{configuration:a}=t.project,n=null;await ce.mktempPromise(async c=>{let f=J.join(c,`${e}.log`),p=`# This file contains the result of Yarn calling the "${e}" lifecycle script inside a workspace ("${fe.fromPortablePath(t.cwd)}")
`,{stdout:h,stderr:E}=a.getSubprocessStreams(f,{report:s,prefix:Yr(a,t.anchoredLocator),header:p});s.reportInfo(36,`Calling the "${e}" lifecycle script`);let C=await rhe(t,e,[],{cwd:r,stdin:n,stdout:h,stderr:E});if(h.end(),E.end(),C!==0)throw ce.detachTemp(c),new jt(36,`${PB(e)} script failed (exit code ${Ht(a,C,ht.NUMBER)}, logs can be found here: ${Ht(a,f,ht.PATH)}); run ${Ht(a,`yarn ${e}`,ht.CODE)} to investigate`)})}async function Ait(t,e,r){qj(t,e)&&await nhe(t,e,r)}function Wj(t){let e=J.extname(t);if(e.match(/\.[cm]?[jt]sx?$/))return!0;if(e===".exe"||e===".bin")return!1;let r=Buffer.alloc(4),s;try{s=ce.openSync(t,"r")}catch{return!0}try{ce.readSync(s,r,0,r.length,0)}finally{ce.closeSync(s)}let a=r.readUint32BE();return!(a===3405691582||a===3489328638||a===2135247942||(a&4294901760)===1297743872)}async function LR(t,{project:e}){let r=e.configuration,s=new Map,a=e.storedPackages.get(t.locatorHash);if(!a)throw new Error(`Package for ${Yr(r,t)} not found in the project`);let n=new b0.Writable,c=r.getLinkers(),f={project:e,report:new Ot({configuration:r,stdout:n})},p=new Set([t.locatorHash]);for(let E of a.dependencies.values()){let C=e.storedResolutions.get(E.descriptorHash);if(!C)throw new Error(`Assertion failed: The resolution (${ni(r,E)}) should have been registered`);p.add(C)}let h=await Promise.all(Array.from(p,async E=>{let C=e.storedPackages.get(E);if(!C)throw new Error(`Assertion failed: The package (${E}) should have been registered`);if(C.bin.size===0)return Wl.skip;let S=c.find(I=>I.supportsPackage(C,f));if(!S)return Wl.skip;let b=null;try{b=await S.findPackageLocation(C,f)}catch(I){if(I.code==="LOCATOR_NOT_INSTALLED")return Wl.skip;throw I}return{dependency:C,packageLocation:b}}));for(let E of h){if(E===Wl.skip)continue;let{dependency:C,packageLocation:S}=E;for(let[b,I]of C.bin){let T=J.resolve(S,I);s.set(b,[C,fe.fromPortablePath(T),Wj(T)])}}return s}async function ihe(t){return await LR(t.anchoredLocator,{project:t.project})}async function Yj(t,e){await Promise.all(Array.from(e,([r,[,s,a]])=>a?P0(t,r,process.execPath,[s]):P0(t,r,s,[])))}async function she(t,e,r,{cwd:s,project:a,stdin:n,stdout:c,stderr:f,nodeArgs:p=[],packageAccessibleBinaries:h}){h??=await LR(t,{project:a});let E=h.get(e);if(!E)throw new Error(`Binary not found (${e}) for ${Yr(a.configuration,t)}`);return await ce.mktempPromise(async C=>{let[,S]=E,b=await Iv({project:a,locator:t,binFolder:C});await Yj(b.BERRY_BIN_FOLDER,h);let I=Wj(fe.toPortablePath(S))?Wu(process.execPath,[...p,S,...r],{cwd:s,env:b,stdin:n,stdout:c,stderr:f}):Wu(S,r,{cwd:s,env:b,stdin:n,stdout:c,stderr:f}),T;try{T=await I}finally{await ce.removePromise(b.BERRY_BIN_FOLDER)}return T.code})}async function pit(t,e,r,{cwd:s,stdin:a,stdout:n,stderr:c,packageAccessibleBinaries:f}){return await she(t.anchoredLocator,e,r,{project:t.project,cwd:s,stdin:a,stdout:n,stderr:c,packageAccessibleBinaries:f})}var Xpe,b0,$pe,ait,lit,Vj=Ze(()=>{Dt();Dt();eA();pv();ql();Xpe=ut(Ld()),b0=Ie("stream");oI();Rc();Ev();yv();gR();xc();bc();Tp();Wo();$pe=(a=>(a.Yarn1="Yarn Classic",a.Yarn2="Yarn",a.Npm="npm",a.Pnpm="pnpm",a))($pe||{});ait=2,lit=(0,Xpe.default)(ait)});var DI=_((U4t,ahe)=>{"use strict";var ohe=new Map([["C","cwd"],["f","file"],["z","gzip"],["P","preservePaths"],["U","unlink"],["strip-components","strip"],["stripComponents","strip"],["keep-newer","newer"],["keepNewer","newer"],["keep-newer-files","newer"],["keepNewerFiles","newer"],["k","keep"],["keep-existing","keep"],["keepExisting","keep"],["m","noMtime"],["no-mtime","noMtime"],["p","preserveOwner"],["L","follow"],["h","follow"]]);ahe.exports=t=>t?Object.keys(t).map(e=>[ohe.has(e)?ohe.get(e):e,t[e]]).reduce((e,r)=>(e[r[0]]=r[1],e),Object.create(null)):{}});var bI=_((_4t,dhe)=>{"use strict";var lhe=typeof process=="object"&&process?process:{stdout:null,stderr:null},hit=Ie("events"),che=Ie("stream"),uhe=Ie("string_decoder").StringDecoder,_p=Symbol("EOF"),Hp=Symbol("maybeEmitEnd"),x0=Symbol("emittedEnd"),MR=Symbol("emittingEnd"),Cv=Symbol("emittedError"),UR=Symbol("closed"),fhe=Symbol("read"),_R=Symbol("flush"),Ahe=Symbol("flushChunk"),ul=Symbol("encoding"),jp=Symbol("decoder"),HR=Symbol("flowing"),wv=Symbol("paused"),PI=Symbol("resume"),Ys=Symbol("bufferLength"),Jj=Symbol("bufferPush"),Kj=Symbol("bufferShift"),Ko=Symbol("objectMode"),zo=Symbol("destroyed"),zj=Symbol("emitData"),phe=Symbol("emitEnd"),Zj=Symbol("emitEnd2"),Gp=Symbol("async"),Bv=t=>Promise.resolve().then(t),hhe=global._MP_NO_ITERATOR_SYMBOLS_!=="1",git=hhe&&Symbol.asyncIterator||Symbol("asyncIterator not implemented"),dit=hhe&&Symbol.iterator||Symbol("iterator not implemented"),mit=t=>t==="end"||t==="finish"||t==="prefinish",yit=t=>t instanceof ArrayBuffer||typeof t=="object"&&t.constructor&&t.constructor.name==="ArrayBuffer"&&t.byteLength>=0,Eit=t=>!Buffer.isBuffer(t)&&ArrayBuffer.isView(t),jR=class{constructor(e,r,s){this.src=e,this.dest=r,this.opts=s,this.ondrain=()=>e[PI](),r.on("drain",this.ondrain)}unpipe(){this.dest.removeListener("drain",this.ond Line truncated
`,a=Buffer.byteLength(s),n=Math.floor(Math.log(a)/Math.log(10))+1;return a+n>=Math.pow(10,n)&&(n+=1),n+a+s}};Sv.parse=(t,e,r)=>new Sv(jit(Git(t),e),r);var jit=(t,e)=>e?Object.keys(t).reduce((r,s)=>(r[s]=t[s],r),e):t,Git=t=>t.replace(/\n$/,"").split(`
`).reduce(qit,Object.create(null)),qit=(t,e)=>{let r=parseInt(e,10);if(r!==Buffer.byteLength(e)+1)return t;e=e.substr((r+" ").length);let s=e.split("="),a=s.shift().replace(/^SCHILY\.(dev|ino|nlink)/,"$1");if(!a)return t;let n=s.join("=");return t[a]=/^([A-Z]+\.)?([mac]|birth|creation)time$/.test(a)?new Date(n*1e3):/^[0-9]+$/.test(n)?+n:n,t};khe.exports=Sv});var FI=_((X4t,Qhe)=>{Qhe.exports=t=>{let e=t.length-1,r=-1;for(;e>-1&&t.charAt(e)==="/";)r=e,e--;return r===-1?t:t.slice(0,r)}});var KR=_(($4t,Rhe)=>{"use strict";Rhe.exports=t=>class extends t{warn(e,r,s={}){this.file&&(s.file=this.file),this.cwd&&(s.cwd=this.cwd),s.code=r instanceof Error&&r.code||e,s.tarCode=e,!this.strict&&s.recoverable!==!1?(r instanceof Error&&(s=Object.assign(r,s),r=r.message),this.emit("warn",s.tarCode,r,s)):r instanceof Error?this.emit("error",Object.assign(r,s)):this.emit("error",Object.assign(new Error(`${e}: ${r}`),s))}}});var v6=_((t3t,The)=>{"use strict";var zR=["|","<",">","?",":"],B6=zR.map(t=>String.fromCharCode(61440+t.charCodeAt(0))),Wit=new Map(zR.map((t,e)=>[t,B6[e]])),Yit=new Map(B6.map((t,e)=>[t,zR[e]]));The.exports={encode:t=>zR.reduce((e,r)=>e.split(r).join(Wit.get(r)),t),decode:t=>B6.reduce((e,r)=>e.split(r).join(Yit.get(r)),t)}});var S6=_((r3t,Nhe)=>{var{isAbsolute:Vit,parse:Fhe}=Ie("path").win32;Nhe.exports=t=>{let e="",r=Fhe(t);for(;Vit(t)||r.root;){let s=t.charAt(0)==="/"&&t.slice(0,4)!=="//?/"?"/":r.root;t=t.substr(s.length),e+=s,r=Fhe(t)}return[e,t]}});var Lhe=_((n3t,Ohe)=>{"use strict";Ohe.exports=(t,e,r)=>(t&=4095,r&&(t=(t|384)&-19),e&&(t&256&&(t|=64),t&32&&(t|=8),t&4&&(t|=1)),t)});var N6=_((o3t,Zhe)=>{"use strict";var qhe=bI(),Whe=JR(),Yhe=TI(),nA=Ie("fs"),Mhe=Ie("path"),rA=QI(),Jit=FI(),Vhe=(t,e)=>e?(t=rA(t).replace(/^\.(\/|$)/,""),Jit(e)+"/"+t):rA(t),Kit=16*1024*1024,Uhe=Symbol("process"),_he=Symbol("file"),Hhe=Symbol("directory"),P6=Symbol("symlink"),jhe=Symbol("hardlink"),Dv=Symbol("header"),ZR=Symbol("read"),b6=Symbol("lstat"),XR=Symbol("onlstat"),x6=Symbol("onread"),k6=Symbol("onreadlink"),Q6=Symbol("openfile"),R6=Symbol("onopenfile"),T0=Symbol("close"),$R=Symbol("mode"),T6=Symbol("awaitDrain"),D6=Symbol("ondrain"),iA=Symbol("prefix"),Ghe=Symbol("hadError"),Jhe=KR(),zit=v6(),Khe=S6(),zhe=Lhe(),eT=Jhe(class extends qhe{constructor(e,r){if(r=r||{},super(r),typeof e!="string")throw new TypeError("path is required");this.path=rA(e),this.portable=!!r.portable,this.myuid=process.getuid&&process.getuid()||0,this.myuser=process.env.USER||"",this.maxReadSize=r.maxReadSize||Kit,this.linkCache=r.linkCache||new Map,this.statCache=r.statCache||new Map,this.preservePaths=!!r.preservePaths,this.cwd=rA(r.cwd||process.cwd()),this.strict=!!r.strict,this.noPax=!!r.noPax,this.noMtime=!!r.noMtime,this.mtime=r.mtime||null,this.prefix=r.prefix?rA(r.prefix):null,this.fd=null,this.blockLen=null,this.blockRemain=null,this.buf=null,this.offset=null,this.length=null,this.pos=null,this.remain=null,typeof r.onwarn=="function"&&this.on("warn",r.onwarn);let s=!1;if(!this.preservePaths){let[a,n]=Khe(this.path);a&&(this.path=n,s=a)}this.win32=!!r.win32||process.platform==="win32",this.win32&&(this.path=zit.decode(this.path.replace(/\\/g,"/")),e=e.replace(/\\/g,"/")),this.absolute=rA(r.absolute||Mhe.resolve(this.cwd,e)),this.path===""&&(this.path="./"),s&&this.warn("TAR_ENTRY_INFO",`stripping ${s} from absolute path`,{entry:this,path:s+this.path}),this.statCache.has(this.absolute)?this[XR](this.statCache.get(this.absolute)):this[b6]()}emit(e,...r){return e==="error"&&(this[Ghe]=!0),super.emit(e,...r)}[b6](){nA.lstat(this.absolute,(e,r)=>{if(e)return this.emit("error",e);this[XR](r)})}[XR](e){this.statCache.set(this.absolute,e),this.stat=e,e.isFile()||(e.size=0),this.type=Xit(e),this.emit("stat",e),this[Uhe]()}[Uhe](){switch(this.type){case"File":return this[_he]();case"Directory":return this[Hhe]();case"SymbolicLink":return this[P6]();default:return this.end()}}[$R](e){return zhe(e,this.type==="Directory",this.portable)}[iA](e){return Vhe(e,this.prefix)}[Dv](){this.type==="Directory"&&this.portable&&(this.noMtime=!0),this.header=new Yhe({path:this[iA](this.path),linkpath:this.type==="Link"?this[iA](this.linkpath):this.linkpath,mode:this[$R](this.stat.mode),uid:this.portable?null:this.stat.uid,gid:this.portable?null:this.stat.gid,size:this.stat.size,mtime:this.noMtime?null:this.mtime||this.stat.mtime,type:this.type,uname:this.portable?null:this.stat.uid===this.myuid?this.myuser:"",atime:this.portable?null:this.stat.atime,ctime:this.portable?null:this.stat.ctime}),this.header.encode()&&!this.noPax&&super.write(new Whe({atime:this.portable?null:this.header.atime,ctime:this.portable?null:this.header.ctime,gid:this.portable?null:this.header.gid,mtime:this.noMtime?null:this.mtime||this.header.mtime,path:this[iA](this.path),linkpath:this.type==="Link"?this[iA](this.linkpath):this.linkpath,size:this.header.size,uid:this.portable?null:this.header.uid,uname:this.portable?null:this.header.uname,dev:this.portable?null:this.stat.dev,ino:this. Line truncated
`}),f},s})});var xs={};Vt(xs,{emitList:()=>qot,emitTree:()=>sde,treeNodeToJson:()=>ide,treeNodeToTreeify:()=>nde});function nde(t,{configuration:e}){let r={},s=0,a=(n,c)=>{let f=Array.isArray(n)?n.entries():Object.entries(n);for(let[p,h]of f){if(!h)continue;let{label:E,value:C,children:S}=h,b=[];typeof E<"u"&&b.push(zd(e,E,2)),typeof C<"u"&&b.push(Ht(e,C[0],C[1])),b.length===0&&b.push(zd(e,`${p}`,2));let I=b.join(": ").trim(),T=`\0${s++}\0`,N=c[`${T}${I}`]={};typeof S<"u"&&a(S,N)}};if(typeof t.children>"u")throw new Error("The root node must only contain children");return a(t.children,r),r}function ide(t){let e=r=>{if(typeof r.children>"u"){if(typeof r.value>"u")throw new Error("Assertion failed: Expected a value to be set if the children are missing");return Zd(r.value[0],r.value[1])}let s=Array.isArray(r.children)?r.children.entries():Object.entries(r.children??{}),a=Array.isArray(r.children)?[]:{};for(let[n,c]of s)c&&(a[Wot(n)]=e(c));return typeof r.value>"u"?a:{value:Zd(r.value[0],r.value[1]),children:a}};return e(t)}function qot(t,{configuration:e,stdout:r,json:s}){let a=t.map(n=>({value:n}));sde({children:a},{configuration:e,stdout:r,json:s})}function sde(t,{configuration:e,stdout:r,json:s,separators:a=0}){if(s){let c=Array.isArray(t.children)?t.children.values():Object.values(t.children??{});for(let f of c)f&&r.write(`${JSON.stringify(ide(f))}
`);return}let n=(0,rde.asTree)(nde(t,{configuration:e}),!1,!1);if(n=n.replace(/\0[0-9]+\0/g,""),a>=1&&(n=n.replace(/^([├└]─)/gm,`\u2502
$1`).replace(/^│\n/,"")),a>=2)for(let c=0;c<2;++c)n=n.replace(/^([│ ].{2}[├│ ].{2}[^\n]+\n)(([│ ]).{2}[├└].{2}[^\n]*\n[│ ].{2}[│ ].{2}[├└]─)/gm,`$1$3 \u2502
$2`).replace(/^│\n/,"");if(a>=3)throw new Error("Only the first two levels are accepted by treeUtils.emitTree");r.write(n)}function Wot(t){return typeof t=="string"?t.replace(/^\0[0-9]+\0/,""):t}var rde,ode=Ze(()=>{rde=ut(tde());xc()});var LT,ade=Ze(()=>{LT=class{constructor(e){this.releaseFunction=e;this.map=new Map}addOrCreate(e,r){let s=this.map.get(e);if(typeof s<"u"){if(s.refCount<=0)throw new Error(`Race condition in RefCountedMap. While adding a new key the refCount is: ${s.refCount} for ${JSON.stringify(e)}`);return s.refCount++,{value:s.value,release:()=>this.release(e)}}else{let a=r();return this.map.set(e,{refCount:1,value:a}),{value:a,release:()=>this.release(e)}}}release(e){let r=this.map.get(e);if(!r)throw new Error(`Unbalanced calls to release. No known instances of: ${JSON.stringify(e)}`);let s=r.refCount;if(s<=0)throw new Error(`Unbalanced calls to release. Too many release vs alloc refcount would become: ${s-1} of ${JSON.stringify(e)}`);s==1?(this.map.delete(e),this.releaseFunction(r.value)):r.refCount--}}});function _v(t){let e=t.match(Yot);if(!e?.groups)throw new Error("Assertion failed: Expected the checksum to match the requested pattern");let r=e.groups.cacheVersion?parseInt(e.groups.cacheVersion):null;return{cacheKey:e.groups.cacheKey??null,cacheVersion:r,cacheSpec:e.groups.cacheSpec??null,hash:e.groups.hash}}var lde,RG,TG,MT,Kr,Yot,FG=Ze(()=>{Ge();Dt();Dt();eA();lde=Ie("crypto"),RG=ut(Ie("fs"));ade();Rc();I0();bc();Wo();TG=YE(process.env.YARN_CACHE_CHECKPOINT_OVERRIDE??process.env.YARN_CACHE_VERSION_OVERRIDE??9),MT=YE(process.env.YARN_CACHE_VERSION_OVERRIDE??10),Kr=class t{constructor(e,{configuration:r,immutable:s=r.get("enableImmutableCache"),check:a=!1}){this.markedFiles=new Set;this.mutexes=new Map;this.refCountedZipFsCache=new LT(e=>{e.discardAndClose()});this.cacheId=`-${(0,lde.randomBytes)(8).toString("hex")}.tmp`;this.configuration=r,this.cwd=e,this.immutable=s,this.check=a;let{cacheSpec:n,cacheKey:c}=t.getCacheKey(r);this.cacheSpec=n,this.cacheKey=c}static async find(e,{immutable:r,check:s}={}){let a=new t(e.get("cacheFolder"),{configuration:e,immutable:r,check:s});return await a.setup(),a}static getCacheKey(e){let r=e.get("compressionLevel"),s=r!=="mixed"?`c${r}`:"";return{cacheKey:[MT,s].join(""),cacheSpec:s}}get mirrorCwd(){if(!this.configuration.get("enableMirror"))return null;let e=`${this.configuration.get("globalFolder")}/cache`;return e!==this.cwd?e:null}getVersionFilename(e){return`${nI(e)}-${this.cacheKey}.zip`}getChecksumFilename(e,r){let a=_v(r).hash.slice(0,10);return`${nI(e)}-${a}.zip`}isChecksumCompatible(e){if(e===null)return!1;let{cacheVersion:r,cacheSpec:s}=_v(e);if(r===null||r<TG)return!1;let a=this.configuration.get("cacheMigrationMode");return!(r<MT&&a==="always"||s!==this.cacheSpec&&a!=="required-only")}getLocatorPath(e,r){return this.mirrorCwd===null?J.resolve(this.cwd,this.getVersionFilename(e)):r===null?J.resolve(this.cwd,this.getVersionFilename(e)):J.resolve(this.cwd,this.getChecksumFilename(e,r))}getLocatorMirrorPath(e){let r=this.mirrorCwd;return r!==null?J.resolve(r,this.getVersionFilename(e)):null}async setup(){if(!this.configuration.get("enableGlobalCache"))if(this.immutable){if(!await ce.existsPromise(this.cwd))throw new jt(56,"Cache path does not exist.")}else{await ce.mkdirPromise(this.cwd,{recursive:!0});let e=J.resolve(this.cwd,".gitignore");await ce.changeFilePromise(e,`/.gitignore
*.flock
*.tmp
`)}(this.mirrorCwd||!this.immutable)&&await ce.mkdirPromise(this.mirrorCwd||this.cwd,{recursive:!0})}async fetchPackageFromCache(e,r,{onHit:s,onMiss:a,loader:n,...c}){let f=this.getLocatorMirrorPath(e),p=new Yn,h=()=>{let pe=new As,Be=J.join(vt.root,P8(e));return pe.mkdirSync(Be,{recursive:!0}),pe.writeJsonSync(J.join(Be,Er.manifest),{name:un(e),mocked:!0}),pe},E=async(pe,{isColdHit:Be,controlPath:Ce=null})=>{if(Ce===null&&c.unstablePackages?.has(e.locatorHash))return{isValid:!0,hash:null};let g=r&&!Be?_v(r).cacheKey:this.cacheKey,we=!c.skipIntegrityCheck||!r?`${g}/${await vQ(pe)}`:r;if(Ce!==null){let Ae=!c.skipIntegrityCheck||!r?`${this.cacheKey}/${await vQ(Ce)}`:r;if(we!==Ae)throw new jt(18,"The remote archive doesn't match the local checksum - has the local cache been corrupted?")}let ye=null;switch(r!==null&&we!==r&&(this.check?ye="throw":_v(r).cacheKey!==_v(we).cacheKey?ye="update":ye=this.configuration.get("checksumBehavior")),ye){case null:case"update":return{isValid:!0,hash:we};case"ignore":return{isValid:!0,hash:r};case"reset":return{isValid:!1,hash:r};default:case"throw":throw new jt(18,"The remote archive doesn't match the expected checksum")}},C=async pe=>{if(!n)throw new Error(`Cache check required but no loader configured for ${Yr(this.configuration,e)}`);let Be=await n(),Ce=Be.getRealPath();Be.saveAndClose(),await ce.chmodPromise(Ce,420);let g=await E(pe,{controlPath:Ce,isColdHit:!1});if(!g.isValid)throw new Error("Assertion failed: Expected a valid checksum");return g.hash},S=async()=>{if(f===null||!await ce.existsPromise(f)){let pe=await n(),Be=pe.getRealPath();return pe.saveAndClose(),{source:"loader",path:Be}}return{source:"mirror",path:f}},b=async()=>{if(!n)throw new Error(`Cache entry required but missing for ${Yr(this.configuration,e)}`);if(this.immutable)throw new jt(56,`Cache entry required but missing for ${Yr(this.configuration,e)}`);let{path:pe,source:Be}=await S(),{hash:Ce}=await E(pe,{isColdHit:!0}),g=this.getLocatorPath(e,Ce),we=[];Be!=="mirror"&&f!==null&&we.push(async()=>{let Ae=`${f}${this.cacheId}`;await ce.copyFilePromise(pe,Ae,RG.default.constants.COPYFILE_FICLONE),await ce.chmodPromise(Ae,420),await ce.renamePromise(Ae,f)}),(!c.mirrorWriteOnly||f===null)&&we.push(async()=>{let Ae=`${g}${this.cacheId}`;await ce.copyFilePromise(pe,Ae,RG.default.constants.COPYFILE_FICLONE),await ce.chmodPromise(Ae,420),await ce.renamePromise(Ae,g)});let ye=c.mirrorWriteOnly?f??g:g;return await Promise.all(we.map(Ae=>Ae())),[!1,ye,Ce]},I=async()=>{let Be=(async()=>{let Ce=c.unstablePackages?.has(e.locatorHash),g=Ce||!r||this.isChecksumCompatible(r)?this.getLocatorPath(e,r):null,we=g!==null?this.markedFiles.has(g)||await p.existsPromise(g):!1,ye=!!c.mockedPackages?.has(e.locatorHash)&&(!this.check||!we),Ae=ye||we,se=Ae?s:a;if(se&&se(),Ae){let X=null,De=g;if(!ye)if(this.check)X=await C(De);else{let Te=await E(De,{isColdHit:!1});if(Te.isValid)X=Te.hash;else return b()}return[ye,De,X]}else{if(this.immutable&&Ce)throw new jt(56,`Cache entry required but missing for ${Yr(this.configuration,e)}; consider defining ${he.pretty(this.configuration,"supportedArchitectures",he.Type.CODE)} to cache packages for multiple systems`);return b()}})();this.mutexes.set(e.locatorHash,Be);try{return await Be}finally{this.mutexes.delete(e.locatorHash)}};for(let pe;pe=this.mutexes.get(e.locatorHash);)await pe;let[T,N,U]=await I();T||this.markedFiles.add(N);let W=()=>this.refCountedZipFsCache.addOrCreate(N,()=>T?h():new As(N,{baseFs:p,readOnly:!0})),ee,ie=new oE(()=>G4(()=>(ee=W(),ee.value),pe=>`Failed to open the cache entry for ${Yr(this.configuration,e)}: ${pe}`),J),ue=new _f(N,{baseFs:ie,pathUtils:J}),le=()=>{ee?.release()},me=c.unstablePackages?.has(e.locatorHash)?null:U;return[ue,le,me]}},Yot=/^(?:(?<cacheKey>(?<cacheVersion>[0-9]+)(?<cacheSpec>.*))\/)?(?<hash>.*)$/});var UT,cde=Ze(()=>{UT=(r=>(r[r.SCRIPT=0]="SCRIPT",r[r.SHELLCODE=1]="SHELLCODE",r))(UT||{})});var Vot,KI,NG=Ze(()=>{Dt();wc();Tp();Wo();Vot=[[/^(git(?:\+(?:https|ssh))?:\/\/.*(?:\.git)?)#(.*)$/,(t,e,r,s)=>`${r}#commit=${s}`],[/^https:\/\/((?:[^/]+?)@)?codeload\.github\.com\/([^/]+\/[^/]+)\/tar\.gz\/([0-9a-f]+)$/,(t,e,r="",s,a)=>`https://${r}github.com/${s}.git#commit=${a}`],[/^https:\/\/((?:[^/]+?)@)?github\.com\/([^/]+\/[^/]+?)(?:\.git)?#([0-9a-f]+)$/,(t,e,r="",s,a)=>`https://${r}github.com/${s}.git#commit=${a}`],[/^https?:\/\/[^/]+\/(?:[^/]+\/)*(?:@.+(?:\/|(?:%2f)))?([^/]+)\/(?:-|download)\/\1-[^/]+\.tgz(?:#|$)/,t=>`npm:${t}`],[/^https:\/\/npm\.pkg\.github\.com\/download\/(?:@[^/]+)\/(?:[^/]+)\/(?:[^/]+)\/(?:[0-9a-f]+)(?:#|$)/,t=>`npm:${t}`],[/^https:\/\/npm\.fontawesome\.com\/(?:@[^/]+)\/([^/]+)\/-\/([^/]+)\/\1-\2.tgz(?:#|$)/,t=>`npm:${t}`],[/^https?:\/\/[^/]+\/.*\/(@[^/]+)\/([^/]+)\/-\/\1\/\2-(?:[.\d\w-]+)\.tgz(?:#|$)/,(t,e)=>xQ({protocol:"npm:",source:null,selector:t,params:{__archiveUrl:e}})],[/^[^/]+\.tgz#[0-9a-f]+$/,t=>`npm:${t}`]],KI=class{constructor(e){this.resolver=e;this.resolutions=null}async setup(e,{report:r}){let s=J.join(e.cwd,Er Line truncated
`)}reportProgress(r){return{...Promise.resolve().then(async()=>{for await(let{}of r);}),stop:()=>{}}}reportJson(r){}reportFold(r,s){}async finalize(){this.errorCount>0&&(this.stdout.write(`
`),this.stdout.write(`${Ht(this.configuration,"\u27A4","redBright")} Errors happened when preparing the environment required to run this command.
`),this.suggestInstall&&this.stdout.write(`${Ht(this.configuration,"\u27A4","redBright")} This might be caused by packages being missing from the lockfile, in which case running "yarn install" might help.
`))}formatNameWithHyperlink(r){return jj(r,{configuration:this.configuration,json:!1})}}});var zI,OG=Ze(()=>{Wo();zI=class{constructor(e){this.resolver=e}supportsDescriptor(e,r){return!!(r.project.storedResolutions.get(e.descriptorHash)||r.project.originalPackages.has(DQ(e).locatorHash))}supportsLocator(e,r){return!!(r.project.originalPackages.has(e.locatorHash)&&!r.project.lockfileNeedsRefresh)}shouldPersistResolution(e,r){throw new Error("The shouldPersistResolution method shouldn't be called on the lockfile resolver, which would always answer yes")}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){return this.resolver.getResolutionDependencies(e,r)}async getCandidates(e,r,s){let a=s.project.storedResolutions.get(e.descriptorHash);if(a){let c=s.project.originalPackages.get(a);if(c)return[c]}let n=s.project.originalPackages.get(DQ(e).locatorHash);if(n)return[n];throw new Error("Resolution expected from the lockfile data")}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){let s=r.project.originalPackages.get(e.locatorHash);if(!s)throw new Error("The lockfile resolver isn't meant to resolve packages - they should already have been stored into a cache");return s}}});function Kp(){}function Jot(t,e,r,s,a){for(var n=0,c=e.length,f=0,p=0;n<c;n++){var h=e[n];if(h.removed){if(h.value=t.join(s.slice(p,p+h.count)),p+=h.count,n&&e[n-1].added){var C=e[n-1];e[n-1]=e[n],e[n]=C}}else{if(!h.added&&a){var E=r.slice(f,f+h.count);E=E.map(function(b,I){var T=s[p+I];return T.length>b.length?T:b}),h.value=t.join(E)}else h.value=t.join(r.slice(f,f+h.count));f+=h.count,h.added||(p+=h.count)}}var S=e[c-1];return c>1&&typeof S.value=="string"&&(S.added||S.removed)&&t.equals("",S.value)&&(e[c-2].value+=S.value,e.pop()),e}function Kot(t){return{newPos:t.newPos,components:t.components.slice(0)}}function zot(t,e){if(typeof t=="function")e.callback=t;else if(t)for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r]);return e}function pde(t,e,r){return r=zot(r,{ignoreWhitespace:!0}),HG.diff(t,e,r)}function Zot(t,e,r){return jG.diff(t,e,r)}function _T(t){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?_T=function(e){return typeof e}:_T=function(e){return e&&typeof Symbol=="function"&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},_T(t)}function LG(t){return eat(t)||tat(t)||rat(t)||nat()}function eat(t){if(Array.isArray(t))return MG(t)}function tat(t){if(typeof Symbol<"u"&&Symbol.iterator in Object(t))return Array.from(t)}function rat(t,e){if(t){if(typeof t=="string")return MG(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);if(r==="Object"&&t.constructor&&(r=t.constructor.name),r==="Map"||r==="Set")return Array.from(t);if(r==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return MG(t,e)}}function MG(t,e){(e==null||e>t.length)&&(e=t.length);for(var r=0,s=new Array(e);r<e;r++)s[r]=t[r];return s}function nat(){throw new TypeError(`Invalid attempt to spread non-iterable instance.
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function UG(t,e,r,s,a){e=e||[],r=r||[],s&&(t=s(a,t));var n;for(n=0;n<e.length;n+=1)if(e[n]===t)return r[n];var c;if(iat.call(t)==="[object Array]"){for(e.push(t),c=new Array(t.length),r.push(c),n=0;n<t.length;n+=1)c[n]=UG(t[n],e,r,s,a);return e.pop(),r.pop(),c}if(t&&t.toJSON&&(t=t.toJSON()),_T(t)==="object"&&t!==null){e.push(t),c={},r.push(c);var f=[],p;for(p in t)t.hasOwnProperty(p)&&f.push(p);for(f.sort(),n=0;n<f.length;n+=1)p=f[n],c[p]=UG(t[p],e,r,s,p);e.pop(),r.pop()}else c=t;return c}function hde(t,e,r,s,a,n,c){c||(c={}),typeof c.context>"u"&&(c.context=4);var f=Zot(r,s,c);if(!f)return;f.push({value:"",lines:[]});function p(U){return U.map(function(W){return" "+W})}for(var h=[],E=0,C=0,S=[],b=1,I=1,T=function(W){var ee=f[W],ie=ee.lines||ee.value.replace(/\n$/,"").split(`
`);if(ee.lines=ie,ee.added||ee.removed){var ue;if(!E){var le=f[W-1];E=b,C=I,le&&(S=c.context>0?p(le.lines.slice(-c.context)):[],E-=S.length,C-=S.length)}(ue=S).push.apply(ue,LG(ie.map(function(Ae){return(ee.added?"+":"-")+Ae}))),ee.added?I+=ie.length:b+=ie.length}else{if(E)if(ie.length<=c.context*2&&W<f.length-2){var me;(me=S).push.apply(me,LG(p(ie)))}else{var pe,Be=Math.min(ie.length,c.context);(pe=S).push.apply(pe,LG(p(ie.slice(0,Be))));var Ce={oldStart:E,oldLines:b-E+Be,newStart:C,newLines:I-C+Be,lines:S};if(W>=f.length-2&&ie.length<=c.context){var g=/\n$/.test(r),we=/\n$/.test(s),ye=ie.length==0&&S.length>Ce.oldLines;!g&&ye&&r.length>0&&S.splice(Ce.oldLines,0,"\\ No newline at end of file"),(!g&&!ye||!we)&&S.push("\\ No newline at end of file")}h.push(Ce),E=0,C=0,S=[]}b+=ie.length,I+=ie.length}},N=0;N<f.length;N++)T(N);return{oldFileName:t,newFileName:e,oldHeader:a,newHeader:n,hunks:h}}var c8t,fde,Ade,HG,jG,Xot,$ot,iat,Hv,_G,GG=Ze(()=>{Kp.prototype={diff:function(e,r){var s=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},a=s.callback;typeof s=="function"&&(a=s,s={}),this.options=s;var n=this;function c(T){return a?(setTimeout(function(){a(void 0,T)},0),!0):T}e=this.castInput(e),r=this.castInput(r),e=this.removeEmpty(this.tokenize(e)),r=this.removeEmpty(this.tokenize(r));var f=r.length,p=e.length,h=1,E=f+p;s.maxEditLength&&(E=Math.min(E,s.maxEditLength));var C=[{newPos:-1,components:[]}],S=this.extractCommon(C[0],r,e,0);if(C[0].newPos+1>=f&&S+1>=p)return c([{value:this.join(r),count:r.length}]);function b(){for(var T=-1*h;T<=h;T+=2){var N=void 0,U=C[T-1],W=C[T+1],ee=(W?W.newPos:0)-T;U&&(C[T-1]=void 0);var ie=U&&U.newPos+1<f,ue=W&&0<=ee&&ee<p;if(!ie&&!ue){C[T]=void 0;continue}if(!ie||ue&&U.newPos<W.newPos?(N=Kot(W),n.pushComponent(N.components,void 0,!0)):(N=U,N.newPos++,n.pushComponent(N.components,!0,void 0)),ee=n.extractCommon(N,r,e,T),N.newPos+1>=f&&ee+1>=p)return c(Jot(n,N.components,r,e,n.useLongestToken));C[T]=N}h++}if(a)(function T(){setTimeout(function(){if(h>E)return a();b()||T()},0)})();else for(;h<=E;){var I=b();if(I)return I}},pushComponent:function(e,r,s){var a=e[e.length-1];a&&a.added===r&&a.removed===s?e[e.length-1]={count:a.count+1,added:r,removed:s}:e.push({count:1,added:r,removed:s})},extractCommon:function(e,r,s,a){for(var n=r.length,c=s.length,f=e.newPos,p=f-a,h=0;f+1<n&&p+1<c&&this.equals(r[f+1],s[p+1]);)f++,p++,h++;return h&&e.components.push({count:h}),e.newPos=f,p},equals:function(e,r){return this.options.comparator?this.options.comparator(e,r):e===r||this.options.ignoreCase&&e.toLowerCase()===r.toLowerCase()},removeEmpty:function(e){for(var r=[],s=0;s<e.length;s++)e[s]&&r.push(e[s]);return r},castInput:function(e){return e},tokenize:function(e){return e.split("")},join:function(e){return e.join("")}};c8t=new Kp;fde=/^[A-Za-z\xC0-\u02C6\u02C8-\u02D7\u02DE-\u02FF\u1E00-\u1EFF]+$/,Ade=/\S/,HG=new Kp;HG.equals=function(t,e){return this.options.ignoreCase&&(t=t.toLowerCase(),e=e.toLowerCase()),t===e||this.options.ignoreWhitespace&&!Ade.test(t)&&!Ade.test(e)};HG.tokenize=function(t){for(var e=t.split(/([^\S\r\n]+|[()[\]{}'"\r\n]|\b)/),r=0;r<e.length-1;r++)!e[r+1]&&e[r+2]&&fde.test(e[r])&&fde.test(e[r+2])&&(e[r]+=e[r+2],e.splice(r+1,2),r--);return e};jG=new Kp;jG.tokenize=function(t){var e=[],r=t.split(/(\n|\r\n)/);r[r.length-1]||r.pop();for(var s=0;s<r.length;s++){var a=r[s];s%2&&!this.options.newlineIsToken?e[e.length-1]+=a:(this.options.ignoreWhitespace&&(a=a.trim()),e.push(a))}return e};Xot=new Kp;Xot.tokenize=function(t){return t.split(/(\S.+?[.!?])(?=\s+|$)/)};$ot=new Kp;$ot.tokenize=function(t){return t.split(/([{}:;,]|\s+)/)};iat=Object.prototype.toString,Hv=new Kp;Hv.useLongestToken=!0;Hv.tokenize=jG.tokenize;Hv.castInput=function(t){var e=this.options,r=e.undefinedReplacement,s=e.stringifyReplacer,a=s===void 0?function(n,c){return typeof c>"u"?r:c}:s;return typeof t=="string"?t:JSON.stringify(UG(t,null,null,a),a," ")};Hv.equals=function(t,e){return Kp.prototype.equals.call(Hv,t.replace(/,([\r\n])/g,"$1"),e.replace(/,([\r\n])/g,"$1"))};_G=new Kp;_G.tokenize=function(t){return t.slice()};_G.join=_G.removeEmpty=function(t){return t}});var HT,gde=Ze(()=>{Rc();HT=class{constructor(e){this.resolver=e}supportsDescriptor(e,r){return this.resolver.supportsDescriptor(e,r)}supportsLocator(e,r){return this.resolver.supportsLocator(e,r)}shouldPersistResolution(e,r){return this.resolver.shouldPersistResolution(e,r)}bindDescriptor(e,r,s){return this.resolver.bindDescriptor(e,r,s)}getResolutionDependencies(e,r){return this.resolver.getResolutionDependencies(e,r)}async getCandidates(e,r,s){throw new jt(20,`This package doesn't seem to be present in your lockfile; run "yarn install" to update the lockfile`)}async getSatisfying(e,r,s,a){throw new jt(20,`This package doesn't seem to be present in your lockfile; run "yarn install" to update the lockfile`)}async resolve(e,r){throw new jt(20,`This package doesn't seem to be present in your lockfile; run "yarn install" to update the lockfLine truncated
`;await ce.changeFilePromise(r,s,{automaticNewlines:!0}),this.manifest.raw=e}}});function uat({project:t,allDescriptors:e,allResolutions:r,allPackages:s,accessibleLocators:a=new Set,optionalBuilds:n=new Set,peerRequirements:c=new Map,peerWarnings:f=[],peerRequirementNodes:p=new Map,volatileDescriptors:h=new Set}){let E=new Map,C=[],S=new Map,b=new Map,I=new Map,T=new Map,N=new Map,U=new Map(t.workspaces.map(le=>{let me=le.anchoredLocator.locatorHash,pe=s.get(me);if(typeof pe>"u")throw new Error("Assertion failed: The workspace should have an associated package");return[me,LB(pe)]})),W=()=>{let le=ce.mktempSync(),me=J.join(le,"stacktrace.log"),pe=String(C.length+1).length,Be=C.map((Ce,g)=>`${`${g+1}.`.padStart(pe," ")} ${ll(Ce)}
`).join("");throw ce.writeFileSync(me,Be),ce.detachTemp(le),new jt(45,`Encountered a stack overflow when resolving peer dependencies; cf ${fe.fromPortablePath(me)}`)},ee=le=>{let me=r.get(le.descriptorHash);if(typeof me>"u")throw new Error("Assertion failed: The resolution should have been registered");let pe=s.get(me);if(!pe)throw new Error("Assertion failed: The package could not be found");return pe},ie=(le,me,pe,{top:Be,optional:Ce})=>{C.length>1e3&&W(),C.push(me);let g=ue(le,me,pe,{top:Be,optional:Ce});return C.pop(),g},ue=(le,me,pe,{top:Be,optional:Ce})=>{if(Ce||n.delete(me.locatorHash),a.has(me.locatorHash))return;a.add(me.locatorHash);let g=s.get(me.locatorHash);if(!g)throw new Error(`Assertion failed: The package (${Yr(t.configuration,me)}) should have been registered`);let we=new Set,ye=new Map,Ae=[],se=[],X=[],De=[];for(let Te of Array.from(g.dependencies.values())){if(g.peerDependencies.has(Te.identHash)&&g.locatorHash!==Be)continue;if(kp(Te))throw new Error("Assertion failed: Virtual packages shouldn't be encountered when virtualizing a branch");h.delete(Te.descriptorHash);let mt=Ce;if(!mt){let ke=g.dependenciesMeta.get(un(Te));if(typeof ke<"u"){let it=ke.get(null);typeof it<"u"&&it.optional&&(mt=!0)}}let j=r.get(Te.descriptorHash);if(!j)throw new Error(`Assertion failed: The resolution (${ni(t.configuration,Te)}) should have been registered`);let rt=U.get(j)||s.get(j);if(!rt)throw new Error(`Assertion failed: The package (${j}, resolved from ${ni(t.configuration,Te)}) should have been registered`);if(rt.peerDependencies.size===0){ie(Te,rt,new Map,{top:Be,optional:mt});continue}let Fe,Ne,be=new Set,Ve=new Map;Ae.push(()=>{Fe=S8(Te,me.locatorHash),Ne=D8(rt,me.locatorHash),g.dependencies.set(Te.identHash,Fe),r.set(Fe.descriptorHash,Ne.locatorHash),e.set(Fe.descriptorHash,Fe),s.set(Ne.locatorHash,Ne),Pp(T,Ne.locatorHash).add(Fe.descriptorHash),we.add(Ne.locatorHash)}),se.push(()=>{N.set(Ne.locatorHash,Ve);for(let ke of Ne.peerDependencies.values()){let Ue=Yl(ye,ke.identHash,()=>{let x=pe.get(ke.identHash)??null,w=g.dependencies.get(ke.identHash);return!w&&UB(me,ke)&&(le.identHash===me.identHash?w=le:(w=On(me,le.range),e.set(w.descriptorHash,w),r.set(w.descriptorHash,me.locatorHash),h.delete(w.descriptorHash),x=null)),w||(w=On(ke,"missing:")),{subject:me,ident:ke,provided:w,root:!x,requests:new Map,hash:`p${cs(me.locatorHash,ke.identHash).slice(0,6)}`}}).provided;if(Ue.range==="missing:"&&Ne.dependencies.has(ke.identHash)){Ne.peerDependencies.delete(ke.identHash);continue}if(Ve.set(ke.identHash,{requester:Ne,descriptor:ke,meta:Ne.peerDependenciesMeta.get(un(ke)),children:new Map}),Ne.dependencies.set(ke.identHash,Ue),kp(Ue)){let x=r.get(Ue.descriptorHash);Pp(I,x).add(Ne.locatorHash)}S.set(Ue.identHash,Ue),Ue.range==="missing:"&&be.add(Ue.identHash)}Ne.dependencies=new Map(qs(Ne.dependencies,([ke,it])=>un(it)))}),X.push(()=>{if(!s.has(Ne.locatorHash))return;let ke=E.get(rt.locatorHash);typeof ke=="number"&&ke>=2&&W();let it=E.get(rt.locatorHash),Ue=typeof it<"u"?it+1:1;E.set(rt.locatorHash,Ue),ie(Fe,Ne,Ve,{top:Be,optional:mt}),E.set(rt.locatorHash,Ue-1)}),De.push(()=>{let ke=r.get(Fe.descriptorHash);if(typeof ke>"u")throw new Error("Assertion failed: Expected the descriptor to be registered");let it=N.get(ke);if(typeof it>"u")throw new Error("Assertion failed: Expected the peer requests to be registered");for(let Ue of ye.values()){let x=it.get(Ue.ident.identHash);x&&(Ue.requests.set(Fe.descriptorHash,x),p.set(Ue.hash,Ue),Ue.root||pe.get(Ue.ident.identHash)?.children.set(Fe.descriptorHash,x))}if(s.has(Ne.locatorHash))for(let Ue of be)Ne.dependencies.delete(Ue)})}for(let Te of[...Ae,...se])Te();for(let Te of we){we.delete(Te);let mt=s.get(Te),j=cs(rI(mt).locatorHash,...Array.from(mt.dependencies.values(),be=>{let Ve=be.range!=="missing:"?r.get(be.descriptorHash):"missing:";if(typeof Ve>"u")throw new Error(`Assertion failed: Expected the resolution for ${ni(t.configuration,be)} to have been registered`);return Ve===Be?`${Ve} (top)`:Ve})),rt=b.get(j);if(typeof rt>"u"){b.set(j,mt);continue}let Fe=Pp(T,rt.locatorHash);for(let be of T.get(mt.locatorHash)??[])r.set(be,rt.locatorHash),Fe.add(be);s.delete(mt.locatorHash),a.delete(mt.locatorHash),we.delete(mt.locatorHash);let Ne=I.get(mt.locatorHash);if(Ne!==void 0){let be=Pp(I,rt.locatorHash);for(let Ve of Ne)be.add(Ve),we.add(Ve)}}for(let Te of[...X,...De])Te()};for(let le of t.workspaces){let me=le.anchoredLocator;h.delete(le.anchoredDescriptor.descriptorHash),ie(le.anchoredDescriptor,me,new Map,{top:me.locatorHash,optional:!1})}for(let le of p.values()){if(!le.root)continue;let me=s.get(le.subject.locatorHash);if(typeof me>"u")continue;for(let Be of le.requests.values()){let Ce=`p${cs(le.subject.locatorHash,un(le.ident),Be.requester.locatorHash).slice(0,6)}`;c.set(Ce,{subject:le.subject.locatorHash,requested:le.ident,rootRequester:Be.requester.locatorHash,allRequesters:Array.from(qB(Be),g=>g.requester.locatorHash)})}let pe=[...qB(le)];if(le.provided.rang Line truncated
${[C,S,b].join(`
`)}`)}async setupResolutions(){this.storedResolutions=new Map,this.storedDescriptors=new Map,this.storedPackages=new Map,this.lockFileChecksum=null;let e=J.join(this.cwd,Er.lockfile),r=this.configuration.get("defaultLanguageName");if(ce.existsSync(e)){let s=await ce.readFilePromise(e,"utf8");this.lockFileChecksum=yde(s);let a=as(s);if(a.__metadata){let n=a.__metadata.version,c=a.__metadata.cacheKey;this.lockfileLastVersion=n,this.lockfileNeedsRefresh=n<qT;for(let f of Object.keys(a)){if(f==="__metadata")continue;let p=a[f];if(typeof p.resolution>"u")throw new Error(`Assertion failed: Expected the lockfile entry to have a resolution field (${f})`);let h=Qp(p.resolution,!0),E=new Ut;E.load(p,{yamlCompatibilityMode:!0});let C=E.version,S=E.languageName||r,b=p.linkType.toUpperCase(),I=p.conditions??null,T=E.dependencies,N=E.peerDependencies,U=E.dependenciesMeta,W=E.peerDependenciesMeta,ee=E.bin;if(p.checksum!=null){let ue=typeof c<"u"&&!p.checksum.includes("/")?`${c}/${p.checksum}`:p.checksum;this.storedChecksums.set(h.locatorHash,ue)}let ie={...h,version:C,languageName:S,linkType:b,conditions:I,dependencies:T,peerDependencies:N,dependenciesMeta:U,peerDependenciesMeta:W,bin:ee};this.originalPackages.set(ie.locatorHash,ie);for(let ue of f.split(oat)){let le=C0(ue);n<=6&&(le=this.configuration.normalizeDependency(le),le=On(le,le.range.replace(/^patch:[^@]+@(?!npm(:|%3A))/,"$1npm%3A"))),this.storedDescriptors.set(le.descriptorHash,le),this.storedResolutions.set(le.descriptorHash,h.locatorHash)}}}else s.includes("yarn lockfile v1")&&(this.lockfileLastVersion=-1)}}async setupWorkspaces(){this.workspaces=[],this.workspacesByCwd=new Map,this.workspacesByIdent=new Map;let e=new Set,r=(0,GT.default)(4),s=async(a,n)=>{if(e.has(n))return a;e.add(n);let c=new ZI(n,{project:this});await r(()=>c.setup());let f=a.then(()=>{this.addWorkspace(c)});return Array.from(c.workspacesCwds).reduce(s,f)};await s(Promise.resolve(),this.cwd)}addWorkspace(e){let r=this.workspacesByIdent.get(e.anchoredLocator.identHash);if(typeof r<"u")throw new Error(`Duplicate workspace name ${Xi(this.configuration,e.anchoredLocator)}: ${fe.fromPortablePath(e.cwd)} conflicts with ${fe.fromPortablePath(r.cwd)}`);this.workspaces.push(e),this.workspacesByCwd.set(e.cwd,e),this.workspacesByIdent.set(e.anchoredLocator.identHash,e)}get topLevelWorkspace(){return this.getWorkspaceByCwd(this.cwd)}tryWorkspaceByCwd(e){J.isAbsolute(e)||(e=J.resolve(this.cwd,e)),e=J.normalize(e).replace(/\/+$/,"");let r=this.workspacesByCwd.get(e);return r||null}getWorkspaceByCwd(e){let r=this.tryWorkspaceByCwd(e);if(!r)throw new Error(`Workspace not found (${e})`);return r}tryWorkspaceByFilePath(e){let r=null;for(let s of this.workspaces)J.relative(s.cwd,e).startsWith("../")||r&&r.cwd.length>=s.cwd.length||(r=s);return r||null}getWorkspaceByFilePath(e){let r=this.tryWorkspaceByFilePath(e);if(!r)throw new Error(`Workspace not found (${e})`);return r}tryWorkspaceByIdent(e){let r=this.workspacesByIdent.get(e.identHash);return typeof r>"u"?null:r}getWorkspaceByIdent(e){let r=this.tryWorkspaceByIdent(e);if(!r)throw new Error(`Workspace not found (${Xi(this.configuration,e)})`);return r}tryWorkspaceByDescriptor(e){if(e.range.startsWith(Ei.protocol)){let s=e.range.slice(Ei.protocol.length);if(s!=="^"&&s!=="~"&&s!=="*"&&!cl(s))return this.tryWorkspaceByCwd(s)}let r=this.tryWorkspaceByIdent(e);return r===null||(kp(e)&&(e=MB(e)),!r.accepts(e.range))?null:r}getWorkspaceByDescriptor(e){let r=this.tryWorkspaceByDescriptor(e);if(r===null)throw new Error(`Workspace not found (${ni(this.configuration,e)})`);return r}tryWorkspaceByLocator(e){let r=this.tryWorkspaceByIdent(e);return r===null||(Gu(e)&&(e=rI(e)),r.anchoredLocator.locatorHash!==e.locatorHash)?null:r}getWorkspaceByLocator(e){let r=this.tryWorkspaceByLocator(e);if(!r)throw new Error(`Workspace not found (${Yr(this.configuration,e)})`);return r}deleteDescriptor(e){this.storedResolutions.delete(e),this.storedDescriptors.delete(e)}deleteLocator(e){this.originalPackages.delete(e),this.storedPackages.delete(e),this.accessibleLocators.delete(e)}forgetResolution(e){if("descriptorHash"in e){let r=this.storedResolutions.get(e.descriptorHash);this.deleteDescriptor(e.descriptorHash);let s=new Set(this.storedResolutions.values());typeof r<"u"&&!s.has(r)&&this.deleteLocator(r)}if("locatorHash"in e){this.deleteLocator(e.locatorHash);for(let[r,s]of this.storedResolutions)s===e.locatorHash&&this.deleteDescriptor(r)}}forgetTransientResolutions(){let e=this.configuration.makeResolver(),r=new Map;for(let[s,a]of this.storedResolutions.entries()){let n=r.get(a);n||r.set(a,n=new Set),n.add(s)}for(let s of this.originalPackages.values()){let a;try{a=e.shouldPersistResolution(s,{project:this,resolver:e})}catch{a=!1}if(!a){this.deleteLocator(s.locatorHash);let n=r.get(s.locatorHash);if(n){r.delete(s.locatorHash);for(let c of n)this.deleteDescriptor(c)}}}}forgetVirtualResolutions(){for(let e of this.storedPackages.values())for(let[r,s]of e.dependencies)kp(s)&&e.dLine truncated
`;switch(rt.type){case 0:Fe+=`# Script name: ${rt.script}
`;break;case 1:Fe+=`# Script code: ${rt.script}
`;break}let Ne=null;if(!await ce.mktempPromise(async Ve=>{let ke=J.join(Ve,"build.log"),{stdout:it,stderr:Ue}=this.configuration.getSubprocessStreams(ke,{header:Fe,prefix:Yr(this.configuration,X),report:r}),x;try{switch(rt.type){case 0:x=await OR(X,rt.script,[],{cwd:j,project:this,stdin:Ne,stdout:it,stderr:Ue});break;case 1:x=await Gj(X,rt.script,[],{cwd:j,project:this,stdin:Ne,stdout:it,stderr:Ue});break}}catch(y){Ue.write(y.stack),x=1}if(it.end(),Ue.end(),x===0)return!0;ce.detachTemp(Ve);let w=`${Yr(this.configuration,X)} couldn't be built successfully (exit code ${Ht(this.configuration,x,ht.NUMBER)}, logs can be found here: ${Ht(this.configuration,ke,ht.PATH)})`,P=this.optionalBuilds.has(X.locatorHash);return P?r.reportInfo(9,w):r.reportError(9,w),zpe&&r.reportFold(fe.fromPortablePath(ke),ce.readFileSync(ke,"utf8")),P}))return!1}return!0});Ae.push(...mt,Promise.allSettled(mt).then(j=>{ie.delete(se),j.every(rt=>rt.status==="fulfilled"&&rt.value===!0)&&Ce.set(X.locatorHash,Te)}))}if(await Uu(Ae),ye===ie.size){let se=Array.from(ie).map(X=>{let De=this.storedPackages.get(X);if(!De)throw new Error("Assertion failed: The package should have been registered");return Yr(this.configuration,De)}).join(", ");r.reportError(3,`Some packages have circular dependencies that make their build order unsatisfiable - as a result they won't be built (affected packages are: ${se})`);break}}this.storedBuildState=Ce,this.skippedBuilds=N}async installWithNewReport(e,r){return(await Ot.start({configuration:this.configuration,json:e.json,stdout:e.stdout,forceSectionAlignment:!0,includeLogs:!e.json&&!e.quiet,includeVersion:!0},async a=>{await this.install({...r,report:a})})).exitCode()}async install(e){let r=this.configuration.get("nodeLinker");ze.telemetry?.reportInstall(r);let s=!1;if(await e.report.startTimerPromise("Project validation",{skipIfEmpty:!0},async()=>{this.configuration.get("enableOfflineMode")&&e.report.reportWarning(90,"Offline work is enabled; Yarn won't fetch packages from the remote registry if it can avoid it"),await this.configuration.triggerHook(E=>E.validateProject,this,{reportWarning:(E,C)=>{e.report.reportWarning(E,C)},reportError:(E,C)=>{e.report.reportError(E,C),s=!0}})}),s)return;let a=await this.configuration.getPackageExtensions();for(let E of a.values())for(let[,C]of E)for(let S of C)S.status="inactive";let n=J.join(this.cwd,Er.lockfile),c=null;if(e.immutable)try{c=await ce.readFilePromise(n,"utf8")}catch(E){throw E.code==="ENOENT"?new jt(28,"The lockfile would have been created by this install, which is explicitly forbidden."):E}await e.report.startTimerPromise("Resolution step",async()=>{await this.resolveEverything(e)}),await e.report.startTimerPromise("Post-resolution validation",{skipIfEmpty:!0},async()=>{Aat(this,e.report);for(let[,E]of a)for(let[,C]of E)for(let S of C)if(S.userProvided){let b=Ht(this.configuration,S,ht.PACKAGE_EXTENSION);switch(S.status){case"inactive":e.report.reportWarning(68,`${b}: No matching package in the dependency tree; you may not need this rule anymore.`);break;case"redundant":e.report.reportWarning(69,`${b}: This rule seems redundant when applied on the original package; the extension may have been applied upstream.`);break}}if(c!==null){let E=Ed(c,this.generateLockfile());if(E!==c){let C=hde(n,n,c,E,void 0,void 0,{maxEditLength:100});if(C){e.report.reportSeparator();for(let S of C.hunks){e.report.reportInfo(null,`@@ -${S.oldStart},${S.oldLines} +${S.newStart},${S.newLines} @@`);for(let b of S.lines)b.startsWith("+")?e.report.reportError(28,Ht(this.configuration,b,ht.ADDED)):b.startsWith("-")?e.report.reportError(28,Ht(this.configuration,b,ht.REMOVED)):e.report.reportInfo(null,Ht(this.configuration,b,"grey"))}e.report.reportSeparator()}throw new jt(28,"The lockfile would have been modified by this install, which is explicitly forbidden.")}}});for(let E of a.values())for(let[,C]of E)for(let S of C)S.userProvided&&S.status==="active"&&ze.telemetry?.reportPackageExtension(Zd(S,ht.PACKAGE_EXTENSION));await e.report.startTimerPromise("Fetch step",async()=>{await this.fetchEverything(e)});let f=e.immutable?[...new Set(this.configuration.get("immutablePatterns"))].sort():[],p=await Promise.all(f.map(async E=>SQ(E,{cwd:this.cwd})));(typeof e.persistProject>"u"||e.persistProject)&&await this.persist(),await e.report.startTimerPromise("Link step",async()=>{if(e.mode==="update-lockfile"){e.report.reportWarning(73,`Skipped due to ${Ht(this.configuration,"mode=update-lockfile",ht.CODE)}`);return}await this.linkEverything(e);let E=await Promise.all(f.map(async C=>SQ(C,{cwd:this.cwd})));for(let C=0;C<f.length;++C)p[C]!==E[C]&&e.report.reportError(64,`The checksum for ${f[C]} has been modified by this install, which is explicitly forbidden.`)}),await this.persistInstallStateFile();let h=!1;await e.report.startTimerPromise("Post-install validation",{skipIfEmpty:!0},async()=>{await this.configuration.triggerHook(E=>E.validateProjectAfterInstall,this,{reportWarning:(E,C)=>{e.report.r Line truncated
`,`# Manual changes might be lost - proceed with caution!
`].join("")}
`+nl(r)}async persistLockfile(){let e=J.join(this.cwd,Er.lockfile),r="";try{r=await ce.readFilePromise(e,"utf8")}catch{}let s=this.generateLockfile(),a=Ed(r,s);a!==r&&(await ce.writeFilePromise(e,a),this.lockFileChecksum=yde(a),this.lockfileNeedsRefresh=!1)}async persistInstallStateFile(){let e=[];for(let c of Object.values(YG))e.push(...c);let r=Kd(this,e),s=VG.default.serialize(r),a=cs(s);if(this.installStateChecksum===a)return;let n=this.configuration.get("installStatePath");await ce.mkdirPromise(J.dirname(n),{recursive:!0}),await ce.writeFilePromise(n,await lat(s)),this.installStateChecksum=a}async restoreInstallState({restoreLinkersCustomData:e=!0,restoreResolutions:r=!0,restoreBuildState:s=!0}={}){let a=this.configuration.get("installStatePath"),n;try{let c=await cat(await ce.readFilePromise(a));n=VG.default.deserialize(c),this.installStateChecksum=cs(c)}catch{r&&await this.applyLightResolution();return}e&&typeof n.linkersCustomData<"u"&&(this.linkersCustomData=n.linkersCustomData),s&&Object.assign(this,Kd(n,YG.restoreBuildState)),r&&(n.lockFileChecksum===this.lockFileChecksum?Object.assign(this,Kd(n,YG.restoreResolutions)):await this.applyLightResolution())}async applyLightResolution(){await this.resolveEverything({lockfileOnly:!0,report:new ki}),await this.persistInstallStateFile()}async persist(){let e=(0,GT.default)(4);await Promise.all([this.persistLockfile(),...this.workspaces.map(r=>e(()=>r.persistManifest()))])}async cacheCleanup({cache:e,report:r}){if(this.configuration.get("enableGlobalCache"))return null;let s=new Set([".gitignore"]);if(!j8(e.cwd,this.cwd)||!await ce.existsPromise(e.cwd))return null;let a=[];for(let c of await ce.readdirPromise(e.cwd)){if(s.has(c))continue;let f=J.resolve(e.cwd,c);e.markedFiles.has(f)||(e.immutable?r.reportError(56,`${Ht(this.configuration,J.basename(f),"magenta")} appears to be unused and would be marked for deletion, but the cache is immutable`):a.push(ce.lstatPromise(f).then(async p=>(await ce.removePromise(f),p.size))))}if(a.length===0)return null;let n=await Promise.all(a);return{count:a.length,size:n.reduce((c,f)=>c+f,0)}}}});function pat(t){let s=Math.floor(t.timeNow/864e5),a=t.updateInterval*864e5,n=t.state.lastUpdate??t.timeNow+a+Math.floor(a*t.randomInitialInterval),c=n+a,f=t.state.lastTips??s*864e5,p=f+864e5+8*36e5-t.timeZone,h=c<=t.timeNow,E=p<=t.timeNow,C=null;return(h||E||!t.state.lastUpdate||!t.state.lastTips)&&(C={},C.lastUpdate=h?t.timeNow:n,C.lastTips=f,C.blocks=h?{}:t.state.blocks,C.displayedTips=t.state.displayedTips),{nextState:C,triggerUpdate:h,triggerTips:E,nextTips:E?s*864e5:f}}var XI,Cde=Ze(()=>{Dt();yv();I0();AR();bc();Tp();XI=class{constructor(e,r){this.values=new Map;this.hits=new Map;this.enumerators=new Map;this.nextTips=0;this.displayedTips=[];this.shouldCommitTips=!1;this.configuration=e;let s=this.getRegistryPath();this.isNew=!ce.existsSync(s),this.shouldShowTips=!1,this.sendReport(r),this.startBuffer()}commitTips(){this.shouldShowTips&&(this.shouldCommitTips=!0)}selectTip(e){let r=new Set(this.displayedTips),s=f=>f&&fn?Xf(fn,f):!1,a=e.map((f,p)=>p).filter(f=>e[f]&&s(e[f]?.selector));if(a.length===0)return null;let n=a.filter(f=>!r.has(f));if(n.length===0){let f=Math.floor(a.length*.2);this.displayedTips=f>0?this.displayedTips.slice(-f):[],n=a.filter(p=>!r.has(p))}let c=n[Math.floor(Math.random()*n.length)];return this.displayedTips.push(c),this.commitTips(),e[c]}reportVersion(e){this.reportValue("version",e.replace(/-git\..*/,"-git"))}reportCommandName(e){this.reportValue("commandName",e||"<none>")}reportPluginName(e){this.reportValue("pluginName",e)}reportProject(e){this.reportEnumerator("projectCount",e)}reportInstall(e){this.reportHit("installCount",e)}reportPackageExtension(e){this.reportValue("packageExtension",e)}reportWorkspaceCount(e){this.reportValue("workspaceCount",String(e))}reportDependencyCount(e){this.reportValue("dependencyCount",String(e))}reportValue(e,r){Pp(this.values,e).add(r)}reportEnumerator(e,r){Pp(this.enumerators,e).add(cs(r))}reportHit(e,r="*"){let s=j4(this.hits,e),a=Yl(s,r,()=>0);s.set(r,a+1)}getRegistryPath(){let e=this.configuration.get("globalFolder");return J.join(e,"telemetry.json")}sendReport(e){let r=this.getRegistryPath(),s;try{s=ce.readJsonSync(r)}catch{s={}}let{nextState:a,triggerUpdate:n,triggerTips:c,nextTips:f}=pat({state:s,timeNow:Date.now(),timeZone:new Date().getTimezoneOffset()*60*1e3,randomInitialInterval:Math.random(),updateInterval:this.configuration.get("telemetryInterval")});if(this.nextTips=f,this.displayedTips=s.displayedTips??[],a!==null)try{ce.mkdirSync(J.dirname(r),{recursive:!0}),ce.writeJsonSync(r,a)}catch{return!1}if(c&&this.configuration.get("enableTips")&&(this.shouldShowTips=!0),n){let p=s.blocks??{};if(Object.keys(p).length===0){let h=`https://browser-http-intake.logs.datadoghq.eu/v1/input/${e}?ddsource=yarn`,E=C=>aj(h,C,{configuration:this.configuration}).catch(()=>{});for(let[C,S]of Object.entries(s.blocks??{})){if(Object.keys(S).length===0)continue;let b=S;b Line truncated
`),h=c.length;for(h>0&&c.includes("unstyle")&&(c=[...new Set(["unstyle",...c])].reverse());h-- >0;)f=r(t.styles[c[h]],f,p);return f},a=(n,c,f)=>{t.styles[n]=e({name:n,codes:c}),(t.keys[f]||(t.keys[f]=[])).push(n),Reflect.defineProperty(t,n,{configurable:!0,enumerable:!0,set(h){t.alias(n,h)},get(){let h=E=>s(E,h.stack);return Reflect.setPrototypeOf(h,t),h.stack=this.stack?this.stack.concat(n):[n],h}})};return a("reset",[0,0],"modifier"),a("bold",[1,22],"modifier"),a("dim",[2,22],"modifier"),a("italic",[3,23],"modifier"),a("underline",[4,24],"modifier"),a("inverse",[7,27],"modifier"),a("hidden",[8,28],"modifier"),a("strikethrough",[9,29],"modifier"),a("black",[30,39],"color"),a("red",[31,39],"color"),a("green",[32,39],"color"),a("yellow",[33,39],"color"),a("blue",[34,39],"color"),a("magenta",[35,39],"color"),a("cyan",[36,39],"color"),a("white",[37,39],"color"),a("gray",[90,39],"color"),a("grey",[90,39],"color"),a("bgBlack",[40,49],"bg"),a("bgRed",[41,49],"bg"),a("bgGreen",[42,49],"bg"),a("bgYellow",[43,49],"bg"),a("bgBlue",[44,49],"bg"),a("bgMagenta",[45,49],"bg"),a("bgCyan",[46,49],"bg"),a("bgWhite",[47,49],"bg"),a("blackBright",[90,39],"bright"),a("redBright",[91,39],"bright"),a("greenBright",[92,39],"bright"),a("yellowBright",[93,39],"bright"),a("blueBright",[94,39],"bright"),a("magentaBright",[95,39],"bright"),a("cyanBright",[96,39],"bright"),a("whiteBright",[97,39],"bright"),a("bgBlackBright",[100,49],"bgBright"),a("bgRedBright",[101,49],"bgBright"),a("bgGreenBright",[102,49],"bgBright"),a("bgYellowBright",[103,49],"bgBright"),a("bgBlueBright",[104,49],"bgBright"),a("bgMagentaBright",[105,49],"bgBright"),a("bgCyanBright",[106,49],"bgBright"),a("bgWhiteBright",[107,49],"bgBright"),t.ansiRegex=yat,t.hasColor=t.hasAnsi=n=>(t.ansiRegex.lastIndex=0,typeof n=="string"&&n!==""&&t.ansiRegex.test(n)),t.alias=(n,c)=>{let f=typeof c=="string"?t[c]:c;if(typeof f!="function")throw new TypeError("Expected alias to be the name of an existing color (string) or a function");f.stack||(Reflect.defineProperty(f,"name",{value:n}),t.styles[n]=f,f.stack=[n]),Reflect.defineProperty(t,n,{configurable:!0,enumerable:!0,set(p){t.alias(n,p)},get(){let p=h=>s(h,p.stack);return Reflect.setPrototypeOf(p,t),p.stack=this.stack?this.stack.concat(f.stack):f.stack,p}})},t.theme=n=>{if(!mat(n))throw new TypeError("Expected theme to be an object");for(let c of Object.keys(n))t.alias(c,n[c]);return t},t.alias("unstyle",n=>typeof n=="string"&&n!==""?(t.ansiRegex.lastIndex=0,n.replace(t.ansiRegex,"")):""),t.alias("noop",n=>n),t.none=t.clear=t.noop,t.stripColor=t.unstyle,t.symbols=Pde(),t.define=a,t};ZG.exports=bde();ZG.exports.create=bde});var Xo=_(pn=>{"use strict";var Eat=Object.prototype.toString,jc=Ju(),xde=!1,XG=[],kde={yellow:"blue",cyan:"red",green:"magenta",black:"white",blue:"yellow",red:"cyan",magenta:"green",white:"black"};pn.longest=(t,e)=>t.reduce((r,s)=>Math.max(r,e?s[e].length:s.length),0);pn.hasColor=t=>!!t&&jc.hasColor(t);var VT=pn.isObject=t=>t!==null&&typeof t=="object"&&!Array.isArray(t);pn.nativeType=t=>Eat.call(t).slice(8,-1).toLowerCase().replace(/\s/g,"");pn.isAsyncFn=t=>pn.nativeType(t)==="asyncfunction";pn.isPrimitive=t=>t!=null&&typeof t!="object"&&typeof t!="function";pn.resolve=(t,e,...r)=>typeof e=="function"?e.call(t,...r):e;pn.scrollDown=(t=[])=>[...t.slice(1),t[0]];pn.scrollUp=(t=[])=>[t.pop(),...t];pn.reorder=(t=[])=>{let e=t.slice();return e.sort((r,s)=>r.index>s.index?1:r.index<s.index?-1:0),e};pn.swap=(t,e,r)=>{let s=t.length,a=r===s?0:r<0?s-1:r,n=t[e];t[e]=t[a],t[a]=n};pn.width=(t,e=80)=>{let r=t&&t.columns?t.columns:e;return t&&typeof t.getWindowSize=="function"&&(r=t.getWindowSize()[0]),process.platform==="win32"?r-1:r};pn.height=(t,e=20)=>{let r=t&&t.rows?t.rows:e;return t&&typeof t.getWindowSize=="function"&&(r=t.getWindowSize()[1]),r};pn.wordWrap=(t,e={})=>{if(!t)return t;typeof e=="number"&&(e={width:e});let{indent:r="",newline:s=`
`+r,width:a=80}=e,n=(s+r).match(/[^\S\n]/g)||[];a-=n.length;let c=`.{1,${a}}([\\s\\u200B]+|$)|[^\\s\\u200B]+?([\\s\\u200B]+|$)`,f=t.trim(),p=new RegExp(c,"g"),h=f.match(p)||[];return h=h.map(E=>E.replace(/\n$/,"")),e.padEnd&&(h=h.map(E=>E.padEnd(a," "))),e.padStart&&(h=h.map(E=>E.padStart(a," "))),r+h.join(s)};pn.unmute=t=>{let e=t.stack.find(s=>jc.keys.color.includes(s));return e?jc[e]:t.stack.find(s=>s.slice(2)==="bg")?jc[e.slice(2)]:s=>s};pn.pascal=t=>t?t[0].toUpperCase()+t.slice(1):"";pn.inverse=t=>{if(!t||!t.stack)return t;let e=t.stack.find(s=>jc.keys.color.includes(s));if(e){let s=jc["bg"+pn.pascal(e)];return s?s.black:t}let r=t.stack.find(s=>s.slice(0,2)==="bg");return r?jc[r.slice(2).toLowerCase()]||t:jc.none};pn.complement=t=>{if(!t||!t.stack)return t;let e=t.stack.find(s=>jc.keys.color.includes(s)),r=t.stack.find(s=>s.slice(0,2)==="bg");if(e&&!r)return jc[kde[e]||e];if(r){let s=r.slice(2).toLowerCase(),a=kde[s];return a&&jc["bg"+pn.pascal(a)]||t}return jc.none};pn.meridiem=t=>{let e=t.getHours(),r=t.getMinutes(),s=e>=12?"pm":"am";e=e%12;let a=e===0?12:e,n=r<10?"0"+r:r;return a+":"+n+" "+s};pn.set=(t={},e="",r)=>e.split(".").reduce((s,a,n,c)=>{let f=c.length-1>n?s[a]||{}:r;return!pn.isObject(f)&&n<c.length-1&&(f={}),s[a]=f},t);pn.get=(t={},e="",r)=>{let s=t[e]==null?e.split(".").reduce((a,n)=>a&&a[n],t):t[e];return s??r};pn.mixin=(t,e)=>{if(!VT(t))return e;if(!VT(e))return t;for(let r of Object.keys(e)){let s=Object.getOwnPropertyDescriptor(e,r);if(s.hasOwnProperty("value"))if(t.hasOwnProperty(r)&&VT(s.value)){let a=Object.getOwnPropertyDescriptor(t,r);VT(a.value)?t[r]=pn.merge({},t[r],e[r]):Reflect.defineProperty(t,r,s)}else Reflect.defineProperty(t,r,s);else Reflect.defineProperty(t,r,s)}return t};pn.merge=(...t)=>{let e={};for(let r of t)pn.mixin(e,r);return e};pn.mixinEmitter=(t,e)=>{let r=e.constructor.prototype;for(let s of Object.keys(r)){let a=r[s];typeof a=="function"?pn.define(t,s,a.bind(e)):pn.define(t,s,a)}};pn.onExit=t=>{let e=(r,s)=>{xde||(xde=!0,XG.forEach(a=>a()),r===!0&&process.exit(128+s))};XG.length===0&&(process.once("SIGTERM",e.bind(null,!0,15)),process.once("SIGINT",e.bind(null,!0,2)),process.once("exit",e)),XG.push(t)};pn.define=(t,e,r)=>{Reflect.defineProperty(t,e,{value:r})};pn.defineExport=(t,e,r)=>{let s;Reflect.defineProperty(t,e,{enumerable:!0,configurable:!0,set(a){s=a},get(){return s?s():r()}})}});var Qde=_(rC=>{"use strict";rC.ctrl={a:"first",b:"backward",c:"cancel",d:"deleteForward",e:"last",f:"forward",g:"reset",i:"tab",k:"cutForward",l:"reset",n:"newItem",m:"cancel",j:"submit",p:"search",r:"remove",s:"save",u:"undo",w:"cutLeft",x:"toggleCursor",v:"paste"};rC.shift={up:"shiftUp",down:"shiftDown",left:"shiftLeft",right:"shiftRight",tab:"prev"};rC.fn={up:"pageUp",down:"pageDown",left:"pageLeft",right:"pageRight",delete:"deleteForward"};rC.option={b:"backward",f:"forward",d:"cutRight",left:"cutLeft",up:"altUp",down:"altDown"};rC.keys={pageup:"pageUp",pagedown:"pageDown",home:"home",end:"end",cancel:"cancel",delete:"deleteForward",backspace:"delete",down:"down",enter:"submit",escape:"cancel",left:"left",space:"space",number:"number",return:"submit",right:"right",tab:"next",up:"up"}});var Fde=_((_Ht,Tde)=>{"use strict";var Rde=Ie("readline"),Iat=Qde(),Cat=/^(?:\x1b)([a-zA-Z0-9])$/,wat=/^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/,Bat={OP:"f1",OQ:"f2",OR:"f3",OS:"f4","[11~":"f1","[12~":"f2","[13~":"f3","[14~":"f4","[[A":"f1","[[B":"f2","[[C":"f3","[[D":"f4","[[E":"f5","[15~":"f5","[17~":"f6","[18~":"f7","[19~":"f8","[20~":"f9","[21~":"f10","[23~":"f11","[24~":"f12","[A":"up","[B":"down","[C":"right","[D":"left","[E":"clear","[F":"end","[H":"home",OA:"up",OB:"down",OC:"right",OD:"left",OE:"clear",OF:"end",OH:"home","[1~":"home","[2~":"insert","[3~":"delete","[4~":"end","[5~":"pageup","[6~":"pagedown","[[5~":"pageup","[[6~":"pagedown","[7~":"home","[8~":"end","[a":"up","[b":"down","[c":"right","[d":"left","[e":"clear","[2$":"insert","[3$":"delete","[5$":"pageup","[6$":"pagedown","[7$":"home","[8$":"end",Oa:"up",Ob:"down",Oc:"right",Od:"left",Oe:"clear","[2^":"insert","[3^":"delete","[5^":"pageup","[6^":"pagedown","[7^":"home","[8^":"end","[Z":"tab"};function vat(t){return["[a","[b","[c","[d","[e","[2$","[3$","[5$","[6$","[7$","[8$","[Z"].includes(t)}function Sat(t){return["Oa","Ob","Oc","Od","Oe","[2^","[3^","[5^","[6^","[7^","[8^"].includes(t)}var JT=(t="",e={})=>{let r,s={name:e.name,ctrl:!1,meta:!1,shift:!1,option:!1,sequence:t,raw:t,...e};if(Buffer.isBuffer(t)?t[0]>127&&t[1]===void 0?(t[0]-=128,t="\x1B"+String(t)):t=String(t):t!==void 0&&typeof t!="string"?t=String(t):t||(t=s.sequence||""),s.sequence=s.sequence||t||s.name,t==="\r")s.raw=void 0,s.name="return";else if(t===`
`)s.name="enter";else if(t===" ")s.name="tab";else if(t==="\b"||t==="\x7F"||t==="\x1B\x7F"||t==="\x1B\b")s.name="backspace",s.meta=t.charAt(0)==="\x1B";else if(t==="\x1B"||t==="\x1B\x1B")s.name="escape",s.meta=t.length===2;else if(t===" "||t==="\x1B ")s.name="space",s.meta=t.length===2;else if(t<="")s.name=String.fromCharCode(t.charCodeAt(0)+97-1),s.ctrl=!0;else if(t.length===1&&t>="0"&&t<="9")s.name="number";else if(t.length===1&&t>="a"&&t<="z")s.name=t;else if(t.length===1&&t>="A"&&t<="Z")s.name=t.toLowerCase(),s.shift=!0;else if(r=Cat.exec(t))s.meta=!0,s.shift=/^[A-Z]$/.test(r[1]);else if(r=wat.exec(t)){let a=[...t];a[0]==="\x1B"&&a[1]==="\x1B"&&(s.option=!0);let n=[r[1],r[2],r[4],r[6]].filter(Boolean).join(""),c=(r[3]||r[5]||1)-1;s.ctrl=!!(c&4),s.meta=!!(c&10),s.shift=!!(c&1),s.code=n,s.name=Bat[n],s.shift=vat(n)||s.shift,s.ctrl=Sat(n)||s.ctrl}return s};JT.listen=(t={},e)=>{let{stdin:r}=t;if(!r||r!==process.stdin&&!r.isTTY)throw new Error("Invalid stream passed");let s=Rde.createInterface({terminal:!0,input:r});Rde.emitKeypressEvents(r,s);let a=(f,p)=>e(f,JT(f,p),s),n=r.isRaw;return r.isTTY&&r.setRawMode(!0),r.on("keypress",a),s.resume(),()=>{r.isTTY&&r.setRawMode(n),r.removeListener("keypress",a),s.pause(),s.close()}};JT.action=(t,e,r)=>{let s={...Iat,...r};return e.ctrl?(e.action=s.ctrl[e.name],e):e.option&&s.option?(e.action=s.option[e.name],e):e.shift?(e.action=s.shift[e.name],e):(e.action=s.keys[e.name],e)};Tde.exports=JT});var Ode=_((HHt,Nde)=>{"use strict";Nde.exports=t=>{t.timers=t.timers||{};let e=t.options.timers;if(e)for(let r of Object.keys(e)){let s=e[r];typeof s=="number"&&(s={interval:s}),Dat(t,r,s)}};function Dat(t,e,r={}){let s=t.timers[e]={name:e,start:Date.now(),ms:0,tick:0},a=r.interval||120;s.frames=r.frames||[],s.loading=!0;let n=setInterval(()=>{s.ms=Date.now()-s.start,s.tick++,t.render()},a);return s.stop=()=>{s.loading=!1,clearInterval(n)},Reflect.defineProperty(s,"interval",{value:n}),t.once("close",()=>s.stop()),s.stop}});var Mde=_((jHt,Lde)=>{"use strict";var{define:Pat,width:bat}=Xo(),$G=class{constructor(e){let r=e.options;Pat(this,"_prompt",e),this.type=e.type,this.name=e.name,this.message="",this.header="",this.footer="",this.error="",this.hint="",this.input="",this.cursor=0,this.index=0,this.lines=0,this.tick=0,this.prompt="",this.buffer="",this.width=bat(r.stdout||process.stdout),Object.assign(this,r),this.name=this.name||this.message,this.message=this.message||this.name,this.symbols=e.symbols,this.styles=e.styles,this.required=new Set,this.cancelled=!1,this.submitted=!1}clone(){let e={...this};return e.status=this.status,e.buffer=Buffer.from(e.buffer),delete e.clone,e}set color(e){this._color=e}get color(){let e=this.prompt.styles;if(this.cancelled)return e.cancelled;if(this.submitted)return e.submitted;let r=this._color||e[this.status];return typeof r=="function"?r:e.pending}set loading(e){this._loading=e}get loading(){return typeof this._loading=="boolean"?this._loading:this.loadingChoices?"choices":!1}get status(){return this.cancelled?"cancelled":this.submitted?"submitted":"pending"}};Lde.exports=$G});var _de=_((GHt,Ude)=>{"use strict";var eq=Xo(),ho=Ju(),tq={default:ho.noop,noop:ho.noop,set inverse(t){this._inverse=t},get inverse(){return this._inverse||eq.inverse(this.primary)},set complement(t){this._complement=t},get complement(){return this._complement||eq.complement(this.primary)},primary:ho.cyan,success:ho.green,danger:ho.magenta,strong:ho.bold,warning:ho.yellow,muted:ho.dim,disabled:ho.gray,dark:ho.dim.gray,underline:ho.underline,set info(t){this._info=t},get info(){return this._info||this.primary},set em(t){this._em=t},get em(){return this._em||this.primary.underline},set heading(t){this._heading=t},get heading(){return this._heading||this.muted.underline},set pending(t){this._pending=t},get pending(){return this._pending||this.primary},set submitted(t){this._submitted=t},get submitted(){return this._submitted||this.success},set cancelled(t){this._cancelled=t},get cancelled(){return this._cancelled||this.danger},set typing(t){this._typing=t},get typing(){return this._typing||this.dim},set placeholder(t){this._placeholder=t},get placeholder(){return this._placeholder||this.primary.dim},set highlight(t){this._highlight=t},get highlight(){return this._highlight||this.inverse}};tq.merge=(t={})=>{t.styles&&typeof t.styles.enabled=="boolean"&&(ho.enabled=t.styles.enabled),t.styles&&typeof t.styles.visible=="boolean"&&(ho.visible=t.styles.visible);let e=eq.merge({},tq,t.styles);delete e.merge;for(let r of Object.keys(ho))e.hasOwnProperty(r)||Reflect.defineProperty(e,r,{get:()=>ho[r]});for(let r of Object.keys(ho.styles))e.hasOwnProperty(r)||Reflect.defineProperty(e,r,{get:()=>ho[r]});return e};Ude.exports=tq});var jde=_((qHt,Hde)=>{"use strict";var rq=process.platform==="win32",zp=Ju(),xat=Xo(),nq={...zp.symbols,upDownDoubleArrow:"\u21D5",upDownDoubleArrow2:"\u2B0D",upDownArrow:"\u2195",asterisk:"*",asterism:"\u2042",bulletWhite:"\u25E6",electricArrow:"\u2301", Line truncated
`),h=p[0],E=p[p.length-1],S=(s+(r?" "+r:"")).length,b=S<h.length?h.slice(S+1):"";return{header:c,prompt:h,after:b,rest:p.slice(1),last:E}}async submit(){this.state.submitted=!0,this.state.validating=!0,this.options.onSubmit&&await this.options.onSubmit.call(this,this.name,this.value,this);let e=this.state.error||await this.validate(this.value,this.state);if(e!==!0){let r=`
`+this.symbols.pointer+" ";typeof e=="string"?r+=e.trim():r+="Invalid input",this.state.error=`
`+this.styles.danger(r),this.state.submitted=!1,await this.render(),await this.alert(),this.state.validating=!1,this.state.error=void 0;return}this.state.validating=!1,await this.render(),await this.close(),this.value=await this.result(this.value),this.emit("submit",this.value)}async cancel(e){this.state.cancelled=this.state.submitted=!0,await this.render(),await this.close(),typeof this.options.onCancel=="function"&&await this.options.onCancel.call(this,this.name,this.value,this),this.emit("cancel",await this.error(e))}async close(){this.state.closed=!0;try{let e=this.sections(),r=Math.ceil(e.prompt.length/this.width);e.rest&&this.write(Bm.cursor.down(e.rest.length)),this.write(`
`.repeat(r))}catch{}this.emit("close")}start(){!this.stop&&this.options.show!==!1&&(this.stop=aq.listen(this,this.keypress.bind(this)),this.once("close",this.stop))}async skip(){return this.skipped=this.options.skip===!0,typeof this.options.skip=="function"&&(this.skipped=await this.options.skip.call(this,this.name,this.value)),this.skipped}async initialize(){let{format:e,options:r,result:s}=this;if(this.format=()=>e.call(this,this.value),this.result=()=>s.call(this,this.value),typeof r.initial=="function"&&(this.initial=await r.initial.call(this,this)),typeof r.onRun=="function"&&await r.onRun.call(this,this),typeof r.onSubmit=="function"){let a=r.onSubmit.bind(this),n=this.submit.bind(this);delete this.options.onSubmit,this.submit=async()=>(await a(this.name,this.value,this),n())}await this.start(),await this.render()}render(){throw new Error("expected prompt to have a custom render method")}run(){return new Promise(async(e,r)=>{if(this.once("submit",e),this.once("cancel",r),await this.skip())return this.render=()=>{},this.submit();await this.initialize(),this.emit("run")})}async element(e,r,s){let{options:a,state:n,symbols:c,timers:f}=this,p=f&&f[e];n.timer=p;let h=a[e]||n[e]||c[e],E=r&&r[e]!=null?r[e]:await h;if(E==="")return E;let C=await this.resolve(E,n,r,s);return!C&&r&&r[e]?this.resolve(h,n,r,s):C}async prefix(){let e=await this.element("prefix")||this.symbols,r=this.timers&&this.timers.prefix,s=this.state;return s.timer=r,pl.isObject(e)&&(e=e[s.status]||e.pending),pl.hasColor(e)?e:(this.styles[s.status]||this.styles.pending)(e)}async message(){let e=await this.element("message");return pl.hasColor(e)?e:this.styles.strong(e)}async separator(){let e=await this.element("separator")||this.symbols,r=this.timers&&this.timers.separator,s=this.state;s.timer=r;let a=e[s.status]||e.pending||s.separator,n=await this.resolve(a,s);return pl.isObject(n)&&(n=n[s.status]||n.pending),pl.hasColor(n)?n:this.styles.muted(n)}async pointer(e,r){let s=await this.element("pointer",e,r);if(typeof s=="string"&&pl.hasColor(s))return s;if(s){let a=this.styles,n=this.index===r,c=n?a.primary:h=>h,f=await this.resolve(s[n?"on":"off"]||s,this.state),p=pl.hasColor(f)?f:c(f);return n?p:" ".repeat(f.length)}}async indicator(e,r){let s=await this.element("indicator",e,r);if(typeof s=="string"&&pl.hasColor(s))return s;if(s){let a=this.styles,n=e.enabled===!0,c=n?a.success:a.dark,f=s[n?"on":"off"]||s;return pl.hasColor(f)?f:c(f)}return""}body(){return null}footer(){if(this.state.status==="pending")return this.element("footer")}header(){if(this.state.status==="pending")return this.element("header")}async hint(){if(this.state.status==="pending"&&!this.isValue(this.state.input)){let e=await this.element("hint");return pl.hasColor(e)?e:this.styles.muted(e)}}error(e){return this.state.submitted?"":e||this.state.error}format(e){return e}result(e){return e}validate(e){return this.options.required===!0?this.isValue(e):!0}isValue(e){return e!=null&&e!==""}resolve(e,...r){return pl.resolve(this,e,...r)}get base(){return t.prototype}get style(){return this.styles[this.state.status]}get height(){return this.options.rows||pl.height(this.stdout,25)}get width(){return this.options.columns||pl.width(this.stdout,80)}get size(){return{width:this.width,height:this.height}}set cursor(e){this.state.cursor=e}get cursor(){return this.state.cursor}set input(e){this.state.input=e}get input(){return this.state.input}set value(e){this.state.value=e}get value(){let{input:e,value:r}=this.state,s=[r,e].find(this.isValue.bind(this));return this.isValue(s)?s:this.initial}static get prompt(){return e=>new this(e).run()}};function Mat(t){let e=a=>t[a]===void 0||typeof t[a]=="function",r=["actions","choices","initial","margin","roles","styles","symbols","theme","timers","value"],s=["body","footer","error","header","hint","indicator","message","prefix","separator","skip"];for(let a of Object.keys(t.options)){if(r.includes(a)||/^on[A-Z]/.test(a))continue;let n=t.options[a];typeof n=="function"&&e(a)?s.includes(a)||(t[a]=n.bind(t)):typeof t[a]!="function"&&(t[a]=n)}}function Uat(t){typeof t=="number"&&(t=[t,t,t,t]);let e=[].concat(t||[]),r=a=>a%2===0?`
`:" ",s=[];for(let a=0;a<4;a++){let n=r(a);e[a]?s.push(n.repeat(e[a])):s.push("")}return s}Zde.exports=lq});var eme=_((VHt,$de)=>{"use strict";var _at=Xo(),Xde={default(t,e){return e},checkbox(t,e){throw new Error("checkbox role is not implemented yet")},editable(t,e){throw new Error("editable role is not implemented yet")},expandable(t,e){throw new Error("expandable role is not implemented yet")},heading(t,e){return e.disabled="",e.indicator=[e.indicator," "].find(r=>r!=null),e.message=e.message||"",e},input(t,e){throw new Error("input role is not implemented yet")},option(t,e){return Xde.default(t,e)},radio(t,e){throw new Error("radio role is not implemented yet")},separator(t,e){return e.disabled="",e.indicator=[e.indicator," "].find(r=>r!=null),e.message=e.message||t.symbols.line.repeat(5),e},spacer(t,e){return e}};$de.exports=(t,e={})=>{let r=_at.merge({},Xde,e.roles);return r[t]||r.default}});var Wv=_((JHt,nme)=>{"use strict";var Hat=Ju(),jat=nC(),Gat=eme(),KT=Xo(),{reorder:cq,scrollUp:qat,scrollDown:Wat,isObject:tme,swap:Yat}=KT,uq=class extends jat{constructor(e){super(e),this.cursorHide(),this.maxSelected=e.maxSelected||1/0,this.multiple=e.multiple||!1,this.initial=e.initial||0,this.delay=e.delay||0,this.longest=0,this.num=""}async initialize(){typeof this.options.initial=="function"&&(this.initial=await this.options.initial.call(this)),await this.reset(!0),await super.initialize()}async reset(){let{choices:e,initial:r,autofocus:s,suggest:a}=this.options;if(this.state._choices=[],this.state.choices=[],this.choices=await Promise.all(await this.toChoices(e)),this.choices.forEach(n=>n.enabled=!1),typeof a!="function"&&this.selectable.length===0)throw new Error("At least one choice must be selectable");tme(r)&&(r=Object.keys(r)),Array.isArray(r)?(s!=null&&(this.index=this.findIndex(s)),r.forEach(n=>this.enable(this.find(n))),await this.render()):(s!=null&&(r=s),typeof r=="string"&&(r=this.findIndex(r)),typeof r=="number"&&r>-1&&(this.index=Math.max(0,Math.min(r,this.choices.length)),this.enable(this.find(this.index)))),this.isDisabled(this.focused)&&await this.down()}async toChoices(e,r){this.state.loadingChoices=!0;let s=[],a=0,n=async(c,f)=>{typeof c=="function"&&(c=await c.call(this)),c instanceof Promise&&(c=await c);for(let p=0;p<c.length;p++){let h=c[p]=await this.toChoice(c[p],a++,f);s.push(h),h.choices&&await n(h.choices,h)}return s};return n(e,r).then(c=>(this.state.loadingChoices=!1,c))}async toChoice(e,r,s){if(typeof e=="function"&&(e=await e.call(this,this)),e instanceof Promise&&(e=await e),typeof e=="string"&&(e={name:e}),e.normalized)return e;e.normalized=!0;let a=e.value;if(e=Gat(e.role,this.options)(this,e),typeof e.disabled=="string"&&!e.hint&&(e.hint=e.disabled,e.disabled=!0),e.disabled===!0&&e.hint==null&&(e.hint="(disabled)"),e.index!=null)return e;e.name=e.name||e.key||e.title||e.value||e.message,e.message=e.message||e.name||"",e.value=[e.value,e.name].find(this.isValue.bind(this)),e.input="",e.index=r,e.cursor=0,KT.define(e,"parent",s),e.level=s?s.level+1:1,e.indent==null&&(e.indent=s?s.indent+" ":e.indent||""),e.path=s?s.path+"."+e.name:e.name,e.enabled=!!(this.multiple&&!this.isDisabled(e)&&(e.enabled||this.isSelected(e))),this.isDisabled(e)||(this.longest=Math.max(this.longest,Hat.unstyle(e.message).length));let c={...e};return e.reset=(f=c.input,p=c.value)=>{for(let h of Object.keys(c))e[h]=c[h];e.input=f,e.value=p},a==null&&typeof e.initial=="function"&&(e.input=await e.initial.call(this,this.state,e,r)),e}async onChoice(e,r){this.emit("choice",e,r,this),typeof e.onChoice=="function"&&await e.onChoice.call(this,this.state,e,r)}async addChoice(e,r,s){let a=await this.toChoice(e,r,s);return this.choices.push(a),this.index=this.choices.length-1,this.limit=this.choices.length,a}async newItem(e,r,s){let a={name:"New choice name?",editable:!0,newChoice:!0,...e},n=await this.addChoice(a,r,s);return n.updateChoice=()=>{delete n.newChoice,n.name=n.message=n.input,n.input="",n.cursor=0},this.render()}indent(e){return e.indent==null?e.level>1?" ".repeat(e.level-1):"":e.indent}dispatch(e,r){if(this.multiple&&this[r.name])return this[r.name]();this.alert()}focus(e,r){return typeof r!="boolean"&&(r=e.enabled),r&&!e.enabled&&this.selected.length>=this.maxSelected?this.alert():(this.index=e.index,e.enabled=r&&!this.isDisabled(e),e)}space(){return this.multiple?(this.toggle(this.focused),this.render()):this.alert()}a(){if(this.maxSelected<this.choices.length)return this.alert();let e=this.selectable.every(r=>r.enabled);return this.choices.forEach(r=>r.enabled=!e),this.render()}i(){return this.choices.length-this.selected.length>this.maxSelected?this.alert():(this.choices.forEach(e=>e.enabled=!e.enabled),this.render())}g(e=this.focused){return this.choices.some(r=>!!r.parent)?(this.toggle(e.parent&&!e.choices?e.parent:e),this.render()):this.a()}toggle(e,r){if(!e.enabled&&this.selected.length>=this.maxSelected)return this.alert();typeof r!="boolean"&&(r=!e.enabled),e.enabled=r,e.choices&&e. Line truncated
`),a;return this.options.choicesHeader&&(a=await this.resolve(this.options.choicesHeader,this.state)),[a,s].filter(Boolean).join(`
`)}format(){return!this.state.submitted||this.state.cancelled?"":Array.isArray(this.selected)?this.selected.map(e=>this.styles.primary(e.name)).join(", "):this.styles.primary(this.selected.name)}async render(){let{submitted:e,size:r}=this.state,s="",a=await this.header(),n=await this.prefix(),c=await this.separator(),f=await this.message();this.options.promptLine!==!1&&(s=[n,f,c,""].join(" "),this.state.prompt=s);let p=await this.format(),h=await this.error()||await this.hint(),E=await this.renderChoices(),C=await this.footer();p&&(s+=p),h&&!s.includes(h)&&(s+=" "+h),e&&!p&&!E.trim()&&this.multiple&&this.emptyError!=null&&(s+=this.styles.danger(this.emptyError)),this.clear(r),this.write([a,s,E,C].filter(Boolean).join(`
`)),this.write(this.margin[2]),this.restore()}};ime.exports=Aq});var ome=_((zHt,sme)=>{"use strict";var Jat=G0(),Kat=(t,e)=>{let r=t.toLowerCase();return s=>{let n=s.toLowerCase().indexOf(r),c=e(s.slice(n,n+r.length));return n>=0?s.slice(0,n)+c+s.slice(n+r.length):s}},pq=class extends Jat{constructor(e){super(e),this.cursorShow()}moveCursor(e){this.state.cursor+=e}dispatch(e){return this.append(e)}space(e){return this.options.multiple?super.space(e):this.append(e)}append(e){let{cursor:r,input:s}=this.state;return this.input=s.slice(0,r)+e+s.slice(r),this.moveCursor(1),this.complete()}delete(){let{cursor:e,input:r}=this.state;return r?(this.input=r.slice(0,e-1)+r.slice(e),this.moveCursor(-1),this.complete()):this.alert()}deleteForward(){let{cursor:e,input:r}=this.state;return r[e]===void 0?this.alert():(this.input=`${r}`.slice(0,e)+`${r}`.slice(e+1),this.complete())}number(e){return this.append(e)}async complete(){this.completing=!0,this.choices=await this.suggest(this.input,this.state._choices),this.state.limit=void 0,this.index=Math.min(Math.max(this.visible.length-1,0),this.index),await this.render(),this.completing=!1}suggest(e=this.input,r=this.state._choices){if(typeof this.options.suggest=="function")return this.options.suggest.call(this,e,r);let s=e.toLowerCase();return r.filter(a=>a.message.toLowerCase().includes(s))}pointer(){return""}format(){if(!this.focused)return this.input;if(this.options.multiple&&this.state.submitted)return this.selected.map(e=>this.styles.primary(e.message)).join(", ");if(this.state.submitted){let e=this.value=this.input=this.focused.value;return this.styles.primary(e)}return this.input}async render(){if(this.state.status!=="pending")return super.render();let e=this.options.highlight?this.options.highlight.bind(this):this.styles.placeholder,r=Kat(this.input,e),s=this.choices;this.choices=s.map(a=>({...a,message:r(a.message)})),await super.render(),this.choices=s}submit(){return this.options.multiple&&(this.value=this.selected.map(e=>e.name)),super.submit()}};sme.exports=pq});var gq=_((ZHt,ame)=>{"use strict";var hq=Xo();ame.exports=(t,e={})=>{t.cursorHide();let{input:r="",initial:s="",pos:a,showCursor:n=!0,color:c}=e,f=c||t.styles.placeholder,p=hq.inverse(t.styles.primary),h=T=>p(t.styles.black(T)),E=r,C=" ",S=h(C);if(t.blink&&t.blink.off===!0&&(h=T=>T,S=""),n&&a===0&&s===""&&r==="")return h(C);if(n&&a===0&&(r===s||r===""))return h(s[0])+f(s.slice(1));s=hq.isPrimitive(s)?`${s}`:"",r=hq.isPrimitive(r)?`${r}`:"";let b=s&&s.startsWith(r)&&s!==r,I=b?h(s[r.length]):S;if(a!==r.length&&n===!0&&(E=r.slice(0,a)+h(r[a])+r.slice(a+1),I=""),n===!1&&(I=""),b){let T=t.styles.unstyle(E+I);return E+I+f(s.slice(T.length))}return E+I}});var zT=_((XHt,lme)=>{"use strict";var zat=Ju(),Zat=G0(),Xat=gq(),dq=class extends Zat{constructor(e){super({...e,multiple:!0}),this.type="form",this.initial=this.options.initial,this.align=[this.options.align,"right"].find(r=>r!=null),this.emptyError="",this.values={}}async reset(e){return await super.reset(),e===!0&&(this._index=this.index),this.index=this._index,this.values={},this.choices.forEach(r=>r.reset&&r.reset()),this.render()}dispatch(e){return!!e&&this.append(e)}append(e){let r=this.focused;if(!r)return this.alert();let{cursor:s,input:a}=r;return r.value=r.input=a.slice(0,s)+e+a.slice(s),r.cursor++,this.render()}delete(){let e=this.focused;if(!e||e.cursor<=0)return this.alert();let{cursor:r,input:s}=e;return e.value=e.input=s.slice(0,r-1)+s.slice(r),e.cursor--,this.render()}deleteForward(){let e=this.focused;if(!e)return this.alert();let{cursor:r,input:s}=e;if(s[r]===void 0)return this.alert();let a=`${s}`.slice(0,r)+`${s}`.slice(r+1);return e.value=e.input=a,this.render()}right(){let e=this.focused;return e?e.cursor>=e.input.length?this.alert():(e.cursor++,this.render()):this.alert()}left(){let e=this.focused;return e?e.cursor<=0?this.alert():(e.cursor--,this.render()):this.alert()}space(e,r){return this.dispatch(e,r)}number(e,r){return this.dispatch(e,r)}next(){let e=this.focused;if(!e)return this.alert();let{initial:r,input:s}=e;return r&&r.startsWith(s)&&s!==r?(e.value=e.input=r,e.cursor=e.value.length,this.render()):super.next()}prev(){let e=this.focused;return e?e.cursor===0?super.prev():(e.value=e.input="",e.cursor=0,this.render()):this.alert()}separator(){return""}format(e){return this.state.submitted?"":super.format(e)}pointer(){return""}indicator(e){return e.input?"\u29BF":"\u2299"}async choiceSeparator(e,r){let s=await this.resolve(e.separator,this.state,e,r)||":";return s?" "+this.styles.disabled(s):""}async renderChoice(e,r){await this.onChoice(e,r);let{state:s,styles:a}=this,{cursor:n,initial:c="",name:f,hint:p,input:h=""}=e,{muted:E,submitted:C,primary:S,danger:b}=a,I=p,T=this.index===r,N=e.validate||(()=>!0),U=await this.choiceSeparator(e,r),W=e.message;this.align==="right"&&(W=W.padStart(this.longest+1," ")),this.align==="left"&&(W=W.padEnd(this.longest+1," "));let ee=this.values[f]=h||c,ie=h?"success":"dark";await N.call(e,ee,thi Line truncated
`)),this.restore()}set value(e){super.value=e}get value(){return this.cast(super.value)}};hme.exports=yq});var dme=_((rjt,gme)=>{"use strict";var olt=ZT(),Eq=class extends olt{constructor(e){super(e),this.default=this.options.default||(this.initial?"(Y/n)":"(y/N)")}};gme.exports=Eq});var yme=_((njt,mme)=>{"use strict";var alt=G0(),llt=zT(),iC=llt.prototype,Iq=class extends alt{constructor(e){super({...e,multiple:!0}),this.align=[this.options.align,"left"].find(r=>r!=null),this.emptyError="",this.values={}}dispatch(e,r){let s=this.focused,a=s.parent||{};return!s.editable&&!a.editable&&(e==="a"||e==="i")?super[e]():iC.dispatch.call(this,e,r)}append(e,r){return iC.append.call(this,e,r)}delete(e,r){return iC.delete.call(this,e,r)}space(e){return this.focused.editable?this.append(e):super.space()}number(e){return this.focused.editable?this.append(e):super.number(e)}next(){return this.focused.editable?iC.next.call(this):super.next()}prev(){return this.focused.editable?iC.prev.call(this):super.prev()}async indicator(e,r){let s=e.indicator||"",a=e.editable?s:super.indicator(e,r);return await this.resolve(a,this.state,e,r)||""}indent(e){return e.role==="heading"?"":e.editable?" ":" "}async renderChoice(e,r){return e.indent="",e.editable?iC.renderChoice.call(this,e,r):super.renderChoice(e,r)}error(){return""}footer(){return this.state.error}async validate(){let e=!0;for(let r of this.choices){if(typeof r.validate!="function"||r.role==="heading")continue;let s=r.parent?this.value[r.parent.name]:this.value;if(r.editable?s=r.value===r.name?r.initial||"":r.value:this.isDisabled(r)||(s=r.enabled===!0),e=await r.validate(s,this.state),e!==!0)break}return e!==!0&&(this.state.error=typeof e=="string"?e:"Invalid Input"),e}submit(){if(this.focused.newChoice===!0)return super.submit();if(this.choices.some(e=>e.newChoice))return this.alert();this.value={};for(let e of this.choices){let r=e.parent?this.value[e.parent.name]:this.value;if(e.role==="heading"){this.value[e.name]={};continue}e.editable?r[e.name]=e.value===e.name?e.initial||"":e.value:this.isDisabled(e)||(r[e.name]=e.enabled===!0)}return this.base.submit.call(this)}};mme.exports=Iq});var vm=_((ijt,Eme)=>{"use strict";var clt=nC(),ult=gq(),{isPrimitive:flt}=Xo(),Cq=class extends clt{constructor(e){super(e),this.initial=flt(this.initial)?String(this.initial):"",this.initial&&this.cursorHide(),this.state.prevCursor=0,this.state.clipboard=[]}async keypress(e,r={}){let s=this.state.prevKeypress;return this.state.prevKeypress=r,this.options.multiline===!0&&r.name==="return"&&(!s||s.name!=="return")?this.append(`
`,r):super.keypress(e,r)}moveCursor(e){this.cursor+=e}reset(){return this.input=this.value="",this.cursor=0,this.render()}dispatch(e,r){if(!e||r.ctrl||r.code)return this.alert();this.append(e)}append(e){let{cursor:r,input:s}=this.state;this.input=`${s}`.slice(0,r)+e+`${s}`.slice(r),this.moveCursor(String(e).length),this.render()}insert(e){this.append(e)}delete(){let{cursor:e,input:r}=this.state;if(e<=0)return this.alert();this.input=`${r}`.slice(0,e-1)+`${r}`.slice(e),this.moveCursor(-1),this.render()}deleteForward(){let{cursor:e,input:r}=this.state;if(r[e]===void 0)return this.alert();this.input=`${r}`.slice(0,e)+`${r}`.slice(e+1),this.render()}cutForward(){let e=this.cursor;if(this.input.length<=e)return this.alert();this.state.clipboard.push(this.input.slice(e)),this.input=this.input.slice(0,e),this.render()}cutLeft(){let e=this.cursor;if(e===0)return this.alert();let r=this.input.slice(0,e),s=this.input.slice(e),a=r.split(" ");this.state.clipboard.push(a.pop()),this.input=a.join(" "),this.cursor=this.input.length,this.input+=s,this.render()}paste(){if(!this.state.clipboard.length)return this.alert();this.insert(this.state.clipboard.pop()),this.render()}toggleCursor(){this.state.prevCursor?(this.cursor=this.state.prevCursor,this.state.prevCursor=0):(this.state.prevCursor=this.cursor,this.cursor=0),this.render()}first(){this.cursor=0,this.render()}last(){this.cursor=this.input.length-1,this.render()}next(){let e=this.initial!=null?String(this.initial):"";if(!e||!e.startsWith(this.input))return this.alert();this.input=this.initial,this.cursor=this.initial.length,this.render()}prev(){if(!this.input)return this.alert();this.reset()}backward(){return this.left()}forward(){return this.right()}right(){return this.cursor>=this.input.length?this.alert():(this.moveCursor(1),this.render())}left(){return this.cursor<=0?this.alert():(this.moveCursor(-1),this.render())}isValue(e){return!!e}async format(e=this.value){let r=await this.resolve(this.initial,this.state);return this.state.submitted?this.styles.submitted(e||r):ult(this,{input:e,initial:r,pos:this.cursor})}async render(){let e=this.state.size,r=await this.prefix(),s=await this.separator(),a=await this.message(),n=[r,a,s].filter(Boolean).join(" ");this.state.prompt=n;let c=await this.header(),f=await this.format(),p=await this.error()||await this.hint(),h=await this.footer();p&&!f.includes(p)&&(f+=" "+p),n+=" "+f,this.clear(e),this.write([c,n,h].filter(Boolean).join(`
`)),this.restore()}};Eme.exports=Cq});var Cme=_((sjt,Ime)=>{"use strict";var Alt=t=>t.filter((e,r)=>t.lastIndexOf(e)===r),XT=t=>Alt(t).filter(Boolean);Ime.exports=(t,e={},r="")=>{let{past:s=[],present:a=""}=e,n,c;switch(t){case"prev":case"undo":return n=s.slice(0,s.length-1),c=s[s.length-1]||"",{past:XT([r,...n]),present:c};case"next":case"redo":return n=s.slice(1),c=s[0]||"",{past:XT([...n,r]),present:c};case"save":return{past:XT([...s,r]),present:""};case"remove":return c=XT(s.filter(f=>f!==r)),a="",c.length&&(a=c.pop()),{past:c,present:a};default:throw new Error(`Invalid action: "${t}"`)}}});var Bq=_((ojt,Bme)=>{"use strict";var plt=vm(),wme=Cme(),wq=class extends plt{constructor(e){super(e);let r=this.options.history;if(r&&r.store){let s=r.values||this.initial;this.autosave=!!r.autosave,this.store=r.store,this.data=this.store.get("values")||{past:[],present:s},this.initial=this.data.present||this.data.past[this.data.past.length-1]}}completion(e){return this.store?(this.data=wme(e,this.data,this.input),this.data.present?(this.input=this.data.present,this.cursor=this.input.length,this.render()):this.alert()):this.alert()}altUp(){return this.completion("prev")}altDown(){return this.completion("next")}prev(){return this.save(),super.prev()}save(){this.store&&(this.data=wme("save",this.data,this.input),this.store.set("values",this.data))}submit(){return this.store&&this.autosave===!0&&this.save(),super.submit()}};Bme.exports=wq});var Sme=_((ajt,vme)=>{"use strict";var hlt=vm(),vq=class extends hlt{format(){return""}};vme.exports=vq});var Pme=_((ljt,Dme)=>{"use strict";var glt=vm(),Sq=class extends glt{constructor(e={}){super(e),this.sep=this.options.separator||/, */,this.initial=e.initial||""}split(e=this.value){return e?String(e).split(this.sep):[]}format(){let e=this.state.submitted?this.styles.primary:r=>r;return this.list.map(e).join(", ")}async submit(e){let r=this.state.error||await this.validate(this.list,this.state);return r!==!0?(this.state.error=r,super.submit()):(this.value=this.list,super.submit())}get list(){return this.split()}};Dme.exports=Sq});var xme=_((cjt,bme)=>{"use strict";var dlt=G0(),Dq=class extends dlt{constructor(e){super({...e,multiple:!0})}};bme.exports=Dq});var bq=_((ujt,kme)=>{"use strict";var mlt=vm(),Pq=class extends mlt{constructor(e={}){super({style:"number",...e}),this.min=this.isValue(e.min)?this.toNumber(e.min):-1/0,this.max=this.isValue(e.max)?this.toNumber(e.max):1/0,this.delay=e.delay!=null?e.delay:1e3,this.float=e.float!==!1,this.round=e.round===!0||e.float===!1,this.major=e.major||10,this.minor=e.minor||1,this.initial=e.initial!=null?e.initial:"",this.input=String(this.initial),this.cursor=this.input.length,this.cursorShow()}append(e){return!/[-+.]/.test(e)||e==="."&&this.input.includes(".")?this.alert("invalid number"):super.append(e)}number(e){return super.append(e)}next(){return this.input&&this.input!==this.initial?this.alert():this.isValue(this.initial)?(this.input=this.initial,this.cursor=String(this.initial).length,this.render()):this.alert()}up(e){let r=e||this.minor,s=this.toNumber(this.input);return s>this.max+r?this.alert():(this.input=`${s+r}`,this.render())}down(e){let r=e||this.minor,s=this.toNumber(this.input);return s<this.min-r?this.alert():(this.input=`${s-r}`,this.render())}shiftDown(){return this.down(this.major)}shiftUp(){return this.up(this.major)}format(e=this.input){return typeof this.options.format=="function"?this.options.format.call(this,e):this.styles.info(e)}toNumber(e=""){return this.float?+e:Math.round(+e)}isValue(e){return/^[-+]?[0-9]+((\.)|(\.[0-9]+))?$/.test(e)}submit(){let e=[this.input,this.initial].find(r=>this.isValue(r));return this.value=this.toNumber(e||0),super.submit()}};kme.exports=Pq});var Rme=_((fjt,Qme)=>{Qme.exports=bq()});var Fme=_((Ajt,Tme)=>{"use strict";var ylt=vm(),xq=class extends ylt{constructor(e){super(e),this.cursorShow()}format(e=this.input){return this.keypressed?(this.state.submitted?this.styles.primary:this.styles.muted)(this.symbols.asterisk.repeat(e.length)):""}};Tme.exports=xq});var Lme=_((pjt,Ome)=>{"use strict";var Elt=Ju(),Ilt=Wv(),Nme=Xo(),kq=class extends Ilt{constructor(e={}){super(e),this.widths=[].concat(e.messageWidth||50),this.align=[].concat(e.align||"left"),this.linebreak=e.linebreak||!1,this.edgeLength=e.edgeLength||3,this.newline=e.newline||`
`;let r=e.startNumber||1;typeof this.scale=="number"&&(this.scaleKey=!1,this.scale=Array(this.scale).fill(0).map((s,a)=>({name:a+r})))}async reset(){return this.tableized=!1,await super.reset(),this.render()}tableize(){if(this.tableized===!0)return;this.tableized=!0;let e=0;for(let r of this.choices){e=Math.max(e,r.message.length),r.scaleIndex=r.initial||2,r.scale=[];for(let s=0;s<this.scale.length;s++)r.scale.push({index:s})}this.widths[0]=Math.min(this.widths[0],e+3)}async dispatch(e,r){if(this.multiple)return this[r.name]?await this[r.name](e,r):await super.dispatch(e,r);this.alert()}heading(e,r,s){return this.styles.strong(e)}separator(){return this.styles.muted(this.symbols.ellipsis)}right(){let e=this.focused;return e.scaleIndex>=this.scale.length-1?this.alert():(e.scaleIndex++,this.render())}left(){let e=this.focused;return e.scaleIndex<=0?this.alert():(e.scaleIndex--,this.render())}indent(){return""}format(){return this.state.submitted?this.choices.map(r=>this.styles.info(r.index)).join(", "):""}pointer(){return""}renderScaleKey(){return this.scaleKey===!1||this.state.submitted?"":["",...this.scale.map(s=>` ${s.name} - ${s.message}`)].map(s=>this.styles.muted(s)).join(`
`)}renderScaleHeading(e){let r=this.scale.map(p=>p.name);typeof this.options.renderScaleHeading=="function"&&(r=this.options.renderScaleHeading.call(this,e));let s=this.scaleLength-r.join("").length,a=Math.round(s/(r.length-1)),c=r.map(p=>this.styles.strong(p)).join(" ".repeat(a)),f=" ".repeat(this.widths[0]);return this.margin[3]+f+this.margin[1]+c}scaleIndicator(e,r,s){if(typeof this.options.scaleIndicator=="function")return this.options.scaleIndicator.call(this,e,r,s);let a=e.scaleIndex===r.index;return r.disabled?this.styles.hint(this.symbols.radio.disabled):a?this.styles.success(this.symbols.radio.on):this.symbols.radio.off}renderScale(e,r){let s=e.scale.map(n=>this.scaleIndicator(e,n,r)),a=this.term==="Hyper"?"":" ";return s.join(a+this.symbols.line.repeat(this.edgeLength))}async renderChoice(e,r){await this.onChoice(e,r);let s=this.index===r,a=await this.pointer(e,r),n=await e.hint;n&&!Nme.hasColor(n)&&(n=this.styles.muted(n));let c=I=>this.margin[3]+I.replace(/\s+$/,"").padEnd(this.widths[0]," "),f=this.newline,p=this.indent(e),h=await this.resolve(e.message,this.state,e,r),E=await this.renderScale(e,r),C=this.margin[1]+this.margin[3];this.scaleLength=Elt.unstyle(E).length,this.widths[0]=Math.min(this.widths[0],this.width-this.scaleLength-C.length);let b=Nme.wordWrap(h,{width:this.widths[0],newline:f}).split(`
`).map(I=>c(I)+this.margin[1]);return s&&(E=this.styles.info(E),b=b.map(I=>this.styles.info(I))),b[0]+=E,this.linebreak&&b.push(""),[p+a,b.join(`
`)].filter(Boolean)}async renderChoices(){if(this.state.submitted)return"";this.tableize();let e=this.visible.map(async(a,n)=>await this.renderChoice(a,n)),r=await Promise.all(e),s=await this.renderScaleHeading();return this.margin[0]+[s,...r.map(a=>a.join(" "))].join(`
`)}async render(){let{submitted:e,size:r}=this.state,s=await this.prefix(),a=await this.separator(),n=await this.message(),c="";this.options.promptLine!==!1&&(c=[s,n,a,""].join(" "),this.state.prompt=c);let f=await this.header(),p=await this.format(),h=await this.renderScaleKey(),E=await this.error()||await this.hint(),C=await this.renderChoices(),S=await this.footer(),b=this.emptyError;p&&(c+=p),E&&!c.includes(E)&&(c+=" "+E),e&&!p&&!C.trim()&&this.multiple&&b!=null&&(c+=this.styles.danger(b)),this.clear(r),this.write([f,c,h,C,S].filter(Boolean).join(`
`)),this.state.submitted||this.write(this.margin[2]),this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIndex;return this.base.submit.call(this)}};Ome.exports=kq});var _me=_((hjt,Ume)=>{"use strict";var Mme=Ju(),Clt=(t="")=>typeof t=="string"?t.replace(/^['"]|['"]$/g,""):"",Rq=class{constructor(e){this.name=e.key,this.field=e.field||{},this.value=Clt(e.initial||this.field.initial||""),this.message=e.message||this.name,this.cursor=0,this.input="",this.lines=[]}},wlt=async(t={},e={},r=s=>s)=>{let s=new Set,a=t.fields||[],n=t.template,c=[],f=[],p=[],h=1;typeof n=="function"&&(n=await n());let E=-1,C=()=>n[++E],S=()=>n[E+1],b=I=>{I.line=h,c.push(I)};for(b({type:"bos",value:""});E<n.length-1;){let I=C();if(/^[^\S\n ]$/.test(I)){b({type:"text",value:I});continue}if(I===`
`){b({type:"newline",value:I}),h++;continue}if(I==="\\"){I+=C(),b({type:"text",value:I});continue}if((I==="$"||I==="#"||I==="{")&&S()==="{"){let N=C();I+=N;let U={type:"template",open:I,inner:"",close:"",value:I},W;for(;W=C();){if(W==="}"){S()==="}"&&(W+=C()),U.value+=W,U.close=W;break}W===":"?(U.initial="",U.key=U.inner):U.initial!==void 0&&(U.initial+=W),U.value+=W,U.inner+=W}U.template=U.open+(U.initial||U.inner)+U.close,U.key=U.key||U.inner,e.hasOwnProperty(U.key)&&(U.initial=e[U.key]),U=r(U),b(U),p.push(U.key),s.add(U.key);let ee=f.find(ie=>ie.name===U.key);U.field=a.find(ie=>ie.name===U.key),ee||(ee=new Rq(U),f.push(ee)),ee.lines.push(U.line-1);continue}let T=c[c.length-1];T.type==="text"&&T.line===h?T.value+=I:b({type:"text",value:I})}return b({type:"eos",value:""}),{input:n,tabstops:c,unique:s,keys:p,items:f}};Ume.exports=async t=>{let e=t.options,r=new Set(e.required===!0?[]:e.required||[]),s={...e.values,...e.initial},{tabstops:a,items:n,keys:c}=await wlt(e,s),f=Qq("result",t,e),p=Qq("format",t,e),h=Qq("validate",t,e,!0),E=t.isValue.bind(t);return async(C={},S=!1)=>{let b=0;C.required=r,C.items=n,C.keys=c,C.output="";let I=async(W,ee,ie,ue)=>{let le=await h(W,ee,ie,ue);return le===!1?"Invalid field "+ie.name:le};for(let W of a){let ee=W.value,ie=W.key;if(W.type!=="template"){ee&&(C.output+=ee);continue}if(W.type==="template"){let ue=n.find(Ce=>Ce.name===ie);e.required===!0&&C.required.add(ue.name);let le=[ue.input,C.values[ue.value],ue.value,ee].find(E),pe=(ue.field||{}).message||W.inner;if(S){let Ce=await I(C.values[ie],C,ue,b);if(Ce&&typeof Ce=="string"||Ce===!1){C.invalid.set(ie,Ce);continue}C.invalid.delete(ie);let g=await f(C.values[ie],C,ue,b);C.output+=Mme.unstyle(g);continue}ue.placeholder=!1;let Be=ee;ee=await p(ee,C,ue,b),le!==ee?(C.values[ie]=le,ee=t.styles.typing(le),C.missing.delete(pe)):(C.values[ie]=void 0,le=`<${pe}>`,ee=t.styles.primary(le),ue.placeholder=!0,C.required.has(ie)&&C.missing.add(pe)),C.missing.has(pe)&&C.validating&&(ee=t.styles.warning(le)),C.invalid.has(ie)&&C.validating&&(ee=t.styles.danger(le)),b===C.index&&(Be!==ee?ee=t.styles.underline(ee):ee=t.styles.heading(Mme.unstyle(ee))),b++}ee&&(C.output+=ee)}let T=C.output.split(`
`).map(W=>" "+W),N=n.length,U=0;for(let W of n)C.invalid.has(W.name)&&W.lines.forEach(ee=>{T[ee][0]===" "&&(T[ee]=C.styles.danger(C.symbols.bullet)+T[ee].slice(1))}),t.isValue(C.values[W.name])&&U++;return C.completed=(U/N*100).toFixed(0),C.output=T.join(`
`),C.output}};function Qq(t,e,r,s){return(a,n,c,f)=>typeof c.field[t]=="function"?c.field[t].call(e,a,n,c,f):[s,a].find(p=>e.isValue(p))}});var jme=_((gjt,Hme)=>{"use strict";var Blt=Ju(),vlt=_me(),Slt=nC(),Tq=class extends Slt{constructor(e){super(e),this.cursorHide(),this.reset(!0)}async initialize(){this.interpolate=await vlt(this),await super.initialize()}async reset(e){this.state.keys=[],this.state.invalid=new Map,this.state.missing=new Set,this.state.completed=0,this.state.values={},e!==!0&&(await this.initialize(),await this.render())}moveCursor(e){let r=this.getItem();this.cursor+=e,r.cursor+=e}dispatch(e,r){if(!r.code&&!r.ctrl&&e!=null&&this.getItem()){this.append(e,r);return}this.alert()}append(e,r){let s=this.getItem(),a=s.input.slice(0,this.cursor),n=s.input.slice(this.cursor);this.input=s.input=`${a}${e}${n}`,this.moveCursor(1),this.render()}delete(){let e=this.getItem();if(this.cursor<=0||!e.input)return this.alert();let r=e.input.slice(this.cursor),s=e.input.slice(0,this.cursor-1);this.input=e.input=`${s}${r}`,this.moveCursor(-1),this.render()}increment(e){return e>=this.state.keys.length-1?0:e+1}decrement(e){return e<=0?this.state.keys.length-1:e-1}first(){this.state.index=0,this.render()}last(){this.state.index=this.state.keys.length-1,this.render()}right(){if(this.cursor>=this.input.length)return this.alert();this.moveCursor(1),this.render()}left(){if(this.cursor<=0)return this.alert();this.moveCursor(-1),this.render()}prev(){this.state.index=this.decrement(this.state.index),this.getItem(),this.render()}next(){this.state.index=this.increment(this.state.index),this.getItem(),this.render()}up(){this.prev()}down(){this.next()}format(e){let r=this.state.completed<100?this.styles.warning:this.styles.success;return this.state.submitted===!0&&this.state.completed!==100&&(r=this.styles.danger),r(`${this.state.completed}% completed`)}async render(){let{index:e,keys:r=[],submitted:s,size:a}=this.state,n=[this.options.newline,`
`].find(W=>W!=null),c=await this.prefix(),f=await this.separator(),p=await this.message(),h=[c,p,f].filter(Boolean).join(" ");this.state.prompt=h;let E=await this.header(),C=await this.error()||"",S=await this.hint()||"",b=s?"":await this.interpolate(this.state),I=this.state.key=r[e]||"",T=await this.format(I),N=await this.footer();T&&(h+=" "+T),S&&!T&&this.state.completed===0&&(h+=" "+S),this.clear(a);let U=[E,h,b,N,C.trim()];this.write(U.filter(Boolean).join(n)),this.restore()}getItem(e){let{items:r,keys:s,index:a}=this.state,n=r.find(c=>c.name===s[a]);return n&&n.input!=null&&(this.input=n.input,this.cursor=n.cursor),n}async submit(){typeof this.interpolate!="function"&&await this.initialize(),await this.interpolate(this.state,!0);let{invalid:e,missing:r,output:s,values:a}=this.state;if(e.size){let f="";for(let[p,h]of e)f+=`Invalid ${p}: ${h}
`;return this.state.error=f,super.submit()}if(r.size)return this.state.error="Required: "+[...r.keys()].join(", "),super.submit();let c=Blt.unstyle(s).split(`
`).map(f=>f.slice(1)).join(`
`);return this.value={values:a,result:c},super.submit()}};Hme.exports=Tq});var qme=_((djt,Gme)=>{"use strict";var Dlt="(Use <shift>+<up/down> to sort)",Plt=G0(),Fq=class extends Plt{constructor(e){super({...e,reorder:!1,sort:!0,multiple:!0}),this.state.hint=[this.options.hint,Dlt].find(this.isValue.bind(this))}indicator(){return""}async renderChoice(e,r){let s=await super.renderChoice(e,r),a=this.symbols.identicalTo+" ",n=this.index===r&&this.sorting?this.styles.muted(a):" ";return this.options.drag===!1&&(n=""),this.options.numbered===!0?n+`${r+1} - `+s:n+s}get selected(){return this.choices}submit(){return this.value=this.choices.map(e=>e.value),super.submit()}};Gme.exports=Fq});var Yme=_((mjt,Wme)=>{"use strict";var blt=Wv(),Nq=class extends blt{constructor(e={}){if(super(e),this.emptyError=e.emptyError||"No items were selected",this.term=process.env.TERM_PROGRAM,!this.options.header){let r=["","4 - Strongly Agree","3 - Agree","2 - Neutral","1 - Disagree","0 - Strongly Disagree",""];r=r.map(s=>this.styles.muted(s)),this.state.header=r.join(`
`)}}async toChoices(...e){if(this.createdScales)return!1;this.createdScales=!0;let r=await super.toChoices(...e);for(let s of r)s.scale=xlt(5,this.options),s.scaleIdx=2;return r}dispatch(){this.alert()}space(){let e=this.focused,r=e.scale[e.scaleIdx],s=r.selected;return e.scale.forEach(a=>a.selected=!1),r.selected=!s,this.render()}indicator(){return""}pointer(){return""}separator(){return this.styles.muted(this.symbols.ellipsis)}right(){let e=this.focused;return e.scaleIdx>=e.scale.length-1?this.alert():(e.scaleIdx++,this.render())}left(){let e=this.focused;return e.scaleIdx<=0?this.alert():(e.scaleIdx--,this.render())}indent(){return" "}async renderChoice(e,r){await this.onChoice(e,r);let s=this.index===r,a=this.term==="Hyper",n=a?9:8,c=a?"":" ",f=this.symbols.line.repeat(n),p=" ".repeat(n+(a?0:1)),h=ee=>(ee?this.styles.success("\u25C9"):"\u25EF")+c,E=r+1+".",C=s?this.styles.heading:this.styles.noop,S=await this.resolve(e.message,this.state,e,r),b=this.indent(e),I=b+e.scale.map((ee,ie)=>h(ie===e.scaleIdx)).join(f),T=ee=>ee===e.scaleIdx?C(ee):ee,N=b+e.scale.map((ee,ie)=>T(ie)).join(p),U=()=>[E,S].filter(Boolean).join(" "),W=()=>[U(),I,N," "].filter(Boolean).join(`
`);return s&&(I=this.styles.cyan(I),N=this.styles.cyan(N)),W()}async renderChoices(){if(this.state.submitted)return"";let e=this.visible.map(async(s,a)=>await this.renderChoice(s,a)),r=await Promise.all(e);return r.length||r.push(this.styles.danger("No matching choices")),r.join(`
`)}format(){return this.state.submitted?this.choices.map(r=>this.styles.info(r.scaleIdx)).join(", "):""}async render(){let{submitted:e,size:r}=this.state,s=await this.prefix(),a=await this.separator(),n=await this.message(),c=[s,n,a].filter(Boolean).join(" ");this.state.prompt=c;let f=await this.header(),p=await this.format(),h=await this.error()||await this.hint(),E=await this.renderChoices(),C=await this.footer();(p||!h)&&(c+=" "+p),h&&!c.includes(h)&&(c+=" "+h),e&&!p&&!E&&this.multiple&&this.type!=="form"&&(c+=this.styles.danger(this.emptyError)),this.clear(r),this.write([c,f,E,C].filter(Boolean).join(`
`)),this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIdx;return this.base.submit.call(this)}};function xlt(t,e={}){if(Array.isArray(e.scale))return e.scale.map(s=>({...s}));let r=[];for(let s=1;s<t+1;s++)r.push({i:s,selected:!1});return r}Wme.exports=Nq});var Jme=_((yjt,Vme)=>{Vme.exports=Bq()});var zme=_((Ejt,Kme)=>{"use strict";var klt=ZT(),Oq=class extends klt{async initialize(){await super.initialize(),this.value=this.initial=!!this.options.initial,this.disabled=this.options.disabled||"no",this.enabled=this.options.enabled||"yes",await this.render()}reset(){this.value=this.initial,this.render()}delete(){this.alert()}toggle(){this.value=!this.value,this.render()}enable(){if(this.value===!0)return this.alert();this.value=!0,this.render()}disable(){if(this.value===!1)return this.alert();this.value=!1,this.render()}up(){this.toggle()}down(){this.toggle()}right(){this.toggle()}left(){this.toggle()}next(){this.toggle()}prev(){this.toggle()}dispatch(e="",r){switch(e.toLowerCase()){case" ":return this.toggle();case"1":case"y":case"t":return this.enable();case"0":case"n":case"f":return this.disable();default:return this.alert()}}format(){let e=s=>this.styles.primary.underline(s);return[this.value?this.disabled:e(this.disabled),this.value?e(this.enabled):this.enabled].join(this.styles.muted(" / "))}async render(){let{size:e}=this.state,r=await this.header(),s=await this.prefix(),a=await this.separator(),n=await this.message(),c=await this.format(),f=await this.error()||await this.hint(),p=await this.footer(),h=[s,n,a,c].join(" ");this.state.prompt=h,f&&!h.includes(f)&&(h+=" "+f),this.clear(e),this.write([r,h,p].filter(Boolean).join(`
`)),this.write(this.margin[2]),this.restore()}};Kme.exports=Oq});var Xme=_((Ijt,Zme)=>{"use strict";var Qlt=G0(),Lq=class extends Qlt{constructor(e){if(super(e),typeof this.options.correctChoice!="number"||this.options.correctChoice<0)throw new Error("Please specify the index of the correct answer from the list of choices")}async toChoices(e,r){let s=await super.toChoices(e,r);if(s.length<2)throw new Error("Please give at least two choices to the user");if(this.options.correctChoice>s.length)throw new Error("Please specify the index of the correct answer from the list of choices");return s}check(e){return e.index===this.options.correctChoice}async result(e){return{selectedAnswer:e,correctAnswer:this.options.choices[this.options.correctChoice].value,correct:await this.check(this.state)}}};Zme.exports=Lq});var eye=_(Mq=>{"use strict";var $me=Xo(),ks=(t,e)=>{$me.defineExport(Mq,t,e),$me.defineExport(Mq,t.toLowerCase(),e)};ks("AutoComplete",()=>ome());ks("BasicAuth",()=>pme());ks("Confirm",()=>dme());ks("Editable",()=>yme());ks("Form",()=>zT());ks("Input",()=>Bq());ks("Invisible",()=>Sme());ks("List",()=>Pme());ks("MultiSelect",()=>xme());ks("Numeral",()=>Rme());ks("Password",()=>Fme());ks("Scale",()=>Lme());ks("Select",()=>G0());ks("Snippet",()=>jme());ks("Sort",()=>qme());ks("Survey",()=>Yme());ks("Text",()=>Jme());ks("Toggle",()=>zme());ks("Quiz",()=>Xme())});var rye=_((wjt,tye)=>{tye.exports={ArrayPrompt:Wv(),AuthPrompt:mq(),BooleanPrompt:ZT(),NumberPrompt:bq(),StringPrompt:vm()}});var Vv=_((Bjt,iye)=>{"use strict";var nye=Ie("assert"),_q=Ie("events"),q0=Xo(),zu=class extends _q{constructor(e,r){super(),this.options=q0.merge({},e),this.answers={...r}}register(e,r){if(q0.isObject(e)){for(let a of Object.keys(e))this.register(a,e[a]);return this}nye.equal(typeof r,"function","expected a function");let s=e.toLowerCase();return r.prototype instanceof this.Prompt?this.prompts[s]=r:this.prompts[s]=r(this.Prompt,this),this}async prompt(e=[]){for(let r of[].concat(e))try{typeof r=="function"&&(r=await r.call(this)),await this.ask(q0.merge({},this.options,r))}catch(s){return Promise.reject(s)}return this.answers}async ask(e){typeof e=="function"&&(e=await e.call(this));let r=q0.merge({},this.options,e),{type:s,name:a}=e,{set:n,get:c}=q0;if(typeof s=="function"&&(s=await s.call(this,e,this.answers)),!s)return this.answers[a];nye(this.prompts[s],`Prompt "${s}" is not registered`);let f=new this.prompts[s](r),p=c(this.answers,a);f.state.answers=this.answers,f.enquirer=this,a&&f.on("submit",E=>{this.emit("answer",a,E,f),n(this.answers,a,E)});let h=f.emit.bind(f);return f.emit=(...E)=>(this.emit.call(this,...E),h(...E)),this.emit("prompt",f,this),r.autofill&&p!=null?(f.value=f.input=p,r.autofill==="show"&&await f.submit()):p=f.value=await f.run(),p}use(e){return e.call(this,this),this}set Prompt(e){this._Prompt=e}get Prompt(){return this._Prompt||this.constructor.Prompt}get prompts(){return this.constructor.prompts}static set Prompt(e){this._Prompt=e}static get Prompt(){return this._Prompt||nC()}static get prompts(){return eye()}static get types(){return rye()}static get prompt(){let e=(r,...s)=>{let a=new this(...s),n=a.emit.bind(a);return a.emit=(...c)=>(e.emit(...c),n(...c)),a.prompt(r)};return q0.mixinEmitter(e,new _q),e}};q0.mixinEmitter(zu,new _q);var Uq=zu.prompts;for(let t of Object.keys(Uq)){let e=t.toLowerCase(),r=s=>new Uq[t](s).run();zu.prompt[e]=r,zu[e]=r,zu[t]||Reflect.defineProperty(zu,t,{get:()=>Uq[t]})}var Yv=t=>{q0.defineExport(zu,t,()=>zu.types[t])};Yv("ArrayPrompt");Yv("AuthPrompt");Yv("BooleanPrompt");Yv("NumberPrompt");Yv("StringPrompt");iye.exports=zu});var Aye=_((Y6t,_lt)=>{_lt.exports={name:"@yarnpkg/cli",version:"4.10.3",license:"BSD-2-Clause",main:"./sources/index.ts",exports:{".":"./sources/index.ts","./polyfills":"./sources/polyfills.ts","./package.json":"./package.json"},dependencies:{"@yarnpkg/core":"workspace:^","@yarnpkg/fslib":"workspace:^","@yarnpkg/libzip":"workspace:^","@yarnpkg/parsers":"workspace:^","@yarnpkg/plugin-catalog":"workspace:^","@yarnpkg/plugin-compat":"workspace:^","@yarnpkg/plugin-constraints":"workspace:^","@yarnpkg/plugin-dlx":"workspace:^","@yarnpkg/plugin-essentials":"workspace:^","@yarnpkg/plugin-exec":"workspace:^","@yarnpkg/plugin-file":"workspace:^","@yarnpkg/plugin-git":"workspace:^","@yarnpkg/plugin-github":"workspace:^","@yarnpkg/plugin-http":"workspace:^","@yarnpkg/plugin-init":"workspace:^","@yarnpkg/plugin-interactive-tools":"workspace:^","@yarnpkg/plugin-jsr":"workspace:^","@yarnpkg/plugin-link":"workspace:^","@yarnpkg/plugin-nm":"workspace:^","@yarnpkg/plugin-npm":"workspace:^","@yarnpkg/plugin-npm-cli":"workspace:^","@yarnpkg/plugin-pack":"workspace:^","@yarnpkg/plugin-patch":"workspace:^","@yarnpkg/plugin-pnp":"workspace:^","@yarnpkg/plugin-pnpm":"workspace:^","@yarnpkg/plugin-stage":"workspace:^","@yarnpkg/plugin-typescript":"workspace:^","@yarnpkg/plugin-version":"workspace:^","@yarnpkg/plugin-workspace-tools":"workspace:^","@yarnpkg/shell":"workspa Line truncated
${W} at ${ee}`:`
${W}`}).join("");h.push({text:`Conflict detected in constraint targeting ${he.pretty(t.configuration,b,he.Type.CODE)}; conflicting values are:${T}`,fixable:!1})}else{let[[T]]=I,N=va(S,b);if(JSON.stringify(N)===JSON.stringify(T))continue;if(!s){let U=typeof N>"u"?`Missing field ${he.pretty(t.configuration,b,he.Type.CODE)}; expected ${he.pretty(t.configuration,T,he.Type.INSPECT)}`:typeof T>"u"?`Extraneous field ${he.pretty(t.configuration,b,he.Type.CODE)} currently set to ${he.pretty(t.configuration,N,he.Type.INSPECT)}`:`Invalid field ${he.pretty(t.configuration,b,he.Type.CODE)}; expected ${he.pretty(t.configuration,T,he.Type.INSPECT)}, found ${he.pretty(t.configuration,N,he.Type.INSPECT)}`;h.push({text:U,fixable:!0});continue}typeof T>"u"?A0(S,b):Jd(S,b,T),E=!0}E&&a.set(C,S)}h.length>0&&n.set(C,h)}return{changedWorkspaces:a,remainingErrors:n}}function Zye(t,{configuration:e}){let r={children:[]};for(let[s,a]of t){let n=[];for(let f of a){let p=f.text.split(/\n/);f.fixable&&(p[0]=`${he.pretty(e,"\u2699","gray")} ${p[0]}`),n.push({value:he.tuple(he.Type.NO_HINT,p[0]),children:p.slice(1).map(h=>({value:he.tuple(he.Type.NO_HINT,h)}))})}let c={value:he.tuple(he.Type.LOCATOR,s.anchoredLocator),children:je.sortMap(n,f=>f.value[1])};r.children.push(c)}return r.children=je.sortMap(r.children,s=>s.value[1]),r}var WC,Qct,Rct,Tct,iS=Ze(()=>{Ge();ql();WC=class{constructor(e){this.indexedFields=e;this.items=[];this.indexes={};this.clear()}clear(){this.items=[];for(let e of this.indexedFields)this.indexes[e]=new Map}insert(e){this.items.push(e);for(let r of this.indexedFields){let s=Object.hasOwn(e,r)?e[r]:void 0;if(typeof s>"u")continue;je.getArrayWithDefault(this.indexes[r],s).push(e)}return e}find(e){if(typeof e>"u")return this.items;let r=Object.entries(e);if(r.length===0)return this.items;let s=[],a;for(let[c,f]of r){let p=c,h=Object.hasOwn(this.indexes,p)?this.indexes[p]:void 0;if(typeof h>"u"){s.push([p,f]);continue}let E=new Set(h.get(f)??[]);if(E.size===0)return[];if(typeof a>"u")a=E;else for(let C of a)E.has(C)||a.delete(C);if(a.size===0)break}let n=[...a??[]];return s.length>0&&(n=n.filter(c=>{for(let[f,p]of s)if(!(typeof p<"u"?Object.hasOwn(c,f)&&c[f]===p:Object.hasOwn(c,f)===!1))return!1;return!0})),n}},Qct=/^[0-9]+$/,Rct=/^[a-zA-Z0-9_]+$/,Tct=new Set(["scripts",...Ut.allDependencies])});var Xye=_((CYt,m5)=>{var Oct;(function(t){var e=function(){return{"append/2":[new t.type.Rule(new t.type.Term("append",[new t.type.Var("X"),new t.type.Var("L")]),new t.type.Term("foldl",[new t.type.Term("append",[]),new t.type.Var("X"),new t.type.Term("[]",[]),new t.type.Var("L")]))],"append/3":[new t.type.Rule(new t.type.Term("append",[new t.type.Term("[]",[]),new t.type.Var("X"),new t.type.Var("X")]),null),new t.type.Rule(new t.type.Term("append",[new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("T")]),new t.type.Var("X"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("S")])]),new t.type.Term("append",[new t.type.Var("T"),new t.type.Var("X"),new t.type.Var("S")]))],"member/2":[new t.type.Rule(new t.type.Term("member",[new t.type.Var("X"),new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("_")])]),null),new t.type.Rule(new t.type.Term("member",[new t.type.Var("X"),new t.type.Term(".",[new t.type.Var("_"),new t.type.Var("Xs")])]),new t.type.Term("member",[new t.type.Var("X"),new t.type.Var("Xs")]))],"permutation/2":[new t.type.Rule(new t.type.Term("permutation",[new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("permutation",[new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("T")]),new t.type.Var("S")]),new t.type.Term(",",[new t.type.Term("permutation",[new t.type.Var("T"),new t.type.Var("P")]),new t.type.Term(",",[new t.type.Term("append",[new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("P")]),new t.type.Term("append",[new t.type.Var("X"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("Y")]),new t.type.Var("S")])])]))],"maplist/2":[new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("_"),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Xs")])]),new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("P"),new t.type.Var("X")]),new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Var("Xs")])]))],"maplist/3":[new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("A"),new t.type.Var("As")]),new t.type.Term(".",[new t.type.Var("B"),new t.type.Var("Bs")])]),new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("P"),new t.type.Var("A"),new t.type.Var("B")]),new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Var("As"),new t.type.Var("Bs")])]))],"maplist/4":[new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Ter Line truncated
`+p:"")),c.error.method="_execFileSync",c.error.program=a,c.error.args=n,c.error.extMessage=p,c.error.exitCode=+f),si.unlinkSync(h),si.unlinkSync(E),si.unlinkSync(C),si.unlinkSync(S),c}function _ct(t){var e,r={},s,a={env:process.env,encoding:t.encoding};if(Y0||(Pm?process.env.PSModulePath?(Y0="powershell.exe",sF=["-ExecutionPolicy","Bypass","-File",__dirname+"\\read.ps1"]):(Y0="cscript.exe",sF=["//nologo",__dirname+"\\read.cs.js"]):(Y0="/bin/sh",sF=[__dirname+"/read.sh"])),Pm&&!process.env.PSModulePath&&(a.stdio=[process.stdin]),I5.execFileSync){e=nEe(t),sS&&sS("execFileSync",e);try{r.input=I5.execFileSync(Y0,e,a)}catch(n){s=n.stderr?(n.stderr+"").trim():"",r.error=new Error(tEe+(s?`
`+s:"")),r.error.method="execFileSync",r.error.program=Y0,r.error.args=e,r.error.extMessage=s,r.error.exitCode=n.status,r.error.code=n.code,r.error.signal=n.signal}}else r=Uct(t,a);return r.error||(r.input=r.input.replace(/^\s*'|'\s*$/g,""),t.display=""),r}function B5(t){var e="",r=t.display,s=!t.display&&t.keyIn&&t.hideEchoBack&&!t.mask;function a(){var n=_ct(t);if(n.error)throw n.error;return n.input}return w5&&w5(t),function(){var n,c,f;function p(){return n||(n=process.binding("fs"),c=process.binding("constants")),n}if(typeof Zp=="string")if(Zp=null,Pm){if(f=function(h){var E=h.replace(/^\D+/,"").split("."),C=0;return(E[0]=+E[0])&&(C+=E[0]*1e4),(E[1]=+E[1])&&(C+=E[1]*100),(E[2]=+E[2])&&(C+=E[2]),C}(process.version),!(f>=20302&&f<40204||f>=5e4&&f<50100||f>=50600&&f<60200)&&process.stdin.isTTY)process.stdin.pause(),Zp=process.stdin.fd,VC=process.stdin._handle;else try{Zp=p().open("CONIN$",c.O_RDWR,parseInt("0666",8)),VC=new $ye(Zp,!0)}catch{}if(process.stdout.isTTY)Xu=process.stdout.fd;else{try{Xu=si.openSync("\\\\.\\CON","w")}catch{}if(typeof Xu!="number")try{Xu=p().open("CONOUT$",c.O_RDWR,parseInt("0666",8))}catch{}}}else{if(process.stdin.isTTY){process.stdin.pause();try{Zp=si.openSync("/dev/tty","r"),VC=process.stdin._handle}catch{}}else try{Zp=si.openSync("/dev/tty","r"),VC=new $ye(Zp,!1)}catch{}if(process.stdout.isTTY)Xu=process.stdout.fd;else try{Xu=si.openSync("/dev/tty","w")}catch{}}}(),function(){var n,c,f=!t.hideEchoBack&&!t.keyIn,p,h,E,C,S;oF="";function b(I){return I===eEe?!0:VC.setRawMode(I)!==0?!1:(eEe=I,!0)}if(rEe||!VC||typeof Xu!="number"&&(t.display||!f)){e=a();return}if(t.display&&(si.writeSync(Xu,t.display),t.display=""),!t.displayOnly){if(!b(!f)){e=a();return}for(h=t.keyIn?1:t.bufferSize,p=Buffer.allocUnsafe&&Buffer.alloc?Buffer.alloc(h):new Buffer(h),t.keyIn&&t.limit&&(c=new RegExp("[^"+t.limit+"]","g"+(t.caseSensitive?"":"i")));;){E=0;try{E=si.readSync(Zp,p,0,h)}catch(I){if(I.code!=="EOF"){b(!1),e+=a();return}}if(E>0?(C=p.toString(t.encoding,0,E),oF+=C):(C=`
`,oF+="\0"),C&&typeof(S=(C.match(/^(.*?)[\r\n]/)||[])[1])=="string"&&(C=S,n=!0),C&&(C=C.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g,"")),C&&c&&(C=C.replace(c,"")),C&&(f||(t.hideEchoBack?t.mask&&si.writeSync(Xu,new Array(C.length+1).join(t.mask)):si.writeSync(Xu,C)),e+=C),!t.keyIn&&n||t.keyIn&&e.length>=h)break}!f&&!s&&si.writeSync(Xu,`
`),b(!1)}}(),t.print&&!s&&t.print(r+(t.displayOnly?"":(t.hideEchoBack?new Array(e.length+1).join(t.mask):e)+`
`),t.encoding),t.displayOnly?"":D5=t.keepWhitespace||t.keyIn?e:e.trim()}function Hct(t,e){var r=[];function s(a){a!=null&&(Array.isArray(a)?a.forEach(s):(!e||e(a))&&r.push(a))}return s(t),r}function P5(t){return t.replace(/[\x00-\x7f]/g,function(e){return"\\x"+("00"+e.charCodeAt().toString(16)).substr(-2)})}function Vs(){var t=Array.prototype.slice.call(arguments),e,r;return t.length&&typeof t[0]=="boolean"&&(r=t.shift(),r&&(e=Object.keys(C5),t.unshift(C5))),t.reduce(function(s,a){return a==null||(a.hasOwnProperty("noEchoBack")&&!a.hasOwnProperty("hideEchoBack")&&(a.hideEchoBack=a.noEchoBack,delete a.noEchoBack),a.hasOwnProperty("noTrim")&&!a.hasOwnProperty("keepWhitespace")&&(a.keepWhitespace=a.noTrim,delete a.noTrim),r||(e=Object.keys(a)),e.forEach(function(n){var c;if(a.hasOwnProperty(n))switch(c=a[n],n){case"mask":case"limitMessage":case"defaultInput":case"encoding":c=c!=null?c+"":"",c&&n!=="limitMessage"&&(c=c.replace(/[\r\n]/g,"")),s[n]=c;break;case"bufferSize":!isNaN(c=parseInt(c,10))&&typeof c=="number"&&(s[n]=c);break;case"displayOnly":case"keyIn":case"hideEchoBack":case"caseSensitive":case"keepWhitespace":case"history":case"cd":s[n]=!!c;break;case"limit":case"trueValue":case"falseValue":s[n]=Hct(c,function(f){var p=typeof f;return p==="string"||p==="number"||p==="function"||f instanceof RegExp}).map(function(f){return typeof f=="string"?f.replace(/[\r\n]/g,""):f});break;case"print":case"phContent":case"preCheck":s[n]=typeof c=="function"?c:void 0;break;case"prompt":case"display":s[n]=c??"";break}})),s},{})}function v5(t,e,r){return e.some(function(s){var a=typeof s;return a==="string"?r?t===s:t.toLowerCase()===s.toLowerCase():a==="number"?parseFloat(t)===s:a==="function"?s(t):s instanceof RegExp?s.test(t):!1})}function b5(t,e){var r=V0.normalize(Pm?(process.env.HOMEDRIVE||"")+(process.env.HOMEPATH||""):process.env.HOME||"").replace(/[\/\\]+$/,"");return t=V0.normalize(t),e?t.replace(/^~(?=\/|\\|$)/,r):t.replace(new RegExp("^"+P5(r)+"(?=\\/|\\\\|$)",Pm?"i":""),"~")}function JC(t,e){var r="(?:\\(([\\s\\S]*?)\\))?(\\w+|.-.)(?:\\(([\\s\\S]*?)\\))?",s=new RegExp("(\\$)?(\\$<"+r+">)","g"),a=new RegExp("(\\$)?(\\$\\{"+r+"\\})","g");function n(c,f,p,h,E,C){var S;return f||typeof(S=e(E))!="string"?p:S?(h||"")+S+(C||""):""}return t.replace(s,n).replace(a,n)}function iEe(t,e,r){var s,a=[],n=-1,c=0,f="",p;function h(E,C){return C.length>3?(E.push(C[0]+"..."+C[C.length-1]),p=!0):C.length&&(E=E.concat(C)),E}return s=t.reduce(function(E,C){return E.concat((C+"").split(""))},[]).reduce(function(E,C){var S,b;return e||(C=C.toLowerCase()),S=/^\d$/.test(C)?1:/^[A-Z]$/.test(C)?2:/^[a-z]$/.test(C)?3:0,r&&S===0?f+=C:(b=C.charCodeAt(0),S&&S===n&&b===c+1?a.push(C):(E=h(E,a),a=[C],n=S),c=b),E},[]),s=h(s,a),f&&(s.push(f),p=!0),{values:s,suppressed:p}}function sEe(t,e){return t.join(t.length>2?", ":e?" / ":"/")}function oEe(t,e){var r,s,a={},n;if(e.phContent&&(r=e.phContent(t,e)),typeof r!="string")switch(t){case"hideEchoBack":case"mask":case"defaultInput":case"caseSensitive":case"keepWhitespace":case"encoding":case"bufferSize":case"history":case"cd":r=e.hasOwnProperty(t)?typeof e[t]=="boolean"?e[t]?"on":"off":e[t]+"":"";break;case"limit":case"trueValue":case"falseValue":s=e[e.hasOwnProperty(t+"Src")?t+"Src":t],e.keyIn?(a=iEe(s,e.caseSensitive),s=a.values):s=s.filter(function(c){var f=typeof c;return f==="string"||f==="number"}),r=sEe(s,a.suppressed);break;case"limitCount":case"limitCountNotZero":r=e[e.hasOwnProperty("limitSrc")?"limitSrc":"limit"].length,r=r||t!=="limitCountNotZero"?r+"":"";break;case"lastInput":r=D5;break;case"cwd":case"CWD":case"cwdHome":r=process.cwd(),t==="CWD"?r=V0.basename(r):t==="cwdHome"&&(r=b5(r));break;case"date":case"time":case"localeDate":case"localeTime":r=new Date()["to"+t.replace(/^./,function(c){return c.toUpperCase()})+"String"]();break;default:typeof(n=(t.match(/^history_m(\d+)$/)||[])[1])=="string"&&(r=Dm[Dm.length-n]||"")}return r}function aEe(t){var e=/^(.)-(.)$/.exec(t),r="",s,a,n,c;if(!e)return null;for(s=e[1].charCodeAt(0),a=e[2].charCodeAt(0),c=s<a?1:-1,n=s;n!==a+c;n+=c)r+=String.fromCharCode(n);return r}function S5(t){var e=new RegExp(/(\s*)(?:("|')(.*?)(?:\2|$)|(\S+))/g),r,s="",a=[],n;for(t=t.trim();r=e.exec(t);)n=r[3]||r[4]||"",r[1]&&(a.push(s),s=""),s+=n;return s&&a.push(s),a}function lEe(t,e){return e.trueValue.length&&v5(t,e.trueValue,e.caseSensitive)?!0:e.falseValue.length&&v5(t,e.falseValue,e.caseSensitive)?!1:t}function cEe(t){var e,r,s,a,n,c,f;function p(E){return oEe(E,t)}function h(E){t.display+=(/[^\r\n]$/.test(t.display)?`
`:"")+E}for(t.limitSrc=t.limit,t.displaySrc=t.display,t.limit="",t.display=JC(t.display+"",p);;){if(e=B5(t),r=!1,s="",t.defaultInput&&!e&&(e=t.defaultInput),t.history&&((a=/^\s*\!(?:\!|-1)(:p)?\s*$/.exec(e))?(n=Dm[0]||"",a[1]?r=!0:e=n,h(n+`
`),r||(t.displayOnly=!0,B5(t),t.displayOnly=!1)):e&&e!==Dm[Dm.length-1]&&(Dm=[e])),!r&&t.cd&&e)switch(c=S5(e),c[0].toLowerCase()){case"cd":if(c[1])try{process.chdir(b5(c[1],!0))}catch(E){h(E+"")}r=!0;break;case"pwd":h(process.cwd()),r=!0;break}if(!r&&t.preCheck&&(f=t.preCheck(e,t),e=f.res,f.forceNext&&(r=!0)),!r){if(!t.limitSrc.length||v5(e,t.limitSrc,t.caseSensitive))break;t.limitMessage&&(s=JC(t.limitMessage,p))}h((s?s+`
`:"")+JC(t.displaySrc+"",p))}return lEe(e,t)}$r._DBG_set_useExt=function(t){rEe=t};$r._DBG_set_checkOptions=function(t){w5=t};$r._DBG_set_checkMethod=function(t){sS=t};$r._DBG_clearHistory=function(){D5="",Dm=[]};$r.setDefaultOptions=function(t){return C5=Vs(!0,t),Vs(!0)};$r.question=function(t,e){return cEe(Vs(Vs(!0,e),{display:t}))};$r.prompt=function(t){var e=Vs(!0,t);return e.display=e.prompt,cEe(e)};$r.keyIn=function(t,e){var r=Vs(Vs(!0,e),{display:t,keyIn:!0,keepWhitespace:!0});return r.limitSrc=r.limit.filter(function(s){var a=typeof s;return a==="string"||a==="number"}).map(function(s){return JC(s+"",aEe)}),r.limit=P5(r.limitSrc.join("")),["trueValue","falseValue"].forEach(function(s){r[s]=r[s].reduce(function(a,n){var c=typeof n;return c==="string"||c==="number"?a=a.concat((n+"").split("")):a.push(n),a},[])}),r.display=JC(r.display+"",function(s){return oEe(s,r)}),lEe(B5(r),r)};$r.questionEMail=function(t,e){return t==null&&(t="Input e-mail address: "),$r.question(t,Vs({hideEchoBack:!1,limit:/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,limitMessage:"Input valid e-mail address, please.",trueValue:null,falseValue:null},e,{keepWhitespace:!1,cd:!1}))};$r.questionNewPassword=function(t,e){var r,s,a,n=Vs({hideEchoBack:!0,mask:"*",limitMessage:`It can include: $<charlist>
And the length must be: $<length>`,trueValue:null,falseValue:null,caseSensitive:!0},e,{history:!1,cd:!1,phContent:function(b){return b==="charlist"?r.text:b==="length"?s+"..."+a:null}}),c,f,p,h,E,C,S;for(e=e||{},c=JC(e.charlist?e.charlist+"":"$<!-~>",aEe),(isNaN(s=parseInt(e.min,10))||typeof s!="number")&&(s=12),(isNaN(a=parseInt(e.max,10))||typeof a!="number")&&(a=24),h=new RegExp("^["+P5(c)+"]{"+s+","+a+"}$"),r=iEe([c],n.caseSensitive,!0),r.text=sEe(r.values,r.suppressed),f=e.confirmMessage!=null?e.confirmMessage:"Reinput a same one to confirm it: ",p=e.unmatchMessage!=null?e.unmatchMessage:"It differs from first one. Hit only the Enter key if you want to retry from first one.",t==null&&(t="Input new password: "),E=n.limitMessage;!S;)n.limit=h,n.limitMessage=E,C=$r.question(t,n),n.limit=[C,""],n.limitMessage=p,S=$r.question(f,n);return C};function uEe(t,e,r){var s;function a(n){return s=r(n),!isNaN(s)&&typeof s=="number"}return $r.question(t,Vs({limitMessage:"Input valid number, please."},e,{limit:a,cd:!1})),s}$r.questionInt=function(t,e){return uEe(t,e,function(r){return parseInt(r,10)})};$r.questionFloat=function(t,e){return uEe(t,e,parseFloat)};$r.questionPath=function(t,e){var r,s="",a=Vs({hideEchoBack:!1,limitMessage:`$<error(
)>Input valid path, please.$<( Min:)min>$<( Max:)max>`,history:!0,cd:!0},e,{keepWhitespace:!1,limit:function(n){var c,f,p;n=b5(n,!0),s="";function h(E){E.split(/\/|\\/).reduce(function(C,S){var b=V0.resolve(C+=S+V0.sep);if(!si.existsSync(b))si.mkdirSync(b);else if(!si.statSync(b).isDirectory())throw new Error("Non directory already exists: "+b);return C},"")}try{if(c=si.existsSync(n),r=c?si.realpathSync(n):V0.resolve(n),!e.hasOwnProperty("exists")&&!c||typeof e.exists=="boolean"&&e.exists!==c)return s=(c?"Already exists":"No such file or directory")+": "+r,!1;if(!c&&e.create&&(e.isDirectory?h(r):(h(V0.dirname(r)),si.closeSync(si.openSync(r,"w"))),r=si.realpathSync(r)),c&&(e.min||e.max||e.isFile||e.isDirectory)){if(f=si.statSync(r),e.isFile&&!f.isFile())return s="Not file: "+r,!1;if(e.isDirectory&&!f.isDirectory())return s="Not directory: "+r,!1;if(e.min&&f.size<+e.min||e.max&&f.size>+e.max)return s="Size "+f.size+" is out of range: "+r,!1}if(typeof e.validate=="function"&&(p=e.validate(r))!==!0)return typeof p=="string"&&(s=p),!1}catch(E){return s=E+"",!1}return!0},phContent:function(n){return n==="error"?s:n!=="min"&&n!=="max"?null:e.hasOwnProperty(n)?e[n]+"":""}});return e=e||{},t==null&&(t='Input path (you can "cd" and "pwd"): '),$r.question(t,a),r};function fEe(t,e){var r={},s={};return typeof t=="object"?(Object.keys(t).forEach(function(a){typeof t[a]=="function"&&(s[e.caseSensitive?a:a.toLowerCase()]=t[a])}),r.preCheck=function(a){var n;return r.args=S5(a),n=r.args[0]||"",e.caseSensitive||(n=n.toLowerCase()),r.hRes=n!=="_"&&s.hasOwnProperty(n)?s[n].apply(a,r.args.slice(1)):s.hasOwnProperty("_")?s._.apply(a,r.args):null,{res:a,forceNext:!1}},s.hasOwnProperty("_")||(r.limit=function(){var a=r.args[0]||"";return e.caseSensitive||(a=a.toLowerCase()),s.hasOwnProperty(a)})):r.preCheck=function(a){return r.args=S5(a),r.hRes=typeof t=="function"?t.apply(a,r.args):!0,{res:a,forceNext:!1}},r}$r.promptCL=function(t,e){var r=Vs({hideEchoBack:!1,limitMessage:"Requested command is not available.",caseSensitive:!1,history:!0},e),s=fEe(t,r);return r.limit=s.limit,r.preCheck=s.preCheck,$r.prompt(r),s.args};$r.promptLoop=function(t,e){for(var r=Vs({hideEchoBack:!1,trueValue:null,falseValue:null,caseSensitive:!1,history:!0},e);!t($r.prompt(r)););};$r.promptCLLoop=function(t,e){var r=Vs({hideEchoBack:!1,limitMessage:"Requested command is not available.",caseSensitive:!1,history:!0},e),s=fEe(t,r);for(r.limit=s.limit,r.preCheck=s.preCheck;$r.prompt(r),!s.hRes;);};$r.promptSimShell=function(t){return $r.prompt(Vs({hideEchoBack:!1,history:!0},t,{prompt:function(){return Pm?"$<cwd>>":(process.env.USER||"")+(process.env.HOSTNAME?"@"+process.env.HOSTNAME.replace(/\..*$/,""):"")+":$<cwdHome>$ "}()}))};function AEe(t,e,r){var s;return t==null&&(t="Are you sure? "),(!e||e.guide!==!1)&&(t+="")&&(t=t.replace(/\s*:?\s*$/,"")+" [y/n]: "),s=$r.keyIn(t,Vs(e,{hideEchoBack:!1,limit:r,trueValue:"y",falseValue:"n",caseSensitive:!1})),typeof s=="boolean"?s:""}$r.keyInYN=function(t,e){return AEe(t,e)};$r.keyInYNStrict=function(t,e){return AEe(t,e,"yn")};$r.keyInPause=function(t,e){t==null&&(t="Continue..."),(!e||e.guide!==!1)&&(t+="")&&(t=t.replace(/\s+$/,"")+" (Hit any key)"),$r.keyIn(t,Vs({limit:null},e,{hideEchoBack:!0,mask:""}))};$r.keyInSelect=function(t,e,r){var s=Vs({hideEchoBack:!1},r,{trueValue:null,falseValue:null,caseSensitive:!1,phContent:function(p){return p==="itemsCount"?t.length+"":p==="firstItem"?(t[0]+"").trim():p==="lastItem"?(t[t.length-1]+"").trim():null}}),a="",n={},c=49,f=`
`;if(!Array.isArray(t)||!t.length||t.length>35)throw"`items` must be Array (max length: 35).";return t.forEach(function(p,h){var E=String.fromCharCode(c);a+=E,n[E]=h,f+="["+E+"] "+(p+"").trim()+`
`,c=c===57?97:c+1}),(!r||r.cancel!==!1)&&(a+="0",n[0]=-1,f+="[0] "+(r&&r.cancel!=null&&typeof r.cancel!="boolean"?(r.cancel+"").trim():"CANCEL")+`
`),s.limit=a,f+=`
`,e==null&&(e="Choose one from list: "),(e+="")&&((!r||r.guide!==!1)&&(e=e.replace(/\s*:?\s*$/,"")+" [$<limit>]: "),f+=e),n[$r.keyIn(f,s).toLowerCase()]};$r.getRawInput=function(){return oF};function oS(t,e){var r;return e.length&&(r={},r[t]=e[0]),$r.setDefaultOptions(r)[t]}$r.setPrint=function(){return oS("print",arguments)};$r.setPrompt=function(){return oS("prompt",arguments)};$r.setEncoding=function(){return oS("encoding",arguments)};$r.setMask=function(){return oS("mask",arguments)};$r.setBufferSize=function(){return oS("bufferSize",arguments)}});var x5=_((BYt,ec)=>{(function(){var t={major:0,minor:2,patch:66,status:"beta"};tau_file_system={files:{},open:function(w,P,y){var F=tau_file_system.files[w];if(!F){if(y==="read")return null;F={path:w,text:"",type:P,get:function(z,Z){return Z===this.text.length||Z>this.text.length?"end_of_file":this.text.substring(Z,Z+z)},put:function(z,Z){return Z==="end_of_file"?(this.text+=z,!0):Z==="past_end_of_file"?null:(this.text=this.text.substring(0,Z)+z+this.text.substring(Z+z.length),!0)},get_byte:function(z){if(z==="end_of_stream")return-1;var Z=Math.floor(z/2);if(this.text.length<=Z)return-1;var $=n(this.text[Math.floor(z/2)],0);return z%2===0?$&255:$/256>>>0},put_byte:function(z,Z){var $=Z==="end_of_stream"?this.text.length:Math.floor(Z/2);if(this.text.length<$)return null;var oe=this.text.length===$?-1:n(this.text[Math.floor(Z/2)],0);return Z%2===0?(oe=oe/256>>>0,oe=(oe&255)<<8|z&255):(oe=oe&255,oe=(z&255)<<8|oe&255),this.text.length===$?this.text+=c(oe):this.text=this.text.substring(0,$)+c(oe)+this.text.substring($+1),!0},flush:function(){return!0},close:function(){var z=tau_file_system.files[this.path];return z?!0:null}},tau_file_system.files[w]=F}return y==="write"&&(F.text=""),F}},tau_user_input={buffer:"",get:function(w,P){for(var y;tau_user_input.buffer.length<w;)y=window.prompt(),y&&(tau_user_input.buffer+=y);return y=tau_user_input.buffer.substr(0,w),tau_user_input.buffer=tau_user_input.buffer.substr(w),y}},tau_user_output={put:function(w,P){return console.log(w),!0},flush:function(){return!0}},nodejs_file_system={open:function(w,P,y){var F=Ie("fs"),z=F.openSync(w,y[0]);return y==="read"&&!F.existsSync(w)?null:{get:function(Z,$){var oe=new Buffer(Z);return F.readSync(z,oe,0,Z,$),oe.toString()},put:function(Z,$){var oe=Buffer.from(Z);if($==="end_of_file")F.writeSync(z,oe);else{if($==="past_end_of_file")return null;F.writeSync(z,oe,0,oe.length,$)}return!0},get_byte:function(Z){return null},put_byte:function(Z,$){return null},flush:function(){return!0},close:function(){return F.closeSync(z),!0}}}},nodejs_user_input={buffer:"",get:function(w,P){for(var y,F=pEe();nodejs_user_input.buffer.length<w;)nodejs_user_input.buffer+=F.question();return y=nodejs_user_input.buffer.substr(0,w),nodejs_user_input.buffer=nodejs_user_input.buffer.substr(w),y}},nodejs_user_output={put:function(w,P){return process.stdout.write(w),!0},flush:function(){return!0}};var e;Array.prototype.indexOf?e=function(w,P){return w.indexOf(P)}:e=function(w,P){for(var y=w.length,F=0;F<y;F++)if(P===w[F])return F;return-1};var r=function(w,P){if(w.length!==0){for(var y=w[0],F=w.length,z=1;z<F;z++)y=P(y,w[z]);return y}},s;Array.prototype.map?s=function(w,P){return w.map(P)}:s=function(w,P){for(var y=[],F=w.length,z=0;z<F;z++)y.push(P(w[z]));return y};var a;Array.prototype.filter?a=function(w,P){return w.filter(P)}:a=function(w,P){for(var y=[],F=w.length,z=0;z<F;z++)P(w[z])&&y.push(w[z]);return y};var n;String.prototype.codePointAt?n=function(w,P){return w.codePointAt(P)}:n=function(w,P){return w.charCodeAt(P)};var c;String.fromCodePoint?c=function(){return String.fromCodePoint.apply(null,arguments)}:c=function(){return String.fromCharCode.apply(null,arguments)};var f=0,p=1,h=/(\\a)|(\\b)|(\\f)|(\\n)|(\\r)|(\\t)|(\\v)|\\x([0-9a-fA-F]+)\\|\\([0-7]+)\\|(\\\\)|(\\')|('')|(\\")|(\\`)|(\\.)|(.)/g,E={"\\a":7,"\\b":8,"\\f":12,"\\n":10,"\\r":13,"\\t":9,"\\v":11};function C(w){var P=[],y=!1;return w.replace(h,function(F,z,Z,$,oe,xe,Re,lt,Ct,qt,ir,bt,gn,br,Ir,Or,nn){switch(!0){case Ct!==void 0:return P.push(parseInt(Ct,16)),"";case qt!==void 0:return P.push(parseInt(qt,8)),"";case ir!==void 0:case bt!==void 0:case gn!==void 0:case br!==void 0:case Ir!==void 0:return P.push(n(F.substr(1),0)),"";case nn!==void 0:return P.push(n(nn,0)),"";case Or!==void 0:y=!0;default:return P.push(E[F]),""}}),y?null:P}function S(w,P){var y="";if(w.length<2)return w;try{w=w.replace(/\\([0-7]+)\\/g,function($,oe){return c(parseInt(oe,8))}),w=w.replace(/\\x([0-9a-fA-F]+)\\/g,function($,oe){return c(parseInt(oe,16))})}catch{return null}for(var F=0;F<w.length;F++){var z=w.charAt(F),Z=w.charAt(F+1);if(z===P&&Z===P)F++,y+=P;else if(z==="\\")if(["a","b","f","n","r","t","v","'",'"',"\\","a","\b","\f",`
`,"\r"," ","\v"].indexOf(Z)!==-1)switch(F+=1,Z){case"a":y+="a";break;case"b":y+="\b";break;case"f":y+="\f";break;case"n":y+=`
`;break;case"r":y+="\r";break;case"t":y+=" ";break;case"v":y+="\v";break;case"'":y+="'";break;case'"':y+='"';break;case"\\":y+="\\";break}else return null;else y+=z}return y}function b(w){for(var P="",y=0;y<w.length;y++)switch(w.charAt(y)){case"'":P+="\\'";break;case"\\":P+="\\\\";break;case"\b":P+="\\b";break;case"\f":P+="\\f";break;case`
`:P+="\\n";break;case"\r":P+="\\r";break;case" ":P+="\\t";break;case"\v":P+="\\v";break;default:P+=w.charAt(y);break}return P}function I(w){var P=w.substr(2);switch(w.substr(0,2).toLowerCase()){case"0x":return parseInt(P,16);case"0b":return parseInt(P,2);case"0o":return parseInt(P,8);case"0'":return C(P)[0];default:return parseFloat(w)}}var T={whitespace:/^\s*(?:(?:%.*)|(?:\/\*(?:\n|\r|.)*?\*\/)|(?:\s+))\s*/,variable:/^(?:[A-Z_][a-zA-Z0-9_]*)/,atom:/^(\!|,|;|[a-z][0-9a-zA-Z_]*|[#\$\&\*\+\-\.\/\:\<\=\>\?\@\^\~\\]+|'(?:[^']*?(?:\\(?:x?\d+)?\\)*(?:'')*(?:\\')*)*')/,number:/^(?:0o[0-7]+|0x[0-9a-fA-F]+|0b[01]+|0'(?:''|\\[abfnrtv\\'"`]|\\x?\d+\\|[^\\])|\d+(?:\.\d+(?:[eE][+-]?\d+)?)?)/,string:/^(?:"([^"]|""|\\")*"|`([^`]|``|\\`)*`)/,l_brace:/^(?:\[)/,r_brace:/^(?:\])/,l_bracket:/^(?:\{)/,r_bracket:/^(?:\})/,bar:/^(?:\|)/,l_paren:/^(?:\()/,r_paren:/^(?:\))/};function N(w,P){return w.get_flag("char_conversion").id==="on"?P.replace(/./g,function(y){return w.get_char_conversion(y)}):P}function U(w){this.thread=w,this.text="",this.tokens=[]}U.prototype.set_last_tokens=function(w){return this.tokens=w},U.prototype.new_text=function(w){this.text=w,this.tokens=[]},U.prototype.get_tokens=function(w){var P,y=0,F=0,z=0,Z=[],$=!1;if(w){var oe=this.tokens[w-1];y=oe.len,P=N(this.thread,this.text.substr(oe.len)),F=oe.line,z=oe.start}else P=this.text;if(/^\s*$/.test(P))return null;for(;P!=="";){var xe=[],Re=!1;if(/^\n/.exec(P)!==null){F++,z=0,y++,P=P.replace(/\n/,""),$=!0;continue}for(var lt in T)if(T.hasOwnProperty(lt)){var Ct=T[lt].exec(P);Ct&&xe.push({value:Ct[0],name:lt,matches:Ct})}if(!xe.length)return this.set_last_tokens([{value:P,matches:[],name:"lexical",line:F,start:z}]);var oe=r(xe,function(br,Ir){return br.value.length>=Ir.value.length?br:Ir});switch(oe.start=z,oe.line=F,P=P.replace(oe.value,""),z+=oe.value.length,y+=oe.value.length,oe.name){case"atom":oe.raw=oe.value,oe.value.charAt(0)==="'"&&(oe.value=S(oe.value.substr(1,oe.value.length-2),"'"),oe.value===null&&(oe.name="lexical",oe.value="unknown escape sequence"));break;case"number":oe.float=oe.value.substring(0,2)!=="0x"&&oe.value.match(/[.eE]/)!==null&&oe.value!=="0'.",oe.value=I(oe.value),oe.blank=Re;break;case"string":var qt=oe.value.charAt(0);oe.value=S(oe.value.substr(1,oe.value.length-2),qt),oe.value===null&&(oe.name="lexical",oe.value="unknown escape sequence");break;case"whitespace":var ir=Z[Z.length-1];ir&&(ir.space=!0),Re=!0;continue;case"r_bracket":Z.length>0&&Z[Z.length-1].name==="l_bracket"&&(oe=Z.pop(),oe.name="atom",oe.value="{}",oe.raw="{}",oe.space=!1);break;case"r_brace":Z.length>0&&Z[Z.length-1].name==="l_brace"&&(oe=Z.pop(),oe.name="atom",oe.value="[]",oe.raw="[]",oe.space=!1);break}oe.len=y,Z.push(oe),Re=!1}var bt=this.set_last_tokens(Z);return bt.length===0?null:bt};function W(w,P,y,F,z){if(!P[y])return{type:f,value:x.error.syntax(P[y-1],"expression expected",!0)};var Z;if(F==="0"){var $=P[y];switch($.name){case"number":return{type:p,len:y+1,value:new x.type.Num($.value,$.float)};case"variable":return{type:p,len:y+1,value:new x.type.Var($.value)};case"string":var oe;switch(w.get_flag("double_quotes").id){case"atom":oe=new j($.value,[]);break;case"codes":oe=new j("[]",[]);for(var xe=$.value.length-1;xe>=0;xe--)oe=new j(".",[new x.type.Num(n($.value,xe),!1),oe]);break;case"chars":oe=new j("[]",[]);for(var xe=$.value.length-1;xe>=0;xe--)oe=new j(".",[new x.type.Term($.value.charAt(xe),[]),oe]);break}return{type:p,len:y+1,value:oe};case"l_paren":var bt=W(w,P,y+1,w.__get_max_priority(),!0);return bt.type!==p?bt:P[bt.len]&&P[bt.len].name==="r_paren"?(bt.len++,bt):{type:f,derived:!0,value:x.error.syntax(P[bt.len]?P[bt.len]:P[bt.len-1],") or operator expected",!P[bt.len])};case"l_bracket":var bt=W(w,P,y+1,w.__get_max_priority(),!0);return bt.type!==p?bt:P[bt.len]&&P[bt.len].name==="r_bracket"?(bt.len++,bt.value=new j("{}",[bt.value]),bt):{type:f,derived:!0,value:x.error.syntax(P[bt.len]?P[bt.len]:P[bt.len-1],"} or operator expected",!P[bt.len])}}var Re=ee(w,P,y,z);return Re.type===p||Re.derived||(Re=ie(w,P,y),Re.type===p||Re.derived)?Re:{type:f,derived:!1,value:x.error.syntax(P[y],"unexpected token")}}var lt=w.__get_max_priority(),Ct=w.__get_next_priority(F),qt=y;if(P[y].name==="atom"&&P[y+1]&&(P[y].space||P[y+1].name!=="l_paren")){var $=P[y++],ir=w.__lookup_operator_classes(F,$.value);if(ir&&ir.indexOf("fy")>-1){var bt=W(w,P,y,F,z);if(bt.type!==f)return $.value==="-"&&!$.space&&x.type.is_number(bt.value)?{value:new x.type.Num(-bt.value.value,bt.value.is_float),len:bt.len,type:p}:{value:new x.type.Term($.value,[bt.value]),len:bt.len,type:p};Z=bt}else if(ir&&ir.indexOf("fx")>-1){var bt=W(w,P,y,Ct,z);if(bt.type!==f)return{value:new x.type.Term($.value,[bt.value]),len:bt.len,type:p};Z=bt}}y=qt;var bt=W(w,P,y,Ct,z);if(bt.type===p){y=bt.len;var $=P[y];if(P[y]&&(P[y].name==="atom"&&w.__lookup_operator_classes(F,$.value)||P[y].name==="bar"&&w.__lookup_operator_classes(F,"|"))){var gn=Ct,br=F,ir=w.__lookup_operator_classes(F,$.value);if(ir.indexOf("xf")>-1Line truncated
`;P+=`
`;for(key in this.rules)for(y=0;y<this.rules[key].length;y++)P+=this.rules[key][y].toString(w),P+=`
`;return P},De.prototype.clone=function(){return new De(this.id)},Te.prototype.clone=function(){return new Te(this.value,this.is_float)},j.prototype.clone=function(){return new j(this.id,s(this.args,function(w){return w.clone()}))},Fe.prototype.clone=function(){return new Stram(this.stream,this.mode,this.alias,this.type,this.reposition,this.eof_action)},Ne.prototype.clone=function(){var w={};for(var P in this.links)this.links.hasOwnProperty(P)&&(w[P]=this.links[P].clone());return new Ne(w)},be.prototype.clone=function(){return new be(this.goal.clone(),this.substitution.clone(),this.parent)},Ve.prototype.clone=function(){return new Ve(this.head.clone(),this.body!==null?this.body.clone():null)},De.prototype.equals=function(w){return x.type.is_variable(w)&&this.id===w.id},Te.prototype.equals=function(w){return x.type.is_number(w)&&this.value===w.value&&this.is_float===w.is_float},j.prototype.equals=function(w){if(!x.type.is_term(w)||this.indicator!==w.indicator)return!1;for(var P=0;P<this.args.length;P++)if(!this.args[P].equals(w.args[P]))return!1;return!0},Fe.prototype.equals=function(w){return x.type.is_stream(w)&&this.id===w.id},Ne.prototype.equals=function(w){var P;if(!x.type.is_substitution(w))return!1;for(P in this.links)if(this.links.hasOwnProperty(P)&&(!w.links[P]||!this.links[P].equals(w.links[P])))return!1;for(P in w.links)if(w.links.hasOwnProperty(P)&&!this.links[P])return!1;return!0},be.prototype.equals=function(w){return x.type.is_state(w)&&this.goal.equals(w.goal)&&this.substitution.equals(w.substitution)&&this.parent===w.parent},Ve.prototype.equals=function(w){return x.type.is_rule(w)&&this.head.equals(w.head)&&(this.body===null&&w.body===null||this.body!==null&&this.body.equals(w.body))},De.prototype.rename=function(w){return w.get_free_variable(this)},Te.prototype.rename=function(w){return this},j.prototype.rename=function(w){return new j(this.id,s(this.args,function(P){return P.rename(w)}))},Fe.prototype.rename=function(w){return this},Ve.prototype.rename=function(w){return new Ve(this.head.rename(w),this.body!==null?this.body.rename(w):null)},De.prototype.variables=function(){return[this.id]},Te.prototype.variables=function(){return[]},j.prototype.variables=function(){return[].concat.apply([],s(this.args,function(w){return w.variables()}))},Fe.prototype.variables=function(){return[]},Ve.prototype.variables=function(){return this.body===null?this.head.variables():this.head.variables().concat(this.body.variables())},De.prototype.apply=function(w){return w.lookup(this.id)?w.lookup(this.id):this},Te.prototype.apply=function(w){return this},j.prototype.apply=function(w){if(this.indicator==="./2"){for(var P=[],y=this;y.indicator==="./2";)P.push(y.args[0].apply(w)),y=y.args[1];for(var F=y.apply(w),z=P.length-1;z>=0;z--)F=new j(".",[P[z],F]);return F}return new j(this.id,s(this.args,function(Z){return Z.apply(w)}),this.ref)},Fe.prototype.apply=function(w){return this},Ve.prototype.apply=function(w){return new Ve(this.head.apply(w),this.body!==null?this.body.apply(w):null)},Ne.prototype.apply=function(w){var P,y={};for(P in this.links)this.links.hasOwnProperty(P)&&(y[P]=this.links[P].apply(w));return new Ne(y)},j.prototype.select=function(){for(var w=this;w.indicator===",/2";)w=w.args[0];return w},j.prototype.replace=function(w){return this.indicator===",/2"?this.args[0].indicator===",/2"?new j(",",[this.args[0].replace(w),this.args[1]]):w===null?this.args[1]:new j(",",[w,this.args[1]]):w},j.prototype.search=function(w){if(x.type.is_term(w)&&w.ref!==void 0&&this.ref===w.ref)return!0;for(var P=0;P<this.args.length;P++)if(x.type.is_term(this.args[P])&&this.args[P].search(w))return!0;return!1},ke.prototype.get_current_input=function(){return this.current_input},it.prototype.get_current_input=function(){return this.session.get_current_input()},ke.prototype.get_current_output=function(){return this.current_output},it.prototype.get_current_output=function(){return this.session.get_current_output()},ke.prototype.set_current_input=function(w){this.current_input=w},it.prototype.set_current_input=function(w){return this.session.set_current_input(w)},ke.prototype.set_current_output=function(w){this.current_input=w},it.prototype.set_current_output=function(w){return this.session.set_current_output(w)},ke.prototype.get_stream_by_alias=function(w){return this.streams[w]},it.prototype.get_stream_by_alias=function(w){return this.session.get_stream_by_alias(w)},ke.prototype.file_system_open=function(w,P,y){return this.file_system.open(w,P,y)},it.prototype.file_system_open=function(w,P,y){return this.session.file_system_open(w,P,y)},ke.prototype.get_char_conversion=function(w){return this.__char_conversion[w]||w},it.prototype.get_char_conversion=function(w){return this.session.get_char_conversion(w)},ke.prototype.parse=function(w){return this.thread.parse(w)},it.prototype.parse=function(w){var P=new U(this);P.new_text(w);var y=P.get_tokens();if(y===null)return!1;var F=W(this,y,0,this.__get_max_priority(),!1);return F Line truncated
`,[])])])),P.substitution,P)])},"nl/1":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j("put_char",[F,new j(`
`,[])])),P.substitution,P)])},"get_byte/1":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(",",[new j("current_input",[new De("S")]),new j("get_byte",[new De("S"),F])])),P.substitution,P)])},"get_byte/2":function(w,P,y){var F=y.args[0],z=y.args[1],Z=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(x.type.is_variable(F))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_byte(z))w.throw_error(x.error.type("in_byte",char,y.indicator));else if(!x.type.is_stream(F)&&!x.type.is_atom(F))w.throw_error(x.error.domain("stream_or_alias",F,y.indicator));else if(!x.type.is_stream(Z)||Z.stream===null)w.throw_error(x.error.existence("stream",F,y.indicator));else if(Z.output)w.throw_error(x.error.permission("input","stream",F,y.indicator));else if(Z.type==="text")w.throw_error(x.error.permission("input","text_stream",F,y.indicator));else if(Z.position==="past_end_of_stream"&&Z.eof_action==="error")w.throw_error(x.error.permission("input","past_end_of_stream",F,y.indicator));else{var $;if(Z.position==="end_of_stream")$="end_of_file",Z.position="past_end_of_stream";else{if($=Z.stream.get_byte(Z.position),$===null){w.throw_error(x.error.representation("byte",y.indicator));return}Z.position++}w.prepend([new be(P.goal.replace(new j("=",[new Te($,!1),z])),P.substitution,P)])}},"peek_byte/1":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(",",[new j("current_input",[new De("S")]),new j("peek_byte",[new De("S"),F])])),P.substitution,P)])},"peek_byte/2":function(w,P,y){var F=y.args[0],z=y.args[1],Z=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(x.type.is_variable(F))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_byte(z))w.throw_error(x.error.type("in_byte",char,y.indicator));else if(!x.type.is_stream(F)&&!x.type.is_atom(F))w.throw_error(x.error.domain("stream_or_alias",F,y.indicator));else if(!x.type.is_stream(Z)||Z.stream===null)w.throw_error(x.error.existence("stream",F,y.indicator));else if(Z.output)w.throw_error(x.error.permission("input","stream",F,y.indicator));else if(Z.type==="text")w.throw_error(x.error.permission("input","text_stream",F,y.indicator));else if(Z.position==="past_end_of_stream"&&Z.eof_action==="error")w.throw_error(x.error.permission("input","past_end_of_stream",F,y.indicator));else{var $;if(Z.position==="end_of_stream")$="end_of_file",Z.position="past_end_of_stream";else if($=Z.stream.get_byte(Z.position),$===null){w.throw_error(x.error.representation("byte",y.indicator));return}w.prepend([new be(P.goal.replace(new j("=",[new Te($,!1),z])),P.substitution,P)])}},"put_byte/1":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(",",[new j("current_output",[new De("S")]),new j("put_byte",[new De("S"),F])])),P.substitution,P)])},"put_byte/2":function(w,P,y){var F=y.args[0],z=y.args[1],Z=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);x.type.is_variable(F)||x.type.is_variable(z)?w.throw_error(x.error.instantiation(y.indicator)):x.type.is_byte(z)?!x.type.is_variable(F)&&!x.type.is_stream(F)&&!x.type.is_atom(F)?w.throw_error(x.error.domain("stream_or_alias",F,y.indicator)):!x.type.is_stream(Z)||Z.stream===null?w.throw_error(x.error.existence("stream",F,y.indicator)):Z.input?w.throw_error(x.error.permission("output","stream",F,y.indicator)):Z.type==="text"?w.throw_error(x.error.permission("output","text_stream",F,y.indicator)):Z.stream.put_byte(z.value,Z.position)&&(typeof Z.position=="number"&&Z.position++,w.success(P)):w.throw_error(x.error.type("byte",z,y.indicator))},"read/1":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(",",[new j("current_input",[new De("S")]),new j("read_term",[new De("S"),F,new j("[]",[])])])),P.substitution,P)])},"read/2":function(w,P,y){var F=y.args[0],z=y.args[1];w.prepend([new be(P.goal.replace(new j("read_term",[F,z,new j("[]",[])])),P.substitution,P)])},"read_term/2":function(w,P,y){var F=y.args[0],z=y.args[1];w.prepend([new be(P.goal.replace(new j(",",[new j("current_input",[new De("S")]),new j("read_term",[new De("S"),F,z])])),P.substitution,P)])},"read_term/3":function(w,P,y){var F=y.args[0],z=y.args[1],Z=y.args[2],$=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(x.type.is_variable(F)||x.type.is_variable(Z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_list(Z))w.throw_error(x.error.type("list",Z,y.indicator));else if(!x.type.is_stream(F)&&!x.type.is_atom(F))w.throw_error(x.error.domain("stream_or_alias",F,y.indicator));else if(!x.type.is_stream($)||$.stream===null)w.throw_error(x.error.existence("stream",F,y.indicator));else if($.output)w.throw_error(x.error.permission("input","stream",F,y.indicator));else if($.type==="binary")w.throw_error(x.error.permission("input","binary_stream",F,y.indicator));else if($.position==="past_end_of_stream"&&$.eof_action==="error")w.throw_error(x.error.permission("input","past_end_of_stream",F,y.indicator));else{for(var oe={},xe=Z,Re; Line truncated
`;for(let r of this.project.workspacesByCwd.values()){let s=r.relativeCwd;e+=`workspace(${K0(s)}).
`,e+=`workspace_ident(${K0(s)}, ${K0(G.stringifyIdent(r.anchoredLocator))}).
`,e+=`workspace_version(${K0(s)}, ${K0(r.manifest.version)}).
`;for(let a of EEe)for(let n of r.manifest[a].values())e+=`workspace_has_dependency(${K0(s)}, ${K0(G.stringifyIdent(n))}, ${K0(n.range)}, ${a}).
`}return e+=`workspace(_) :- false.
`,e+=`workspace_ident(_, _) :- false.
`,e+=`workspace_version(_, _) :- false.
`,e+=`workspace_has_dependency(_, _, _, _) :- false.
`,e}getDeclarations(){let e="";return e+=`gen_enforced_dependency(_, _, _, _) :- false.
`,e+=`gen_enforced_field(_, _, _) :- false.
`,e}get fullSource(){return`${this.getProjectDatabase()}
${this.source}
${this.getDeclarations()}`}createSession(){return new Q5(this.project,this.fullSource)}async processClassic(){let e=this.createSession();return{enforcedDependencies:await this.genEnforcedDependencies(e),enforcedFields:await this.genEnforcedFields(e)}}async process(){let{enforcedDependencies:e,enforcedFields:r}=await this.processClassic(),s=new Map;for(let{workspace:a,dependencyIdent:n,dependencyRange:c,dependencyType:f}of e){let p=nS([f,G.stringifyIdent(n)]),h=je.getMapWithDefault(s,a.cwd);je.getMapWithDefault(h,p).set(c??void 0,new Set)}for(let{workspace:a,fieldPath:n,fieldValue:c}of r){let f=nS(n),p=je.getMapWithDefault(s,a.cwd);je.getMapWithDefault(p,f).set(JSON.parse(c)??void 0,new Set)}return{manifestUpdates:s,reportedErrors:new Map}}async genEnforcedDependencies(e){let r=[];for await(let s of e.makeQuery("workspace(WorkspaceCwd), dependency_type(DependencyType), gen_enforced_dependency(WorkspaceCwd, DependencyIdent, DependencyRange, DependencyType).")){let a=J.resolve(this.project.cwd,bm(s.links.WorkspaceCwd)),n=bm(s.links.DependencyIdent),c=bm(s.links.DependencyRange),f=bm(s.links.DependencyType);if(a===null||n===null)throw new Error("Invalid rule");let p=this.project.getWorkspaceByCwd(a),h=G.parseIdent(n);r.push({workspace:p,dependencyIdent:h,dependencyRange:c,dependencyType:f})}return je.sortMap(r,[({dependencyRange:s})=>s!==null?"0":"1",({workspace:s})=>G.stringifyIdent(s.anchoredLocator),({dependencyIdent:s})=>G.stringifyIdent(s)])}async genEnforcedFields(e){let r=[];for await(let s of e.makeQuery("workspace(WorkspaceCwd), gen_enforced_field(WorkspaceCwd, FieldPath, FieldValue).")){let a=J.resolve(this.project.cwd,bm(s.links.WorkspaceCwd)),n=bm(s.links.FieldPath),c=Wct(s.links.FieldValue);if(a===null||n===null)throw new Error("Invalid rule");let f=this.project.getWorkspaceByCwd(a);r.push({workspace:f,fieldPath:n,fieldValue:c})}return je.sortMap(r,[({workspace:s})=>G.stringifyIdent(s.anchoredLocator),({fieldPath:s})=>s])}async*query(e){let r=this.createSession();for await(let s of r.makeQuery(e)){let a={};for(let[n,c]of Object.entries(s.links))n!=="_"&&(a[n]=bm(c));yield a}}}});var QEe=_(uF=>{"use strict";Object.defineProperty(uF,"__esModule",{value:!0});function BS(t){let e=[...t.caches],r=e.shift();return r===void 0?kEe():{get(s,a,n={miss:()=>Promise.resolve()}){return r.get(s,a,n).catch(()=>BS({caches:e}).get(s,a,n))},set(s,a){return r.set(s,a).catch(()=>BS({caches:e}).set(s,a))},delete(s){return r.delete(s).catch(()=>BS({caches:e}).delete(s))},clear(){return r.clear().catch(()=>BS({caches:e}).clear())}}}function kEe(){return{get(t,e,r={miss:()=>Promise.resolve()}){return e().then(a=>Promise.all([a,r.miss(a)])).then(([a])=>a)},set(t,e){return Promise.resolve(e)},delete(t){return Promise.resolve()},clear(){return Promise.resolve()}}}uF.createFallbackableCache=BS;uF.createNullCache=kEe});var TEe=_((iJt,REe)=>{REe.exports=QEe()});var FEe=_(Y5=>{"use strict";Object.defineProperty(Y5,"__esModule",{value:!0});function uut(t={serializable:!0}){let e={};return{get(r,s,a={miss:()=>Promise.resolve()}){let n=JSON.stringify(r);if(n in e)return Promise.resolve(t.serializable?JSON.parse(e[n]):e[n]);let c=s(),f=a&&a.miss||(()=>Promise.resolve());return c.then(p=>f(p)).then(()=>c)},set(r,s){return e[JSON.stringify(r)]=t.serializable?JSON.stringify(s):s,Promise.resolve(s)},delete(r){return delete e[JSON.stringify(r)],Promise.resolve()},clear(){return e={},Promise.resolve()}}}Y5.createInMemoryCache=uut});var OEe=_((oJt,NEe)=>{NEe.exports=FEe()});var MEe=_($u=>{"use strict";Object.defineProperty($u,"__esModule",{value:!0});function fut(t,e,r){let s={"x-algolia-api-key":r,"x-algolia-application-id":e};return{headers(){return t===V5.WithinHeaders?s:{}},queryParameters(){return t===V5.WithinQueryParameters?s:{}}}}function Aut(t){let e=0,r=()=>(e++,new Promise(s=>{setTimeout(()=>{s(t(r))},Math.min(100*e,1e3))}));return t(r)}function LEe(t,e=(r,s)=>Promise.resolve()){return Object.assign(t,{wait(r){return LEe(t.then(s=>Promise.all([e(s,r),s])).then(s=>s[1]))}})}function put(t){let e=t.length-1;for(e;e>0;e--){let r=Math.floor(Math.random()*(e+1)),s=t[e];t[e]=t[r],t[r]=s}return t}function hut(t,e){return e&&Object.keys(e).forEach(r=>{t[r]=e[r](t)}),t}function gut(t,...e){let r=0;return t.replace(/%s/g,()=>encodeURIComponent(e[r++]))}var dut="4.22.1",mut=t=>()=>t.transporter.requester.destroy(),V5={WithinQueryParameters:0,WithinHeaders:1};$u.AuthMode=V5;$u.addMethods=hut;$u.createAuth=fut;$u.createRetryablePromise=Aut;$u.createWaitablePromise=LEe;$u.destroy=mut;$u.encode=gut;$u.shuffle=put;$u.version=dut});var vS=_((lJt,UEe)=>{UEe.exports=MEe()});var _Ee=_(J5=>{"use strict";Object.defineProperty(J5,"__esModule",{value:!0});var yut={Delete:"DELETE",Get:"GET",Post:"POST",Put:"PUT"};J5.MethodEnum=yut});var SS=_((uJt,HEe)=>{HEe.exports=_Ee()});var rIe=_(Wi=>{"use strict";Object.defineProperty(Wi,"__esModule",{value:!0});var GEe=SS();function K5(t,e){let r=t||{},s=r.data||{};return Object.keys(r).forEach(a=>{["timeout","head Line truncated
`;f!==s&&(s=f,t.write($Ce.default.eraseLines(r)+f),r=f.split(`
`).length)};return n.clear=()=>{t.write($Ce.default.eraseLines(r)),s="",r=0},n.done=()=>{s="",r=0,e||(ewe.default.show(),a=!1)},n};LS.default={create:Apt}});var nwe=_((XJt,ppt)=>{ppt.exports=[{name:"AppVeyor",constant:"APPVEYOR",env:"APPVEYOR",pr:"APPVEYOR_PULL_REQUEST_NUMBER"},{name:"Azure Pipelines",constant:"AZURE_PIPELINES",env:"SYSTEM_TEAMFOUNDATIONCOLLECTIONURI",pr:"SYSTEM_PULLREQUEST_PULLREQUESTID"},{name:"Bamboo",constant:"BAMBOO",env:"bamboo_planKey"},{name:"Bitbucket Pipelines",constant:"BITBUCKET",env:"BITBUCKET_COMMIT",pr:"BITBUCKET_PR_ID"},{name:"Bitrise",constant:"BITRISE",env:"BITRISE_IO",pr:"BITRISE_PULL_REQUEST"},{name:"Buddy",constant:"BUDDY",env:"BUDDY_WORKSPACE_ID",pr:"BUDDY_EXECUTION_PULL_REQUEST_ID"},{name:"Buildkite",constant:"BUILDKITE",env:"BUILDKITE",pr:{env:"BUILDKITE_PULL_REQUEST",ne:"false"}},{name:"CircleCI",constant:"CIRCLE",env:"CIRCLECI",pr:"CIRCLE_PULL_REQUEST"},{name:"Cirrus CI",constant:"CIRRUS",env:"CIRRUS_CI",pr:"CIRRUS_PR"},{name:"AWS CodeBuild",constant:"CODEBUILD",env:"CODEBUILD_BUILD_ARN"},{name:"Codeship",constant:"CODESHIP",env:{CI_NAME:"codeship"}},{name:"Drone",constant:"DRONE",env:"DRONE",pr:{DRONE_BUILD_EVENT:"pull_request"}},{name:"dsari",constant:"DSARI",env:"DSARI"},{name:"GitLab CI",constant:"GITLAB",env:"GITLAB_CI"},{name:"GoCD",constant:"GOCD",env:"GO_PIPELINE_LABEL"},{name:"Hudson",constant:"HUDSON",env:"HUDSON_URL"},{name:"Jenkins",constant:"JENKINS",env:["JENKINS_URL","BUILD_ID"],pr:{any:["ghprbPullId","CHANGE_ID"]}},{name:"Magnum CI",constant:"MAGNUM",env:"MAGNUM"},{name:"Netlify CI",constant:"NETLIFY",env:"NETLIFY_BUILD_BASE",pr:{env:"PULL_REQUEST",ne:"false"}},{name:"Sail CI",constant:"SAIL",env:"SAILCI",pr:"SAIL_PULL_REQUEST_NUMBER"},{name:"Semaphore",constant:"SEMAPHORE",env:"SEMAPHORE",pr:"PULL_REQUEST_NUMBER"},{name:"Shippable",constant:"SHIPPABLE",env:"SHIPPABLE",pr:{IS_PULL_REQUEST:"true"}},{name:"Solano CI",constant:"SOLANO",env:"TDDIUM",pr:"TDDIUM_PR_ID"},{name:"Strider CD",constant:"STRIDER",env:"STRIDER"},{name:"TaskCluster",constant:"TASKCLUSTER",env:["TASK_ID","RUN_ID"]},{name:"TeamCity",constant:"TEAMCITY",env:"TEAMCITY_VERSION"},{name:"Travis CI",constant:"TRAVIS",env:"TRAVIS",pr:{env:"TRAVIS_PULL_REQUEST",ne:"false"}}]});var owe=_(tc=>{"use strict";var swe=nwe(),uA=process.env;Object.defineProperty(tc,"_vendors",{value:swe.map(function(t){return t.constant})});tc.name=null;tc.isPR=null;swe.forEach(function(t){var e=Array.isArray(t.env)?t.env:[t.env],r=e.every(function(s){return iwe(s)});if(tc[t.constant]=r,r)switch(tc.name=t.name,typeof t.pr){case"string":tc.isPR=!!uA[t.pr];break;case"object":"env"in t.pr?tc.isPR=t.pr.env in uA&&uA[t.pr.env]!==t.pr.ne:"any"in t.pr?tc.isPR=t.pr.any.some(function(s){return!!uA[s]}):tc.isPR=iwe(t.pr);break;default:tc.isPR=null}});tc.isCI=!!(uA.CI||uA.CONTINUOUS_INTEGRATION||uA.BUILD_NUMBER||uA.RUN_ID||tc.name);function iwe(t){return typeof t=="string"?!!uA[t]:Object.keys(t).every(function(e){return uA[e]===t[e]})}});var lwe=_((eKt,awe)=>{"use strict";awe.exports=owe().isCI});var uwe=_((tKt,cwe)=>{"use strict";var hpt=t=>{let e=new Set;do for(let r of Reflect.ownKeys(t))e.add([t,r]);while((t=Reflect.getPrototypeOf(t))&&t!==Object.prototype);return e};cwe.exports=(t,{include:e,exclude:r}={})=>{let s=a=>{let n=c=>typeof c=="string"?a===c:c.test(a);return e?e.some(n):r?!r.some(n):!0};for(let[a,n]of hpt(t.constructor.prototype)){if(n==="constructor"||!s(n))continue;let c=Reflect.getOwnPropertyDescriptor(a,n);c&&typeof c.value=="function"&&(t[n]=t[n].bind(t))}return t}});var dwe=_(Vn=>{"use strict";var mw,_S,kF,F9;typeof performance=="object"&&typeof performance.now=="function"?(fwe=performance,Vn.unstable_now=function(){return fwe.now()}):(b9=Date,Awe=b9.now(),Vn.unstable_now=function(){return b9.now()-Awe});var fwe,b9,Awe;typeof window>"u"||typeof MessageChannel!="function"?(dw=null,x9=null,k9=function(){if(dw!==null)try{var t=Vn.unstable_now();dw(!0,t),dw=null}catch(e){throw setTimeout(k9,0),e}},mw=function(t){dw!==null?setTimeout(mw,0,t):(dw=t,setTimeout(k9,0))},_S=function(t,e){x9=setTimeout(t,e)},kF=function(){clearTimeout(x9)},Vn.unstable_shouldYield=function(){return!1},F9=Vn.unstable_forceFrameRate=function(){}):(pwe=window.setTimeout,hwe=window.clearTimeout,typeof console<"u"&&(gwe=window.cancelAnimationFrame,typeof window.requestAnimationFrame!="function"&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills"),typeof gwe!="function"&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills")),MS=!1,US=null,PF=-1,Q9=5,R9=0,Vn.unstable_shouldYield=function(){return Vn.unstable_now()>=R9},F9=function(){},Vn.unstable_forceFrameRate=function(t){0>t||125<t?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):Q9=0<t?Math Line truncated
`+fu+v}var ve=!1;function Nt(v,D){if(!v||ve)return"";ve=!0;var Q=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(D)if(D=function(){throw Error()},Object.defineProperty(D.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(D,[])}catch(pt){var H=pt}Reflect.construct(v,[],D)}else{try{D.call()}catch(pt){H=pt}v.call(D.prototype)}else{try{throw Error()}catch(pt){H=pt}v()}}catch(pt){if(pt&&H&&typeof pt.stack=="string"){for(var V=pt.stack.split(`
`),ne=H.stack.split(`
`),Se=V.length-1,_e=ne.length-1;1<=Se&&0<=_e&&V[Se]!==ne[_e];)_e--;for(;1<=Se&&0<=_e;Se--,_e--)if(V[Se]!==ne[_e]){if(Se!==1||_e!==1)do if(Se--,_e--,0>_e||V[Se]!==ne[_e])return`
`+V[Se].replace(" at new "," at ");while(1<=Se&&0<=_e);break}}}finally{ve=!1,Error.prepareStackTrace=Q}return(v=v?v.displayName||v.name:"")?oc(v):""}var ac=[],Oi=-1;function no(v){return{current:v}}function Tt(v){0>Oi||(v.current=ac[Oi],ac[Oi]=null,Oi--)}function xn(v,D){Oi++,ac[Oi]=v.current,v.current=D}var la={},ji=no(la),Li=no(!1),Na=la;function dn(v,D){var Q=v.type.contextTypes;if(!Q)return la;var H=v.stateNode;if(H&&H.__reactInternalMemoizedUnmaskedChildContext===D)return H.__reactInternalMemoizedMaskedChildContext;var V={},ne;for(ne in Q)V[ne]=D[ne];return H&&(v=v.stateNode,v.__reactInternalMemoizedUnmaskedChildContext=D,v.__reactInternalMemoizedMaskedChildContext=V),V}function Kn(v){return v=v.childContextTypes,v!=null}function Au(){Tt(Li),Tt(ji)}function yh(v,D,Q){if(ji.current!==la)throw Error(c(168));xn(ji,D),xn(Li,Q)}function Oa(v,D,Q){var H=v.stateNode;if(v=D.childContextTypes,typeof H.getChildContext!="function")return Q;H=H.getChildContext();for(var V in H)if(!(V in v))throw Error(c(108,g(D)||"Unknown",V));return s({},Q,H)}function La(v){return v=(v=v.stateNode)&&v.__reactInternalMemoizedMergedChildContext||la,Na=ji.current,xn(ji,v),xn(Li,Li.current),!0}function Ma(v,D,Q){var H=v.stateNode;if(!H)throw Error(c(169));Q?(v=Oa(v,D,Na),H.__reactInternalMemoizedMergedChildContext=v,Tt(Li),Tt(ji),xn(ji,v)):Tt(Li),xn(Li,Q)}var $e=null,Ua=null,hf=n.unstable_now;hf();var lc=0,wn=8;function ca(v){if(1&v)return wn=15,1;if(2&v)return wn=14,2;if(4&v)return wn=13,4;var D=24&v;return D!==0?(wn=12,D):v&32?(wn=11,32):(D=192&v,D!==0?(wn=10,D):v&256?(wn=9,256):(D=3584&v,D!==0?(wn=8,D):v&4096?(wn=7,4096):(D=4186112&v,D!==0?(wn=6,D):(D=62914560&v,D!==0?(wn=5,D):v&67108864?(wn=4,67108864):v&134217728?(wn=3,134217728):(D=805306368&v,D!==0?(wn=2,D):1073741824&v?(wn=1,1073741824):(wn=8,v))))))}function LA(v){switch(v){case 99:return 15;case 98:return 10;case 97:case 96:return 8;case 95:return 2;default:return 0}}function MA(v){switch(v){case 15:case 14:return 99;case 13:case 12:case 11:case 10:return 98;case 9:case 8:case 7:case 6:case 4:case 5:return 97;case 3:case 2:case 1:return 95;case 0:return 90;default:throw Error(c(358,v))}}function ua(v,D){var Q=v.pendingLanes;if(Q===0)return wn=0;var H=0,V=0,ne=v.expiredLanes,Se=v.suspendedLanes,_e=v.pingedLanes;if(ne!==0)H=ne,V=wn=15;else if(ne=Q&134217727,ne!==0){var pt=ne&~Se;pt!==0?(H=ca(pt),V=wn):(_e&=ne,_e!==0&&(H=ca(_e),V=wn))}else ne=Q&~Se,ne!==0?(H=ca(ne),V=wn):_e!==0&&(H=ca(_e),V=wn);if(H===0)return 0;if(H=31-rs(H),H=Q&((0>H?0:1<<H)<<1)-1,D!==0&&D!==H&&!(D&Se)){if(ca(D),V<=wn)return D;wn=V}if(D=v.entangledLanes,D!==0)for(v=v.entanglements,D&=H;0<D;)Q=31-rs(D),V=1<<Q,H|=v[Q],D&=~V;return H}function Bl(v){return v=v.pendingLanes&-1073741825,v!==0?v:v&1073741824?1073741824:0}function Mt(v,D){switch(v){case 15:return 1;case 14:return 2;case 12:return v=kn(24&~D),v===0?Mt(10,D):v;case 10:return v=kn(192&~D),v===0?Mt(8,D):v;case 8:return v=kn(3584&~D),v===0&&(v=kn(4186112&~D),v===0&&(v=512)),v;case 2:return D=kn(805306368&~D),D===0&&(D=268435456),D}throw Error(c(358,v))}function kn(v){return v&-v}function fa(v){for(var D=[],Q=0;31>Q;Q++)D.push(v);return D}function Ha(v,D,Q){v.pendingLanes|=D;var H=D-1;v.suspendedLanes&=H,v.pingedLanes&=H,v=v.eventTimes,D=31-rs(D),v[D]=Q}var rs=Math.clz32?Math.clz32:uc,cc=Math.log,pu=Math.LN2;function uc(v){return v===0?32:31-(cc(v)/pu|0)|0}var ja=n.unstable_runWithPriority,Mi=n.unstable_scheduleCallback,Is=n.unstable_cancelCallback,vl=n.unstable_shouldYield,gf=n.unstable_requestPaint,fc=n.unstable_now,wi=n.unstable_getCurrentPriorityLevel,Qn=n.unstable_ImmediatePriority,Ac=n.unstable_UserBlockingPriority,Ke=n.unstable_NormalPriority,st=n.unstable_LowPriority,St=n.unstable_IdlePriority,lr={},te=gf!==void 0?gf:function(){},Ee=null,Oe=null,dt=!1,Et=fc(),Pt=1e4>Et?fc:function(){return fc()-Et};function tr(){switch(wi()){case Qn:return 99;case Ac:return 98;case Ke:return 97;case st:return 96;case St:return 95;default:throw Error(c(332))}}function An(v){switch(v){case 99:return Qn;case 98:return Ac;case 97:return Ke;case 96:return st;case 95:return St;default:throw Error(c(332))}}function li(v,D){return v=An(v),ja(v,D)}function Gi(v,D,Q){return v=An(v),Mi(v,D,Q)}function Rn(){if(Oe!==null){var v=Oe;Oe=null,Is(v)}Ga()}function Ga(){if(!dt&&Ee!==null){dt=!0;var v=0;try{var D=Ee;li(99,function(){for(;v<D.length;v++){var Q=D[v];do Q=Q(!0);while(Q!==null)}}),Ee=null}catch(Q){throw Ee!==null&&(Ee=Ee.slice(v+1)),Mi(Qn,Rn),Q}finally{dt=!1}}}var my=f.ReactCurrentBatchConfig;function X1(v,D){return v===D&&(v!==0||1/v===1/D)||v!==v&&D!==D}var vo=typeof Object.is=="function"?Object.is:X1,yy=Object.prototype.hasOwnProperty;function Eh(v,D){if(vo(v,D))return!0;if(typeof v!="object"||v===null||typeof D!="object"||D===null)return!1;var Q=Object.keys(v),H=Object.keys(D);if(Q.length!==H.length)return!1;for(H=0;H<Q.length;H++)if(!yy.call(D,Q[H])||!vo(v[Q[H]],D[Q[H]]))return!1;return!0}function $1(v){switch(v.tag){case 5:return oc(v.type);case 16:return oc("Lazy" Line truncated
Error generating stack: `+ne.message+`
`+ne.stack}return{value:v,source:D,stack:V}}function Vg(v,D){try{console.error(D.value)}catch(Q){setTimeout(function(){throw Q})}}var qL=typeof WeakMap=="function"?WeakMap:Map;function i2(v,D,Q){Q=Dl(-1,Q),Q.tag=3,Q.payload={element:null};var H=D.value;return Q.callback=function(){_y||(_y=!0,y2=H),Vg(v,D)},Q}function Jg(v,D,Q){Q=Dl(-1,Q),Q.tag=3;var H=v.type.getDerivedStateFromError;if(typeof H=="function"){var V=D.value;Q.payload=function(){return Vg(v,D),H(V)}}var ne=v.stateNode;return ne!==null&&typeof ne.componentDidCatch=="function"&&(Q.callback=function(){typeof H!="function"&&(hc===null?hc=new Set([this]):hc.add(this),Vg(v,D));var Se=D.stack;this.componentDidCatch(D.value,{componentStack:Se!==null?Se:""})}),Q}var WL=typeof WeakSet=="function"?WeakSet:Set;function s2(v){var D=v.ref;if(D!==null)if(typeof D=="function")try{D(null)}catch(Q){xf(v,Q)}else D.current=null}function xy(v,D){switch(D.tag){case 0:case 11:case 15:case 22:return;case 1:if(D.flags&256&&v!==null){var Q=v.memoizedProps,H=v.memoizedState;v=D.stateNode,D=v.getSnapshotBeforeUpdate(D.elementType===D.type?Q:So(D.type,Q),H),v.__reactInternalSnapshotBeforeUpdate=D}return;case 3:F&&D.flags&256&&Rs(D.stateNode.containerInfo);return;case 5:case 6:case 4:case 17:return}throw Error(c(163))}function Rh(v,D){if(D=D.updateQueue,D=D!==null?D.lastEffect:null,D!==null){var Q=D=D.next;do{if((Q.tag&v)===v){var H=Q.destroy;Q.destroy=void 0,H!==void 0&&H()}Q=Q.next}while(Q!==D)}}function ub(v,D,Q){switch(Q.tag){case 0:case 11:case 15:case 22:if(D=Q.updateQueue,D=D!==null?D.lastEffect:null,D!==null){v=D=D.next;do{if((v.tag&3)===3){var H=v.create;v.destroy=H()}v=v.next}while(v!==D)}if(D=Q.updateQueue,D=D!==null?D.lastEffect:null,D!==null){v=D=D.next;do{var V=v;H=V.next,V=V.tag,V&4&&V&1&&(vb(Q,v),eM(Q,v)),v=H}while(v!==D)}return;case 1:v=Q.stateNode,Q.flags&4&&(D===null?v.componentDidMount():(H=Q.elementType===Q.type?D.memoizedProps:So(Q.type,D.memoizedProps),v.componentDidUpdate(H,D.memoizedState,v.__reactInternalSnapshotBeforeUpdate))),D=Q.updateQueue,D!==null&&Cy(Q,D,v);return;case 3:if(D=Q.updateQueue,D!==null){if(v=null,Q.child!==null)switch(Q.child.tag){case 5:v=Te(Q.child.stateNode);break;case 1:v=Q.child.stateNode}Cy(Q,D,v)}return;case 5:v=Q.stateNode,D===null&&Q.flags&4&&$s(v,Q.type,Q.memoizedProps,Q);return;case 6:return;case 4:return;case 12:return;case 13:Z&&Q.memoizedState===null&&(Q=Q.alternate,Q!==null&&(Q=Q.memoizedState,Q!==null&&(Q=Q.dehydrated,Q!==null&&uu(Q))));return;case 19:case 17:case 20:case 21:case 23:case 24:return}throw Error(c(163))}function fb(v,D){if(F)for(var Q=v;;){if(Q.tag===5){var H=Q.stateNode;D?dh(H):to(Q.stateNode,Q.memoizedProps)}else if(Q.tag===6)H=Q.stateNode,D?mh(H):jn(H,Q.memoizedProps);else if((Q.tag!==23&&Q.tag!==24||Q.memoizedState===null||Q===v)&&Q.child!==null){Q.child.return=Q,Q=Q.child;continue}if(Q===v)break;for(;Q.sibling===null;){if(Q.return===null||Q.return===v)return;Q=Q.return}Q.sibling.return=Q.return,Q=Q.sibling}}function ky(v,D){if(Ua&&typeof Ua.onCommitFiberUnmount=="function")try{Ua.onCommitFiberUnmount($e,D)}catch{}switch(D.tag){case 0:case 11:case 14:case 15:case 22:if(v=D.updateQueue,v!==null&&(v=v.lastEffect,v!==null)){var Q=v=v.next;do{var H=Q,V=H.destroy;if(H=H.tag,V!==void 0)if(H&4)vb(D,Q);else{H=D;try{V()}catch(ne){xf(H,ne)}}Q=Q.next}while(Q!==v)}break;case 1:if(s2(D),v=D.stateNode,typeof v.componentWillUnmount=="function")try{v.props=D.memoizedProps,v.state=D.memoizedState,v.componentWillUnmount()}catch(ne){xf(D,ne)}break;case 5:s2(D);break;case 4:F?gb(v,D):z&&z&&(D=D.stateNode.containerInfo,v=ou(D),RA(D,v))}}function Ab(v,D){for(var Q=D;;)if(ky(v,Q),Q.child===null||F&&Q.tag===4){if(Q===D)break;for(;Q.sibling===null;){if(Q.return===null||Q.return===D)return;Q=Q.return}Q.sibling.return=Q.return,Q=Q.sibling}else Q.child.return=Q,Q=Q.child}function Qy(v){v.alternate=null,v.child=null,v.dependencies=null,v.firstEffect=null,v.lastEffect=null,v.memoizedProps=null,v.memoizedState=null,v.pendingProps=null,v.return=null,v.updateQueue=null}function pb(v){return v.tag===5||v.tag===3||v.tag===4}function hb(v){if(F){e:{for(var D=v.return;D!==null;){if(pb(D))break e;D=D.return}throw Error(c(160))}var Q=D;switch(D=Q.stateNode,Q.tag){case 5:var H=!1;break;case 3:D=D.containerInfo,H=!0;break;case 4:D=D.containerInfo,H=!0;break;default:throw Error(c(161))}Q.flags&16&&(Af(D),Q.flags&=-17);e:t:for(Q=v;;){for(;Q.sibling===null;){if(Q.return===null||pb(Q.return)){Q=null;break e}Q=Q.return}for(Q.sibling.return=Q.return,Q=Q.sibling;Q.tag!==5&&Q.tag!==6&&Q.tag!==18;){if(Q.flags&2||Q.child===null||Q.tag===4)continue t;Q.child.return=Q,Q=Q.child}if(!(Q.flags&2)){Q=Q.stateNode;break e}}H?o2(v,Q,D):a2(v,Q,D)}}function o2(v,D,Q){var H=v.tag,V=H===5||H===6;if(V)v=V?v.stateNode:v.stateNode.instance,D?eo(Q,v,D):Io(Q,v);else if(H!==4&&(v=v.child,v!==null))for(o2(v,D,Q),v=v.sibling;v!==null;)o2(v,D,Q),v=v.sibling}function a2(v,D,Q){var H=v.tag,V=H===5||H===6;if(V)v=V?v.stateNode:v.stateNode.instance,D?Hi(Q,v,D):ai(Q,v);els Line truncated
Add a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.`)}ws!==5&&(ws=2),pt=Yg(pt,_e),Xt=Se;do{switch(Xt.tag){case 3:ne=pt,Xt.flags|=4096,D&=-D,Xt.lanes|=D;var Xn=i2(Xt,ne,D);Iy(Xt,Xn);break e;case 1:ne=pt;var kr=Xt.type,Tn=Xt.stateNode;if(!(Xt.flags&64)&&(typeof kr.getDerivedStateFromError=="function"||Tn!==null&&typeof Tn.componentDidCatch=="function"&&(hc===null||!hc.has(Tn)))){Xt.flags|=4096,D&=-D,Xt.lanes|=D;var _n=Jg(Xt,ne,D);Iy(Xt,_n);break e}}Xt=Xt.return}while(Xt!==null)}Bb(Q)}catch(zr){D=zr,zi===Q&&Q!==null&&(zi=Q=Q.return);continue}break}while(!0)}function Cb(){var v=My.current;return My.current=kt,v===null?kt:v}function id(v,D){var Q=xr;xr|=16;var H=Cb();so===v&&Ns===D||Oh(v,D);do try{zL();break}catch(V){Ib(v,V)}while(!0);if(Fg(),xr=Q,My.current=H,zi!==null)throw Error(c(261));return so=null,Ns=0,ws}function zL(){for(;zi!==null;)wb(zi)}function ZL(){for(;zi!==null&&!vl();)wb(zi)}function wb(v){var D=Pb(v.alternate,v,XA);v.memoizedProps=v.pendingProps,D===null?Bb(v):zi=D,f2.current=null}function Bb(v){var D=v;do{var Q=D.alternate;if(v=D.return,D.flags&2048){if(Q=jL(D),Q!==null){Q.flags&=2047,zi=Q;return}v!==null&&(v.firstEffect=v.lastEffect=null,v.flags|=2048)}else{if(Q=HL(Q,D,XA),Q!==null){zi=Q;return}if(Q=D,Q.tag!==24&&Q.tag!==23||Q.memoizedState===null||XA&1073741824||!(Q.mode&4)){for(var H=0,V=Q.child;V!==null;)H|=V.lanes|V.childLanes,V=V.sibling;Q.childLanes=H}v!==null&&!(v.flags&2048)&&(v.firstEffect===null&&(v.firstEffect=D.firstEffect),D.lastEffect!==null&&(v.lastEffect!==null&&(v.lastEffect.nextEffect=D.firstEffect),v.lastEffect=D.lastEffect),1<D.flags&&(v.lastEffect!==null?v.lastEffect.nextEffect=D:v.firstEffect=D,v.lastEffect=D))}if(D=D.sibling,D!==null){zi=D;return}zi=D=v}while(D!==null);ws===0&&(ws=5)}function $A(v){var D=tr();return li(99,XL.bind(null,v,D)),null}function XL(v,D){do vu();while($g!==null);if(xr&48)throw Error(c(327));var Q=v.finishedWork;if(Q===null)return null;if(v.finishedWork=null,v.finishedLanes=0,Q===v.current)throw Error(c(177));v.callbackNode=null;var H=Q.lanes|Q.childLanes,V=H,ne=v.pendingLanes&~V;v.pendingLanes=V,v.suspendedLanes=0,v.pingedLanes=0,v.expiredLanes&=V,v.mutableReadLanes&=V,v.entangledLanes&=V,V=v.entanglements;for(var Se=v.eventTimes,_e=v.expirationTimes;0<ne;){var pt=31-rs(ne),Wt=1<<pt;V[pt]=0,Se[pt]=-1,_e[pt]=-1,ne&=~Wt}if(wu!==null&&!(H&24)&&wu.has(v)&&wu.delete(v),v===so&&(zi=so=null,Ns=0),1<Q.flags?Q.lastEffect!==null?(Q.lastEffect.nextEffect=Q,H=Q.firstEffect):H=Q:H=Q.firstEffect,H!==null){V=xr,xr|=32,f2.current=null,rd=rt(v.containerInfo),nd=!1,sr=H;do try{$L()}catch(qe){if(sr===null)throw Error(c(330));xf(sr,qe),sr=sr.nextEffect}while(sr!==null);rd=null,sr=H;do try{for(Se=v;sr!==null;){var Sr=sr.flags;if(Sr&16&&F&&Af(sr.stateNode),Sr&128){var Lr=sr.alternate;if(Lr!==null){var Xt=Lr.ref;Xt!==null&&(typeof Xt=="function"?Xt(null):Xt.current=null)}}switch(Sr&1038){case 2:hb(sr),sr.flags&=-3;break;case 6:hb(sr),sr.flags&=-3,l2(sr.alternate,sr);break;case 1024:sr.flags&=-1025;break;case 1028:sr.flags&=-1025,l2(sr.alternate,sr);break;case 4:l2(sr.alternate,sr);break;case 8:_e=Se,ne=sr,F?gb(_e,ne):Ab(_e,ne);var zn=ne.alternate;Qy(ne),zn!==null&&Qy(zn)}sr=sr.nextEffect}}catch(qe){if(sr===null)throw Error(c(330));xf(sr,qe),sr=sr.nextEffect}while(sr!==null);nd&&lt(),Fe(v.containerInfo),v.current=Q,sr=H;do try{for(Sr=v;sr!==null;){var yi=sr.flags;if(yi&36&&ub(Sr,sr.alternate,sr),yi&128){Lr=void 0;var za=sr.ref;if(za!==null){var et=sr.stateNode;switch(sr.tag){case 5:Lr=Te(et);break;default:Lr=et}typeof za=="function"?za(Lr):za.current=Lr}}sr=sr.nextEffect}}catch(qe){if(sr===null)throw Error(c(330));xf(sr,qe),sr=sr.nextEffect}while(sr!==null);sr=null,te(),xr=V}else v.current=Q;if(bf)bf=!1,$g=v,ed=D;else for(sr=H;sr!==null;)D=sr.nextEffect,sr.nextEffect=null,sr.flags&8&&(yi=sr,yi.sibling=null,yi.stateNode=null),sr=D;if(H=v.pendingLanes,H===0&&(hc=null),H===1?v===C2?td++:(td=0,C2=v):td=0,Q=Q.stateNode,Ua&&typeof Ua.onCommitFiberRoot=="function")try{Ua.onCommitFiberRoot($e,Q,void 0,(Q.current.flags&64)===64)}catch{}if(ga(v,Pt()),_y)throw _y=!1,v=y2,y2=null,v;return xr&8||Rn(),null}function $L(){for(;sr!==null;){var v=sr.alternate;nd||rd===null||(sr.flags&8?De(sr,rd)&&(nd=!0,Re()):sr.tag===13&&YL(v,sr)&&De(sr,rd)&&(nd=!0,Re()));var D=sr.flags;D&256&&xy(v,sr),!(D&512)||bf||(bf=!0,Gi(97,function(){return vu(),null})),sr=sr.nextEffect}}function vu(){if(ed!==90){var v=97<ed?97:ed;return ed=90,li(v,tM)}return!1}function eM(v,D){E2.push(D,v),bf||(bf=!0,Gi(97,function(){return vu(),null}))}function vb(v,D){I2.push(D,v),bf||(bf=!0,Gi(97,function(){return vu(),null}))}function tM(){if($g===null)return!1;var v=$g;if($g=null,xr&48)throw Error(c(331));var D=xr;xr|=32;var Q=I2;I2=[];for(var H=0;H<Q.length;H+=2){var V=Q[H],ne=Q[H+1],Se=V.destroy;if(V.destroy=void 0,typeof Se=="function")try{Se()}catch(pt){if(ne===null)throw Error(c(330));xf(ne,pt)}}for(Q=E2,E2=[],H=0;H<Q.length;H+=2){V=Q[H],ne=Q[H+1];try{va Line truncated
`+(H.join(" > ")+`
No matching component was found for:
`)+v.join(" > ")}return null},r.getPublicRootInstance=function(v){if(v=v.current,!v.child)return null;switch(v.child.tag){case 5:return Te(v.child.stateNode);default:return v.child.stateNode}},r.injectIntoDevTools=function(v){if(v={bundleType:v.bundleType,version:v.version,rendererPackageName:v.rendererPackageName,rendererConfig:v.rendererConfig,overrideHookState:null,overrideHookStateDeletePath:null,overrideHookStateRenamePath:null,overrideProps:null,overridePropsDeletePath:null,overridePropsRenamePath:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:f.ReactCurrentDispatcher,findHostInstanceByFiber:oM,findFiberByHostInstance:v.findFiberByHostInstance||aM,findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null},typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u")v=!1;else{var D=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(!D.isDisabled&&D.supportsFiber)try{$e=D.inject(v),Ua=D}catch{}v=!0}return v},r.observeVisibleRects=function(v,D,Q,H){if(!qt)throw Error(c(363));v=u2(v,D);var V=nn(v,Q,H).disconnect;return{disconnect:function(){V()}}},r.registerMutableSourceForHydration=function(v,D){var Q=D._getVersion;Q=Q(D._source),v.mutableSourceEagerHydrationData==null?v.mutableSourceEagerHydrationData=[D,Q]:v.mutableSourceEagerHydrationData.push(D,Q)},r.runWithPriority=function(v,D){var Q=lc;try{return lc=v,D()}finally{lc=Q}},r.shouldSuspend=function(){return!1},r.unbatchedUpdates=function(v,D){var Q=xr;xr&=-2,xr|=8;try{return v(D)}finally{xr=Q,xr===0&&(Pf(),Rn())}},r.updateContainer=function(v,D,Q,H){var V=D.current,ne=ko(),Se=Bs(V);e:if(Q){Q=Q._reactInternals;t:{if(we(Q)!==Q||Q.tag!==1)throw Error(c(170));var _e=Q;do{switch(_e.tag){case 3:_e=_e.stateNode.context;break t;case 1:if(Kn(_e.type)){_e=_e.stateNode.__reactInternalMemoizedMergedChildContext;break t}}_e=_e.return}while(_e!==null);throw Error(c(171))}if(Q.tag===1){var pt=Q.type;if(Kn(pt)){Q=Oa(Q,pt,_e);break e}}Q=_e}else Q=la;return D.context===null?D.context=Q:D.pendingContext=Q,D=Dl(ne,Se),D.payload={element:v},H=H===void 0?null:H,H!==null&&(D.callback=H),Pl(V,D),Rl(V,Se,ne),Se},r}});var Iwe=_((sKt,Ewe)=>{"use strict";Ewe.exports=ywe()});var wwe=_((oKt,Cwe)=>{"use strict";var mpt={ALIGN_COUNT:8,ALIGN_AUTO:0,ALIGN_FLEX_START:1,ALIGN_CENTER:2,ALIGN_FLEX_END:3,ALIGN_STRETCH:4,ALIGN_BASELINE:5,ALIGN_SPACE_BETWEEN:6,ALIGN_SPACE_AROUND:7,DIMENSION_COUNT:2,DIMENSION_WIDTH:0,DIMENSION_HEIGHT:1,DIRECTION_COUNT:3,DIRECTION_INHERIT:0,DIRECTION_LTR:1,DIRECTION_RTL:2,DISPLAY_COUNT:2,DISPLAY_FLEX:0,DISPLAY_NONE:1,EDGE_COUNT:9,EDGE_LEFT:0,EDGE_TOP:1,EDGE_RIGHT:2,EDGE_BOTTOM:3,EDGE_START:4,EDGE_END:5,EDGE_HORIZONTAL:6,EDGE_VERTICAL:7,EDGE_ALL:8,EXPERIMENTAL_FEATURE_COUNT:1,EXPERIMENTAL_FEATURE_WEB_FLEX_BASIS:0,FLEX_DIRECTION_COUNT:4,FLEX_DIRECTION_COLUMN:0,FLEX_DIRECTION_COLUMN_REVERSE:1,FLEX_DIRECTION_ROW:2,FLEX_DIRECTION_ROW_REVERSE:3,JUSTIFY_COUNT:6,JUSTIFY_FLEX_START:0,JUSTIFY_CENTER:1,JUSTIFY_FLEX_END:2,JUSTIFY_SPACE_BETWEEN:3,JUSTIFY_SPACE_AROUND:4,JUSTIFY_SPACE_EVENLY:5,LOG_LEVEL_COUNT:6,LOG_LEVEL_ERROR:0,LOG_LEVEL_WARN:1,LOG_LEVEL_INFO:2,LOG_LEVEL_DEBUG:3,LOG_LEVEL_VERBOSE:4,LOG_LEVEL_FATAL:5,MEASURE_MODE_COUNT:3,MEASURE_MODE_UNDEFINED:0,MEASURE_MODE_EXACTLY:1,MEASURE_MODE_AT_MOST:2,NODE_TYPE_COUNT:2,NODE_TYPE_DEFAULT:0,NODE_TYPE_TEXT:1,OVERFLOW_COUNT:3,OVERFLOW_VISIBLE:0,OVERFLOW_HIDDEN:1,OVERFLOW_SCROLL:2,POSITION_TYPE_COUNT:2,POSITION_TYPE_RELATIVE:0,POSITION_TYPE_ABSOLUTE:1,PRINT_OPTIONS_COUNT:3,PRINT_OPTIONS_LAYOUT:1,PRINT_OPTIONS_STYLE:2,PRINT_OPTIONS_CHILDREN:4,UNIT_COUNT:4,UNIT_UNDEFINED:0,UNIT_POINT:1,UNIT_PERCENT:2,UNIT_AUTO:3,WRAP_COUNT:3,WRAP_NO_WRAP:0,WRAP_WRAP:1,WRAP_WRAP_REVERSE:2};Cwe.exports=mpt});var Dwe=_((aKt,Swe)=>{"use strict";var ypt=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var s in r)Object.prototype.hasOwnProperty.call(r,s)&&(t[s]=r[s])}return t},TF=function(){function t(e,r){for(var s=0;s<r.length;s++){var a=r[s];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,a.key,a)}}return function(e,r,s){return r&&t(e.prototype,r),s&&t(e,s),e}}();function _9(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function H9(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var tf=wwe(),Ept=function(){function t(e,r,s,a,n,c){H9(this,t),this.left=e,this.right=r,this.top=s,this.bottom=a,this.width=n,this.height=c}return TF(t,[{key:"fromJS",value:function(r){r(this.left,this.right,this.top,this.bottom,this.width,this.height)}},{key:"toString",value:function(){return"<Layout#"+this.left+":"+this.right+";"+this.top+":"+this.bottom+";"+this.width+":"+this.height+">"}}]),t}(),Bwe=function(){TF(t,null,[{key:"fromJS",value:function(r){var s=r.width,a=r.height;return new t(s,a)}}]);function t(e,r){H9(this,t),this.width=e,this.height=r}return TF(t,[{key:"fromJS",value:function(r){r(this.width,this.height)}},{key:"toStri Line truncated
`+Module.extraStackTrace()),demangleAll(t)}Module.stackTrace=stackTrace;var HEAP,buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferViews(){Module.HEAP8=HEAP8=new Int8Array(buffer),Module.HEAP16=HEAP16=new Int16Array(buffer),Module.HEAP32=HEAP32=new Int32Array(buffer),Module.HEAPU8=HEAPU8=new Uint8Array(buffer),Module.HEAPU16=HEAPU16=new Uint16Array(buffer),Module.HEAPU32=HEAPU32=new Uint32Array(buffer),Module.HEAPF32=HEAPF32=new Float32Array(buffer),Module.HEAPF64=HEAPF64=new Float64Array(buffer)}var STATIC_BASE,STATICTOP,staticSealed,STACK_BASE,STACKTOP,STACK_MAX,DYNAMIC_BASE,DYNAMICTOP_PTR;STATIC_BASE=STATICTOP=STACK_BASE=STACKTOP=STACK_MAX=DYNAMIC_BASE=DYNAMICTOP_PTR=0,staticSealed=!1;function abortOnCannotGrowMemory(){abort("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+TOTAL_MEMORY+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime but prevents some optimizations, (3) set Module.TOTAL_MEMORY to a higher value before the program runs, or (4) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")}function enlargeMemory(){abortOnCannotGrowMemory()}var TOTAL_STACK=Module.TOTAL_STACK||5242880,TOTAL_MEMORY=Module.TOTAL_MEMORY||134217728;TOTAL_MEMORY<TOTAL_STACK&&Module.printErr("TOTAL_MEMORY should be larger than TOTAL_STACK, was "+TOTAL_MEMORY+"! (TOTAL_STACK="+TOTAL_STACK+")"),Module.buffer?buffer=Module.buffer:buffer=new ArrayBuffer(TOTAL_MEMORY),updateGlobalBufferViews();function getTotalMemory(){return TOTAL_MEMORY}if(HEAP32[0]=1668509029,HEAP16[1]=25459,HEAPU8[2]!==115||HEAPU8[3]!==99)throw"Runtime error: expected the system to be little-endian!";Module.HEAP=HEAP,Module.buffer=buffer,Module.HEAP8=HEAP8,Module.HEAP16=HEAP16,Module.HEAP32=HEAP32,Module.HEAPU8=HEAPU8,Module.HEAPU16=HEAPU16,Module.HEAPU32=HEAPU32,Module.HEAPF32=HEAPF32,Module.HEAPF64=HEAPF64;function callRuntimeCallbacks(t){for(;t.length>0;){var e=t.shift();if(typeof e=="function"){e();continue}var r=e.func;typeof r=="number"?e.arg===void 0?Module.dynCall_v(r):Module.dynCall_vi(r,e.arg):r(e.arg===void 0?null:e.arg)}}var __ATPRERUN__=[],__ATINIT__=[],__ATMAIN__=[],__ATEXIT__=[],__ATPOSTRUN__=[],runtimeInitialized=!1,runtimeExited=!1;function preRun(){if(Module.preRun)for(typeof Module.preRun=="function"&&(Module.preRun=[Module.preRun]);Module.preRun.length;)addOnPreRun(Module.preRun.shift());callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){runtimeInitialized||(runtimeInitialized=!0,callRuntimeCallbacks(__ATINIT__))}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__),runtimeExited=!0}function postRun(){if(Module.postRun)for(typeof Module.postRun=="function"&&(Module.postRun=[Module.postRun]);Module.postRun.length;)addOnPostRun(Module.postRun.shift());callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(t){__ATPRERUN__.unshift(t)}Module.addOnPreRun=addOnPreRun;function addOnInit(t){__ATINIT__.unshift(t)}Module.addOnInit=addOnInit;function addOnPreMain(t){__ATMAIN__.unshift(t)}Module.addOnPreMain=addOnPreMain;function addOnExit(t){__ATEXIT__.unshift(t)}Module.addOnExit=addOnExit;function addOnPostRun(t){__ATPOSTRUN__.unshift(t)}Module.addOnPostRun=addOnPostRun;function intArrayFromString(t,e,r){var s=r>0?r:lengthBytesUTF8(t)+1,a=new Array(s),n=stringToUTF8Array(t,a,0,a.length);return e&&(a.length=n),a}Module.intArrayFromString=intArrayFromString;function intArrayToString(t){for(var e=[],r=0;r<t.length;r++){var s=t[r];s>255&&(s&=255),e.push(String.fromCharCode(s))}return e.join("")}Module.intArrayToString=intArrayToString;function writeStringToMemory(t,e,r){Runtime.warnOnce("writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!");var s,a;r&&(a=e+lengthBytesUTF8(t),s=HEAP8[a]),stringToUTF8(t,e,1/0),r&&(HEAP8[a]=s)}Module.writeStringToMemory=writeStringToMemory;function writeArrayToMemory(t,e){HEAP8.set(t,e)}Module.writeArrayToMemory=writeArrayToMemory;function writeAsciiToMemory(t,e,r){for(var s=0;s<t.length;++s)HEAP8[e++>>0]=t.charCodeAt(s);r||(HEAP8[e>>0]=0)}if(Module.writeAsciiToMemory=writeAsciiToMemory,(!Math.imul||Math.imul(4294967295,5)!==-5)&&(Math.imul=function t(e,r){var s=e>>>16,a=e&65535,n=r>>>16,c=r&65535;return a*c+(s*c+a*n<<16)|0}),Math.imul=Math.imul,!Math.fround){var froundBuffer=new Float32Array(1);Math.fround=function(t){return froundBuffer[0]=t,froundBuffer[0]}}Math.fround=Math.fround,Math.clz32||(Math.clz32=function(t){t=t>>>0;for(var e=0;e<32;e++)if(t&1<<31-e)return e;return 32}),Math.clz32=Math.clz32,Math.trunc||(Math.trunc=function(t){return t<0?Math.ceil(t):Math.floor(t)}),Math.trunc=Math.trunc;var Math_abs=Math.abs,Math_cos=Math.cos,Math_sin=Math.sin,Math_tan=Math.tan,Math_acos=Math.acos,Math_asin=Math.asin,Math_atan=Math.atan,Math_atan2=Math.atan2,Math_exp=Math.exp,Math_log=Math.log,Math_sqrt=Math.sqrt,Math_ceil=Math.cei Line truncated
If this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.`,r="abort("+t+") at "+stackTrace()+e;throw abortDecorators&&abortDecorators.forEach(function(s){r=s(r,t)}),r}if(Module.abort=Module.abort=abort,Module.preInit)for(typeof Module.preInit=="function"&&(Module.preInit=[Module.preInit]);Module.preInit.length>0;)Module.preInit.pop()();var shouldRunNow=!0;Module.noInitialRun&&(shouldRunNow=!1),run()})});var Fm=_((cKt,bwe)=>{"use strict";var Ipt=Dwe(),Cpt=Pwe(),j9=!1,G9=null;Cpt({},function(t,e){if(!j9){if(j9=!0,t)throw t;G9=e}});if(!j9)throw new Error("Failed to load the yoga module - it needed to be loaded synchronously, but didn't");bwe.exports=Ipt(G9.bind,G9.lib)});var W9=_((uKt,q9)=>{"use strict";var xwe=t=>Number.isNaN(t)?!1:t>=4352&&(t<=4447||t===9001||t===9002||11904<=t&&t<=12871&&t!==12351||12880<=t&&t<=19903||19968<=t&&t<=42182||43360<=t&&t<=43388||44032<=t&&t<=55203||63744<=t&&t<=64255||65040<=t&&t<=65049||65072<=t&&t<=65131||65281<=t&&t<=65376||65504<=t&&t<=65510||110592<=t&&t<=110593||127488<=t&&t<=127569||131072<=t&&t<=262141);q9.exports=xwe;q9.exports.default=xwe});var Qwe=_((fKt,kwe)=>{"use strict";kwe.exports=function(){return/\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F|\uD83D\uDC68(?:\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68\uD83C\uDFFB|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|[\u2695\u2696\u2708]\uFE0F|\uD83D[\uDC66\uDC67]|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708])\uFE0F|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C[\uDFFB-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)\uD83C\uDFFB|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])|\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)(?:\uD83C[\uDFFB\uDFFC])|\uD83D\uDC69(?:\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|(?:\uD83E Line truncated
`))e=Math.max(e,Spt(r));return e};V9.exports=Twe;V9.exports.default=Twe});var Fwe=_(qS=>{"use strict";var Dpt=qS&&qS.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(qS,"__esModule",{value:!0});var Ppt=Dpt(J9()),K9={};qS.default=t=>{if(t.length===0)return{width:0,height:0};if(K9[t])return K9[t];let e=Ppt.default(t),r=t.split(`
`).length;return K9[t]={width:e,height:r},{width:e,height:r}}});var Nwe=_(WS=>{"use strict";var bpt=WS&&WS.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(WS,"__esModule",{value:!0});var Pn=bpt(Fm()),xpt=(t,e)=>{"position"in e&&t.setPositionType(e.position==="absolute"?Pn.default.POSITION_TYPE_ABSOLUTE:Pn.default.POSITION_TYPE_RELATIVE)},kpt=(t,e)=>{"marginLeft"in e&&t.setMargin(Pn.default.EDGE_START,e.marginLeft||0),"marginRight"in e&&t.setMargin(Pn.default.EDGE_END,e.marginRight||0),"marginTop"in e&&t.setMargin(Pn.default.EDGE_TOP,e.marginTop||0),"marginBottom"in e&&t.setMargin(Pn.default.EDGE_BOTTOM,e.marginBottom||0)},Qpt=(t,e)=>{"paddingLeft"in e&&t.setPadding(Pn.default.EDGE_LEFT,e.paddingLeft||0),"paddingRight"in e&&t.setPadding(Pn.default.EDGE_RIGHT,e.paddingRight||0),"paddingTop"in e&&t.setPadding(Pn.default.EDGE_TOP,e.paddingTop||0),"paddingBottom"in e&&t.setPadding(Pn.default.EDGE_BOTTOM,e.paddingBottom||0)},Rpt=(t,e)=>{var r;"flexGrow"in e&&t.setFlexGrow((r=e.flexGrow)!==null&&r!==void 0?r:0),"flexShrink"in e&&t.setFlexShrink(typeof e.flexShrink=="number"?e.flexShrink:1),"flexDirection"in e&&(e.flexDirection==="row"&&t.setFlexDirection(Pn.default.FLEX_DIRECTION_ROW),e.flexDirection==="row-reverse"&&t.setFlexDirection(Pn.default.FLEX_DIRECTION_ROW_REVERSE),e.flexDirection==="column"&&t.setFlexDirection(Pn.default.FLEX_DIRECTION_COLUMN),e.flexDirection==="column-reverse"&&t.setFlexDirection(Pn.default.FLEX_DIRECTION_COLUMN_REVERSE)),"flexBasis"in e&&(typeof e.flexBasis=="number"?t.setFlexBasis(e.flexBasis):typeof e.flexBasis=="string"?t.setFlexBasisPercent(Number.parseInt(e.flexBasis,10)):t.setFlexBasis(NaN)),"alignItems"in e&&((e.alignItems==="stretch"||!e.alignItems)&&t.setAlignItems(Pn.default.ALIGN_STRETCH),e.alignItems==="flex-start"&&t.setAlignItems(Pn.default.ALIGN_FLEX_START),e.alignItems==="center"&&t.setAlignItems(Pn.default.ALIGN_CENTER),e.alignItems==="flex-end"&&t.setAlignItems(Pn.default.ALIGN_FLEX_END)),"alignSelf"in e&&((e.alignSelf==="auto"||!e.alignSelf)&&t.setAlignSelf(Pn.default.ALIGN_AUTO),e.alignSelf==="flex-start"&&t.setAlignSelf(Pn.default.ALIGN_FLEX_START),e.alignSelf==="center"&&t.setAlignSelf(Pn.default.ALIGN_CENTER),e.alignSelf==="flex-end"&&t.setAlignSelf(Pn.default.ALIGN_FLEX_END)),"justifyContent"in e&&((e.justifyContent==="flex-start"||!e.justifyContent)&&t.setJustifyContent(Pn.default.JUSTIFY_FLEX_START),e.justifyContent==="center"&&t.setJustifyContent(Pn.default.JUSTIFY_CENTER),e.justifyContent==="flex-end"&&t.setJustifyContent(Pn.default.JUSTIFY_FLEX_END),e.justifyContent==="space-between"&&t.setJustifyContent(Pn.default.JUSTIFY_SPACE_BETWEEN),e.justifyContent==="space-around"&&t.setJustifyContent(Pn.default.JUSTIFY_SPACE_AROUND))},Tpt=(t,e)=>{var r,s;"width"in e&&(typeof e.width=="number"?t.setWidth(e.width):typeof e.width=="string"?t.setWidthPercent(Number.parseInt(e.width,10)):t.setWidthAuto()),"height"in e&&(typeof e.height=="number"?t.setHeight(e.height):typeof e.height=="string"?t.setHeightPercent(Number.parseInt(e.height,10)):t.setHeightAuto()),"minWidth"in e&&(typeof e.minWidth=="string"?t.setMinWidthPercent(Number.parseInt(e.minWidth,10)):t.setMinWidth((r=e.minWidth)!==null&&r!==void 0?r:0)),"minHeight"in e&&(typeof e.minHeight=="string"?t.setMinHeightPercent(Number.parseInt(e.minHeight,10)):t.setMinHeight((s=e.minHeight)!==null&&s!==void 0?s:0))},Fpt=(t,e)=>{"display"in e&&t.setDisplay(e.display==="flex"?Pn.default.DISPLAY_FLEX:Pn.default.DISPLAY_NONE)},Npt=(t,e)=>{if("borderStyle"in e){let r=typeof e.borderStyle=="string"?1:0;t.setBorder(Pn.default.EDGE_TOP,r),t.setBorder(Pn.default.EDGE_BOTTOM,r),t.setBorder(Pn.default.EDGE_LEFT,r),t.setBorder(Pn.default.EDGE_RIGHT,r)}};WS.default=(t,e={})=>{xpt(t,e),kpt(t,e),Qpt(t,e),Rpt(t,e),Tpt(t,e),Fpt(t,e),Npt(t,e)}});var Mwe=_((dKt,Lwe)=>{"use strict";var YS=GS(),Opt=dk(),Lpt=sk(),Z9=new Set(["\x1B","\x9B"]),Mpt=39,Owe=t=>`${Z9.values().next().value}[${t}m`,Upt=t=>t.split(" ").map(e=>YS(e)),z9=(t,e,r)=>{let s=[...e],a=!1,n=YS(Opt(t[t.length-1]));for(let[c,f]of s.entries()){let p=YS(f);if(n+p<=r?t[t.length-1]+=f:(t.push(f),n=0),Z9.has(f))a=!0;else if(a&&f==="m"){a=!1;continue}a||(n+=p,n===r&&c<s.length-1&&(t.push(""),n=0))}!n&&t[t.length-1].length>0&&t.length>1&&(t[t.length-2]+=t.pop())},_pt=t=>{let e=t.split(" "),r=e.length;for(;r>0&&!(YS(e[r-1])>0);)r--;return r===e.length?t:e.slice(0,r).join(" ")+e.slice(r).join("")},Hpt=(t,e,r={})=>{if(r.trim!==!1&&t.trim()==="")return"";let s="",a="",n,c=Upt(t),f=[""];for(let[p,h]of t.split(" ").entries()){r.trim!==!1&&(f[f.length-1]=f[f.length-1].trimLeft());let E=YS(f[f.length-1]);if(p!==0&&(E>=e&&(r.wordWrap===!1||r.trim===!1)&&(f.push(""),E=0),(E>0||r.trim===!1)&&(f[f.length-1]+=" ",E++)),r.hard&&c[p]>e){let C=e-E,S=1+Math.floor((c[p]-C-1)/e);Math.floor((c[p]-1)/e)<S&&f.push(""),z9(f,h,e);continue}if(E+c[p]>e&&E>0&&c[p]>0){if(r.wordWrap===!1&&E<e){z9(f,h,e);continue}f.push("")}if(E+c[p]>e&&r.wordWrap===!1){z9(f,h,e);continue}f[f. Line truncated
`);for(let[p,h]of[...s].entries()){if(a+=h,Z9.has(h)){let C=parseFloat(/\d[^m]*/.exec(s.slice(p,p+4)));n=C===Mpt?null:C}let E=Lpt.codes.get(Number(n));n&&E&&(s[p+1]===`
`?a+=Owe(E):h===`
`&&(a+=Owe(n)))}return a};Lwe.exports=(t,e,r)=>String(t).normalize().replace(/\r\n/g,`
`).split(`
`).map(s=>Hpt(s,e,r)).join(`
`)});var Hwe=_((mKt,_we)=>{"use strict";var Uwe="[\uD800-\uDBFF][\uDC00-\uDFFF]",jpt=t=>t&&t.exact?new RegExp(`^${Uwe}$`):new RegExp(Uwe,"g");_we.exports=jpt});var X9=_((yKt,Wwe)=>{"use strict";var Gpt=W9(),qpt=Hwe(),jwe=sk(),qwe=["\x1B","\x9B"],FF=t=>`${qwe[0]}[${t}m`,Gwe=(t,e,r)=>{let s=[];t=[...t];for(let a of t){let n=a;a.match(";")&&(a=a.split(";")[0][0]+"0");let c=jwe.codes.get(parseInt(a,10));if(c){let f=t.indexOf(c.toString());f>=0?t.splice(f,1):s.push(FF(e?c:n))}else if(e){s.push(FF(0));break}else s.push(FF(n))}if(e&&(s=s.filter((a,n)=>s.indexOf(a)===n),r!==void 0)){let a=FF(jwe.codes.get(parseInt(r,10)));s=s.reduce((n,c)=>c===a?[c,...n]:[...n,c],[])}return s.join("")};Wwe.exports=(t,e,r)=>{let s=[...t.normalize()],a=[];r=typeof r=="number"?r:s.length;let n=!1,c,f=0,p="";for(let[h,E]of s.entries()){let C=!1;if(qwe.includes(E)){let S=/\d[^m]*/.exec(t.slice(h,h+18));c=S&&S.length>0?S[0]:void 0,f<r&&(n=!0,c!==void 0&&a.push(c))}else n&&E==="m"&&(n=!1,C=!0);if(!n&&!C&&++f,!qpt({exact:!0}).test(E)&&Gpt(E.codePointAt())&&++f,f>e&&f<=r)p+=E;else if(f===e&&!n&&c!==void 0)p=Gwe(a);else if(f>=r){p+=Gwe(a,!0,c);break}}return p}});var Vwe=_((EKt,Ywe)=>{"use strict";var $0=X9(),Wpt=GS();function NF(t,e,r){if(t.charAt(e)===" ")return e;for(let s=1;s<=3;s++)if(r){if(t.charAt(e+s)===" ")return e+s}else if(t.charAt(e-s)===" ")return e-s;return e}Ywe.exports=(t,e,r)=>{r={position:"end",preferTruncationOnSpace:!1,...r};let{position:s,space:a,preferTruncationOnSpace:n}=r,c="\u2026",f=1;if(typeof t!="string")throw new TypeError(`Expected \`input\` to be a string, got ${typeof t}`);if(typeof e!="number")throw new TypeError(`Expected \`columns\` to be a number, got ${typeof e}`);if(e<1)return"";if(e===1)return c;let p=Wpt(t);if(p<=e)return t;if(s==="start"){if(n){let h=NF(t,p-e+1,!0);return c+$0(t,h,p).trim()}return a===!0&&(c+=" ",f=2),c+$0(t,p-e+f,p)}if(s==="middle"){a===!0&&(c=" "+c+" ",f=3);let h=Math.floor(e/2);if(n){let E=NF(t,h),C=NF(t,p-(e-h)+1,!0);return $0(t,0,E)+c+$0(t,C,p).trim()}return $0(t,0,h)+c+$0(t,p-(e-h)+f,p)}if(s==="end"){if(n){let h=NF(t,e-1);return $0(t,0,h)+c}return a===!0&&(c=" "+c,f=2),$0(t,0,e-f)+c}throw new Error(`Expected \`options.position\` to be either \`start\`, \`middle\` or \`end\`, got ${s}`)}});var eW=_(VS=>{"use strict";var Jwe=VS&&VS.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(VS,"__esModule",{value:!0});var Ypt=Jwe(Mwe()),Vpt=Jwe(Vwe()),$9={};VS.default=(t,e,r)=>{let s=t+String(e)+String(r);if($9[s])return $9[s];let a=t;if(r==="wrap"&&(a=Ypt.default(t,e,{trim:!1,hard:!0})),r.startsWith("truncate")){let n="end";r==="truncate-middle"&&(n="middle"),r==="truncate-start"&&(n="start"),a=Vpt.default(t,e,{position:n})}return $9[s]=a,a}});var rW=_(tW=>{"use strict";Object.defineProperty(tW,"__esModule",{value:!0});var Kwe=t=>{let e="";if(t.childNodes.length>0)for(let r of t.childNodes){let s="";r.nodeName==="#text"?s=r.nodeValue:((r.nodeName==="ink-text"||r.nodeName==="ink-virtual-text")&&(s=Kwe(r)),s.length>0&&typeof r.internal_transform=="function"&&(s=r.internal_transform(s))),e+=s}return e};tW.default=Kwe});var nW=_(Pi=>{"use strict";var JS=Pi&&Pi.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(Pi,"__esModule",{value:!0});Pi.setTextNodeValue=Pi.createTextNode=Pi.setStyle=Pi.setAttribute=Pi.removeChildNode=Pi.insertBeforeNode=Pi.appendChildNode=Pi.createNode=Pi.TEXT_NAME=void 0;var Jpt=JS(Fm()),zwe=JS(Fwe()),Kpt=JS(Nwe()),zpt=JS(eW()),Zpt=JS(rW());Pi.TEXT_NAME="#text";Pi.createNode=t=>{var e;let r={nodeName:t,style:{},attributes:{},childNodes:[],parentNode:null,yogaNode:t==="ink-virtual-text"?void 0:Jpt.default.Node.create()};return t==="ink-text"&&((e=r.yogaNode)===null||e===void 0||e.setMeasureFunc(Xpt.bind(null,r))),r};Pi.appendChildNode=(t,e)=>{var r;e.parentNode&&Pi.removeChildNode(e.parentNode,e),e.parentNode=t,t.childNodes.push(e),e.yogaNode&&((r=t.yogaNode)===null||r===void 0||r.insertChild(e.yogaNode,t.yogaNode.getChildCount())),(t.nodeName==="ink-text"||t.nodeName==="ink-virtual-text")&&OF(t)};Pi.insertBeforeNode=(t,e,r)=>{var s,a;e.parentNode&&Pi.removeChildNode(e.parentNode,e),e.parentNode=t;let n=t.childNodes.indexOf(r);if(n>=0){t.childNodes.splice(n,0,e),e.yogaNode&&((s=t.yogaNode)===null||s===void 0||s.insertChild(e.yogaNode,n));return}t.childNodes.push(e),e.yogaNode&&((a=t.yogaNode)===null||a===void 0||a.insertChild(e.yogaNode,t.yogaNode.getChildCount())),(t.nodeName==="ink-text"||t.nodeName==="ink-virtual-text")&&OF(t)};Pi.removeChildNode=(t,e)=>{var r,s;e.yogaNode&&((s=(r=e.parentNode)===null||r===void 0?void 0:r.yogaNode)===null||s===void 0||s.removeChild(e.yogaNode)),e.parentNode=null;let a=t.childNodes.indexOf(e);a>=0&&t.childNodes.splice(a,1),(t.nodeName==="ink-text"||t.nodeName==="ink-virtual-text")&&OF(t)};Pi.setAttribute=(t,e,r)=>{t.attributes[e]=r};Pi.setStyle=(t,e)=>{t.style=e,t.yogaNode&&Kpt.default(t.yogaNode,e)};Pi.createTextNode=t=>{let e={nodeName:"#text",nodeValue:t,yogaLine truncated
`).repeat(n-2),E=oW.default(f.bottomLeft+f.horizontal.repeat(a-2)+f.bottomRight,c,"foreground");s.write(t,e,p,{transformers:[]}),s.write(t,e+1,h,{transformers:[]}),s.write(t+a-1,e+1,h,{transformers:[]}),s.write(t,e+n-1,E,{transformers:[]})}}});var A1e=_(eD=>{"use strict";var Nm=eD&&eD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(eD,"__esModule",{value:!0});var oht=Nm(Fm()),aht=Nm(J9()),lht=Nm(i1e()),cht=Nm(eW()),uht=Nm(s1e()),fht=Nm(rW()),Aht=Nm(u1e()),pht=(t,e)=>{var r;let s=(r=t.childNodes[0])===null||r===void 0?void 0:r.yogaNode;if(s){let a=s.getComputedLeft(),n=s.getComputedTop();e=`
`.repeat(n)+lht.default(e,a)}return e},f1e=(t,e,r)=>{var s;let{offsetX:a=0,offsetY:n=0,transformers:c=[],skipStaticElements:f}=r;if(f&&t.internal_static)return;let{yogaNode:p}=t;if(p){if(p.getDisplay()===oht.default.DISPLAY_NONE)return;let h=a+p.getComputedLeft(),E=n+p.getComputedTop(),C=c;if(typeof t.internal_transform=="function"&&(C=[t.internal_transform,...c]),t.nodeName==="ink-text"){let S=fht.default(t);if(S.length>0){let b=aht.default(S),I=uht.default(p);if(b>I){let T=(s=t.style.textWrap)!==null&&s!==void 0?s:"wrap";S=cht.default(S,I,T)}S=pht(t,S),e.write(h,E,S,{transformers:C})}return}if(t.nodeName==="ink-box"&&Aht.default(h,E,t,e),t.nodeName==="ink-root"||t.nodeName==="ink-box")for(let S of t.childNodes)f1e(S,e,{offsetX:h,offsetY:E,transformers:C,skipStaticElements:f})}};eD.default=f1e});var g1e=_(tD=>{"use strict";var h1e=tD&&tD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(tD,"__esModule",{value:!0});var p1e=h1e(X9()),hht=h1e(GS()),aW=class{constructor(e){this.writes=[];let{width:r,height:s}=e;this.width=r,this.height=s}write(e,r,s,a){let{transformers:n}=a;s&&this.writes.push({x:e,y:r,text:s,transformers:n})}get(){let e=[];for(let s=0;s<this.height;s++)e.push(" ".repeat(this.width));for(let s of this.writes){let{x:a,y:n,text:c,transformers:f}=s,p=c.split(`
`),h=0;for(let E of p){let C=e[n+h];if(!C)continue;let S=hht.default(E);for(let b of f)E=b(E);e[n+h]=p1e.default(C,0,a)+E+p1e.default(C,a+S),h++}}return{output:e.map(s=>s.trimRight()).join(`
`),height:e.length}}};tD.default=aW});var y1e=_(rD=>{"use strict";var lW=rD&&rD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(rD,"__esModule",{value:!0});var ght=lW(Fm()),d1e=lW(A1e()),m1e=lW(g1e());rD.default=(t,e)=>{var r;if(t.yogaNode.setWidth(e),t.yogaNode){t.yogaNode.calculateLayout(void 0,void 0,ght.default.DIRECTION_LTR);let s=new m1e.default({width:t.yogaNode.getComputedWidth(),height:t.yogaNode.getComputedHeight()});d1e.default(t,s,{skipStaticElements:!0});let a;!((r=t.staticNode)===null||r===void 0)&&r.yogaNode&&(a=new m1e.default({width:t.staticNode.yogaNode.getComputedWidth(),height:t.staticNode.yogaNode.getComputedHeight()}),d1e.default(t.staticNode,a,{skipStaticElements:!1}));let{output:n,height:c}=s.get();return{output:n,outputHeight:c,staticOutput:a?`${a.get().output}
`:""}}return{output:"",outputHeight:0,staticOutput:""}}});var w1e=_((TKt,C1e)=>{"use strict";var E1e=Ie("stream"),I1e=["assert","count","countReset","debug","dir","dirxml","error","group","groupCollapsed","groupEnd","info","log","table","time","timeEnd","timeLog","trace","warn"],cW={},dht=t=>{let e=new E1e.PassThrough,r=new E1e.PassThrough;e.write=a=>t("stdout",a),r.write=a=>t("stderr",a);let s=new console.Console(e,r);for(let a of I1e)cW[a]=console[a],console[a]=s[a];return()=>{for(let a of I1e)console[a]=cW[a];cW={}}};C1e.exports=dht});var fW=_(uW=>{"use strict";Object.defineProperty(uW,"__esModule",{value:!0});uW.default=new WeakMap});var pW=_(AW=>{"use strict";Object.defineProperty(AW,"__esModule",{value:!0});var mht=hn(),B1e=mht.createContext({exit:()=>{}});B1e.displayName="InternalAppContext";AW.default=B1e});var gW=_(hW=>{"use strict";Object.defineProperty(hW,"__esModule",{value:!0});var yht=hn(),v1e=yht.createContext({stdin:void 0,setRawMode:()=>{},isRawModeSupported:!1,internal_exitOnCtrlC:!0});v1e.displayName="InternalStdinContext";hW.default=v1e});var mW=_(dW=>{"use strict";Object.defineProperty(dW,"__esModule",{value:!0});var Eht=hn(),S1e=Eht.createContext({stdout:void 0,write:()=>{}});S1e.displayName="InternalStdoutContext";dW.default=S1e});var EW=_(yW=>{"use strict";Object.defineProperty(yW,"__esModule",{value:!0});var Iht=hn(),D1e=Iht.createContext({stderr:void 0,write:()=>{}});D1e.displayName="InternalStderrContext";yW.default=D1e});var UF=_(IW=>{"use strict";Object.defineProperty(IW,"__esModule",{value:!0});var Cht=hn(),P1e=Cht.createContext({activeId:void 0,add:()=>{},remove:()=>{},activate:()=>{},deactivate:()=>{},enableFocus:()=>{},disableFocus:()=>{},focusNext:()=>{},focusPrevious:()=>{},focus:()=>{}});P1e.displayName="InternalFocusContext";IW.default=P1e});var x1e=_((_Kt,b1e)=>{"use strict";var wht=/[|\\{}()[\]^$+*?.-]/g;b1e.exports=t=>{if(typeof t!="string")throw new TypeError("Expected a string");return t.replace(wht,"\\$&")}});var T1e=_((HKt,R1e)=>{"use strict";var Bht=x1e(),vht=typeof process=="object"&&process&&typeof process.cwd=="function"?process.cwd():".",Q1e=[].concat(Ie("module").builtinModules,"bootstrap_node","node").map(t=>new RegExp(`(?:\\((?:node:)?${t}(?:\\.js)?:\\d+:\\d+\\)$|^\\s*at (?:node:)?${t}(?:\\.js)?:\\d+:\\d+$)`));Q1e.push(/\((?:node:)?internal\/[^:]+:\d+:\d+\)$/,/\s*at (?:node:)?internal\/[^:]+:\d+:\d+$/,/\/\.node-spawn-wrap-\w+-\w+\/node:\d+:\d+\)?$/);var CW=class t{constructor(e){e={ignoredPackages:[],...e},"internals"in e||(e.internals=t.nodeInternals()),"cwd"in e||(e.cwd=vht),this._cwd=e.cwd.replace(/\\/g,"/"),this._internals=[].concat(e.internals,Sht(e.ignoredPackages)),this._wrapCallSite=e.wrapCallSite||!1}static nodeInternals(){return[...Q1e]}clean(e,r=0){r=" ".repeat(r),Array.isArray(e)||(e=e.split(`
`)),!/^\s*at /.test(e[0])&&/^\s*at /.test(e[1])&&(e=e.slice(1));let s=!1,a=null,n=[];return e.forEach(c=>{if(c=c.replace(/\\/g,"/"),this._internals.some(p=>p.test(c)))return;let f=/^\s*at /.test(c);s?c=c.trimEnd().replace(/^(\s+)at /,"$1"):(c=c.trim(),f&&(c=c.slice(3))),c=c.replace(`${this._cwd}/`,""),c&&(f?(a&&(n.push(a),a=null),n.push(c)):(s=!0,a=c))}),n.map(c=>`${r}${c}
`).join("")}captureString(e,r=this.captureString){typeof e=="function"&&(r=e,e=1/0);let{stackTraceLimit:s}=Error;e&&(Error.stackTraceLimit=e);let a={};Error.captureStackTrace(a,r);let{stack:n}=a;return Error.stackTraceLimit=s,this.clean(n)}capture(e,r=this.capture){typeof e=="function"&&(r=e,e=1/0);let{prepareStackTrace:s,stackTraceLimit:a}=Error;Error.prepareStackTrace=(f,p)=>this._wrapCallSite?p.map(this._wrapCallSite):p,e&&(Error.stackTraceLimit=e);let n={};Error.captureStackTrace(n,r);let{stack:c}=n;return Object.assign(Error,{prepareStackTrace:s,stackTraceLimit:a}),c}at(e=this.at){let[r]=this.capture(1,e);if(!r)return{};let s={line:r.getLineNumber(),column:r.getColumnNumber()};k1e(s,r.getFileName(),this._cwd),r.isConstructor()&&(s.constructor=!0),r.isEval()&&(s.evalOrigin=r.getEvalOrigin()),r.isNative()&&(s.native=!0);let a;try{a=r.getTypeName()}catch{}a&&a!=="Object"&&a!=="[object Object]"&&(s.type=a);let n=r.getFunctionName();n&&(s.function=n);let c=r.getMethodName();return c&&n!==c&&(s.method=c),s}parseLine(e){let r=e&&e.match(Dht);if(!r)return null;let s=r[1]==="new",a=r[2],n=r[3],c=r[4],f=Number(r[5]),p=Number(r[6]),h=r[7],E=r[8],C=r[9],S=r[10]==="native",b=r[11]===")",I,T={};if(E&&(T.line=Number(E)),C&&(T.column=Number(C)),b&&h){let N=0;for(let U=h.length-1;U>0;U--)if(h.charAt(U)===")")N++;else if(h.charAt(U)==="("&&h.charAt(U-1)===" "&&(N--,N===-1&&h.charAt(U-1)===" ")){let W=h.slice(0,U-1);h=h.slice(U+1),a+=` (${W}`;break}}if(a){let N=a.match(Pht);N&&(a=N[1],I=N[2])}return k1e(T,h,this._cwd),s&&(T.constructor=!0),n&&(T.evalOrigin=n,T.evalLine=f,T.evalColumn=p,T.evalFile=c&&c.replace(/\\/g,"/")),S&&(T.native=!0),a&&(T.function=a),I&&a!==I&&(T.method=I),T}};function k1e(t,e,r){e&&(e=e.replace(/\\/g,"/"),e.startsWith(`${r}/`)&&(e=e.slice(r.length+1)),t.file=e)}function Sht(t){if(t.length===0)return[];let e=t.map(r=>Bht(r));return new RegExp(`[/\\\\]node_modules[/\\\\](?:${e.join("|")})[/\\\\][^:]+:\\d+:\\d+`)}var Dht=new RegExp("^(?:\\s*at )?(?:(new) )?(?:(.*?) \\()?(?:eval at ([^ ]+) \\((.+?):(\\d+):(\\d+)\\), )?(?:(.+?):(\\d+):(\\d+)|(native))(\\)?)$"),Pht=/^(.*?) \[as (.*?)\]$/;R1e.exports=CW});var N1e=_((jKt,F1e)=>{"use strict";F1e.exports=(t,e)=>t.replace(/^\t+/gm,r=>" ".repeat(r.length*(e||2)))});var L1e=_((GKt,O1e)=>{"use strict";var bht=N1e(),xht=(t,e)=>{let r=[],s=t-e,a=t+e;for(let n=s;n<=a;n++)r.push(n);return r};O1e.exports=(t,e,r)=>{if(typeof t!="string")throw new TypeError("Source code is missing.");if(!e||e<1)throw new TypeError("Line number must start from `1`.");if(t=bht(t).split(/\r?\n/),!(e>t.length))return r={around:3,...r},xht(e,r.around).filter(s=>t[s-1]!==void 0).map(s=>({line:s,value:t[s-1]}))}});var _F=_(rf=>{"use strict";var kht=rf&&rf.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),Qht=rf&&rf.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),Rht=rf&&rf.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.hasOwnProperty.call(t,r)&&kht(e,t,r);return Qht(e,t),e},Tht=rf&&rf.__rest||function(t,e){var r={};for(var s in t)Object.prototype.hasOwnProperty.call(t,s)&&e.indexOf(s)<0&&(r[s]=t[s]);if(t!=null&&typeof Object.getOwnPropertySymbols=="function")for(var a=0,s=Object.getOwnPropertySymbols(t);a<s.length;a++)e.indexOf(s[a])<0&&Object.prototype.propertyIsEnumerable.call(t,s[a])&&(r[s[a]]=t[s[a]]);return r};Object.defineProperty(rf,"__esModule",{value:!0});var M1e=Rht(hn()),wW=M1e.forwardRef((t,e)=>{var{children:r}=t,s=Tht(t,["children"]);let a=Object.assign(Object.assign({},s),{marginLeft:s.marginLeft||s.marginX||s.margin||0,marginRight:s.marginRight||s.marginX||s.margin||0,marginTop:s.marginTop||s.marginY||s.margin||0,marginBottom:s.marginBottom||s.marginY||s.margin||0,paddingLeft:s.paddingLeft||s.paddingX||s.padding||0,paddingRight:s.paddingRight||s.paddingX||s.padding||0,paddingTop:s.paddingTop||s.paddingY||s.padding||0,paddingBottom:s.paddingBottom||s.paddingY||s.padding||0});return M1e.default.createElement("ink-box",{ref:e,style:a},r)});wW.displayName="Box";wW.defaultProps={flexDirection:"row",flexGrow:0,flexShrink:1};rf.default=wW});var SW=_(nD=>{"use strict";var BW=nD&&nD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(nD,"__esModule",{value:!0});var Fht=BW(hn()),yw=BW(RE()),U1e=BW(sW()),vW=({color:t,backgroundColor:e,dimColor:r,bold:s,italic:a,underline:n,strikethrough:c,inverse:f,wrap:p,children:h})=>{if(h==null)return null;let E=C=>(r&&(C=yw.default.dim(C)),t&&(C=U1e.default(C,t,"foreground")),e&&(C=U1e.default(C,e,"background")),s&&(C=yw.default.bold(C)),a&&(C=yw.default.italic(C)),n&&(C=yw.default.underline(C)),c&&(C=yw.default.strikethrough(C)),f&&(C=yw.default.inverse(C)),C);return Fht.default.createElement("ink-text",{style:{flexGrow:0,flexSLine truncated
`).slice(1):void 0,r=e?j1e.parseLine(e[0]):void 0,s,a=0;if(r?.file&&r?.line&&_1e.existsSync(r.file)){let n=_1e.readFileSync(r.file,"utf8");if(s=Mht.default(n,r.line),s)for(let{line:c}of s)a=Math.max(a,String(c).length)}return Qs.default.createElement($p.default,{flexDirection:"column",padding:1},Qs.default.createElement($p.default,null,Qs.default.createElement(AA.default,{backgroundColor:"red",color:"white"}," ","ERROR"," "),Qs.default.createElement(AA.default,null," ",t.message)),r&&Qs.default.createElement($p.default,{marginTop:1},Qs.default.createElement(AA.default,{dimColor:!0},r.file,":",r.line,":",r.column)),r&&s&&Qs.default.createElement($p.default,{marginTop:1,flexDirection:"column"},s.map(({line:n,value:c})=>Qs.default.createElement($p.default,{key:n},Qs.default.createElement($p.default,{width:a+1},Qs.default.createElement(AA.default,{dimColor:n!==r.line,backgroundColor:n===r.line?"red":void 0,color:n===r.line?"white":void 0},String(n).padStart(a," "),":")),Qs.default.createElement(AA.default,{key:n,backgroundColor:n===r.line?"red":void 0,color:n===r.line?"white":void 0}," "+c)))),t.stack&&Qs.default.createElement($p.default,{marginTop:1,flexDirection:"column"},t.stack.split(`
`).slice(1).map(n=>{let c=j1e.parseLine(n);return c?Qs.default.createElement($p.default,{key:n},Qs.default.createElement(AA.default,{dimColor:!0},"- "),Qs.default.createElement(AA.default,{dimColor:!0,bold:!0},c.function),Qs.default.createElement(AA.default,{dimColor:!0,color:"gray"}," ","(",c.file,":",c.line,":",c.column,")")):Qs.default.createElement($p.default,{key:n},Qs.default.createElement(AA.default,{dimColor:!0},"- "),Qs.default.createElement(AA.default,{dimColor:!0,bold:!0},n))})))};nf.default=Uht});var W1e=_(sf=>{"use strict";var _ht=sf&&sf.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),Hht=sf&&sf.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),jht=sf&&sf.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.hasOwnProperty.call(t,r)&&_ht(e,t,r);return Hht(e,t),e},Lm=sf&&sf.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(sf,"__esModule",{value:!0});var Om=jht(hn()),q1e=Lm(P9()),Ght=Lm(pW()),qht=Lm(gW()),Wht=Lm(mW()),Yht=Lm(EW()),Vht=Lm(UF()),Jht=Lm(G1e()),Kht=" ",zht="\x1B[Z",Zht="\x1B",HF=class extends Om.PureComponent{constructor(){super(...arguments),this.state={isFocusEnabled:!0,activeFocusId:void 0,focusables:[],error:void 0},this.rawModeEnabledCount=0,this.handleSetRawMode=e=>{let{stdin:r}=this.props;if(!this.isRawModeSupported())throw r===process.stdin?new Error(`Raw mode is not supported on the current process.stdin, which Ink uses as input stream by default.
Read about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported`):new Error(`Raw mode is not supported on the stdin provided to Ink.
Read about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported`);if(r.setEncoding("utf8"),e){this.rawModeEnabledCount===0&&(r.addListener("data",this.handleInput),r.resume(),r.setRawMode(!0)),this.rawModeEnabledCount++;return}--this.rawModeEnabledCount===0&&(r.setRawMode(!1),r.removeListener("data",this.handleInput),r.pause())},this.handleInput=e=>{e===""&&this.props.exitOnCtrlC&&this.handleExit(),e===Zht&&this.state.activeFocusId&&this.setState({activeFocusId:void 0}),this.state.isFocusEnabled&&this.state.focusables.length>0&&(e===Kht&&this.focusNext(),e===zht&&this.focusPrevious())},this.handleExit=e=>{this.isRawModeSupported()&&this.handleSetRawMode(!1),this.props.onExit(e)},this.enableFocus=()=>{this.setState({isFocusEnabled:!0})},this.disableFocus=()=>{this.setState({isFocusEnabled:!1})},this.focus=e=>{this.setState(r=>r.focusables.some(a=>a?.id===e)?{activeFocusId:e}:r)},this.focusNext=()=>{this.setState(e=>{var r;let s=(r=e.focusables[0])===null||r===void 0?void 0:r.id;return{activeFocusId:this.findNextFocusable(e)||s}})},this.focusPrevious=()=>{this.setState(e=>{var r;let s=(r=e.focusables[e.focusables.length-1])===null||r===void 0?void 0:r.id;return{activeFocusId:this.findPreviousFocusable(e)||s}})},this.addFocusable=(e,{autoFocus:r})=>{this.setState(s=>{let a=s.activeFocusId;return!a&&r&&(a=e),{activeFocusId:a,focusables:[...s.focusables,{id:e,isActive:!0}]}})},this.removeFocusable=e=>{this.setState(r=>({activeFocusId:r.activeFocusId===e?void 0:r.activeFocusId,focusables:r.focusables.filter(s=>s.id!==e)}))},this.activateFocusable=e=>{this.setState(r=>({focusables:r.focusables.map(s=>s.id!==e?s:{id:e,isActive:!0})}))},this.deactivateFocusable=e=>{this.setState(r=>({activeFocusId:r.activeFocusId===e?void 0:r.activeFocusId,focusables:r.focusables.map(s=>s.id!==e?s:{id:e,isActive:!1})}))},this.findNextFocusable=e=>{var r;let s=e.focusables.findIndex(a=>a.id===e.activeFocusId);for(let a=s+1;a<e.focusables.length;a++)if(!((r=e.focusables[a])===null||r===void 0)&&r.isActive)return e.focusables[a].id},this.findPreviousFocusable=e=>{var r;let s=e.focusables.findIndex(a=>a.id===e.activeFocusId);for(let a=s-1;a>=0;a--)if(!((r=e.focusables[a])===null||r===void 0)&&r.isActive)return e.focusables[a].id}}static getDerivedStateFromError(e){return{error:e}}isRawModeSupported(){return this.props.stdin.isTTY}render(){return Om.default.createElement(Ght.default.Provider,{value:{exit:this.handleExit}},Om.default.createElement(qht.default.Provider,{value:{stdin:this.props.stdin,setRawMode:this.handleSetRawMode,isRawModeSupported:this.isRawModeSupported(),internal_exitOnCtrlC:this.props.exitOnCtrlC}},Om.default.createElement(Wht.default.Provider,{value:{stdout:this.props.stdout,write:this.props.writeToStdout}},Om.default.createElement(Yht.default.Provider,{value:{stderr:this.props.stderr,write:this.props.writeToStderr}},Om.default.createElement(Vht.default.Provider,{value:{activeId:this.state.activeFocusId,add:this.addFocusable,remove:this.removeFocusable,activate:this.activateFocusable,deactivate:this.deactivateFocusable,enableFocus:this.enableFocus,disableFocus:this.disableFocus,focusNext:this.focusNext,focusPrevious:this.focusPrevious,focus:this.focus}},this.state.error?Om.default.createElement(Jht.default,{error:this.state.error}):this.props.children)))))}componentDidMount(){q1e.default.hide(this.props.stdout)}componentWillUnmount(){q1e.default.show(this.props.stdout),this.isRawModeSupported()&&this.handleSetRawMode(!1)}componentDidCatch(e){this.handleExit(e)}};sf.default=HF;HF.displayName="InternalApp"});var J1e=_(of=>{"use strict";var Xht=of&&of.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),$ht=of&&of.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),e0t=of&&of.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.hasOwnProperty.call(t,r)&&Xht(e,t,r);return $ht(e,t),e},af=of&&of.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(of,"__esModule",{value:!0});var t0t=af(hn()),Y1e=_Ce(),r0t=af(rwe()),n0t=af(w9()),i0t=af(lwe()),s0t=af(uwe()),DW=af(r1e()),o0t=af(y1e()),a0t=af(D9()),l0t=af(w1e()),c0t=e0t(nW()),u0t=af(fW()),f0t=af(W1e()),Ew=process.env.CI==="false"?!1:i0t.default,V1e=()=>{},PW=class{constructor(e){this.resolveExitPromise=()=>{},this.rejectExitPromise=()=>{},this.unsubscribeExit=()=>{},this.onRender=()=>{if(this.isUnmounted)return;let{output:r,outputHeight:s,staticOutput:a}=o0t.default(this.rootNode,this.options.stdout.columns||80),n=a&&a!==`
`;if(this.options.debug){n&&(this.fullStaticOutput+=a),this.options.stdout.write(this.fullStaticOutput+r);return}if(Ew){n&&this.options.stdout.write(a),this.lastOutput=r;return}if(n&&(this.fullStaticOutput+=a),s>=this.options.stdout.rows){this.options.stdout.write(n0t.default.clearTerminal+this.fullStaticOutput+r),this.lastOutput=r;return}n&&(this.log.clear(),this.options.stdout.write(a),this.log(r)),!n&&r!==this.lastOutput&&this.throttledLog(r),this.lastOutput=r},s0t.default(this),this.options=e,this.rootNode=c0t.createNode("ink-root"),this.rootNode.onRender=e.debug?this.onRender:Y1e(this.onRender,32,{leading:!0,trailing:!0}),this.rootNode.onImmediateRender=this.onRender,this.log=r0t.default.create(e.stdout),this.throttledLog=e.debug?this.log:Y1e(this.log,void 0,{leading:!0,trailing:!0}),this.isUnmounted=!1,this.lastOutput="",this.fullStaticOutput="",this.container=DW.default.createContainer(this.rootNode,0,!1,null),this.unsubscribeExit=a0t.default(this.unmount,{alwaysLast:!1}),e.patchConsole&&this.patchConsole(),Ew||(e.stdout.on("resize",this.onRender),this.unsubscribeResize=()=>{e.stdout.off("resize",this.onRender)})}render(e){let r=t0t.default.createElement(f0t.default,{stdin:this.options.stdin,stdout:this.options.stdout,stderr:this.options.stderr,writeToStdout:this.writeToStdout,writeToStderr:this.writeToStderr,exitOnCtrlC:this.options.exitOnCtrlC,onExit:this.unmount},e);DW.default.updateContainer(r,this.container,null,V1e)}writeToStdout(e){if(!this.isUnmounted){if(this.options.debug){this.options.stdout.write(e+this.fullStaticOutput+this.lastOutput);return}if(Ew){this.options.stdout.write(e);return}this.log.clear(),this.options.stdout.write(e),this.log(this.lastOutput)}}writeToStderr(e){if(!this.isUnmounted){if(this.options.debug){this.options.stderr.write(e),this.options.stdout.write(this.fullStaticOutput+this.lastOutput);return}if(Ew){this.options.stderr.write(e);return}this.log.clear(),this.options.stderr.write(e),this.log(this.lastOutput)}}unmount(e){this.isUnmounted||(this.onRender(),this.unsubscribeExit(),typeof this.restoreConsole=="function"&&this.restoreConsole(),typeof this.unsubscribeResize=="function"&&this.unsubscribeResize(),Ew?this.options.stdout.write(this.lastOutput+`
`):this.options.debug||this.log.done(),this.isUnmounted=!0,DW.default.updateContainer(null,this.container,null,V1e),u0t.default.delete(this.options.stdout),e instanceof Error?this.rejectExitPromise(e):this.resolveExitPromise())}waitUntilExit(){return this.exitPromise||(this.exitPromise=new Promise((e,r)=>{this.resolveExitPromise=e,this.rejectExitPromise=r})),this.exitPromise}clear(){!Ew&&!this.options.debug&&this.log.clear()}patchConsole(){this.options.debug||(this.restoreConsole=l0t.default((e,r)=>{e==="stdout"&&this.writeToStdout(r),e==="stderr"&&(r.startsWith("The above error occurred")||this.writeToStderr(r))}))}};of.default=PW});var z1e=_(sD=>{"use strict";var K1e=sD&&sD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(sD,"__esModule",{value:!0});var A0t=K1e(J1e()),jF=K1e(fW()),p0t=Ie("stream"),h0t=(t,e)=>{let r=Object.assign({stdout:process.stdout,stdin:process.stdin,stderr:process.stderr,debug:!1,exitOnCtrlC:!0,patchConsole:!0},g0t(e)),s=d0t(r.stdout,()=>new A0t.default(r));return s.render(t),{rerender:s.render,unmount:()=>s.unmount(),waitUntilExit:s.waitUntilExit,cleanup:()=>jF.default.delete(r.stdout),clear:s.clear}};sD.default=h0t;var g0t=(t={})=>t instanceof p0t.Stream?{stdout:t,stdin:process.stdin}:t,d0t=(t,e)=>{let r;return jF.default.has(t)?r=jF.default.get(t):(r=e(),jF.default.set(t,r)),r}});var X1e=_(eh=>{"use strict";var m0t=eh&&eh.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),y0t=eh&&eh.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),E0t=eh&&eh.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.hasOwnProperty.call(t,r)&&m0t(e,t,r);return y0t(e,t),e};Object.defineProperty(eh,"__esModule",{value:!0});var oD=E0t(hn()),Z1e=t=>{let{items:e,children:r,style:s}=t,[a,n]=oD.useState(0),c=oD.useMemo(()=>e.slice(a),[e,a]);oD.useLayoutEffect(()=>{n(e.length)},[e.length]);let f=c.map((h,E)=>r(h,a+E)),p=oD.useMemo(()=>Object.assign({position:"absolute",flexDirection:"column"},s),[s]);return oD.default.createElement("ink-box",{internal_static:!0,style:p},f)};Z1e.displayName="Static";eh.default=Z1e});var e2e=_(aD=>{"use strict";var I0t=aD&&aD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(aD,"__esModule",{value:!0});var C0t=I0t(hn()),$1e=({children:t,transform:e})=>t==null?null:C0t.default.createElement("ink-text",{style:{flexGrow:0,flexShrink:1,flexDirection:"row"},internal_transform:e},t);$1e.displayName="Transform";aD.default=$1e});var r2e=_(lD=>{"use strict";var w0t=lD&&lD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(lD,"__esModule",{value:!0});var B0t=w0t(hn()),t2e=({count:t=1})=>B0t.default.createElement("ink-text",null,`
`.repeat(t));t2e.displayName="Newline";lD.default=t2e});var s2e=_(cD=>{"use strict";var n2e=cD&&cD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(cD,"__esModule",{value:!0});var v0t=n2e(hn()),S0t=n2e(_F()),i2e=()=>v0t.default.createElement(S0t.default,{flexGrow:1});i2e.displayName="Spacer";cD.default=i2e});var GF=_(uD=>{"use strict";var D0t=uD&&uD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(uD,"__esModule",{value:!0});var P0t=hn(),b0t=D0t(gW()),x0t=()=>P0t.useContext(b0t.default);uD.default=x0t});var a2e=_(fD=>{"use strict";var k0t=fD&&fD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(fD,"__esModule",{value:!0});var o2e=hn(),Q0t=k0t(GF()),R0t=(t,e={})=>{let{stdin:r,setRawMode:s,internal_exitOnCtrlC:a}=Q0t.default();o2e.useEffect(()=>{if(e.isActive!==!1)return s(!0),()=>{s(!1)}},[e.isActive,s]),o2e.useEffect(()=>{if(e.isActive===!1)return;let n=c=>{let f=String(c),p={upArrow:f==="\x1B[A",downArrow:f==="\x1B[B",leftArrow:f==="\x1B[D",rightArrow:f==="\x1B[C",pageDown:f==="\x1B[6~",pageUp:f==="\x1B[5~",return:f==="\r",escape:f==="\x1B",ctrl:!1,shift:!1,tab:f===" "||f==="\x1B[Z",backspace:f==="\b",delete:f==="\x7F"||f==="\x1B[3~",meta:!1};f<=""&&!p.return&&(f=String.fromCharCode(f.charCodeAt(0)+97-1),p.ctrl=!0),f.startsWith("\x1B")&&(f=f.slice(1),p.meta=!0);let h=f>="A"&&f<="Z",E=f>="\u0410"&&f<="\u042F";f.length===1&&(h||E)&&(p.shift=!0),p.tab&&f==="[Z"&&(p.shift=!0),(p.tab||p.backspace||p.delete)&&(f=""),(!(f==="c"&&p.ctrl)||!a)&&t(f,p)};return r?.on("data",n),()=>{r?.off("data",n)}},[e.isActive,r,a,t])};fD.default=R0t});var l2e=_(AD=>{"use strict";var T0t=AD&&AD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(AD,"__esModule",{value:!0});var F0t=hn(),N0t=T0t(pW()),O0t=()=>F0t.useContext(N0t.default);AD.default=O0t});var c2e=_(pD=>{"use strict";var L0t=pD&&pD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(pD,"__esModule",{value:!0});var M0t=hn(),U0t=L0t(mW()),_0t=()=>M0t.useContext(U0t.default);pD.default=_0t});var u2e=_(hD=>{"use strict";var H0t=hD&&hD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(hD,"__esModule",{value:!0});var j0t=hn(),G0t=H0t(EW()),q0t=()=>j0t.useContext(G0t.default);hD.default=q0t});var A2e=_(dD=>{"use strict";var f2e=dD&&dD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(dD,"__esModule",{value:!0});var gD=hn(),W0t=f2e(UF()),Y0t=f2e(GF()),V0t=({isActive:t=!0,autoFocus:e=!1,id:r}={})=>{let{isRawModeSupported:s,setRawMode:a}=Y0t.default(),{activeId:n,add:c,remove:f,activate:p,deactivate:h,focus:E}=gD.useContext(W0t.default),C=gD.useMemo(()=>r??Math.random().toString().slice(2,7),[r]);return gD.useEffect(()=>(c(C,{autoFocus:e}),()=>{f(C)}),[C,e]),gD.useEffect(()=>{t?p(C):h(C)},[t,C]),gD.useEffect(()=>{if(!(!s||!t))return a(!0),()=>{a(!1)}},[t]),{isFocused:!!C&&n===C,focus:E}};dD.default=V0t});var p2e=_(mD=>{"use strict";var J0t=mD&&mD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(mD,"__esModule",{value:!0});var K0t=hn(),z0t=J0t(UF()),Z0t=()=>{let t=K0t.useContext(z0t.default);return{enableFocus:t.enableFocus,disableFocus:t.disableFocus,focusNext:t.focusNext,focusPrevious:t.focusPrevious,focus:t.focus}};mD.default=Z0t});var h2e=_(bW=>{"use strict";Object.defineProperty(bW,"__esModule",{value:!0});bW.default=t=>{var e,r,s,a;return{width:(r=(e=t.yogaNode)===null||e===void 0?void 0:e.getComputedWidth())!==null&&r!==void 0?r:0,height:(a=(s=t.yogaNode)===null||s===void 0?void 0:s.getComputedHeight())!==null&&a!==void 0?a:0}}});var Wc=_(mo=>{"use strict";Object.defineProperty(mo,"__esModule",{value:!0});var X0t=z1e();Object.defineProperty(mo,"render",{enumerable:!0,get:function(){return X0t.default}});var $0t=_F();Object.defineProperty(mo,"Box",{enumerable:!0,get:function(){return $0t.default}});var egt=SW();Object.defineProperty(mo,"Text",{enumerable:!0,get:function(){return egt.default}});var tgt=X1e();Object.defineProperty(mo,"Static",{enumerable:!0,get:function(){return tgt.default}});var rgt=e2e();Object.defineProperty(mo,"Transform",{enumerable:!0,get:function(){return rgt.default}});var ngt=r2e();Object.defineProperty(mo,"Newline",{enumerable:!0,get:function(){return ngt.default}});var igt=s2e();Object.defineProperty(mo,"Spacer",{enumerable:!0,get:function(){return igt.default}});var sgt=a2e();Object.defineProperty(mo,"useInput",{enumerable:!0,get:function(){return sgt.default}});var ogt=l2e();Object.defineProperty(mo,"useApp",{enumerable:!0,get:function(){return ogt.default}});var agt=GF();Object.defineProperty(mo,"useStdin",{enumerable:!0,get:function(){return agt.default}});var lgt=c2e();Object.defineProperty(mo,"useStdout",{enumerable:!0,get:function(){return lgt.default}});var cgt=u2e();Object.defineProperty(mo,"useStderr",{enumerable:!0,get:function(){ Line truncated
`:"";return c?C+=`@IF EXIST ${c} (\r
${c} ${p} ${a} ${E}%*\r
) ELSE (\r
@SETLOCAL\r
@SET PATHEXT=%PATHEXT:;.JS;=;%\r
${f} ${p} ${a} ${E}%*\r
)\r
`:C+=`@${f} ${p} ${a} ${E}%*\r
`,C}function Pdt(t,e,r){let s=Vc.relative(Vc.dirname(e),t),a=r.prog&&r.prog.split("\\").join("/"),n;s=s.split("\\").join("/");let c=Vc.isAbsolute(s)?`"${s}"`:`"$basedir/${s}"`,f=r.args||"",p=EY(r.nodePath).posix;a?(n=`"$basedir/${r.prog}"`,s=c):(a=c,f="",s="");let h=r.progArgs?`${r.progArgs.join(" ")} `:"",E=`#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
case \`uname\` in
*CYGWIN*) basedir=\`cygpath -w "$basedir"\`;;
esac
`,C=r.nodePath?`export NODE_PATH="${p}"
`:"";return n?E+=`${C}if [ -x ${n} ]; then
exec ${n} ${f} ${s} ${h}"$@"
else
exec ${a} ${f} ${s} ${h}"$@"
fi
`:E+=`${C}${a} ${f} ${s} ${h}"$@"
exit $?
`,E}function bdt(t,e,r){let s=Vc.relative(Vc.dirname(e),t),a=r.prog&&r.prog.split("\\").join("/"),n=a&&`"${a}$exe"`,c;s=s.split("\\").join("/");let f=Vc.isAbsolute(s)?`"${s}"`:`"$basedir/${s}"`,p=r.args||"",h=EY(r.nodePath),E=h.win32,C=h.posix;n?(c=`"$basedir/${r.prog}$exe"`,s=f):(n=f,p="",s="");let S=r.progArgs?`${r.progArgs.join(" ")} `:"",b=`#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
${r.nodePath?`$env_node_path=$env:NODE_PATH
$env:NODE_PATH="${E}"
`:""}if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}`;return r.nodePath&&(b+=` else {
$env:NODE_PATH="${C}"
}`),c?b+=`
$ret=0
if (Test-Path ${c}) {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & ${c} ${p} ${s} ${S}$args
} else {
& ${c} ${p} ${s} ${S}$args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & ${n} ${p} ${s} ${S}$args
} else {
& ${n} ${p} ${s} ${S}$args
}
$ret=$LASTEXITCODE
}
${r.nodePath?`$env:NODE_PATH=$env_node_path
`:""}exit $ret
`:b+=`
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & ${n} ${p} ${s} ${S}$args
} else {
& ${n} ${p} ${s} ${S}$args
}
${r.nodePath?`$env:NODE_PATH=$env_node_path
`:""}exit $LASTEXITCODE
`,b}function xdt(t,e){return e.fs_.chmod(t,493)}function EY(t){if(!t)return{win32:"",posix:""};let e=typeof t=="string"?t.split(Vc.delimiter):Array.from(t),r={};for(let s=0;s<e.length;s++){let a=e[s].split("/").join("\\"),n=bBe()?e[s].split("\\").join("/").replace(/^([^:\\/]*):/,(c,f)=>`/mnt/${f.toLowerCase()}`):e[s];r.win32=r.win32?`${r.win32};${a}`:a,r.posix=r.posix?`${r.posix}:${n}`:n,r[s]={win32:a,posix:n}}return r}kBe.exports=yY});var TY=_((Ctr,zBe)=>{zBe.exports=Ie("stream")});var eve=_((wtr,$Be)=>{"use strict";function ZBe(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(t);e&&(s=s.filter(function(a){return Object.getOwnPropertyDescriptor(t,a).enumerable})),r.push.apply(r,s)}return r}function cmt(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?ZBe(Object(r),!0).forEach(function(s){umt(t,s,r[s])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):ZBe(Object(r)).forEach(function(s){Object.defineProperty(t,s,Object.getOwnPropertyDescriptor(r,s))})}return t}function umt(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function fmt(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function XBe(t,e){for(var r=0;r<e.length;r++){var s=e[r];s.enumerable=s.enumerable||!1,s.configurable=!0,"value"in s&&(s.writable=!0),Object.defineProperty(t,s.key,s)}}function Amt(t,e,r){return e&&XBe(t.prototype,e),r&&XBe(t,r),t}var pmt=Ie("buffer"),AN=pmt.Buffer,hmt=Ie("util"),FY=hmt.inspect,gmt=FY&&FY.custom||"inspect";function dmt(t,e,r){AN.prototype.copy.call(t,e,r)}$Be.exports=function(){function t(){fmt(this,t),this.head=null,this.tail=null,this.length=0}return Amt(t,[{key:"push",value:function(r){var s={data:r,next:null};this.length>0?this.tail.next=s:this.head=s,this.tail=s,++this.length}},{key:"unshift",value:function(r){var s={data:r,next:this.head};this.length===0&&(this.tail=s),this.head=s,++this.length}},{key:"shift",value:function(){if(this.length!==0){var r=this.head.data;return this.length===1?this.head=this.tail=null:this.head=this.head.next,--this.length,r}}},{key:"clear",value:function(){this.head=this.tail=null,this.length=0}},{key:"join",value:function(r){if(this.length===0)return"";for(var s=this.head,a=""+s.data;s=s.next;)a+=r+s.data;return a}},{key:"concat",value:function(r){if(this.length===0)return AN.alloc(0);for(var s=AN.allocUnsafe(r>>>0),a=this.head,n=0;a;)dmt(a.data,s,n),n+=a.data.length,a=a.next;return s}},{key:"consume",value:function(r,s){var a;return r<this.head.data.length?(a=this.head.data.slice(0,r),this.head.data=this.head.data.slice(r)):r===this.head.data.length?a=this.shift():a=s?this._getString(r):this._getBuffer(r),a}},{key:"first",value:function(){return this.head.data}},{key:"_getString",value:function(r){var s=this.head,a=1,n=s.data;for(r-=n.length;s=s.next;){var c=s.data,f=r>c.length?c.length:r;if(f===c.length?n+=c:n+=c.slice(0,r),r-=f,r===0){f===c.length?(++a,s.next?this.head=s.next:this.head=this.tail=null):(this.head=s,s.data=c.slice(f));break}++a}return this.length-=a,n}},{key:"_getBuffer",value:function(r){var s=AN.allocUnsafe(r),a=this.head,n=1;for(a.data.copy(s),r-=a.data.length;a=a.next;){var c=a.data,f=r>c.length?c.length:r;if(c.copy(s,s.length-r,0,f),r-=f,r===0){f===c.length?(++n,a.next?this.head=a.next:this.head=this.tail=null):(this.head=a,a.data=c.slice(f));break}++n}return this.length-=n,s}},{key:gmt,value:function(r,s){return FY(this,cmt({},s,{depth:0,customInspect:!1}))}}]),t}()});var OY=_((Btr,rve)=>{"use strict";function mmt(t,e){var r=this,s=this._readableState&&this._readableState.destroyed,a=this._writableState&&this._writableState.destroyed;return s||a?(e?e(t):t&&(this._writableState?this._writableState.errorEmitted||(this._writableState.errorEmitted=!0,process.nextTick(NY,this,t)):process.nextTick(NY,this,t)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(t||null,function(n){!e&&n?r._writableState?r._writableState.errorEmitted?process.nextTick(pN,r):(r._writableState.errorEmitted=!0,process.nextTick(tve,r,n)):process.nextTick(tve,r,n):e?(process.nextTick(pN,r),e(n)):process.nextTick(pN,r)}),this)}function tve(t,e){NY(t,e),pN(t)}function pN(t){t._writableState&&!t._writableState.emitClose||t._readableState&&!t._readableState.emitClose||t.emit("close")}function ymt(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function NY(t,e){t.emit("error",e)}function Emt(t,e){var r=t._readableState,s=t._writableState;r&& Line truncated
`)),t.linkname&&(e+=uV(" linkpath="+t.linkname+`
`));var r=t.pax;if(r)for(var s in r)e+=uV(" "+s+"="+r[s]+`
`);return Buffer.from(e)};Uw.decodePax=function(t){for(var e={};t.length;){for(var r=0;r<t.length&&t[r]!==32;)r++;var s=parseInt(t.slice(0,r).toString(),10);if(!s)return e;var a=t.slice(r+1,s-1).toString(),n=a.indexOf("=");if(n===-1)return e;e[a.slice(0,n)]=a.slice(n+1),t=t.slice(s)}return e};Uw.encode=function(t){var e=fEt(512),r=t.name,s="";if(t.typeflag===5&&r[r.length-1]!=="/"&&(r+="/"),Buffer.byteLength(r)!==r.length)return null;for(;Buffer.byteLength(r)>100;){var a=r.indexOf("/");if(a===-1)return null;s+=s?"/"+r.slice(0,a):r.slice(0,a),r=r.slice(a+1)}return Buffer.byteLength(r)>100||Buffer.byteLength(s)>155||t.linkname&&Buffer.byteLength(t.linkname)>100?null:(e.write(r),e.write(hg(t.mode&mEt,6),100),e.write(hg(t.uid,6),108),e.write(hg(t.gid,6),116),e.write(hg(t.size,11),124),e.write(hg(t.mtime.getTime()/1e3|0,11),136),e[156]=rSe+IEt(t.type),t.linkname&&e.write(t.linkname,157),nSe.copy(e,aP),hEt.copy(e,fV),t.uname&&e.write(t.uname,265),t.gname&&e.write(t.gname,297),e.write(hg(t.devmajor||0,6),329),e.write(hg(t.devminor||0,6),337),s&&e.write(s,345),e.write(hg(sSe(e),6),148),e)};Uw.decode=function(t,e,r){var s=t[156]===0?0:t[156]-rSe,a=Mw(t,0,100,e),n=gg(t,100,8),c=gg(t,108,8),f=gg(t,116,8),p=gg(t,124,12),h=gg(t,136,12),E=EEt(s),C=t[157]===0?null:Mw(t,157,100,e),S=Mw(t,265,32),b=Mw(t,297,32),I=gg(t,329,8),T=gg(t,337,8),N=sSe(t);if(N===8*32)return null;if(N!==gg(t,148,8))throw new Error("Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?");if(nSe.compare(t,aP,aP+6)===0)t[345]&&(a=Mw(t,345,155,e)+"/"+a);else if(!(gEt.compare(t,aP,aP+6)===0&&dEt.compare(t,fV,fV+2)===0)){if(!r)throw new Error("Invalid tar header: unknown format.")}return s===0&&a&&a[a.length-1]==="/"&&(s=5),{name:a,mode:n,uid:c,gid:f,size:p,mtime:new Date(1e3*h),type:E,linkname:C,uname:S,gname:b,devmajor:I,devminor:T}}});var ASe=_((Gtr,fSe)=>{var aSe=Ie("util"),wEt=tSe(),lP=AV(),lSe=Lw().Writable,cSe=Lw().PassThrough,uSe=function(){},oSe=function(t){return t&=511,t&&512-t},BEt=function(t,e){var r=new bN(t,e);return r.end(),r},vEt=function(t,e){return e.path&&(t.name=e.path),e.linkpath&&(t.linkname=e.linkpath),e.size&&(t.size=parseInt(e.size,10)),t.pax=e,t},bN=function(t,e){this._parent=t,this.offset=e,cSe.call(this,{autoDestroy:!1})};aSe.inherits(bN,cSe);bN.prototype.destroy=function(t){this._parent.destroy(t)};var ch=function(t){if(!(this instanceof ch))return new ch(t);lSe.call(this,t),t=t||{},this._offset=0,this._buffer=wEt(),this._missing=0,this._partial=!1,this._onparse=uSe,this._header=null,this._stream=null,this._overflow=null,this._cb=null,this._locked=!1,this._destroyed=!1,this._pax=null,this._paxGlobal=null,this._gnuLongPath=null,this._gnuLongLinkPath=null;var e=this,r=e._buffer,s=function(){e._continue()},a=function(S){if(e._locked=!1,S)return e.destroy(S);e._stream||s()},n=function(){e._stream=null;var S=oSe(e._header.size);S?e._parse(S,c):e._parse(512,C),e._locked||s()},c=function(){e._buffer.consume(oSe(e._header.size)),e._parse(512,C),s()},f=function(){var S=e._header.size;e._paxGlobal=lP.decodePax(r.slice(0,S)),r.consume(S),n()},p=function(){var S=e._header.size;e._pax=lP.decodePax(r.slice(0,S)),e._paxGlobal&&(e._pax=Object.assign({},e._paxGlobal,e._pax)),r.consume(S),n()},h=function(){var S=e._header.size;this._gnuLongPath=lP.decodeLongPath(r.slice(0,S),t.filenameEncoding),r.consume(S),n()},E=function(){var S=e._header.size;this._gnuLongLinkPath=lP.decodeLongPath(r.slice(0,S),t.filenameEncoding),r.consume(S),n()},C=function(){var S=e._offset,b;try{b=e._header=lP.decode(r.slice(0,512),t.filenameEncoding,t.allowUnknownFormat)}catch(I){e.emit("error",I)}if(r.consume(512),!b){e._parse(512,C),s();return}if(b.type==="gnu-long-path"){e._parse(b.size,h),s();return}if(b.type==="gnu-long-link-path"){e._parse(b.size,E),s();return}if(b.type==="pax-global-header"){e._parse(b.size,f),s();return}if(b.type==="pax-header"){e._parse(b.size,p),s();return}if(e._gnuLongPath&&(b.name=e._gnuLongPath,e._gnuLongPath=null),e._gnuLongLinkPath&&(b.linkname=e._gnuLongLinkPath,e._gnuLongLinkPath=null),e._pax&&(e._header=b=vEt(b,e._pax),e._pax=null),e._locked=!0,!b.size||b.type==="directory"){e._parse(512,C),e.emit("entry",b,BEt(e,S),a);return}e._stream=new bN(e,S),e.emit("entry",b,e._stream,a),e._parse(b.size,n),s()};this._onheader=C,this._parse(512,C)};aSe.inherits(ch,lSe);ch.prototype.destroy=function(t){this._destroyed||(this._destroyed=!0,t&&this.emit("error",t),this.emit("close"),this._stream&&this._stream.emit("close"))};ch.prototype._parse=function(t,e){this._destroyed||(this._offset+=t,this._missing=t,e===this._onheader&&(this._partial=!1),this._onparse=e)};ch.prototype._continue=function(){if(!this._destroyed){var t=this._cb;this._cb=uSe,this._overflow?this._write(this._overflow,void 0,t):t()}};ch.prototype._write=function(t,e,r){if(!this._destroyed){var s=this._stream,a=this._buffer,n=this._missing;if(t.length&&(this._partial=!0),t.length<n)return this._missing-=t.length,this._overflow=null,s?s.write(t,r):(a.append(t), Line truncated
Wanted: ${this.expectedSize}
Found: ${this.size}`);s.code="EBADSIZE",s.found=this.size,s.expected=this.expectedSize,s.sri=this.sri,this.emit("error",s)}else if(this.sri&&!r){let s=new Error(`${this.sri} integrity checksum failed when using ${this.algorithm}: wanted ${this.digests} but got ${e}. (${this.size} bytes)`);s.code="EINTEGRITY",s.found=e,s.expected=this.digests,s.algorithm=this.algorithm,s.sri=this.sri,this.emit("error",s)}else this.#r=this.size,this.emit("size",this.size),this.#t=e,this.emit("integrity",e),r&&(this.#i=r,this.emit("verified",r))}},Ah=class{get isHash(){return!0}constructor(e,r){let s=r?.strict;this.source=e.trim(),this.digest="",this.algorithm="",this.options=[];let a=this.source.match(s?rIt:tIt);if(!a||s&&!xV.includes(a[1]))return;this.algorithm=a[1],this.digest=a[2];let n=a[3];n&&(this.options=n.slice(1).split("?"))}hexDigest(){return this.digest&&Buffer.from(this.digest,"base64").toString("hex")}toJSON(){return this.toString()}match(e,r){let s=nc(e,r);if(!s)return!1;if(s.isIntegrity){let a=s.pickAlgorithm(r,[this.algorithm]);if(!a)return!1;let n=s[a].find(c=>c.digest===this.digest);return n||!1}return s.digest===this.digest?s:!1}toString(e){return e?.strict&&!(xV.includes(this.algorithm)&&this.digest.match(eIt)&&this.options.every(r=>r.match(nIt)))?"":`${this.algorithm}-${this.digest}${dP(this.options)}`}};function FSe(t,e,r,s){let a=t!=="",n=!1,c="",f=s.length-1;for(let h=0;h<f;h++){let E=Ah.prototype.toString.call(s[h],r);E&&(n=!0,c+=E,c+=e)}let p=Ah.prototype.toString.call(s[f],r);return p&&(n=!0,c+=p),a&&n?t+e+c:t+c}var Zm=class{get isIntegrity(){return!0}toJSON(){return this.toString()}isEmpty(){return Object.keys(this).length===0}toString(e){let r=e?.sep||" ",s="";if(e?.strict){r=r.replace(/\S+/g," ");for(let a of xV)this[a]&&(s=FSe(s,r,e,this[a]))}else for(let a of Object.keys(this))s=FSe(s,r,e,this[a]);return s}concat(e,r){let s=typeof e=="string"?e:hP(e,r);return nc(`${this.toString(r)} ${s}`,r)}hexDigest(){return nc(this,{single:!0}).hexDigest()}merge(e,r){let s=nc(e,r);for(let a in s)if(this[a]){if(!this[a].find(n=>s[a].find(c=>n.digest===c.digest)))throw new Error("hashes do not match, cannot update integrity")}else this[a]=s[a]}match(e,r){let s=nc(e,r);if(!s)return!1;let a=s.pickAlgorithm(r,Object.keys(this));return!!a&&this[a]&&s[a]&&this[a].find(n=>s[a].find(c=>n.digest===c.digest))||!1}pickAlgorithm(e,r){let s=e?.pickAlgorithm||fIt,a=Object.keys(this).filter(n=>r?.length?r.includes(n):!0);return a.length?a.reduce((n,c)=>s(n,c)||n):null}};IA.exports.parse=nc;function nc(t,e){if(!t)return null;if(typeof t=="string")return bV(t,e);if(t.algorithm&&t.digest){let r=new Zm;return r[t.algorithm]=[t],bV(hP(r,e),e)}else return bV(hP(t,e),e)}function bV(t,e){if(e?.single)return new Ah(t,e);let r=t.trim().split(/\s+/).reduce((s,a)=>{let n=new Ah(a,e);if(n.algorithm&&n.digest){let c=n.algorithm;s[c]||(s[c]=[]),s[c].push(n)}return s},new Zm);return r.isEmpty()?null:r}IA.exports.stringify=hP;function hP(t,e){return t.algorithm&&t.digest?Ah.prototype.toString.call(t,e):typeof t=="string"?hP(nc(t,e),e):Zm.prototype.toString.call(t,e)}IA.exports.fromHex=iIt;function iIt(t,e,r){let s=dP(r?.options);return nc(`${e}-${Buffer.from(t,"hex").toString("base64")}${s}`,r)}IA.exports.fromData=sIt;function sIt(t,e){let r=e?.algorithms||[...QV],s=dP(e?.options);return r.reduce((a,n)=>{let c=gP.createHash(n).update(t).digest("base64"),f=new Ah(`${n}-${c}${s}`,e);if(f.algorithm&&f.digest){let p=f.algorithm;a[p]||(a[p]=[]),a[p].push(f)}return a},new Zm)}IA.exports.fromStream=oIt;function oIt(t,e){let r=RV(e);return new Promise((s,a)=>{t.pipe(r),t.on("error",a),r.on("error",a);let n;r.on("integrity",c=>{n=c}),r.on("end",()=>s(n)),r.resume()})}IA.exports.checkData=aIt;function aIt(t,e,r){if(e=nc(e,r),!e||!Object.keys(e).length){if(r?.error)throw Object.assign(new Error("No valid integrity hashes to check against"),{code:"EINTEGRITY"});return!1}let s=e.pickAlgorithm(r),a=gP.createHash(s).update(t).digest("base64"),n=nc({algorithm:s,digest:a}),c=n.match(e,r);if(r=r||{},c||!r.error)return c;if(typeof r.size=="number"&&t.length!==r.size){let f=new Error(`data size mismatch when checking ${e}.
Wanted: ${r.size}
Found: ${t.length}`);throw f.code="EBADSIZE",f.found=t.length,f.expected=r.size,f.sri=e,f}else{let f=new Error(`Integrity checksum failed when using ${s}: Wanted ${e}, but got ${n}. (${t.length} bytes)`);throw f.code="EINTEGRITY",f.found=n,f.expected=e,f.algorithm=s,f.sri=e,f}}IA.exports.checkStream=lIt;function lIt(t,e,r){if(r=r||Object.create(null),r.integrity=e,e=nc(e,r),!e||!Object.keys(e).length)return Promise.reject(Object.assign(new Error("No valid integrity hashes to check against"),{code:"EINTEGRITY"}));let s=RV(r);return new Promise((a,n)=>{t.pipe(s),t.on("error",n),s.on("error",n);let c;s.on("verified",f=>{c=f}),s.on("end",()=>a(c)),s.resume()})}IA.exports.integrityStream=RV;function RV(t=Object.create(null)){return new kV(t)}IA.exports.create=cIt;function cIt(t){let e=t?.algorithms||[...QV],r=dP(t?.options),s=e.map(gP.createHash);return{update:function(a,n){return s.forEach(c=>c.update(a,n)),this},digest:function(){return e.reduce((n,c)=>{let f=s.shift().digest("base64"),p=new Ah(`${c}-${f}${r}`,t);if(p.algorithm&&p.digest){let h=p.algorithm;n[h]||(n[h]=[]),n[h].push(p)}return n},new Zm)}}}var uIt=gP.getHashes(),NSe=["md5","whirlpool","sha1","sha224","sha256","sha384","sha512","sha3","sha3-256","sha3-384","sha3-512","sha3_256","sha3_384","sha3_512"].filter(t=>uIt.includes(t));function fIt(t,e){return NSe.indexOf(t.toLowerCase())>=NSe.indexOf(e.toLowerCase())?t:e}});var TV=_(mg=>{"use strict";Object.defineProperty(mg,"__esModule",{value:!0});mg.Signature=mg.Envelope=void 0;mg.Envelope={fromJSON(t){return{payload:jN(t.payload)?Buffer.from(LSe(t.payload)):Buffer.alloc(0),payloadType:jN(t.payloadType)?globalThis.String(t.payloadType):"",signatures:globalThis.Array.isArray(t?.signatures)?t.signatures.map(e=>mg.Signature.fromJSON(e)):[]}},toJSON(t){let e={};return t.payload.length!==0&&(e.payload=MSe(t.payload)),t.payloadType!==""&&(e.payloadType=t.payloadType),t.signatures?.length&&(e.signatures=t.signatures.map(r=>mg.Signature.toJSON(r))),e}};mg.Signature={fromJSON(t){return{sig:jN(t.sig)?Buffer.from(LSe(t.sig)):Buffer.alloc(0),keyid:jN(t.keyid)?globalThis.String(t.keyid):""}},toJSON(t){let e={};return t.sig.length!==0&&(e.sig=MSe(t.sig)),t.keyid!==""&&(e.keyid=t.keyid),e}};function LSe(t){return Uint8Array.from(globalThis.Buffer.from(t,"base64"))}function MSe(t){return globalThis.Buffer.from(t).toString("base64")}function jN(t){return t!=null}});var _Se=_(GN=>{"use strict";Object.defineProperty(GN,"__esModule",{value:!0});GN.Timestamp=void 0;GN.Timestamp={fromJSON(t){return{seconds:USe(t.seconds)?globalThis.String(t.seconds):"0",nanos:USe(t.nanos)?globalThis.Number(t.nanos):0}},toJSON(t){let e={};return t.seconds!=="0"&&(e.seconds=t.seconds),t.nanos!==0&&(e.nanos=Math.round(t.nanos)),e}};function USe(t){return t!=null}});var Ww=_(Ur=>{"use strict";Object.defineProperty(Ur,"__esModule",{value:!0});Ur.TimeRange=Ur.X509CertificateChain=Ur.SubjectAlternativeName=Ur.X509Certificate=Ur.DistinguishedName=Ur.ObjectIdentifierValuePair=Ur.ObjectIdentifier=Ur.PublicKeyIdentifier=Ur.PublicKey=Ur.RFC3161SignedTimestamp=Ur.LogId=Ur.MessageSignature=Ur.HashOutput=Ur.SubjectAlternativeNameType=Ur.PublicKeyDetails=Ur.HashAlgorithm=void 0;Ur.hashAlgorithmFromJSON=jSe;Ur.hashAlgorithmToJSON=GSe;Ur.publicKeyDetailsFromJSON=qSe;Ur.publicKeyDetailsToJSON=WSe;Ur.subjectAlternativeNameTypeFromJSON=YSe;Ur.subjectAlternativeNameTypeToJSON=VSe;var AIt=_Se(),yl;(function(t){t[t.HASH_ALGORITHM_UNSPECIFIED=0]="HASH_ALGORITHM_UNSPECIFIED",t[t.SHA2_256=1]="SHA2_256",t[t.SHA2_384=2]="SHA2_384",t[t.SHA2_512=3]="SHA2_512",t[t.SHA3_256=4]="SHA3_256",t[t.SHA3_384=5]="SHA3_384"})(yl||(Ur.HashAlgorithm=yl={}));function jSe(t){switch(t){case 0:case"HASH_ALGORITHM_UNSPECIFIED":return yl.HASH_ALGORITHM_UNSPECIFIED;case 1:case"SHA2_256":return yl.SHA2_256;case 2:case"SHA2_384":return yl.SHA2_384;case 3:case"SHA2_512":return yl.SHA2_512;case 4:case"SHA3_256":return yl.SHA3_256;case 5:case"SHA3_384":return yl.SHA3_384;default:throw new globalThis.Error("Unrecognized enum value "+t+" for enum HashAlgorithm")}}function GSe(t){switch(t){case yl.HASH_ALGORITHM_UNSPECIFIED:return"HASH_ALGORITHM_UNSPECIFIED";case yl.SHA2_256:return"SHA2_256";case yl.SHA2_384:return"SHA2_384";case yl.SHA2_512:return"SHA2_512";case yl.SHA3_256:return"SHA3_256";case yl.SHA3_384:return"SHA3_384";default:throw new globalThis.Error("Unrecognized enum value "+t+" for enum HashAlgorithm")}}var rn;(function(t){t[t.PUBLIC_KEY_DETAILS_UNSPECIFIED=0]="PUBLIC_KEY_DETAILS_UNSPECIFIED",t[t.PKCS1_RSA_PKCS1V5=1]="PKCS1_RSA_PKCS1V5",t[t.PKCS1_RSA_PSS=2]="PKCS1_RSA_PSS",t[t.PKIX_RSA_PKCS1V5=3]="PKIX_RSA_PKCS1V5",t[t.PKIX_RSA_PSS=4]="PKIX_RSA_PSS",t[t.PKIX_RSA_PKCS1V15_2048_SHA256=9]="PKIX_RSA_PKCS1V15_2048_SHA256",t[t.PKIX_RSA_PKCS1V15_3072_SHA256=10]="PKIX_RSA_PKCS1V15_3072_SHA256",t[t.PKIX_RSA_PKCS1V15_4096_SHA256=11]="PKIX_RSA_PKCS1V15_4096_SHA256",t[t.PKIX_RSA_PSS_2048_SHA256=16]="PKIX_RSA_PSS_2048_SHA256",t[t.PKIX_RSA_PSS_3072_SHA256=17]="PKIX_RSA_PSS_3072_SHA256",t[t.PKIX_RS Line truncated
`).forEach(r=>{r.match(iCt)||r.match(sCt)||(e+=r)}),Buffer.from(e,"base64")}function aCt(t,e="CERTIFICATE"){let s=t.toString("base64").match(/.{1,64}/g)||"";return[`-----BEGIN ${e}-----`,...s,`-----END ${e}-----`].join(`
`).concat(`
`)}});var fO=_(zw=>{"use strict";Object.defineProperty(zw,"__esModule",{value:!0});zw.SHA2_HASH_ALGOS=zw.ECDSA_SIGNATURE_ALGOS=void 0;zw.ECDSA_SIGNATURE_ALGOS={"1.2.840.10045.4.3.1":"sha224","1.2.840.10045.4.3.2":"sha256","1.2.840.10045.4.3.3":"sha384","1.2.840.10045.4.3.4":"sha512"};zw.SHA2_HASH_ALGOS={"2.16.840.1.101.3.4.2.1":"sha256","2.16.840.1.101.3.4.2.2":"sha384","2.16.840.1.101.3.4.2.3":"sha512"}});var XV=_(AO=>{"use strict";Object.defineProperty(AO,"__esModule",{value:!0});AO.RFC3161TimestampVerificationError=void 0;var ZV=class extends Error{};AO.RFC3161TimestampVerificationError=ZV});var BDe=_(vA=>{"use strict";var lCt=vA&&vA.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||("get"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),cCt=vA&&vA.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),uCt=vA&&vA.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.prototype.hasOwnProperty.call(t,r)&&lCt(e,t,r);return cCt(e,t),e};Object.defineProperty(vA,"__esModule",{value:!0});vA.TSTInfo=void 0;var wDe=uCt(Kw()),fCt=fO(),ACt=XV(),$V=class{constructor(e){this.root=e}get version(){return this.root.subs[0].toInteger()}get genTime(){return this.root.subs[4].toDate()}get messageImprintHashAlgorithm(){let e=this.messageImprintObj.subs[0].subs[0].toOID();return fCt.SHA2_HASH_ALGOS[e]}get messageImprintHashedMessage(){return this.messageImprintObj.subs[1].value}get raw(){return this.root.toDER()}verify(e){let r=wDe.digest(this.messageImprintHashAlgorithm,e);if(!wDe.bufferEqual(r,this.messageImprintHashedMessage))throw new ACt.RFC3161TimestampVerificationError("message imprint does not match artifact")}get messageImprintObj(){return this.root.subs[2]}};vA.TSTInfo=$V});var SDe=_(SA=>{"use strict";var pCt=SA&&SA.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||("get"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),hCt=SA&&SA.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),gCt=SA&&SA.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.prototype.hasOwnProperty.call(t,r)&&pCt(e,t,r);return hCt(e,t),e};Object.defineProperty(SA,"__esModule",{value:!0});SA.RFC3161Timestamp=void 0;var dCt=lO(),e7=gCt(Kw()),vDe=fO(),wP=XV(),mCt=BDe(),yCt="1.2.840.113549.1.7.2",ECt="1.2.840.113549.1.9.16.1.4",ICt="1.2.840.113549.1.9.4",t7=class t{constructor(e){this.root=e}static parse(e){let r=dCt.ASN1Obj.parseBuffer(e);return new t(r)}get status(){return this.pkiStatusInfoObj.subs[0].toInteger()}get contentType(){return this.contentTypeObj.toOID()}get eContentType(){return this.eContentTypeObj.toOID()}get signingTime(){return this.tstInfo.genTime}get signerIssuer(){return this.signerSidObj.subs[0].value}get signerSerialNumber(){return this.signerSidObj.subs[1].value}get signerDigestAlgorithm(){let e=this.signerDigestAlgorithmObj.subs[0].toOID();return vDe.SHA2_HASH_ALGOS[e]}get signatureAlgorithm(){let e=this.signatureAlgorithmObj.subs[0].toOID();return vDe.ECDSA_SIGNATURE_ALGOS[e]}get signatureValue(){return this.signatureValueObj.value}get tstInfo(){return new mCt.TSTInfo(this.eContentObj.subs[0].subs[0])}verify(e,r){if(!this.timeStampTokenObj)throw new wP.RFC3161TimestampVerificationError("timeStampToken is missing");if(this.contentType!==yCt)throw new wP.RFC3161TimestampVerificationError(`incorrect content type: ${this.contentType}`);if(this.eContentType!==ECt)throw new wP.RFC3161TimestampVerificationError(`incorrect encapsulated content type: ${this.eContentType}`);this.tstInfo.verify(e),this.verifyMessageDigest(),this.verifySignature(r)}verifyMessageDigest(){let e=e7.digest(this.signerDigestAlgorithm,this.tstInfo.raw),r=this.messageDigestAttributeObj.subs[1].subs[0].value;if(!e7.bufferEqual(e,r))throw new wP.RFC3161TimestampVerificationError("signed data does not match tstInfo")}verifySignature(e){let r=this.signedAttrsObj.toDER();if(r[0]=49,!e7.verify(r,e,this.signatureValue,this.signatureAlgorithm))throw new wP.RFC3161TimestampVerificationError("signature verification failed")}get pkiStatusInfoObj(){return this.root.subs[0]}get timeStampTokenObj(){return this.root.subs[1]}get contentTypeObj(){return this.timeStampTokenObj.subs[0]}get signedDataObj(){return this.timeStampTokenObj.subs.find(r=>r.tag.isContextSpecific(0)).subs[0]}get encapContentInfoObj(){return this.signedDataObj.subs[2]}get signerInfosObj(){let e=this.signedDataObj;return e.subs[e.subs.length-1]}get sig Line truncated
globstar while`,e,S,r,b,I),this.matchOne(e.slice(S),r.slice(b),s))return this.debug("globstar found match!",S,p,I),!0;if(I==="."||I===".."||!a.dot&&I.charAt(0)==="."){this.debug("dot detected!",e,S,r,b);break}this.debug("globstar swallow a segment, and continue"),S++}return!!(s&&(this.debug(`
>>> no match, partial?`,e,S,r,b),S===p))}let T;if(typeof E=="string"?(T=C===E,this.debug("string match",E,C,T)):(T=E.test(C),this.debug("pattern match",E,C,T)),!T)return!1}if(c===p&&f===h)return!0;if(c===p)return s;if(f===h)return c===p-1&&e[c]==="";throw new Error("wtf?")}braceExpand(){return(0,pr.braceExpand)(this.pattern,this.options)}parse(e){(0,GO.assertValidPattern)(e);let r=this.options;if(e==="**")return pr.GLOBSTAR;if(e==="")return"";let s,a=null;(s=e.match(U2t))?a=r.dot?H2t:_2t:(s=e.match(x2t))?a=(r.nocase?r.dot?T2t:R2t:r.dot?Q2t:k2t)(s[1]):(s=e.match(j2t))?a=(r.nocase?r.dot?q2t:G2t:r.dot?W2t:Y2t)(s):(s=e.match(F2t))?a=r.dot?O2t:N2t:(s=e.match(L2t))&&(a=M2t);let n=mbe.AST.fromGlob(e,this.options).toMMPattern();return a&&typeof n=="object"&&Reflect.defineProperty(n,"test",{value:a}),n}makeRe(){if(this.regexp||this.regexp===!1)return this.regexp;let e=this.set;if(!e.length)return this.regexp=!1,this.regexp;let r=this.options,s=r.noglobstar?J2t:r.dot?K2t:z2t,a=new Set(r.nocase?["i"]:[]),n=e.map(p=>{let h=p.map(E=>{if(E instanceof RegExp)for(let C of E.flags.split(""))a.add(C);return typeof E=="string"?rBt(E):E===pr.GLOBSTAR?pr.GLOBSTAR:E._src});return h.forEach((E,C)=>{let S=h[C+1],b=h[C-1];E!==pr.GLOBSTAR||b===pr.GLOBSTAR||(b===void 0?S!==void 0&&S!==pr.GLOBSTAR?h[C+1]="(?:\\/|"+s+"\\/)?"+S:h[C]=s:S===void 0?h[C-1]=b+"(?:\\/|"+s+")?":S!==pr.GLOBSTAR&&(h[C-1]=b+"(?:\\/|\\/"+s+"\\/)"+S,h[C+1]=pr.GLOBSTAR))}),h.filter(E=>E!==pr.GLOBSTAR).join("/")}).join("|"),[c,f]=e.length>1?["(?:",")"]:["",""];n="^"+c+n+f+"$",this.negate&&(n="^(?!"+n+").+$");try{this.regexp=new RegExp(n,[...a].join(""))}catch{this.regexp=!1}return this.regexp}slashSplit(e){return this.preserveMultipleSlashes?e.split("/"):this.isWindows&&/^\/\/[^\/]+/.test(e)?["",...e.split(/\/+/)]:e.split(/\/+/)}match(e,r=this.partial){if(this.debug("match",e,this.pattern),this.comment)return!1;if(this.empty)return e==="";if(e==="/"&&r)return!0;let s=this.options;this.isWindows&&(e=e.split("\\").join("/"));let a=this.slashSplit(e);this.debug(this.pattern,"split",a);let n=this.set;this.debug(this.pattern,"set",n);let c=a[a.length-1];if(!c)for(let f=a.length-2;!c&&f>=0;f--)c=a[f];for(let f=0;f<n.length;f++){let p=n[f],h=a;if(s.matchBase&&p.length===1&&(h=[c]),this.matchOne(h,p,r))return s.flipNegate?!0:!this.negate}return s.flipNegate?!1:this.negate}static defaults(e){return pr.minimatch.defaults(e).Minimatch}};pr.Minimatch=ly;var nBt=eJ();Object.defineProperty(pr,"AST",{enumerable:!0,get:function(){return nBt.AST}});var iBt=tJ();Object.defineProperty(pr,"escape",{enumerable:!0,get:function(){return iBt.escape}});var sBt=MO();Object.defineProperty(pr,"unescape",{enumerable:!0,get:function(){return sBt.unescape}});pr.minimatch.AST=mbe.AST;pr.minimatch.Minimatch=ly;pr.minimatch.escape=D2t.escape;pr.minimatch.unescape=P2t.unescape});var iJ=_(ru=>{"use strict";var wbe=ru&&ru.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(ru,"__esModule",{value:!0});ru.SuccinctRoles=ru.DelegatedRole=ru.Role=ru.TOP_LEVEL_ROLE_NAMES=void 0;var Bbe=wbe(Ie("crypto")),oBt=Cbe(),qO=wbe(Ie("util")),WO=bA(),cy=ff();ru.TOP_LEVEL_ROLE_NAMES=["root","targets","snapshot","timestamp"];var LP=class t{constructor(e){let{keyIDs:r,threshold:s,unrecognizedFields:a}=e;if(aBt(r))throw new WO.ValueError("duplicate key IDs found");if(s<1)throw new WO.ValueError("threshold must be at least 1");this.keyIDs=r,this.threshold=s,this.unrecognizedFields=a||{}}equals(e){return e instanceof t?this.threshold===e.threshold&&qO.default.isDeepStrictEqual(this.keyIDs,e.keyIDs)&&qO.default.isDeepStrictEqual(this.unrecognizedFields,e.unrecognizedFields):!1}toJSON(){return{keyids:this.keyIDs,threshold:this.threshold,...this.unrecognizedFields}}static fromJSON(e){let{keyids:r,threshold:s,...a}=e;if(!cy.guard.isStringArray(r))throw new TypeError("keyids must be an array");if(typeof s!="number")throw new TypeError("threshold must be a number");return new t({keyIDs:r,threshold:s,unrecognizedFields:a})}};ru.Role=LP;function aBt(t){return new Set(t).size!==t.length}var rJ=class t extends LP{constructor(e){super(e);let{name:r,terminating:s,paths:a,pathHashPrefixes:n}=e;if(this.name=r,this.terminating=s,e.paths&&e.pathHashPrefixes)throw new WO.ValueError("paths and pathHashPrefixes are mutually exclusive");this.paths=a,this.pathHashPrefixes=n}equals(e){return e instanceof t?super.equals(e)&&this.name===e.name&&this.terminating===e.terminating&&qO.default.isDeepStrictEqual(this.paths,e.paths)&&qO.default.isDeepStrictEqual(this.pathHashPrefixes,e.pathHashPrefixes):!1}isDelegatedPath(e){if(this.paths)return this.paths.some(r=>cBt(e,r));if(this.pathHashPrefixes){let s=Bbe.default.createHash("sha256").update(e).digest("hex");return this.pathHashPrefixes.some(a=>s.startsWith(a))}return!1}toJSON(){let e={...super.toJSON(),name:this.name,terminating:this.terminating};return this.paths&&(e.paths=this.paths),this.pathHashPrefixes&&(e.path_hash_prefixes=this.pathHashPrefixes),e}static fro Line truncated
`).join(`
`+n),t.push(a+"m+"+nL.exports.humanize(this.diff)+"\x1B[0m")}else t[0]=fvt()+e+" "+t[0]}function fvt(){return Xs.inspectOpts.hideDate?"":new Date().toISOString()+" "}function Avt(...t){return process.stderr.write(rL.formatWithOptions(Xs.inspectOpts,...t)+`
`)}function pvt(t){t?process.env.DEBUG=t:delete process.env.DEBUG}function hvt(){return process.env.DEBUG}function gvt(t){t.inspectOpts={};let e=Object.keys(Xs.inspectOpts);for(let r=0;r<e.length;r++)t.inspectOpts[e[r]]=Xs.inspectOpts[e[r]]}nL.exports=vJ()(Xs);var{formatters:Mbe}=nL.exports;Mbe.o=function(t){return this.inspectOpts.colors=this.useColors,rL.inspect(t,this.inspectOpts).split(`
`).map(e=>e.trim()).join(" ")};Mbe.O=function(t){return this.inspectOpts.colors=this.useColors,rL.inspect(t,this.inspectOpts)}});var DJ=_((cir,SJ)=>{typeof process>"u"||process.type==="renderer"||process.browser===!0||process.__nwjs?SJ.exports=Lbe():SJ.exports=Ube()});var sL=_(Ji=>{"use strict";Object.defineProperty(Ji,"__esModule",{value:!0});Ji.DownloadHTTPError=Ji.DownloadLengthMismatchError=Ji.DownloadError=Ji.ExpiredMetadataError=Ji.EqualVersionError=Ji.BadVersionError=Ji.RepositoryError=Ji.PersistError=Ji.RuntimeError=Ji.ValueError=void 0;var PJ=class extends Error{};Ji.ValueError=PJ;var bJ=class extends Error{};Ji.RuntimeError=bJ;var xJ=class extends Error{};Ji.PersistError=xJ;var UP=class extends Error{};Ji.RepositoryError=UP;var iL=class extends UP{};Ji.BadVersionError=iL;var kJ=class extends iL{};Ji.EqualVersionError=kJ;var QJ=class extends UP{};Ji.ExpiredMetadataError=QJ;var _P=class extends Error{};Ji.DownloadError=_P;var RJ=class extends _P{};Ji.DownloadLengthMismatchError=RJ;var TJ=class extends _P{constructor(e,r){super(e),this.statusCode=r}};Ji.DownloadHTTPError=TJ});var Hbe=_(d1=>{"use strict";var NJ=d1&&d1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(d1,"__esModule",{value:!0});d1.withTempFile=void 0;var FJ=NJ(Ie("fs/promises")),dvt=NJ(Ie("os")),_be=NJ(Ie("path")),mvt=async t=>yvt(async e=>t(_be.default.join(e,"tempfile")));d1.withTempFile=mvt;var yvt=async t=>{let e=await FJ.default.realpath(dvt.default.tmpdir()),r=await FJ.default.mkdtemp(e+_be.default.sep);try{return await t(r)}finally{await FJ.default.rm(r,{force:!0,recursive:!0,maxRetries:3})}}});var LJ=_(kg=>{"use strict";var aL=kg&&kg.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(kg,"__esModule",{value:!0});kg.DefaultFetcher=kg.BaseFetcher=void 0;var Evt=aL(DJ()),jbe=aL(Ie("fs")),Ivt=aL(IO()),Cvt=aL(Ie("util")),Gbe=sL(),wvt=Hbe(),Bvt=(0,Evt.default)("tuf:fetch"),oL=class{async downloadFile(e,r,s){return(0,wvt.withTempFile)(async a=>{let n=await this.fetch(e),c=0,f=jbe.default.createWriteStream(a);try{for await(let p of n){let h=Buffer.from(p);if(c+=h.length,c>r)throw new Gbe.DownloadLengthMismatchError("Max length reached");await vvt(f,h)}}finally{await Cvt.default.promisify(f.close).bind(f)()}return s(a)})}async downloadBytes(e,r){return this.downloadFile(e,r,async s=>{let a=jbe.default.createReadStream(s),n=[];for await(let c of a)n.push(c);return Buffer.concat(n)})}};kg.BaseFetcher=oL;var OJ=class extends oL{constructor(e={}){super(),this.timeout=e.timeout,this.retry=e.retry}async fetch(e){Bvt("GET %s",e);let r=await(0,Ivt.default)(e,{timeout:this.timeout,retry:this.retry});if(!r.ok||!r?.body)throw new Gbe.DownloadHTTPError("Failed to download",r.status);return r.body}};kg.DefaultFetcher=OJ;var vvt=async(t,e)=>new Promise((r,s)=>{t.write(e,a=>{a&&s(a),r(!0)})})});var qbe=_(lL=>{"use strict";Object.defineProperty(lL,"__esModule",{value:!0});lL.defaultConfig=void 0;lL.defaultConfig={maxRootRotations:256,maxDelegations:32,rootMaxLength:512e3,timestampMaxLength:16384,snapshotMaxLength:2e6,targetsMaxLength:5e6,prefixTargetsWithHash:!0,fetchTimeout:1e5,fetchRetries:void 0,fetchRetry:2}});var Wbe=_(cL=>{"use strict";Object.defineProperty(cL,"__esModule",{value:!0});cL.TrustedMetadataStore=void 0;var Es=$O(),_i=sL(),MJ=class{constructor(e){this.trustedSet={},this.referenceTime=new Date,this.loadTrustedRoot(e)}get root(){if(!this.trustedSet.root)throw new ReferenceError("No trusted root metadata");return this.trustedSet.root}get timestamp(){return this.trustedSet.timestamp}get snapshot(){return this.trustedSet.snapshot}get targets(){return this.trustedSet.targets}getRole(e){return this.trustedSet[e]}updateRoot(e){let r=JSON.parse(e.toString("utf8")),s=Es.Metadata.fromJSON(Es.MetadataKind.Root,r);if(s.signed.type!=Es.MetadataKind.Root)throw new _i.RepositoryError(`Expected 'root', got ${s.signed.type}`);if(this.root.verifyDelegate(Es.MetadataKind.Root,s),s.signed.version!=this.root.signed.version+1)throw new _i.BadVersionError(`Expected version ${this.root.signed.version+1}, got ${s.signed.version}`);return s.verifyDelegate(Es.MetadataKind.Root,s),this.trustedSet.root=s,s}updateTimestamp(e){if(this.snapshot)throw new _i.RuntimeError("Cannot update timestamp after snapshot");if(this.root.signed.isExpired(this.referenceTime))throw new _i.ExpiredMetadataError("Final root.json is expired");let r=JSON.parse(e.toString("utf8")),s=Es.Metadata.fromJSON(Es.MetadataKind.Timestamp,r);if(s.signed.type!=Es.MetadataKind.Timestamp)throw new _i.RepositoryError(`Expected 'timestamp', got ${s.signed.type}`);if(this.root.verifyDelegate(Es.MetadataKind.Timestamp,s),this.timestamp){if(s.signed.version<this.timestamp.signed.version)throw new _i.BadVersionError(`New timestamp version ${s.signed.version} is less than current version ${this.timestamp.signed.version}`);if(s.signed.version===this.timestamp.signed.version)throw new _i.EqualVersionError(`New timestamp version ${s.sLine truncated
`,RSt=/\u2014 (\S+) (\S+)\n/g;function TSt(t,e){let r=(0,QSt.filterTLogAuthorities)(e,{targetDate:new Date(Number(t.integratedTime)*1e3)}),s=t.inclusionProof,a=oK.fromString(s.checkpoint.envelope),n=aK.fromString(a.note);if(!FSt(a,r))throw new I1.VerificationError({code:"TLOG_INCLUSION_PROOF_ERROR",message:"invalid checkpoint signature"});if(!sK.crypto.bufferEqual(n.logHash,s.rootHash))throw new I1.VerificationError({code:"TLOG_INCLUSION_PROOF_ERROR",message:"root hash mismatch"})}function FSt(t,e){let r=Buffer.from(t.note,"utf-8");return t.signatures.every(s=>{let a=e.find(n=>sK.crypto.bufferEqual(n.logID.subarray(0,4),s.keyHint));return a?sK.crypto.verify(r,a.publicKey,s.signature):!1})}var oK=class t{constructor(e,r){this.note=e,this.signatures=r}static fromString(e){if(!e.includes(iK))throw new I1.VerificationError({code:"TLOG_INCLUSION_PROOF_ERROR",message:"missing checkpoint separator"});let r=e.indexOf(iK),s=e.slice(0,r+1),n=e.slice(r+iK.length).matchAll(RSt),c=Array.from(n,f=>{let[,p,h]=f,E=Buffer.from(h,"base64");if(E.length<5)throw new I1.VerificationError({code:"TLOG_INCLUSION_PROOF_ERROR",message:"malformed checkpoint signature"});return{name:p,keyHint:E.subarray(0,4),signature:E.subarray(4)}});if(c.length===0)throw new I1.VerificationError({code:"TLOG_INCLUSION_PROOF_ERROR",message:"no signatures found in checkpoint"});return new t(s,c)}},aK=class t{constructor(e,r,s,a){this.origin=e,this.logSize=r,this.logHash=s,this.rest=a}static fromString(e){let r=e.trimEnd().split(`
`);if(r.length<3)throw new I1.VerificationError({code:"TLOG_INCLUSION_PROOF_ERROR",message:"too few lines in checkpoint header"});let s=r[0],a=BigInt(r[1]),n=Buffer.from(r[2],"base64"),c=r.slice(3);return new t(s,a,n,c)}}});var hxe=_(AK=>{"use strict";Object.defineProperty(AK,"__esModule",{value:!0});AK.verifyMerkleInclusion=LSt;var fK=Cl(),cK=Eo(),NSt=Buffer.from([0]),OSt=Buffer.from([1]);function LSt(t){let e=t.inclusionProof,r=BigInt(e.logIndex),s=BigInt(e.treeSize);if(r<0n||r>=s)throw new cK.VerificationError({code:"TLOG_INCLUSION_PROOF_ERROR",message:`invalid index: ${r}`});let{inner:a,border:n}=MSt(r,s);if(e.hashes.length!==a+n)throw new cK.VerificationError({code:"TLOG_INCLUSION_PROOF_ERROR",message:"invalid hash count"});let c=e.hashes.slice(0,a),f=e.hashes.slice(a),p=qSt(t.canonicalizedBody),h=_St(USt(p,c,r),f);if(!fK.crypto.bufferEqual(h,e.rootHash))throw new cK.VerificationError({code:"TLOG_INCLUSION_PROOF_ERROR",message:"calculated root hash does not match inclusion proof"})}function MSt(t,e){let r=HSt(t,e),s=jSt(t>>BigInt(r));return{inner:r,border:s}}function USt(t,e,r){return e.reduce((s,a,n)=>r>>BigInt(n)&BigInt(1)?uK(a,s):uK(s,a),t)}function _St(t,e){return e.reduce((r,s)=>uK(s,r),t)}function HSt(t,e){return GSt(t^e-BigInt(1))}function jSt(t){return t.toString(2).split("1").length-1}function GSt(t){return t===0n?0:t.toString(2).length}function uK(t,e){return fK.crypto.digest("sha256",OSt,t,e)}function qSt(t){return fK.crypto.digest("sha256",NSt,t)}});var dxe=_(pK=>{"use strict";Object.defineProperty(pK,"__esModule",{value:!0});pK.verifyTLogSET=VSt;var gxe=Cl(),WSt=Eo(),YSt=py();function VSt(t,e){if(!(0,YSt.filterTLogAuthorities)(e,{logID:t.logId.keyId,targetDate:new Date(Number(t.integratedTime)*1e3)}).some(a=>{let n=JSt(t),c=Buffer.from(gxe.json.canonicalize(n),"utf8"),f=t.inclusionPromise.signedEntryTimestamp;return gxe.crypto.verify(c,a.publicKey,f)}))throw new WSt.VerificationError({code:"TLOG_INCLUSION_PROMISE_ERROR",message:"inclusion promise could not be verified"})}function JSt(t){let{integratedTime:e,logIndex:r,logId:s,canonicalizedBody:a}=t;return{body:a.toString("base64"),integratedTime:Number(e),logIndex:Number(r),logID:s.keyId.toString("hex")}}});var mxe=_(dK=>{"use strict";Object.defineProperty(dK,"__esModule",{value:!0});dK.verifyRFC3161Timestamp=ZSt;var hK=Cl(),gK=Eo(),KSt=rK(),zSt=py();function ZSt(t,e,r){let s=t.signingTime;if(r=(0,zSt.filterCertAuthorities)(r,{start:s,end:s}),r=$St(r,{serialNumber:t.signerSerialNumber,issuer:t.signerIssuer}),!r.some(n=>{try{return XSt(t,e,n),!0}catch{return!1}}))throw new gK.VerificationError({code:"TIMESTAMP_ERROR",message:"timestamp could not be verified"})}function XSt(t,e,r){let[s,...a]=r.certChain,n=hK.crypto.createPublicKey(s.publicKey),c=t.signingTime;try{new KSt.CertificateChainVerifier({untrustedCert:s,trustedCerts:a}).verify()}catch{throw new gK.VerificationError({code:"TIMESTAMP_ERROR",message:"invalid certificate chain"})}if(!r.certChain.every(p=>p.validForDate(c)))throw new gK.VerificationError({code:"TIMESTAMP_ERROR",message:"timestamp was signed with an expired certificate"});t.verify(e,n)}function $St(t,e){return t.filter(r=>r.certChain.length>0&&hK.crypto.bufferEqual(r.certChain[0].serialNumber,e.serialNumber)&&hK.crypto.bufferEqual(r.certChain[0].issuer,e.issuer))}});var yxe=_(BL=>{"use strict";Object.defineProperty(BL,"__esModule",{value:!0});BL.verifyTSATimestamp=sDt;BL.verifyTLogTimestamp=oDt;var eDt=Eo(),tDt=pxe(),rDt=hxe(),nDt=dxe(),iDt=mxe();function sDt(t,e,r){return(0,iDt.verifyRFC3161Timestamp)(t,e,r),{type:"timestamp-authority",logID:t.signerSerialNumber,timestamp:t.signingTime}}function oDt(t,e){let r=!1;if(aDt(t)&&((0,nDt.verifyTLogSET)(t,e),r=!0),lDt(t)&&((0,rDt.verifyMerkleInclusion)(t),(0,tDt.verifyCheckpoint)(t,e),r=!0),!r)throw new eDt.VerificationError({code:"TLOG_MISSING_INCLUSION_ERROR",message:"inclusion could not be verified"});return{type:"transparency-log",logID:t.logId.keyId,timestamp:new Date(Number(t.integratedTime)*1e3)}}function aDt(t){return t.inclusionPromise!==void 0}function lDt(t){return t.inclusionProof!==void 0}});var Exe=_(mK=>{"use strict";Object.defineProperty(mK,"__esModule",{value:!0});mK.verifyDSSETLogBody=cDt;var vL=Eo();function cDt(t,e){switch(t.apiVersion){case"0.0.1":return uDt(t,e);default:throw new vL.VerificationError({code:"TLOG_BODY_ERROR",message:`unsupported dsse version: ${t.apiVersion}`})}}function uDt(t,e){if(t.spec.signatures?.length!==1)throw new vL.VerificationError({code:"TLOG_BODY_ERROR",message:"signature count mismatch"});let r=t.spec.signatures[0].signature;if(!e.compareSignature(Buffer.from(r,"base64")))throw new vL.VerificationError({code:"TLOG_BODY_ERROR",message:"tlog entry signature mismatch"});let s=t.spec.payloadHash?.value||"";if(!e.compareDigest(Buffer.from(s,"hex")))throw new vL.VerificationError({code:"TLOG_BODY_ERROR",message:"DSSE payload hash mismatch"})}});var Ixe=_(EK=>{"use strict";Object.defineProperty(EK,"__esModule",{value:!0});EK.verify Line truncated
Try running the command again with the package name prefixed: ${he.pretty(r,"yarn add",he.Type.CODE)} ${he.pretty(r,G.makeDescriptor(G.makeIdent(null,"my-package"),`${ie[0]}...`),he.Type.DESCRIPTOR)}`);if(!ee)throw new nt(`The ${he.pretty(r,W,he.Type.CODE)} string didn't match the required format (package-name@range). Did you perhaps forget to explicitly reference the package name?`);let ue=Llt(a,ee,{dev:this.dev,peer:this.peer,preferDev:this.preferDev,optional:this.optional});return await Promise.all(ue.map(async me=>{let pe=await zv(ee,{project:s,workspace:a,cache:n,fixed:c,target:me,modifier:h,strategies:E,maxResults:C});return{request:ee,suggestedDescriptors:pe,target:me}}))})).then(W=>W.flat()),I=await lA.start({configuration:r,stdout:this.context.stdout,suggestInstall:!1},async W=>{for(let{request:ee,suggestedDescriptors:{suggestions:ie,rejections:ue}}of b)if(ie.filter(me=>me.descriptor!==null).length===0){let[me]=ue;if(typeof me>"u")throw new Error("Assertion failed: Expected an error to have been set");s.configuration.get("enableNetwork")?W.reportError(27,`${G.prettyDescriptor(r,ee)} can't be resolved to a satisfying range`):W.reportError(27,`${G.prettyDescriptor(r,ee)} can't be resolved to a satisfying range (note: network resolution has been disabled)`),W.reportSeparator(),W.reportExceptionOnce(me)}});if(I.hasErrors())return I.exitCode();let T=!1,N=[],U=[];for(let{suggestedDescriptors:{suggestions:W},target:ee}of b){let ie,ue=W.filter(Be=>Be.descriptor!==null),le=ue[0].descriptor,me=ue.every(Be=>G.areDescriptorsEqual(Be.descriptor,le));ue.length===1||me?ie=le:(T=!0,{answer:ie}=await(0,uye.prompt)({type:"select",name:"answer",message:"Which range do you want to use?",choices:W.map(({descriptor:Be,name:Ce,reason:g})=>Be?{name:Ce,hint:g,descriptor:Be}:{name:Ce,hint:g,disabled:!0}),onCancel:()=>process.exit(130),result(Be){return this.find(Be,"descriptor")},stdin:this.context.stdin,stdout:this.context.stdout}));let pe=a.manifest[ee].get(ie.identHash);(typeof pe>"u"||pe.descriptorHash!==ie.descriptorHash)&&(a.manifest[ee].set(ie.identHash,ie),this.optional&&(ee==="dependencies"?a.manifest.ensureDependencyMeta({...ie,range:"unknown"}).optional=!0:ee==="peerDependencies"&&(a.manifest.ensurePeerDependencyMeta({...ie,range:"unknown"}).optional=!0)),typeof pe>"u"?N.push([a,ee,ie,E]):U.push([a,ee,pe,ie]))}return await r.triggerMultipleHooks(W=>W.afterWorkspaceDependencyAddition,N),await r.triggerMultipleHooks(W=>W.afterWorkspaceDependencyReplacement,U),T&&this.context.stdout.write(`
`),await s.installWithNewReport({json:this.json,stdout:this.context.stdout,quiet:this.context.quiet},{cache:n,mode:this.mode})}};function Llt(t,e,{dev:r,peer:s,preferDev:a,optional:n}){let c=t.manifest.dependencies.has(e.identHash),f=t.manifest.devDependencies.has(e.identHash),p=t.manifest.peerDependencies.has(e.identHash);if((r||s)&&c)throw new nt(`Package "${G.prettyIdent(t.project.configuration,e)}" is already listed as a regular dependency - remove the -D,-P flags or remove it from your dependencies first`);if(!r&&!s&&p)throw new nt(`Package "${G.prettyIdent(t.project.configuration,e)}" is already listed as a peer dependency - use either of -D or -P, or remove it from your peer dependencies first`);if(n&&f)throw new nt(`Package "${G.prettyIdent(t.project.configuration,e)}" is already listed as a dev dependency - remove the -O flag or remove it from your dev dependencies first`);if(n&&!s&&p)throw new nt(`Package "${G.prettyIdent(t.project.configuration,e)}" is already listed as a peer dependency - remove the -O flag or add the -P flag or remove it from your peer dependencies first`);if((r||a)&&n)throw new nt(`Package "${G.prettyIdent(t.project.configuration,e)}" cannot simultaneously be a dev dependency and an optional dependency`);let h=[];return s&&h.push("peerDependencies"),(r||a)&&h.push("devDependencies"),n&&h.push("dependencies"),h.length>0?h:f?["devDependencies"]:p?["peerDependencies"]:["dependencies"]}Ge();Ge();Yt();var oC=class extends ft{constructor(){super(...arguments);this.verbose=ge.Boolean("-v,--verbose",!1,{description:"Print both the binary name and the locator of the package that provides the binary"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.name=ge.String({required:!1})}static{this.paths=[["bin"]]}static{this.usage=ot.Usage({description:"get the path to a binary script",details:`
When used without arguments, this command will print the list of all the binaries available in the current workspace. Adding the \`-v,--verbose\` flag will cause the output to contain both the binary name and the locator of the package that provides the binary.
When an argument is specified, this command will just print the path to the binary on the standard output and exit. Note that the reported path may be stored within a zip archive.
`,examples:[["List all the available binaries","$0 bin"],["Print the path to a specific binary","$0 bin eslint"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,locator:a}=await Rt.find(r,this.context.cwd);if(await s.restoreInstallState(),this.name){let f=(await In.getPackageAccessibleBinaries(a,{project:s})).get(this.name);if(!f)throw new nt(`Couldn't find a binary named "${this.name}" for package "${G.prettyLocator(r,a)}"`);let[,p]=f;return this.context.stdout.write(`${p}
`),0}return(await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async c=>{let f=await In.getPackageAccessibleBinaries(a,{project:s}),h=Array.from(f.keys()).reduce((E,C)=>Math.max(E,C.length),0);for(let[E,[C,S]]of f)c.reportJson({name:E,source:G.stringifyIdent(C),path:S});if(this.verbose)for(let[E,[C]]of f)c.reportInfo(null,`${E.padEnd(h," ")} ${G.prettyLocator(r,C)}`);else for(let E of f.keys())c.reportInfo(null,E)})).exitCode()}};Ge();Dt();Yt();var aC=class extends ft{constructor(){super(...arguments);this.mirror=ge.Boolean("--mirror",!1,{description:"Remove the global cache files instead of the local cache files"});this.all=ge.Boolean("--all",!1,{description:"Remove both the global cache files and the local cache files of the current project"})}static{this.paths=[["cache","clean"],["cache","clear"]]}static{this.usage=ot.Usage({description:"remove the shared cache files",details:`
This command will remove all the files from the cache.
`,examples:[["Remove all the local archives","$0 cache clean"],["Remove all the archives stored in the ~/.yarn directory","$0 cache clean --mirror"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins);if(!r.get("enableCacheClean"))throw new nt("Cache cleaning is currently disabled. To enable it, set `enableCacheClean: true` in your configuration file. Note: Cache cleaning is typically not required and should be avoided when using Zero-Installs.");let s=await Kr.find(r);return(await Ot.start({configuration:r,stdout:this.context.stdout},async()=>{let n=(this.all||this.mirror)&&s.mirrorCwd!==null,c=!this.mirror;n&&(await ce.removePromise(s.mirrorCwd),await r.triggerHook(f=>f.cleanGlobalArtifacts,r)),c&&await ce.removePromise(s.cwd)})).exitCode()}};Ge();Yt();ql();var Wq=Ie("util"),lC=class extends ft{constructor(){super(...arguments);this.why=ge.Boolean("--why",!1,{description:"Print the explanation for why a setting has its value"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.unsafe=ge.Boolean("--no-redacted",!1,{description:"Don't redact secrets (such as tokens) from the output"});this.name=ge.String()}static{this.paths=[["config","get"]]}static{this.usage=ot.Usage({description:"read a configuration settings",details:`
This command will print a configuration setting.
Secrets (such as tokens) will be redacted from the output by default. If this behavior isn't desired, set the \`--no-redacted\` to get the untransformed value.
`,examples:[["Print a simple configuration setting","yarn config get yarnPath"],["Print a complex configuration setting","yarn config get packageExtensions"],["Print a nested field from the configuration",`yarn config get 'npmScopes["my-company"].npmRegistryServer'`],["Print a token from the configuration","yarn config get npmAuthToken --no-redacted"],["Print a configuration setting as JSON","yarn config get packageExtensions --json"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=this.name.replace(/[.[].*$/,""),a=this.name.replace(/^[^.[]*/,"");if(typeof r.settings.get(s)>"u")throw new nt(`Couldn't find a configuration settings named "${s}"`);let c=r.getSpecial(s,{hideSecrets:!this.unsafe,getNativePaths:!0}),f=je.convertMapsToIndexableObjects(c),p=a?va(f,a):f,h=await Ot.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async E=>{E.reportJson(p)});if(!this.json){if(typeof p=="string")return this.context.stdout.write(`${p}
`),h.exitCode();Wq.inspect.styles.name="cyan",this.context.stdout.write(`${(0,Wq.inspect)(p,{depth:1/0,colors:r.get("enableColors"),compact:!1})}
`)}return h.exitCode()}};Ge();Yt();ql();var Yq=Ie("util"),cC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Set complex configuration settings to JSON values"});this.home=ge.Boolean("-H,--home",!1,{description:"Update the home configuration instead of the project configuration"});this.name=ge.String();this.value=ge.String()}static{this.paths=[["config","set"]]}static{this.usage=ot.Usage({description:"change a configuration settings",details:`
This command will set a configuration setting.
When used without the \`--json\` flag, it can only set a simple configuration setting (a string, a number, or a boolean).
When used with the \`--json\` flag, it can set both simple and complex configuration settings, including Arrays and Objects.
`,examples:[["Set a simple configuration setting (a string, a number, or a boolean)","yarn config set initScope myScope"],["Set a simple configuration setting (a string, a number, or a boolean) using the `--json` flag",'yarn config set initScope --json \\"myScope\\"'],["Set a complex configuration setting (an Array) using the `--json` flag",`yarn config set unsafeHttpWhitelist --json '["*.example.com", "example.com"]'`],["Set a complex configuration setting (an Object) using the `--json` flag",`yarn config set packageExtensions --json '{ "@babel/parser@*": { "dependencies": { "@babel/types": "*" } } }'`],["Set a nested configuration setting",'yarn config set npmScopes.company.npmRegistryServer "https://npm.example.com"'],["Set a nested configuration setting using indexed access for non-simple keys",`yarn config set 'npmRegistries["//npm.example.com"].npmAuthToken' "ffffffff-ffff-ffff-ffff-ffffffffffff"`]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=()=>{if(!r.projectCwd)throw new nt("This command must be run from within a project folder");return r.projectCwd},a=this.name.replace(/[.[].*$/,""),n=this.name.replace(/^[^.[]*\.?/,"");if(typeof r.settings.get(a)>"u")throw new nt(`Couldn't find a configuration settings named "${a}"`);if(a==="enableStrictSettings")throw new nt("This setting only affects the file it's in, and thus cannot be set from the CLI");let f=this.json?JSON.parse(this.value):this.value;await(this.home?I=>ze.updateHomeConfiguration(I):I=>ze.updateConfiguration(s(),I))(I=>{if(n){let T=f0(I);return Jd(T,this.name,f),T}else return{...I,[a]:f}});let E=(await ze.find(this.context.cwd,this.context.plugins)).getSpecial(a,{hideSecrets:!0,getNativePaths:!0}),C=je.convertMapsToIndexableObjects(E),S=n?va(C,n):C;return(await Ot.start({configuration:r,includeFooter:!1,stdout:this.context.stdout},async I=>{Yq.inspect.styles.name="cyan",I.reportInfo(0,`Successfully set ${this.name} to ${(0,Yq.inspect)(S,{depth:1/0,colors:r.get("enableColors"),compact:!1})}`)})).exitCode()}};Ge();Yt();ql();var uC=class extends ft{constructor(){super(...arguments);this.home=ge.Boolean("-H,--home",!1,{description:"Update the home configuration instead of the project configuration"});this.name=ge.String()}static{this.paths=[["config","unset"]]}static{this.usage=ot.Usage({description:"unset a configuration setting",details:`
This command will unset a configuration setting.
`,examples:[["Unset a simple configuration setting","yarn config unset initScope"],["Unset a complex configuration setting","yarn config unset packageExtensions"],["Unset a nested configuration setting","yarn config unset npmScopes.company.npmRegistryServer"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=()=>{if(!r.projectCwd)throw new nt("This command must be run from within a project folder");return r.projectCwd},a=this.name.replace(/[.[].*$/,""),n=this.name.replace(/^[^.[]*\.?/,"");if(typeof r.settings.get(a)>"u")throw new nt(`Couldn't find a configuration settings named "${a}"`);let f=this.home?h=>ze.updateHomeConfiguration(h):h=>ze.updateConfiguration(s(),h);return(await Ot.start({configuration:r,includeFooter:!1,stdout:this.context.stdout},async h=>{let E=!1;await f(C=>{if(!vB(C,this.name))return h.reportWarning(0,`Configuration doesn't contain setting ${this.name}; there is nothing to unset`),E=!0,C;let S=n?f0(C):{...C};return A0(S,this.name),S}),E||h.reportInfo(0,`Successfully unset ${this.name}`)})).exitCode()}};Ge();Dt();Yt();var eF=Ie("util"),fC=class extends ft{constructor(){super(...arguments);this.noDefaults=ge.Boolean("--no-defaults",!1,{description:"Omit the default values from the display"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.verbose=ge.Boolean("-v,--verbose",{hidden:!0});this.why=ge.Boolean("--why",{hidden:!0});this.names=ge.Rest()}static{this.paths=[["config"]]}static{this.usage=ot.Usage({description:"display the current configuration",details:`
This command prints the current active configuration settings.
`,examples:[["Print the active configuration settings","$0 config"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins,{strict:!1}),s=await SI({configuration:r,stdout:this.context.stdout,forceError:this.json},[{option:this.verbose,message:"The --verbose option is deprecated, the settings' descriptions are now always displayed"},{option:this.why,message:"The --why option is deprecated, the settings' sources are now always displayed"}]);if(s!==null)return s;let a=this.names.length>0?[...new Set(this.names)].sort():[...r.settings.keys()].sort(),n,c=await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async f=>{if(r.invalid.size>0&&!this.json){for(let[p,h]of r.invalid)f.reportError(34,`Invalid configuration key "${p}" in ${h}`);f.reportSeparator()}if(this.json)for(let p of a){if(this.noDefaults&&!r.sources.has(p))continue;let h=r.settings.get(p);typeof h>"u"&&f.reportError(34,`No configuration key named "${p}"`);let E=r.getSpecial(p,{hideSecrets:!0,getNativePaths:!0}),C=r.sources.get(p)??"<default>",S=C&&C[0]!=="<"?fe.fromPortablePath(C):C;f.reportJson({key:p,effective:E,source:S,...h})}else{let p={breakLength:1/0,colors:r.get("enableColors"),maxArrayLength:2},h={},E={children:h};for(let C of a){if(this.noDefaults&&!r.sources.has(C))continue;let S=r.settings.get(C),b=r.sources.get(C)??"<default>",I=r.getSpecial(C,{hideSecrets:!0,getNativePaths:!0}),T={Description:{label:"Description",value:he.tuple(he.Type.MARKDOWN,{text:S.description,format:this.cli.format(),paragraphs:!1})},Source:{label:"Source",value:he.tuple(b[0]==="<"?he.Type.CODE:he.Type.PATH,b)}};h[C]={value:he.tuple(he.Type.CODE,C),children:T};let N=(U,W)=>{for(let[ee,ie]of W)if(ie instanceof Map){let ue={};U[ee]={children:ue},N(ue,ie)}else U[ee]={label:ee,value:he.tuple(he.Type.NO_HINT,(0,eF.inspect)(ie,p))}};I instanceof Map?N(T,I):T.Value={label:"Value",value:he.tuple(he.Type.NO_HINT,(0,eF.inspect)(I,p))}}a.length!==1&&(n=void 0),xs.emitTree(E,{configuration:r,json:this.json,stdout:this.context.stdout,separators:2})}});if(!this.json&&typeof n<"u"){let f=a[0],p=(0,eF.inspect)(r.getSpecial(f,{hideSecrets:!0,getNativePaths:!0}),{colors:r.get("enableColors")});this.context.stdout.write(`
`),this.context.stdout.write(`${p}
`)}return c.exitCode()}};Ge();Yt();Ul();var tF={};Vt(tF,{Strategy:()=>Zv,acceptedStrategies:()=>Mlt,dedupe:()=>Vq});Ge();Ge();var fye=ut(Go()),Zv=(e=>(e.HIGHEST="highest",e))(Zv||{}),Mlt=new Set(Object.values(Zv)),Ult={highest:async(t,e,{resolver:r,fetcher:s,resolveOptions:a,fetchOptions:n})=>{let c=new Map;for(let[p,h]of t.storedResolutions){let E=t.storedDescriptors.get(p);if(typeof E>"u")throw new Error(`Assertion failed: The descriptor (${p}) should have been registered`);je.getSetWithDefault(c,E.identHash).add(h)}let f=new Map(je.mapAndFilter(t.storedDescriptors.values(),p=>G.isVirtualDescriptor(p)?je.mapAndFilter.skip:[p.descriptorHash,je.makeDeferred()]));for(let p of t.storedDescriptors.values()){let h=f.get(p.descriptorHash);if(typeof h>"u")throw new Error(`Assertion failed: The descriptor (${p.descriptorHash}) should have been registered`);let E=t.storedResolutions.get(p.descriptorHash);if(typeof E>"u")throw new Error(`Assertion failed: The resolution (${p.descriptorHash}) should have been registered`);let C=t.originalPackages.get(E);if(typeof C>"u")throw new Error(`Assertion failed: The package (${E}) should have been registered`);Promise.resolve().then(async()=>{let S=r.getResolutionDependencies(p,a),b=Object.fromEntries(await je.allSettledSafe(Object.entries(S).map(async([ee,ie])=>{let ue=f.get(ie.descriptorHash);if(typeof ue>"u")throw new Error(`Assertion failed: The descriptor (${ie.descriptorHash}) should have been registered`);let le=await ue.promise;if(!le)throw new Error("Assertion failed: Expected the dependency to have been through the dedupe process itself");return[ee,le.updatedPackage]})));if(e.length&&!fye.default.isMatch(G.stringifyIdent(p),e)||!r.shouldPersistResolution(C,a))return C;let I=c.get(p.identHash);if(typeof I>"u")throw new Error(`Assertion failed: The resolutions (${p.identHash}) should have been registered`);if(I.size===1)return C;let T=[...I].map(ee=>{let ie=t.originalPackages.get(ee);if(typeof ie>"u")throw new Error(`Assertion failed: The package (${ee}) should have been registered`);return ie}),N=await r.getSatisfying(p,b,T,a),U=N.locators?.[0];if(typeof U>"u"||!N.sorted)return C;let W=t.originalPackages.get(U.locatorHash);if(typeof W>"u")throw new Error(`Assertion failed: The package (${U.locatorHash}) should have been registered`);return W}).then(async S=>{let b=await t.preparePackage(S,{resolver:r,resolveOptions:a});h.resolve({descriptor:p,currentPackage:C,updatedPackage:S,resolvedPackage:b})}).catch(S=>{h.reject(S)})}return[...f.values()].map(p=>p.promise)}};async function Vq(t,{strategy:e,patterns:r,cache:s,report:a}){let{configuration:n}=t,c=new ki,f=n.makeResolver(),p=n.makeFetcher(),h={cache:s,checksums:t.storedChecksums,fetcher:p,project:t,report:c,cacheOptions:{skipIntegrityCheck:!0}},E={project:t,resolver:f,report:c,fetchOptions:h};return await a.startTimerPromise("Deduplication step",async()=>{let C=Ult[e],S=await C(t,r,{resolver:f,resolveOptions:E,fetcher:p,fetchOptions:h}),b=Ao.progressViaCounter(S.length);await a.reportProgress(b);let I=0;await Promise.all(S.map(U=>U.then(W=>{if(W===null||W.currentPackage.locatorHash===W.updatedPackage.locatorHash)return;I++;let{descriptor:ee,currentPackage:ie,updatedPackage:ue}=W;a.reportInfo(0,`${G.prettyDescriptor(n,ee)} can be deduped from ${G.prettyLocator(n,ie)} to ${G.prettyLocator(n,ue)}`),a.reportJson({descriptor:G.stringifyDescriptor(ee),currentResolution:G.stringifyLocator(ie),updatedResolution:G.stringifyLocator(ue)}),t.storedResolutions.set(ee.descriptorHash,ue.locatorHash)}).finally(()=>b.tick())));let T;switch(I){case 0:T="No packages";break;case 1:T="One package";break;default:T=`${I} packages`}let N=he.pretty(n,e,he.Type.CODE);return a.reportInfo(0,`${T} can be deduped using the ${N} strategy`),I})}var AC=class extends ft{constructor(){super(...arguments);this.strategy=ge.String("-s,--strategy","highest",{description:"The strategy to use when deduping dependencies",validator:fo(Zv)});this.check=ge.Boolean("-c,--check",!1,{description:"Exit with exit code 1 when duplicates are found, without persisting the dependency tree"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.mode=ge.String("--mode",{description:"Change what artifacts installs generate",validator:fo($l)});this.patterns=ge.Rest()}static{this.paths=[["dedupe"]]}static{this.usage=ot.Usage({description:"deduplicate dependencies with overlapping ranges",details:"\n Duplicates are defined as descriptors with overlapping ranges being resolved and locked to different locators. They are a natural consequence of Yarn's deterministic installs, but they can sometimes pile up and unnecessarily increase the size of your project.\n\n This command dedupes dependencies in the current project using different strategies (only one is implemented at the moment):\n\n - `highest`: Reuses (where possible) the locators with the highest versions. This means that dependencies can only be upgraded, never dow Line truncated
`)}};var hC=class extends ft{static{this.paths=[["help"],["--help"],["-h"]]}async execute(){this.context.stdout.write(this.cli.usage(null))}};Ge();Dt();Yt();var gC=class extends ft{constructor(){super(...arguments);this.leadingArgument=ge.String();this.args=ge.Proxy()}async execute(){if(this.leadingArgument.match(/[\\/]/)&&!G.tryParseIdent(this.leadingArgument)){let r=J.resolve(this.context.cwd,fe.toPortablePath(this.leadingArgument));return await this.cli.run(this.args,{cwd:r})}else return await this.cli.run(["run",this.leadingArgument,...this.args])}};Ge();var dC=class extends ft{static{this.paths=[["-v"],["--version"]]}async execute(){this.context.stdout.write(`${fn||"<unknown>"}
`)}};Ge();Ge();Yt();var mC=class extends ft{constructor(){super(...arguments);this.commandName=ge.String();this.args=ge.Proxy()}static{this.paths=[["exec"]]}static{this.usage=ot.Usage({description:"execute a shell script",details:`
This command simply executes a shell script within the context of the root directory of the active workspace using the portable shell.
It also makes sure to call it in a way that's compatible with the current project (for example, on PnP projects the environment will be setup in such a way that PnP will be correctly injected into the environment).
`,examples:[["Execute a single shell command","$0 exec echo Hello World"],["Execute a shell script",'$0 exec "tsc & babel src --out-dir lib"']]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,locator:a}=await Rt.find(r,this.context.cwd);return await s.restoreInstallState(),await In.executePackageShellcode(a,this.commandName,this.args,{cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,project:s})}};Ge();Yt();Ul();var yC=class extends ft{constructor(){super(...arguments);this.hash=ge.String({required:!1,validator:Nx(wE(),[X2(/^p[0-9a-f]{6}$/)])})}static{this.paths=[["explain","peer-requirements"]]}static{this.usage=ot.Usage({description:"explain a set of peer requirements",details:`
A peer requirement represents all peer requests that a subject must satisfy when providing a requested package to requesters.
When the hash argument is specified, this command prints a detailed explanation of the peer requirement corresponding to the hash and whether it is satisfied or not.
When used without arguments, this command lists all peer requirements and the corresponding hash that can be used to get detailed information about a given requirement.
**Note:** A hash is a seven-letter code consisting of the letter 'p' followed by six characters that can be obtained from peer dependency warnings or from the list of all peer requirements(\`yarn explain peer-requirements\`).
`,examples:[["Explain the corresponding peer requirement for a hash","$0 explain peer-requirements p1a4ed"],["List all peer requirements","$0 explain peer-requirements"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Rt.find(r,this.context.cwd);return await s.restoreInstallState({restoreResolutions:!1}),await s.applyLightResolution(),typeof this.hash<"u"?await Hlt(this.hash,s,{stdout:this.context.stdout}):await jlt(s,{stdout:this.context.stdout})}};async function Hlt(t,e,r){let s=e.peerRequirementNodes.get(t);if(typeof s>"u")throw new Error(`No peerDependency requirements found for hash: "${t}"`);let a=new Set,n=p=>a.has(p.requester.locatorHash)?{value:he.tuple(he.Type.DEPENDENT,{locator:p.requester,descriptor:p.descriptor}),children:p.children.size>0?[{value:he.tuple(he.Type.NO_HINT,"...")}]:[]}:(a.add(p.requester.locatorHash),{value:he.tuple(he.Type.DEPENDENT,{locator:p.requester,descriptor:p.descriptor}),children:Object.fromEntries(Array.from(p.children.values(),h=>[G.stringifyLocator(h.requester),n(h)]))}),c=e.peerWarnings.find(p=>p.hash===t);return(await Ot.start({configuration:e.configuration,stdout:r.stdout,includeFooter:!1,includePrefix:!1},async p=>{let h=he.mark(e.configuration),E=c?h.Cross:h.Check;if(p.reportInfo(0,`Package ${he.pretty(e.configuration,s.subject,he.Type.LOCATOR)} is requested to provide ${he.pretty(e.configuration,s.ident,he.Type.IDENT)} by its descendants`),p.reportSeparator(),p.reportInfo(0,he.pretty(e.configuration,s.subject,he.Type.LOCATOR)),xs.emitTree({children:Object.fromEntries(Array.from(s.requests.values(),C=>[G.stringifyLocator(C.requester),n(C)]))},{configuration:e.configuration,stdout:r.stdout,json:!1}),p.reportSeparator(),s.provided.range==="missing:"){let C=c?"":" , but all peer requests are optional";p.reportInfo(0,`${E} Package ${he.pretty(e.configuration,s.subject,he.Type.LOCATOR)} does not provide ${he.pretty(e.configuration,s.ident,he.Type.IDENT)}${C}.`)}else{let C=e.storedResolutions.get(s.provided.descriptorHash);if(!C)throw new Error("Assertion failed: Expected the descriptor to be registered");let S=e.storedPackages.get(C);if(!S)throw new Error("Assertion failed: Expected the package to be registered");p.reportInfo(0,`${E} Package ${he.pretty(e.configuration,s.subject,he.Type.LOCATOR)} provides ${he.pretty(e.configuration,s.ident,he.Type.IDENT)} with version ${G.prettyReference(e.configuration,S.version??"0.0.0")}, ${c?"which does not satisfy all requests.":"which satisfies all requests"}`),c?.type===3&&(c.range?p.reportInfo(0,` The combined requested range is ${he.pretty(e.configuration,c.range,he.Type.RANGE)}`):p.reportInfo(0," Unfortunately, the requested ranges have no overlap"))}})).exitCode()}async function jlt(t,e){return(await Ot.start({configuration:t.configuration,stdout:e.stdout,includeFooter:!1,includePrefix:!1},async s=>{let a=he.mark(t.configuration),n=je.sortMap(t.peerRequirementNodes,[([,c])=>G.stringifyLocator(c.subject),([,c])=>G.stringifyIdent(c.ident)]);for(let[,c]of n.values()){if(!c.root)continue;let f=t.peerWarnings.find(E=>E.hash===c.hash),p=[...G.allPeerRequests(c)],h;if(p.length>2?h=` and ${p.length-1} other dependencies`:p.length===2?h=" and 1 other dependency":h="",c.provided.range!=="missing:"){let E=t.storedResolutions.get(c.provided.descriptorHash);if(!E)throw new Error("Assertion failed: Expected the resolution to have been registered");let C=t.storedPackages.get(E);if(!C)throw new Error("Assertion failed: Expected the provided package to have been registered");let S=`${he.pretty(t.configuration,c.hash,he.Type.CODE)} \u2192 ${f?a.Cross:a.Check} ${G.prettyLocator(t.configuration,c.subject)} provides ${G.prettyLocator(t.configuration,C)} to ${G.prettyLocator(t.configuration,p[0].requester)}${h}`;f?s.reportWarning(0,S):s.reportInfo(0,S)}else{let E=`${he.pretty(t.configuration,c.hash,he.Type.CODE)} \u2192 ${f?a.Cross:a.Check} ${G.prettyLocator(t.configuration,c.subject)} doesn't provide ${G.prettyIdent(t.configuration,c.ident)} to ${G.prettyLocator(t.configuration,p[0].requester)}${h}`;f?s.reportWarning(0,E):s.reportInfo(0,E)}}})).exitCode()}Ge();Yt();Ul();Ge();Ge();Dt();Yt();var pye=ut(Ai()),EC=class extends ft{constructor(){super(...arguments);this.useYarnPath=ge.Boolean("--yarn-path",{description:"Set the yarnPath setting even if the version can be accessed by Corepack"});this.onlyIfNeeded=ge.Boolean("--only-if-needed",!1,{description:"Only lock the Yarn version if it isn't already locked"});this.version=ge.String()}static{this.paths=[["set","version"]]}static{this.usage=ot.Usage({description:"lock the Yarn version used by the project",details:"\n This command will set a specific release of Yarn to be used by Corepack: https://nodejs.org/api/corepack.html.\n\n By default it only will set the `packageManager` field at the root of your project, but if the referenced release cannot be represented this way, if you already have `yarnPath` configured, or if you set th Line truncated
${e}`)})}let f=t.projectCwd??t.startingCwd,p=J.resolve(f,".yarn/releases"),h=J.resolve(p,`yarn-${e}.cjs`),E=J.relative(t.startingCwd,h),C=je.isTaggedYarnVersion(e),S=t.get("yarnPath"),b=!C,I=b||!!S||!!a;if(a===!1){if(b)throw new jt(0,"You explicitly opted out of yarnPath usage in your command line, but the version you specified cannot be represented by Corepack");I=!1}else!I&&!process.env.COREPACK_ROOT&&(s.reportWarning(0,`You don't seem to have ${he.applyHyperlink(t,"Corepack","https://nodejs.org/api/corepack.html")} enabled; we'll have to rely on ${he.applyHyperlink(t,"yarnPath","https://yarnpkg.com/configuration/yarnrc#yarnPath")} instead`),I=!0);if(I){let ee=await c();s.reportInfo(0,`Saving the new release in ${he.pretty(t,E,"magenta")}`),await ce.removePromise(J.dirname(h)),await ce.mkdirPromise(J.dirname(h),{recursive:!0}),await ce.writeFilePromise(h,ee,{mode:493}),await ze.updateConfiguration(f,{yarnPath:J.relative(f,h)})}else await ce.removePromise(J.dirname(h)),await ze.updateConfiguration(f,{yarnPath:ze.deleteProperty});let T=await Ut.tryFind(f)||new Ut;T.packageManager=`yarn@${C?e:await Xv(t,"stable")}`;let N={};T.exportTo(N);let U=J.join(f,Ut.fileName),W=`${JSON.stringify(N,null,T.indent)}
`;return await ce.changeFilePromise(U,W,{automaticNewlines:!0}),{bundleVersion:e}}function hye(t){return Br[jx(t)]}var qlt=/## (?<code>YN[0-9]{4}) - `(?<name>[A-Z_]+)`\n\n(?<details>(?:.(?!##))+)/gs;async function Wlt(t){let r=`https://repo.yarnpkg.com/${je.isTaggedYarnVersion(fn)?fn:await Xv(t,"canary")}/packages/docusaurus/docs/advanced/01-general-reference/error-codes.mdx`,s=await ln.get(r,{configuration:t});return new Map(Array.from(s.toString().matchAll(qlt),({groups:a})=>{if(!a)throw new Error("Assertion failed: Expected the match to have been successful");let n=hye(a.code);if(a.name!==n)throw new Error(`Assertion failed: Invalid error code data: Expected "${a.name}" to be named "${n}"`);return[a.code,a.details]}))}var IC=class extends ft{constructor(){super(...arguments);this.code=ge.String({required:!1,validator:$2(wE(),[X2(/^YN[0-9]{4}$/)])});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}static{this.paths=[["explain"]]}static{this.usage=ot.Usage({description:"explain an error code",details:`
When the code argument is specified, this command prints its name and its details.
When used without arguments, this command lists all error codes and their names.
`,examples:[["Explain an error code","$0 explain YN0006"],["List all error codes","$0 explain"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins);if(typeof this.code<"u"){let s=hye(this.code),a=he.pretty(r,s,he.Type.CODE),n=this.cli.format().header(`${this.code} - ${a}`),f=(await Wlt(r)).get(this.code),p=typeof f<"u"?he.jsonOrPretty(this.json,r,he.tuple(he.Type.MARKDOWN,{text:f,format:this.cli.format(),paragraphs:!0})):`This error code does not have a description.
You can help us by editing this page on GitHub \u{1F642}:
${he.jsonOrPretty(this.json,r,he.tuple(he.Type.URL,"https://github.com/yarnpkg/berry/blob/master/packages/docusaurus/docs/advanced/01-general-reference/error-codes.mdx"))}
`;this.json?this.context.stdout.write(`${JSON.stringify({code:this.code,name:s,details:p})}
`):this.context.stdout.write(`${n}
${p}
`)}else{let s={children:je.mapAndFilter(Object.entries(Br),([a,n])=>Number.isNaN(Number(a))?je.mapAndFilter.skip:{label:Yf(Number(a)),value:he.tuple(he.Type.CODE,n)})};xs.emitTree(s,{configuration:r,stdout:this.context.stdout,json:this.json})}}};Ge();Dt();Yt();var gye=ut(Go()),CC=class extends ft{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Print versions of a package from the whole project"});this.recursive=ge.Boolean("-R,--recursive",!1,{description:"Print information for all packages, including transitive dependencies"});this.extra=ge.Array("-X,--extra",[],{description:"An array of requests of extra data provided by plugins"});this.cache=ge.Boolean("--cache",!1,{description:"Print information about the cache entry of a package (path, size, checksum)"});this.dependents=ge.Boolean("--dependents",!1,{description:"Print all dependents for each matching package"});this.manifest=ge.Boolean("--manifest",!1,{description:"Print data obtained by looking at the package archive (license, homepage, ...)"});this.nameOnly=ge.Boolean("--name-only",!1,{description:"Only print the name for the matching packages"});this.virtuals=ge.Boolean("--virtuals",!1,{description:"Print each instance of the virtual packages"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.patterns=ge.Rest()}static{this.paths=[["info"]]}static{this.usage=ot.Usage({description:"see information related to packages",details:"\n This command prints various information related to the specified packages, accepting glob patterns.\n\n By default, if the locator reference is missing, Yarn will default to print the information about all the matching direct dependencies of the package for the active workspace. To instead print all versions of the package that are direct dependencies of any of your workspaces, use the `-A,--all` flag. Adding the `-R,--recursive` flag will also report transitive dependencies.\n\n Some fields will be hidden by default in order to keep the output readable, but can be selectively displayed by using additional options (`--dependents`, `--manifest`, `--virtuals`, ...) described in the option descriptions.\n\n Note that this command will only print the information directly related to the selected packages - if you wish to know why the package is there in the first place, use `yarn why` which will do just that (it also provides a `-R,--recursive` flag that may be of some help).\n ",examples:[["Show information about Lodash","$0 info lodash"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n=await Kr.find(r);if(!a&&!this.all)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState();let c=new Set(this.extra);this.cache&&c.add("cache"),this.dependents&&c.add("dependents"),this.manifest&&c.add("manifest");let f=(ie,{recursive:ue})=>{let le=ie.anchoredLocator.locatorHash,me=new Map,pe=[le];for(;pe.length>0;){let Be=pe.shift();if(me.has(Be))continue;let Ce=s.storedPackages.get(Be);if(typeof Ce>"u")throw new Error("Assertion failed: Expected the package to be registered");if(me.set(Be,Ce),G.isVirtualLocator(Ce)&&pe.push(G.devirtualizeLocator(Ce).locatorHash),!(!ue&&Be!==le))for(let g of Ce.dependencies.values()){let we=s.storedResolutions.get(g.descriptorHash);if(typeof we>"u")throw new Error("Assertion failed: Expected the resolution to be registered");pe.push(we)}}return me.values()},p=({recursive:ie})=>{let ue=new Map;for(let le of s.workspaces)for(let me of f(le,{recursive:ie}))ue.set(me.locatorHash,me);return ue.values()},h=({all:ie,recursive:ue})=>ie&&ue?s.storedPackages.values():ie?p({recursive:ue}):f(a,{recursive:ue}),E=({all:ie,recursive:ue})=>{let le=h({all:ie,recursive:ue}),me=this.patterns.map(Ce=>{let g=G.parseLocator(Ce),we=gye.default.makeRe(G.stringifyIdent(g)),ye=G.isVirtualLocator(g),Ae=ye?G.devirtualizeLocator(g):g;return se=>{let X=G.stringifyIdent(se);if(!we.test(X))return!1;if(g.reference==="unknown")return!0;let De=G.isVirtualLocator(se),Te=De?G.devirtualizeLocator(se):se;return!(ye&&De&&g.reference!==se.reference||Ae.reference!==Te.reference)}}),pe=je.sortMap([...le],Ce=>G.stringifyLocator(Ce));return{selection:pe.filter(Ce=>me.length===0||me.some(g=>g(Ce))),sortedLookup:pe}},{selection:C,sortedLookup:S}=E({all:this.all,recursive:this.recursive});if(C.length===0)throw new nt("No package matched your request");let b=new Map;if(this.dependents)for(let ie of S)for(let ue of ie.dependencies.values()){let le=s.storedResolutions.get(ue.descriptorHash);if(typeof le>"u")throw new Error("Assertion failed: Expected the resolution to be registered");je.getArrayWithDefault(b,le).push(ie)}let I=new Map;for(let ie of S){if(!G.isVirtualLocator(ie))continue;let ue=G.devirtualizeLocator(ie);je.getArrayWithDefault(I,ue.locatorHash).push(ie)}let T={},N={children:T},U=r.makeFetcher(),W={project:s,fetcher:U,cache:n,checksums:s.storedChecksum Line truncated
This command simply runs Node. It also makes sure to call it in a way that's compatible with the current project (for example, on PnP projects the environment will be setup in such a way that PnP will be correctly injected into the environment).
The Node process will use the exact same version of Node as the one used to run Yarn itself, which might be a good way to ensure that your commands always use a consistent Node version.
`,examples:[["Run a Node script","$0 node ./my-script.js"]]})}async execute(){return this.cli.run(["exec","node",...this.args])}};Ge();Yt();var SC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}static{this.paths=[["plugin","check"]]}static{this.usage=ot.Usage({category:"Plugin-related commands",description:"find all third-party plugins that differ from their own spec",details:`
Check only the plugins from https.
If this command detects any plugin differences in the CI environment, it will throw an error.
`,examples:[["find all third-party plugins that differ from their own spec","$0 plugin check"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=await ze.findRcFiles(this.context.cwd);return(await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async n=>{for(let c of s)if(c.data?.plugins)for(let f of c.data.plugins){if(!f.checksum||!f.spec.match(/^https?:/))continue;let p=await ln.get(f.spec,{configuration:r}),h=Nn.makeHash(p);if(f.checksum===h)continue;let E=he.pretty(r,f.path,he.Type.PATH),C=he.pretty(r,f.spec,he.Type.URL),S=`${E} is different from the file provided by ${C}`;n.reportJson({...f,newChecksum:h}),n.reportError(0,S)}})).exitCode()}};Ge();Ge();Dt();Yt();var Iye=Ie("os");Ge();Dt();Yt();var dye=Ie("os");Ge();wc();Yt();var zlt="https://raw.githubusercontent.com/yarnpkg/berry/master/plugins.yml";async function Sm(t,e){let r=await ln.get(zlt,{configuration:t}),s=as(r.toString());return Object.fromEntries(Object.entries(s).filter(([a,n])=>!e||Fr.satisfiesWithPrereleases(e,n.range??"<4.0.0-rc.1")))}var DC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}static{this.paths=[["plugin","list"]]}static{this.usage=ot.Usage({category:"Plugin-related commands",description:"list the available official plugins",details:"\n This command prints the plugins available directly from the Yarn repository. Only those plugins can be referenced by name in `yarn plugin import`.\n ",examples:[["List the official plugins","$0 plugin list"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins);return(await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async a=>{let n=await Sm(r,fn);for(let[c,{experimental:f,...p}]of Object.entries(n)){let h=c;f&&(h+=" [experimental]"),a.reportJson({name:c,experimental:f,...p}),a.reportInfo(null,h)}})).exitCode()}};var Zlt=/^[0-9]+$/,Xlt=process.platform==="win32";function mye(t){return Zlt.test(t)?`pull/${t}/head`:t}var $lt=({repository:t,branch:e},r)=>[["git","init",fe.fromPortablePath(r)],["git","remote","add","origin",t],["git","fetch","origin","--depth=1",mye(e)],["git","reset","--hard","FETCH_HEAD"]],ect=({branch:t})=>[["git","fetch","origin","--depth=1",mye(t),"--force"],["git","reset","--hard","FETCH_HEAD"],["git","clean","-dfx","-e","packages/yarnpkg-cli/bundles"]],tct=({plugins:t,noMinify:e},r,s)=>[["yarn","build:cli",...new Array().concat(...t.map(a=>["--plugin",J.resolve(s,a)])),...e?["--no-minify"]:[],"|"],[Xlt?"move":"mv","packages/yarnpkg-cli/bundles/yarn.js",fe.fromPortablePath(r),"|"]],PC=class extends ft{constructor(){super(...arguments);this.installPath=ge.String("--path",{description:"The path where the repository should be cloned to"});this.repository=ge.String("--repository","https://github.com/yarnpkg/berry.git",{description:"The repository that should be cloned"});this.branch=ge.String("--branch","master",{description:"The branch of the repository that should be cloned"});this.plugins=ge.Array("--plugin",[],{description:"An array of additional plugins that should be included in the bundle"});this.dryRun=ge.Boolean("-n,--dry-run",!1,{description:"If set, the bundle will be built but not added to the project"});this.noMinify=ge.Boolean("--no-minify",!1,{description:"Build a bundle for development (debugging) - non-minified and non-mangled"});this.force=ge.Boolean("-f,--force",!1,{description:"Always clone the repository instead of trying to fetch the latest commits"});this.skipPlugins=ge.Boolean("--skip-plugins",!1,{description:"Skip updating the contrib plugins"})}static{this.paths=[["set","version","from","sources"]]}static{this.usage=ot.Usage({description:"build Yarn from master",details:`
This command will clone the Yarn repository into a temporary folder, then build it. The resulting bundle will then be copied into the local project.
By default, it also updates all contrib plugins to the same commit the bundle is built from. This behavior can be disabled by using the \`--skip-plugins\` flag.
`,examples:[["Build Yarn from master","$0 set version from sources"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Rt.find(r,this.context.cwd),a=typeof this.installPath<"u"?J.resolve(this.context.cwd,fe.toPortablePath(this.installPath)):J.resolve(fe.toPortablePath((0,dye.tmpdir)()),"yarnpkg-sources",Nn.makeHash(this.repository).slice(0,6));return(await Ot.start({configuration:r,stdout:this.context.stdout},async c=>{await zq(this,{configuration:r,report:c,target:a}),c.reportSeparator(),c.reportInfo(0,"Building a fresh bundle"),c.reportSeparator();let f=await qr.execvp("git",["rev-parse","--short","HEAD"],{cwd:a,strict:!0}),p=J.join(a,`packages/yarnpkg-cli/bundles/yarn-${f.stdout.trim()}.js`);ce.existsSync(p)||(await $v(tct(this,p,a),{configuration:r,context:this.context,target:a}),c.reportSeparator());let h=await ce.readFilePromise(p);if(!this.dryRun){let{bundleVersion:E}=await Jq(r,null,async()=>h,{report:c});this.skipPlugins||await rct(this,E,{project:s,report:c,target:a})}})).exitCode()}};async function $v(t,{configuration:e,context:r,target:s}){for(let[a,...n]of t){let c=n[n.length-1]==="|";if(c&&n.pop(),c)await qr.pipevp(a,n,{cwd:s,stdin:r.stdin,stdout:r.stdout,stderr:r.stderr,strict:!0});else{r.stdout.write(`${he.pretty(e,` $ ${[a,...n].join(" ")}`,"grey")}
`);try{await qr.execvp(a,n,{cwd:s,strict:!0})}catch(f){throw r.stdout.write(f.stdout||f.stack),f}}}}async function zq(t,{configuration:e,report:r,target:s}){let a=!1;if(!t.force&&ce.existsSync(J.join(s,".git"))){r.reportInfo(0,"Fetching the latest commits"),r.reportSeparator();try{await $v(ect(t),{configuration:e,context:t.context,target:s}),a=!0}catch{r.reportSeparator(),r.reportWarning(0,"Repository update failed; we'll try to regenerate it")}}a||(r.reportInfo(0,"Cloning the remote repository"),r.reportSeparator(),await ce.removePromise(s),await ce.mkdirPromise(s,{recursive:!0}),await $v($lt(t,s),{configuration:e,context:t.context,target:s}))}async function rct(t,e,{project:r,report:s,target:a}){let n=await Sm(r.configuration,e),c=new Set(Object.keys(n));for(let f of r.configuration.plugins.keys())c.has(f)&&await Zq(f,t,{project:r,report:s,target:a})}Ge();Ge();Dt();Yt();var yye=ut(Ai()),Eye=Ie("vm");var bC=class extends ft{constructor(){super(...arguments);this.name=ge.String();this.checksum=ge.Boolean("--checksum",!0,{description:"Whether to care if this plugin is modified"})}static{this.paths=[["plugin","import"]]}static{this.usage=ot.Usage({category:"Plugin-related commands",description:"download a plugin",details:`
This command downloads the specified plugin from its remote location and updates the configuration to reference it in further CLI invocations.
Three types of plugin references are accepted:
- If the plugin is stored within the Yarn repository, it can be referenced by name.
- Third-party plugins can be referenced directly through their public urls.
- Local plugins can be referenced by their path on the disk.
If the \`--no-checksum\` option is set, Yarn will no longer care if the plugin is modified.
Plugins cannot be downloaded from the npm registry, and aren't allowed to have dependencies (they need to be bundled into a single file, possibly thanks to the \`@yarnpkg/builder\` package).
`,examples:[['Download and activate the "@yarnpkg/plugin-exec" plugin',"$0 plugin import @yarnpkg/plugin-exec"],['Download and activate the "@yarnpkg/plugin-exec" plugin (shorthand)',"$0 plugin import exec"],["Download and activate a community plugin","$0 plugin import https://example.org/path/to/plugin.js"],["Activate a local plugin","$0 plugin import ./path/to/plugin.js"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins);return(await Ot.start({configuration:r,stdout:this.context.stdout},async a=>{let{project:n}=await Rt.find(r,this.context.cwd),c,f;if(this.name.match(/^\.{0,2}[\\/]/)||fe.isAbsolute(this.name)){let p=J.resolve(this.context.cwd,fe.toPortablePath(this.name));a.reportInfo(0,`Reading ${he.pretty(r,p,he.Type.PATH)}`),c=J.relative(n.cwd,p),f=await ce.readFilePromise(p)}else{let p;if(this.name.match(/^https?:/)){try{new URL(this.name)}catch{throw new jt(52,`Plugin specifier "${this.name}" is neither a plugin name nor a valid url`)}c=this.name,p=this.name}else{let h=G.parseLocator(this.name.replace(/^((@yarnpkg\/)?plugin-)?/,"@yarnpkg/plugin-"));if(h.reference!=="unknown"&&!yye.default.valid(h.reference))throw new jt(0,"Official plugins only accept strict version references. Use an explicit URL if you wish to download them from another location.");let E=G.stringifyIdent(h),C=await Sm(r,fn);if(!Object.hasOwn(C,E)){let S=`Couldn't find a plugin named ${G.prettyIdent(r,h)} on the remote registry.
`;throw r.plugins.has(E)?S+=`A plugin named ${G.prettyIdent(r,h)} is already installed; possibly attempting to import a built-in plugin.`:S+=`Note that only the plugins referenced on our website (${he.pretty(r,"https://github.com/yarnpkg/berry/blob/master/plugins.yml",he.Type.URL)}) can be referenced by their name; any other plugin will have to be referenced through its public url (for example ${he.pretty(r,"https://github.com/yarnpkg/berry/raw/master/packages/plugin-typescript/bin/%40yarnpkg/plugin-typescript.js",he.Type.URL)}).`,new jt(51,S)}c=E,p=C[E].url,h.reference!=="unknown"?p=p.replace(/\/master\//,`/${E}/${h.reference}/`):fn!==null&&(p=p.replace(/\/master\//,`/@yarnpkg/cli/${fn}/`))}a.reportInfo(0,`Downloading ${he.pretty(r,p,"green")}`),f=await ln.get(p,{configuration:r})}await Xq(c,f,{checksum:this.checksum,project:n,report:a})})).exitCode()}};async function Xq(t,e,{checksum:r=!0,project:s,report:a}){let{configuration:n}=s,c={},f={exports:c};(0,Eye.runInNewContext)(e.toString(),{module:f,exports:c});let h=`.yarn/plugins/${f.exports.name}.cjs`,E=J.resolve(s.cwd,h);a.reportInfo(0,`Saving the new plugin in ${he.pretty(n,h,"magenta")}`),await ce.mkdirPromise(J.dirname(E),{recursive:!0}),await ce.writeFilePromise(E,e);let C={path:h,spec:t};r&&(C.checksum=Nn.makeHash(e)),await ze.addPlugin(s.cwd,[C])}var nct=({pluginName:t,noMinify:e},r)=>[["yarn",`build:${t}`,...e?["--no-minify"]:[],"|"]],xC=class extends ft{constructor(){super(...arguments);this.installPath=ge.String("--path",{description:"The path where the repository should be cloned to"});this.repository=ge.String("--repository","https://github.com/yarnpkg/berry.git",{description:"The repository that should be cloned"});this.branch=ge.String("--branch","master",{description:"The branch of the repository that should be cloned"});this.noMinify=ge.Boolean("--no-minify",!1,{description:"Build a plugin for development (debugging) - non-minified and non-mangled"});this.force=ge.Boolean("-f,--force",!1,{description:"Always clone the repository instead of trying to fetch the latest commits"});this.name=ge.String()}static{this.paths=[["plugin","import","from","sources"]]}static{this.usage=ot.Usage({category:"Plugin-related commands",description:"build a plugin from sources",details:`
This command clones the Yarn repository into a temporary folder, builds the specified contrib plugin and updates the configuration to reference it in further CLI invocations.
The plugins can be referenced by their short name if sourced from the official Yarn repository.
`,examples:[['Build and activate the "@yarnpkg/plugin-exec" plugin',"$0 plugin import from sources @yarnpkg/plugin-exec"],['Build and activate the "@yarnpkg/plugin-exec" plugin (shorthand)',"$0 plugin import from sources exec"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=typeof this.installPath<"u"?J.resolve(this.context.cwd,fe.toPortablePath(this.installPath)):J.resolve(fe.toPortablePath((0,Iye.tmpdir)()),"yarnpkg-sources",Nn.makeHash(this.repository).slice(0,6));return(await Ot.start({configuration:r,stdout:this.context.stdout},async n=>{let{project:c}=await Rt.find(r,this.context.cwd),f=G.parseIdent(this.name.replace(/^((@yarnpkg\/)?plugin-)?/,"@yarnpkg/plugin-")),p=G.stringifyIdent(f),h=await Sm(r,fn);if(!Object.hasOwn(h,p))throw new jt(51,`Couldn't find a plugin named "${p}" on the remote registry. Note that only the plugins referenced on our website (https://github.com/yarnpkg/berry/blob/master/plugins.yml) can be built and imported from sources.`);let E=p;await zq(this,{configuration:r,report:n,target:s}),await Zq(E,this,{project:c,report:n,target:s})})).exitCode()}};async function Zq(t,{context:e,noMinify:r},{project:s,report:a,target:n}){let c=t.replace(/@yarnpkg\//,""),{configuration:f}=s;a.reportSeparator(),a.reportInfo(0,`Building a fresh ${c}`),a.reportSeparator(),await $v(nct({pluginName:c,noMinify:r},n),{configuration:f,context:e,target:n}),a.reportSeparator();let p=J.resolve(n,`packages/${c}/bundles/${t}.js`),h=await ce.readFilePromise(p);await Xq(t,h,{project:s,report:a})}Ge();Dt();Yt();var kC=class extends ft{constructor(){super(...arguments);this.name=ge.String()}static{this.paths=[["plugin","remove"]]}static{this.usage=ot.Usage({category:"Plugin-related commands",description:"remove a plugin",details:`
This command deletes the specified plugin from the .yarn/plugins folder and removes it from the configuration.
**Note:** The plugins have to be referenced by their name property, which can be obtained using the \`yarn plugin runtime\` command. Shorthands are not allowed.
`,examples:[["Remove a plugin imported from the Yarn repository","$0 plugin remove @yarnpkg/plugin-typescript"],["Remove a plugin imported from a local file","$0 plugin remove my-local-plugin"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Rt.find(r,this.context.cwd);return(await Ot.start({configuration:r,stdout:this.context.stdout},async n=>{let c=this.name,f=G.parseIdent(c);if(!r.plugins.has(c))throw new nt(`${G.prettyIdent(r,f)} isn't referenced by the current configuration`);let p=`.yarn/plugins/${c}.cjs`,h=J.resolve(s.cwd,p);ce.existsSync(h)&&(n.reportInfo(0,`Removing ${he.pretty(r,p,he.Type.PATH)}...`),await ce.removePromise(h)),n.reportInfo(0,"Updating the configuration..."),await ze.updateConfiguration(s.cwd,{plugins:E=>{if(!Array.isArray(E))return E;let C=E.filter(S=>S.path!==p);return C.length===0?ze.deleteProperty:C.length===E.length?E:C}})})).exitCode()}};Ge();Yt();var QC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}static{this.paths=[["plugin","runtime"]]}static{this.usage=ot.Usage({category:"Plugin-related commands",description:"list the active plugins",details:`
This command prints the currently active plugins. Will be displayed both builtin plugins and external plugins.
`,examples:[["List the currently active plugins","$0 plugin runtime"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins);return(await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async a=>{for(let n of r.plugins.keys()){let c=this.context.plugins.plugins.has(n),f=n;c&&(f+=" [builtin]"),a.reportJson({name:n,builtin:c}),a.reportInfo(null,`${f}`)}})).exitCode()}};Ge();Ge();Yt();var RC=class extends ft{constructor(){super(...arguments);this.idents=ge.Rest()}static{this.paths=[["rebuild"]]}static{this.usage=ot.Usage({description:"rebuild the project's native packages",details:`
This command will automatically cause Yarn to forget about previous compilations of the given packages and to run them again.
Note that while Yarn forgets the compilation, the previous artifacts aren't erased from the filesystem and may affect the next builds (in good or bad). To avoid this, you may remove the .yarn/unplugged folder, or any other relevant location where packages might have been stored (Yarn may offer a way to do that automatically in the future).
By default all packages will be rebuilt, but you can filter the list by specifying the names of the packages you want to clear from memory.
`,examples:[["Rebuild all packages","$0 rebuild"],["Rebuild fsevents only","$0 rebuild fsevents"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);let c=new Set;for(let f of this.idents)c.add(G.parseIdent(f).identHash);if(await s.restoreInstallState({restoreResolutions:!1}),await s.resolveEverything({cache:n,report:new ki}),c.size>0)for(let f of s.storedPackages.values())c.has(f.identHash)&&(s.storedBuildState.delete(f.locatorHash),s.skippedBuilds.delete(f.locatorHash));else s.storedBuildState.clear(),s.skippedBuilds.clear();return await s.installWithNewReport({stdout:this.context.stdout,quiet:this.context.quiet},{cache:n})}};Ge();Ge();Ge();Yt();var $q=ut(Go());Ul();var TC=class extends ft{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Apply the operation to all workspaces from the current project"});this.mode=ge.String("--mode",{description:"Change what artifacts installs generate",validator:fo($l)});this.patterns=ge.Rest()}static{this.paths=[["remove"]]}static{this.usage=ot.Usage({description:"remove dependencies from the project",details:`
This command will remove the packages matching the specified patterns from the current workspace.
If the \`--mode=<mode>\` option is set, Yarn will change which artifacts are generated. The modes currently supported are:
- \`skip-build\` will not run the build scripts at all. Note that this is different from setting \`enableScripts\` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.
- \`update-lockfile\` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.
This command accepts glob patterns as arguments (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.
`,examples:[["Remove a dependency from the current project","$0 remove lodash"],["Remove a dependency from all workspaces at once","$0 remove lodash --all"],["Remove all dependencies starting with `eslint-`","$0 remove 'eslint-*'"],["Remove all dependencies with the `@babel` scope","$0 remove '@babel/*'"],["Remove all dependencies matching `react-dom` or `react-helmet`","$0 remove 'react-{dom,helmet}'"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState({restoreResolutions:!1});let c=this.all?s.workspaces:[a],f=["dependencies","devDependencies","peerDependencies"],p=[],h=!1,E=[];for(let I of this.patterns){let T=!1,N=G.parseIdent(I);for(let U of c){let W=[...U.manifest.peerDependenciesMeta.keys()];for(let ee of(0,$q.default)(W,I))U.manifest.peerDependenciesMeta.delete(ee),h=!0,T=!0;for(let ee of f){let ie=U.manifest.getForScope(ee),ue=[...ie.values()].map(le=>G.stringifyIdent(le));for(let le of(0,$q.default)(ue,G.stringifyIdent(N))){let{identHash:me}=G.parseIdent(le),pe=ie.get(me);if(typeof pe>"u")throw new Error("Assertion failed: Expected the descriptor to be registered");U.manifest[ee].delete(me),E.push([U,ee,pe]),h=!0,T=!0}}}T||p.push(I)}let C=p.length>1?"Patterns":"Pattern",S=p.length>1?"don't":"doesn't",b=this.all?"any":"this";if(p.length>0)throw new nt(`${C} ${he.prettyList(r,p,he.Type.CODE)} ${S} match any packages referenced by ${b} workspace`);return h?(await r.triggerMultipleHooks(I=>I.afterWorkspaceDependencyRemoval,E),await s.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})):0}};Ge();Ge();Yt();var Cye=Ie("util"),FC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}static{this.paths=[["run"]]}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);return(await Ot.start({configuration:r,stdout:this.context.stdout,json:this.json},async c=>{let f=a.manifest.scripts,p=je.sortMap(f.keys(),C=>C),h={breakLength:1/0,colors:r.get("enableColors"),maxArrayLength:2},E=p.reduce((C,S)=>Math.max(C,S.length),0);for(let[C,S]of f.entries())c.reportInfo(null,`${C.padEnd(E," ")} ${(0,Cye.inspect)(S,h)}`),c.reportJson({name:C,script:S})})).exitCode()}};Ge();Ge();Yt();var NC=class extends ft{constructor(){super(...arguments);this.inspect=ge.String("--inspect",!1,{tolerateBoolean:!0,description:"Forwarded to the underlying Node process when executing a binary"});this.inspectBrk=ge.String("--inspect-brk",!1,{tolerateBoolean:!0,description:"Forwarded to the underlying Node process when executing a binary"});this.topLevel=ge.Boolean("-T,--top-level",!1,{description:"Check the root workspace for scripts and/or binaries instead of the current one"});this.binariesOnly=ge.Boolean("-B,--binaries-only",!1,{description:"Ignore any user defined scripts and only check for binaries"});this.require=ge.String("--require",{description:"Forwarded to the underlying Node process when executing a binary"});this.silent=ge.Boolean("--silent",{hidden:!0});this.scriptName=ge.String();this.args=ge.Proxy()}static{this.paths=[["run"]]}static{this.usage=ot.Usage({description:"run a script defined in the package.json",details:`
This command will run a tool. The exact tool that will be executed will depend on the current state of your workspace:
- If the \`scripts\` field from your local package.json contains a matching script name, its definition will get executed.
- Otherwise, if one of the local workspace's dependencies exposes a binary with a matching name, this binary will get executed.
- Otherwise, if the specified name contains a colon character and if one of the workspaces in the project contains exactly one script with a matching name, then this script will get executed.
Whatever happens, the cwd of the spawned process will be the workspace that declares the script (which makes it possible to call commands cross-workspaces using the third syntax).
`,examples:[["Run the tests from the local workspace","$0 run test"],['Same thing, but without the "run" keyword',"$0 test"],["Inspect Webpack while running","$0 run --inspect-brk webpack"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a,locator:n}=await Rt.find(r,this.context.cwd);await s.restoreInstallState();let c=this.topLevel?s.topLevelWorkspace.anchoredLocator:n;if(!this.binariesOnly&&await In.hasPackageScript(c,this.scriptName,{project:s}))return await In.executePackageScript(c,this.scriptName,this.args,{project:s,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});let f=await In.getPackageAccessibleBinaries(c,{project:s});if(f.get(this.scriptName)){let h=[];return this.inspect&&(typeof this.inspect=="string"?h.push(`--inspect=${this.inspect}`):h.push("--inspect")),this.inspectBrk&&(typeof this.inspectBrk=="string"?h.push(`--inspect-brk=${this.inspectBrk}`):h.push("--inspect-brk")),this.require&&h.push(`--require=${this.require}`),await In.executePackageAccessibleBinary(c,this.scriptName,this.args,{cwd:this.context.cwd,project:s,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,nodeArgs:h,packageAccessibleBinaries:f})}if(!this.topLevel&&!this.binariesOnly&&a&&this.scriptName.includes(":")){let E=(await Promise.all(s.workspaces.map(async C=>C.manifest.scripts.has(this.scriptName)?C:null))).filter(C=>C!==null);if(E.length===1)return await In.executeWorkspaceScript(E[0],this.scriptName,this.args,{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})}if(this.topLevel)throw this.scriptName==="node-gyp"?new nt(`Couldn't find a script name "${this.scriptName}" in the top-level (used by ${G.prettyLocator(r,n)}). This typically happens because some package depends on "node-gyp" to build itself, but didn't list it in their dependencies. To fix that, please run "yarn add node-gyp" into your top-level workspace. You also can open an issue on the repository of the specified package to suggest them to use an optional peer dependency.`):new nt(`Couldn't find a script name "${this.scriptName}" in the top-level (used by ${G.prettyLocator(r,n)}).`);{if(this.scriptName==="global")throw new nt("The 'yarn global' commands have been removed in 2.x - consider using 'yarn dlx' or a third-party plugin instead");let h=[this.scriptName].concat(this.args);for(let[E,C]of $I)for(let S of C)if(h.length>=S.length&&JSON.stringify(h.slice(0,S.length))===JSON.stringify(S))throw new nt(`Couldn't find a script named "${this.scriptName}", but a matching command can be found in the ${E} plugin. You can install it with "yarn plugin import ${E}".`);throw new nt(`Couldn't find a script named "${this.scriptName}".`)}}};Ge();Ge();Yt();var OC=class extends ft{constructor(){super(...arguments);this.descriptor=ge.String();this.resolution=ge.String()}static{this.paths=[["set","resolution"]]}static{this.usage=ot.Usage({description:"enforce a package resolution",details:'\n This command updates the resolution table so that `descriptor` is resolved by `resolution`.\n\n Note that by default this command only affect the current resolution table - meaning that this "manual override" will disappear if you remove the lockfile, or if the package disappear from the table. If you wish to make the enforced resolution persist whatever happens, edit the `resolutions` field in your top-level manifest.\n\n Note that no attempt is made at validating that `resolution` is a valid resolution entry for `descriptor`.\n ',examples:[["Force all instances of lodash@npm:^1.2.3 to resolve to 1.5.0","$0 set resolution lodash@npm:^1.2.3 npm:1.5.0"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n=await Kr.find(r);if(await s.restoreInstallState({restoreResolutions:!1}),!a)throw new ar(s.cwd,this.context.cwd);let c=G.parseDescriptor(this.descriptor,!0),f=G.makeDescriptor(c,this.resolution);return s.storedDescriptors.set(c.descriptorHash,c),s.storedDescriptors.set(f.descriptorHash,f),s.resolutionAliases.set(c.descriptorHash,f.descriptorHash),await s.installWithNewReport({stdout:this.context.stdout},{cache:n})}};Ge();Dt();Yt();var wye=ut(Go()),LC=class extends ft{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Unlink all workspaces belonging to the target project from the current one"});this.leadingArguments=ge.Rest()}static{this.paths=[["unlink"]]}static{this.usage=ot.Usage({description:"disconnect the local project from another one",details:`
This command will remove any resolutions in the project-level manifest that would have been added via a yarn link with similar arguments.
`,examples:[["Unregister a remote workspace in the current project","$0 unlink ~/ts-loader"],["Unregister all workspaces from a remote project in the current project","$0 unlink ~/jest --all"],["Unregister all previously linked workspaces","$0 unlink --all"],["Unregister all workspaces matching a glob","$0 unlink '@babel/*' 'pkg-{a,b}'"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);let c=s.topLevelWorkspace,f=new Set;if(this.leadingArguments.length===0&&this.all)for(let{pattern:p,reference:h}of c.manifest.resolutions)h.startsWith("portal:")&&f.add(p.descriptor.fullName);if(this.leadingArguments.length>0)for(let p of this.leadingArguments){let h=J.resolve(this.context.cwd,fe.toPortablePath(p));if(je.isPathLike(p)){let E=await ze.find(h,this.context.plugins,{useRc:!1,strict:!1}),{project:C,workspace:S}=await Rt.find(E,h);if(!S)throw new ar(C.cwd,h);if(this.all){for(let b of C.workspaces)b.manifest.name&&f.add(G.stringifyIdent(b.anchoredLocator));if(f.size===0)throw new nt("No workspace found to be unlinked in the target project")}else{if(!S.manifest.name)throw new nt("The target workspace doesn't have a name and thus cannot be unlinked");f.add(G.stringifyIdent(S.anchoredLocator))}}else{let E=[...c.manifest.resolutions.map(({pattern:C})=>C.descriptor.fullName)];for(let C of(0,wye.default)(E,p))f.add(C)}}return c.manifest.resolutions=c.manifest.resolutions.filter(({pattern:p})=>!f.has(p.descriptor.fullName)),await s.installWithNewReport({stdout:this.context.stdout,quiet:this.context.quiet},{cache:n})}};Ge();Ge();Ge();Yt();var Bye=ut(Vv()),e5=ut(Go());Ul();var MC=class extends ft{constructor(){super(...arguments);this.interactive=ge.Boolean("-i,--interactive",{description:"Offer various choices, depending on the detected upgrade paths"});this.fixed=ge.Boolean("-F,--fixed",!1,{description:"Store dependency tags as-is instead of resolving them"});this.exact=ge.Boolean("-E,--exact",!1,{description:"Don't use any semver modifier on the resolved range"});this.tilde=ge.Boolean("-T,--tilde",!1,{description:"Use the `~` semver modifier on the resolved range"});this.caret=ge.Boolean("-C,--caret",!1,{description:"Use the `^` semver modifier on the resolved range"});this.recursive=ge.Boolean("-R,--recursive",!1,{description:"Resolve again ALL resolutions for those packages"});this.mode=ge.String("--mode",{description:"Change what artifacts installs generate",validator:fo($l)});this.patterns=ge.Rest()}static{this.paths=[["up"]]}static{this.usage=ot.Usage({description:"upgrade dependencies across the project",details:"\n This command upgrades the packages matching the list of specified patterns to their latest available version across the whole project (regardless of whether they're part of `dependencies` or `devDependencies` - `peerDependencies` won't be affected). This is a project-wide command: all workspaces will be upgraded in the process.\n\n If `-R,--recursive` is set the command will change behavior and no other switch will be allowed. When operating under this mode `yarn up` will force all ranges matching the selected packages to be resolved again (often to the highest available versions) before being stored in the lockfile. It however won't touch your manifests anymore, so depending on your needs you might want to run both `yarn up` and `yarn up -R` to cover all bases.\n\n If `-i,--interactive` is set (or if the `preferInteractive` settings is toggled on) the command will offer various choices, depending on the detected upgrade paths. Some upgrades require this flag in order to resolve ambiguities.\n\n The, `-C,--caret`, `-E,--exact` and `-T,--tilde` options have the same meaning as in the `add` command (they change the modifier used when the range is missing or a tag, and are ignored when the range is explicitly set).\n\n If the `--mode=<mode>` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\n\n - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\n\n - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\n\n Generally you can see `yarn up` as a counterpart to what was `yarn upgrade --latest` in Yarn 1 (ie it ignores the ranges previously listed in your manifests), but unlike `yarn upgrade` which only upgraded dependencies in the current workspace, `yarn up`Line truncated
${le}`):N.reportError(27,`${G.prettyDescriptor(r,U)} can't be resolved to a satisfying range (note: network resolution has been disabled)
${le}`)}else ie.length>1&&!f&&N.reportError(27,`${G.prettyDescriptor(r,U)} has multiple possible upgrade strategies; use -i to disambiguate manually`)}});if(b.hasErrors())return b.exitCode();let I=!1,T=[];for(let[N,U,,{suggestions:W}]of S){let ee,ie=W.filter(pe=>pe.descriptor!==null),ue=ie[0].descriptor,le=ie.every(pe=>G.areDescriptorsEqual(pe.descriptor,ue));ie.length===1||le?ee=ue:(I=!0,{answer:ee}=await(0,Bye.prompt)({type:"select",name:"answer",message:`Which range do you want to use in ${G.prettyWorkspace(r,N)} \u276F ${U}?`,choices:W.map(({descriptor:pe,name:Be,reason:Ce})=>pe?{name:Be,hint:Ce,descriptor:pe}:{name:Be,hint:Ce,disabled:!0}),onCancel:()=>process.exit(130),result(pe){return this.find(pe,"descriptor")},stdin:this.context.stdin,stdout:this.context.stdout}));let me=N.manifest[U].get(ee.identHash);if(typeof me>"u")throw new Error("Assertion failed: This descriptor should have a matching entry");if(me.descriptorHash!==ee.descriptorHash)N.manifest[U].set(ee.identHash,ee),T.push([N,U,me,ee]);else{let pe=r.makeResolver(),Be={project:s,resolver:pe},Ce=r.normalizeDependency(me),g=pe.bindDescriptor(Ce,N.anchoredLocator,Be);s.forgetResolution(g)}}return await r.triggerMultipleHooks(N=>N.afterWorkspaceDependencyReplacement,T),I&&this.context.stdout.write(`
`),await s.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})}};Ge();Ge();Ge();Yt();var UC=class extends ft{constructor(){super(...arguments);this.recursive=ge.Boolean("-R,--recursive",!1,{description:"List, for each workspace, what are all the paths that lead to the dependency"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.peers=ge.Boolean("--peers",!1,{description:"Also print the peer dependencies that match the specified name"});this.package=ge.String()}static{this.paths=[["why"]]}static{this.usage=ot.Usage({description:"display the reason why a package is needed",details:`
This command prints the exact reasons why a package appears in the dependency tree.
If \`-R,--recursive\` is set, the listing will go in depth and will list, for each workspaces, what are all the paths that lead to the dependency. Note that the display is somewhat optimized in that it will not print the package listing twice for a single package, so if you see a leaf named "Foo" when looking for "Bar", it means that "Foo" already got printed higher in the tree.
`,examples:[["Explain why lodash is used in your project","$0 why lodash"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState();let n=G.parseIdent(this.package).identHash,c=this.recursive?sct(s,n,{configuration:r,peers:this.peers}):ict(s,n,{configuration:r,peers:this.peers});xs.emitTree(c,{configuration:r,stdout:this.context.stdout,json:this.json,separators:1})}};function ict(t,e,{configuration:r,peers:s}){let a=je.sortMap(t.storedPackages.values(),f=>G.stringifyLocator(f)),n={},c={children:n};for(let f of a){let p={};for(let E of f.dependencies.values()){if(!s&&f.peerDependencies.has(E.identHash))continue;let C=t.storedResolutions.get(E.descriptorHash);if(!C)throw new Error("Assertion failed: The resolution should have been registered");let S=t.storedPackages.get(C);if(!S)throw new Error("Assertion failed: The package should have been registered");if(S.identHash!==e)continue;{let I=G.stringifyLocator(f);n[I]={value:[f,he.Type.LOCATOR],children:p}}let b=G.stringifyLocator(S);p[b]={value:[{descriptor:E,locator:S},he.Type.DEPENDENT]}}}return c}function sct(t,e,{configuration:r,peers:s}){let a=je.sortMap(t.workspaces,S=>G.stringifyLocator(S.anchoredLocator)),n=new Set,c=new Set,f=S=>{if(n.has(S.locatorHash))return c.has(S.locatorHash);if(n.add(S.locatorHash),S.identHash===e)return c.add(S.locatorHash),!0;let b=!1;S.identHash===e&&(b=!0);for(let I of S.dependencies.values()){if(!s&&S.peerDependencies.has(I.identHash))continue;let T=t.storedResolutions.get(I.descriptorHash);if(!T)throw new Error("Assertion failed: The resolution should have been registered");let N=t.storedPackages.get(T);if(!N)throw new Error("Assertion failed: The package should have been registered");f(N)&&(b=!0)}return b&&c.add(S.locatorHash),b};for(let S of a)f(S.anchoredPackage);let p=new Set,h={},E={children:h},C=(S,b,I)=>{if(!c.has(S.locatorHash))return;let T=I!==null?he.tuple(he.Type.DEPENDENT,{locator:S,descriptor:I}):he.tuple(he.Type.LOCATOR,S),N={},U={value:T,children:N},W=G.stringifyLocator(S);if(b[W]=U,!(I!==null&&t.tryWorkspaceByLocator(S))&&!p.has(S.locatorHash)){p.add(S.locatorHash);for(let ee of S.dependencies.values()){if(!s&&S.peerDependencies.has(ee.identHash))continue;let ie=t.storedResolutions.get(ee.descriptorHash);if(!ie)throw new Error("Assertion failed: The resolution should have been registered");let ue=t.storedPackages.get(ie);if(!ue)throw new Error("Assertion failed: The package should have been registered");C(ue,N,ee)}}};for(let S of a)C(S.anchoredPackage,h,null);return E}Ge();var u5={};Vt(u5,{GitFetcher:()=>tS,GitResolver:()=>rS,default:()=>Dct,gitUtils:()=>ka});Ge();Dt();var ka={};Vt(ka,{TreeishProtocols:()=>eS,clone:()=>c5,fetchBase:()=>qye,fetchChangedFiles:()=>Wye,fetchChangedWorkspaces:()=>vct,fetchRoot:()=>Gye,isGitUrl:()=>jC,lsRemote:()=>jye,normalizeLocator:()=>Bct,normalizeRepoUrl:()=>_C,resolveUrl:()=>l5,splitRepoUrl:()=>W0,validateRepoUrl:()=>a5});Ge();Dt();Yt();ql();var _ye=ut(Lye()),HC=ut(Ie("querystring")),s5=ut(Ai());function i5(t,e,r){let s=t.indexOf(r);return t.lastIndexOf(e,s>-1?s:1/0)}function Mye(t){try{return new URL(t)}catch{return}}function Cct(t){let e=i5(t,"@","#"),r=i5(t,":","#");return r>e&&(t=`${t.slice(0,r)}/${t.slice(r+1)}`),i5(t,":","#")===-1&&t.indexOf("//")===-1&&(t=`ssh://${t}`),t}function Uye(t){return Mye(t)||Mye(Cct(t))}function _C(t,{git:e=!1}={}){if(t=t.replace(/^git\+https:/,"https:"),t=t.replace(/^(?:github:|https:\/\/github\.com\/|git:\/\/github\.com\/)?(?!\.{1,2}\/)([a-zA-Z0-9._-]+)\/(?!\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)(?:\.git)?(#.*)?$/,"https://github.com/$1/$2.git$3"),t=t.replace(/^https:\/\/github\.com\/(?!\.{1,2}\/)([a-zA-Z0-9._-]+)\/(?!\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)\/tarball\/(.+)?$/,"https://github.com/$1/$2.git#$3"),e){let r=Uye(t);r&&(t=r.href),t=t.replace(/^git\+([^:]+):/,"$1:")}return t}function Hye(){return{...process.env,GIT_SSH_COMMAND:process.env.GIT_SSH_COMMAND||`${process.env.GIT_SSH||"ssh"} -o BatchMode=yes`}}var wct=[/^ssh:/,/^git(?:\+[^:]+)?:/,/^(?:git\+)?https?:[^#]+\/[^#]+(?:\.git)(?:#.*)?$/,/^git@[^#]+\/[^#]+\.git(?:#.*)?$/,/^(?:github:|https:\/\/github\.com\/)?(?!\.{1,2}\/)([a-zA-Z._0-9-]+)\/(?!\.{1,2}(?:#|$))([a-zA-Z._0-9-]+?)(?:\.git)?(?:#.*)?$/,/^https:\/\/github\.com\/(?!\.{1,2}\/)([a-zA-Z0-9._-]+)\/(?!\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)\/tarball\/(.+)?$/],eS=(a=>(a.Commit="commit",a.Head="head",a.Tag="tag",a.Semver="semver",a))(eS||{});function jC(t){return t?wct.some(e=>!!t.match(e)):!1}function W0(t){t=_C(t);let e=t.indexOf("#");if(e===-1)return{repo:t,treeish:{protocol:"head",request:"HEAD"},extra:{}};let r=t.slice(0,e),s=t.slice(e+1);if(s.match(/^[a-z]+=/)){let a=HC.default.parse(s);for(let[p,h]of Object.entries(a))if(typeof h!="string")throw new Error(`Assertion failed: The ${p} parameter must be a literal string`);let n=Object.values(eS).find(p=>Object.hasOwn(a,p)),[c,f]=typeof n Line truncated
This command will run a given sub-command on a single workspace.
`,examples:[["Add a package to a single workspace","yarn workspace components add -D react"],["Run build script on a single workspace","yarn workspace components run build"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);let n=s.workspaces,c=new Map(n.map(p=>[G.stringifyIdent(p.anchoredLocator),p])),f=c.get(this.workspaceName);if(f===void 0){let p=Array.from(c.keys()).sort();throw new nt(`Workspace '${this.workspaceName}' not found. Did you mean any of the following:
- ${p.join(`
- `)}?`)}return this.cli.run([this.commandName,...this.args],{cwd:f.cwd})}};var Pct={configuration:{enableImmutableInstalls:{description:"If true (the default on CI), prevents the install command from modifying the lockfile",type:"BOOLEAN",default:Yye.isCI},defaultSemverRangePrefix:{description:"The default save prefix: '^', '~' or ''",type:"STRING",values:["^","~",""],default:"^"},preferReuse:{description:"If true, `yarn add` will attempt to reuse the most common dependency range in other workspaces.",type:"BOOLEAN",default:!1}},commands:[aC,lC,cC,uC,OC,PC,EC,GC,pC,hC,gC,dC,sC,oC,fC,AC,mC,yC,IC,CC,wC,BC,LC,vC,SC,xC,bC,kC,DC,QC,RC,TC,FC,NC,MC,UC,qC]},bct=Pct;var d5={};Vt(d5,{default:()=>kct});Ge();var Qt={optional:!0},A5=[["@tailwindcss/aspect-ratio@<0.2.1",{peerDependencies:{tailwindcss:"^2.0.2"}}],["@tailwindcss/line-clamp@<0.2.1",{peerDependencies:{tailwindcss:"^2.0.2"}}],["@fullhuman/[email protected] || 3.1.3-alpha.0",{peerDependencies:{postcss:"^8.0.0"}}],["@samverschueren/stream-to-observable@<0.3.1",{peerDependenciesMeta:{rxjs:Qt,zenObservable:Qt}}],["any-observable@<0.5.1",{peerDependenciesMeta:{rxjs:Qt,zenObservable:Qt}}],["@pm2/agent@<1.0.4",{dependencies:{debug:"*"}}],["debug@<4.2.0",{peerDependenciesMeta:{"supports-color":Qt}}],["got@<11",{dependencies:{"@types/responselike":"^1.0.0","@types/keyv":"^3.1.1"}}],["cacheable-lookup@<4.1.2",{dependencies:{"@types/keyv":"^3.1.1"}}],["http-link-dataloader@*",{peerDependencies:{graphql:"^0.13.1 || ^14.0.0"}}],["typescript-language-server@*",{dependencies:{"vscode-jsonrpc":"^5.0.1","vscode-languageserver-protocol":"^3.15.0"}}],["postcss-syntax@*",{peerDependenciesMeta:{"postcss-html":Qt,"postcss-jsx":Qt,"postcss-less":Qt,"postcss-markdown":Qt,"postcss-scss":Qt}}],["jss-plugin-rule-value-function@<=10.1.1",{dependencies:{"tiny-warning":"^1.0.2"}}],["ink-select-input@<4.1.0",{peerDependencies:{react:"^16.8.2"}}],["license-webpack-plugin@<2.3.18",{peerDependenciesMeta:{webpack:Qt}}],["snowpack@>=3.3.0",{dependencies:{"node-gyp":"^7.1.0"}}],["promise-inflight@*",{peerDependenciesMeta:{bluebird:Qt}}],["reactcss@*",{peerDependencies:{react:"*"}}],["react-color@<=2.19.0",{peerDependencies:{react:"*"}}],["gatsby-plugin-i18n@*",{dependencies:{ramda:"^0.24.1"}}],["useragent@^2.0.0",{dependencies:{request:"^2.88.0",yamlparser:"0.0.x",semver:"5.5.x"}}],["@apollographql/apollo-tools@<=0.5.2",{peerDependencies:{graphql:"^14.2.1 || ^15.0.0"}}],["material-table@^2.0.0",{dependencies:{"@babel/runtime":"^7.11.2"}}],["@babel/parser@*",{dependencies:{"@babel/types":"^7.8.3"}}],["fork-ts-checker-webpack-plugin@<=6.3.4",{peerDependencies:{eslint:">= 6",typescript:">= 2.7",webpack:">= 4","vue-template-compiler":"*"},peerDependenciesMeta:{eslint:Qt,"vue-template-compiler":Qt}}],["rc-animate@<=3.1.1",{peerDependencies:{react:">=16.9.0","react-dom":">=16.9.0"}}],["react-bootstrap-table2-paginator@*",{dependencies:{classnames:"^2.2.6"}}],["react-draggable@<=4.4.3",{peerDependencies:{react:">= 16.3.0","react-dom":">= 16.3.0"}}],["apollo-upload-client@<14",{peerDependencies:{graphql:"14 - 15"}}],["react-instantsearch-core@<=6.7.0",{peerDependencies:{algoliasearch:">= 3.1 < 5"}}],["react-instantsearch-dom@<=6.7.0",{dependencies:{"react-fast-compare":"^3.0.0"}}],["ws@<7.2.1",{peerDependencies:{bufferutil:"^4.0.1","utf-8-validate":"^5.0.2"},peerDependenciesMeta:{bufferutil:Qt,"utf-8-validate":Qt}}],["react-portal@<4.2.2",{peerDependencies:{"react-dom":"^15.0.0-0 || ^16.0.0-0 || ^17.0.0-0"}}],["react-scripts@<=4.0.1",{peerDependencies:{react:"*"}}],["testcafe@<=1.10.1",{dependencies:{"@babel/plugin-transform-for-of":"^7.12.1","@babel/runtime":"^7.12.5"}}],["testcafe-legacy-api@<=4.2.0",{dependencies:{"testcafe-hammerhead":"^17.0.1","read-file-relative":"^1.2.0"}}],["@google-cloud/firestore@<=4.9.3",{dependencies:{protobufjs:"^6.8.6"}}],["gatsby-source-apiserver@*",{dependencies:{"babel-polyfill":"^6.26.0"}}],["@webpack-cli/package-utils@<=1.0.1-alpha.4",{dependencies:{"cross-spawn":"^7.0.3"}}],["gatsby-remark-prismjs@<3.3.28",{dependencies:{lodash:"^4"}}],["gatsby-plugin-favicon@*",{peerDependencies:{webpack:"*"}}],["gatsby-plugin-sharp@<=4.6.0-next.3",{dependencies:{debug:"^4.3.1"}}],["gatsby-react-router-scroll@<=5.6.0-next.0",{dependencies:{"prop-types":"^15.7.2"}}],["@rebass/forms@*",{dependencies:{"@styled-system/should-forward-prop":"^5.0.0"},peerDependencies:{react:"^16.8.6"}}],["rebass@*",{peerDependencies:{react:"^16.8.6"}}],["@ant-design/react-slick@<=0.28.3",{peerDependencies:{react:">=16.0.0"}}],["mqtt@<4.2.7",{dependencies:{duplexify:"^4.1.1"}}],["vue-cli-plugin-vuetify@<=2.0.3",{dependencies:{semver:"^6.3.0"},peerDependenciesMeta:{"sass-loader":Qt,"vuetify-loader":Qt}}],["vue-cli-plugin-vuetify@<=2.0.4",{dependencies:{"null-loader":"^3.0.0"}}],["vue-cli-plugin-vuetify@>=2.4.3",{peerDependencies:{vue:"*"}}],["@vuetify/cli-plugin-utils@<=0.0.4",{dependencies:{semver:"^6.3.0"},peerDependenciesMeta:{"sass-loader":Qt}}],["@vue/cli-plugin-typescript@<=5.0.0-alpha.0",{deLine truncated
This command will output all matches to the given prolog query.
`,examples:[["List all dependencies throughout the workspace","yarn constraints query 'workspace_has_dependency(_, DependencyName, _, _).'"]]})}async execute(){let{Constraints:r}=await Promise.resolve().then(()=>(lS(),aS)),s=await ze.find(this.context.cwd,this.context.plugins),{project:a}=await Rt.find(s,this.context.cwd),n=await r.find(a),c=this.query;return c.endsWith(".")||(c=`${c}.`),(await Ot.start({configuration:s,json:this.json,stdout:this.context.stdout},async p=>{for await(let h of n.query(c)){let E=Array.from(Object.entries(h)),C=E.length,S=E.reduce((b,[I])=>Math.max(b,I.length),0);for(let b=0;b<C;b++){let[I,T]=E[b];p.reportInfo(null,`${Vct(b,C)}${I.padEnd(S," ")} = ${Yct(T)}`)}p.reportJson(h)}})).exitCode()}};function Yct(t){return typeof t!="string"?`${t}`:t.match(/^[a-zA-Z][a-zA-Z0-9_]+$/)?t:`'${t}'`}function Vct(t,e){let r=t===0,s=t===e-1;return r&&s?"":r?"\u250C ":s?"\u2514 ":"\u2502 "}Ge();Yt();var ZC=class extends ft{constructor(){super(...arguments);this.verbose=ge.Boolean("-v,--verbose",!1,{description:"Also print the fact database automatically compiled from the workspace manifests"})}static{this.paths=[["constraints","source"]]}static{this.usage=ot.Usage({category:"Constraints-related commands",description:"print the source code for the constraints",details:"\n This command will print the Prolog source code used by the constraints engine. Adding the `-v,--verbose` flag will print the *full* source code, including the fact database automatically compiled from the workspace manifests.\n ",examples:[["Prints the source code","yarn constraints source"],["Print the source code and the fact database","yarn constraints source -v"]]})}async execute(){let{Constraints:r}=await Promise.resolve().then(()=>(lS(),aS)),s=await ze.find(this.context.cwd,this.context.plugins),{project:a}=await Rt.find(s,this.context.cwd),n=await r.find(a);this.context.stdout.write(this.verbose?n.fullSource:n.source)}};Ge();Ge();Yt();iS();var XC=class extends ft{constructor(){super(...arguments);this.fix=ge.Boolean("--fix",!1,{description:"Attempt to automatically fix unambiguous issues, following a multi-pass process"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}static{this.paths=[["constraints"]]}static{this.usage=ot.Usage({category:"Constraints-related commands",description:"check that the project constraints are met",details:`
This command will run constraints on your project and emit errors for each one that is found but isn't met. If any error is emitted the process will exit with a non-zero exit code.
If the \`--fix\` flag is used, Yarn will attempt to automatically fix the issues the best it can, following a multi-pass process (with a maximum of 10 iterations). Some ambiguous patterns cannot be autofixed, in which case you'll have to manually specify the right resolution.
For more information as to how to write constraints, please consult our dedicated page on our website: https://yarnpkg.com/features/constraints.
`,examples:[["Check that all constraints are satisfied","yarn constraints"],["Autofix all unmet constraints","yarn constraints --fix"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Rt.find(r,this.context.cwd);await s.restoreInstallState();let a=await s.loadUserConfig(),n;if(a?.constraints)n=new YC(s);else{let{Constraints:h}=await Promise.resolve().then(()=>(lS(),aS));n=await h.find(s)}let c,f=!1,p=!1;for(let h=this.fix?10:1;h>0;--h){let E=await n.process();if(!E)break;let{changedWorkspaces:C,remainingErrors:S}=nF(s,E,{fix:this.fix}),b=[];for(let[I,T]of C){let N=I.manifest.indent;I.manifest=new Ut,I.manifest.indent=N,I.manifest.load(T),b.push(I.persistManifest())}if(await Promise.all(b),!(C.size>0&&h>1)){c=Zye(S,{configuration:r}),f=!1,p=!0;for(let[,I]of S)for(let T of I)T.fixable?f=!0:p=!1}}if(c.children.length===0)return 0;if(f){let h=p?`Those errors can all be fixed by running ${he.pretty(r,"yarn constraints --fix",he.Type.CODE)}`:`Errors prefixed by '\u2699' can be fixed by running ${he.pretty(r,"yarn constraints --fix",he.Type.CODE)}`;await Ot.start({configuration:r,stdout:this.context.stdout,includeNames:!1,includeFooter:!1},async E=>{E.reportInfo(0,h),E.reportSeparator()})}return c.children=je.sortMap(c.children,h=>h.value[1]),xs.emitTree(c,{configuration:r,stdout:this.context.stdout,json:this.json,separators:1}),1}};iS();var Jct={configuration:{enableConstraintsChecks:{description:"If true, constraints will run during installs",type:"BOOLEAN",default:!1},constraintsPath:{description:"The path of the constraints file.",type:"ABSOLUTE_PATH",default:"./constraints.pro"}},commands:[zC,ZC,XC],hooks:{async validateProjectAfterInstall(t,{reportError:e}){if(!t.configuration.get("enableConstraintsChecks"))return;let r=await t.loadUserConfig(),s;if(r?.constraints)s=new YC(t);else{let{Constraints:c}=await Promise.resolve().then(()=>(lS(),aS));s=await c.find(t)}let a=await s.process();if(!a)return;let{remainingErrors:n}=nF(t,a);if(n.size!==0)if(t.configuration.isCI)for(let[c,f]of n)for(let p of f)e(84,`${he.pretty(t.configuration,c.anchoredLocator,he.Type.IDENT)}: ${p.text}`);else e(84,`Constraint check failed; run ${he.pretty(t.configuration,"yarn constraints",he.Type.CODE)} for more details`)}}},Kct=Jct;var F5={};Vt(F5,{CreateCommand:()=>$C,DlxCommand:()=>ew,default:()=>Zct});Ge();Yt();var $C=class extends ft{constructor(){super(...arguments);this.pkg=ge.String("-p,--package",{description:"The package to run the provided command from"});this.quiet=ge.Boolean("-q,--quiet",!1,{description:"Only report critical errors instead of printing the full install logs"});this.command=ge.String();this.args=ge.Proxy()}static{this.paths=[["create"]]}async execute(){let r=[];this.pkg&&r.push("--package",this.pkg),this.quiet&&r.push("--quiet");let s=this.command.replace(/^(@[^@/]+)(@|$)/,"$1/create$2"),a=G.parseDescriptor(s),n=a.name.match(/^create(-|$)/)?a:a.scope?G.makeIdent(a.scope,`create-${a.name}`):G.makeIdent(null,`create-${a.name}`),c=G.stringifyIdent(n);return a.range!=="unknown"&&(c+=`@${a.range}`),this.cli.run(["dlx",...r,c,...this.args])}};Ge();Ge();Dt();Yt();var ew=class extends ft{constructor(){super(...arguments);this.packages=ge.Array("-p,--package",{description:"The package(s) to install before running the command"});this.quiet=ge.Boolean("-q,--quiet",!1,{description:"Only report critical errors instead of printing the full install logs"});this.command=ge.String();this.args=ge.Proxy()}static{this.paths=[["dlx"]]}static{this.usage=ot.Usage({description:"run a package in a temporary environment",details:"\n This command will install a package within a temporary environment, and run its binary script if it contains any. The binary will run within the current cwd.\n\n By default Yarn will download the package named `command`, but this can be changed through the use of the `-p,--package` flag which will instruct Yarn to still run the same command but from a different package.\n\n Using `yarn dlx` as a replacement of `yarn add` isn't recommended, as it makes your project non-deterministic (Yarn doesn't keep track of the packages installed through `dlx` - neither their name, nor their version).\n ",examples:[["Use create-vite to scaffold a new Vite project","yarn dlx create-vite"],["Install multiple packages for a single command",`yarn dlx -p typescript -p ts-node ts-node --transpile-only -e "console.log('hello!')"`]]})}async execute(){return ze.telemetry=null,await ce.mktempPromise(async r=>{let s=J.join(r,`dlx-${process.pid}`);await ce.mkdirPromise(s),await ce.writeFilePromise(J.join(s,"package.json"),`{}
`),await ce.writeFilePromise(J.join(s,"yarn.lock"),"");let a=J.join(s,".yarnrc.yml"),n=await ze.findProjectCwd(this.context.cwd),f={enableGlobalCache:!(await ze.find(this.context.cwd,null,{strict:!1})).get("enableGlobalCache"),enableTelemetry:!1,logFilters:[{code:Yf(68),level:he.LogLevel.Discard}]},p=n!==null?J.join(n,".yarnrc.yml"):null;p!==null&&ce.existsSync(p)?(await ce.copyFilePromise(p,a),await ze.updateConfiguration(s,N=>{let U=je.toMerged(N,f);return Array.isArray(N.plugins)&&(U.plugins=N.plugins.map(W=>{let ee=typeof W=="string"?W:W.path,ie=fe.isAbsolute(ee)?ee:fe.resolve(fe.fromPortablePath(n),ee);return typeof W=="string"?ie:{path:ie,spec:W.spec}})),U})):await ce.writeJsonPromise(a,f);let h=this.packages??[this.command],E=G.parseDescriptor(this.command).name,C=await this.cli.run(["add","--fixed","--",...h],{cwd:s,quiet:this.quiet});if(C!==0)return C;this.quiet||this.context.stdout.write(`
`);let S=await ze.find(s,this.context.plugins),{project:b,workspace:I}=await Rt.find(S,s);if(I===null)throw new ar(b.cwd,s);await b.restoreInstallState();let T=await In.getWorkspaceAccessibleBinaries(I);return T.has(E)===!1&&T.size===1&&typeof this.packages>"u"&&(E=Array.from(T)[0][0]),await In.executeWorkspaceAccessibleBinary(I,E,this.args,{packageAccessibleBinaries:T,cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})})}};var zct={commands:[$C,ew]},Zct=zct;var L5={};Vt(L5,{ExecFetcher:()=>uS,ExecResolver:()=>fS,default:()=>eut,execUtils:()=>aF});Ge();Ge();Dt();var cA="exec:";var aF={};Vt(aF,{loadGeneratorFile:()=>cS,makeLocator:()=>O5,makeSpec:()=>BEe,parseSpec:()=>N5});Ge();Dt();function N5(t){let{params:e,selector:r}=G.parseRange(t),s=fe.toPortablePath(r);return{parentLocator:e&&typeof e.locator=="string"?G.parseLocator(e.locator):null,path:s}}function BEe({parentLocator:t,path:e,generatorHash:r,protocol:s}){let a=t!==null?{locator:G.stringifyLocator(t)}:{},n=typeof r<"u"?{hash:r}:{};return G.makeRange({protocol:s,source:e,selector:e,params:{...n,...a}})}function O5(t,{parentLocator:e,path:r,generatorHash:s,protocol:a}){return G.makeLocator(t,BEe({parentLocator:e,path:r,generatorHash:s,protocol:a}))}async function cS(t,e,r){let{parentLocator:s,path:a}=G.parseFileStyleRange(t,{protocol:e}),n=J.isAbsolute(a)?{packageFs:new Sn(vt.root),prefixPath:vt.dot,localPath:vt.root}:await r.fetcher.fetch(s,r),c=n.localPath?{packageFs:new Sn(vt.root),prefixPath:J.relative(vt.root,n.localPath)}:n;n!==c&&n.releaseFs&&n.releaseFs();let f=c.packageFs,p=J.join(c.prefixPath,a);return await f.readFilePromise(p,"utf8")}var uS=class{supports(e,r){return!!e.reference.startsWith(cA)}getLocalPath(e,r){let{parentLocator:s,path:a}=G.parseFileStyleRange(e.reference,{protocol:cA});if(J.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(s,r);return n===null?null:J.resolve(n,a)}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:c}}async fetchFromDisk(e,r){let s=await cS(e.reference,cA,r);return ce.mktempPromise(async a=>{let n=J.join(a,"generator.js");return await ce.writeFilePromise(n,s),ce.mktempPromise(async c=>{if(await this.generatePackage(c,e,n,r),!ce.existsSync(J.join(c,"build")))throw new Error("The script should have generated a build directory");return await ps.makeArchiveFromDirectory(J.join(c,"build"),{prefixPath:G.getIdentVendorPath(e),compressionLevel:r.project.configuration.get("compressionLevel")})})})}async generatePackage(e,r,s,a){return await ce.mktempPromise(async n=>{let c=await In.makeScriptEnv({project:a.project,binFolder:n}),f=J.join(e,"runtime.js");return await ce.mktempPromise(async p=>{let h=J.join(p,"buildfile.log"),E=J.join(e,"generator"),C=J.join(e,"build");await ce.mkdirPromise(E),await ce.mkdirPromise(C);let S={tempDir:fe.fromPortablePath(E),buildDir:fe.fromPortablePath(C),locator:G.stringifyLocator(r)};await ce.writeFilePromise(f,`
// Expose 'Module' as a global variable
Object.defineProperty(global, 'Module', {
get: () => require('module'),
configurable: true,
enumerable: false,
});
// Expose non-hidden built-in modules as global variables
for (const name of Module.builtinModules.filter((name) => name !== 'module' && !name.startsWith('_'))) {
Object.defineProperty(global, name, {
get: () => require(name),
configurable: true,
enumerable: false,
});
}
// Expose the 'execEnv' global variable
Object.defineProperty(global, 'execEnv', {
value: {
...${JSON.stringify(S)},
},
enumerable: true,
});
`);let b=c.NODE_OPTIONS||"",I=/\s*--require\s+\S*\.pnp\.c?js\s*/g;b=b.replace(I," ").trim(),c.NODE_OPTIONS=b;let{stdout:T,stderr:N}=a.project.configuration.getSubprocessStreams(h,{header:`# This file contains the result of Yarn generating a package (${G.stringifyLocator(r)})
`,prefix:G.prettyLocator(a.project.configuration,r),report:a.report}),{code:U}=await qr.pipevp(process.execPath,["--require",fe.fromPortablePath(f),fe.fromPortablePath(s),G.stringifyIdent(r)],{cwd:e,env:c,stdin:null,stdout:T,stderr:N});if(U!==0)throw ce.detachTemp(p),new Error(`Package generation failed (exit code ${U}, logs can be found here: ${he.pretty(a.project.configuration,h,he.Type.PATH)})`)})})}};Ge();Ge();var Xct=2,fS=class{supportsDescriptor(e,r){return!!e.range.startsWith(cA)}supportsLocator(e,r){return!!e.reference.startsWith(cA)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,s){return G.bindDescriptor(e,{locator:G.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){if(!s.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let{path:a,parentLocator:n}=N5(e.range);if(n===null)throw new Error("Assertion failed: The descriptor should have been bound");let c=await cS(G.makeRange({protocol:cA,source:a,selector:a,params:{locator:G.stringifyLocator(n)}}),cA,s.fetchOptions),f=Nn.makeHash(`${Xct}`,c).slice(0,6);return[O5(e,{parentLocator:n,path:a,generatorHash:f,protocol:cA})]}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let s=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Ut.find(s.prefixPath,{baseFs:s.packageFs}),s.releaseFs);return{...e,version:a.version||"0.0.0",languageName:a.languageName||r.project.configuration.get("defaultLanguageName"),linkType:"HARD",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var $ct={fetchers:[uS],resolvers:[fS]},eut=$ct;var U5={};Vt(U5,{FileFetcher:()=>gS,FileResolver:()=>dS,TarballFileFetcher:()=>mS,TarballFileResolver:()=>yS,default:()=>nut,fileUtils:()=>xm});Ge();Dt();var tw=/^(?:[a-zA-Z]:[\\/]|\.{0,2}\/)/,AS=/^[^?]*\.(?:tar\.gz|tgz)(?:::.*)?$/,$i="file:";var xm={};Vt(xm,{fetchArchiveFromLocator:()=>hS,makeArchiveFromLocator:()=>lF,makeBufferFromLocator:()=>M5,makeLocator:()=>rw,makeSpec:()=>vEe,parseSpec:()=>pS});Ge();Dt();function pS(t){let{params:e,selector:r}=G.parseRange(t),s=fe.toPortablePath(r);return{parentLocator:e&&typeof e.locator=="string"?G.parseLocator(e.locator):null,path:s}}function vEe({parentLocator:t,path:e,hash:r,protocol:s}){let a=t!==null?{locator:G.stringifyLocator(t)}:{},n=typeof r<"u"?{hash:r}:{};return G.makeRange({protocol:s,source:e,selector:e,params:{...n,...a}})}function rw(t,{parentLocator:e,path:r,hash:s,protocol:a}){return G.makeLocator(t,vEe({parentLocator:e,path:r,hash:s,protocol:a}))}async function hS(t,e){let{parentLocator:r,path:s}=G.parseFileStyleRange(t.reference,{protocol:$i}),a=J.isAbsolute(s)?{packageFs:new Sn(vt.root),prefixPath:vt.dot,localPath:vt.root}:await e.fetcher.fetch(r,e),n=a.localPath?{packageFs:new Sn(vt.root),prefixPath:J.relative(vt.root,a.localPath)}:a;a!==n&&a.releaseFs&&a.releaseFs();let c=n.packageFs,f=J.join(n.prefixPath,s);return await je.releaseAfterUseAsync(async()=>await c.readFilePromise(f),n.releaseFs)}async function lF(t,{protocol:e,fetchOptions:r,inMemory:s=!1}){let{parentLocator:a,path:n}=G.parseFileStyleRange(t.reference,{protocol:e}),c=J.isAbsolute(n)?{packageFs:new Sn(vt.root),prefixPath:vt.dot,localPath:vt.root}:await r.fetcher.fetch(a,r),f=c.localPath?{packageFs:new Sn(vt.root),prefixPath:J.relative(vt.root,c.localPath)}:c;c!==f&&c.releaseFs&&c.releaseFs();let p=f.packageFs,h=J.join(f.prefixPath,n);return await je.releaseAfterUseAsync(async()=>await ps.makeArchiveFromDirectory(h,{baseFs:p,prefixPath:G.getIdentVendorPath(t),compressionLevel:r.project.configuration.get("compressionLevel"),inMemory:s}),f.releaseFs)}async function M5(t,{protocol:e,fetchOptions:r}){return(await lF(t,{protocol:e,fetchOptions:r,inMemory:!0})).getBufferAndClose()}var gS=class{supports(e,r){return!!e.reference.startsWith($i)}getLocalPath(e,r){let{parentLocator:s,path:a}=G.parseFileStyleRange(e.reference,{protocol:$i});if(J.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(s,r);return n===null?null:J.resolve(n,a)}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:c}}async fetchFromDisk(e,r){return lF(e,{protocol:$i,fetchOptions:r})}};Ge();Ge();var tut=2,dS=c Line truncated
`,{automaticNewlines:!0});let h=[p],E=J.join(this.context.cwd,"README.md");if(ce.existsSync(E)||(await ce.writeFilePromise(E,`# ${G.stringifyIdent(n.name)}
`),h.push(E)),!s||s.cwd===this.context.cwd){let C=J.join(this.context.cwd,Er.lockfile);ce.existsSync(C)||(await ce.writeFilePromise(C,""),h.push(C));let b=[".yarn/*","!.yarn/patches","!.yarn/plugins","!.yarn/releases","!.yarn/sdks","!.yarn/versions","","# Whether you use PnP or not, the node_modules folder is often used to store","# build artifacts that should be gitignored","node_modules","","# Swap the comments on the following lines if you wish to use zero-installs","# In that case, don't forget to run `yarn config set enableGlobalCache false`!","# Documentation here: https://yarnpkg.com/features/caching#zero-installs","","#!.yarn/cache",".pnp.*"].map(ue=>`${ue}
`).join(""),I=J.join(this.context.cwd,".gitignore");ce.existsSync(I)||(await ce.writeFilePromise(I,b),h.push(I));let N=["/.yarn/** linguist-vendored","/.yarn/releases/* binary","/.yarn/plugins/**/* binary","/.pnp.* binary linguist-generated"].map(ue=>`${ue}
`).join(""),U=J.join(this.context.cwd,".gitattributes");ce.existsSync(U)||(await ce.writeFilePromise(U,N),h.push(U));let W={"*":{charset:"utf-8",endOfLine:"lf",indentSize:2,indentStyle:"space",insertFinalNewline:!0}};je.mergeIntoTarget(W,r.get("initEditorConfig"));let ee=`root = true
`;for(let[ue,le]of Object.entries(W)){ee+=`
[${ue}]
`;for(let[me,pe]of Object.entries(le)){let Be=me.replace(/[A-Z]/g,Ce=>`_${Ce.toLowerCase()}`);ee+=`${Be} = ${pe}
`}}let ie=J.join(this.context.cwd,".editorconfig");ce.existsSync(ie)||(await ce.writeFilePromise(ie,ee),h.push(ie)),await this.cli.run(["install"],{quiet:!0}),await this.initialize(),ce.existsSync(J.join(this.context.cwd,".git"))||(await qr.execvp("git",["init"],{cwd:this.context.cwd}),await qr.execvp("git",["add","--",...h],{cwd:this.context.cwd}),await qr.execvp("git",["commit","--allow-empty","-m","First commit"],{cwd:this.context.cwd}))}}};var nw=class extends z0{constructor(){super(...arguments);this.initializer=ge.String();this.argv=ge.Proxy()}static{this.paths=[["init"]]}async initialize(){this.context.stdout.write(`
`),await this.cli.run(["dlx",this.initializer,...this.argv],{quiet:!0})}};var lut={configuration:{initScope:{description:"Scope used when creating packages via the init command",type:"STRING",default:null},initFields:{description:"Additional fields to set when creating packages via the init command",type:"MAP",valueDefinition:{description:"",type:"ANY"}},initEditorConfig:{description:"Extra rules to define in the generator editorconfig",type:"MAP",valueDefinition:{description:"",type:"ANY"}}},commands:[z0,nw]},cut=lut;var HW={};Vt(HW,{SearchCommand:()=>Iw,UpgradeInteractiveCommand:()=>Cw,default:()=>ygt});Ge();var xEe=ut(Ie("os"));function iw({stdout:t}){if(xEe.default.endianness()==="BE")throw new Error("Interactive commands cannot be used on big-endian systems because ink depends on yoga-layout-prebuilt which only supports little-endian architectures");if(!t.isTTY)throw new Error("Interactive commands can only be used inside a TTY environment")}Yt();var HIe=ut(l9()),c9={appId:"OFCNCOG2CU",apiKey:"6fe4476ee5a1832882e326b506d14126",indexName:"npm-search"},oAt=(0,HIe.default)(c9.appId,c9.apiKey).initIndex(c9.indexName),u9=async(t,e=0)=>await oAt.search(t,{analyticsTags:["yarn-plugin-interactive-tools"],attributesToRetrieve:["name","version","owner","repository","humanDownloadsLast30Days"],page:e,hitsPerPage:10});var CD=["regular","dev","peer"],Iw=class extends ft{static{this.paths=[["search"]]}static{this.usage=ot.Usage({category:"Interactive commands",description:"open the search interface",details:`
This command opens a fullscreen terminal interface where you can search for and install packages from the npm registry.
`,examples:[["Open the search window","yarn search"]]})}async execute(){iw(this.context);let{Gem:e}=await Promise.resolve().then(()=>(qF(),kW)),{ScrollableItems:r}=await Promise.resolve().then(()=>(JF(),VF)),{useKeypress:s}=await Promise.resolve().then(()=>(yD(),m2e)),{useMinistore:a}=await Promise.resolve().then(()=>(OW(),NW)),{renderForm:n}=await Promise.resolve().then(()=>(XF(),ZF)),{default:c}=await Promise.resolve().then(()=>ut(P2e())),{Box:f,Text:p}=await Promise.resolve().then(()=>ut(Wc())),{default:h,useEffect:E,useState:C}=await Promise.resolve().then(()=>ut(hn())),S=await ze.find(this.context.cwd,this.context.plugins),b=()=>h.createElement(f,{flexDirection:"row"},h.createElement(f,{flexDirection:"column",width:48},h.createElement(f,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"<up>"),"/",h.createElement(p,{bold:!0,color:"cyanBright"},"<down>")," to move between packages.")),h.createElement(f,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"<space>")," to select a package.")),h.createElement(f,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"<space>")," again to change the target."))),h.createElement(f,{flexDirection:"column"},h.createElement(f,{marginLeft:1},h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"<enter>")," to install the selected packages.")),h.createElement(f,{marginLeft:1},h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"<ctrl+c>")," to abort.")))),I=()=>h.createElement(h.Fragment,null,h.createElement(f,{width:15},h.createElement(p,{bold:!0,underline:!0,color:"gray"},"Owner")),h.createElement(f,{width:11},h.createElement(p,{bold:!0,underline:!0,color:"gray"},"Version")),h.createElement(f,{width:10},h.createElement(p,{bold:!0,underline:!0,color:"gray"},"Downloads"))),T=()=>h.createElement(f,{width:17},h.createElement(p,{bold:!0,underline:!0,color:"gray"},"Target")),N=({hit:pe,active:Be})=>{let[Ce,g]=a(pe.name,null);s({active:Be},(Ae,se)=>{if(se.name!=="space")return;if(!Ce){g(CD[0]);return}let X=CD.indexOf(Ce)+1;X===CD.length?g(null):g(CD[X])},[Ce,g]);let we=G.parseIdent(pe.name),ye=G.prettyIdent(S,we);return h.createElement(f,null,h.createElement(f,{width:45},h.createElement(p,{bold:!0,wrap:"wrap"},ye)),h.createElement(f,{width:14,marginLeft:1},h.createElement(p,{bold:!0,wrap:"truncate"},pe.owner.name)),h.createElement(f,{width:10,marginLeft:1},h.createElement(p,{italic:!0,wrap:"truncate"},pe.version)),h.createElement(f,{width:16,marginLeft:1},h.createElement(p,null,pe.humanDownloadsLast30Days)))},U=({name:pe,active:Be})=>{let[Ce]=a(pe,null),g=G.parseIdent(pe);return h.createElement(f,null,h.createElement(f,{width:47},h.createElement(p,{bold:!0}," - ",G.prettyIdent(S,g))),CD.map(we=>h.createElement(f,{key:we,width:14,marginLeft:1},h.createElement(p,null," ",h.createElement(e,{active:Ce===we})," ",h.createElement(p,{bold:!0},we)))))},W=()=>h.createElement(f,{marginTop:1},h.createElement(p,null,"Powered by Algolia.")),ie=await n(({useSubmit:pe})=>{let Be=a();pe(Be);let Ce=Array.from(Be.keys()).filter(j=>Be.get(j)!==null),[g,we]=C(""),[ye,Ae]=C(0),[se,X]=C([]),De=j=>{j.match(/\t| /)||we(j)},Te=async()=>{Ae(0);let j=await u9(g);j.query===g&&X(j.hits)},mt=async()=>{let j=await u9(g,ye+1);j.query===g&&j.page-1===ye&&(Ae(j.page),X([...se,...j.hits]))};return E(()=>{g?Te():X([])},[g]),h.createElement(f,{flexDirection:"column"},h.createElement(b,null),h.createElement(f,{flexDirection:"row",marginTop:1},h.createElement(p,{bold:!0},"Search: "),h.createElement(f,{width:41},h.createElement(c,{value:g,onChange:De,placeholder:"i.e. babel, webpack, react...",showCursor:!1})),h.createElement(I,null)),se.length?h.createElement(r,{radius:2,loop:!1,children:se.map(j=>h.createElement(N,{key:j.name,hit:j,active:!1})),willReachEnd:mt}):h.createElement(p,{color:"gray"},"Start typing..."),h.createElement(f,{flexDirection:"row",marginTop:1},h.createElement(f,{width:49},h.createElement(p,{bold:!0},"Selected:")),h.createElement(T,null)),Ce.length?Ce.map(j=>h.createElement(U,{key:j,name:j,active:!1})):h.createElement(p,{color:"gray"},"No selected packages..."),h.createElement(W,null))},{},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof ie>"u")return 1;let ue=Array.from(ie.keys()).filter(pe=>ie.get(pe)==="regular"),le=Array.from(ie.keys()).filter(pe=>ie.get(pe)==="dev"),me=Array.from(ie.keys()).filter(pe=>ie.get(pe)==="peer");return ue.length&&await this.cli.run(["add",...ue]),le.length&&await this.cli.run(["add","--dev",...le]),me&&await this.cli.run(["add","--peer",...me]),0}};Ge();Yt();GG();var F2e=ut(Ai()),T2e=/^((?:[\^~]|>=?)?)([0-9]+)(\.[0-9]+)(\.[0-9]+)((?:-\S+)?)$/;function N2e(t,e){return t.length>0?[t.slice(0,e)].concat(N2e(t.slice(e),e)):[]}var Cw=class extends ft{static{this.paths=[["upgrade-interactive"]]}static{this.usage=ot.Usage({category:"Interactive commands",description:"open Line truncated
This command opens a fullscreen terminal interface where you can see any out of date packages used by your application, their status compared to the latest versions available on the remote registry, and select packages to upgrade.
`,examples:[["Open the upgrade window","yarn upgrade-interactive"]]})}async execute(){iw(this.context);let{ItemOptions:e}=await Promise.resolve().then(()=>(R2e(),Q2e)),{Pad:r}=await Promise.resolve().then(()=>(_W(),k2e)),{ScrollableItems:s}=await Promise.resolve().then(()=>(JF(),VF)),{useMinistore:a}=await Promise.resolve().then(()=>(OW(),NW)),{renderForm:n}=await Promise.resolve().then(()=>(XF(),ZF)),{Box:c,Text:f}=await Promise.resolve().then(()=>ut(Wc())),{default:p,useEffect:h,useRef:E,useState:C}=await Promise.resolve().then(()=>ut(hn())),S=await ze.find(this.context.cwd,this.context.plugins),{project:b,workspace:I}=await Rt.find(S,this.context.cwd),T=await Kr.find(S);if(!I)throw new ar(b.cwd,this.context.cwd);await b.restoreInstallState({restoreResolutions:!1});let N=this.context.stdout.rows-7,U=(we,ye)=>{let Ae=pde(we,ye),se="";for(let X of Ae)X.added?se+=he.pretty(S,X.value,"green"):X.removed||(se+=X.value);return se},W=(we,ye)=>{if(we===ye)return ye;let Ae=G.parseRange(we),se=G.parseRange(ye),X=Ae.selector.match(T2e),De=se.selector.match(T2e);if(!X||!De)return U(we,ye);let Te=["gray","red","yellow","green","magenta"],mt=null,j="";for(let rt=1;rt<Te.length;++rt)mt!==null||X[rt]!==De[rt]?(mt===null&&(mt=Te[rt-1]),j+=he.pretty(S,De[rt],mt)):j+=De[rt];return j},ee=async(we,ye,Ae)=>{let se=await Zu.fetchDescriptorFrom(we,Ae,{project:b,cache:T,preserveModifier:ye,workspace:I});return se!==null?se.range:we.range},ie=async we=>{let ye=F2e.default.valid(we.range)?`^${we.range}`:we.range,[Ae,se]=await Promise.all([ee(we,we.range,ye).catch(()=>null),ee(we,we.range,"latest").catch(()=>null)]),X=[{value:null,label:we.range}];return Ae&&Ae!==we.range?X.push({value:Ae,label:W(we.range,Ae)}):X.push({value:null,label:""}),se&&se!==Ae&&se!==we.range?X.push({value:se,label:W(we.range,se)}):X.push({value:null,label:""}),X},ue=()=>p.createElement(c,{flexDirection:"row"},p.createElement(c,{flexDirection:"column",width:49},p.createElement(c,{marginLeft:1},p.createElement(f,null,"Press ",p.createElement(f,{bold:!0,color:"cyanBright"},"<up>"),"/",p.createElement(f,{bold:!0,color:"cyanBright"},"<down>")," to select packages.")),p.createElement(c,{marginLeft:1},p.createElement(f,null,"Press ",p.createElement(f,{bold:!0,color:"cyanBright"},"<left>"),"/",p.createElement(f,{bold:!0,color:"cyanBright"},"<right>")," to select versions."))),p.createElement(c,{flexDirection:"column"},p.createElement(c,{marginLeft:1},p.createElement(f,null,"Press ",p.createElement(f,{bold:!0,color:"cyanBright"},"<enter>")," to install.")),p.createElement(c,{marginLeft:1},p.createElement(f,null,"Press ",p.createElement(f,{bold:!0,color:"cyanBright"},"<ctrl+c>")," to abort.")))),le=()=>p.createElement(c,{flexDirection:"row",paddingTop:1,paddingBottom:1},p.createElement(c,{width:50},p.createElement(f,{bold:!0},p.createElement(f,{color:"greenBright"},"?")," Pick the packages you want to upgrade.")),p.createElement(c,{width:17},p.createElement(f,{bold:!0,underline:!0,color:"gray"},"Current")),p.createElement(c,{width:17},p.createElement(f,{bold:!0,underline:!0,color:"gray"},"Range")),p.createElement(c,{width:17},p.createElement(f,{bold:!0,underline:!0,color:"gray"},"Latest"))),me=({active:we,descriptor:ye,suggestions:Ae})=>{let[se,X]=a(ye.descriptorHash,null),De=G.stringifyIdent(ye),Te=Math.max(0,45-De.length);return p.createElement(p.Fragment,null,p.createElement(c,null,p.createElement(c,{width:45},p.createElement(f,{bold:!0},G.prettyIdent(S,ye)),p.createElement(r,{active:we,length:Te})),p.createElement(e,{active:we,options:Ae,value:se,skewer:!0,onChange:X,sizes:[17,17,17]})))},pe=({dependencies:we})=>{let[ye,Ae]=C(we.map(()=>null)),se=E(!0),X=async De=>{let Te=await ie(De);return Te.filter(mt=>mt.label!=="").length<=1?null:{descriptor:De,suggestions:Te}};return h(()=>()=>{se.current=!1},[]),h(()=>{let De=Math.trunc(N*1.75),Te=we.slice(0,De),mt=we.slice(De),j=N2e(mt,N),rt=Te.map(X).reduce(async(Fe,Ne)=>{await Fe;let be=await Ne;be!==null&&se.current&&Ae(Ve=>{let ke=Ve.findIndex(Ue=>Ue===null),it=[...Ve];return it[ke]=be,it})},Promise.resolve());j.reduce((Fe,Ne)=>Promise.all(Ne.map(be=>Promise.resolve().then(()=>X(be)))).then(async be=>{be=be.filter(Ve=>Ve!==null),await Fe,se.current&&Ae(Ve=>{let ke=Ve.findIndex(it=>it===null);return Ve.slice(0,ke).concat(be).concat(Ve.slice(ke+be.length))})}),rt).then(()=>{se.current&&Ae(Fe=>Fe.filter(Ne=>Ne!==null))})},[]),ye.length?p.createElement(s,{radius:N>>1,children:ye.map((De,Te)=>De!==null?p.createElement(me,{key:Te,active:!1,descriptor:De.descriptor,suggestions:De.suggestions}):p.createElement(f,{key:Te},"Loading..."))}):p.createElement(f,null,"No upgrades found")},Ce=await n(({useSubmit:we})=>{we(a());let ye=new Map;for(let se of b.workspaces)for(let X of["dependencies","devDependencies"])for(let De of se.manifest[X].values())b.tryWorkspaceByDescriptor(De)===null&&(De.range.startsWith("link:")||ye.set(De.descriptorHash,De));let Ae=je.sortMap(ye.values(),se=>G.stringifyDescriptor(se));return p.createEleme Line truncated
${E}, next tree:
${bD(f)}`);let S=U2e(f);if(S)throw new Error(`${S}, after hoisting finished:
${bD(f)}`)}return n.debugLevel>=2&&console.log(bD(f)),Rgt(f)},Sgt=t=>{let e=t[t.length-1],r=new Map,s=new Set,a=n=>{if(!s.has(n)){s.add(n);for(let c of n.hoistedDependencies.values())r.set(c.name,c);for(let c of n.dependencies.values())n.peerNames.has(c.name)||a(c)}};return a(e),r},Dgt=t=>{let e=t[t.length-1],r=new Map,s=new Set,a=new Set,n=(c,f)=>{if(s.has(c))return;s.add(c);for(let h of c.hoistedDependencies.values())if(!f.has(h.name)){let E;for(let C of t)E=C.dependencies.get(h.name),E&&r.set(E.name,E)}let p=new Set;for(let h of c.dependencies.values())p.add(h.name);for(let h of c.dependencies.values())c.peerNames.has(h.name)||n(h,p)};return n(e,a),r},L2e=(t,e)=>{if(e.decoupled)return e;let{name:r,references:s,ident:a,locator:n,dependencies:c,originalDependencies:f,hoistedDependencies:p,peerNames:h,reasons:E,isHoistBorder:C,hoistPriority:S,dependencyKind:b,hoistedFrom:I,hoistedTo:T}=e,N={name:r,references:new Set(s),ident:a,locator:n,dependencies:new Map(c),originalDependencies:new Map(f),hoistedDependencies:new Map(p),peerNames:new Set(h),reasons:new Map(E),decoupled:!0,isHoistBorder:C,hoistPriority:S,dependencyKind:b,hoistedFrom:new Map(I),hoistedTo:new Map(T)},U=N.dependencies.get(r);return U&&U.ident==N.ident&&N.dependencies.set(r,N),t.dependencies.set(N.name,N),N},Pgt=(t,e)=>{let r=new Map([[t.name,[t.ident]]]);for(let a of t.dependencies.values())t.peerNames.has(a.name)||r.set(a.name,[a.ident]);let s=Array.from(e.keys());s.sort((a,n)=>{let c=e.get(a),f=e.get(n);if(f.hoistPriority!==c.hoistPriority)return f.hoistPriority-c.hoistPriority;{let p=c.dependents.size+c.peerDependents.size;return f.dependents.size+f.peerDependents.size-p}});for(let a of s){let n=a.substring(0,a.indexOf("@",1)),c=a.substring(n.length+1);if(!t.peerNames.has(n)){let f=r.get(n);f||(f=[],r.set(n,f)),f.indexOf(c)<0&&f.push(c)}}return r},WW=t=>{let e=new Set,r=(s,a=new Set)=>{if(!a.has(s)){a.add(s);for(let n of s.peerNames)if(!t.peerNames.has(n)){let c=t.dependencies.get(n);c&&!e.has(c)&&r(c,a)}e.add(s)}};for(let s of t.dependencies.values())t.peerNames.has(s.name)||r(s);return e},VW=(t,e,r,s,a,n=new Set)=>{let c=e[e.length-1];if(n.has(c))return{anotherRoundNeeded:!1,isGraphChanged:!1};n.add(c);let f=Tgt(c),p=Pgt(c,f),h=t==c?new Map:a.fastLookupPossible?Sgt(e):Dgt(e),E,C=!1,S=!1,b=new Map(Array.from(p.entries()).map(([T,N])=>[T,N[0]])),I=new Map;do{let T=kgt(t,e,r,h,b,p,s,I,a);T.isGraphChanged&&(S=!0),T.anotherRoundNeeded&&(C=!0),E=!1;for(let[N,U]of p)U.length>1&&!c.dependencies.has(N)&&(b.delete(N),U.shift(),b.set(N,U[0]),E=!0)}while(E);for(let T of c.dependencies.values())if(!c.peerNames.has(T.name)&&!r.has(T.locator)){r.add(T.locator);let N=VW(t,[...e,T],r,I,a);N.isGraphChanged&&(S=!0),N.anotherRoundNeeded&&(C=!0),r.delete(T.locator)}return{anotherRoundNeeded:C,isGraphChanged:S}},bgt=t=>{for(let[e,r]of t.dependencies)if(!t.peerNames.has(e)&&r.ident!==t.ident)return!0;return!1},xgt=(t,e,r,s,a,n,c,f,{outputReason:p,fastLookupPossible:h})=>{let E,C=null,S=new Set;p&&(E=`${Array.from(e).map(N=>yo(N)).join("\u2192")}`);let b=r[r.length-1],T=!(s.ident===b.ident);if(p&&!T&&(C="- self-reference"),T&&(T=s.dependencyKind!==1,p&&!T&&(C="- workspace")),T&&s.dependencyKind===2&&(T=!bgt(s),p&&!T&&(C="- external soft link with unhoisted dependencies")),T&&(T=!t.peerNames.has(s.name),p&&!T&&(C=`- cannot shadow peer: ${yo(t.originalDependencies.get(s.name).locator)} at ${E}`)),T){let N=!1,U=a.get(s.name);if(N=!U||U.ident===s.ident,p&&!N&&(C=`- filled by: ${yo(U.locator)} at ${E}`),N)for(let W=r.length-1;W>=1;W--){let ie=r[W].dependencies.get(s.name);if(ie&&ie.ident!==s.ident){N=!1;let ue=f.get(b);ue||(ue=new Set,f.set(b,ue)),ue.add(s.name),p&&(C=`- filled by ${yo(ie.locator)} at ${r.slice(0,W).map(le=>yo(le.locator)).join("\u2192")}`);break}}T=N}if(T&&(T=n.get(s.name)===s.ident,p&&!T&&(C=`- filled by: ${yo(c.get(s.name)[0])} at ${E}`)),T){let N=!0,U=new Set(s.peerNames);for(let W=r.length-1;W>=1;W--){let ee=r[W];for(let ie of U){if(ee.peerNames.has(ie)&&ee.originalDependencies.has(ie))continue;let ue=ee.dependencies.get(ie);ue&&t.dependencies.get(ie)!==ue&&(W===r.length-1?S.add(ue):(S=null,N=!1,p&&(C=`- peer dependency ${yo(ue.locator)} from parent ${yo(ee.locator)} was not hoisted to ${E}`))),U.delete(ie)}if(!N)break}T=N}if(T&&!h)for(let N of s.hoistedDependencies.values()){let U=a.get(N.name)||t.dependencies.get(N.name);if(!U||N.ident!==U.ident){T=!1,p&&(C=`- previously hoisted dependency mismatch, needed: ${yo(N.locator)}, available: ${yo(U?.locator)}`);break}}return S!==null&&S.size>0?{isHoistable:2,dependsOn:S,reason:C}:{isHoistable:T?0:1,reason:C}},tN=t=>`${t.name}@${t.locator}`,kgt=(t,e,r,s,a,n,c,f,p)=>{let h=e[e.length-1],E=new Set,C=!1,S=!1,b=(U,W,ee,ie,ue)=>{if(E.has(ie))return;let le=[...W,tN(ie)],me=[...ee,tN(ie)],pe=new Map,Be=new Map;for(let Ae of WW(ie)){let se=xgt(h,r,[h,...U,ie],Ae,s,a,n,f,{outputReason:p.debugLevel>=2,fastLookupPossible:p.fastLookupPossible});if(Be.set(Ae,se),se.isHoistable===2)for(let X of se.dependsOn){let Line truncated
${bD(t)}`)}let ye=WW(ie);for(let Ae of ye)if(Ce.has(Ae)){let se=Be.get(Ae);if((a.get(Ae.name)===Ae.ident||!ie.reasons.has(Ae.name))&&se.isHoistable!==0&&ie.reasons.set(Ae.name,se.reason),!Ae.isHoistBorder&&me.indexOf(tN(Ae))<0){E.add(ie);let De=L2e(ie,Ae);b([...U,ie],le,me,De,T),E.delete(ie)}}},I,T=new Set(WW(h)),N=Array.from(e).map(U=>tN(U));do{I=T,T=new Set;for(let U of I){if(U.locator===h.locator||U.isHoistBorder)continue;let W=L2e(h,U);b([],Array.from(r),N,W,T)}}while(T.size>0);return{anotherRoundNeeded:C,isGraphChanged:S}},U2e=t=>{let e=[],r=new Set,s=new Set,a=(n,c,f)=>{if(r.has(n)||(r.add(n),s.has(n)))return;let p=new Map(c);for(let h of n.dependencies.values())n.peerNames.has(h.name)||p.set(h.name,h);for(let h of n.originalDependencies.values()){let E=p.get(h.name),C=()=>`${Array.from(s).concat([n]).map(S=>yo(S.locator)).join("\u2192")}`;if(n.peerNames.has(h.name)){let S=c.get(h.name);(S!==E||!S||S.ident!==h.ident)&&e.push(`${C()} - broken peer promise: expected ${h.ident} but found ${S&&S.ident}`)}else{let S=f.hoistedFrom.get(n.name),b=n.hoistedTo.get(h.name),I=`${S?` hoisted from ${S.join(", ")}`:""}`,T=`${b?` hoisted to ${b}`:""}`,N=`${C()}${I}`;E?E.ident!==h.ident&&e.push(`${N} - broken require promise for ${h.name}${T}: expected ${h.ident}, but found: ${E.ident}`):e.push(`${N} - broken require promise: no required dependency ${h.name}${T} found`)}}s.add(n);for(let h of n.dependencies.values())n.peerNames.has(h.name)||a(h,p,n);s.delete(n)};return a(t,t.dependencies,t),e.join(`
`)},Qgt=(t,e)=>{let{identName:r,name:s,reference:a,peerNames:n}=t,c={name:s,references:new Set([a]),locator:YW(r,a),ident:O2e(r,a),dependencies:new Map,originalDependencies:new Map,hoistedDependencies:new Map,peerNames:new Set(n),reasons:new Map,decoupled:!0,isHoistBorder:!0,hoistPriority:0,dependencyKind:1,hoistedFrom:new Map,hoistedTo:new Map},f=new Map([[t,c]]),p=(h,E)=>{let C=f.get(h),S=!!C;if(!C){let{name:b,identName:I,reference:T,peerNames:N,hoistPriority:U,dependencyKind:W}=h,ee=e.hoistingLimits.get(E.locator);C={name:b,references:new Set([T]),locator:YW(I,T),ident:O2e(I,T),dependencies:new Map,originalDependencies:new Map,hoistedDependencies:new Map,peerNames:new Set(N),reasons:new Map,decoupled:!0,isHoistBorder:ee?ee.has(b):!1,hoistPriority:U||0,dependencyKind:W||0,hoistedFrom:new Map,hoistedTo:new Map},f.set(h,C)}if(E.dependencies.set(h.name,C),E.originalDependencies.set(h.name,C),S){let b=new Set,I=T=>{if(!b.has(T)){b.add(T),T.decoupled=!1;for(let N of T.dependencies.values())T.peerNames.has(N.name)||I(N)}};I(C)}else for(let b of h.dependencies)p(b,C)};for(let h of t.dependencies)p(h,c);return c},JW=t=>t.substring(0,t.indexOf("@",1)),Rgt=t=>{let e={name:t.name,identName:JW(t.locator),references:new Set(t.references),dependencies:new Set},r=new Set([t]),s=(a,n,c)=>{let f=r.has(a),p;if(n===a)p=c;else{let{name:h,references:E,locator:C}=a;p={name:h,identName:JW(C),references:E,dependencies:new Set}}if(c.dependencies.add(p),!f){r.add(a);for(let h of a.dependencies.values())a.peerNames.has(h.name)||s(h,a,p);r.delete(a)}};for(let a of t.dependencies.values())s(a,t,e);return e},Tgt=t=>{let e=new Map,r=new Set([t]),s=c=>`${c.name}@${c.ident}`,a=c=>{let f=s(c),p=e.get(f);return p||(p={dependents:new Set,peerDependents:new Set,hoistPriority:0},e.set(f,p)),p},n=(c,f)=>{let p=!!r.has(f);if(a(f).dependents.add(c.ident),!p){r.add(f);for(let E of f.dependencies.values()){let C=a(E);C.hoistPriority=Math.max(C.hoistPriority,E.hoistPriority),f.peerNames.has(E.name)?C.peerDependents.add(f.ident):n(f,E)}}};for(let c of t.dependencies.values())t.peerNames.has(c.name)||n(t,c);return e},yo=t=>{if(!t)return"none";let e=t.indexOf("@",1),r=t.substring(0,e);r.endsWith("$wsroot$")&&(r=`wh:${r.replace("$wsroot$","")}`);let s=t.substring(e+1);if(s==="workspace:.")return".";if(s){let a=(s.indexOf("#")>0?s.split("#")[1]:s).replace("npm:","");return s.startsWith("virtual")&&(r=`v:${r}`),a.startsWith("workspace")&&(r=`w:${r}`,a=""),`${r}${a?`@${a}`:""}`}else return`${r}`};var bD=t=>{let e=0,r=(a,n,c="")=>{if(e>5e4||n.has(a))return"";e++;let f=Array.from(a.dependencies.values()).sort((h,E)=>h.name===E.name?0:h.name>E.name?1:-1),p="";n.add(a);for(let h=0;h<f.length;h++){let E=f[h];if(!a.peerNames.has(E.name)&&E!==a){let C=a.reasons.get(E.name),S=JW(E.locator);p+=`${c}${h<f.length-1?"\u251C\u2500":"\u2514\u2500"}${(n.has(E)?">":"")+(S!==E.name?`a:${E.name}:`:"")+yo(E.locator)+(C?` ${C}`:"")}
`,p+=r(E,n,`${c}${h<f.length-1?"\u2502 ":" "}`)}}return n.delete(a),p};return r(t,new Set)+(e>5e4?`
Tree is too large, part of the tree has been dunped
`:"")};var xD=(s=>(s.WORKSPACES="workspaces",s.DEPENDENCIES="dependencies",s.NONE="none",s))(xD||{}),_2e="node_modules",rg="$wsroot$";var kD=(t,e)=>{let{packageTree:r,hoistingLimits:s,errors:a,preserveSymlinksRequired:n}=Ngt(t,e),c=null;if(a.length===0){let f=M2e(r,{hoistingLimits:s});c=Lgt(t,f,e)}return{tree:c,errors:a,preserveSymlinksRequired:n}},pA=t=>`${t.name}@${t.reference}`,zW=t=>{let e=new Map;for(let[r,s]of t.entries())if(!s.dirList){let a=e.get(s.locator);a||(a={target:s.target,linkType:s.linkType,locations:[],aliases:s.aliases},e.set(s.locator,a)),a.locations.push(r)}for(let r of e.values())r.locations=r.locations.sort((s,a)=>{let n=s.split(J.delimiter).length,c=a.split(J.delimiter).length;return a===s?0:n!==c?c-n:a>s?1:-1});return e},H2e=(t,e)=>{let r=G.isVirtualLocator(t)?G.devirtualizeLocator(t):t,s=G.isVirtualLocator(e)?G.devirtualizeLocator(e):e;return G.areLocatorsEqual(r,s)},KW=(t,e,r,s)=>{if(t.linkType!=="SOFT")return!1;let a=fe.toPortablePath(r.resolveVirtual&&e.reference&&e.reference.startsWith("virtual:")?r.resolveVirtual(t.packageLocation):t.packageLocation);return J.contains(s,a)===null},Fgt=t=>{let e=t.getPackageInformation(t.topLevel);if(e===null)throw new Error("Assertion failed: Expected the top-level package to have been registered");if(t.findPackageLocator(e.packageLocation)===null)throw new Error("Assertion failed: Expected the top-level package to have a physical locator");let s=fe.toPortablePath(e.packageLocation.slice(0,-1)),a=new Map,n={children:new Map},c=t.getDependencyTreeRoots(),f=new Map,p=new Set,h=(S,b)=>{let I=pA(S);if(p.has(I))return;p.add(I);let T=t.getPackageInformation(S);if(T){let N=b?pA(b):"";if(pA(S)!==N&&T.linkType==="SOFT"&&!S.reference.startsWith("link:")&&!KW(T,S,t,s)){let U=j2e(T,S,t);(!f.get(U)||S.reference.startsWith("workspace:"))&&f.set(U,S)}for(let[U,W]of T.packageDependencies)W!==null&&(T.packagePeers.has(U)||h(t.getLocator(U,W),S))}};for(let S of c)h(S,null);let E=s.split(J.sep);for(let S of f.values()){let b=t.getPackageInformation(S),T=fe.toPortablePath(b.packageLocation.slice(0,-1)).split(J.sep).slice(E.length),N=n;for(let U of T){let W=N.children.get(U);W||(W={children:new Map},N.children.set(U,W)),N=W}N.workspaceLocator=S}let C=(S,b)=>{if(S.workspaceLocator){let I=pA(b),T=a.get(I);T||(T=new Set,a.set(I,T)),T.add(S.workspaceLocator)}for(let I of S.children.values())C(I,S.workspaceLocator||b)};for(let S of n.children.values())C(S,n.workspaceLocator);return a},Ngt=(t,e)=>{let r=[],s=!1,a=new Map,n=Fgt(t),c=t.getPackageInformation(t.topLevel);if(c===null)throw new Error("Assertion failed: Expected the top-level package to have been registered");let f=t.findPackageLocator(c.packageLocation);if(f===null)throw new Error("Assertion failed: Expected the top-level package to have a physical locator");let p=fe.toPortablePath(c.packageLocation.slice(0,-1)),h={name:f.name,identName:f.name,reference:f.reference,peerNames:c.packagePeers,dependencies:new Set,dependencyKind:1},E=new Map,C=(b,I)=>`${pA(I)}:${b}`,S=(b,I,T,N,U,W,ee,ie)=>{let ue=C(b,T),le=E.get(ue),me=!!le;!me&&T.name===f.name&&T.reference===f.reference&&(le=h,E.set(ue,h));let pe=KW(I,T,t,p);if(!le){let Ae=0;pe?Ae=2:I.linkType==="SOFT"&&T.name.endsWith(rg)&&(Ae=1),le={name:b,identName:T.name,reference:T.reference,dependencies:new Set,peerNames:Ae===1?new Set:I.packagePeers,dependencyKind:Ae},E.set(ue,le)}let Be;if(pe?Be=2:U.linkType==="SOFT"?Be=1:Be=0,le.hoistPriority=Math.max(le.hoistPriority||0,Be),ie&&!pe){let Ae=pA({name:N.identName,reference:N.reference}),se=a.get(Ae)||new Set;a.set(Ae,se),se.add(le.name)}let Ce=new Map(I.packageDependencies);if(e.project){let Ae=e.project.workspacesByCwd.get(fe.toPortablePath(I.packageLocation.slice(0,-1)));if(Ae){let se=new Set([...Array.from(Ae.manifest.peerDependencies.values(),X=>G.stringifyIdent(X)),...Array.from(Ae.manifest.peerDependenciesMeta.keys())]);for(let X of se)Ce.has(X)||(Ce.set(X,W.get(X)||null),le.peerNames.add(X))}}let g=pA({name:T.name.replace(rg,""),reference:T.reference}),we=n.get(g);if(we)for(let Ae of we)Ce.set(`${Ae.name}${rg}`,Ae.reference);(I!==U||I.linkType!=="SOFT"||!pe&&(!e.selfReferencesByCwd||e.selfReferencesByCwd.get(ee)))&&N.dependencies.add(le);let ye=T!==f&&I.linkType==="SOFT"&&!T.name.endsWith(rg)&&!pe;if(!me&&!ye){let Ae=new Map;for(let[se,X]of Ce)if(X!==null){let De=t.getLocator(se,X),Te=t.getLocator(se.replace(rg,""),X),mt=t.getPackageInformation(Te);if(mt===null)throw new Error("Assertion failed: Expected the package to have been registered");let j=KW(mt,De,t,p);if(e.validateExternalSoftLinks&&e.project&&j){mt.packageDependencies.size>0&&(s=!0);for(let[Ve,ke]of mt.packageDependencies)if(ke!==null){let it=G.parseLocator(Array.isArray(ke)?`${ke[0]}@${ke[1]}`:`${Ve}@${ke}`);if(pA(it)!==pA(De)){let Ue=Ce.get(Ve);if(Ue){let x=G.parseLocator(Array.isArray(Ue)?`${Ue[0]}@${Ue[1]}`:`${Ve}@${Ue}`);H2e(x,it)||r.push({messageName:71,text:`Cannot link ${G.prettyIdent(e.project.configuration,G.parseIdent(De.name))} into ${G.pretLine truncated
`;for(let n=0,c=t.length;n<c;++n)a+=s+rN(String(n),t[n],e,s).replace(/^ +/,""),n+1<c&&(a+=","),a+=`
`;return a+=r,a+="]",a}function _gt(t,e,r){let s=Object.keys(t),a="";a+="{";for(let n=0,c=s.length,f=0;n<c;++n){let p=s[n],h=t[p];typeof h>"u"||(f!==0&&(a+=", "),a+=JSON.stringify(p),a+=": ",a+=rN(p,h,e,r).replace(/^ +/g,""),f+=1)}return a+="}",a}function Hgt(t,e,r){let s=Object.keys(t),a=`${r} `,n="";n+=r,n+=`{
`;let c=0;for(let f=0,p=s.length;f<p;++f){let h=s[f],E=t[h];typeof E>"u"||(c!==0&&(n+=",",n+=`
`),n+=a,n+=JSON.stringify(h),n+=": ",n+=rN(h,E,e,a).replace(/^ +/g,""),c+=1)}return c!==0&&(n+=`
`),n+=r,n+="}",n}function rN(t,e,r,s){let{next:a}=G2e[r],n=a[t]||a["*"];return q2e(e,n,s)}function q2e(t,e,r){let{collapsed:s}=G2e[e];return Array.isArray(t)?s?Mgt(t,e,r):Ugt(t,e,r):typeof t=="object"&&t!==null?s?_gt(t,e,r):Hgt(t,e,r):JSON.stringify(t)}function W2e(t){return q2e(t,"TOP_LEVEL","")}function QD(t,e){let r=Array.from(t);Array.isArray(e)||(e=[e]);let s=[];for(let n of e)s.push(r.map(c=>n(c)));let a=r.map((n,c)=>c);return a.sort((n,c)=>{for(let f of s){let p=f[n]<f[c]?-1:f[n]>f[c]?1:0;if(p!==0)return p}return 0}),a.map(n=>r[n])}function jgt(t){let e=new Map,r=QD(t.fallbackExclusionList||[],[({name:s,reference:a})=>s,({name:s,reference:a})=>a]);for(let{name:s,reference:a}of r){let n=e.get(s);typeof n>"u"&&e.set(s,n=new Set),n.add(a)}return Array.from(e).map(([s,a])=>[s,Array.from(a)])}function Ggt(t){return QD(t.fallbackPool||[],([e])=>e)}function qgt(t){let e=[],r=t.dependencyTreeRoots.find(s=>t.packageRegistry.get(s.name)?.get(s.reference)?.packageLocation==="./");for(let[s,a]of QD(t.packageRegistry,([n])=>n===null?"0":`1${n}`)){if(s===null)continue;let n=[];e.push([s,n]);for(let[c,{packageLocation:f,packageDependencies:p,packagePeers:h,linkType:E,discardFromLookup:C}]of QD(a,([S])=>S===null?"0":`1${S}`)){if(c===null)continue;let S=[];s!==null&&c!==null&&!p.has(s)&&S.push([s,c]);for(let[U,W]of p)S.push([U,W]);let b=QD(S,([U])=>U),I=h&&h.size>0?Array.from(h):void 0,N={packageLocation:f,packageDependencies:b,packagePeers:I,linkType:E,discardFromLookup:C||void 0};n.push([c,N]),r&&s===r.name&&c===r.reference&&e.unshift([null,[[null,N]]])}}return e}function RD(t){return{__info:["This file is automatically generated. Do not touch it, or risk","your modifications being lost."],dependencyTreeRoots:t.dependencyTreeRoots,enableTopLevelFallback:t.enableTopLevelFallback||!1,ignorePatternData:t.ignorePattern||null,pnpZipBackend:t.pnpZipBackend,fallbackExclusionList:jgt(t),fallbackPool:Ggt(t),packageRegistryData:qgt(t)}}var J2e=ut(V2e());function K2e(t,e){return[t?`${t}
`:"",`/* eslint-disable */
`,`// @ts-nocheck
`,`"use strict";
`,`
`,e,`
`,(0,J2e.default)()].join("")}function Wgt(t){return JSON.stringify(t,null,2)}function Ygt(t){return`'${t.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/\n/g,`\\
`)}'`}function Vgt(t){return[`const RAW_RUNTIME_STATE =
`,`${Ygt(W2e(t))};
`,`function $$SETUP_STATE(hydrateRuntimeState, basePath) {
`,` return hydrateRuntimeState(JSON.parse(RAW_RUNTIME_STATE), {basePath: basePath || __dirname});
`,`}
`].join("")}function Jgt(){return[`function $$SETUP_STATE(hydrateRuntimeState, basePath) {
`,` const fs = require('fs');
`,` const path = require('path');
`,` const pnpDataFilepath = path.resolve(__dirname, ${JSON.stringify(Er.pnpData)});
`,` return hydrateRuntimeState(JSON.parse(fs.readFileSync(pnpDataFilepath, 'utf8')), {basePath: basePath || __dirname});
`,`}
`].join("")}function z2e(t){let e=RD(t),r=Vgt(e);return K2e(t.shebang,r)}function Z2e(t){let e=RD(t),r=Jgt(),s=K2e(t.shebang,r);return{dataFile:Wgt(e),loaderFile:s}}Dt();function XW(t,{basePath:e}){let r=fe.toPortablePath(e),s=J.resolve(r),a=t.ignorePatternData!==null?new RegExp(t.ignorePatternData):null,n=new Map,c=new Map(t.packageRegistryData.map(([C,S])=>[C,new Map(S.map(([b,I])=>{if(C===null!=(b===null))throw new Error("Assertion failed: The name and reference should be null, or neither should");let T=I.discardFromLookup??!1,N={name:C,reference:b},U=n.get(I.packageLocation);U?(U.discardFromLookup=U.discardFromLookup&&T,T||(U.locator=N)):n.set(I.packageLocation,{locator:N,discardFromLookup:T});let W=null;return[b,{packageDependencies:new Map(I.packageDependencies),packagePeers:new Set(I.packagePeers),linkType:I.linkType,discardFromLookup:T,get packageLocation(){return W||(W=J.join(s,I.packageLocation))}}]}))])),f=new Map(t.fallbackExclusionList.map(([C,S])=>[C,new Set(S)])),p=new Map(t.fallbackPool),h=t.dependencyTreeRoots,E=t.enableTopLevelFallback;return{basePath:r,dependencyTreeRoots:h,enableTopLevelFallback:E,fallbackExclusionList:f,pnpZipBackend:t.pnpZipBackend,fallbackPool:p,ignorePattern:a,packageLocatorsByLocations:n,packageRegistry:c}}Dt();Dt();var sh=Ie("module"),jm=Ie("url"),lY=Ie("util");var ta=Ie("url");var tBe=ut(Ie("assert"));var $W=Array.isArray,TD=JSON.stringify,FD=Object.getOwnPropertyNames,Hm=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),eY=(t,e)=>RegExp.prototype.exec.call(t,e),tY=(t,...e)=>RegExp.prototype[Symbol.replace].apply(t,e),ng=(t,...e)=>String.prototype.endsWith.apply(t,e),rY=(t,...e)=>String.prototype.includes.apply(t,e),nY=(t,...e)=>String.prototype.lastIndexOf.apply(t,e),ND=(t,...e)=>String.prototype.indexOf.apply(t,e),X2e=(t,...e)=>String.prototype.replace.apply(t,e),ig=(t,...e)=>String.prototype.slice.apply(t,e),hA=(t,...e)=>String.prototype.startsWith.apply(t,e),$2e=Map,eBe=JSON.parse;function OD(t,e,r){return class extends r{constructor(...s){super(e(...s)),this.code=t,this.name=`${r.name} [${t}]`}}}var rBe=OD("ERR_PACKAGE_IMPORT_NOT_DEFINED",(t,e,r)=>`Package import specifier "${t}" is not defined${e?` in package ${e}package.json`:""} imported from ${r}`,TypeError),iY=OD("ERR_INVALID_MODULE_SPECIFIER",(t,e,r=void 0)=>`Invalid module "${t}" ${e}${r?` imported from ${r}`:""}`,TypeError),nBe=OD("ERR_INVALID_PACKAGE_TARGET",(t,e,r,s=!1,a=void 0)=>{let n=typeof r=="string"&&!s&&r.length&&!hA(r,"./");return e==="."?((0,tBe.default)(s===!1),`Invalid "exports" main target ${TD(r)} defined in the package config ${t}package.json${a?` imported from ${a}`:""}${n?'; targets must start with "./"':""}`):`Invalid "${s?"imports":"exports"}" target ${TD(r)} defined for '${e}' in the package config ${t}package.json${a?` imported from ${a}`:""}${n?'; targets must start with "./"':""}`},Error),LD=OD("ERR_INVALID_PACKAGE_CONFIG",(t,e,r)=>`Invalid package config ${t}${e?` while importing ${e}`:""}${r?`. ${r}`:""}`,Error),iBe=OD("ERR_PACKAGE_PATH_NOT_EXPORTED",(t,e,r=void 0)=>e==="."?`No "exports" main defined in ${t}package.json${r?` imported from ${r}`:""}`:`Package subpath '${e}' is not defined by "exports" in ${t}package.json${r?` imported from ${r}`:""}`,Error);var iN=Ie("url");function sBe(t,e){let r=Object.create(null);for(let s=0;s<e.length;s++){let a=e[s];Hm(t,a)&&(r[a]=t[a])}return r}var nN=new $2e;function Kgt(t,e,r,s){let a=nN.get(t);if(a!==void 0)return a;let n=s(t);if(n===void 0){let b={pjsonPath:t,exists:!1,main:void 0,name:void 0,type:"none",exports:void 0,imports:void 0};return nN.set(t,b),b}let c;try{c=eBe(n)}catch(b){throw new LD(t,(r?`"${e}" from `:"")+(0,iN.fileURLToPath)(r||e),b.message)}let{imports:f,main:p,name:h,type:E}=sBe(c,["imports","main","name","type"]),C=Hm(c,"exports")?c.exports:void 0;(typeof f!="object"||f===null)&&(f=void 0),typeof p!="string"&&(p=void 0),typeof h!="string"&&(h=void 0),E!=="module"&&E!=="commonjs"&&(E="none");let S={pjsonPath:t,exists:!0,main:p,name:h,type:E,exports:C,imports:f};return nN.set(t,S),S}function oBe(t,e){let r=new URL("./package.json",t);for(;;){let n=r.pathname;if(ng(n,"node_modules/package.json"))break;let c=Kgt((0,iN.fileURLToPath)(r),t,void 0,e);if(c.exists)return c;let f=r;if(r=new URL("../package.json",r),r.pathname===f.pathname)break}let s=(0,iN.fileURLToPath)(r),a={pjsonPath:s,exists:!1,main:void 0,name:void 0,type:"none",exports:void 0,imports:void 0};return nN.set(s,a),a}function zgt(t,e,r){throw new rBe(t,e&&(0,ta.fileURLToPath)(new URL(".",e)),(0,ta.fileURLToPath)(r))}function Zgt(t,e,r,s){let a=`request is not a valid subpath for the "${r?"imports":"exports"}" resolution of ${(0,ta.fileURLToPath)(e)}`;throw new iY(t,a,s&&(0,ta.fileURLToPath)(s))}function MD(t,e,r,s,a){throw typeof e=="object"&&e!==null?e=TD(e,null,""):e=`${e}`,new nBe((0,ta.fileURLToPath)(new URL(".",r)),t,e,s,a&&(0,ta.fileURLToPath)(a))}var aBe=/(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f Line truncated
`),r;c=t[++n]}else if(c===" "&&!s){a=!0;continue}else if(c==='"'){s=!s;continue}a?(r.push(c),a=!1):r[r.length-1]+=c}return s&&e.push(`invalid value for NODE_OPTIONS (unterminated string)
`),r}Dt();var[ml,ih]=process.versions.node.split(".").map(t=>parseInt(t,10)),yBe=ml>19||ml===19&&ih>=2||ml===18&&ih>=13,IXt=ml===20&&ih<6||ml===19&&ih>=3,CXt=ml>19||ml===19&&ih>=6,wXt=ml>=21||ml===20&&ih>=10||ml===18&&ih>=19,BXt=ml>=21||ml===20&&ih>=10||ml===18&&ih>=20,vXt=ml>=22;function EBe(t){if(process.env.WATCH_REPORT_DEPENDENCIES&&process.send)if(t=t.map(e=>fe.fromPortablePath(uo.resolveVirtual(fe.toPortablePath(e)))),yBe)process.send({"watch:require":t});else for(let e of t)process.send({"watch:require":e})}function cY(t,e){let r=Number(process.env.PNP_ALWAYS_WARN_ON_FALLBACK)>0,s=Number(process.env.PNP_DEBUG_LEVEL),a=/^(?![a-zA-Z]:[\\/]|\\\\|\.{0,2}(?:\/|$))((?:node:)?(?:@[^/]+\/)?[^/]+)\/*(.*|)$/,n=/^(\/|\.{1,2}(\/|$))/,c=/\/$/,f=/^\.{0,2}\//,p={name:null,reference:null},h=[],E=new Set;if(t.enableTopLevelFallback===!0&&h.push(p),e.compatibilityMode!==!1)for(let Fe of["react-scripts","gatsby"]){let Ne=t.packageRegistry.get(Fe);if(Ne)for(let be of Ne.keys()){if(be===null)throw new Error("Assertion failed: This reference shouldn't be null");h.push({name:Fe,reference:be})}}let{ignorePattern:C,packageRegistry:S,packageLocatorsByLocations:b}=t;function I(Fe,Ne){return{fn:Fe,args:Ne,error:null,result:null}}function T(Fe){let Ne=process.stderr?.hasColors?.()??process.stdout.isTTY,be=(it,Ue)=>`\x1B[${it}m${Ue}\x1B[0m`,Ve=Fe.error;console.error(Ve?be("31;1",`\u2716 ${Fe.error?.message.replace(/\n.*/s,"")}`):be("33;1","\u203C Resolution")),Fe.args.length>0&&console.error();for(let it of Fe.args)console.error(` ${be("37;1","In \u2190")} ${(0,lY.inspect)(it,{colors:Ne,compact:!0})}`);Fe.result&&(console.error(),console.error(` ${be("37;1","Out \u2192")} ${(0,lY.inspect)(Fe.result,{colors:Ne,compact:!0})}`));let ke=new Error().stack.match(/(?<=^ +)at.*/gm)?.slice(2)??[];if(ke.length>0){console.error();for(let it of ke)console.error(` ${be("38;5;244",it)}`)}console.error()}function N(Fe,Ne){if(e.allowDebug===!1)return Ne;if(Number.isFinite(s)){if(s>=2)return(...be)=>{let Ve=I(Fe,be);try{return Ve.result=Ne(...be)}catch(ke){throw Ve.error=ke}finally{T(Ve)}};if(s>=1)return(...be)=>{try{return Ne(...be)}catch(Ve){let ke=I(Fe,be);throw ke.error=Ve,T(ke),Ve}}}return Ne}function U(Fe){let Ne=g(Fe);if(!Ne)throw gs("INTERNAL","Couldn't find a matching entry in the dependency tree for the specified parent (this is probably an internal error)");return Ne}function W(Fe){if(Fe.name===null)return!0;for(let Ne of t.dependencyTreeRoots)if(Ne.name===Fe.name&&Ne.reference===Fe.reference)return!0;return!1}let ee=new Set(["node","require",...mBe("--conditions")]);function ie(Fe,Ne=ee,be){let Ve=Ae(J.join(Fe,"internal.js"),{resolveIgnored:!0,includeDiscardFromLookup:!0});if(Ve===null)throw gs("INTERNAL",`The locator that owns the "${Fe}" path can't be found inside the dependency tree (this is probably an internal error)`);let{packageLocation:ke}=U(Ve),it=J.join(ke,Er.manifest);if(!e.fakeFs.existsSync(it))return null;let Ue=JSON.parse(e.fakeFs.readFileSync(it,"utf8"));if(Ue.exports==null)return null;let x=J.contains(ke,Fe);if(x===null)throw gs("INTERNAL","unqualifiedPath doesn't contain the packageLocation (this is probably an internal error)");x!=="."&&!f.test(x)&&(x=`./${x}`);try{let w=fBe({packageJSONUrl:(0,jm.pathToFileURL)(fe.fromPortablePath(it)),packageSubpath:x,exports:Ue.exports,base:be?(0,jm.pathToFileURL)(fe.fromPortablePath(be)):null,conditions:Ne});return fe.toPortablePath((0,jm.fileURLToPath)(w))}catch(w){throw gs("EXPORTS_RESOLUTION_FAILED",w.message,{unqualifiedPath:lf(Fe),locator:Ve,pkgJson:Ue,subpath:lf(x),conditions:Ne},w.code)}}function ue(Fe,Ne,{extensions:be}){let Ve;try{Ne.push(Fe),Ve=e.fakeFs.statSync(Fe)}catch{}if(Ve&&!Ve.isDirectory())return e.fakeFs.realpathSync(Fe);if(Ve&&Ve.isDirectory()){let ke;try{ke=JSON.parse(e.fakeFs.readFileSync(J.join(Fe,Er.manifest),"utf8"))}catch{}let it;if(ke&&ke.main&&(it=J.resolve(Fe,ke.main)),it&&it!==Fe){let Ue=ue(it,Ne,{extensions:be});if(Ue!==null)return Ue}}for(let ke=0,it=be.length;ke<it;ke++){let Ue=`${Fe}${be[ke]}`;if(Ne.push(Ue),e.fakeFs.existsSync(Ue))return Ue}if(Ve&&Ve.isDirectory())for(let ke=0,it=be.length;ke<it;ke++){let Ue=J.format({dir:Fe,name:"index",ext:be[ke]});if(Ne.push(Ue),e.fakeFs.existsSync(Ue))return Ue}return null}function le(Fe){let Ne=new sh.Module(Fe,null);return Ne.filename=Fe,Ne.paths=sh.Module._nodeModulePaths(Fe),Ne}function me(Fe,Ne){return Ne.endsWith("/")&&(Ne=J.join(Ne,"internal.js")),sh.Module._resolveFilename(fe.fromPortablePath(Fe),le(fe.fromPortablePath(Ne)),!1,{plugnplay:!1})}function pe(Fe){if(C===null)return!1;let Ne=J.contains(t.basePath,Fe);return Ne===null?!1:!!C.test(Ne.replace(/\/$/,""))}let Be={std:3,resolveVirtual:1,getAllLocators:1},Ce=p;function g({name:Fe,reference:Ne}){let be=S.get(Fe);if(!be)return null;let Ve=be.get(Ne);return Ve||null}function we({name:Fe,reference:Ne}){let be=[];for(let[Ve,ke]of S)if(Ve!==null)for(let[it,Ue]of ke)it===null||Ue.packageDependencies.get(Fe)!==Ne||Ve===Fe&&it===Ne||be.push({name:Ve,reLine truncated
Require request: "${Ve}"
Required by: ${ke}
`,{request:Ve,issuer:ke});return fe.toPortablePath(x)}let it,Ue=Fe.match(a);if(Ue){if(!Ne)throw gs("API_ERROR","The resolveToUnqualified function must be called with a valid issuer when the path isn't a builtin nor absolute",{request:Ve,issuer:ke});let[,x,w]=Ue,P=Ae(Ne);if(!P){let Re=me(Fe,Ne);if(Re===!1)throw gs("BUILTIN_NODE_RESOLUTION_FAILED",`The builtin node resolution algorithm was unable to resolve the requested module (it didn't go through the pnp resolver because the issuer doesn't seem to be part of the Yarn-managed dependency tree).
Require path: "${Ve}"
Required by: ${ke}
`,{request:Ve,issuer:ke});return fe.toPortablePath(Re)}let F=U(P).packageDependencies.get(x),z=null;if(F==null&&P.name!==null){let Re=t.fallbackExclusionList.get(P.name);if(!Re||!Re.has(P.reference)){for(let Ct=0,qt=h.length;Ct<qt;++Ct){let bt=U(h[Ct]).packageDependencies.get(x);if(bt!=null){r?z=bt:F=bt;break}}if(t.enableTopLevelFallback&&F==null&&z===null){let Ct=t.fallbackPool.get(x);Ct!=null&&(z=Ct)}}}let Z=null;if(F===null)if(W(P))Z=gs("MISSING_PEER_DEPENDENCY",`Your application tried to access ${x} (a peer dependency); this isn't allowed as there is no ancestor to satisfy the requirement. Use a devDependency if needed.
Required package: ${x}${x!==Ve?` (via "${Ve}")`:""}
Required by: ${ke}
`,{request:Ve,issuer:ke,dependencyName:x});else{let Re=ye(x,P);Re.every(lt=>W(lt))?Z=gs("MISSING_PEER_DEPENDENCY",`${P.name} tried to access ${x} (a peer dependency) but it isn't provided by your application; this makes the require call ambiguous and unsound.
Required package: ${x}${x!==Ve?` (via "${Ve}")`:""}
Required by: ${P.name}@${P.reference} (via ${ke})
${Re.map(lt=>`Ancestor breaking the chain: ${lt.name}@${lt.reference}
`).join("")}
`,{request:Ve,issuer:ke,issuerLocator:Object.assign({},P),dependencyName:x,brokenAncestors:Re}):Z=gs("MISSING_PEER_DEPENDENCY",`${P.name} tried to access ${x} (a peer dependency) but it isn't provided by its ancestors; this makes the require call ambiguous and unsound.
Required package: ${x}${x!==Ve?` (via "${Ve}")`:""}
Required by: ${P.name}@${P.reference} (via ${ke})
${Re.map(lt=>`Ancestor breaking the chain: ${lt.name}@${lt.reference}
`).join("")}
`,{request:Ve,issuer:ke,issuerLocator:Object.assign({},P),dependencyName:x,brokenAncestors:Re})}else F===void 0&&(!be&&(0,sh.isBuiltin)(Fe)?W(P)?Z=gs("UNDECLARED_DEPENDENCY",`Your application tried to access ${x}. While this module is usually interpreted as a Node builtin, your resolver is running inside a non-Node resolution context where such builtins are ignored. Since ${x} isn't otherwise declared in your dependencies, this makes the require call ambiguous and unsound.
Required package: ${x}${x!==Ve?` (via "${Ve}")`:""}
Required by: ${ke}
`,{request:Ve,issuer:ke,dependencyName:x}):Z=gs("UNDECLARED_DEPENDENCY",`${P.name} tried to access ${x}. While this module is usually interpreted as a Node builtin, your resolver is running inside a non-Node resolution context where such builtins are ignored. Since ${x} isn't otherwise declared in ${P.name}'s dependencies, this makes the require call ambiguous and unsound.
Required package: ${x}${x!==Ve?` (via "${Ve}")`:""}
Required by: ${ke}
`,{request:Ve,issuer:ke,issuerLocator:Object.assign({},P),dependencyName:x}):W(P)?Z=gs("UNDECLARED_DEPENDENCY",`Your application tried to access ${x}, but it isn't declared in your dependencies; this makes the require call ambiguous and unsound.
Required package: ${x}${x!==Ve?` (via "${Ve}")`:""}
Required by: ${ke}
`,{request:Ve,issuer:ke,dependencyName:x}):Z=gs("UNDECLARED_DEPENDENCY",`${P.name} tried to access ${x}, but it isn't declared in its dependencies; this makes the require call ambiguous and unsound.
Required package: ${x}${x!==Ve?` (via "${Ve}")`:""}
Required by: ${P.name}@${P.reference} (via ${ke})
`,{request:Ve,issuer:ke,issuerLocator:Object.assign({},P),dependencyName:x}));if(F==null){if(z===null||Z===null)throw Z||new Error("Assertion failed: Expected an error to have been set");F=z;let Re=Z.message.replace(/\n.*/g,"");Z.message=Re,!E.has(Re)&&s!==0&&(E.add(Re),process.emitWarning(Z))}let $=Array.isArray(F)?{name:F[0],reference:F[1]}:{name:x,reference:F},oe=U($);if(!oe.packageLocation)throw gs("MISSING_DEPENDENCY",`A dependency seems valid but didn't get installed for some reason. This might be caused by a partial install, such as dev vs prod.
Required package: ${$.name}@${$.reference}${$.name!==Ve?` (via "${Ve}")`:""}
Required by: ${P.name}@${P.reference} (via ${ke})
`,{request:Ve,issuer:ke,dependencyLocator:Object.assign({},$)});let xe=oe.packageLocation;w?it=J.join(xe,w):it=xe}else if(J.isAbsolute(Fe))it=J.normalize(Fe);else{if(!Ne)throw gs("API_ERROR","The resolveToUnqualified function must be called with a valid issuer when the path isn't a builtin nor absolute",{request:Ve,issuer:ke});let x=J.resolve(Ne);Ne.match(c)?it=J.normalize(J.join(x,Fe)):it=J.normalize(J.join(J.dirname(x),Fe))}return J.normalize(it)}function De(Fe,Ne,be=ee,Ve){if(n.test(Fe))return Ne;let ke=ie(Ne,be,Ve);return ke?J.normalize(ke):Ne}function Te(Fe,{extensions:Ne=Object.keys(sh.Module._extensions)}={}){let be=[],Ve=ue(Fe,be,{extensions:Ne});if(Ve)return J.normalize(Ve);{EBe(be.map(Ue=>fe.fromPortablePath(Ue)));let ke=lf(Fe),it=Ae(Fe);if(it){let{packageLocation:Ue}=U(it),x=!0;try{e.fakeFs.accessSync(Ue)}catch(w){if(w?.code==="ENOENT")x=!1;else{let P=(w?.message??w??"empty exception thrown").replace(/^[A-Z]/,y=>y.toLowerCase());throw gs("QUALIFIED_PATH_RESOLUTION_FAILED",`Required package exists but could not be accessed (${P}).
Missing package: ${it.name}@${it.reference}
Expected package location: ${lf(Ue)}
`,{unqualifiedPath:ke,extensions:Ne})}}if(!x){let w=Ue.includes("/unplugged/")?"Required unplugged package missing from disk. This may happen when switching branches without running installs (unplugged packages must be fully materialized on disk to work).":"Required package missing from disk. If you keep your packages inside your repository then restarting the Node process may be enough. Otherwise, try to run an install first.";throw gs("QUALIFIED_PATH_RESOLUTION_FAILED",`${w}
Missing package: ${it.name}@${it.reference}
Expected package location: ${lf(Ue)}
`,{unqualifiedPath:ke,extensions:Ne})}}throw gs("QUALIFIED_PATH_RESOLUTION_FAILED",`Qualified path resolution failed: we looked for the following paths, but none could be accessed.
Source path: ${ke}
${be.map(Ue=>`Not found: ${lf(Ue)}
`).join("")}`,{unqualifiedPath:ke,extensions:Ne})}}function mt(Fe,Ne,be){if(!Ne)throw new Error("Assertion failed: An issuer is required to resolve private import mappings");let Ve=ABe({name:Fe,base:(0,jm.pathToFileURL)(fe.fromPortablePath(Ne)),conditions:be.conditions??ee,readFileSyncFn:se});if(Ve instanceof URL)return Te(fe.toPortablePath((0,jm.fileURLToPath)(Ve)),{extensions:be.extensions});if(Ve.startsWith("#"))throw new Error("Mapping from one private import to another isn't allowed");return j(Ve,Ne,be)}function j(Fe,Ne,be={}){try{if(Fe.startsWith("#"))return mt(Fe,Ne,be);let{considerBuiltins:Ve,extensions:ke,conditions:it}=be,Ue=X(Fe,Ne,{considerBuiltins:Ve});if(Fe==="pnpapi")return Ue;if(Ue===null)return null;let x=()=>Ne!==null?pe(Ne):!1,w=(!Ve||!(0,sh.isBuiltin)(Fe))&&!x()?De(Fe,Ue,it,Ne):Ue;return Te(w,{extensions:ke})}catch(Ve){throw Object.hasOwn(Ve,"pnpCode")&&Object.assign(Ve.data,{request:lf(Fe),issuer:Ne&&lf(Ne)}),Ve}}function rt(Fe){let Ne=J.normalize(Fe),be=uo.resolveVirtual(Ne);return be!==Ne?be:null}return{VERSIONS:Be,topLevel:Ce,getLocator:(Fe,Ne)=>Array.isArray(Ne)?{name:Ne[0],reference:Ne[1]}:{name:Fe,reference:Ne},getDependencyTreeRoots:()=>[...t.dependencyTreeRoots],getAllLocators(){let Fe=[];for(let[Ne,be]of S)for(let Ve of be.keys())Ne!==null&&Ve!==null&&Fe.push({name:Ne,reference:Ve});return Fe},getPackageInformation:Fe=>{let Ne=g(Fe);if(Ne===null)return null;let be=fe.fromPortablePath(Ne.packageLocation);return{...Ne,packageLocation:be}},findPackageLocator:Fe=>Ae(fe.toPortablePath(Fe)),resolveToUnqualified:N("resolveToUnqualified",(Fe,Ne,be)=>{let Ve=Ne!==null?fe.toPortablePath(Ne):null,ke=X(fe.toPortablePath(Fe),Ve,be);return ke===null?null:fe.fromPortablePath(ke)}),resolveUnqualified:N("resolveUnqualified",(Fe,Ne)=>fe.fromPortablePath(Te(fe.toPortablePath(Fe),Ne))),resolveRequest:N("resolveRequest",(Fe,Ne,be)=>{let Ve=Ne!==null?fe.toPortablePath(Ne):null,ke=j(fe.toPortablePath(Fe),Ve,be);return ke===null?null:fe.fromPortablePath(ke)}),resolveVirtual:N("resolveVirtual",Fe=>{let Ne=rt(fe.toPortablePath(Fe));return Ne!==null?fe.fromPortablePath(Ne):null})}}Dt();var IBe=(t,e,r)=>{let s=RD(t),a=XW(s,{basePath:e}),n=fe.join(e,Er.pnpCjs);return cY(a,{fakeFs:r,pnpapiResolution:n})};var fY=ut(wBe());Yt();var gA={};Vt(gA,{checkManifestCompatibility:()=>BBe,extractBuildRequest:()=>sN,getExtractHint:()=>AY,hasBindingGyp:()=>pY});Ge();Dt();function BBe(t){return G.isPackageCompatible(t,fs.getArchitectureSet())}function sN(t,e,r,{configuration:s}){let a=[];for(let n of["preinstall","install","postinstall"])e.manifest.scripts.has(n)&&a.push({type:0,script:n});return!e.manifest.scripts.has("install")&&e.misc.hasBindingGyp&&a.push({type:1,script:"node-gyp rebuild"}),a.length===0?null:t.linkType!=="HARD"?{skipped:!0,explain:n=>n.reportWarningOnce(6,`${G.prettyLocator(s,t)} lists build scripts, but is referenced through a soft link. Soft links don't support build scripts, so they'll be ignored.`)}:r&&r.built===!1?{skipped:!0,explain:n=>n.reportInfoOnce(5,`${G.prettyLocator(s,t)} lists build scripts, but its build has been explicitly disabled through configuration.`)}:!s.get("enableScripts")&&!r.built?{skipped:!0,explain:n=>n.reportWarningOnce(4,`${G.prettyLocator(s,t)} lists build scripts, but all build scripts have been disabled.`)}:BBe(t)?{skipped:!1,directives:a}:{skipped:!0,explain:n=>n.reportWarningOnce(76,`${G.prettyLocator(s,t)} The ${fs.getArchitectureName()} architecture is incompatible with this package, build skipped.`)}}var adt=new Set([".exe",".bin",".h",".hh",".hpp",".c",".cc",".cpp",".java",".jar",".node"]);function AY(t){return t.packageFs.getExtractHint({relevantExtensions:adt})}function pY(t){let e=J.join(t.prefixPath,"binding.gyp");return t.packageFs.existsSync(e)}var HD={};Vt(HD,{getUnpluggedPath:()=>_D});Ge();Dt();function _D(t,{configuration:e}){return J.resolve(e.get("pnpUnpluggedFolder"),G.slugifyLocator(t))}var ldt=new Set([G.makeIdent(null,"open").identHash,G.makeIdent(null,"opn").identHash]),sg=class{constructor(){this.mode="strict";this.pnpCache=new Map}getCustomDataKey(){return JSON.stringify({name:"PnpLinker",version:2})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error("Assertion failed: Expected the PnP linker to be enabled");let s=og(r.project).cjs;if(!ce.existsSync(s))throw new nt(`The project in ${he.pretty(r.project.configuration,`${r.project.cwd}/package.json`,he.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let a=je.getFactoryWithDefault(this.pnpCache,s,()=>je.dynamicRequire(s,{cachingStrategy:je.CachingStrategy.FsTime})),n={name:G.stringifyIdent(e),reference:e.reference},c=a.getPackageInformation(n);if(!c)throw new nt(`Couldn't find ${G.prettyLocator(r.project.configuration,e)} in the currently installed PnP map - running an install might help`);return fe.toPortablePath(c.packageLocation)}async findPackageLocator(e,r){if(!this.isEnabled(r))return nullLine truncated
`,n+=`# cause your node_modules installation to become invalidated.
`,n+=`
`,n+=`__metadata:
`,n+=` version: ${OBe}
`,n+=` nmMode: ${s.value}
`;let c=Array.from(e.keys()).sort(),f=G.stringifyLocator(t.topLevelWorkspace.anchoredLocator);for(let E of c){let C=e.get(E);n+=`
`,n+=`${JSON.stringify(E)}:
`,n+=` locations:
`;for(let S of C.locations){let b=J.contains(t.cwd,S);if(b===null)throw new Error(`Assertion failed: Expected the path to be within the project (${S})`);n+=` - ${JSON.stringify(b)}
`}if(C.aliases.length>0){n+=` aliases:
`;for(let S of C.aliases)n+=` - ${JSON.stringify(S)}
`}if(E===f&&r.size>0){n+=` bin:
`;for(let[S,b]of r){let I=J.contains(t.cwd,S);if(I===null)throw new Error(`Assertion failed: Expected the path to be within the project (${S})`);n+=` ${JSON.stringify(I)}:
`;for(let[T,N]of b){let U=J.relative(J.join(S,Ri),N);n+=` ${JSON.stringify(T)}: ${JSON.stringify(U)}
`}}}}let p=t.cwd,h=J.join(p,Ri,LBe);a&&await ce.removePromise(h),await ce.changeFilePromise(h,n,{automaticNewlines:!0})}async function CY(t,{unrollAliases:e=!1}={}){let r=t.cwd,s=J.join(r,Ri,LBe),a;try{a=await ce.statPromise(s)}catch{}if(!a)return null;let n=as(await ce.readFilePromise(s,"utf8"));if(n.__metadata.version>OBe)return null;let c=n.__metadata.nmMode||"classic",f=new Map,p=new Map;delete n.__metadata;for(let[h,E]of Object.entries(n)){let C=E.locations.map(b=>J.join(r,b)),S=E.bin;if(S)for(let[b,I]of Object.entries(S)){let T=J.join(r,fe.toPortablePath(b)),N=je.getMapWithDefault(p,T);for(let[U,W]of Object.entries(I))N.set(U,fe.toPortablePath([T,Ri,W].join(J.sep)))}if(f.set(h,{target:vt.dot,linkType:"HARD",locations:C,aliases:E.aliases||[]}),e&&E.aliases)for(let b of E.aliases){let{scope:I,name:T}=G.parseLocator(h),N=G.makeLocator(G.makeIdent(I,T),b),U=G.stringifyLocator(N);f.set(U,{target:vt.dot,linkType:"HARD",locations:C,aliases:[]})}}return{locatorMap:f,binSymlinks:p,locationTree:MBe(f,{skipPrefix:t.cwd}),nmMode:c,mtimeMs:a.mtimeMs}}var Pw=async(t,e)=>{if(t.split(J.sep).indexOf(Ri)<0)throw new Error(`Assertion failed: trying to remove dir that doesn't contain node_modules: ${t}`);try{let r;if(!e.innerLoop&&(r=await ce.lstatPromise(t),!r.isDirectory()&&!r.isSymbolicLink()||r.isSymbolicLink()&&!e.isWorkspaceDir)){await ce.unlinkPromise(t);return}let s=await ce.readdirPromise(t,{withFileTypes:!0});for(let n of s){let c=J.join(t,n.name);n.isDirectory()?(n.name!==Ri||e&&e.innerLoop)&&await Pw(c,{innerLoop:!0,contentsOnly:!1}):await ce.unlinkPromise(c)}let a=!e.innerLoop&&e.isWorkspaceDir&&r?.isSymbolicLink();!e.contentsOnly&&!a&&await ce.rmdirPromise(t)}catch(r){if(r.code!=="ENOENT"&&r.code!=="ENOTEMPTY")throw r}},RBe=4,aN=(t,{skipPrefix:e})=>{let r=J.contains(e,t);if(r===null)throw new Error(`Assertion failed: Writing attempt prevented to ${t} which is outside project root: ${e}`);let s=r.split(J.sep).filter(p=>p!==""),a=s.indexOf(Ri),n=s.slice(0,a).join(J.sep),c=J.join(e,n),f=s.slice(a);return{locationRoot:c,segments:f}},MBe=(t,{skipPrefix:e})=>{let r=new Map;if(t===null)return r;let s=()=>({children:new Map,linkType:"HARD"});for(let[a,n]of t.entries()){if(n.linkType==="SOFT"&&J.contains(e,n.target)!==null){let f=je.getFactoryWithDefault(r,n.target,s);f.locator=a,f.linkType=n.linkType}for(let c of n.locations){let{locationRoot:f,segments:p}=aN(c,{skipPrefix:e}),h=je.getFactoryWithDefault(r,f,s);for(let E=0;E<p.length;++E){let C=p[E];if(C!=="."){let S=je.getFactoryWithDefault(h.children,C,s);h.children.set(C,S),h=S}E===p.length-1&&(h.locator=a,h.linkType=n.linkType)}}}return r},vY=async(t,e,r)=>{if(process.platform==="win32"&&r==="junctions"){let s;try{s=await ce.lstatPromise(t)}catch{}if(!s||s.isDirectory()){await ce.symlinkPromise(t,e,"junction");return}}await ce.symlinkPromise(J.relative(J.dirname(e),t),e)};async function UBe(t,e,r){let s=J.join(t,`${wY.default.randomBytes(16).toString("hex")}.tmp`);try{await ce.writeFilePromise(s,r);try{await ce.linkPromise(s,e)}catch{}}finally{await ce.unlinkPromise(s)}}async function Tdt({srcPath:t,dstPath:e,entry:r,globalHardlinksStore:s,baseFs:a,nmMode:n}){if(r.kind==="file"){if(n.value==="hardlinks-global"&&s&&r.digest){let f=J.join(s,r.digest.substring(0,2),`${r.digest.substring(2)}.dat`),p;try{let h=await ce.statPromise(f);if(h&&(!r.mtimeMs||h.mtimeMs>r.mtimeMs||h.mtimeMs<r.mtimeMs-kdt))if(await Nn.checksumFile(f,{baseFs:ce,algorithm:"sha1"})!==r.digest){let C=J.join(s,`${wY.default.randomBytes(16).toString("hex")}.tmp`);await ce.renamePromise(f,C);let S=await a.readFilePromise(t);await ce.writeFilePromise(C,S);try{await ce.linkPromise(C,f),r.mtimeMs=new Date().getTime(),await ce.unlinkPromise(C)}catch{}}else r.mtimeMs||(r.mtimeMs=Math.ceil(h.mtimeMs));await ce.linkPromise(f,e),p=!0}catch{p=!1}if(!p){let h=await a.readFilePromise(t);await UBe(s,f,h),r.mtimeMs=new Date().getTime();try{await ce.linkPromise(f,e)}catch(E){E&&E.code&&E.code=="EXDEV"&&(n.value="hardlinks-local",await a.copyFilePromise(t,e))}}}else await a.copyFilePromise(t,e);let c=r.mode&511;c!==420&&await ce.chmodPromise(e,c)}}var Fdt=async(t,e,{baseFs:r,globalHardlinksStore:s,nmMode:a,windowsLinkType:n,packageChecksum:c})=>{await ce.mkdirPromise(t,{recursive:!0});let f=async(E=vt.dot)=>{let C=J.join(e,E),S=await r.readdirPromise(C,{withFileTypes:!0}),b=new Map;for(let I of S){let T=J.join(E,I.name),N,U=J.join(C,I.name);if(I.isFile()){if(N={kind:"file",mode:(await r.lstatPromise(U)).mode},a.value==="hardlinks-global"){let W=await Nn.checksumFile(U,{baseFs:r,algorithm:"sha1"});N.digest=W}}else if(I.isDirectory())N={kind:"directory"};else if(I.isSymbolicLink())N={kind:"symlink",symlinkTo:await r.readlinkPromise(U)};else throw new Error(`Unsupported file type (file: ${U}, mode: 0o${await r.statSync(U).mode.toString(8).padStart(6,"0")})`);if(b.set(T,N),I.isDirectory()&&T!==Ri){let W=await f(T);for(let[ee,ie]of W)b.set(ee,ie)}}return b},p;if(a.value==="hardlinks-global"&&s&&c){let E=J.join(s,c.sub Line truncated
`)),process.env.YARN_IS_TEST_ENV)return process.env.YARN_INJECT_NPM_2FA_TOKEN||"";let{otp:s}=await(0,kY.prompt)({type:"password",name:"otp",message:"One-time password:",required:!0,onCancel:()=>process.exit(130)});return process.stdout.write(`
`),s}function cN(t){if(t.originalError?.name!=="HTTPError")return!1;try{return(t.originalError?.response.headers["www-authenticate"].split(/,\s*/).map(r=>r.toLowerCase())).includes("otp")}catch{return!1}}function kw(t){return{"npm-otp":t}}async function amt(t,{configuration:e,ident:r}){let s=null;if(process.env.GITLAB)s=process.env.NPM_ID_TOKEN||null;else if(process.env.GITHUB_ACTIONS){if(!(process.env.ACTIONS_ID_TOKEN_REQUEST_URL&&process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN))return null;let a=`npm:${new URL(t).host.replace("registry.yarnpkg.com","registry.npmjs.org").replace("yarn.npmjs.org","registry.npmjs.org")}`,n=new URL(process.env.ACTIONS_ID_TOKEN_REQUEST_URL);n.searchParams.append("audience",a),s=(await ln.get(n.href,{configuration:e,jsonResponse:!0,headers:{Authorization:`Bearer ${process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN}`}})).value}if(!s)return null;try{return(await ln.post(`${t}/-/npm/v1/oidc/token/exchange/package${WD(r)}`,null,{configuration:e,jsonResponse:!0,headers:{Authorization:`Bearer ${s}`}})).token||null}catch{}return null}var VD=class{supports(e,r){if(!e.reference.startsWith(oi))return!1;let{selector:s,params:a}=G.parseRange(e.reference);return!(!JBe.default.valid(s)||a===null||typeof a.__archiveUrl!="string")}getLocalPath(e,r){return null}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote server`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),checksum:c}}async fetchFromNetwork(e,r){let{params:s}=G.parseRange(e.reference);if(s===null||typeof s.__archiveUrl!="string")throw new Error("Assertion failed: The archiveUrl querystring parameter should have been available");let a=await Wm(s.__archiveUrl,{customErrorMessage:qm,configuration:r.project.configuration,ident:e});return await ps.convertToZip(a,{configuration:r.project.configuration,prefixPath:G.getIdentVendorPath(e),stripComponents:1})}};Ge();var JD=class{supportsDescriptor(e,r){return!(!e.range.startsWith(oi)||!G.tryParseDescriptor(e.range.slice(oi.length),!0))}supportsLocator(e,r){return!1}shouldPersistResolution(e,r){throw new Error("Unreachable")}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){let s=r.project.configuration.normalizeDependency(G.parseDescriptor(e.range.slice(oi.length),!0));return r.resolver.getResolutionDependencies(s,r)}async getCandidates(e,r,s){let a=s.project.configuration.normalizeDependency(G.parseDescriptor(e.range.slice(oi.length),!0));return await s.resolver.getCandidates(a,r,s)}async getSatisfying(e,r,s,a){let n=a.project.configuration.normalizeDependency(G.parseDescriptor(e.range.slice(oi.length),!0));return a.resolver.getSatisfying(n,r,s,a)}resolve(e,r){throw new Error("Unreachable")}};Ge();Ge();var KBe=ut(Ai());var oh=class t{supports(e,r){if(!e.reference.startsWith(oi))return!1;let s=new URL(e.reference);return!(!KBe.default.valid(s.pathname)||s.searchParams.has("__archiveUrl"))}getLocalPath(e,r){return null}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote registry`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),checksum:c}}async fetchFromNetwork(e,r){let s;try{s=await Wm(t.getLocatorUrl(e),{customErrorMessage:qm,configuration:r.project.configuration,ident:e})}catch{s=await Wm(t.getLocatorUrl(e).replace(/%2f/g,"/"),{customErrorMessage:qm,configuration:r.project.configuration,ident:e})}return await ps.convertToZip(s,{configuration:r.project.configuration,prefixPath:G.getIdentVendorPath(e),stripComponents:1})}static isConventionalTarballUrl(e,r,{configuration:s}){let a=bw(e.scope,{configuration:s}),n=t.getLocatorUrl(e);return r=r.replace(/^https?:(\/\/(?:[^/]+\.)?npmjs.org(?:$|\/))/,"https:$1"),a=a.replace(/^https:\/\/registry\.npmjs\.org($|\/)/,"https://registry.yarnpkg.com$1"),r=r.replace(/^https:\/\/registry\.npmjs\.org($|\/)/,"https://registry.yarnpkg.com$1"),r===a+n||r===a+n.replace(/%2f/g,"/")}static getLocatorUrl(e){let r=Fr.clean(e.reference.slice(oi.length));if(r===null)throw new jt(10,"The npm semver resolver got selected, but the version isn't semver");return`${WD(e)}/-/${e.name}-${r}.tgz`}};Ge();Ge();Ge();var RY=ut(Ai());var uN=G.makeIdent(null,"node-gyp"),lmt=/\b(node-gyp|prebuild-install)\b/,KD=class{supportsDescriptor(e,r){return e.range.startsWith(oi)?!!Fr.validRange(e.range.slice(oi.length)):!1}supportsLocator(e,r){if(!e.reference.startsWith(oi))return!1;let{selector:s}=G.parseRange(e.reference);return!!RY.default.valid(s)}shouldPersistRLine truncated
https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html`);r={_type:qDt,subject:t,predicateType:YDt,predicate:{buildType:`${zDt}/${ZDt}`,builder:{id:`${Bt.CI_PROJECT_URL}/-/runners/${Bt.CI_RUNNER_ID}`},invocation:{configSource:{uri:`git+${Bt.CI_PROJECT_URL}`,digest:{sha1:Bt.CI_COMMIT_SHA},entryPoint:Bt.CI_JOB_NAME},parameters:{CI:Bt.CI,CI_API_GRAPHQL_URL:Bt.CI_API_GRAPHQL_URL,CI_API_V4_URL:Bt.CI_API_V4_URL,CI_BUILD_BEFORE_SHA:Bt.CI_BUILD_BEFORE_SHA,CI_BUILD_ID:Bt.CI_BUILD_ID,CI_BUILD_NAME:Bt.CI_BUILD_NAME,CI_BUILD_REF:Bt.CI_BUILD_REF,CI_BUILD_REF_NAME:Bt.CI_BUILD_REF_NAME,CI_BUILD_REF_SLUG:Bt.CI_BUILD_REF_SLUG,CI_BUILD_STAGE:Bt.CI_BUILD_STAGE,CI_COMMIT_BEFORE_SHA:Bt.CI_COMMIT_BEFORE_SHA,CI_COMMIT_BRANCH:Bt.CI_COMMIT_BRANCH,CI_COMMIT_REF_NAME:Bt.CI_COMMIT_REF_NAME,CI_COMMIT_REF_PROTECTED:Bt.CI_COMMIT_REF_PROTECTED,CI_COMMIT_REF_SLUG:Bt.CI_COMMIT_REF_SLUG,CI_COMMIT_SHA:Bt.CI_COMMIT_SHA,CI_COMMIT_SHORT_SHA:Bt.CI_COMMIT_SHORT_SHA,CI_COMMIT_TIMESTAMP:Bt.CI_COMMIT_TIMESTAMP,CI_COMMIT_TITLE:Bt.CI_COMMIT_TITLE,CI_CONFIG_PATH:Bt.CI_CONFIG_PATH,CI_DEFAULT_BRANCH:Bt.CI_DEFAULT_BRANCH,CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX:Bt.CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX,CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX:Bt.CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX,CI_DEPENDENCY_PROXY_SERVER:Bt.CI_DEPENDENCY_PROXY_SERVER,CI_DEPENDENCY_PROXY_USER:Bt.CI_DEPENDENCY_PROXY_USER,CI_JOB_ID:Bt.CI_JOB_ID,CI_JOB_NAME:Bt.CI_JOB_NAME,CI_JOB_NAME_SLUG:Bt.CI_JOB_NAME_SLUG,CI_JOB_STAGE:Bt.CI_JOB_STAGE,CI_JOB_STARTED_AT:Bt.CI_JOB_STARTED_AT,CI_JOB_URL:Bt.CI_JOB_URL,CI_NODE_TOTAL:Bt.CI_NODE_TOTAL,CI_PAGES_DOMAIN:Bt.CI_PAGES_DOMAIN,CI_PAGES_URL:Bt.CI_PAGES_URL,CI_PIPELINE_CREATED_AT:Bt.CI_PIPELINE_CREATED_AT,CI_PIPELINE_ID:Bt.CI_PIPELINE_ID,CI_PIPELINE_IID:Bt.CI_PIPELINE_IID,CI_PIPELINE_SOURCE:Bt.CI_PIPELINE_SOURCE,CI_PIPELINE_URL:Bt.CI_PIPELINE_URL,CI_PROJECT_CLASSIFICATION_LABEL:Bt.CI_PROJECT_CLASSIFICATION_LABEL,CI_PROJECT_DESCRIPTION:Bt.CI_PROJECT_DESCRIPTION,CI_PROJECT_ID:Bt.CI_PROJECT_ID,CI_PROJECT_NAME:Bt.CI_PROJECT_NAME,CI_PROJECT_NAMESPACE:Bt.CI_PROJECT_NAMESPACE,CI_PROJECT_NAMESPACE_ID:Bt.CI_PROJECT_NAMESPACE_ID,CI_PROJECT_PATH:Bt.CI_PROJECT_PATH,CI_PROJECT_PATH_SLUG:Bt.CI_PROJECT_PATH_SLUG,CI_PROJECT_REPOSITORY_LANGUAGES:Bt.CI_PROJECT_REPOSITORY_LANGUAGES,CI_PROJECT_ROOT_NAMESPACE:Bt.CI_PROJECT_ROOT_NAMESPACE,CI_PROJECT_TITLE:Bt.CI_PROJECT_TITLE,CI_PROJECT_URL:Bt.CI_PROJECT_URL,CI_PROJECT_VISIBILITY:Bt.CI_PROJECT_VISIBILITY,CI_REGISTRY:Bt.CI_REGISTRY,CI_REGISTRY_IMAGE:Bt.CI_REGISTRY_IMAGE,CI_REGISTRY_USER:Bt.CI_REGISTRY_USER,CI_RUNNER_DESCRIPTION:Bt.CI_RUNNER_DESCRIPTION,CI_RUNNER_ID:Bt.CI_RUNNER_ID,CI_RUNNER_TAGS:Bt.CI_RUNNER_TAGS,CI_SERVER_HOST:Bt.CI_SERVER_HOST,CI_SERVER_NAME:Bt.CI_SERVER_NAME,CI_SERVER_PORT:Bt.CI_SERVER_PORT,CI_SERVER_PROTOCOL:Bt.CI_SERVER_PROTOCOL,CI_SERVER_REVISION:Bt.CI_SERVER_REVISION,CI_SERVER_SHELL_SSH_HOST:Bt.CI_SERVER_SHELL_SSH_HOST,CI_SERVER_SHELL_SSH_PORT:Bt.CI_SERVER_SHELL_SSH_PORT,CI_SERVER_URL:Bt.CI_SERVER_URL,CI_SERVER_VERSION:Bt.CI_SERVER_VERSION,CI_SERVER_VERSION_MAJOR:Bt.CI_SERVER_VERSION_MAJOR,CI_SERVER_VERSION_MINOR:Bt.CI_SERVER_VERSION_MINOR,CI_SERVER_VERSION_PATCH:Bt.CI_SERVER_VERSION_PATCH,CI_TEMPLATE_REGISTRY_HOST:Bt.CI_TEMPLATE_REGISTRY_HOST,GITLAB_CI:Bt.GITLAB_CI,GITLAB_FEATURES:Bt.GITLAB_FEATURES,GITLAB_USER_ID:Bt.GITLAB_USER_ID,GITLAB_USER_LOGIN:Bt.GITLAB_USER_LOGIN,RUNNER_GENERATE_ARTIFACTS_METADATA:Bt.RUNNER_GENERATE_ARTIFACTS_METADATA},environment:{name:Bt.CI_RUNNER_DESCRIPTION,architecture:Bt.CI_RUNNER_EXECUTABLE_ARCH,server:Bt.CI_SERVER_URL,project:Bt.CI_PROJECT_PATH,job:{id:Bt.CI_JOB_ID},pipeline:{id:Bt.CI_PIPELINE_ID,ref:Bt.CI_CONFIG_PATH}}},metadata:{buildInvocationId:`${Bt.CI_JOB_URL}`,completeness:{parameters:!0,environment:!0,materials:!1},reproducible:!1},materials:[{uri:`git+${Bt.CI_PROJECT_URL}`,digest:{sha1:Bt.CI_COMMIT_SHA}}]}}}else throw new jt(91,"Provenance generation is only supported in GitHub Actions and GitLab CI");return Oxe.attest(Buffer.from(JSON.stringify(r)),GDt,e)};async function XDt(t,e,{access:r,tag:s,registry:a,gitHead:n,provenance:c}){let f=t.manifest.name,p=t.manifest.version,h=G.stringifyIdent(f),E=Mxe.default.fromData(e,{algorithms:["sha1","sha512"]}),C=r??Uxe(t,f),S=await _xe(t),b=await yA.genPackageManifest(t),I=`${h}-${p}.tgz`,T=new URL(`${Jc(a)}/${h}/-/${I}`),N={[I]:{content_type:"application/octet-stream",data:e.toString("base64"),length:e.length}};if(c){let U={name:`pkg:npm/${h.replace(/^@/,"%40")}@${p}`,digest:{sha512:E.sha512[0].hexDigest()}},W=await Lxe([U]),ee=JSON.stringify(W);N[`${h}-${p}.sigstore`]={content_type:W.mediaType,data:ee,length:ee.length}}return{_id:h,_attachments:N,name:h,access:C,"dist-tags":{[s]:p},versions:{[p]:{...b,_id:`${h}@${p}`,name:h,version:p,gitHead:n,dist:{shasum:E.sha1[0].hexDigest(),integrity:E.sha512[0].toString(),tarball:T.toString()}}},readme:S}}async function $Dt(t){try{let{stdout:e}=await qr.execvp("git",["rev-parse","--revs-only","HEAD"],{cwd:t});return e.trim()===""?void 0:e.trim()}catch{return} Line truncated
`;try{a=await ce.readFilePromise(e,"utf8")}catch(n){if(n.code==="ENOENT")return a;throw n}return a}var DK={npmAlwaysAuth:{description:"URL of the selected npm registry (note: npm enterprise isn't supported)",type:"BOOLEAN",default:!1},npmAuthIdent:{description:"Authentication identity for the npm registry (_auth in npm and yarn v1)",type:"SECRET",default:null},npmAuthToken:{description:"Authentication token for the npm registry (_authToken in npm and yarn v1)",type:"SECRET",default:null}},Hxe={npmAuditRegistry:{description:"Registry to query for audit reports",type:"STRING",default:null},npmPublishRegistry:{description:"Registry to push packages to",type:"STRING",default:null},npmRegistryServer:{description:"URL of the selected npm registry (note: npm enterprise isn't supported)",type:"STRING",default:"https://registry.yarnpkg.com"}},ePt={npmMinimalAgeGate:{description:"Minimum age of a package version according to the publish date on the npm registry in minutes to be considered for installation",type:"NUMBER",default:0},npmPreapprovedPackages:{description:"Array of package descriptors or package name glob patterns to exclude from the minimum release age check",type:"STRING",isArray:!0,default:[]}},tPt={configuration:{...DK,...Hxe,...ePt,npmScopes:{description:"Settings per package scope",type:"MAP",valueDefinition:{description:"",type:"SHAPE",properties:{...DK,...Hxe}}},npmRegistries:{description:"Settings per registry",type:"MAP",normalizeKeys:Jc,valueDefinition:{description:"",type:"SHAPE",properties:{...DK}}}},fetchers:[VD,oh],resolvers:[JD,KD,zD]},rPt=tPt;var OK={};Vt(OK,{NpmAuditCommand:()=>D1,NpmInfoCommand:()=>P1,NpmLoginCommand:()=>b1,NpmLogoutCommand:()=>k1,NpmPublishCommand:()=>Q1,NpmTagAddCommand:()=>T1,NpmTagListCommand:()=>R1,NpmTagRemoveCommand:()=>F1,NpmWhoamiCommand:()=>N1,default:()=>cPt,npmAuditTypes:()=>KP,npmAuditUtils:()=>xL});Ge();Ge();Yt();var RK=ut(Go());Ul();var KP={};Vt(KP,{Environment:()=>VP,Severity:()=>JP});var VP=(s=>(s.All="all",s.Production="production",s.Development="development",s))(VP||{}),JP=(n=>(n.Info="info",n.Low="low",n.Moderate="moderate",n.High="high",n.Critical="critical",n))(JP||{});var xL={};Vt(xL,{allSeverities:()=>S1,getPackages:()=>QK,getReportTree:()=>xK,getSeverityInclusions:()=>bK,getTopLevelDependencies:()=>kK});Ge();var jxe=ut(Ai());var S1=["info","low","moderate","high","critical"];function bK(t){if(typeof t>"u")return new Set(S1);let e=S1.indexOf(t),r=S1.slice(e);return new Set(r)}function xK(t){let e={},r={children:e};for(let[s,a]of je.sortMap(Object.entries(t),n=>n[0]))for(let n of je.sortMap(a,c=>`${c.id}`))e[`${s}/${n.id}`]={value:he.tuple(he.Type.IDENT,G.parseIdent(s)),children:{ID:typeof n.id<"u"&&{label:"ID",value:he.tuple(he.Type.ID,n.id)},Issue:{label:"Issue",value:he.tuple(he.Type.NO_HINT,n.title)},URL:typeof n.url<"u"&&{label:"URL",value:he.tuple(he.Type.URL,n.url)},Severity:{label:"Severity",value:he.tuple(he.Type.NO_HINT,n.severity)},"Vulnerable Versions":{label:"Vulnerable Versions",value:he.tuple(he.Type.RANGE,n.vulnerable_versions)},"Tree Versions":{label:"Tree Versions",children:[...n.versions].sort(jxe.default.compare).map(c=>({value:he.tuple(he.Type.REFERENCE,c)}))},Dependents:{label:"Dependents",children:je.sortMap(n.dependents,c=>G.stringifyLocator(c)).map(c=>({value:he.tuple(he.Type.LOCATOR,c)}))}}};return r}function kK(t,e,{all:r,environment:s}){let a=[],n=r?t.workspaces:[e],c=["all","production"].includes(s),f=["all","development"].includes(s);for(let p of n)for(let h of p.anchoredPackage.dependencies.values())(p.manifest.devDependencies.has(h.identHash)?!f:!c)||a.push({workspace:p,dependency:h});return a}function QK(t,e,{recursive:r}){let s=new Map,a=new Set,n=[],c=(f,p)=>{let h=t.storedResolutions.get(p.descriptorHash);if(typeof h>"u")throw new Error("Assertion failed: The resolution should have been registered");if(!a.has(h))a.add(h);else return;let E=t.storedPackages.get(h);if(typeof E>"u")throw new Error("Assertion failed: The package should have been registered");if(G.ensureDevirtualizedLocator(E).reference.startsWith("npm:")&&E.version!==null){let S=G.stringifyIdent(E),b=je.getMapWithDefault(s,S);je.getArrayWithDefault(b,E.version).push(f)}if(r)for(let S of E.dependencies.values())n.push([E,S])};for(let{workspace:f,dependency:p}of e)n.push([f.anchoredLocator,p]);for(;n.length>0;){let[f,p]=n.shift();c(f,p)}return s}var D1=class extends ft{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Audit dependencies from all workspaces"});this.recursive=ge.Boolean("-R,--recursive",!1,{description:"Audit transitive dependencies as well"});this.environment=ge.String("--environment","all",{description:"Which environments to cover",validator:fo(VP)});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.noDeprecations=ge.Boolean("--no-deprecations",!1,{description:"Don't warn about deprecated packages"});this.severity=ge.String("--severity","info",{description:"Mini Line truncated
This command checks for known security reports on the packages you use. The reports are by default extracted from the npm registry, and may or may not be relevant to your actual program (not all vulnerabilities affect all code paths).
For consistency with our other commands the default is to only check the direct dependencies for the active workspace. To extend this search to all workspaces, use \`-A,--all\`. To extend this search to both direct and transitive dependencies, use \`-R,--recursive\`.
Applying the \`--severity\` flag will limit the audit table to vulnerabilities of the corresponding severity and above. Valid values are ${S1.map(r=>`\`${r}\``).join(", ")}.
If the \`--json\` flag is set, Yarn will print the output exactly as received from the registry. Regardless of this flag, the process will exit with a non-zero exit code if a report is found for the selected packages.
If certain packages produce false positives for a particular environment, the \`--exclude\` flag can be used to exclude any number of packages from the audit. This can also be set in the configuration file with the \`npmAuditExcludePackages\` option.
If particular advisories are needed to be ignored, the \`--ignore\` flag can be used with Advisory ID's to ignore any number of advisories in the audit report. This can also be set in the configuration file with the \`npmAuditIgnoreAdvisories\` option.
To understand the dependency tree requiring vulnerable packages, check the raw report with the \`--json\` flag or use \`yarn why package\` to get more information as to who depends on them.
`,examples:[["Checks for known security issues with the installed packages. The output is a list of known issues.","yarn npm audit"],["Audit dependencies in all workspaces","yarn npm audit --all"],["Limit auditing to `dependencies` (excludes `devDependencies`)","yarn npm audit --environment production"],["Show audit report as valid JSON","yarn npm audit --json"],["Audit all direct and transitive dependencies","yarn npm audit --recursive"],["Output moderate (or more severe) vulnerabilities","yarn npm audit --severity moderate"],["Exclude certain packages","yarn npm audit --exclude package1 --exclude package2"],["Ignore specific advisories","yarn npm audit --ignore 1234567 --ignore 7654321"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState();let n=kK(s,a,{all:this.all,environment:this.environment}),c=QK(s,n,{recursive:this.recursive}),f=Array.from(new Set([...r.get("npmAuditExcludePackages"),...this.excludes])),p=Object.create(null);for(let[N,U]of c)f.some(W=>RK.default.isMatch(N,W))||(p[N]=[...U.keys()]);let h=hi.getAuditRegistry({configuration:r}),E,C=await lA.start({configuration:r,stdout:this.context.stdout},async()=>{let N=an.post("/-/npm/v1/security/advisories/bulk",p,{authType:an.AuthType.BEST_EFFORT,configuration:r,jsonResponse:!0,registry:h}),U=this.noDeprecations?[]:await Promise.all(Array.from(Object.entries(p),async([ee,ie])=>{let ue=await an.getPackageMetadata(G.parseIdent(ee),{project:s});return je.mapAndFilter(ie,le=>{let{deprecated:me}=ue.versions[le];return me?[ee,le,me]:je.mapAndFilter.skip})})),W=await N;for(let[ee,ie,ue]of U.flat(1))Object.hasOwn(W,ee)&&W[ee].some(le=>Fr.satisfiesWithPrereleases(ie,le.vulnerable_versions))||(W[ee]??=[],W[ee].push({id:`${ee} (deprecation)`,title:(typeof ue=="string"?ue:"").trim()||"This package has been deprecated.",severity:"moderate",vulnerable_versions:ie}));E=W});if(C.hasErrors())return C.exitCode();let S=bK(this.severity),b=Array.from(new Set([...r.get("npmAuditIgnoreAdvisories"),...this.ignores])),I=Object.create(null);for(let[N,U]of Object.entries(E)){let W=U.filter(ee=>!RK.default.isMatch(`${ee.id}`,b)&&S.has(ee.severity));W.length>0&&(I[N]=W.map(ee=>{let ie=c.get(N);if(typeof ie>"u")throw new Error("Assertion failed: Expected the registry to only return packages that were requested");let ue=[...ie.keys()].filter(me=>Fr.satisfiesWithPrereleases(me,ee.vulnerable_versions)),le=new Map;for(let me of ue)for(let pe of ie.get(me))le.set(pe.locatorHash,pe);return{...ee,versions:ue,dependents:[...le.values()]}}))}let T=Object.keys(I).length>0;return T?(xs.emitTree(xK(I),{configuration:r,json:this.json,stdout:this.context.stdout,separators:2}),1):(await Ot.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async N=>{N.reportInfo(1,"No audit suggestions")}),T?1:0)}};Ge();Ge();Dt();Yt();var TK=ut(Ai()),FK=Ie("util"),P1=class extends ft{constructor(){super(...arguments);this.fields=ge.String("-f,--fields",{description:"A comma-separated list of manifest fields that should be displayed"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.packages=ge.Rest()}static{this.paths=[["npm","info"]]}static{this.usage=ot.Usage({category:"Npm-related commands",description:"show information about a package",details:"\n This command fetches information about a package from the npm registry and prints it in a tree format.\n\n The package does not have to be installed locally, but needs to have been published (in particular, local changes will be ignored even for workspaces).\n\n Append `@<range>` to the package argument to provide information specific to the latest version that satisfies the range or to the corresponding tagged version. If the range is invalid or if there is no version satisfying the range, the command will print a warning and fall back to the latest version.\n\n If the `-f,--fields` option is set, it's a comma-separated list of fields which will be used to only display part of the package information.\n\n By default, this command won't return the `dist`, `readme`, and `users` fields, since they are often very long. To explicitly request those fields, explicitly list them with the `--fields` flag or request the output in JSON mode.\n ",examples:[["Show all available information about react (except the `dist`, `readme`, and `users` fields)","yarn npm info react"],["Show all available information about react as valid JSON (including the `dist`, `readme`, and `users` fields)","yarn npm info react --json"],["Show all available information about [email protected]","yarn npm info [email protected]"],["Show all available information about react@next","yarn npm info react@next"],["Show the description of react","yarn npm info react --fields description"],["Show all available versions of react","yarn npm info react Line truncated
`),this.context.stdout.write(`${(0,FK.inspect)(p,{depth:1/0,colors:!0,compact:!1})}
`);return f.exitCode()}};function NK(t){if(Array.isArray(t)){let e=[];for(let r of t)r=NK(r),r&&e.push(r);return e}else if(typeof t=="object"&&t!==null){let e={};for(let r of Object.keys(t)){if(r.startsWith("_"))continue;let s=NK(t[r]);s&&(e[r]=s)}return e}else return t||null}Ge();Ge();Yt();var Gxe=ut(Vv()),b1=class extends ft{constructor(){super(...arguments);this.scope=ge.String("-s,--scope",{description:"Login to the registry configured for a given scope"});this.publish=ge.Boolean("--publish",!1,{description:"Login to the publish registry"});this.alwaysAuth=ge.Boolean("--always-auth",{description:"Set the npmAlwaysAuth configuration"})}static{this.paths=[["npm","login"]]}static{this.usage=ot.Usage({category:"Npm-related commands",description:"store new login info to access the npm registry",details:"\n This command will ask you for your username, password, and 2FA One-Time-Password (when it applies). It will then modify your local configuration (in your home folder, never in the project itself) to reference the new tokens thus generated.\n\n Adding the `-s,--scope` flag will cause the authentication to be done against whatever registry is configured for the associated scope (see also `npmScopes`).\n\n Adding the `--publish` flag will cause the authentication to be done against the registry used when publishing the package (see also `publishConfig.registry` and `npmPublishRegistry`).\n ",examples:[["Login to the default registry","yarn npm login"],["Login to the registry linked to the @my-scope registry","yarn npm login --scope my-scope"],["Login to the publish registry for the current package","yarn npm login --publish"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=await kL({configuration:r,cwd:this.context.cwd,publish:this.publish,scope:this.scope});return(await Ot.start({configuration:r,stdout:this.context.stdout,includeFooter:!1},async n=>{let c=await sPt({configuration:r,registry:s,report:n,stdin:this.context.stdin,stdout:this.context.stdout}),f=await nPt(s,c,r);return await iPt(s,f,{alwaysAuth:this.alwaysAuth,scope:this.scope}),n.reportInfo(0,"Successfully logged in")})).exitCode()}};async function kL({scope:t,publish:e,configuration:r,cwd:s}){return t&&e?hi.getScopeRegistry(t,{configuration:r,type:hi.RegistryType.PUBLISH_REGISTRY}):t?hi.getScopeRegistry(t,{configuration:r}):e?hi.getPublishRegistry((await eC(r,s)).manifest,{configuration:r}):hi.getDefaultRegistry({configuration:r})}async function nPt(t,e,r){let s=`/-/user/org.couchdb.user:${encodeURIComponent(e.name)}`,a={_id:`org.couchdb.user:${e.name}`,name:e.name,password:e.password,type:"user",roles:[],date:new Date().toISOString()},n={attemptedAs:e.name,configuration:r,registry:t,jsonResponse:!0,authType:an.AuthType.NO_AUTH};try{return(await an.put(s,a,n)).token}catch(E){if(!(E.originalError?.name==="HTTPError"&&E.originalError?.response.statusCode===409))throw E}let c={...n,authType:an.AuthType.NO_AUTH,headers:{authorization:`Basic ${Buffer.from(`${e.name}:${e.password}`).toString("base64")}`}},f=await an.get(s,c);for(let[E,C]of Object.entries(f))(!a[E]||E==="roles")&&(a[E]=C);let p=`${s}/-rev/${a._rev}`;return(await an.put(p,a,c)).token}async function iPt(t,e,{alwaysAuth:r,scope:s}){let a=c=>f=>{let p=je.isIndexableObject(f)?f:{},h=p[c],E=je.isIndexableObject(h)?h:{};return{...p,[c]:{...E,...r!==void 0?{npmAlwaysAuth:r}:{},npmAuthToken:e}}},n=s?{npmScopes:a(s)}:{npmRegistries:a(t)};return await ze.updateHomeConfiguration(n)}async function sPt({configuration:t,registry:e,report:r,stdin:s,stdout:a}){r.reportInfo(0,`Logging in to ${he.pretty(t,e,he.Type.URL)}`);let n=!1;if(e.match(/^https:\/\/npm\.pkg\.github\.com(\/|$)/)&&(r.reportInfo(0,"You seem to be using the GitHub Package Registry. Tokens must be generated with the 'repo', 'write:packages', and 'read:packages' permissions."),n=!0),r.reportSeparator(),t.env.YARN_IS_TEST_ENV)return{name:t.env.YARN_INJECT_NPM_USER||"",password:t.env.YARN_INJECT_NPM_PASSWORD||""};let c=await(0,Gxe.prompt)([{type:"input",name:"name",message:"Username:",required:!0,onCancel:()=>process.exit(130),stdin:s,stdout:a},{type:"password",name:"password",message:n?"Token:":"Password:",required:!0,onCancel:()=>process.exit(130),stdin:s,stdout:a}]);return r.reportSeparator(),c}Ge();Ge();Yt();var x1=new Set(["npmAuthIdent","npmAuthToken"]),k1=class extends ft{constructor(){super(...arguments);this.scope=ge.String("-s,--scope",{description:"Logout of the registry configured for a given scope"});this.publish=ge.Boolean("--publish",!1,{description:"Logout of the publish registry"});this.all=ge.Boolean("-A,--all",!1,{description:"Logout of all registries"})}static{this.paths=[["npm","logout"]]}static{this.usage=ot.Usage({category:"Npm-related commands",description:"logout of the npm registry",details:"\n This command will log you out by modifying your local configuration (in your home folder, never in the project itself) to delete all credentials linked to a registry.\Line truncated
This command will list all tags of a package from the npm registry.
If the package is not specified, Yarn will default to the current workspace.
`,examples:[["List all tags of package `my-pkg`","yarn npm tag list my-pkg"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n;if(typeof this.package<"u")n=G.parseIdent(this.package);else{if(!a)throw new ar(s.cwd,this.context.cwd);if(!a.manifest.name)throw new nt(`Missing 'name' field in ${fe.fromPortablePath(J.join(a.cwd,Er.manifest))}`);n=a.manifest.name}let c=await zP(n,r),p={children:je.sortMap(Object.entries(c),([h])=>h).map(([h,E])=>({value:he.tuple(he.Type.RESOLUTION,{descriptor:G.makeDescriptor(n,h),locator:G.makeLocator(n,E)})}))};return xs.emitTree(p,{configuration:r,json:this.json,stdout:this.context.stdout})}};async function zP(t,e){let r=`/-/package${an.getIdentUrl(t)}/dist-tags`;return an.get(r,{configuration:e,ident:t,jsonResponse:!0,customErrorMessage:an.customPackageError})}var T1=class extends ft{constructor(){super(...arguments);this.package=ge.String();this.tag=ge.String()}static{this.paths=[["npm","tag","add"]]}static{this.usage=ot.Usage({category:"Npm-related commands",description:"add a tag for a specific version of a package",details:`
This command will add a tag to the npm registry for a specific version of a package. If the tag already exists, it will be overwritten.
`,examples:[["Add a `beta` tag for version `2.3.4-beta.4` of package `my-pkg`","yarn npm tag add [email protected] beta"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);let n=G.parseDescriptor(this.package,!0),c=n.range;if(!Wxe.default.valid(c))throw new nt(`The range ${he.pretty(r,n.range,he.Type.RANGE)} must be a valid semver version`);let f=hi.getPublishRegistry(a.manifest,{configuration:r}),p=he.pretty(r,n,he.Type.IDENT),h=he.pretty(r,c,he.Type.RANGE),E=he.pretty(r,this.tag,he.Type.CODE);return(await Ot.start({configuration:r,stdout:this.context.stdout},async S=>{let b=await zP(n,r);Object.hasOwn(b,this.tag)&&b[this.tag]===c&&S.reportWarning(0,`Tag ${E} is already set to version ${h}`);let I=`/-/package${an.getIdentUrl(n)}/dist-tags/${encodeURIComponent(this.tag)}`;await an.put(I,c,{configuration:r,registry:f,ident:n,jsonRequest:!0,jsonResponse:!0}),S.reportInfo(0,`Tag ${E} added to version ${h} of package ${p}`)})).exitCode()}};Ge();Yt();var F1=class extends ft{constructor(){super(...arguments);this.package=ge.String();this.tag=ge.String()}static{this.paths=[["npm","tag","remove"]]}static{this.usage=ot.Usage({category:"Npm-related commands",description:"remove a tag from a package",details:`
This command will remove a tag from a package from the npm registry.
`,examples:[["Remove the `beta` tag from package `my-pkg`","yarn npm tag remove my-pkg beta"]]})}async execute(){if(this.tag==="latest")throw new nt("The 'latest' tag cannot be removed.");let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);let n=G.parseIdent(this.package),c=hi.getPublishRegistry(a.manifest,{configuration:r}),f=he.pretty(r,this.tag,he.Type.CODE),p=he.pretty(r,n,he.Type.IDENT),h=await zP(n,r);if(!Object.hasOwn(h,this.tag))throw new nt(`${f} is not a tag of package ${p}`);return(await Ot.start({configuration:r,stdout:this.context.stdout},async C=>{let S=`/-/package${an.getIdentUrl(n)}/dist-tags/${encodeURIComponent(this.tag)}`;await an.del(S,{configuration:r,registry:c,ident:n,jsonResponse:!0}),C.reportInfo(0,`Tag ${f} removed from package ${p}`)})).exitCode()}};Ge();Ge();Yt();var N1=class extends ft{constructor(){super(...arguments);this.scope=ge.String("-s,--scope",{description:"Print username for the registry configured for a given scope"});this.publish=ge.Boolean("--publish",!1,{description:"Print username for the publish registry"})}static{this.paths=[["npm","whoami"]]}static{this.usage=ot.Usage({category:"Npm-related commands",description:"display the name of the authenticated user",details:"\n Print the username associated with the current authentication settings to the standard output.\n\n When using `-s,--scope`, the username printed will be the one that matches the authentication settings of the registry associated with the given scope (those settings can be overriden using the `npmRegistries` map, and the registry associated with the scope is configured via the `npmScopes` map).\n\n When using `--publish`, the registry we'll select will by default be the one used when publishing packages (`publishConfig.registry` or `npmPublishRegistry` if available, otherwise we'll fallback to the regular `npmRegistryServer`).\n ",examples:[["Print username for the default registry","yarn npm whoami"],["Print username for the registry on a given scope","yarn npm whoami --scope company"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s;return this.scope&&this.publish?s=hi.getScopeRegistry(this.scope,{configuration:r,type:hi.RegistryType.PUBLISH_REGISTRY}):this.scope?s=hi.getScopeRegistry(this.scope,{configuration:r}):this.publish?s=hi.getPublishRegistry((await eC(r,this.context.cwd)).manifest,{configuration:r}):s=hi.getDefaultRegistry({configuration:r}),(await Ot.start({configuration:r,stdout:this.context.stdout},async n=>{let c;try{c=await an.get("/-/whoami",{configuration:r,registry:s,authType:an.AuthType.ALWAYS_AUTH,jsonResponse:!0,ident:this.scope?G.makeIdent(this.scope,""):void 0})}catch(f){if(f.response?.statusCode===401||f.response?.statusCode===403){n.reportError(41,"Authentication failed - your credentials may have expired");return}else throw f}n.reportInfo(0,c.username)})).exitCode()}};var lPt={configuration:{npmPublishAccess:{description:"Default access of the published packages",type:"STRING",default:null},npmPublishProvenance:{description:"Whether to generate provenance for the published packages",type:"BOOLEAN",default:!1},npmAuditExcludePackages:{description:"Array of glob patterns of packages to exclude from npm audit",type:"STRING",default:[],isArray:!0},npmAuditIgnoreAdvisories:{description:"Array of glob patterns of advisory IDs to exclude from npm audit",type:"STRING",default:[],isArray:!0}},commands:[D1,P1,b1,k1,Q1,T1,R1,F1,N1]},cPt=lPt;var GK={};Vt(GK,{PatchCommand:()=>H1,PatchCommitCommand:()=>_1,PatchFetcher:()=>tb,PatchResolver:()=>rb,default:()=>PPt,patchUtils:()=>gy});Ge();Ge();Dt();eA();var gy={};Vt(gy,{applyPatchFile:()=>RL,diffFolders:()=>HK,ensureUnpatchedDescriptor:()=>LK,ensureUnpatchedLocator:()=>FL,extractPackageToDisk:()=>_K,extractPatchFlags:()=>Xxe,isParentRequired:()=>UK,isPatchDescriptor:()=>TL,isPatchLocator:()=>Tg,loadPatchFiles:()=>eb,makeDescriptor:()=>NL,makeLocator:()=>MK,makePatchHash:()=>jK,parseDescriptor:()=>XP,parseLocator:()=>$P,parsePatchFile:()=>ZP,unpatchDescriptor:()=>vPt,unpatchLocator:()=>SPt});Ge();Dt();Ge();Dt();var uPt=/^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@.*/;function O1(t){return J.relative(vt.root,J.resolve(vt.root,fe.toPortablePath(t)))}function fPt(t){let e=t.trim().match(uPt);if(!e)throw new Error(`Bad header line: '${t}'`);return{original:{start:Math.max(Number(e[1]),1),length:Number(e[3]||1)},patched:{start:Math.max(Number(e[4]),1),length:Number(e[6]||1)}}}var APt=420,pPt=493;var Yxe=()=>({semverExclusivity:null,diffLineFromPath:null,diffLineToPath:null,oldMode:null,newMode:null,deletedFileMode:null,newFileMode:null,renameFrom:null,renameTo:null,beforeHash:null,afterHash:null,fromPath:null,toPath:null,hunks:null}),hPt=t=>({header:fPt(t),parts:[]}),gPt={"@":"header","-":"deletion","+":"insertion"," ":"context","\\":"pragma",undefined:"context"};function dPt(t){let e=[],r=Line truncated
`)+(a.hunk.parts[0].noNewlineAtEndOfFile?"":`
`):"";await e.mkdirpPromise(J.dirname(a.path),{chmod:493,utimes:[fi.SAFE_TIME,fi.SAFE_TIME]}),await e.writeFilePromise(a.path,n,{mode:a.mode}),await e.utimesPromise(a.path,fi.SAFE_TIME,fi.SAFE_TIME)}break;case"patch":await M1(e,a.path,async()=>{await CPt(a,{baseFs:e,dryRun:r})});break;case"mode change":{let c=(await e.statPromise(a.path)).mode;if(Vxe(a.newMode)!==Vxe(c))continue;await M1(e,a.path,async()=>{await e.chmodPromise(a.path,a.newMode)})}break;default:je.assertNever(a);break}}function Vxe(t){return(t&64)>0}function Jxe(t){return t.replace(/\s+$/,"")}function IPt(t,e){return Jxe(t)===Jxe(e)}async function CPt({hunks:t,path:e},{baseFs:r,dryRun:s=!1}){let a=await r.statSync(e).mode,c=(await r.readFileSync(e,"utf8")).split(/\n/),f=[],p=0,h=0;for(let C of t){let S=Math.max(h,C.header.patched.start+p),b=Math.max(0,S-h),I=Math.max(0,c.length-S-C.header.original.length),T=Math.max(b,I),N=0,U=0,W=null;for(;N<=T;){if(N<=b&&(U=S-N,W=Kxe(C,c,U),W!==null)){N=-N;break}if(N<=I&&(U=S+N,W=Kxe(C,c,U),W!==null))break;N+=1}if(W===null)throw new L1(t.indexOf(C),C);f.push(W),p+=N,h=U+C.header.original.length}if(s)return;let E=0;for(let C of f)for(let S of C)switch(S.type){case"splice":{let b=S.index+E;c.splice(b,S.numToDelete,...S.linesToInsert),E+=S.linesToInsert.length-S.numToDelete}break;case"pop":c.pop();break;case"push":c.push(S.line);break;default:je.assertNever(S);break}await r.writeFilePromise(e,c.join(`
`),{mode:a})}function Kxe(t,e,r){let s=[];for(let a of t.parts)switch(a.type){case"context":case"deletion":{for(let n of a.lines){let c=e[r];if(c==null||!IPt(c,n))return null;r+=1}a.type==="deletion"&&(s.push({type:"splice",index:r-a.lines.length,numToDelete:a.lines.length,linesToInsert:[]}),a.noNewlineAtEndOfFile&&s.push({type:"push",line:""}))}break;case"insertion":s.push({type:"splice",index:r,numToDelete:0,linesToInsert:a.lines}),a.noNewlineAtEndOfFile&&s.push({type:"pop"});break;default:je.assertNever(a.type);break}return s}var BPt=/^builtin<([^>]+)>$/;function U1(t,e){let{protocol:r,source:s,selector:a,params:n}=G.parseRange(t);if(r!=="patch:")throw new Error("Invalid patch range");if(s===null)throw new Error("Patch locators must explicitly define their source");let c=a?a.split(/&/).map(E=>fe.toPortablePath(E)):[],f=n&&typeof n.locator=="string"?G.parseLocator(n.locator):null,p=n&&typeof n.version=="string"?n.version:null,h=e(s);return{parentLocator:f,sourceItem:h,patchPaths:c,sourceVersion:p}}function TL(t){return t.range.startsWith("patch:")}function Tg(t){return t.reference.startsWith("patch:")}function XP(t){let{sourceItem:e,...r}=U1(t.range,G.parseDescriptor);return{...r,sourceDescriptor:e}}function $P(t){let{sourceItem:e,...r}=U1(t.reference,G.parseLocator);return{...r,sourceLocator:e}}function vPt(t){let{sourceItem:e}=U1(t.range,G.parseDescriptor);return e}function SPt(t){let{sourceItem:e}=U1(t.reference,G.parseLocator);return e}function LK(t){if(!TL(t))return t;let{sourceItem:e}=U1(t.range,G.parseDescriptor);return e}function FL(t){if(!Tg(t))return t;let{sourceItem:e}=U1(t.reference,G.parseLocator);return e}function zxe({parentLocator:t,sourceItem:e,patchPaths:r,sourceVersion:s,patchHash:a},n){let c=t!==null?{locator:G.stringifyLocator(t)}:{},f=typeof s<"u"?{version:s}:{},p=typeof a<"u"?{hash:a}:{};return G.makeRange({protocol:"patch:",source:n(e),selector:r.join("&"),params:{...f,...p,...c}})}function NL(t,{parentLocator:e,sourceDescriptor:r,patchPaths:s}){return G.makeDescriptor(t,zxe({parentLocator:e,sourceItem:r,patchPaths:s},G.stringifyDescriptor))}function MK(t,{parentLocator:e,sourcePackage:r,patchPaths:s,patchHash:a}){return G.makeLocator(t,zxe({parentLocator:e,sourceItem:r,sourceVersion:r.version,patchPaths:s,patchHash:a},G.stringifyLocator))}function Zxe({onAbsolute:t,onRelative:e,onProject:r,onBuiltin:s},a){let n=a.lastIndexOf("!");n!==-1&&(a=a.slice(n+1));let c=a.match(BPt);return c!==null?s(c[1]):a.startsWith("~/")?r(a.slice(2)):J.isAbsolute(a)?t(a):e(a)}function Xxe(t){let e=t.lastIndexOf("!");return{optional:(e!==-1?new Set(t.slice(0,e).split(/!/)):new Set).has("optional")}}function UK(t){return Zxe({onAbsolute:()=>!1,onRelative:()=>!0,onProject:()=>!1,onBuiltin:()=>!1},t)}async function eb(t,e,r){let s=t!==null?await r.fetcher.fetch(t,r):null,a=s&&s.localPath?{packageFs:new Sn(vt.root),prefixPath:J.relative(vt.root,s.localPath)}:s;s&&s!==a&&s.releaseFs&&s.releaseFs();let n=await je.releaseAfterUseAsync(async()=>await Promise.all(e.map(async c=>{let f=Xxe(c),p=await Zxe({onAbsolute:async h=>await ce.readFilePromise(h,"utf8"),onRelative:async h=>{if(a===null)throw new Error("Assertion failed: The parent locator should have been fetched");return await a.packageFs.readFilePromise(J.join(a.prefixPath,h),"utf8")},onProject:async h=>await ce.readFilePromise(J.join(r.project.cwd,h),"utf8"),onBuiltin:async h=>await r.project.configuration.firstHook(E=>E.getBuiltinPatch,r.project,h)},c);return{...f,source:p}})));for(let c of n)typeof c.source=="string"&&(c.source=c.source.replace(/\r\n?/g,`
`));return n}async function _K(t,{cache:e,project:r}){let s=r.storedPackages.get(t.locatorHash);if(typeof s>"u")throw new Error("Assertion failed: Expected the package to be registered");let a=FL(t),n=r.storedChecksums,c=new ki,f=await ce.mktempPromise(),p=J.join(f,"source"),h=J.join(f,"user"),E=J.join(f,".yarn-patch.json"),C=r.configuration.makeFetcher(),S=[];try{let b,I;if(t.locatorHash===a.locatorHash){let T=await C.fetch(t,{cache:e,project:r,fetcher:C,checksums:n,report:c});S.push(()=>T.releaseFs?.()),b=T,I=T}else b=await C.fetch(t,{cache:e,project:r,fetcher:C,checksums:n,report:c}),S.push(()=>b.releaseFs?.()),I=await C.fetch(t,{cache:e,project:r,fetcher:C,checksums:n,report:c}),S.push(()=>I.releaseFs?.());await Promise.all([ce.copyPromise(p,b.prefixPath,{baseFs:b.packageFs}),ce.copyPromise(h,I.prefixPath,{baseFs:I.packageFs}),ce.writeJsonPromise(E,{locator:G.stringifyLocator(t),version:s.version})])}finally{for(let b of S)b()}return ce.detachTemp(f),h}async function HK(t,e){let r=fe.fromPortablePath(t).replace(/\\/g,"/"),s=fe.fromPortablePath(e).replace(/\\/g,"/"),{stdout:a,stderr:n}=await qr.execvp("git",["-c","core.safecrlf=false","diff","--src-prefix=a/","--dst-prefix=b/","--ignore-cr-at-eol","--full-index","--no-index","--no-renames","--text",r,s],{cwd:fe.toPortablePath(process.cwd()),env:{...process.env,GIT_CONFIG_NOSYSTEM:"1",HOME:"",XDG_CONFIG_HOME:"",USERPROFILE:""}});if(n.length>0)throw new Error(`Unable to diff directories. Make sure you have a recent version of 'git' available in PATH.
The following error was reported by 'git':
${n}`);let c=r.startsWith("/")?f=>f.slice(1):f=>f;return a.replace(new RegExp(`(a|b)(${je.escapeRegExp(`/${c(r)}/`)})`,"g"),"$1/").replace(new RegExp(`(a|b)${je.escapeRegExp(`/${c(s)}/`)}`,"g"),"$1/").replace(new RegExp(je.escapeRegExp(`${r}/`),"g"),"").replace(new RegExp(je.escapeRegExp(`${s}/`),"g"),"")}function jK(t,e){let r=[];for(let{source:s}of t){if(s===null)continue;let a=ZP(s);for(let n of a){let{semverExclusivity:c,...f}=n;c!==null&&e!==null&&!Fr.satisfiesWithPrereleases(e,c)||r.push(JSON.stringify(f))}}return Nn.makeHash(`${3}`,...r).slice(0,6)}Ge();function $xe(t,{configuration:e,report:r}){for(let s of t.parts)for(let a of s.lines)switch(s.type){case"context":r.reportInfo(null,` ${he.pretty(e,a,"grey")}`);break;case"deletion":r.reportError(28,`- ${he.pretty(e,a,he.Type.REMOVED)}`);break;case"insertion":r.reportError(28,`+ ${he.pretty(e,a,he.Type.ADDED)}`);break;default:je.assertNever(s.type)}}var tb=class{supports(e,r){return!!Tg(e)}getLocalPath(e,r){return null}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.patchPackage(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:c}}async patchPackage(e,r){let{parentLocator:s,sourceLocator:a,sourceVersion:n,patchPaths:c}=$P(e),f=await eb(s,c,r),p=await ce.mktempPromise(),h=J.join(p,"current.zip"),E=await r.fetcher.fetch(a,r),C=G.getIdentVendorPath(e),S=new As(h,{create:!0,level:r.project.configuration.get("compressionLevel")});await je.releaseAfterUseAsync(async()=>{await S.copyPromise(C,E.prefixPath,{baseFs:E.packageFs,stableSort:!0})},E.releaseFs),S.saveAndClose();for(let{source:b,optional:I}of f){if(b===null)continue;let T=new As(h,{level:r.project.configuration.get("compressionLevel")}),N=new Sn(J.resolve(vt.root,C),{baseFs:T});try{await RL(ZP(b),{baseFs:N,version:n})}catch(U){if(!(U instanceof L1))throw U;let W=r.project.configuration.get("enableInlineHunks"),ee=!W&&!I?" (set enableInlineHunks for details)":"",ie=`${G.prettyLocator(r.project.configuration,e)}: ${U.message}${ee}`,ue=le=>{W&&$xe(U.hunk,{configuration:r.project.configuration,report:le})};if(T.discardAndClose(),I){r.report.reportWarningOnce(66,ie,{reportExtra:ue});continue}else throw new jt(66,ie,ue)}T.saveAndClose()}return new As(h,{level:r.project.configuration.get("compressionLevel")})}};Ge();var rb=class{supportsDescriptor(e,r){return!!TL(e)}supportsLocator(e,r){return!!Tg(e)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,s){let{patchPaths:a}=XP(e);return a.every(n=>!UK(n))?e:G.bindDescriptor(e,{locator:G.stringifyLocator(r)})}getResolutionDependencies(e,r){let{sourceDescriptor:s}=XP(e);return{sourceDescriptor:r.project.configuration.normalizeDependency(s)}}async getCandidates(e,r,s){if(!s.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let{parentLocator:a,patchPaths:n}=XP(e),c=await eb(a,n,s.fetchOptions),f=r.sourceDescriptor;if(typeof f>"u")throw new Error("Assertion failed: The dependency should have been resolved");let p=jK(c,f.version);return[MK(e,{parentLocator:a,sourcePackage:f,patchPaths:n,patchHash:p})]}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){let{sourceLocator:s}=$P(e);return{...await r.resolver.resolve(s,r),...e}}};Ge();Dt();Yt();var _1=class extends ft{constructor(){super(...arguments);this.save=ge.Boolean("-s,--save",!1,{description:"Add the patch to your resolution entries"});this.patchFolder=ge.String()}static{this.paths=[["patch-commit"]]}static{this.usage=ot.Usage({description:"generate a patch out of a directory",details:"\n By default, this will print a patchfile on stdout based on the diff between the folder passed in and the original version of the package. Such file is suitable for consumption with the `patch:` protocol.\n\n With the `-s,--save` option set, the patchfile won't be printed on stdout anymore and will instead be stored within a local file (by default kept within `.yarn/patches`, but configurable via the `patchFolder` setting). A `resolutions` entry will also be added to your top-level manifest, referencing the patched package via the `patch:` protocol.\n\n Note that only folders generated by `yarn patch` are accepted as valid input for `yarn patch-commit`.\n "})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState();let n=J.resolve(this.context.cwd,fe.toPortablePath(this.patchFolder)),c=J.join(n,"../source"),f=J.join(n,"../.yarn-patch.json");if(!ce.existsSLine truncated
${f.map(p=>`
- ${G.prettyLocator(r,p)}`).join("")}`);c=f[0]}if(!s.storedPackages.has(c.locatorHash))throw new nt("No package found in the project for the given locator");await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async f=>{let p=FL(c),h=await _K(c,{cache:n,project:s});f.reportJson({locator:G.stringifyLocator(p),path:fe.fromPortablePath(h)});let E=this.update?" along with its current modifications":"";f.reportInfo(0,`Package ${G.prettyLocator(r,p)} got extracted with success${E}!`),f.reportInfo(0,`You can now edit the following folder: ${he.pretty(r,fe.fromPortablePath(h),"magenta")}`),f.reportInfo(0,`Once you are done run ${he.pretty(r,`yarn patch-commit -s ${process.platform==="win32"?'"':""}${fe.fromPortablePath(h)}${process.platform==="win32"?'"':""}`,"cyan")} and Yarn will store a patchfile based on your changes.`)})}};var DPt={configuration:{enableInlineHunks:{description:"If true, the installs will print unmatched patch hunks",type:"BOOLEAN",default:!1},patchFolder:{description:"Folder where the patch files must be written",type:"ABSOLUTE_PATH",default:"./.yarn/patches"}},commands:[_1,H1],fetchers:[tb],resolvers:[rb]},PPt=DPt;var YK={};Vt(YK,{PnpmLinker:()=>nb,default:()=>TPt});Ge();Dt();Yt();var nb=class{getCustomDataKey(){return JSON.stringify({name:"PnpmLinker",version:3})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error("Assertion failed: Expected the pnpm linker to be enabled");let s=this.getCustomDataKey(),a=r.project.linkersCustomData.get(s);if(!a)throw new nt(`The project in ${he.pretty(r.project.configuration,`${r.project.cwd}/package.json`,he.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let n=a.pathsByLocator.get(e.locatorHash);if(typeof n>"u")throw new nt(`Couldn't find ${G.prettyLocator(r.project.configuration,e)} in the currently installed pnpm map - running an install might help`);return n.packageLocation}async findPackageLocator(e,r){if(!this.isEnabled(r))return null;let s=this.getCustomDataKey(),a=r.project.linkersCustomData.get(s);if(!a)throw new nt(`The project in ${he.pretty(r.project.configuration,`${r.project.cwd}/package.json`,he.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let n=e.match(/(^.*\/node_modules\/(@[^/]*\/)?[^/]+)(\/.*$)/);if(n){let p=a.locatorByPath.get(n[1]);if(p)return p}let c=e,f=e;do{f=c,c=J.dirname(f);let p=a.locatorByPath.get(f);if(p)return p}while(c!==f);return null}makeInstaller(e){return new qK(e)}isEnabled(e){return e.project.configuration.get("nodeLinker")==="pnpm"}},qK=class{constructor(e){this.opts=e;this.asyncActions=new je.AsyncActions(10);this.customData={pathsByLocator:new Map,locatorByPath:new Map};this.indexFolderPromise=$b(ce,{indexPath:J.join(e.project.configuration.get("globalFolder"),"index")})}attachCustomData(e){}async installPackage(e,r,s){switch(e.linkType){case"SOFT":return this.installPackageSoft(e,r,s);case"HARD":return this.installPackageHard(e,r,s)}throw new Error("Assertion failed: Unsupported package link type")}async installPackageSoft(e,r,s){let a=J.resolve(r.packageFs.getRealPath(),r.prefixPath),n=this.opts.project.tryWorkspaceByLocator(e)?J.join(a,Er.nodeModules):null;return this.customData.pathsByLocator.set(e.locatorHash,{packageLocation:a,dependenciesLocation:n}),{packageLocation:a,buildRequest:null}}async installPackageHard(e,r,s){let a=xPt(e,{project:this.opts.project}),n=a.packageLocation;this.customData.locatorByPath.set(n,G.stringifyLocator(e)),this.customData.pathsByLocator.set(e.locatorHash,a),s.holdFetchResult(this.asyncActions.set(e.locatorHash,async()=>{await ce.mkdirPromise(n,{recursive:!0}),await ce.copyPromise(n,r.prefixPath,{baseFs:r.packageFs,overwrite:!1,linkStrategy:{type:"HardlinkFromIndex",indexPath:await this.indexFolderPromise,autoRepair:!0}})}));let f=G.isVirtualLocator(e)?G.devirtualizeLocator(e):e,p={manifest:await Ut.tryFind(r.prefixPath,{baseFs:r.packageFs})??new Ut,misc:{hasBindingGyp:gA.hasBindingGyp(r)}},h=this.opts.project.getDependencyMeta(f,e.version),E=gA.extractBuildRequest(e,p,h,{configuration:this.opts.project.configuration});return{packageLocation:n,buildRequest:E}}async attachInternalDependencies(e,r){if(this.opts.project.configuration.get("nodeLinker")!=="pnpm"||!eke(e,{project:this.opts.project}))return;let s=this.customData.pathsByLocator.get(e.locatorHash);if(typeof s>"u")throw new Error(`Assertion failed: Expected the package to have been registered (${G.stringifyLocator(e)})`);let{dependenciesLocation:a}=s;a&&this.asyncActions.reduce(e.locatorHash,async n=>{await ce.mkdirPromise(a,{recursive:!0});let c=await kPt(a),f=new Map(c),p=[n],h=(C,S)=>{let b=S;eke(S,{project:this.opts.project})||(this.opts.report.reportWarningOnce(0,"The pnpm linker doesn't support providing different versions to workspaces' peer dependencies"),b=G.devirtualizeLocator(S));let I=this.customData.pathsByLocator.get(b.locatorHash);if(typeof I>"Line truncated
${NPt}
`,"--",...s],{cwd:t,strict:!0})},async makeReset(t,e){let r=e.map(s=>fe.fromPortablePath(s.path));await qr.execvp("git",["reset","HEAD","--",...r],{cwd:t,strict:!0})}};var _Pt=[ike],j1=class extends ft{constructor(){super(...arguments);this.commit=ge.Boolean("-c,--commit",!1,{description:"Commit the staged files"});this.reset=ge.Boolean("-r,--reset",!1,{description:"Remove all files from the staging area"});this.dryRun=ge.Boolean("-n,--dry-run",!1,{description:"Print the commit message and the list of modified files without staging / committing"});this.update=ge.Boolean("-u,--update",!1,{hidden:!0})}static{this.paths=[["stage"]]}static{this.usage=ot.Usage({description:"add all yarn files to your vcs",details:"\n This command will add to your staging area the files belonging to Yarn (typically any modified `package.json` and `.yarnrc.yml` files, but also linker-generated files, cache data, etc). It will take your ignore list into account, so the cache files won't be added if the cache is ignored in a `.gitignore` file (assuming you use Git).\n\n Running `--reset` will instead remove them from the staging area (the changes will still be there, but won't be committed until you stage them back).\n\n Since the staging area is a non-existent concept in Mercurial, Yarn will always create a new commit when running this command on Mercurial repositories. You can get this behavior when using Git by using the `--commit` flag which will directly create a commit.\n ",examples:[["Adds all modified project files to the staging area","yarn stage"],["Creates a new commit containing all modified project files","yarn stage --commit"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Rt.find(r,this.context.cwd),{driver:a,root:n}=await HPt(s.cwd),c=[r.get("cacheFolder"),r.get("globalFolder"),r.get("virtualFolder"),r.get("yarnPath")];await r.triggerHook(C=>C.populateYarnPaths,s,C=>{c.push(C)});let f=new Set;for(let C of c)for(let S of jPt(n,C))f.add(S);let p=new Set([r.get("rcFilename"),Er.lockfile,Er.manifest]),h=await a.filterChanges(n,f,p),E=await a.genCommitMessage(n,h);if(this.dryRun)if(this.commit)this.context.stdout.write(`${E}
`);else for(let C of h)this.context.stdout.write(`${fe.fromPortablePath(C.path)}
`);else if(this.reset){let C=await a.filterChanges(n,f,p,{staged:!0});C.length===0?this.context.stdout.write("No staged changes found!"):await a.makeReset(n,C)}else h.length===0?this.context.stdout.write("No changes found!"):this.commit?await a.makeCommit(n,h,E):(await a.makeStage(n,h),this.context.stdout.write(E))}};async function HPt(t){let e=null,r=null;for(let s of _Pt)if((r=await s.findRoot(t))!==null){e=s;break}if(e===null||r===null)throw new nt("No stage driver has been found for your current project");return{driver:e,root:r}}function jPt(t,e){let r=[];if(e===null)return r;for(;;){(e===t||e.startsWith(`${t}/`))&&r.push(e);let s;try{s=ce.statSync(e)}catch{break}if(s.isSymbolicLink())e=J.resolve(J.dirname(e),ce.readlinkSync(e));else break}return r}var GPt={commands:[j1]},qPt=GPt;var ez={};Vt(ez,{default:()=>XPt});Ge();Ge();Dt();var ake=ut(Ai());Ge();var ske=ut(l9()),WPt="e8e1bd300d860104bb8c58453ffa1eb4",YPt="OFCNCOG2CU",oke=async(t,e)=>{let r=G.stringifyIdent(t),a=VPt(e).initIndex("npm-search");try{return(await a.getObject(r,{attributesToRetrieve:["types"]})).types?.ts==="definitely-typed"}catch{return!1}},VPt=t=>(0,ske.default)(YPt,WPt,{requester:{async send(r){try{let s=await ln.request(r.url,r.data||null,{configuration:t,headers:r.headers});return{content:s.body,isTimedOut:!1,status:s.statusCode}}catch(s){return{content:s.response.body,isTimedOut:!1,status:s.response.statusCode}}}}});var lke=t=>t.scope?`${t.scope}__${t.name}`:`${t.name}`,JPt=async(t,e,r,s)=>{if(r.scope==="types")return;let{project:a}=t,{configuration:n}=a;if(!(n.get("tsEnableAutoTypes")??(ce.existsSync(J.join(t.cwd,"tsconfig.json"))||ce.existsSync(J.join(a.cwd,"tsconfig.json")))))return;let f=n.makeResolver(),p={project:a,resolver:f,report:new ki};if(!await oke(r,n))return;let E=lke(r),C=G.parseRange(r.range).selector;if(!Fr.validRange(C)){let N=n.normalizeDependency(r),U=await f.getCandidates(N,{},p);C=G.parseRange(U[0].reference).selector}let S=ake.default.coerce(C);if(S===null)return;let b=`${Zu.Modifier.CARET}${S.major}`,I=G.makeDescriptor(G.makeIdent("types",E),b),T=je.mapAndFind(a.workspaces,N=>{let U=N.manifest.dependencies.get(r.identHash)?.descriptorHash,W=N.manifest.devDependencies.get(r.identHash)?.descriptorHash;if(U!==r.descriptorHash&&W!==r.descriptorHash)return je.mapAndFind.skip;let ee=[];for(let ie of Ut.allDependencies){let ue=N.manifest[ie].get(I.identHash);typeof ue>"u"||ee.push([ie,ue])}return ee.length===0?je.mapAndFind.skip:ee});if(typeof T<"u")for(let[N,U]of T)t.manifest[N].set(U.identHash,U);else{try{let N=n.normalizeDependency(I);if((await f.getCandidates(N,{},p)).length===0)return}catch{return}t.manifest[Zu.Target.DEVELOPMENT].set(I.identHash,I)}},KPt=async(t,e,r)=>{if(r.scope==="types")return;let{project:s}=t,{configuration:a}=s;if(!(a.get("tsEnableAutoTypes")??(ce.existsSync(J.join(t.cwd,"tsconfig.json"))||ce.existsSync(J.join(s.cwd,"tsconfig.json")))))return;let c=lke(r),f=G.makeIdent("types",c);for(let p of Ut.allDependencies)typeof t.manifest[p].get(f.identHash)>"u"||t.manifest[p].delete(f.identHash)},zPt=(t,e)=>{e.publishConfig&&e.publishConfig.typings&&(e.typings=e.publishConfig.typings),e.publishConfig&&e.publishConfig.types&&(e.types=e.publishConfig.types)},ZPt={configuration:{tsEnableAutoTypes:{description:"Whether Yarn should auto-install @types/ dependencies on 'yarn add'",type:"BOOLEAN",isNullable:!0,default:null}},hooks:{afterWorkspaceDependencyAddition:JPt,afterWorkspaceDependencyRemoval:KPt,beforeWorkspacePacking:zPt}},XPt=ZPt;var sz={};Vt(sz,{VersionApplyCommand:()=>Y1,VersionCheckCommand:()=>V1,VersionCommand:()=>J1,default:()=>nbt,versionUtils:()=>W1});Ge();Ge();Yt();var W1={};Vt(W1,{Decision:()=>G1,applyPrerelease:()=>cke,applyReleases:()=>iz,applyStrategy:()=>ib,clearVersionFiles:()=>tz,getUndecidedDependentWorkspaces:()=>ob,getUndecidedWorkspaces:()=>ML,openVersionFile:()=>q1,requireMoreDecisions:()=>ebt,resolveVersionFiles:()=>sb,suggestStrategy:()=>nz,updateVersionFiles:()=>rz,validateReleaseDecision:()=>dy});Ge();Dt();wc();Yt();ql();var kA=ut(Ai()),$Pt=/^(>=|[~^]|)(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(-(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\+[0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*)?$/,G1=(h=>(h.UNDECIDED="undecided",h.DECLINE="decline",h.MAJOR="major",h.MINOR="minor",h.PATCH="patch",h.PREMAJOR="premajor",h.PREMINOR="preminor",h.PREPATCH="prepatch",h.PRERELEASE="prerelease",h))(G1||{});function dy(t){let e=kA.default.valid(t);return e||je.validateEnum(N4(G1,"UNDECIDED"),t)}async function sb(t,{prerelease:e=null}={}){let r=new Map,s=t.configuration.get("deferredVersionFolder");if(!ce.existsSync(s))return r;let a=await ce.readdirPromise(s);for(let n of a){if(!n.endsWith(".yml"))continue;let c=J.join(s,n),f=await ce.readFilePromise(c,"utf8"),p=as(f);for(let[h,E]of Object.entries(p.releases||{})){if(E==="decline")continue;let C=G.parseIdent(h),S=t.tryWorkspaceByIdent(C);if(S===null)throw new Error(`Assertion failed: Expected a release definitioLine truncated
- ${f.map(b=>fe.fromPortablePath(b)).join(`
- `)}`);let p=new Set(je.mapAndFilter(n,b=>{let I=t.tryWorkspaceByFilePath(b);return I===null?je.mapAndFilter.skip:I}));if(f.length===0&&p.size===0&&!e)return null;let h=f.length===1?f[0]:J.join(c,`${Nn.makeHash(Math.random().toString()).slice(0,8)}.yml`),E=ce.existsSync(h)?await ce.readFilePromise(h,"utf8"):"{}",C=as(E),S=new Map;for(let b of C.declined||[]){let I=G.parseIdent(b),T=t.getWorkspaceByIdent(I);S.set(T,"decline")}for(let[b,I]of Object.entries(C.releases||{})){let T=G.parseIdent(b),N=t.getWorkspaceByIdent(T);S.set(N,dy(I))}return{project:t,root:s,baseHash:a!==null?a.hash:null,baseTitle:a!==null?a.title:null,changedFiles:new Set(n),changedWorkspaces:p,releaseRoots:new Set([...p].filter(b=>b.manifest.version!==null)),releases:S,async saveAll(){let b={},I=[],T=[];for(let N of t.workspaces){if(N.manifest.version===null)continue;let U=G.stringifyIdent(N.anchoredLocator),W=S.get(N);W==="decline"?I.push(U):typeof W<"u"?b[U]=dy(W):p.has(N)&&T.push(U)}await ce.mkdirPromise(J.dirname(h),{recursive:!0}),await ce.changeFilePromise(h,nl(new nl.PreserveOrdering({releases:Object.keys(b).length>0?b:void 0,declined:I.length>0?I:void 0,undecided:T.length>0?T:void 0})))}}}function ebt(t){return ML(t).size>0||ob(t).length>0}function ML(t){let e=new Set;for(let r of t.changedWorkspaces)r.manifest.version!==null&&(t.releases.has(r)||e.add(r));return e}function ob(t,{include:e=new Set}={}){let r=[],s=new Map(je.mapAndFilter([...t.releases],([n,c])=>c==="decline"?je.mapAndFilter.skip:[n.anchoredLocator.locatorHash,n])),a=new Map(je.mapAndFilter([...t.releases],([n,c])=>c!=="decline"?je.mapAndFilter.skip:[n.anchoredLocator.locatorHash,n]));for(let n of t.project.workspaces)if(!(!e.has(n)&&(a.has(n.anchoredLocator.locatorHash)||s.has(n.anchoredLocator.locatorHash)))&&n.manifest.version!==null)for(let c of Ut.hardDependencies)for(let f of n.manifest.getForScope(c).values()){let p=t.project.tryWorkspaceByDescriptor(f);p!==null&&s.has(p.anchoredLocator.locatorHash)&&r.push([n,p])}return r}function nz(t,e){let r=kA.default.clean(e);for(let s of Object.values(G1))if(s!=="undecided"&&s!=="decline"&&kA.default.inc(t,s)===r)return s;return null}function ib(t,e){if(kA.default.valid(e))return e;if(t===null)throw new nt(`Cannot apply the release strategy "${e}" unless the workspace already has a valid version`);if(!kA.default.valid(t))throw new nt(`Cannot apply the release strategy "${e}" on a non-semver version (${t})`);let r=kA.default.inc(t,e);if(r===null)throw new nt(`Cannot apply the release strategy "${e}" on the specified version (${t})`);return r}function iz(t,e,{report:r,exact:s}){let a=new Map;for(let n of t.workspaces)for(let c of Ut.allDependencies)for(let f of n.manifest[c].values()){let p=t.tryWorkspaceByDescriptor(f);if(p===null||!e.has(p))continue;je.getArrayWithDefault(a,p).push([n,c,f.identHash])}for(let[n,c]of e){let f=n.manifest.version;n.manifest.version=c,kA.default.prerelease(c)===null?delete n.manifest.raw.stableVersion:n.manifest.raw.stableVersion||(n.manifest.raw.stableVersion=f);let p=n.manifest.name!==null?G.stringifyIdent(n.manifest.name):null;r.reportInfo(0,`${G.prettyLocator(t.configuration,n.anchoredLocator)}: Bumped to ${c}`),r.reportJson({cwd:fe.fromPortablePath(n.cwd),ident:p,oldVersion:f,newVersion:c});let h=a.get(n);if(!(typeof h>"u"))for(let[E,C,S]of h){let b=E.manifest[C].get(S);if(typeof b>"u")throw new Error("Assertion failed: The dependency should have existed");let I=b.range,T=!1;if(I.startsWith(Ei.protocol)&&(I=I.slice(Ei.protocol.length),T=!0,I===n.relativeCwd))continue;let N=I.match($Pt);if(!N){r.reportWarning(0,`Couldn't auto-upgrade range ${I} (in ${G.prettyLocator(t.configuration,E.anchoredLocator)})`);continue}let U=s?`${c}`:`${N[1]}${c}`;T&&(U=`${Ei.protocol}${U}`);let W=G.makeDescriptor(b,U);E.manifest[C].set(S,W)}}}var tbt=new Map([["%n",{extract:t=>t.length>=1?[t[0],t.slice(1)]:null,generate:(t=0)=>`${t+1}`}]]);function cke(t,{current:e,prerelease:r}){let s=new kA.default.SemVer(e),a=s.prerelease.slice(),n=[];s.prerelease=[],s.format()!==t&&(a.length=0);let c=!0,f=r.split(/\./g);for(let p of f){let h=tbt.get(p);if(typeof h>"u")n.push(p),a[0]===p?a.shift():c=!1;else{let E=c?h.extract(a):null;E!==null&&typeof E[0]=="number"?(n.push(h.generate(E[0])),a=E[1]):(n.push(h.generate()),c=!1)}}return s.prerelease&&(s.prerelease=[]),`${t}-${n.join(".")}`}var Y1=class extends ft{constructor(){super(...arguments);this.all=ge.Boolean("--all",!1,{description:"Apply the deferred version changes on all workspaces"});this.dryRun=ge.Boolean("--dry-run",!1,{description:"Print the versions without actually generating the package archive"});this.prerelease=ge.String("--prerelease",{description:"Add a prerelease identifier to new versions",tolerateBoolean:!0});this.exact=ge.Boolean("--exact",!1,{description:"Use the exact version of each package, removes any range. Useful for nightly releases where the range might match another version."});this.recursive=ge.Boolean("-R,--recursive",{description:"ReleLine truncated
This command will apply the deferred version changes and remove their definitions from the repository.
Note that if \`--prerelease\` is set, the given prerelease identifier (by default \`rc.%n\`) will be used on all new versions and the version definitions will be kept as-is.
By default only the current workspace will be bumped, but you can configure this behavior by using one of:
- \`--recursive\` to also apply the version bump on its dependencies
- \`--all\` to apply the version bump on all packages in the repository
Note that this command will also update the \`workspace:\` references across all your local workspaces, thus ensuring that they keep referring to the same workspaces even after the version bump.
`,examples:[["Apply the version change to the local workspace","yarn version apply"],["Apply the version change to all the workspaces in the local workspace","yarn version apply --all"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState({restoreResolutions:!1});let c=await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async f=>{let p=this.prerelease?typeof this.prerelease!="boolean"?this.prerelease:"rc.%n":null,h=await sb(s,{prerelease:p}),E=new Map;if(this.all)E=h;else{let C=this.recursive?a.getRecursiveWorkspaceDependencies():[a];for(let S of C){let b=h.get(S);typeof b<"u"&&E.set(S,b)}}if(E.size===0){let C=h.size>0?" Did you want to add --all?":"";f.reportWarning(0,`The current workspace doesn't seem to require a version bump.${C}`);return}iz(s,E,{report:f,exact:this.exact}),this.dryRun||(p||(this.all?await tz(s):await rz(s,[...E.keys()])),f.reportSeparator())});return this.dryRun||c.hasErrors()?c.exitCode():await s.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:n})}};Ge();Dt();Yt();var UL=ut(Ai());var V1=class extends ft{constructor(){super(...arguments);this.interactive=ge.Boolean("-i,--interactive",{description:"Open an interactive interface used to set version bumps"})}static{this.paths=[["version","check"]]}static{this.usage=ot.Usage({category:"Release-related commands",description:"check that all the relevant packages have been bumped",details:"\n **Warning:** This command currently requires Git.\n\n This command will check that all the packages covered by the files listed in argument have been properly bumped or declined to bump.\n\n In the case of a bump, the check will also cover transitive packages - meaning that should `Foo` be bumped, a package `Bar` depending on `Foo` will require a decision as to whether `Bar` will need to be bumped. This check doesn't cross packages that have declined to bump.\n\n In case no arguments are passed to the function, the list of modified files will be generated by comparing the HEAD against `master`.\n ",examples:[["Check whether the modified packages need a bump","yarn version check"]]})}async execute(){return this.interactive?await this.executeInteractive():await this.executeStandard()}async executeInteractive(){iw(this.context);let{Gem:r}=await Promise.resolve().then(()=>(qF(),kW)),{ScrollableItems:s}=await Promise.resolve().then(()=>(JF(),VF)),{FocusRequest:a}=await Promise.resolve().then(()=>(RW(),E2e)),{useListInput:n}=await Promise.resolve().then(()=>(YF(),I2e)),{renderForm:c}=await Promise.resolve().then(()=>(XF(),ZF)),{Box:f,Text:p}=await Promise.resolve().then(()=>ut(Wc())),{default:h,useCallback:E,useState:C}=await Promise.resolve().then(()=>ut(hn())),S=await ze.find(this.context.cwd,this.context.plugins),{project:b,workspace:I}=await Rt.find(S,this.context.cwd);if(!I)throw new ar(b.cwd,this.context.cwd);await b.restoreInstallState();let T=await q1(b);if(T===null||T.releaseRoots.size===0)return 0;if(T.root===null)throw new nt("This command can only be run on Git repositories");let N=()=>h.createElement(f,{flexDirection:"row",paddingBottom:1},h.createElement(f,{flexDirection:"column",width:60},h.createElement(f,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"<up>"),"/",h.createElement(p,{bold:!0,color:"cyanBright"},"<down>")," to select workspaces.")),h.createElement(f,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"<left>"),"/",h.createElement(p,{bold:!0,color:"cyanBright"},"<right>")," to select release strategies."))),h.createElement(f,{flexDirection:"column"},h.createElement(f,{marginLeft:1},h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"<enter>")," to save.")),h.createElement(f,{marginLeft:1},h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"<ctrl+c>")," to abort.")))),U=({workspace:me,active:pe,decision:Be,setDecision:Ce})=>{let g=me.manifest.raw.stableVersion??me.manifest.version;if(g===null)throw new Error(`Assertion failed: The version should have been set (${G.prettyLocator(S,me.anchoredLocator)})`);if(UL.default.prerelease(g)!==null)throw new Error(`Assertion failed: Prerelease identifiers shouldn't be found (${g})`);let we=["undecided","decline","patch","minor","major"];n(Be,we,{active:pe,minus:"left",plus:"right",set:Ce});let ye=Be==="undecided"?h.createElement(p,{color:"yellow"},g):Be==="decline"?h.createElement(p,{color:"green"},g):h.createElement(p,null,h.createElement(p,{color:"magenta"},g)," \u2192 ",h.createElement(p,{color:"green"},UL.default.valid(Be)?Be:UL.default.inc(g,Be)));return h.createElement(f,{flexDirection:"column"},h.createElement(f,null,h.createElement(p,null,G.prettyLocator(S,me.anchoredLocator)," - ",ye)),h.createElement(f,null,we.map(AeLine truncated
`)},p=()=>{let Ce=this.from.map(g=>z1.default.matcher(g));return s.workspaces.filter(g=>{let we=G.stringifyIdent(g.anchoredLocator),ye=g.relativeCwd;return Ce.some(Ae=>Ae(we)||Ae(ye))})},h=[];if(this.since?(f("Option --since is set; selecting the changed workspaces as root for workspace selection"),h=Array.from(await ka.fetchChangedWorkspaces({ref:this.since,project:s}))):this.from?(f("Option --from is set; selecting the specified workspaces"),h=[...p()]):this.worktree?(f("Option --worktree is set; selecting the current workspace"),h=[a]):this.recursive?(f("Option --recursive is set; selecting the current workspace"),h=[a]):this.all&&(f("Option --all is set; selecting all workspaces"),h=[...s.workspaces]),this.dryRun&&!this.all){for(let Ce of h)f(`
- ${Ce.relativeCwd}
${G.prettyLocator(r,Ce.anchoredLocator)}`);h.length>0&&f("")}let E;if(this.recursive?this.since?(f("Option --recursive --since is set; recursively selecting all dependent workspaces"),E=new Set(h.map(Ce=>[...Ce.getRecursiveWorkspaceDependents()]).flat())):(f("Option --recursive is set; recursively selecting all transitive dependencies"),E=new Set(h.map(Ce=>[...Ce.getRecursiveWorkspaceDependencies()]).flat())):this.worktree?(f("Option --worktree is set; recursively selecting all nested workspaces"),E=new Set(h.map(Ce=>[...Ce.getRecursiveWorkspaceChildren()]).flat())):E=null,E!==null&&(h=[...new Set([...h,...E])],this.dryRun))for(let Ce of E)f(`
- ${Ce.relativeCwd}
${G.prettyLocator(r,Ce.anchoredLocator)}`);let C=[],S=!1;if(c?.includes(":")){for(let Ce of s.workspaces)if(Ce.manifest.scripts.has(c)&&(S=!S,S===!1))break}for(let Ce of h){if(c&&!Ce.manifest.scripts.has(c)&&!S&&!(await In.getWorkspaceAccessibleBinaries(Ce)).has(c)){f(`Excluding ${Ce.relativeCwd} because it doesn't have a "${c}" script`);continue}if(!(c===r.env.npm_lifecycle_event&&Ce.cwd===a.cwd)){if(this.include.length>0&&!z1.default.isMatch(G.stringifyIdent(Ce.anchoredLocator),this.include)&&!z1.default.isMatch(Ce.relativeCwd,this.include)){f(`Excluding ${Ce.relativeCwd} because it doesn't match the --include filter`);continue}if(this.exclude.length>0&&(z1.default.isMatch(G.stringifyIdent(Ce.anchoredLocator),this.exclude)||z1.default.isMatch(Ce.relativeCwd,this.exclude))){f(`Excluding ${Ce.relativeCwd} because it matches the --exclude filter`);continue}if(this.publicOnly&&Ce.manifest.private===!0){f(`Excluding ${Ce.relativeCwd} because it's a private workspace and --no-private was set`);continue}C.push(Ce)}}if(this.dryRun)return 0;let b=this.verbose??(this.context.stdout.isTTY?1/0:0),I=b>0,T=b>1,N=this.parallel?this.jobs==="unlimited"?1/0:Number(this.jobs)||Math.ceil(fs.availableParallelism()/2):1,U=N===1?!1:this.parallel,W=U?this.interlaced:!0,ee=(0,fke.default)(N),ie=new Map,ue=new Set,le=0,me=null,pe=!1,Be=await Ot.start({configuration:r,stdout:this.context.stdout,includePrefix:!1},async Ce=>{let g=async(we,{commandIndex:ye})=>{if(pe)return-1;!U&&T&&ye>1&&Ce.reportSeparator();let Ae=ibt(we,{configuration:r,label:I,commandIndex:ye}),[se,X]=uke(Ce,{prefix:Ae,interlaced:W}),[De,Te]=uke(Ce,{prefix:Ae,interlaced:W});try{T&&Ce.reportInfo(null,`${Ae?`${Ae} `:""}Process started`);let mt=Date.now(),j=await this.cli.run([this.commandName,...this.args],{cwd:we.cwd,stdout:se,stderr:De})||0;se.end(),De.end(),await X,await Te;let rt=Date.now();if(T){let Fe=r.get("enableTimers")?`, completed in ${he.pretty(r,rt-mt,he.Type.DURATION)}`:"";Ce.reportInfo(null,`${Ae?`${Ae} `:""}Process exited (exit code ${j})${Fe}`)}return j===130&&(pe=!0,me=j),j}catch(mt){throw se.end(),De.end(),await X,await Te,mt}};for(let we of C)ie.set(we.anchoredLocator.locatorHash,we);for(;ie.size>0&&!Ce.hasErrors();){let we=[];for(let[X,De]of ie){if(ue.has(De.anchoredDescriptor.descriptorHash))continue;let Te=!0;if(this.topological||this.topologicalDev){let mt=this.topologicalDev?new Map([...De.manifest.dependencies,...De.manifest.devDependencies]):De.manifest.dependencies;for(let j of mt.values()){let rt=s.tryWorkspaceByDescriptor(j);if(Te=rt===null||!ie.has(rt.anchoredLocator.locatorHash),!Te)break}}if(Te&&(ue.add(De.anchoredDescriptor.descriptorHash),we.push(ee(async()=>{let mt=await g(De,{commandIndex:++le});return ie.delete(X),ue.delete(De.anchoredDescriptor.descriptorHash),{workspace:De,exitCode:mt}})),!U))break}if(we.length===0){let X=Array.from(ie.values()).map(De=>G.prettyLocator(r,De.anchoredLocator)).join(", ");Ce.reportError(3,`Dependency cycle detected (${X})`);return}let ye=await Promise.all(we);ye.forEach(({workspace:X,exitCode:De})=>{De!==0&&Ce.reportError(0,`The command failed in workspace ${G.prettyLocator(r,X.anchoredLocator)} with exit code ${De}`)});let se=ye.map(X=>X.exitCode).find(X=>X!==0);(this.topological||this.topologicalDev)&&typeof se<"u"&&Ce.reportError(0,"The command failed for workspaces that are depended upon by other workspaces; can't satisfy the dependency graph")}});return me!==null?me:Be.exitCode()}};function uke(t,{prefix:e,interlaced:r}){let s=t.createStreamReporter(e),a=new je.DefaultStream;a.pipe(s,{end:!1}),a.on("finish",()=>{s.end()});let n=new Promise(f=>{s.on("finish",()=>{f(a.active)})});if(r)return[a,n];let c=new je.BufferStream;return c.pipe(a,{end:!1}),c.on("finish",()=>{a.end()}),[c,n]}function ibt(t,{configuration:e,commandIndex:r,label:s}){if(!s)return null;let n=`[${G.stringifyIdent(t.anchoredLocator)}]:`,c=["#2E86AB","#A23B72","#F18F01","#C73E1D","#CCE2A3"],f=c[r%c.length];return he.pretty(e,n,f)}var sbt={commands:[K1,Z1]},obt=sbt;var uz={};Vt(uz,{default:()=>ubt});Ge();Ge();var az="catalog:";var lz=t=>t.startsWith(az),abt=t=>t.range.slice(az.length)||null,Ake=t=>t===null?"default catalog":`catalog "${t}"`,lbt=t=>t.scope?`@${t.scope}/${t.name}`:t.name,cz=(t,e,r,s)=>{let a=abt(e),n;if(a===null)n=t.configuration.get("catalog");else try{let E=t.configuration.get("catalogs");E&&(n=E.get(a))}catch{n=void 0}if(!n||n.size===0)throw new jt(82,`${G.prettyDescriptor(t.configuration,e)}: ${Ake(a)} not found or empty`);let c=lbt(e),f=n.get(c);if(!f)throw new jt(82,`${G.prettyDescriptor(t.configuration,e)}: entry not found in ${Ake(a)}`);let p=t.configuration.normalizeDependency(G.makeDescriptor(e,f));return r.bindDescriptor(p,t.topLevelWorkspace.anchoredLocator,s)};var cbt={configuration:{catalog:{description:"The default catalog of packages",type:"MAP",valueDefinition:{description:"The catalog of packages",type:"STRING"}},catalogs:{description:"Named catalogs of packages",type:"MAP",valueDefinition:{dLine truncated
Please report this issue at https://github.com/yarnpkg/berry/issues.`)}process.once("beforeExit",n);try{process.exitCode=42,process.exitCode=await dbt(a,t,{selfPath:r,pluginConfiguration:s})}catch(c){Ca.defaultContext.stdout.write(a.error(c)),process.exitCode=1}finally{process.off("beforeExit",n),await ce.rmtempPromise()}}YT(process.argv.slice(2),{cwd:J.cwd(),selfPath:fe.toPortablePath(fe.resolve(process.argv[1])),pluginConfiguration:tC()});})();
/**
@license
Copyright (c) 2015, Rebecca Turner
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
/**
@license
Copyright Node.js contributors. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
/**
@license
The MIT License (MIT)
Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/**
@license
Copyright Joyent, Inc. and other Node contributors.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*! Bundled license information:
is-number/index.js:
(*!
* is-number <https://github.com/jonschlinkert/is-number>
*
* Copyright (c) 2014-present, Jon Schlinkert.
* Released under the MIT License.
*)
to-regex-range/index.js:
(*!
* to-regex-range <https://github.com/micromatch/to-regex-range>
*
* Copyright (c) 2015-present, Jon Schlinkert.
* Released under the MIT License.
*)
fill-range/index.js:
(*!
* fill-range <https://github.com/jonschlinkert/fill-range>
*
* Copyright (c) 2014-present, Jon Schlinkert.
* Licensed under the MIT License.
*)
is-extglob/index.js:
(*!
* is-extglob <https://github.com/jonschlinkert/is-extglob>
*
* Copyright (c) 2014-2016, Jon Schlinkert.
* Licensed under the MIT License.
*)
is-glob/index.js:
(*!
* is-glob <https://github.com/jonschlinkert/is-glob>
*
* Copyright (c) 2014-2017, Jon Schlinkert.
* Released under the MIT License.
*)
queue-microtask/index.js:
(*! queue-microtask. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> *)
run-parallel/index.js:
(*! run-parallel. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> *)
git-url-parse/lib/index.js:
(*!
* buildToken
* Builds OAuth token prefix (helper function)
*
* @name buildToken
* @function
* @param {GitUrl} obj The parsed Git url object.
* @return {String} token prefix
*)
object-assign/index.js:
(*
object-assign
(c) Sindre Sorhus
@license MIT
*)
react/cjs/react.production.min.js:
(** @license React v17.0.2
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
scheduler/cjs/scheduler.production.min.js:
(** @license React v0.20.2
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
react-reconciler/cjs/react-reconciler.production.min.js:
(** @license React v0.26.2
* react-reconciler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
is-windows/index.js:
(*!
* is-windows <https://github.com/jonschlinkert/is-windows>
*
* Copyright © 2015-2018, Jon Schlinkert.
* Released under the MIT License.
*)
*/
-9
View File
@@ -1,9 +0,0 @@
compressionLevel: mixed
defaultSemverRangePrefix: ""
enableGlobalCache: false
nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-4.10.3.cjs
+65
View File
@@ -0,0 +1,65 @@
# Home Assistant Frontend Agent Guide
You are helping develop the Home Assistant frontend. This repository is a TypeScript application built from Lit-based Web Components for the Home Assistant web UI.
## Essential Commands
```bash
pnpm lint # ESLint + Prettier + TypeScript + Lit
pnpm format # Auto-fix ESLint + Prettier
pnpm lint:types # TypeScript compiler, run without file arguments
pnpm test # Vitest
pnpm dev # App dev server, supports --background/--status/--stop/--logs
pnpm dev:serve # Local serving dev server, supports -c core URL, -p port, and dev flags
```
Never run `tsc` or `pnpm lint:types` with file arguments. When `tsc` receives file arguments, it ignores `tsconfig.json` and can emit `.js` files into `src/`. Always run `pnpm lint:types` without arguments. For individual file type checking, rely on editor diagnostics.
## Architecture
- The frontend uses custom elements built with Lit and TypeScript strict mode.
- Components communicate with the backend through the Home Assistant WebSocket API.
- Use `ha-` for Home Assistant components, `hui-` for Lovelace UI components, and `dialog-` for dialogs.
- Prefer `ha-*` components and current Web Awesome wrappers. Avoid adding new legacy `mwc-*` usage.
- Leaf components should consume narrow Lit contexts instead of taking the broad `hass` object unless they are containers that own and provide `hass`.
## Development Standards
- Use strict TypeScript, proper interfaces, and `import type` for type-only imports.
- Avoid `any`; model data with existing Home Assistant types or narrow new types.
- Keep imports organized and remove unused imports.
- Do not use `console`; use existing logging or user-visible error patterns.
- Use `@state()` for internal Lit state and `@property()` for public API.
- Do not query or manipulate DOM manually when Lit decorators, component refs, or render state are appropriate.
- Scope styles to components, use theme custom properties, and keep layouts mobile-first and RTL-safe.
- All user-facing text must be localized through the translation system.
- Do not write tests just because you changed some code. Write a test when there is real logic that could break without anyone noticing, and explain what the test protects.
## Project Skills
Detailed guidance lives in `.agents/skills/<name>/SKILL.md`. Load every matching skill before detailed implementation or review. For reviews, load `ha-frontend-review` alongside all companions that apply to the changed code or behavior:
- `ha-frontend-contexts`: Lit contexts, `hass` migration, and rerender-sensitive state access.
- `ha-frontend-components`: dialogs, forms, alerts, shortcuts, tooltips, panels, and Lovelace cards.
- `ha-frontend-events`: event handler typing, custom event dispatch, and event-map declarations.
- `ha-frontend-types`: backend data contracts, optional schemas, shared types, assertions, and lifecycle types.
- `ha-frontend-lit`: reactive fields, DOM queries, lifecycle behavior, and render-derived state.
- `ha-frontend-styling`: theme variables, spacing tokens, responsive layout, RTL, and view transitions.
- `ha-frontend-testing`: lint, typecheck, Vitest, Playwright e2e dev servers, and benchmarks.
- `ha-frontend-user-facing-text`: localization, terminology, sentence case, and Home Assistant text style.
- `ha-frontend-review`: PR template use, existing review feedback, review checklist, recurring issues, and UI/UX evidence including gallery specifications.
- `ha-frontend-ux-readiness`: UI/UX routing that complements frontend review for new user experiences.
- `ha-frontend-gallery`: gallery pages, demos, sidebar structure, content, and verification.
- `ha-frontend-demo`: standalone demo structure, configurations, navigation, shared stubs, and verification.
## Pull Requests
When creating a pull request, use `.github/PULL_REQUEST_TEMPLATE.md` as the PR body. Preserve template sections, check only the appropriate type-of-change boxes, and do not check checklist items on behalf of the user. If the PR includes UI changes, remind the user to add screenshots or a short video.
## AI policy
This project follows the [Open Home Foundation AI Policy](AI_POLICY.md).
Autonomous contributions are not accepted: a human must review, understand,
and be able to explain every change before it is submitted. Do not open
issues or pull requests autonomously, and do not post comments on behalf of
a user without their review.
+45
View File
@@ -0,0 +1,45 @@
# Open Home Foundation - AI Policy
We support using AI (i.e., LLMs) as tools when contributing to Open Home Foundation projects. However, you are responsible for any contributions you submit, and we are responsible for any contributions we merge and release. We hold a high bar for all contributions to our projects.
Our maintainers dedicate their time and expertise to reviewing contributions. Submitting AI-generated content that you have not personally reviewed and understood wastes that time and will not be accepted.
## Autonomous agents
**We do not allow autonomous agents to be used for contributing to our projects.** We will close any pull requests or issues that we believe were created autonomously, and may mark automated comments as spam. This includes contributions that bypass the provided issue or pull request templates.
## Communication on issues, pull requests, and code reviews
We don't mind if you use AI tools to help you write. However, do not have tools post unreviewed content on your behalf. Keep responses to the minimum needed to communicate your intent. We may hide any comments that we believe are unreviewed AI output.
If you are opening a pull request, we expect you to be able to explain the proposed changes in your own words. This includes the pull request description and responses to questions. If you use AI to help generate the pull request summary, you must review it for technical accuracy.
**Do not use AI to generate answers to questions from maintainers.** You should understand and be able to explain your own work. Using AI to improve grammar or clarity is fine, but the substance of your responses must be your own.
If you wish to include context from an interaction with AI in your comments, it must be in a quote block (e.g., using `>`) and disclosed as such. It must be accompanied by your own commentary explaining the relevance and implications of the context. Do not share long snippets.
## Non-native English speakers
We understand that AI is useful when communicating as a non-native English speaker. Using AI to improve the grammar or clarity of text you have written yourself is fine. If you are using AI to translate your comments, please ensure the translation accurately reflects your intent. Including your original text in a details block shows the effort behind your contribution, helps maintainers verify the translation if needed, and keeps the conversation readable.
## Code and documentation contributions
AI can be a helpful tool for writing code and documentation. However, due to the foundational open source nature of our projects, we require a human in the loop who understands the work produced by AI.
All contributions must be reviewed and understood by the contributor before submission. You should be able to explain every change in a pull request you submit. Pull requests that appear to be unreviewed AI output will be closed without review.
## Our use of AI
Some of our projects use AI tools to assist with code reviews, issue triaging, reporting, and other project management tasks. These tools may leave comments on pull requests or issues. As with any automated tooling, these comments are not always correct.
If an AI tool leaves a comment on your contribution, treat it as you would any other review comment. If you believe it is incorrect, say so; a brief explanation is sufficient. Maintainers always have the final say. If in doubt, ask a maintainer.
## Enforcement
Contributions that do not follow this policy will be closed. Repeated violations may result in being blocked from contributing to OHF projects. If you believe your contribution was closed in error, you are welcome to reach out to a maintainer to discuss.
---
The canonical version of this policy is published at
<https://developers.home-assistant.io/docs/ai_policy>. In case of differences,
the published version applies.
+1 -1
View File
@@ -1 +1 @@
.github/copilot-instructions.md
AGENTS.md
+169 -162
View File
@@ -1,194 +1,201 @@
Apache License
==============
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
_Version 2.0, January 2004_
_&lt;<http://www.apache.org/licenses/>&gt;_
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
### Terms and Conditions for use, reproduction, and distribution
1. Definitions.
#### 1. Definitions
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
“License” shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
“Licensor” shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
“Legal Entity” shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, “control” means **(i)** the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
outstanding shares, or **(iii)** beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
“You” (or “Your”) shall mean an individual or Legal Entity exercising
permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
“Source” form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
“Object” form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
“Work” shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
“Derivative Works” shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
“Contribution” shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
“submitted” means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as “Not a Contribution.”
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
#### 2. Grant of Copyright License
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
#### 3. Grant of Patent License
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
#### 4. Redistribution
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
this License; and
* **(b)** You must cause any modified files to carry prominent notices stating that You
changed the files; and
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
#### 5. Submission of Contributions
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
#### 6. Trademarks
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
#### 7. Disclaimer of Warranty
END OF TERMS AND CONDITIONS
Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
APPENDIX: How to apply the Apache License to your work.
#### 8. Limitation of Liability
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.
Copyright [yyyy] [name of copyright owner]
#### 9. Accepting Warranty or Additional Liability
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.
http://www.apache.org/licenses/LICENSE-2.0
_END OF TERMS AND CONDITIONS_
### APPENDIX: How to apply the Apache License to your work
To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets `[]` replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same “printed page” as the copyright notice for easier identification within
third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+1 -2
View File
@@ -12,9 +12,8 @@ This is the repository for the official [Home Assistant](https://home-assistant.
- Initial setup: `script/setup`
- Development: [Instructions](https://developers.home-assistant.io/docs/frontend/development/)
- Production build: `script/build_frontend`
- Production build: `pnpm build`
- Gallery: `cd gallery && script/develop_gallery`
- Supervisor: [Instructions](https://developers.home-assistant.io/docs/supervisor/developing)
## Frontend development
+9 -1
View File
@@ -34,6 +34,14 @@ In production, the following responsibilities are added:
- Minify HTML
- Bundle multiple imports so that the browser can fetch less files
- Generate a second version that is ES5 compatible
- Generate a second version that is compatible with older browsers (legacy build)
Configuration for all these steps are specified in [bundle.js](bundle.js).
## Auditing browser support changes
`node build-scripts/list-plugins-and-polyfills.js` prints, per browserslist
environment (modern/legacy), the Babel transforms preset-env enables and the
Core-JS polyfills that may be injected — as collapsible markdown ready to
paste into a PR. Use it to show the bundle impact when changing
`.browserslistrc` or the Babel configuration.
+56
View File
@@ -0,0 +1,56 @@
// Gulp transform that brotli-compresses files, several at a time.
//
// Drop-in replacement for gulp-brotli. zlib already does the work off the main
// thread, but that plugin wraps it in through2, which waits for each file
// before starting the next, so only one compression is ever in flight. The
// compressed bytes are unchanged; only how many run at once differs.
//
// The real ceiling is libuv's threadpool, which zlib runs on. It sizes itself
// from UV_THREADPOOL_SIZE before any JavaScript runs, so it can only be raised
// from the environment, never from inside the build.
import { availableParallelism } from "node:os";
import { buffer as readStream } from "node:stream/consumers";
import { promisify } from "node:util";
import { brotliCompress, constants } from "node:zlib";
import { withCache } from "./compress-cache.mjs";
import { ParallelTransform } from "./parallel-transform.mjs";
const EXTENSION = ".br";
const compress = promisify(brotliCompress);
/**
* @param {object} [options]
* @param {boolean} [options.skipLarger] Drop files that compression grows.
* @param {object} [options.params] Brotli parameters, passed to zlib as-is.
*/
export default ({ skipLarger = false, params } = {}) => {
// Isolate cache entries by anything that changes the output bytes: the brotli
// quality, and the node major that produced them.
const quality = params?.[constants.BROTLI_PARAM_QUALITY] ?? "default";
const namespace = `brotli-q${quality}-node${process.versions.node.split(".")[0]}`;
return new ParallelTransform(availableParallelism(), async (file) => {
if (file.isNull()) {
return file;
}
if (file.isStream()) {
file.contents = await readStream(file.contents);
}
const compressed = await withCache(namespace, file.contents, async () => {
const out = await compress(file.contents, { params });
// Dropped rather than passed through, as gulp-brotli did: the
// uncompressed file is already in the output directory.
return skipLarger && out.length >= file.contents.length ? undefined : out;
});
if (compressed === undefined) {
return undefined;
}
file.contents = compressed;
file.path += EXTENSION;
return file;
});
};
+311
View File
@@ -0,0 +1,311 @@
// Manage a Home Assistant frontend production build with an agent-friendly
// interface, matching build-scripts/dev-server.mjs.
//
// node build-scripts/build-manager.mjs [--modern] [mode]
//
// (no mode) Run in the foreground.
// --background Start detached, print the pid, then exit and leave it
// running.
// --status Report whether a managed build is running.
// --stop Stop a managed build.
// --logs [--follow] Print (or follow) the background build log.
//
// --modern Build only the modern frontend_latest bundle.
import path from "node:path";
import { fileURLToPath } from "node:url";
import {
LIFECYCLE_MODE_FLAGS,
acquireProcessRecord,
isProcessRecordAlive,
outputLog,
offerToStopProcessRecord,
processStartTime,
readProcessRecord,
releaseProcessRecord,
runCli,
spawnDetachedToLog,
spawnForeground,
terminateDetachedProcess,
terminateProcess,
waitFor,
writeProcessRecord,
} from "./managed-process.mjs";
import {
buildCacheDir,
describeOutputOwner,
workflowLockEnv,
workflowLockFile,
} from "./output-lock.mjs";
const repoRoot = path.resolve(
path.dirname(fileURLToPath(import.meta.url)),
".."
);
const gulpBin = path.join(repoRoot, "node_modules", ".bin", "gulp");
const stateDir = path.join(buildCacheDir, "ha-build");
const logFile = path.join(stateDir, "build.log");
const lockFile = workflowLockFile;
const usage = () => {
process.stderr.write(
"Usage: node build-scripts/build-manager.mjs [--modern] " +
"[--background | --status | --stop | --logs [--follow]]\n"
);
};
const parseArgs = (argv) => {
const args = {
mode: "foreground",
modes: [],
follow: false,
modern: false,
unknown: [],
};
for (const arg of argv) {
if (LIFECYCLE_MODE_FLAGS.has(arg)) {
args.mode = LIFECYCLE_MODE_FLAGS.get(arg);
args.modes.push(arg);
} else if (arg === "--modern") {
args.modern = true;
} else if (arg === "--follow") {
args.follow = true;
} else {
args.unknown.push(arg);
}
}
return args;
};
const hints = () =>
" Stop: pnpm build --stop\n" +
" Status: pnpm build --status\n" +
" Logs: pnpm build --logs\n";
const devCommand = (suite) => {
switch (suite) {
case "app-serve":
return "dev:serve";
case "demo":
return "dev:demo";
case "gallery":
return "dev:gallery";
case "e2e-app":
return "test:e2e:app:dev";
default:
return "dev";
}
};
const readBuild = () => readProcessRecord(lockFile);
const releaseBuild = (token) => releaseProcessRecord(lockFile, token);
const stopCommandFor = (owner) =>
owner?.kind === "build"
? "pnpm build --stop"
: owner?.kind === "dev"
? `pnpm ${devCommand(owner.suite)} --stop`
: undefined;
const acquireBuild = async (modern, foreground) => {
const token = `${process.pid}-${Date.now()}-${Math.random()}`;
const record = {
pid: process.pid,
startTime: processStartTime(process.pid),
processGroup: false,
foreground,
kind: "build",
modern,
starting: true,
token,
};
const result = acquireProcessRecord(lockFile, record);
if (result.acquired) {
return { token };
}
reportExisting(result.existing);
return (await offerToStopProcessRecord({
file: lockFile,
owner: result.existing,
ownerDescription: describeOutputOwner(result.existing),
stopCommand: stopCommandFor(result.existing),
}))
? acquireBuild(modern, foreground)
: { existing: result.existing };
};
const updateBuild = (token, child, processGroup) => {
const existing = readBuild();
if (existing?.token !== token) {
throw Error("Frontend build lock ownership was lost during startup.");
}
writeProcessRecord(lockFile, {
...existing,
pid: child.pid,
startTime: processStartTime(child.pid),
processGroup,
starting: false,
});
};
const taskFor = (modern) => (modern ? "build-app-modern" : "build-app");
const reportExisting = (existing) => {
if (existing?.kind === "output") {
process.stdout.write(
`${describeOutputOwner(existing)} already owns the build and development workflow` +
`${existing.pid ? ` (pid ${existing.pid})` : ""}.\n`
);
return;
}
if (existing?.kind === "dev") {
const command = devCommand(existing.suite);
process.stdout.write(
`Dev server (${existing.suite}) already running` +
`${existing.pid ? ` (pid ${existing.pid})` : ""}.\n` +
` Stop: pnpm ${command} --stop\n` +
` Status: pnpm ${command} --status\n` +
` Logs: pnpm ${command} --logs\n`
);
return;
}
process.stdout.write(
`Frontend ${existing?.modern ? "modern " : ""}build already running` +
`${existing?.pid ? ` (pid ${existing.pid})` : ""}.\n${hints()}`
);
};
const runForeground = async (modern) => {
const lock = await acquireBuild(modern, true);
if (!lock.token) {
return 1;
}
try {
return await spawnForeground({
cmd: gulpBin,
args: [taskFor(modern)],
cwd: repoRoot,
env: workflowLockEnv(lock.token),
processGroup: true,
onSpawn: (child) => updateBuild(lock.token, child, true),
});
} finally {
releaseBuild(lock.token);
}
};
const runBackground = async (modern) => {
const lock = await acquireBuild(modern, false);
if (!lock.token) {
return 1;
}
let child;
try {
child = await spawnDetachedToLog({
cmd: gulpBin,
args: [taskFor(modern)],
cwd: repoRoot,
env: workflowLockEnv(lock.token),
logFile,
});
updateBuild(lock.token, child, true);
process.stdout.write(
`Started ${modern ? "modern " : ""}frontend build (pid ${child.pid})\n` +
hints()
);
return 0;
} catch (err) {
if (child) {
await terminateDetachedProcess(child);
}
releaseBuild(lock.token);
throw err;
}
};
const runStatus = () => {
const existing = readBuild();
if (existing?.kind === "build" && isProcessRecordAlive(existing)) {
process.stdout.write(
`Frontend ${existing.modern ? "modern " : ""}build running (pid ${existing.pid}).\n`
);
} else {
if (existing?.kind === "build") {
releaseBuild(existing.token);
}
process.stdout.write("Frontend build not running.\n");
}
return 0;
};
const runStop = async () => {
let existing = readBuild();
if (existing?.kind !== "build") {
process.stdout.write("Frontend build not running.\n");
return 0;
}
if (existing?.starting) {
const token = existing.token;
await waitFor(
() => {
const current = readBuild();
return !current?.starting || current.token !== token;
},
100,
5000
);
existing = readBuild();
}
if (
!existing ||
existing.kind !== "build" ||
!isProcessRecordAlive(existing)
) {
if (existing) releaseBuild(existing.token);
process.stdout.write("Frontend build not running.\n");
return 0;
}
if (
!(await terminateProcess({
pid: existing.pid,
processGroup: existing.processGroup,
isStopped: () => !isProcessRecordAlive(existing),
}))
) {
process.stderr.write(
`Failed to stop frontend build (pid ${existing.pid}). Stop it manually.\n`
);
return 1;
}
releaseBuild(existing.token);
process.stdout.write(`Stopped frontend build (pid ${existing.pid}).\n`);
return 0;
};
const runLogs = (follow) =>
outputLog(logFile, follow, `No frontend build log yet (${logFile}).\n`);
const main = async () => {
const args = parseArgs(process.argv.slice(2));
if (args.unknown.length) {
process.stderr.write(`Unknown arguments: ${args.unknown.join(" ")}\n`);
usage();
return 1;
}
if (args.modes.length > 1 || (args.follow && args.mode !== "logs")) {
process.stderr.write("Invalid combination of build arguments.\n");
usage();
return 1;
}
const handlers = {
foreground: () => runForeground(args.modern),
background: () => runBackground(args.modern),
status: runStatus,
stop: runStop,
logs: () => runLogs(args.follow),
};
return handlers[args.mode]();
};
runCli(main);
+15
View File
@@ -0,0 +1,15 @@
{
"_comment": "Initial JS budget (raw/uncompressed bytes) for the cold-load critical entrypoints. Enforced by build-scripts/check-bundle-size.cjs in CI. Re-seed after an intentional change with `--update --headroom=<percent>`.",
"frontend-modern": {
"app": 624240,
"core": 55144,
"authorize": 594400,
"onboarding": 705499
},
"frontend-legacy": {
"app": 776696,
"core": 188309,
"authorize": 763316,
"onboarding": 879807
}
}
+105 -71
View File
@@ -18,29 +18,57 @@ module.exports.sourceMapURL = () => {
module.exports.ignorePackages = () => [];
// Files from NPM packages that we should replace with empty file
module.exports.emptyPackages = ({ isHassioBuild }) =>
module.exports.emptyPackages = ({ isLandingPageBuild }) =>
[
require.resolve("@vaadin/vaadin-material-styles/typography.js"),
require.resolve("@vaadin/vaadin-material-styles/font-icons.js"),
// Icons in supervisor conflict with icons in HA so we don't load.
isHassioBuild &&
// Icons in landingpage conflict with icons in HA so we don't load.
isLandingPageBuild &&
require.resolve(
path.resolve(paths.root_dir, "src/components/ha-icon.ts")
),
isHassioBuild &&
isLandingPageBuild &&
require.resolve(
path.resolve(paths.root_dir, "src/components/ha-icon-picker.ts")
),
].filter(Boolean);
module.exports.definedVars = ({ isProdBuild, latestBuild, defineOverlay }) => ({
// MapLibre runs its tile work in a worker that it spawns from a URL. The
// package ships that worker as untranspiled ES2022, so it is bundled here as
// its own entry per build target, like the rest of MapLibre. One self-contained
// file: the worker cannot import chunks, and a classic-compatible script runs
// wherever the main bundle does, module workers or not. The layer keeps the
// page's polyfills out of it; see `babelOptions`.
const MAP_WORKER_NAME = "maplibre-gl-worker";
module.exports.mapWorkerName = MAP_WORKER_NAME;
module.exports.mapWorkerEntry = () => ({
[MAP_WORKER_NAME]: {
import: "maplibre-gl/dist/maplibre-gl-worker.mjs",
chunkLoading: false,
layer: "worker",
},
});
// MapLibre is handed the URL at build time, so the name cannot carry a content
// hash. The frontend version stands in for it, in the file name rather than a
// query string: the service worker precaches everything under the bundle
// directory as immutable and matches it with the query stripped, so a `?v=`
// would keep serving the worker of the first version it ever cached.
module.exports.mapWorkerFilename = () =>
`${MAP_WORKER_NAME}.${env.version()}.js`;
module.exports.definedVars = ({
isProdBuild,
latestBuild,
publicPath,
defineOverlay,
}) => ({
__DEV__: !isProdBuild,
__BUILD__: JSON.stringify(latestBuild ? "modern" : "legacy"),
__VERSION__: JSON.stringify(env.version()),
__DEMO__: false,
__SUPERVISOR__: false,
__BACKWARDS_COMPAT__: false,
__STATIC_PATH__: "/static/",
__MAPLIBRE_WORKER_URL__: JSON.stringify(
`${publicPath}${module.exports.mapWorkerFilename()}`
),
__HASS_URL__: `\`${
"HASS_URL" in process.env
? process.env.HASS_URL
@@ -66,8 +94,10 @@ module.exports.htmlMinifierOptions = {
};
module.exports.terserOptions = ({ latestBuild, isTestBuild }) => ({
safari10: !latestBuild,
ecma: latestBuild ? 2015 : 5,
// Highest syntax the minifier may emit; it never downlevels. Every browser
// in [modern] is well past ES2020 (universal since spring 2020); the
// [legacy] floors (Chrome 59 / Safari 12) top out at ES2017.
ecma: latestBuild ? 2020 : 2017,
module: latestBuild,
format: { comments: false },
sourceMap: !isTestBuild,
@@ -86,12 +116,7 @@ module.exports.swcOptions = () => ({
},
});
module.exports.babelOptions = ({
latestBuild,
isProdBuild,
isTestBuild,
sw,
}) => ({
module.exports.babelOptions = ({ latestBuild, isTestBuild, sw, worker }) => ({
babelrc: false,
compact: false,
assumptions: {
@@ -104,14 +129,22 @@ module.exports.babelOptions = ({
[
"@babel/preset-env",
{
useBuiltIns: "usage",
corejs: dependencies["core-js"],
bugfixes: true,
shippedProposals: true,
},
],
],
plugins: [
// Inject Core-JS polyfills on demand. Babel 8 removed preset-env's
// `useBuiltIns`/`corejs` options, so the equivalent polyfill provider is
// configured directly here (`usage-global` matches the old `useBuiltIns: "usage"`).
[
"babel-plugin-polyfill-corejs3",
{
method: "usage-global",
version: dependencies["core-js"],
shippedProposals: true,
},
],
[
path.join(BABEL_PLUGINS, "inline-constants-plugin.cjs"),
{
@@ -119,32 +152,14 @@ module.exports.babelOptions = ({
ignoreModuleNotFound: true,
},
],
// Minify template literals for production
isProdBuild && [
"template-html-minifier",
{
modules: {
...Object.fromEntries(
["lit", "lit-element", "lit-html"].map((m) => [
m,
[
"html",
{ name: "svg", encapsulation: "svg" },
{ name: "css", encapsulation: "style" },
],
])
),
"@polymer/polymer/lib/utils/html-tag.js": ["html"],
},
strictCSS: true,
htmlMinifier: module.exports.htmlMinifierOptions,
failOnError: false, // we can turn this off in case of false positives
},
],
// Import helpers and regenerator from runtime package
// Import helpers from runtime package.
// `moduleName` is pinned so helpers resolve from `@babel/runtime`: the
// corejs3 polyfill provider above otherwise redirects them to the
// (uninstalled) `@babel/runtime-corejs3`, which preset-env used to suppress
// internally when it owned the polyfill injection via `useBuiltIns`.
[
"@babel/plugin-transform-runtime",
{ version: dependencies["@babel/runtime"] },
{ version: dependencies["@babel/runtime"], moduleName: "@babel/runtime" },
],
"@babel/plugin-transform-class-properties",
"@babel/plugin-transform-private-methods",
@@ -155,9 +170,11 @@ module.exports.babelOptions = ({
],
sourceMaps: !isTestBuild,
overrides: [
{
// Add plugin to inject various polyfills, excluding the polyfills
// themselves to prevent self-injection.
// Add plugin to inject various polyfills, excluding the polyfills
// themselves to prevent self-injection. Not in a worker: these polyfill
// the page (Intl locale data, DOM APIs) and assume one, so injecting them
// into a worker's graph makes its bootstrap fail before it starts.
!worker && {
plugins: [
[
path.join(BABEL_PLUGINS, "custom-polyfill-plugin.js"),
@@ -171,22 +188,23 @@ module.exports.babelOptions = ({
"@lit-labs/virtualizer/polyfills",
"@webcomponents/scoped-custom-element-registry",
"element-internals-polyfill",
"proxy-polyfill",
"unfetch",
].map((p) => new RegExp(`/node_modules/${p}/`)),
],
},
{
// Use unambiguous for dependencies so that require() is correctly injected into CommonJS files
// Exclusions are needed in some cases where ES modules have no static imports or exports, such as polyfills
// (otherwise babel-plugin-polyfill-corejs3 injects bare require("core-js/modules/...") calls
// that rspack does not transform, causing ReferenceError in browsers like Safari 14).
sourceType: "unambiguous",
include: /\/node_modules\//,
exclude: [
"element-internals-polyfill",
"@?lit(?:-labs|-element|-html)?",
"@formatjs/(?:ecma402-abstract|intl-\\w+)",
].map((p) => new RegExp(`/node_modules/${p}/`)),
},
],
].filter(Boolean),
});
const nameSuffix = (latestBuild) => (latestBuild ? "-modern" : "-legacy");
@@ -236,6 +254,7 @@ module.exports.config = {
onboarding: "./src/entrypoints/onboarding.ts",
core: "./src/entrypoints/core.ts",
"custom-panel": "./src/entrypoints/custom-panel.ts",
...module.exports.mapWorkerEntry(),
},
outputPath: outputPath(paths.app_output_root, latestBuild),
publicPath: publicPath(latestBuild),
@@ -247,11 +266,12 @@ module.exports.config = {
};
},
demo({ isProdBuild, latestBuild, isStatsBuild }) {
demo({ isProdBuild, latestBuild, isStatsBuild, isTestBuild }) {
return {
name: "demo" + nameSuffix(latestBuild),
entry: {
main: path.resolve(paths.demo_dir, "src/entrypoint.ts"),
...module.exports.mapWorkerEntry(),
},
outputPath: outputPath(paths.demo_output_root, latestBuild),
publicPath: publicPath(latestBuild),
@@ -262,6 +282,7 @@ module.exports.config = {
isProdBuild,
latestBuild,
isStatsBuild,
isTestBuild,
};
},
@@ -271,11 +292,13 @@ module.exports.config = {
media: path.resolve(paths.cast_dir, "src/media/entrypoint.ts"),
};
// Only the receiver renders maps, and it is built for modern browsers only
if (latestBuild) {
entry.receiver = path.resolve(
paths.cast_dir,
"src/receiver/entrypoint.ts"
);
Object.assign(entry, module.exports.mapWorkerEntry());
}
return {
@@ -291,36 +314,18 @@ module.exports.config = {
};
},
hassio({ isProdBuild, latestBuild, isStatsBuild, isTestBuild }) {
return {
name: "supervisor" + nameSuffix(latestBuild),
entry: {
entrypoint: path.resolve(paths.hassio_dir, "src/entrypoint.ts"),
},
outputPath: outputPath(paths.hassio_output_root, latestBuild),
publicPath: publicPath(latestBuild, paths.hassio_publicPath),
isProdBuild,
latestBuild,
isStatsBuild,
isTestBuild,
isHassioBuild: true,
defineOverlay: {
__SUPERVISOR__: true,
__STATIC_PATH__: `"${paths.hassio_publicPath}/static/"`,
},
};
},
gallery({ isProdBuild, latestBuild }) {
gallery({ isProdBuild, latestBuild, isTestBuild }) {
return {
name: "gallery" + nameSuffix(latestBuild),
entry: {
entrypoint: path.resolve(paths.gallery_dir, "src/entrypoint.js"),
...module.exports.mapWorkerEntry(),
},
outputPath: outputPath(paths.gallery_output_root, latestBuild),
publicPath: publicPath(latestBuild),
isProdBuild,
latestBuild,
isTestBuild,
defineOverlay: {
__DEMO__: true,
},
@@ -337,6 +342,35 @@ module.exports.config = {
publicPath: publicPath(latestBuild),
isProdBuild,
latestBuild,
isLandingPageBuild: true,
};
},
e2eTestApp({ isProdBuild, latestBuild, isStatsBuild, isTestBuild }) {
return {
name: "e2e-test-app" + nameSuffix(latestBuild),
entry: {
dashboard: path.resolve(
paths.e2eTestApp_dir,
"src/dashboard-entrypoint.ts"
),
main: path.resolve(paths.e2eTestApp_dir, "src/entrypoint.ts"),
onboarding: path.resolve(
paths.e2eTestApp_dir,
"src/onboarding-entrypoint.ts"
),
...module.exports.mapWorkerEntry(),
},
outputPath: outputPath(paths.e2eTestApp_output_root, latestBuild),
publicPath: publicPath(latestBuild),
defineOverlay: {
__VERSION__: JSON.stringify(`E2E-TEST-${env.version()}`),
__DEMO__: true,
},
isProdBuild,
latestBuild,
isStatsBuild,
isTestBuild,
};
},
};
+155
View File
@@ -0,0 +1,155 @@
/* global require, process, __dirname */
// Enforce a strict size budget on the initial JS of the most critical
// entrypoints (`app` and `core`). These two are downloaded on every cold load
// before anything interactive can happen, so unintended growth here hurts
// first-load performance directly.
//
// In production rspack does not split initial chunks (splitChunks only operates
// on `!chunk.canBeInitial()`), so each entrypoint resolves to a single initial
// JS asset. We read the per-build stats written by StatsWriterPlugin and compare
// the entrypoint's initial JS size against a committed budget.
//
// Usage:
// node build-scripts/check-bundle-size.cjs # enforce, exit 1 on regression
// node build-scripts/check-bundle-size.cjs --update # rewrite budgets from current sizes
// node build-scripts/check-bundle-size.cjs --update --headroom=3 # current + 3% headroom
const fs = require("fs");
const path = require("path");
const paths = require("./paths.cjs");
// Entrypoints whose initial JS we hold to a strict budget. These are all
// downloaded on a user-facing cold load before anything interactive can happen:
// `app`/`core` for the main app, plus the standalone `authorize` and
// `onboarding` pages. `custom-panel` is intentionally excluded (only loaded
// when a custom panel is opened).
const TRACKED_ENTRYPOINTS = ["app", "core", "authorize", "onboarding"];
// App build stats files, as written by StatsWriterPlugin (`${name}.json`).
const BUILDS = ["frontend-modern", "frontend-legacy"];
const BUDGET_FILE = path.join(__dirname, "bundle-budget.json");
const STATS_DIR = path.join(paths.build_dir, "stats");
const readStats = (build) => {
const file = path.join(STATS_DIR, `${build}.json`);
if (!fs.existsSync(file)) {
throw new Error(
`Missing stats file: ${path.relative(process.cwd(), file)}.\n` +
`Run a production build first (e.g. \`gulp build-app\`), then re-run this check.`
);
}
return JSON.parse(fs.readFileSync(file, "utf8"));
};
// Initial JS bytes for an entrypoint = sum of the .js asset sizes of its initial
// entry chunk(s). Sizes are raw (uncompressed) bytes, matching the stats output.
const entrypointInitialJS = (stats, entrypoint) => {
const assetSize = new Map(stats.assets.map((a) => [a.name, a.size]));
let total = 0;
let found = false;
for (const chunk of stats.chunks) {
if (!chunk.entry || !chunk.initial) {
continue;
}
if (!(chunk.names || []).includes(entrypoint)) {
continue;
}
found = true;
for (const file of chunk.files || []) {
if (file.endsWith(".js") && assetSize.has(file)) {
total += assetSize.get(file);
}
}
}
if (!found) {
throw new Error(`Entrypoint "${entrypoint}" not found in bundle stats.`);
}
return total;
};
const kib = (bytes) => `${(bytes / 1024).toFixed(1)} KiB`;
const main = () => {
const update = process.argv.includes("--update");
const headroomArg = process.argv.find((a) => a.startsWith("--headroom="));
const headroom = headroomArg ? Number(headroomArg.split("=")[1]) : 0;
const current = {};
for (const build of BUILDS) {
const stats = readStats(build);
current[build] = {};
for (const entrypoint of TRACKED_ENTRYPOINTS) {
current[build][entrypoint] = entrypointInitialJS(stats, entrypoint);
}
}
if (update) {
const budget = { _comment: BUDGET_COMMENT };
for (const build of BUILDS) {
budget[build] = {};
for (const entrypoint of TRACKED_ENTRYPOINTS) {
budget[build][entrypoint] = Math.ceil(
current[build][entrypoint] * (1 + headroom / 100)
);
}
}
fs.writeFileSync(BUDGET_FILE, `${JSON.stringify(budget, null, 2)}\n`);
console.log(
`Updated ${path.relative(process.cwd(), BUDGET_FILE)} from current sizes` +
(headroom ? ` (+${headroom}% headroom).` : ".")
);
return;
}
if (!fs.existsSync(BUDGET_FILE)) {
throw new Error(
`Missing budget file ${path.relative(process.cwd(), BUDGET_FILE)}.\n` +
`Seed it from a production build with: node build-scripts/check-bundle-size.cjs --update --headroom=3`
);
}
const budget = JSON.parse(fs.readFileSync(BUDGET_FILE, "utf8"));
let failed = false;
console.log("Initial JS budget (entry chunks, raw bytes):\n");
for (const build of BUILDS) {
for (const entrypoint of TRACKED_ENTRYPOINTS) {
const actual = current[build][entrypoint];
const limit = budget[build] && budget[build][entrypoint];
if (typeof limit !== "number") {
failed = true;
console.log(
` ✗ ${build} / ${entrypoint}: no budget set (current ${kib(actual)})`
);
continue;
}
const ok = actual <= limit;
const delta = (((actual - limit) / limit) * 100).toFixed(1);
console.log(
` ${ok ? "✓" : "✗"} ${build} / ${entrypoint}: ` +
`${kib(actual)} / ${kib(limit)}${ok ? "" : ` (+${delta}% over budget)`}`
);
if (!ok) {
failed = true;
}
}
}
if (failed) {
console.error(
"\nInitial JS budget exceeded for a critical entrypoint.\n" +
"Investigate what was pulled into the entry chunk (a static import that should be lazy?).\n" +
"If the growth is intentional, re-seed the budget:\n" +
" node build-scripts/check-bundle-size.cjs --update --headroom=3"
);
process.exit(1);
}
console.log("\nAll tracked entrypoints within budget.");
};
const BUDGET_COMMENT =
"Initial JS budget (raw/uncompressed bytes) for the cold-load critical entrypoints. " +
"Enforced by build-scripts/check-bundle-size.cjs in CI. " +
"Re-seed after an intentional change with `--update --headroom=<percent>`.";
main();
+212
View File
@@ -0,0 +1,212 @@
// Content-addressed cache for compression output.
//
// brotli (quality 11) and zopfli are the slowest part of a production build,
// and they redo every file from scratch on every run. But production chunks are
// content-hashed in their filenames, so a chunk that didn't change produces
// byte-identical input here. Keying the compressed output by a hash of the
// input bytes lets an unchanged file skip compression entirely, and lets a
// nightly build warm the cache a release reuses the next day.
//
// Disabled unless COMPRESS_CACHE_DIR points at a directory. Local builds set
// nothing and behave exactly as before. The compressed bytes are unchanged
// either way; only whether they were recomputed differs.
import { createHash } from "node:crypto";
import { existsSync } from "node:fs";
import {
mkdir,
readFile,
readdir,
rename,
rm,
stat,
utimes,
writeFile,
} from "node:fs/promises";
import path from "node:path";
const rootDir = process.env.COMPRESS_CACHE_DIR;
export const cacheEnabled = Boolean(rootDir);
// Total cache size to keep across builds, least-recently-used first when over.
// The cache is shared between branches (a dev nightly warms it for a release,
// which builds from rc/master), so pruning must NOT drop everything the current
// build didn't touch — that would make each branch evict the other's
// branch-specific files every run. Instead the current build is pinned and the
// rest is kept up to this budget, so nothing is dropped unless the cache is
// genuinely too large. Override with COMPRESS_CACHE_MAX_BYTES.
const DEFAULT_MAX_BYTES = 1024 * 1024 * 1024; // 1 GiB
const maxBytes = () => {
// A valid, explicit budget wins — including 0, which keeps only the current
// build (evict everything else). An unset or invalid value uses the default.
const configured = Number(process.env.COMPRESS_CACHE_MAX_BYTES);
return Number.isFinite(configured) && configured >= 0
? configured
: DEFAULT_MAX_BYTES;
};
// Every cache key touched this build, hits and writes alike, so a prune can pin
// the current dist and never evict a file this build depends on.
const touched = new Set();
// Per-namespace directory, created lazily and only once.
const dirs = new Map();
let tmpCounter = 0;
const sha256 = (contents) =>
createHash("sha256").update(contents).digest("hex");
const namespaceDir = (namespace) => {
let dir = dirs.get(namespace);
if (!dir) {
const dirPath = path.join(rootDir, namespace);
dir = { path: dirPath, ready: undefined };
dirs.set(namespace, dir);
}
return dir;
};
const ensureDir = (dir) => {
dir.ready ??= mkdir(dir.path, { recursive: true });
return dir.ready;
};
// Written via a unique temp file and renamed into place so a concurrent reader
// in the same build never sees a half-written entry (rename is atomic on the
// same filesystem).
const writeAtomic = async (dir, name, contents) => {
await ensureDir(dir);
tmpCounter += 1;
const tmp = path.join(dir.path, `.${process.pid}-${tmpCounter}.tmp`);
const dest = path.join(dir.path, name);
await writeFile(tmp, contents);
try {
await rename(tmp, dest);
} catch (error) {
// Two files with identical contents can miss and write the same entry at
// once. On POSIX the rename just overwrites, but Windows rejects a rename
// onto an existing path. Either way the destination already holds the same
// bytes (content-addressed), so drop our temp and treat it as done.
if (existsSync(dest)) {
await rm(tmp, { force: true });
} else {
throw error;
}
}
};
/**
* Return the cached compression result for `contents`, or run `compute` and
* cache what it returns. `compute` resolves to a Buffer for compressed output,
* or `undefined` when the file should be dropped (brotli skipLarger); both
* outcomes are cached, so a dropped file is not recompressed on the next build.
*
* @param {string} namespace Isolates entries by algorithm, parameters and tool
* version, so a change to any of them can never return a stale result.
* @param {Buffer} contents Uncompressed input bytes, used as the cache key.
* @param {() => Promise<Buffer | undefined>} compute Runs on a cache miss.
* @returns {Promise<Buffer | undefined>}
*/
export const withCache = async (namespace, contents, compute) => {
if (!cacheEnabled) {
return compute();
}
const dir = namespaceDir(namespace);
const hash = sha256(contents);
touched.add(`${namespace}/${hash}`);
const dataPath = path.join(dir.path, hash);
const dropName = `${hash}.drop`;
try {
return await readFile(dataPath);
} catch {
// Miss (or unreadable) — fall through and compute.
}
if (existsSync(path.join(dir.path, dropName))) {
return undefined;
}
const result = await compute();
if (result === undefined) {
await writeAtomic(dir, dropName, "");
} else {
await writeAtomic(dir, hash, result);
}
return result;
};
/**
* Keep the cache under `maxBytes`, evicting least-recently-used entries first.
* Files this build touched are always kept (and their timestamp refreshed, so
* shared files stay warm across branches); the remainder — including another
* branch's entries — is kept up to the budget. No-op when the cache is disabled
* or nothing was compressed, so it never wipes a warm cache on a build that
* skipped compression.
*/
export const pruneCache = async () => {
if (!cacheEnabled || touched.size === 0 || !existsSync(rootDir)) {
return;
}
const now = new Date();
const pinned = [];
const others = [];
// Scan every namespace on disk, not just the ones this build used, so entries
// from an old tool version (a different namespace) are eligible for eviction.
const namespaces = await readdir(rootDir, { withFileTypes: true });
await Promise.all(
namespaces.map(async (ns) => {
if (!ns.isDirectory()) {
return;
}
const nsDir = path.join(rootDir, ns.name);
const entries = await readdir(nsDir);
await Promise.all(
entries.map(async (entry) => {
const entryPath = path.join(nsDir, entry);
// Stray temp files from an interrupted write are never valid entries.
if (entry.endsWith(".tmp")) {
await rm(entryPath, { force: true });
return;
}
const hash = entry.endsWith(".drop") ? entry.slice(0, -5) : entry;
const info = await stat(entryPath);
if (touched.has(`${ns.name}/${hash}`)) {
pinned.push({ entryPath, size: info.size });
} else {
others.push({ entryPath, size: info.size, mtimeMs: info.mtimeMs });
}
})
);
})
);
// Pinned files stay and are refreshed so they rank as most-recently-used for
// future prunes; they always count against the budget first.
let kept = 0;
await Promise.all(
pinned.map(async ({ entryPath, size }) => {
kept += size;
// A failed timestamp refresh only affects future LRU ordering, not
// correctness, so it is safe to ignore.
await utimes(entryPath, now, now).catch(() => undefined);
})
);
// Keep the most-recently-used others until the budget is spent; drop the rest.
others.sort((a, b) => b.mtimeMs - a.mtimeMs);
const budget = maxBytes();
const toDelete = [];
for (const entry of others) {
if (kept + entry.size <= budget) {
kept += entry.size;
} else {
toDelete.push(entry.entryPath);
}
}
await Promise.all(toDelete.map((p) => rm(p, { force: true })));
};
+761
View File
@@ -0,0 +1,761 @@
// Manage a Home Assistant frontend dev server with an agent-friendly interface.
//
// node build-scripts/dev-server.mjs --suite <suite> [mode] [extra args]
//
// (no mode) Run in the foreground.
// --background Start detached, wait until it is ready, print the URL
// (when it has one) and pid, then exit and leave it running.
// --status Report whether the suite's dev server is running.
// --stop Stop a running background dev server.
// --logs [--follow] Print (or follow) the background dev server log.
// --fetch-translations
// Fetch nightly translations before starting (app,
// app-serve, demo, and gallery only).
//
// Extra args (for example -p or -c on app-serve) are forwarded to the underlying
// script. Suites use one of two liveness models:
//
// health demo, gallery, e2e-app: a fixed port plus the /__ha_dev_status
// endpoint each dev server exposes (see runDevServer in
// build-scripts/gulp/rspack.js).
// process app (pnpm dev) and app-serve (pnpm dev:serve): plain pnpm dev has
// no port, so these treat the first "Build done" log line as ready.
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import {
LIFECYCLE_MODE_FLAGS,
acquireProcessRecord,
detectCodingAgent,
isProcessRecordAlive,
outputLog,
offerToStopProcessRecord,
processStartTime,
readProcessRecord,
releaseProcessRecord,
runCli,
sleep,
spawnDetachedToLog,
spawnForeground,
terminateDetachedProcess,
terminateProcess,
writeProcessRecord,
} from "./managed-process.mjs";
import {
buildCacheDir,
describeOutputOwner,
workflowLockEnv,
workflowLockFile,
} from "./output-lock.mjs";
const repoRoot = path.resolve(
path.dirname(fileURLToPath(import.meta.url)),
".."
);
const gulpBin = path.join(repoRoot, "node_modules", ".bin", "gulp");
const developAndServeScript = path.join(
repoRoot,
"script",
"develop_and_serve"
);
const logDir = path.join(buildCacheDir, "ha-dev-server");
// Each suite names its pnpm alias (for hints), a liveness model, and how to
// spawn it. health suites carry a fixed port; process suites carry the log line
// that means "ready" and, for app-serve, forward extra args to the script.
const SUITES = new Map([
[
"e2e-app",
{
alias: "test:e2e:app:dev",
liveness: "health",
port: 8095,
spawn: { cmd: gulpBin, args: ["develop-e2e-test-app"] },
},
],
[
"demo",
{
alias: "dev:demo",
fetchTranslations: true,
liveness: "health",
port: 8090,
spawn: { cmd: gulpBin, args: ["develop-demo"] },
},
],
[
"gallery",
{
alias: "dev:gallery",
fetchTranslations: true,
liveness: "health",
port: 8100,
spawn: { cmd: gulpBin, args: ["develop-gallery"] },
},
],
[
"app",
{
alias: "dev",
fetchTranslations: true,
liveness: "process",
readyLog: /Build done @/,
spawn: { cmd: gulpBin, args: ["develop-app"] },
},
],
[
"app-serve",
{
alias: "dev:serve",
liveness: "process",
acceptsArgs: true,
fetchTranslations: true,
readyLog: /Build done @/,
spawn: { cmd: developAndServeScript, args: [] },
},
],
]);
// Cover a cold build on a slow machine before the server starts listening.
// Override with HA_DEV_SERVER_TIMEOUT (seconds).
const readyTimeoutSeconds = Number(process.env.HA_DEV_SERVER_TIMEOUT || "180");
const READY_TIMEOUT_MS =
Number.isFinite(readyTimeoutSeconds) && readyTimeoutSeconds > 0
? readyTimeoutSeconds * 1000
: 180_000;
const usage = () => {
const suites = [...SUITES.keys()].join("|");
process.stderr.write(
`Usage: node build-scripts/dev-server.mjs --suite <${suites}> ` +
`[--background | --status | --stop | --logs [--follow]] ` +
`[--fetch-translations]\n`
);
};
const parseArgs = (argv) => {
const args = {
fetchTranslations: false,
mode: "foreground",
follow: false,
modes: [],
suite: undefined,
passthrough: [],
};
for (let i = 0; i < argv.length; i++) {
const arg = argv[i];
switch (arg) {
case "--suite":
args.suite = argv[++i];
break;
case "--follow":
args.follow = true;
break;
case "--fetch-translations":
args.fetchTranslations = true;
break;
default:
if (LIFECYCLE_MODE_FLAGS.has(arg)) {
args.mode = LIFECYCLE_MODE_FLAGS.get(arg);
args.modes.push(arg);
} else {
// Anything unrecognised is forwarded to the underlying script.
args.passthrough.push(arg);
}
}
}
return args;
};
const translationPrebuildEnv = (token) => {
const env = workflowLockEnv(token);
delete env.SKIP_FETCH_NIGHTLY_TRANSLATIONS;
return env;
};
const suiteEnv = (token, fetchTranslations = false) => ({
...workflowLockEnv(token),
...(fetchTranslations && { SKIP_FETCH_NIGHTLY_TRANSLATIONS: "1" }),
});
const runPrebuild = (token, fetchTranslations = false) =>
fetchTranslations
? spawnForeground({
cmd: gulpBin,
args: ["setup-and-fetch-nightly-translations"],
cwd: repoRoot,
env: translationPrebuildEnv(token),
processGroup: true,
})
: Promise.resolve(0);
const logFileFor = (suite) => path.join(logDir, `${suite}.log`);
const acquireSuite = (suite) => {
const token = `${process.pid}-${Date.now()}-${Math.random()}`;
const record = {
pid: process.pid,
startTime: processStartTime(process.pid),
processGroup: false,
kind: "dev",
suite,
starting: true,
token,
};
const result = acquireProcessRecord(workflowLockFile, record);
return result.acquired ? { token } : { existing: result.existing };
};
const updateSuite = (suite, token, child, port) => {
const existing = readProcessRecord(workflowLockFile);
if (existing?.token !== token) {
throw Error(`Dev server (${suite}) ownership was lost during startup.`);
}
writeProcessRecord(workflowLockFile, {
...existing,
pid: child.pid,
startTime: processStartTime(child.pid),
processGroup: true,
starting: false,
port,
});
};
const releaseSuite = (token) => releaseProcessRecord(workflowLockFile, token);
const readSuite = (suite) => {
const existing = readProcessRecord(workflowLockFile);
if (existing?.kind !== "dev" || existing.suite !== suite) {
return undefined;
}
if (isProcessRecordAlive(existing)) {
return existing;
}
releaseSuite(existing.token);
return undefined;
};
const hints = (suite) => {
const alias = `pnpm ${SUITES.get(suite).alias}`;
return (
` Stop: ${alias} --stop\n` +
` Status: ${alias} --status\n` +
` Logs: ${alias} --logs\n`
);
};
const reportProcessConflict = (suite, existing) => {
if (existing?.kind === "output") {
process.stdout.write(
`${describeOutputOwner(existing)} already owns the app output` +
`${existing.pid ? ` (pid ${existing.pid})` : ""}.\n`
);
return;
}
if (existing?.kind === "build") {
process.stdout.write(
`Frontend build already running${existing.pid ? ` (pid ${existing.pid})` : ""}. ` +
"Stop it with pnpm build --stop.\n"
);
return;
}
process.stdout.write(
`Dev server (${existing?.suite ?? suite}) already running` +
`${urlSuffix(existing?.port)} ` +
`${existing?.pid ? `(pid ${existing.pid})` : ""}\n` +
hints(existing?.suite ?? suite)
);
};
const stopCommandFor = (owner) =>
owner?.kind === "build"
? "pnpm build --stop"
: owner?.kind === "dev"
? `pnpm ${SUITES.get(owner.suite)?.alias ?? "dev"} --stop`
: undefined;
const acquireSuiteForStart = async (suite) => {
const lock = acquireSuite(suite);
if (lock.token) {
return lock;
}
reportProcessConflict(suite, lock.existing);
if (
await offerToStopProcessRecord({
file: workflowLockFile,
owner: lock.existing,
ownerDescription: describeOutputOwner(lock.existing),
stopCommand: stopCommandFor(lock.existing),
})
) {
return acquireSuiteForStart(suite);
}
return {
code:
lock.existing?.kind === "dev" &&
lock.existing.suite === suite &&
!lock.existing.starting
? 0
: 1,
};
};
// --- shared spawning and lifecycle ------------------------------------------
const urlSuffix = (port) => (port ? ` at http://localhost:${port}` : "");
// Poll until the server is ready, the child exits, or we time out. Prints the
// progress dots and outcome; returns 0 when ready, 1 otherwise. onExit runs if
// the child dies before it is ready (used to clear a stale pidfile).
const awaitReady = async ({ suite, child, logFile, port, isReady, onExit }) => {
let childExited = false;
child.on("exit", () => {
childExited = true;
});
const deadline = Date.now() + READY_TIMEOUT_MS;
process.stdout.write(`Starting ${suite} dev server`);
const poll = async () => {
if (childExited) {
process.stdout.write("\n");
process.stderr.write(
`Dev server (${suite}) exited before it was ready. See ${logFile}\n`
);
onExit?.();
return 1;
}
if (await isReady()) {
process.stdout.write("\n");
process.stdout.write(
`Dev server (${suite}) running${urlSuffix(port)} ` +
`(pid ${child.pid})\n${hints(suite)}`
);
return 0;
}
if (Date.now() >= deadline) {
return undefined;
}
process.stdout.write(".");
await sleep(1000);
return poll();
};
const result = await poll();
if (result !== undefined) {
return result;
}
process.stdout.write("\n");
process.stderr.write(
`Dev server (${suite}) did not become ready within ${
READY_TIMEOUT_MS / 1000
}s. See ${logFile}\n`
);
const stopped = await terminateProcess({
pid: child.pid,
isStopped: () => childExited,
});
if (stopped) {
onExit?.();
}
return 1;
};
// Stop a running background server: SIGTERM, wait for it to go, then SIGKILL.
// isStopped reports when it is gone; onStopped runs on success (pidfile cleanup).
const terminate = async (suite, pid, isStopped, onStopped) => {
if (!(await terminateProcess({ pid, isStopped }))) {
process.stderr.write(
`Failed to stop dev server (${suite}) (pid ${pid}). Stop it manually.\n`
);
return 1;
}
onStopped?.();
process.stdout.write(`Stopped dev server (${suite}) (pid ${pid}).\n`);
return 0;
};
// --- health liveness (port + /__ha_dev_status) ------------------------------
/**
* Probe the health endpoint. Dev servers bind IPv4 or IPv6 localhost depending
* on the OS, so try each; the port is "free" only if every address refuses.
* @returns {Promise<{state: "ours" | "foreign" | "free", suite?: string}>}
*/
const PROBE_HOSTS = ["localhost", "127.0.0.1", "[::1]"];
const probe = async (port, timeoutMs = 1000) => {
const probeHost = async (index, sawResponse) => {
const host = PROBE_HOSTS[index];
if (!host) {
return sawResponse ? { state: "foreign" } : { state: "free" };
}
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
try {
const res = await fetch(`http://${host}:${port}/__ha_dev_status`, {
signal: controller.signal,
});
sawResponse = true;
if (res.ok) {
const body = await res.json().catch(() => null);
if (body && body.server === "ha-frontend-dev") {
return { state: "ours", suite: body.suite };
}
}
} catch {
// Try the next address.
} finally {
clearTimeout(timer);
}
return probeHost(index + 1, sawResponse);
};
return probeHost(0, false);
};
const isHttpServing = async (port, timeoutMs = 1000) => {
const probeHost = async (index) => {
const host = PROBE_HOSTS[index];
if (!host) {
return false;
}
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
try {
const response = await fetch(`http://${host}:${port}`, {
signal: controller.signal,
});
if (response.ok) {
return true;
}
} catch {
// Try the next address.
} finally {
clearTimeout(timer);
}
return probeHost(index + 1);
};
return probeHost(0);
};
const runForegroundHealth = async (suite, cfg, fetchTranslations = false) => {
const { port } = cfg;
const lock = await acquireSuiteForStart(suite);
if (!lock.token) {
return lock.code;
}
const status = await probe(port);
if (status.state === "ours") {
releaseSuite(lock.token);
process.stderr.write(
`Port ${port} is already serving the ${status.suite ?? "unknown"} dev server.\n`
);
return 1;
}
if (status.state === "foreign") {
releaseSuite(lock.token);
process.stderr.write(
`Port ${port} is in use by another process; not the ${suite} dev server.\n`
);
return 1;
}
try {
const prebuildCode = await runPrebuild(lock.token, fetchTranslations);
if (prebuildCode !== 0) {
return prebuildCode;
}
return await spawnForeground({
cmd: cfg.spawn.cmd,
args: cfg.spawn.args,
cwd: repoRoot,
env: suiteEnv(lock.token, fetchTranslations),
processGroup: true,
onSpawn: (child) => updateSuite(suite, lock.token, child, port),
});
} finally {
releaseSuite(lock.token);
}
};
const runBackgroundHealth = async (suite, cfg, fetchTranslations = false) => {
const { port } = cfg;
const lock = await acquireSuiteForStart(suite);
if (!lock.token) {
return lock.code;
}
const preflight = await probe(port);
if (preflight.state === "ours") {
releaseSuite(lock.token);
process.stderr.write(
`Port ${port} is already serving the ${preflight.suite ?? "unknown"} dev server.\n`
);
return 1;
}
if (preflight.state === "foreign") {
releaseSuite(lock.token);
process.stderr.write(
`Port ${port} is in use by another process; not the ${suite} dev server.\n`
);
return 1;
}
let child;
try {
const prebuildCode = await runPrebuild(lock.token, fetchTranslations);
if (prebuildCode !== 0) {
releaseSuite(lock.token);
return prebuildCode;
}
const logFile = logFileFor(suite);
child = await spawnDetachedToLog({
cmd: cfg.spawn.cmd,
args: cfg.spawn.args,
cwd: repoRoot,
env: suiteEnv(lock.token, fetchTranslations),
logFile,
});
updateSuite(suite, lock.token, child, port);
return awaitReady({
suite,
child,
logFile,
port,
isReady: async () => {
const status = await probe(port, 1000);
return status.state === "ours" && status.suite === suite;
},
onExit: () => releaseSuite(lock.token),
});
} catch (err) {
if (child) {
await terminateDetachedProcess(child);
}
releaseSuite(lock.token);
throw err;
}
};
const logIsReady = (logFile, readyLog) => {
try {
return readyLog.test(fs.readFileSync(logFile, "utf8"));
} catch {
return false;
}
};
// app-serve serves on 8124 by default (8123 in a devcontainer), or whatever -p
// the caller passed. Used only to show a URL; liveness comes from the pidfile.
const resolveServePort = (passthrough) => {
for (let i = passthrough.length - 1; i >= 0; i--) {
const arg = passthrough[i];
if (arg === "-p" || arg.startsWith("-p")) {
const port = Number(arg === "-p" ? passthrough[i + 1] : arg.slice(2));
if (Number.isInteger(port) && port > 0) {
return port;
}
}
}
return process.env.DEVCONTAINER ? 8123 : 8124;
};
const spawnArgs = (cfg, passthrough) => [
...cfg.spawn.args,
...(cfg.acceptsArgs ? passthrough : []),
];
const runForegroundProcess = async (
suite,
cfg,
passthrough,
fetchTranslations = false
) => {
const lock = await acquireSuiteForStart(suite);
if (!lock.token) {
return lock.code;
}
try {
const prebuildCode = await runPrebuild(lock.token, fetchTranslations);
if (prebuildCode !== 0) {
return prebuildCode;
}
return await spawnForeground({
cmd: cfg.spawn.cmd,
args: spawnArgs(cfg, passthrough),
cwd: repoRoot,
env: suiteEnv(lock.token, fetchTranslations),
processGroup: true,
onSpawn: (child) => updateSuite(suite, lock.token, child),
});
} finally {
releaseSuite(lock.token);
}
};
const runBackgroundProcess = async (
suite,
cfg,
passthrough,
fetchTranslations = false
) => {
const lock = await acquireSuiteForStart(suite);
if (!lock.token) {
return lock.code;
}
let child;
try {
const prebuildCode = await runPrebuild(lock.token, fetchTranslations);
if (prebuildCode !== 0) {
releaseSuite(lock.token);
return prebuildCode;
}
const logFile = logFileFor(suite);
child = await spawnDetachedToLog({
cmd: cfg.spawn.cmd,
args: spawnArgs(cfg, passthrough),
cwd: repoRoot,
env: suiteEnv(lock.token, fetchTranslations),
logFile,
});
const port = cfg.acceptsArgs ? resolveServePort(passthrough) : cfg.port;
updateSuite(suite, lock.token, child, port);
return awaitReady({
suite,
child,
logFile,
port,
isReady: async () =>
logIsReady(logFile, cfg.readyLog) &&
(!cfg.acceptsArgs || (await isHttpServing(port))),
onExit: () => releaseSuite(lock.token),
});
} catch (err) {
if (child) {
await terminateDetachedProcess(child);
}
releaseSuite(lock.token);
throw err;
}
};
const runStatusSuite = async (suite, cfg) => {
const existing = readSuite(suite);
if (existing) {
process.stdout.write(
`Dev server (${existing.suite ?? suite}) running${urlSuffix(existing.port ?? cfg.port)} ` +
`(pid ${existing.pid})\n`
);
} else {
process.stdout.write(`Dev server (${suite}) not running.\n`);
}
return 0;
};
const runStopSuite = async (suite) => {
const existing = readSuite(suite);
if (!existing) {
process.stdout.write(`Dev server (${suite}) not running.\n`);
return 0;
}
const { pid } = existing;
const activeSuite = existing.suite ?? suite;
return terminate(
activeSuite,
pid,
() => !isProcessRecordAlive(existing),
() => releaseSuite(existing.token)
);
};
// --- shared -----------------------------------------------------------------
const runLogs = (suite, follow) => {
const activeSuite = readSuite(suite)?.suite ?? suite;
return outputLog(
logFileFor(activeSuite),
follow,
`No log for the ${activeSuite} dev server yet (${logFileFor(activeSuite)}).\n`
);
};
const main = async () => {
const args = parseArgs(process.argv.slice(2));
const cfg = SUITES.get(args.suite);
if (!cfg) {
usage();
return 1;
}
if (args.modes.length > 1 || (args.follow && args.mode !== "logs")) {
process.stderr.write("Invalid combination of lifecycle arguments.\n");
usage();
return 1;
}
if (
args.fetchTranslations &&
(!["foreground", "background"].includes(args.mode) ||
!cfg.fetchTranslations)
) {
process.stderr.write(
"--fetch-translations is only supported when starting app, app-serve, demo, or gallery.\n"
);
usage();
return 1;
}
if (args.passthrough.length && !cfg.acceptsArgs) {
process.stderr.write(
`Ignoring unexpected arguments: ${args.passthrough.join(" ")}\n`
);
}
// A plain dev:<suite> under a coding agent backgrounds itself; explicit modes
// are untouched.
let { mode } = args;
if (
mode === "foreground" &&
!["0", "false"].includes(process.env.HA_DEV_BACKGROUND)
) {
const agent = detectCodingAgent();
if (agent) {
process.stdout.write(
`Detected coding agent (${agent}); starting in the background. ` +
`Set HA_DEV_BACKGROUND=0 to force foreground.\n`
);
mode = "background";
}
}
if (mode === "logs") {
return runLogs(args.suite, args.follow);
}
if (mode === "status") {
return runStatusSuite(args.suite, cfg);
}
if (mode === "stop") {
return runStopSuite(args.suite);
}
const handlers =
cfg.liveness === "health"
? {
foreground: () =>
runForegroundHealth(args.suite, cfg, args.fetchTranslations),
background: () =>
runBackgroundHealth(args.suite, cfg, args.fetchTranslations),
}
: {
foreground: () =>
runForegroundProcess(
args.suite,
cfg,
args.passthrough,
args.fetchTranslations
),
background: () =>
runBackgroundProcess(
args.suite,
cfg,
args.passthrough,
args.fetchTranslations
),
};
return handlers[mode]();
};
runCli(main);
+10
View File
@@ -0,0 +1,10 @@
// @ts-check
import { noUnusedElementImport } from "./no-unused-element-import.mjs";
export default {
meta: { name: "eslint-plugin-ha" },
rules: {
"no-unused-element-import": noUnusedElementImport,
},
};
@@ -0,0 +1,188 @@
// @ts-check
import fs from "node:fs";
import path from "node:path";
const TAG_PATTERN =
/@customElement\(\s*["'`]([a-z0-9_-]+)["'`]|customElements\.define\(\s*["'`]([a-z0-9_-]+)["'`]/g;
const EXTENSIONS = /\.(ts|js)$/;
// Entry points register the root element that the served HTML renders.
const ENTRY_POINT = /(^|[\\/])(entrypoints[\\/]|entrypoint\.(ts|js)$)/;
// These resolve a tag from config at runtime, so they register every candidate
// they may be asked for.
const RUNTIME_REGISTRY =
/[\\/]create-element[\\/]|createLovelaceElement\(|getLovelaceElementClass\(/;
/** @type {Map<string, string[]>} */
const tagCache = new Map();
/** Tags the module at `file` registers when imported. */
const registeredTags = (file) => {
let tags = tagCache.get(file);
if (!tags) {
try {
const source = fs.readFileSync(file, "utf8");
tags = [...source.matchAll(TAG_PATTERN)].map((m) => m[1] || m[2]);
} catch {
tags = [];
}
tagCache.set(file, tags);
}
return tags;
};
const isFile = (candidate) => {
try {
return fs.statSync(candidate).isFile();
} catch {
return false;
}
};
const resolveModule = (fromFile, request) => {
const base = path.resolve(path.dirname(fromFile), request);
return [
base,
`${base}.ts`,
`${base}.js`,
base.replace(/\.js$/, ".ts"),
path.join(base, "index.ts"),
path.join(base, "index.js"),
].find((candidate) => EXTENSIONS.test(candidate) && isFile(candidate));
};
// `hui-${type}-card` or "state-card-" + domain never spell the tag out.
const buildsTagAtRuntime = (source, tag) => {
const segments = tag.split("-");
for (let end = 1; end < segments.length; end++) {
const prefix = `${segments.slice(0, end).join("-")}-`;
if (
source.includes(`\`${prefix}\${`) ||
source.includes(`"${prefix}" +`) ||
source.includes(`'${prefix}' +`)
) {
return true;
}
}
return false;
};
// Plain substring matching, so <ha-icon-button> counts as a use of ha-icon.
// That direction is deliberate: it misses dead imports rather than asking for
// a removal that breaks registration.
const usesTag = (body, tag) => body.includes(tag);
// A gallery page registers the elements its sibling markdown demos render, so
// that markdown is part of what the module is used by.
const siblingMarkup = (file) => {
const markdown = file.replace(EXTENSIONS, ".markdown");
try {
return fs.readFileSync(markdown, "utf8");
} catch {
return "";
}
};
/** Blanks out the given ranges so an import path cannot count as a usage. */
const withoutRanges = (source, ranges) => {
let result = source;
for (const [start, end] of ranges) {
result =
result.slice(0, start) + " ".repeat(end - start) + result.slice(end);
}
return result;
};
/**
* Side-effect imports register a custom element. ESLint's unused-import rules
* cannot judge them — there is no binding to be unused — so a registration
* outlives the template that needed it and nothing reports the dead import.
*
* Deliberately not fixable: removing the import is only safe once every file
* that renders the element imports it itself, which this rule cannot see.
*
* Off in eslint.config.mjs while a backlog of those paired cases remains;
* `pnpm lint:element-imports` enables it as a warning to list them. Flip it to
* "error" there once the list is empty.
*
* No disable comments while it is off: ESLint reports them as unused
* directives, which fails lint:eslint. Imports that must stay get theirs in
* the change that turns the rule on.
*/
export const noUnusedElementImport = {
meta: {
type: "suggestion",
docs: {
description:
"Disallow side-effect imports of a custom element the importing file never uses",
},
schema: [],
messages: {
unused:
'"{{request}}" only registers <{{tags}}>, which this file never uses. Remove the import, adding it to whichever file renders the element if that file relies on this registration.',
},
},
create(context) {
const filename = context.filename;
if (!EXTENSIONS.test(filename) || ENTRY_POINT.test(filename)) {
return {};
}
return {
Program(program) {
const imports = program.body.filter(
(node) => node.type === "ImportDeclaration"
);
const sideEffectImports = imports.filter(
(node) =>
node.specifiers.length === 0 &&
typeof node.source.value === "string" &&
node.source.value.startsWith(".")
);
if (!sideEffectImports.length) {
return;
}
const source = context.sourceCode.getText();
if (RUNTIME_REGISTRY.test(filename) || RUNTIME_REGISTRY.test(source)) {
return;
}
// Every import declaration, not just the side-effect ones: a module
// path is never a usage, and `import type { HaCard } from "./ha-card"`
// would otherwise pass off its own path as one.
const body =
withoutRanges(
source,
imports.map((node) => node.range)
) + siblingMarkup(filename);
for (const node of sideEffectImports) {
const request = node.source.value;
const target = resolveModule(filename, request);
if (!target) {
continue;
}
// No tags means no registration to judge: styles, polyfills, mocks.
const tags = registeredTags(target);
if (
!tags.length ||
tags.some(
(tag) => usesTag(body, tag) || buildsTagAtRuntime(body, tag)
)
) {
continue;
}
context.report({
node,
messageId: "unused",
data: { request, tags: tags.join(">, <") },
});
}
},
};
},
};
+7 -3
View File
@@ -1,14 +1,18 @@
// @ts-check
import globals from "globals";
import tseslint from "typescript-eslint";
import rootConfig from "../eslint.config.mjs";
export default tseslint.config(...rootConfig, {
languageOptions: {
globals: globals.node,
},
rules: {
"no-console": "off",
"import/no-extraneous-dependencies": "off",
"import/extensions": "off",
"import/no-dynamic-require": "off",
"import-x/no-extraneous-dependencies": "off",
"import-x/extensions": "off",
"import-x/no-dynamic-require": "off",
"global-require": "off",
"@typescript-eslint/no-require-imports": "off",
"prefer-arrow-callback": "off",
@@ -0,0 +1,11 @@
// Browser-only replacement for core-js/internals/get-built-in-node-module.
// The original helper evaluates `Function('return require("...")')()`
// when it detects a Node environment, which causes a runtime
// ReferenceError on browsers (notably Safari 14) if environment
// detection mis-classifies the page. Since browser bundles never need to
// access Node built-in modules, return undefined unconditionally.
//
// Wired up via rspack `NormalModuleReplacementPlugin` in build-scripts/rspack.cjs.
module.exports = function () {
return undefined;
};
+36 -1
View File
@@ -1,10 +1,12 @@
import gulp from "gulp";
import env from "../env.cjs";
import { createWorkflowLockTask } from "../output-lock.mjs";
import "./clean.js";
import "./compress.js";
import "./entry-html.js";
import "./gather-static.js";
import "./gen-icons-json.js";
import "./licenses.js";
import "./locale-data.js";
import "./service-worker.js";
import "./translations.js";
@@ -16,6 +18,7 @@ gulp.task(
async function setEnv() {
process.env.NODE_ENV = "development";
},
createWorkflowLockTask("develop-app"),
"clean",
gulp.parallel(
"gen-service-worker-app-dev",
@@ -35,12 +38,44 @@ gulp.task(
async function setEnv() {
process.env.NODE_ENV = "production";
},
createWorkflowLockTask("build-app"),
"clean",
gulp.parallel("gen-icons-json", "build-translations", "build-locale-data"),
gulp.parallel(
"gen-icons-json",
"build-translations",
"build-locale-data",
"gen-licenses"
),
"copy-static-app",
"rspack-prod-app",
gulp.parallel("gen-pages-app-prod", "gen-service-worker-app-prod"),
// Don't compress running tests
...(env.isTestBuild() || env.isStatsBuild()
? []
: ["compress-app", "prune-compress-cache"])
)
);
gulp.task(
"build-app-modern",
gulp.series(
async function setEnv() {
process.env.NODE_ENV = "production";
},
createWorkflowLockTask("build-app-modern"),
"clean",
gulp.parallel(
"gen-icons-json",
"build-translations",
"build-locale-data",
"gen-licenses"
),
"copy-static-app",
"rspack-prod-app-modern",
gulp.parallel(
"gen-pages-app-prod-modern",
"gen-service-worker-app-prod-modern"
),
...(env.isTestBuild() || env.isStatsBuild() ? [] : ["compress-app"])
)
);
+7 -4
View File
@@ -24,10 +24,6 @@ gulp.task(
)
);
gulp.task("clean-hassio", async () =>
deleteSync([paths.hassio_output_root, paths.build_dir])
);
gulp.task(
"clean-gallery",
gulp.parallel("clean-translations", async () =>
@@ -49,3 +45,10 @@ gulp.task(
])
)
);
gulp.task(
"clean-e2e-test-app",
gulp.parallel("clean-translations", async () =>
deleteSync([paths.e2eTestApp_output_root, paths.build_dir])
)
);
+7 -29
View File
@@ -2,9 +2,10 @@
import { constants } from "node:zlib";
import gulp from "gulp";
import brotli from "gulp-brotli";
import zopfli from "gulp-zopfli-green";
import brotli from "../brotli.mjs";
import { pruneCache } from "../compress-cache.mjs";
import paths from "../paths.cjs";
import zopfli from "../zopfli.mjs";
const filesGlob = "*.{js,json,css,svg,xml}";
const brotliOptions = {
@@ -43,29 +44,11 @@ const compressAppModernBrotli = () =>
const compressAppModernZopfli = () =>
compressModern(paths.app_output_root, paths.app_output_latest, "zopfli");
const compressHassioModernBrotli = () =>
compressModern(
paths.hassio_output_root,
paths.hassio_output_latest,
"brotli"
);
const compressHassioModernZopfli = () =>
compressModern(
paths.hassio_output_root,
paths.hassio_output_latest,
"zopfli"
);
const compressAppOtherBrotli = () =>
compressOther(paths.app_output_root, paths.app_output_latest, "brotli");
const compressAppOtherZopfli = () =>
compressOther(paths.app_output_root, paths.app_output_latest, "zopfli");
const compressHassioOtherBrotli = () =>
compressOther(paths.hassio_output_root, paths.hassio_output_latest, "brotli");
const compressHassioOtherZopfli = () =>
compressOther(paths.hassio_output_root, paths.hassio_output_latest, "zopfli");
gulp.task(
"compress-app",
gulp.parallel(
@@ -75,12 +58,7 @@ gulp.task(
compressAppOtherZopfli
)
);
gulp.task(
"compress-hassio",
gulp.parallel(
compressHassioModernBrotli,
compressHassioOtherBrotli,
compressHassioModernZopfli,
compressHassioOtherZopfli
)
);
// Keep the compression cache under its size budget (LRU, this build pinned).
// No-op unless COMPRESS_CACHE_DIR is set.
gulp.task("prune-compress-cache", () => pruneCache());
+19
View File
@@ -1,4 +1,5 @@
import gulp from "gulp";
import { createWorkflowLockTask } from "../output-lock.mjs";
import "./clean.js";
import "./entry-html.js";
import "./gather-static.js";
@@ -13,6 +14,7 @@ gulp.task(
async function setEnv() {
process.env.NODE_ENV = "development";
},
createWorkflowLockTask("develop-demo"),
"clean-demo",
"translations-enable-merge-backend",
gulp.parallel(
@@ -32,6 +34,7 @@ gulp.task(
async function setEnv() {
process.env.NODE_ENV = "production";
},
createWorkflowLockTask("build-demo"),
"clean-demo",
// Cast needs to be backwards compatible and older HA has no translations
"translations-enable-merge-backend",
@@ -42,6 +45,22 @@ gulp.task(
)
);
gulp.task(
"build-demo-e2e",
gulp.series(
async function setEnv() {
process.env.NODE_ENV = "production";
},
"clean-demo",
// Cast needs to be backwards compatible and older HA has no translations
"translations-enable-merge-backend",
gulp.parallel("gen-icons-json", "build-translations", "build-locale-data"),
"copy-static-demo",
"rspack-prod-demo-e2e",
"gen-pages-demo-prod-e2e"
)
);
gulp.task(
"analyze-demo",
gulp.series(
+105 -48
View File
@@ -99,6 +99,44 @@ const lokaliseProjects = {
frontend: "3420425759f6d6d241f598.13594006",
};
const POLL_INTERVAL_MS = 1000;
/* eslint-disable no-await-in-loop */
async function pollProcess(lokaliseApi, projectId, processId) {
while (true) {
const process = await lokaliseApi
.queuedProcesses()
.get(processId, { project_id: projectId });
const project =
projectId === lokaliseProjects.backend ? "backend" : "frontend";
if (process.status === "finished") {
console.log(`Lokalise export process for ${project} finished`);
return process;
}
if (process.status === "failed" || process.status === "cancelled") {
throw new Error(
`Lokalise export process for ${project} ${process.status}: ${process.message}`
);
}
console.log(
`Lokalise export process for ${project} in progress...`,
process.status,
process.details?.items_to_process
? `${Math.round(((process.details.items_processed || 0) / process.details.items_to_process) * 100)}% (${process.details.items_processed}/${process.details.items_to_process})`
: ""
);
await new Promise((resolve) => {
setTimeout(resolve, POLL_INTERVAL_MS);
});
}
}
/* eslint-enable no-await-in-loop */
gulp.task("fetch-lokalise", async function () {
let apiKey;
try {
@@ -117,56 +155,75 @@ gulp.task("fetch-lokalise", async function () {
fs.mkdir(inDirBackend, { recursive: true }),
]);
// The backend project only provides entity_component translations, which are
// merged into the demo, gallery, cast and e2e builds. The shipped app fetches
// them live from core, so builds that only produce the app (release, release
// landing-page) can skip this second, whole-project export to save time.
const projects = Object.entries(lokaliseProjects).filter(
([project]) =>
!(project === "backend" && process.env.SKIP_BACKEND_TRANSLATIONS)
);
if (projects.length !== Object.keys(lokaliseProjects).length) {
console.log(
"Skipping backend translations download (SKIP_BACKEND_TRANSLATIONS)"
);
}
await Promise.all(
Object.entries(lokaliseProjects).map(([project, projectId]) =>
lokaliseApi
.files()
.download(projectId, {
format: "json",
original_filenames: false,
replace_breaks: false,
json_unescaped_slashes: true,
export_empty_as: "skip",
filter_data: ["verified"],
})
.then((download) => fetch(download.bundle_url))
.then((response) => {
if (response.status === 200 || response.status === 0) {
return response.arrayBuffer();
}
projects.map(async ([project, projectId]) => {
try {
const exportProcess = await lokaliseApi
.files()
.async_download(projectId, {
format: "json",
original_filenames: false,
replace_breaks: false,
json_unescaped_slashes: true,
export_empty_as: "skip",
filter_data: ["verified"],
});
const finishedProcess = await pollProcess(
lokaliseApi,
projectId,
exportProcess.process_id
);
const bundleUrl = finishedProcess.details.download_url;
console.log(`Downloading translations from: ${bundleUrl}`);
const response = await fetch(bundleUrl);
if (response.status !== 200 && response.status !== 0) {
throw new Error(response.statusText);
})
.then(JSZip.loadAsync)
.then(async (contents) => {
await mkdirPromise;
return Promise.all(
Object.keys(contents.files).map(async (filename) => {
const file = contents.file(filename);
if (!file) {
// no file, probably a directory
return Promise.resolve();
}
return file
.async("nodebuffer")
.then((content) =>
fs.writeFile(
path.join(
inDir,
project,
filename.split("/").splice(-1)[0]
),
content,
{ flag: "w", encoding }
)
);
})
);
})
.catch((err) => {
console.error(err);
throw err;
})
)
}
console.log(`Extracting translations...`);
const contents = await JSZip.loadAsync(await response.arrayBuffer());
await mkdirPromise;
await Promise.all(
Object.keys(contents.files).map(async (filename) => {
const file = contents.file(filename);
if (!file) {
// no file, probably a directory
return;
}
const content = await file.async("nodebuffer");
await fs.writeFile(
path.join(inDir, project, filename.split("/").splice(-1)[0]),
content,
{ flag: "w", encoding }
);
})
);
} catch (err) {
console.error(err);
throw err;
}
})
);
});
+59
View File
@@ -0,0 +1,59 @@
import gulp from "gulp";
import { createWorkflowLockTask } from "../output-lock.mjs";
import "./clean.js";
import "./entry-html.js";
import "./gather-static.js";
import "./gen-icons-json.js";
import "./translations.js";
import "./rspack.js";
gulp.task(
"develop-e2e-test-app",
gulp.series(
async function setEnv() {
process.env.NODE_ENV = "development";
},
createWorkflowLockTask("develop-e2e-test-app"),
"clean-e2e-test-app",
"translations-enable-merge-backend",
gulp.parallel(
"gen-icons-json",
"gen-pages-e2e-test-app-dev",
"build-translations",
"build-locale-data"
),
"copy-static-e2e-test-app",
"rspack-dev-server-e2e-test-app"
)
);
gulp.task(
"build-e2e-test-app",
gulp.series(
async function setEnv() {
process.env.NODE_ENV = "production";
},
createWorkflowLockTask("build-e2e-test-app"),
"clean-e2e-test-app",
"translations-enable-merge-backend",
gulp.parallel("gen-icons-json", "build-translations", "build-locale-data"),
"copy-static-e2e-test-app",
"rspack-prod-e2e-test-app",
"gen-pages-e2e-test-app-prod"
)
);
gulp.task(
"build-e2e-test-app-e2e",
gulp.series(
async function setEnv() {
process.env.NODE_ENV = "production";
},
"clean-e2e-test-app",
"translations-enable-merge-backend",
gulp.parallel("gen-icons-json", "build-translations", "build-locale-data"),
"copy-static-e2e-test-app",
"rspack-prod-e2e-test-app-e2e",
"gen-pages-e2e-test-app-prod"
)
);
+53 -17
View File
@@ -25,6 +25,7 @@ const SAFARI_TO_MACOS = {
16: [11, 0, 0],
17: [12, 0, 0],
18: [13, 0, 0],
26: [14, 6, 0],
};
const getCommonTemplateVars = () => {
@@ -57,6 +58,12 @@ const getCommonTemplateVars = () => {
return {
modernRegex: compileRegex(browserRegexes.concat(haMacOSRegex)).toString(),
hassUrl: process.env.HASS_URL || "",
// Single source for the stale-build recovery patterns, shared with the
// bundled src/util/recover-stale-build.ts and injected into the inline
// boot guard (_bootstrap_recovery.html.template).
staleBuildPatterns: fs.readJsonSync(
resolve(paths.root_dir, "src/util/stale-build-patterns.json")
),
};
};
@@ -82,7 +89,7 @@ const minifyHtml = (content, ext) => {
...htmlMinifierOptions,
conservativeCollapse: false,
minifyJS: terserOptions({
latestBuild: false, // Shared scripts should be ES5
latestBuild: false, // Shared scripts must satisfy the legacy targets
isTestBuild: true, // Don't need source maps
}),
}).then((wrapped) =>
@@ -106,6 +113,9 @@ const genPagesDevTask =
resolve(inputRoot, inputSub, `${page}.template`),
{
...commonVars,
// Dev entries are unhashed, so the stale-index recovery guard has
// nothing to key off and rebuild churn could cause spurious reloads.
useCacheRecovery: false,
latestEntryJS: entries.map(
(entry) => `${publicRoot}/frontend_latest/${entry}.js`
),
@@ -145,10 +155,15 @@ const genPagesProdTask =
resolve(inputRoot, inputSub, `${page}.template`),
{
...commonVars,
// Recover from a stale index.html that pins deleted hashed entry
// bundles (see _bootstrap_recovery.html.template).
useCacheRecovery: true,
latestEntryJS: entries.map((entry) => latestManifest[`${entry}.js`]),
es5EntryJS: entries.map((entry) => es5Manifest[`${entry}.js`]),
es5EntryJS: outputES5
? entries.map((entry) => es5Manifest[`${entry}.js`])
: [],
latestCustomPanelJS: latestManifest["custom-panel.js"],
es5CustomPanelJS: es5Manifest["custom-panel.js"],
es5CustomPanelJS: outputES5 ? es5Manifest["custom-panel.js"] : "",
}
);
minifiedHTML.push(
@@ -183,6 +198,17 @@ gulp.task(
)
);
gulp.task(
"gen-pages-app-prod-modern",
genPagesProdTask(
APP_PAGE_ENTRIES,
paths.root_dir,
paths.app_output_root,
paths.app_output_latest,
undefined
)
);
const CAST_PAGE_ENTRIES = {
"faq.html": ["launcher"],
"index.html": ["launcher"],
@@ -224,6 +250,16 @@ gulp.task(
)
);
gulp.task(
"gen-pages-demo-prod-e2e",
genPagesProdTask(
DEMO_PAGE_ENTRIES,
paths.demo_dir,
paths.demo_output_root,
paths.demo_output_latest
)
);
const GALLERY_PAGE_ENTRIES = { "index.html": ["entrypoint"] };
gulp.task(
@@ -267,27 +303,27 @@ gulp.task(
)
);
const HASSIO_PAGE_ENTRIES = { "entrypoint.js": ["entrypoint"] };
const E2E_TEST_APP_PAGE_ENTRIES = {
"index.html": ["main"],
"dashboard.html": ["dashboard"],
"onboarding.html": ["onboarding"],
};
gulp.task(
"gen-pages-hassio-dev",
"gen-pages-e2e-test-app-dev",
genPagesDevTask(
HASSIO_PAGE_ENTRIES,
paths.hassio_dir,
paths.hassio_output_root,
"src",
paths.hassio_publicPath
E2E_TEST_APP_PAGE_ENTRIES,
paths.e2eTestApp_dir,
paths.e2eTestApp_output_root
)
);
gulp.task(
"gen-pages-hassio-prod",
"gen-pages-e2e-test-app-prod",
genPagesProdTask(
HASSIO_PAGE_ENTRIES,
paths.hassio_dir,
paths.hassio_output_root,
paths.hassio_output_latest,
paths.hassio_output_es5,
"src"
E2E_TEST_APP_PAGE_ENTRIES,
paths.e2eTestApp_dir,
paths.e2eTestApp_output_root,
paths.e2eTestApp_output_latest
)
);
@@ -1,7 +1,6 @@
// Task to download the latest Lokalise translations from the nightly workflow artifacts
import { createOAuthDeviceAuth } from "@octokit/auth-oauth-device";
import { retry } from "@octokit/plugin-retry";
import { Octokit } from "@octokit/rest";
import { deleteAsync } from "del";
import { mkdir, readFile, writeFile } from "fs/promises";
@@ -10,11 +9,20 @@ import jszip from "jszip";
import path from "path";
import process from "process";
import { extract } from "tar";
import {
RetryableError,
withRetry,
} from "../../.github/scripts/github-retry.mts";
type Artifact = Awaited<
ReturnType<Octokit["rest"]["actions"]["listArtifactsForRepo"]>
>["data"]["artifacts"][number];
const MAX_AGE = 24; // hours
const OWNER = "home-assistant";
const REPO = "frontend";
const WORKFLOW_NAME = "nightly.yaml";
const BRANCH = "dev";
const ARTIFACT_NAME = "translations";
const CLIENT_ID = "Iv1.3914e28cb27834d1";
const EXTRACT_DIR = "translations";
@@ -36,11 +44,16 @@ gulp.task("fetch-nightly-translations", async function () {
// Read current translations artifact info if it exists,
// and stop if they are not old enough
let currentArtifact;
let currentArtifact: Artifact | null;
try {
currentArtifact = JSON.parse(await readFile(ARTIFACT_FILE, "utf-8"));
const artifact: Artifact = JSON.parse(
await readFile(ARTIFACT_FILE, "utf-8")
);
currentArtifact = artifact;
const currentAge =
(Date.now() - Date.parse(currentArtifact.created_at)) / 3600000;
(Date.now() - Date.parse(artifact.created_at ?? "")) / 3600000;
if (currentAge < MAX_AGE) {
console.log(
"Keeping current translations (only %s hours old)",
@@ -52,13 +65,30 @@ gulp.task("fetch-nightly-translations", async function () {
currentArtifact = null;
}
try {
await fetchTranslations(currentArtifact);
} catch (err) {
// Local builds should work offline or without valid GitHub credentials,
// so fall back to English only. CI must fail instead of silently
// building without translations.
if (process.env.CI) {
throw err;
}
console.warn(
"Failed to fetch nightly translations, continuing with English only:",
err instanceof Error ? err.message : err
);
}
});
async function fetchTranslations(currentArtifact: Artifact | null) {
// To store file writing promises
const createExtractDir = mkdir(EXTRACT_DIR, { recursive: true });
const writings = [];
const writings: Promise<void>[] = [];
// Authenticate to GitHub using GitHub action token if it exists,
// otherwise look for a saved user token or generate a new one if none
let tokenAuth;
let tokenAuth: { token: string };
if (process.env.GITHUB_TOKEN) {
tokenAuth = { token: process.env.GITHUB_TOKEN };
} else {
@@ -87,80 +117,97 @@ gulp.task("fetch-nightly-translations", async function () {
});
tokenAuth = await auth({ type: "oauth" });
writings.push(
createExtractDir.then(
createExtractDir.then(() =>
writeFile(TOKEN_FILE, JSON.stringify(tokenAuth, null, 2))
)
);
}
}
// Authenticate with token and request workflow runs from GitHub
console.log("Fetching new translations...");
const octokit = new (Octokit.plugin(retry))({
// Authenticate with token and find the newest translations artifact
const octokit = new Octokit({
userAgent: "Fetch Nightly Translations",
auth: tokenAuth.token,
});
const workflowRunsResponse = await octokit.rest.actions.listWorkflowRuns({
owner: OWNER,
repo: REPO,
workflow_id: WORKFLOW_NAME,
status: "success",
event: "schedule",
per_page: 1,
exclude_pull_requests: true,
});
if (workflowRunsResponse.data.total_count === 0) {
throw Error("No successful nightly workflow runs found");
}
const latestNightlyRun = workflowRunsResponse.data.workflow_runs[0];
// Only the nightly workflow uploads this artifact. Requiring a run from this
// repository's own branch excludes artifacts uploaded by fork pull requests.
const latestArtifact = await withRetry(
"translations artifact lookup",
async () => {
const { data } = await octokit.rest.actions.listArtifactsForRepo({
owner: OWNER,
repo: REPO,
name: ARTIFACT_NAME,
per_page: 10,
});
// Stop if current is already the latest, otherwise Find the translations artifact
if (currentArtifact?.workflow_run.id === latestNightlyRun.id) {
const artifact = data.artifacts.find(
({ expired, workflow_run: run }) =>
!expired &&
run?.head_branch === BRANCH &&
run.head_repository_id === run.repository_id
);
if (!artifact) {
throw new RetryableError(
`No ${ARTIFACT_NAME} artifact found from ${BRANCH}`
);
}
return artifact;
}
);
console.log(
"Latest translations artifact is %s from workflow run %s (%s)",
latestArtifact.id,
latestArtifact.workflow_run?.id,
latestArtifact.created_at
);
// Stop if current is already the latest
if (currentArtifact?.id === latestArtifact.id) {
console.log("Stopping because current translations are still the latest");
return;
}
const latestArtifact = (
await octokit.actions.listWorkflowRunArtifacts({
owner: OWNER,
repo: REPO,
run_id: latestNightlyRun.id,
})
).data.artifacts.find((artifact) => artifact.name === ARTIFACT_NAME);
if (!latestArtifact) {
throw Error("Latest nightly workflow run has no translations artifact");
}
writings.push(
createExtractDir.then(
writeFile(ARTIFACT_FILE, JSON.stringify(latestArtifact, null, 2))
)
);
// Remove the current translations
const deleteCurrent = Promise.all(writings).then(
const deleteCurrent = Promise.all(writings).then(() =>
deleteAsync([`${EXTRACT_DIR}/*`, `!${ARTIFACT_FILE}`, `!${TOKEN_FILE}`])
);
// Get the download URL and follow the redirect to download (stored as ArrayBuffer)
const downloadResponse = await octokit.actions.downloadArtifact({
owner: OWNER,
repo: REPO,
artifact_id: latestArtifact.id,
archive_format: "zip",
});
if (downloadResponse.status !== 200) {
const downloadResponse = await withRetry("translations download", () =>
octokit.rest.actions.downloadArtifact({
owner: OWNER,
repo: REPO,
artifact_id: latestArtifact.id,
archive_format: "zip",
})
);
// Octokit types the redirect, but fetch follows it to the archive
if ((downloadResponse.status as number) !== 200) {
throw Error("Failure downloading translations artifact");
}
// Artifact is a tarball, but GitHub adds it to a zip file
console.log("Unpacking downloaded translations...");
const zip = await jszip.loadAsync(downloadResponse.data);
const zip = await jszip.loadAsync(downloadResponse.data as ArrayBuffer);
await deleteCurrent;
const extractStream = zip.file(/.*/)[0].nodeStream().pipe(extract());
await new Promise((resolve, reject) => {
extractStream.on("close", resolve).on("error", reject);
});
});
// Record the artifact only after successful extraction, so a failed fetch
// is retried by the next build instead of being considered current.
await createExtractDir;
await writeFile(ARTIFACT_FILE, JSON.stringify(latestArtifact, null, 2));
}
gulp.task(
"setup-and-fetch-nightly-translations",
+26 -4
View File
@@ -1,9 +1,10 @@
import fs from "fs";
import { glob } from "glob";
import gulp from "gulp";
import yaml from "js-yaml";
import { load as loadYaml } from "js-yaml";
import { marked } from "marked";
import path from "path";
import { createWorkflowLockTask } from "../output-lock.mjs";
import paths from "../paths.cjs";
import "./clean.js";
import "./entry-html.js";
@@ -47,7 +48,7 @@ gulp.task("gather-gallery-pages", async function gatherPages() {
if (descriptionContent.startsWith("---")) {
const metadataEnd = descriptionContent.indexOf("---", 3);
metadata = yaml.load(descriptionContent.substring(3, metadataEnd));
metadata = loadYaml(descriptionContent.substring(3, metadataEnd));
descriptionContent = descriptionContent
.substring(metadataEnd + 3)
.trim();
@@ -57,7 +58,9 @@ gulp.task("gather-gallery-pages", async function gatherPages() {
if (descriptionContent === "") {
hasDescription = false;
} else {
descriptionContent = marked(descriptionContent).replace(/`/g, "\\`");
descriptionContent = marked(descriptionContent)
.replace(/\\/g, "\\\\")
.replace(/`/g, "\\`");
fs.mkdirSync(path.resolve(galleryBuild, category), { recursive: true });
fs.writeFileSync(
path.resolve(galleryBuild, `${pageId}-description.ts`),
@@ -101,12 +104,29 @@ gulp.task("gather-gallery-pages", async function gatherPages() {
if (!toProcess) {
console.error("Unknown category", group.category);
if (!group.pages) {
if (!group.subsections && !group.pages) {
group.pages = [];
}
continue;
}
if (group.subsections) {
// Listed pages keep their per-subsection order.
for (const subsection of group.subsections) {
for (const page of subsection.pages) {
if (!toProcess.delete(page)) {
console.error("Found unreferenced demo", page);
}
}
}
// Any remaining pages land in a trailing "Other" subsection.
const leftover = Array.from(toProcess).sort();
if (leftover.length) {
group.subsections.push({ header: "Other", pages: leftover });
}
continue;
}
// Any pre-defined groups will not be sorted.
if (group.pages) {
for (const page of group.pages) {
@@ -145,6 +165,7 @@ gulp.task(
async function setEnv() {
process.env.NODE_ENV = "development";
},
createWorkflowLockTask("develop-gallery"),
"clean-gallery",
"translations-enable-merge-backend",
gulp.parallel(
@@ -176,6 +197,7 @@ gulp.task(
async function setEnv() {
process.env.NODE_ENV = "production";
},
createWorkflowLockTask("build-gallery"),
"clean-gallery",
"translations-enable-merge-backend",
gulp.parallel(
+36 -50
View File
@@ -4,6 +4,7 @@ import fs from "fs-extra";
import gulp from "gulp";
import path from "path";
import paths from "../paths.cjs";
import { ensureMapAssets, mapAssetsDir } from "./map-assets.js";
const npmPath = (...parts) =>
path.resolve(paths.root_dir, "node_modules", ...parts);
@@ -41,37 +42,6 @@ function copyMdiIcons(staticDir) {
fs.copySync(polyPath("build/mdi"), staticPath("mdi"));
}
function copyPolyfills(staticDir) {
const staticPath = genStaticPath(staticDir);
// For custom panels using ES5 builds that don't use Babel 7+
copyFileDir(
npmPath("@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"),
staticPath("polyfills/")
);
// Web Component polyfills and adapters
copyFileDir(
npmPath("@webcomponents/webcomponentsjs/webcomponents-bundle.js"),
staticPath("polyfills/")
);
copyFileDir(
npmPath("@webcomponents/webcomponentsjs/webcomponents-bundle.js.map"),
staticPath("polyfills/")
);
// Lit polyfill support
fs.copySync(
npmPath("lit/polyfill-support.js"),
path.join(staticPath("polyfills/"), "lit-polyfill-support.js")
);
// dialog-polyfill css
copyFileDir(
npmPath("dialog-polyfill/dialog-polyfill.css"),
staticPath("polyfills/")
);
}
function copyFonts(staticDir) {
const staticPath = genStaticPath(staticDir);
// Local fonts
@@ -89,7 +59,7 @@ function copyQrScannerWorker(staticDir) {
copyFileDir(npmPath("qr-scanner/qr-scanner-worker.min.js"), staticPath("js"));
}
function copyMapPanel(staticDir) {
async function copyMapPanel(staticDir) {
const staticPath = genStaticPath(staticDir);
copyFileDir(
npmPath("leaflet/dist/leaflet.css"),
@@ -103,6 +73,16 @@ function copyMapPanel(staticDir) {
npmPath("leaflet/dist/images"),
staticPath("images/leaflet/images/")
);
// Style, glyphs and sprites for the vector base map
await ensureMapAssets();
fs.copySync(mapAssetsDir, staticPath("map/"));
copyFileDir(
npmPath("@mapbox/mapbox-gl-rtl-text/dist/mapbox-gl-rtl-text.js"),
staticPath("map/")
);
// Controls and popups of the native MapLibre engine
copyFileDir(npmPath("maplibre-gl/dist/maplibre-gl.css"), staticPath("map/"));
}
function copyZXingWasm(staticDir) {
@@ -123,34 +103,22 @@ gulp.task("copy-translations-app", async () => {
copyTranslations(staticDir);
});
gulp.task("copy-translations-supervisor", async () => {
const staticDir = paths.hassio_output_static;
copyTranslations(staticDir);
});
gulp.task("copy-translations-landing-page", async () => {
const staticDir = paths.landingPage_output_static;
copyTranslations(staticDir);
});
gulp.task("copy-static-supervisor", async () => {
const staticDir = paths.hassio_output_static;
copyLocaleData(staticDir);
copyFonts(staticDir);
});
gulp.task("copy-static-app", async () => {
const staticDir = paths.app_output_static;
// Basic static files
fs.copySync(polyPath("public"), paths.app_output_root);
copyPolyfills(staticDir);
copyFonts(staticDir);
copyTranslations(staticDir);
copyLocaleData(staticDir);
copyMdiIcons(staticDir);
// Panel assets
copyMapPanel(staticDir);
await copyMapPanel(staticDir);
// Qr Scanner assets
copyZXingWasm(staticDir);
@@ -165,8 +133,7 @@ gulp.task("copy-static-demo", async () => {
);
// Copy demo static files
fs.copySync(path.resolve(paths.demo_dir, "public"), paths.demo_output_root);
copyPolyfills(paths.demo_output_static);
copyMapPanel(paths.demo_output_static);
await copyMapPanel(paths.demo_output_static);
copyFonts(paths.demo_output_static);
copyTranslations(paths.demo_output_static);
copyLocaleData(paths.demo_output_static);
@@ -178,8 +145,7 @@ gulp.task("copy-static-cast", async () => {
fs.copySync(polyPath("public/static"), paths.cast_output_static);
// Copy cast static files
fs.copySync(path.resolve(paths.cast_dir, "public"), paths.cast_output_root);
copyPolyfills(paths.cast_output_static);
copyMapPanel(paths.cast_output_static);
await copyMapPanel(paths.cast_output_static);
copyFonts(paths.cast_output_static);
copyTranslations(paths.cast_output_static);
copyLocaleData(paths.cast_output_static);
@@ -195,7 +161,7 @@ gulp.task("copy-static-gallery", async () => {
paths.gallery_output_root
);
copyMapPanel(paths.gallery_output_static);
await copyMapPanel(paths.gallery_output_static);
copyFonts(paths.gallery_output_static);
copyTranslations(paths.gallery_output_static);
copyLocaleData(paths.gallery_output_static);
@@ -211,4 +177,24 @@ gulp.task("copy-static-landing-page", async () => {
copyFonts(paths.landingPage_output_static);
copyTranslations(paths.landingPage_output_static);
copyLocaleData(paths.landingPage_output_static);
});
gulp.task("copy-static-e2e-test-app", async () => {
// Copy app static files (icons, polyfills, etc.)
fs.copySync(
polyPath("public/static"),
path.resolve(paths.e2eTestApp_output_root, "static")
);
// Copy e2e test app public files (manifest, sw stubs)
const e2ePublic = path.resolve(paths.e2eTestApp_dir, "public");
if (fs.existsSync(e2ePublic)) {
fs.copySync(e2ePublic, paths.e2eTestApp_output_root);
}
await copyMapPanel(paths.e2eTestApp_output_static);
copyFonts(paths.e2eTestApp_output_static);
copyTranslations(paths.e2eTestApp_output_static);
copyLocaleData(paths.e2eTestApp_output_static);
copyMdiIcons(paths.e2eTestApp_output_static);
});
+40
View File
@@ -0,0 +1,40 @@
import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import process from "node:process";
import gulp from "gulp";
import paths from "../paths.cjs";
const SOURCE_URL =
process.env.SENSOR_METADATA_URL ||
"https://raw.githubusercontent.com/home-assistant/core/refs/heads/dev/homeassistant/generated/device_classes.json";
const TARGET = join(paths.root_dir, "src", "data", "device_classes.ts");
gulp.task("gen-device-classes", async () => {
const response = await fetch(SOURCE_URL);
if (!response.ok) {
throw new Error(`Failed to fetch ${SOURCE_URL}: ${response.status}`);
}
const data = await response.json();
const domainDeviceClasses = data ?? {};
if (!Object.keys(domainDeviceClasses).length) {
throw new Error(`No device classes found in ${SOURCE_URL}`);
}
const content = `// This file is auto-generated from Home Assistant Core's
// entity platform device classes. Do not edit by hand.
// Regenerate with \`script/gen_device_classes\`.
export const DOMAIN_DEVICE_CLASSES: Record<string, string[]> = {
${Object.entries(domainDeviceClasses)
.map(
([domain, deviceClasses]) =>
` "${domain}": [${deviceClasses.map((deviceClass) => `"${deviceClass}"`).join(", ")}],`
)
.join("\n")}
};
`;
await writeFile(TARGET, content);
});
@@ -0,0 +1,83 @@
import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import process from "node:process";
import gulp from "gulp";
import paths from "../paths.cjs";
const SOURCE_URL =
process.env.SENSOR_METADATA_URL ||
"https://raw.githubusercontent.com/home-assistant/core/dev/homeassistant/generated/sensor.json";
const TARGET = join(
paths.root_dir,
"src",
"data",
"sensor_entity_constants.ts"
);
gulp.task("gen-sensor-entity-constants", async () => {
const response = await fetch(SOURCE_URL);
if (!response.ok) {
throw new Error(`Failed to fetch ${SOURCE_URL}: ${response.status}`);
}
const data = await response.json();
const numericDeviceClasses = [...(data.numeric_device_classes ?? [])].sort();
const deviceClassUnits = data.device_class_units ?? {};
const convertibleClassUnits = data.convertible_units ?? {};
const stateClasses = data.state_classes ?? [];
const stateClassUnits = data.state_class_units ?? {};
if (
!numericDeviceClasses.length ||
!stateClasses.length ||
!Object.keys(deviceClassUnits).length ||
!Object.keys(stateClassUnits).length
) {
throw new Error(
`No sensor device classes, state classes or units found in ${SOURCE_URL}`
);
}
const content = `// This file is auto-generated from Home Assistant Core's \`DEVICE_CLASS_UNITS\`
// and \`STATE_CLASS_UNITS\`) and \`SensorDeviceClass\`
// (all values minus \`NON_NUMERIC_DEVICE_CLASSES\`). Do not edit by hand.
// Regenerate with \`script/gen_sensor_entity_constants\`.
export const SENSOR_NUMERIC_DEVICE_CLASSES: string[] = [
${numericDeviceClasses.map((deviceClass) => ` "${deviceClass}",`).join("\n")}
];
export const SENSOR_DEVICE_CLASS_UNITS: Record<string, (string | null)[]> = {
${Object.entries(deviceClassUnits)
.map(
([deviceClass, units]) =>
` ${deviceClass}: [${units.map((u) => (u === null ? "null" : `"${u}"`)).join(", ")}],`
)
.join("\n")}
};
export const SENSOR_DEVICE_CLASS_CONVERTIBLE_UNITS: Record<string, (string | null)[]> = {
${Object.entries(convertibleClassUnits)
.map(
([deviceClass, units]) =>
` ${deviceClass}: [${units.map((u) => (u === null ? "null" : `"${u}"`)).join(", ")}],`
)
.join("\n")}
};
export const SENSOR_STATE_CLASSES: string[] = [
${stateClasses.map((stateClass) => ` "${stateClass}",`).join("\n")}
];
export const SENSOR_STATE_CLASS_UNITS: Record<string, (string | null)[]> = {
${Object.entries(stateClassUnits)
.map(
([stateClass, units]) =>
` ${stateClass}: [${units.map((u) => (u === null ? "null" : `"${u}"`)).join(", ")}],`
)
.join("\n")}
};
`;
await writeFile(TARGET, content);
});
-45
View File
@@ -1,45 +0,0 @@
import gulp from "gulp";
import env from "../env.cjs";
import "./clean.js";
import "./compress.js";
import "./entry-html.js";
import "./gather-static.js";
import "./gen-icons-json.js";
import "./translations.js";
import "./rspack.js";
gulp.task(
"develop-hassio",
gulp.series(
async function setEnv() {
process.env.NODE_ENV = "development";
},
"clean-hassio",
"gen-dummy-icons-json",
"gen-pages-hassio-dev",
"build-supervisor-translations",
"copy-translations-supervisor",
"build-locale-data",
"copy-static-supervisor",
"rspack-watch-hassio"
)
);
gulp.task(
"build-hassio",
gulp.series(
async function setEnv() {
process.env.NODE_ENV = "production";
},
"clean-hassio",
"gen-dummy-icons-json",
"build-supervisor-translations",
"copy-translations-supervisor",
"build-locale-data",
"copy-static-supervisor",
"rspack-prod-hassio",
"gen-pages-hassio-prod",
...// Don't compress running tests
(env.isTestBuild() ? [] : ["compress-hassio"])
)
);
+6 -2
View File
@@ -4,14 +4,18 @@ import "./clean.js";
import "./compress.js";
import "./demo.js";
import "./download-translations.js";
import "./e2e-test-app.js";
import "./entry-html.js";
import "./fetch-nightly-translations.js";
import "./fetch-nightly-translations.mts";
import "./gallery.js";
import "./gather-static.js";
import "./gen-device-classes.js";
import "./gen-icons-json.js";
import "./hassio.js";
import "./gen-sensor-entity-constants.js";
import "./landing-page.js";
import "./locale-data.js";
import "./map-assets.js";
import "./map-sprites.js";
import "./rspack.js";
import "./service-worker.js";
import "./translations.js";
+94
View File
@@ -0,0 +1,94 @@
// Gulp task to generate third-party license notices.
import { readFile, access, readdir } from "fs/promises";
import { generateLicenseFile } from "generate-license-file";
import gulp from "gulp";
import path from "path";
import paths from "../paths.cjs";
const OUTPUT_FILE = path.join(
paths.app_output_static,
"third-party-licenses.txt"
);
const NODE_MODULES = path.resolve(paths.root_dir, "node_modules");
// The echarts package ships an Apache-2.0 NOTICE file that must be
// redistributed alongside the compiled output per Apache License §4(d).
const NOTICE_FILES = [path.join(NODE_MODULES, "echarts/NOTICE")];
// Some packages need a manual license override (e.g. they ship multiple
// license files and we must pick the right one for the bundled code).
//
// Each entry is pinned to a specific version. If a package is updated,
// this list must be reviewed and the version updated after verifying
// that the new version's license still matches. The build will fail if
// the pinned version is no longer installed.
const LICENSE_OVERRIDES = [
{
// type-fest ships two license files (MIT for code, CC0 for types).
// We use the MIT license since that covers the bundled code.
packageName: "type-fest",
version: "5.10.0",
licenseFile: "license-mit",
},
];
// Locate the directory of an installed package matching an exact version.
//
// pnpm stores every installed version under
// node_modules/.pnpm/<name>@<version>[(peers)]/node_modules/<name>, with the
// "/" of scoped names replaced by "+". Looking there finds the pinned version
// whether or not it is the one linked at the top level.
async function findPackageDir(packageName, version) {
const storeDir = path.join(NODE_MODULES, ".pnpm");
const prefix = `${packageName.replace("/", "+")}@${version}`;
const entries = await readdir(storeDir).catch(() => []);
for (const entry of entries) {
if (entry !== prefix && !entry.startsWith(`${prefix}(`)) {
continue;
}
const dir = path.join(storeDir, entry, "node_modules", packageName);
// eslint-disable-next-line no-await-in-loop
const pkg = await readFile(path.join(dir, "package.json"), "utf-8")
.then(JSON.parse)
.catch(() => null);
if (pkg?.version === version) {
return dir;
}
}
return null;
}
gulp.task("gen-licenses", async () => {
const licenseOverrides = {};
for (const { packageName, version, licenseFile } of LICENSE_OVERRIDES) {
// eslint-disable-next-line no-await-in-loop
const packageDir = await findPackageDir(packageName, version);
if (!packageDir) {
throw new Error(
`License override for "${packageName}" is pinned to version ${version}, but that version is not installed. ` +
`Please verify the new version's license and update the override in build-scripts/gulp/licenses.js.`
);
}
const licensePath = path.join(packageDir, licenseFile);
try {
// eslint-disable-next-line no-await-in-loop
await access(licensePath);
} catch {
throw new Error(`License file not found or unreadable: ${licensePath}`);
}
licenseOverrides[`${packageName}@${version}`] = licensePath;
}
await generateLicenseFile(
path.resolve(paths.root_dir, "package.json"),
OUTPUT_FILE,
{ append: NOTICE_FILES, replace: licenseOverrides }
);
});
+17 -4
View File
@@ -40,18 +40,31 @@ const convertToJSON = async (
throw e;
}
// Convert to JSON
const parts = localeData.split("} else {");
const firstBlock = parts[0];
const obj = INTL_POLYFILLS[pkg];
const dataRegex = new RegExp(
`Intl\\.${obj}\\.${addFunc}\\((?<data>.*)\\)`,
"s"
);
localeData = localeData.match(dataRegex)?.groups?.data;
if (!localeData) {
const encodedData = localeData.match(
/JSON\.parse\((?<data>"(?:[^"\\]|\\.)*")\)/
)?.groups?.data;
localeData = firstBlock.match(dataRegex)?.groups?.data;
if (!localeData && !encodedData) {
throw Error(`Failed to extract data for language ${lang} from ${pkg}`);
}
// Parse to validate JSON, then stringify to minify
localeData = JSON.stringify(JSON.parse(localeData));
await writeFile(join(outDir, `${pkg}/${lang}.json`), localeData);
try {
localeData = JSON.stringify(
JSON.parse(encodedData ? JSON.parse(encodedData) : localeData)
);
await writeFile(join(outDir, `${pkg}/${lang}.json`), localeData);
} catch (e) {
throw Error(`Failed to parse JSON for language ${lang} from ${pkg}: ${e}`, {
cause: e,
});
}
};
gulp.task("clean-locale-data", async () => deleteSync([outDir]));
+120
View File
@@ -0,0 +1,120 @@
// Generates the MapLibre styles for the vector base map. Only the styles:
// glyphs and tiles come from core's proxy, the sprite sheet ships with the
// frontend (see map-sprites.js). They are generated here because core has no
// node toolchain to run @versatiles/style with.
//
// Only the default pair is written out; anything else is built in the browser
// from the same builder, which is why the preparation is shared with the
// frontend and why the asset URLs are written alongside the styles.
import { createHash } from "node:crypto";
import { readFile, writeFile } from "node:fs/promises";
import path from "node:path";
import { osm } from "@versatiles/style";
import fs from "fs-extra";
import gulp from "gulp";
import paths from "../paths.cjs";
import { finalizeMapStyle } from "../../src/common/map/map-style-transforms.ts";
import {
HA_MAP_COLORS,
HA_MAP_COLORS_DARK,
} from "../../src/common/map/ha-map-palette.ts";
import {
missingSprites,
SHEET_FILES,
SPRITE_SHEET,
spritesDir,
} from "./map-sprites.js";
const PROXY_PATH = "/api/map_tiles";
const outputDir = path.resolve(paths.build_dir, "map");
// Core serves /static with a month of max-age, so a re-vendored sheet would
// otherwise be read from cache next to a style expecting the new one.
const sheetHash = async () => {
const contents = await Promise.all(
SHEET_FILES.map((file) => readFile(path.join(spritesDir, file)))
);
const hash = createHash("sha256");
contents.forEach((content) => hash.update(content));
return hash.digest("hex").slice(0, 8);
};
const styleUrls = (spriteVersion) => ({
// Keeps the generated URLs origin relative.
base: "",
glyphsPattern: `${PROXY_PATH}/fonts/{fontstack}/{range}.pbf`,
sprite: [
{
id: SPRITE_SHEET,
url: `/static/map/sprites/${SPRITE_SHEET}?v=${spriteVersion}`,
},
],
});
const checkSprites = (name, style, sheet) => {
const missing = missingSprites(style, sheet);
if (missing.length) {
throw new Error(
`Style "${name}" references icons missing from the bundled ${SPRITE_SHEET} ` +
`sprite sheet: ${missing.join(", ")}. Run \`pnpm exec gulp update-map-sprites\` ` +
`and commit the result.`
);
}
return style;
};
// The styles a card can pick, each as a light and a dark palette. Kept in sync
// with MAP_STYLES in src/common/map/map-styles.ts.
const STYLES = ["colorful", "natural", "muted", "gray", "toner"];
const PALETTES = STYLES.flatMap((style) => [style, `${style}-dark`]);
// Colors baked in, so the map a dashboard shows without configuration costs
// no builder and no second request.
const SHIPPED = [
["light", "colorful", HA_MAP_COLORS],
["dark", "colorful-dark", HA_MAP_COLORS_DARK],
];
const generateStyles = async () => {
const sheet = await fs.readJson(
path.join(spritesDir, `${SPRITE_SHEET}.json`)
);
const urls = styleUrls(await sheetHash());
// Built so a bump that needs an icon the sheet lacks fails here, not in a
// browser. Recoloring cannot add icons, so the palettes cover it.
PALETTES.forEach((theme) => checkSprites(theme, osm({ theme, urls }), sheet));
return urls;
};
const buildMapAssets = async () => {
await fs.emptyDir(outputDir);
const urls = await generateStyles();
await Promise.all([
// Read by src/common/map/build-map-style.ts, which cannot know the hash
// of the sprite sheet this build vendored.
writeFile(path.join(outputDir, "urls.json"), JSON.stringify(urls)),
...SHIPPED.map(([name, theme, colors]) =>
writeFile(
path.join(outputDir, `${name}.json`),
JSON.stringify(finalizeMapStyle(name, osm({ theme, colors, urls })))
)
),
]);
};
// Shared so it does not have to be wired into every pipeline separately.
let pending;
export const ensureMapAssets = () => {
pending ??= buildMapAssets();
return pending;
};
gulp.task("build-map-assets", ensureMapAssets);
// Runs in the required lint job so a @versatiles/style bump that needs new
// icons cannot merge before the sheet is re-vendored on that branch.
gulp.task("check-map-sprites", generateStyles);
export const mapAssetsDir = outputDir;
+80
View File
@@ -0,0 +1,80 @@
import { spawn } from "node:child_process";
import { createRequire } from "node:module";
import path from "node:path";
import { Readable } from "node:stream";
import { pipeline } from "node:stream/promises";
import gulp from "gulp";
import paths from "../paths.cjs";
const require = createRequire(import.meta.url);
export const SPRITE_SHEET = "base";
export const spritesDir = path.resolve(
paths.root_dir,
"public",
"static",
"map",
"sprites"
);
export const SHEET_FILES = [".json", ".png", "@2x.json", "@2x.png"].map(
(suffix) => `${SPRITE_SHEET}${suffix}`
);
// The only style properties that resolve to a sprite image.
const IMAGE_PROPERTIES = [
"icon-image",
"fill-pattern",
"line-pattern",
"fill-extrusion-pattern",
"background-pattern",
];
const collectStrings = (value, into) => {
if (typeof value === "string") {
into.push(value);
} else if (Array.isArray(value)) {
value.forEach((item) => collectStrings(item, into));
} else if (value && typeof value === "object") {
Object.values(value).forEach((item) => collectStrings(item, into));
}
return into;
};
export const spriteIds = (style) => {
const prefix = `${SPRITE_SHEET}:`;
const strings = style.layers.flatMap((layer) =>
IMAGE_PROPERTIES.flatMap((property) =>
collectStrings([layer.layout?.[property], layer.paint?.[property]], [])
)
);
return new Set(
strings
.filter((value) => value.startsWith(prefix))
.map((value) => value.slice(prefix.length))
);
};
export const missingSprites = (style, sheet) =>
[...spriteIds(style)].filter((id) => !(id in sheet));
gulp.task("update-map-sprites", async () => {
const { version } = require("@versatiles/style/package.json");
const url = `https://github.com/versatiles-org/versatiles-style/releases/download/v${version}/sprites.tar.gz`;
const response = await fetch(url);
if (!response.ok || !response.body) {
throw new Error(`Failed to fetch ${url}: ${response.status}`);
}
const tar = spawn("tar", ["-xzf", "-", "-C", spritesDir, ...SHEET_FILES], {
stdio: ["pipe", "inherit", "inherit"],
});
const exited = new Promise((resolve, reject) => {
tar.on("error", reject);
tar.on("close", (code) =>
code === 0 ? resolve() : reject(new Error(`tar exited with ${code}`))
);
});
await pipeline(Readable.fromWeb(response.body), tar.stdin);
await exited;
});
Loaded 100 of 3143 files, more files were not shown because too many files have changed in this diff. Show more