fix: индекс эталонов хранит платформу съёмки, а не платформу приёмки (#571)

Аудит 14.09, §4 и §9. `golden-report.json` не нёс платформу вовсе, поэтому
приёмщик вызывал `captureEnvironment()` у себя и записывал СВОЮ платформу как
платформу кадров. На `ad4000f9` это дало `"platform": "win32"` у кадров,
снятых Linux-прогоном 34853080375, а причина осознанного обхода осталась в
stdout и в индекс не попала — хотя `AGENTS.md` обещает след в обоих местах.
Сами PNG были и остаются целы: 101 свидетель совпал байт-в-байт. Врал
провенанс.

Что сделано:

- отчёт съёмки получил раздел `capture`: платформа, архитектура, сборка
  Chromium, отпечаток материала и — в CI — прогон с попыткой и SHA. Схема
  отчёта поднята до 2;
- приёмка читает среду съёмки из отчёта. Гейт чужой среды теперь судит обе
  стороны: съёмку (из отчёта) и приёмку (свою). Отказ — до единой записи;
- индекс эталонов поднят до схемы 2 и различает `capturedOn` и `acceptedOn`,
  несёт раздел `capture` и причину осознанного обхода в `foreignCapture`;
- отчёт схемы 1 платформы съёмки не несёт физически: это отдельная явная
  ветка, `capturedOn` уезжает `null`. Выдумывать платформу нельзя — ровно этим
  задача и вызвана;
- `--baselines=<dir>` у приёмки: без него проверить «отказ произошёл ДО
  записи» можно было бы только порчей рабочего дерева, то есть никак (#556).

Осознанно отменено решение #455 «не трогать run.mjs»: ради ГЕЙТА цена
фингерпринта не окупалась, ради ПРОВЕНАНСА окупилась — платформу кадров знает
только тот, кто их снял. Плата разовая: пересобран бандл, индекс скриншотов
документации переснят отдельным коммитом. Тест #455 переписан под новый
инвариант, а не удалён.

Свидетели: `test/golden-capture-provenance.test.mjs` — семь проверок, все пять
сценариев приёмки из issue, включая «отказ до записи» и «подмена PNG и неполный
артефакт по-прежнему fail-closed». Мутанты `golden-index-invents-capture-platform`
(возвращает платформу приёмщика) и `golden-report-provenance-optional`
(разрешает отчёт схемы 2 без провенанса) прогнаны лично: оба краснеют.

npm test 2762/2761/0 fail, typecheck чистый.

Issue: #571
User-Visible: no
This commit is contained in:
Codex
2026-09-17 23:19:56 +03:00
parent df9031b1ba
commit 3f95dac451
49 changed files with 666 additions and 345 deletions
@@ -1,295 +1,295 @@
{
"schema": 1,
"fingerprint": "ead0f4146471ab778119d7575ca6c0fae2c76260315828e505380a3e32910549",
"fingerprint": "09fae293e9dee5623085ca73035bb09914a27ad744cffaa70dab64fb29b96787",
"entry": "houseplan-card.js",
"panelEntry": "houseplan-panel.js",
"initialViewFiles": [
"houseplan-assets/houseplan-card-QCQsWhm9.js",
"houseplan-assets/houseplan-card-B0Q_XTHX.js",
"houseplan-card.js"
],
"initialViewGzipBytes": 291158,
"initialViewGzipBytes": 291160,
"initialPanelFiles": [
"houseplan-assets/houseplan-card-QCQsWhm9.js",
"houseplan-assets/houseplan-card-B0Q_XTHX.js",
"houseplan-panel.js"
],
"initialPanelGzipBytes": 292680,
"initialPanelGzipBytes": 292683,
"initialPanelOnlyFiles": [
"houseplan-panel.js"
],
"initialPanelOnlyGzipBytes": 2327,
"lazyFiles": [
"houseplan-assets/backdrop-pick-CHXO6wCC.js",
"houseplan-assets/de-Ckd-utGr.js",
"houseplan-assets/editor-Cm8BzYup.js",
"houseplan-assets/fr-dTwY5e5m.js",
"houseplan-assets/furniture-plan-art.generated-DH4ULp8h.js",
"houseplan-assets/houseplan-editor-runtime-A7oaN5to.js",
"houseplan-assets/houseplan-onboarding-runtime-DF0pKq_1.js",
"houseplan-assets/hp-zigbee-topology-overlay-BLPQa5-z.js",
"houseplan-assets/iso-scene-render-B-LgWkof.js",
"houseplan-assets/live-interaction-runtime-B2_XndWb.js",
"houseplan-assets/pdf-export-Ddvg38aO.js",
"houseplan-assets/summary-panel-runtime-loaded-Ci-uYIPy.js",
"houseplan-assets/zigbee-topology-df97gjoC.js",
"houseplan-assets/zigbee-topology-runtime-BjT4xEwX.js"
"houseplan-assets/backdrop-pick-CeEIa4lG.js",
"houseplan-assets/de-BaSj7HzM.js",
"houseplan-assets/editor-D8B3OQYD.js",
"houseplan-assets/fr-4HoeVytE.js",
"houseplan-assets/furniture-plan-art.generated-CaYvEWnV.js",
"houseplan-assets/houseplan-editor-runtime-CXJl9W9o.js",
"houseplan-assets/houseplan-onboarding-runtime-BtkZ0Mkc.js",
"houseplan-assets/hp-zigbee-topology-overlay-CpQn86-U.js",
"houseplan-assets/iso-scene-render-BONN6ODJ.js",
"houseplan-assets/live-interaction-runtime-CgqWId3n.js",
"houseplan-assets/pdf-export-BPZM2cuP.js",
"houseplan-assets/summary-panel-runtime-loaded-BLYtOezP.js",
"houseplan-assets/zigbee-topology-D_LrAqE3.js",
"houseplan-assets/zigbee-topology-runtime-DJH5125h.js"
],
"lazyGzipBytes": 433657,
"lazyGzipBytes": 433647,
"lazyEditorFiles": [
"houseplan-assets/backdrop-pick-CHXO6wCC.js",
"houseplan-assets/editor-Cm8BzYup.js",
"houseplan-assets/furniture-plan-art.generated-DH4ULp8h.js",
"houseplan-assets/houseplan-editor-runtime-A7oaN5to.js",
"houseplan-assets/zigbee-topology-df97gjoC.js"
"houseplan-assets/backdrop-pick-CeEIa4lG.js",
"houseplan-assets/editor-D8B3OQYD.js",
"houseplan-assets/furniture-plan-art.generated-CaYvEWnV.js",
"houseplan-assets/houseplan-editor-runtime-CXJl9W9o.js",
"houseplan-assets/zigbee-topology-D_LrAqE3.js"
],
"lazyEditorGzipBytes": 218045,
"lazyEditorGzipBytes": 218051,
"lazyOnboardingFiles": [
"houseplan-assets/backdrop-pick-CHXO6wCC.js",
"houseplan-assets/houseplan-onboarding-runtime-DF0pKq_1.js"
"houseplan-assets/backdrop-pick-CeEIa4lG.js",
"houseplan-assets/houseplan-onboarding-runtime-BtkZ0Mkc.js"
],
"lazyOnboardingGzipBytes": 13919,
"lazyOnboardingGzipBytes": 13918,
"lazyLocaleFiles": [
"houseplan-assets/de-Ckd-utGr.js",
"houseplan-assets/fr-dTwY5e5m.js"
"houseplan-assets/de-BaSj7HzM.js",
"houseplan-assets/fr-4HoeVytE.js"
],
"lazyLocaleGzipBytes": 54937,
"lazyLocaleGzipBytes": 54921,
"lazyIsometricFiles": [
"houseplan-assets/iso-scene-render-B-LgWkof.js"
"houseplan-assets/iso-scene-render-BONN6ODJ.js"
],
"lazyIsometricGzipBytes": 15017,
"lazyIsometricGzipBytes": 15016,
"lazyFurnitureArtFiles": [
"houseplan-assets/furniture-plan-art.generated-DH4ULp8h.js"
"houseplan-assets/furniture-plan-art.generated-CaYvEWnV.js"
],
"lazyFurnitureArtGzipBytes": 23338,
"lazyFurnitureArtGzipBytes": 23346,
"lazyPdfFiles": [
"houseplan-assets/furniture-plan-art.generated-DH4ULp8h.js",
"houseplan-assets/pdf-export-Ddvg38aO.js"
"houseplan-assets/furniture-plan-art.generated-CaYvEWnV.js",
"houseplan-assets/pdf-export-BPZM2cuP.js"
],
"lazyPdfGzipBytes": 133208,
"lazyPdfGzipBytes": 133220,
"files": [
{
"path": "houseplan-assets/backdrop-pick-CHXO6wCC.js",
"sha256": "36465bc759532e306598d53a85050f0b74b1530c529da70f79216f4b69c9c373",
"path": "houseplan-assets/backdrop-pick-CeEIa4lG.js",
"sha256": "7366654abb5d7a9c273cbaf01b95bb5ce792f41a335dca6b520f8ef2e699ddf6",
"rawBytes": 19956,
"gzipBytes": 6880,
"gzipBytes": 6881,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/de-Ckd-utGr.js",
"sha256": "a57614e4a6cca92f90d763c0c1d1cda24b24d329a40a5ac3cad38a8aa78b5681",
"path": "houseplan-assets/de-BaSj7HzM.js",
"sha256": "104dd42e44f0a9fc7edd5d78bc7965dc706cb0722dd52a18347f1d738f3cf0b3",
"rawBytes": 91590,
"gzipBytes": 27751,
"gzipBytes": 27743,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/editor-Cm8BzYup.js",
"sha256": "517ff6fc16f3e51a610c957d66204d61314ee26fe77189e7d401f109abd3c46a",
"path": "houseplan-assets/editor-D8B3OQYD.js",
"sha256": "7785e1e4b736f6e3ed1fca97a2713b05bc52ee1199faf0ee7f7461f8c8669223",
"rawBytes": 3831,
"gzipBytes": 1583,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/fr-dTwY5e5m.js",
"sha256": "33b9690000ebb0bb53d91e00df0e105875ba1281e4b86d439e78dd98998d85a1",
"path": "houseplan-assets/fr-4HoeVytE.js",
"sha256": "b748e68e439550a6cad6a85b250ae32f16b8cf3cb83621e68b8c39a38d0c7746",
"rawBytes": 93884,
"gzipBytes": 27186,
"gzipBytes": 27178,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/furniture-plan-art.generated-DH4ULp8h.js",
"sha256": "0d6b8f7e60d366244931bfe015a94ed349689cf9d8ad21f1c7fae5efdaf4b73f",
"path": "houseplan-assets/furniture-plan-art.generated-CaYvEWnV.js",
"sha256": "5565fd38519ff3d7c57dbaacb38daf041c0d2b8b810dccb601bf518e348254c0",
"rawBytes": 90517,
"gzipBytes": 23338,
"gzipBytes": 23346,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-card-QCQsWhm9.js",
"sha256": "4326ca9b05e0d1383e94e4a6439af56b3746962c210ce93c87dba80df7e0db2a",
"path": "houseplan-assets/houseplan-card-B0Q_XTHX.js",
"sha256": "a2e6f4c2c11a06e9e93bd7bef54d179932f703c07e76141da18b82ad8c9de5dc",
"rawBytes": 1034124,
"gzipBytes": 290353,
"gzipBytes": 290356,
"isEntry": false,
"imports": [],
"dynamicImports": [
"houseplan-assets/de-Ckd-utGr.js",
"houseplan-assets/editor-Cm8BzYup.js",
"houseplan-assets/fr-dTwY5e5m.js",
"houseplan-assets/furniture-plan-art.generated-DH4ULp8h.js",
"houseplan-assets/houseplan-editor-runtime-A7oaN5to.js",
"houseplan-assets/houseplan-onboarding-runtime-DF0pKq_1.js",
"houseplan-assets/hp-zigbee-topology-overlay-BLPQa5-z.js",
"houseplan-assets/iso-scene-render-B-LgWkof.js",
"houseplan-assets/live-interaction-runtime-B2_XndWb.js",
"houseplan-assets/pdf-export-Ddvg38aO.js",
"houseplan-assets/summary-panel-runtime-loaded-Ci-uYIPy.js"
"houseplan-assets/de-BaSj7HzM.js",
"houseplan-assets/editor-D8B3OQYD.js",
"houseplan-assets/fr-4HoeVytE.js",
"houseplan-assets/furniture-plan-art.generated-CaYvEWnV.js",
"houseplan-assets/houseplan-editor-runtime-CXJl9W9o.js",
"houseplan-assets/houseplan-onboarding-runtime-BtkZ0Mkc.js",
"houseplan-assets/hp-zigbee-topology-overlay-CpQn86-U.js",
"houseplan-assets/iso-scene-render-BONN6ODJ.js",
"houseplan-assets/live-interaction-runtime-CgqWId3n.js",
"houseplan-assets/pdf-export-BPZM2cuP.js",
"houseplan-assets/summary-panel-runtime-loaded-BLYtOezP.js"
]
},
{
"path": "houseplan-assets/houseplan-editor-runtime-A7oaN5to.js",
"sha256": "d54628476b6722561afbdfc8d6dfa83b4bda516507f7ba33554637e39ef9bd47",
"path": "houseplan-assets/houseplan-editor-runtime-CXJl9W9o.js",
"sha256": "2414ce2d9561c61b6ada65dbe98cd3b65eb92f1c3b4ce5ea3a3e7ea37c20fa82",
"rawBytes": 670154,
"gzipBytes": 178817,
"gzipBytes": 178815,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-CHXO6wCC.js",
"houseplan-assets/furniture-plan-art.generated-DH4ULp8h.js",
"houseplan-assets/houseplan-card-QCQsWhm9.js",
"houseplan-assets/zigbee-topology-df97gjoC.js"
"houseplan-assets/backdrop-pick-CeEIa4lG.js",
"houseplan-assets/furniture-plan-art.generated-CaYvEWnV.js",
"houseplan-assets/houseplan-card-B0Q_XTHX.js",
"houseplan-assets/zigbee-topology-D_LrAqE3.js"
],
"dynamicImports": [
"houseplan-assets/zigbee-topology-runtime-BjT4xEwX.js"
"houseplan-assets/zigbee-topology-runtime-DJH5125h.js"
]
},
{
"path": "houseplan-assets/houseplan-onboarding-runtime-DF0pKq_1.js",
"sha256": "3b7e7fd5dc5c74fe8d8e7319e8ea922bab6966b7d4eb70805c1e90647d1c43d2",
"path": "houseplan-assets/houseplan-onboarding-runtime-BtkZ0Mkc.js",
"sha256": "a02a4c3f1ffea7b70b6c447cad51cd9b206a6eec646b56a2b2bef180f5c193e0",
"rawBytes": 28287,
"gzipBytes": 7039,
"gzipBytes": 7037,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-CHXO6wCC.js",
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/backdrop-pick-CeEIa4lG.js",
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/hp-zigbee-topology-overlay-BLPQa5-z.js",
"sha256": "b53bc8b0c7af9ed65be8efd205023d60f1561b95b10c47d9a3996a9c35b6b68c",
"path": "houseplan-assets/hp-zigbee-topology-overlay-CpQn86-U.js",
"sha256": "5ab766472675b105499354752c02924afc9c00da0daa510bf6ae4dcc1c167953",
"rawBytes": 10756,
"gzipBytes": 3686,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js",
"houseplan-assets/zigbee-topology-df97gjoC.js",
"houseplan-assets/zigbee-topology-runtime-BjT4xEwX.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js",
"houseplan-assets/zigbee-topology-D_LrAqE3.js",
"houseplan-assets/zigbee-topology-runtime-DJH5125h.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/iso-scene-render-B-LgWkof.js",
"sha256": "dcfdaee5d2b49794f00ebccffa269f275790cae594e4d06da6d52662ce13c336",
"path": "houseplan-assets/iso-scene-render-BONN6ODJ.js",
"sha256": "71729dc9c99e6f742751159f60a14c873713bea6b1bf1a0acd407addf4e459a9",
"rawBytes": 44439,
"gzipBytes": 15017,
"gzipBytes": 15016,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/live-interaction-runtime-B2_XndWb.js",
"sha256": "9146866e15503381f4aa648d077ed549fb278bd9f42561d5aa79ab6b52c2c773",
"path": "houseplan-assets/live-interaction-runtime-CgqWId3n.js",
"sha256": "f14c3b58a2c9745d237c1cb2a9ccb5ccbc41e780ea031ffa322ae33c3c76a9d6",
"rawBytes": 8216,
"gzipBytes": 3211,
"gzipBytes": 3208,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/pdf-export-Ddvg38aO.js",
"sha256": "abbfd9ad72786711fd60553b9c42a87a2b61b53ca00953f9df3c6cdcc5712a67",
"path": "houseplan-assets/pdf-export-BPZM2cuP.js",
"sha256": "8e53c48062204e7cff5a681a6ddb599e0477e98e5dfa1b777cee1ca5fe57ae14",
"rawBytes": 236244,
"gzipBytes": 109870,
"gzipBytes": 109874,
"isEntry": false,
"imports": [
"houseplan-assets/furniture-plan-art.generated-DH4ULp8h.js",
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/furniture-plan-art.generated-CaYvEWnV.js",
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-editor-BQEDzzj8.js",
"sha256": "c34475fa1a5eb4ca2d270d4f2751150d65ccf3d7f28a624ecdc11db41524d8e3",
"path": "houseplan-assets/summary-panel-editor-D4-1cfJa.js",
"sha256": "4000d940ce12e9dba008bb0f85a28d201deb2bb955ffa8a7c197c793ea7dc1fa",
"rawBytes": 14824,
"gzipBytes": 3402,
"gzipBytes": 3401,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js",
"houseplan-assets/summary-panel-runtime-loaded-Ci-uYIPy.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js",
"houseplan-assets/summary-panel-runtime-loaded-BLYtOezP.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-metrics-BAzt2V0V.js",
"sha256": "4a6f5b24ed4a5e2264a13f910e9d19454b0e04debf0dc3c771ca6dc11733b939",
"path": "houseplan-assets/summary-panel-metrics-DNBrlcVo.js",
"sha256": "b05e3dc25fd75f13c3463ecc212bb29ad30fa2e9c670e161bbf0d81aa14c0b31",
"rawBytes": 2610,
"gzipBytes": 1307,
"gzipBytes": 1306,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-runtime-loaded-Ci-uYIPy.js",
"sha256": "1d73ae628e53d078d195b6dfc460d97591ceba5a3cf9c98e904b093ff271e1f2",
"path": "houseplan-assets/summary-panel-runtime-loaded-BLYtOezP.js",
"sha256": "8daa20aafbb97a797f052f89a64a28e2acc284040ad9099fe0befa3fef92a2f0",
"rawBytes": 73366,
"gzipBytes": 20089,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": [
"houseplan-assets/summary-panel-editor-BQEDzzj8.js",
"houseplan-assets/summary-panel-metrics-BAzt2V0V.js"
"houseplan-assets/summary-panel-editor-D4-1cfJa.js",
"houseplan-assets/summary-panel-metrics-DNBrlcVo.js"
]
},
{
"path": "houseplan-assets/zigbee-topology-df97gjoC.js",
"sha256": "f2ee5f6443203a28589cbef4a052b04b6385292af9eec9a8442f4facb8e8f0ba",
"path": "houseplan-assets/zigbee-topology-D_LrAqE3.js",
"sha256": "fec21590ff7137d1f7ababf97f83fa30e91af3979ec5759e3d971587bcf96ef0",
"rawBytes": 18961,
"gzipBytes": 7427,
"gzipBytes": 7426,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/zigbee-topology-runtime-BjT4xEwX.js",
"sha256": "863961ec4a50885458b61718aa67ef149a04847c4ca7b734f1fb8e7190868392",
"path": "houseplan-assets/zigbee-topology-runtime-DJH5125h.js",
"sha256": "d16b09ae316f28f0704edc9ad893561bd4b2a8b3dd5c07051bcaceca17456c9c",
"rawBytes": 3941,
"gzipBytes": 1763,
"gzipBytes": 1765,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js",
"houseplan-assets/zigbee-topology-df97gjoC.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js",
"houseplan-assets/zigbee-topology-D_LrAqE3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-card.js",
"sha256": "3d3522bf22c00355dc51dd06610373920bf9cd3529a624be0f5776c1be27d1fc",
"sha256": "1204c95eabef5e07dfe73cfaf44226cbe18e85a5329836339090d36910941a52",
"rawBytes": 1205,
"gzipBytes": 805,
"gzipBytes": 804,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
},
{
"path": "houseplan-panel.js",
"sha256": "ff2f53182fa516127f9e85d7ebe2aab6708b4fd880c483f109bb4911527110b1",
"sha256": "cf3e9badfa13fcd73ee98adf32121a15676e848a90d5ee12a1f0472ad99233b6",
"rawBytes": 6165,
"gzipBytes": 2327,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
}
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="ead0f4146471ab778119d7575ca6c0fae2c76260315828e505380a3e32910549";import{q as e,l as o,v as t,e5 as s,A as a,e6 as i,e7 as l,e8 as n,E as r,c}from"./houseplan-card-QCQsWhm9.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="09fae293e9dee5623085ca73035bb09914a27ad744cffaa70dab64fb29b96787";import{q as e,l as o,v as t,e5 as s,A as a,e6 as i,e7 as l,e8 as n,E as r,c}from"./houseplan-card-B0Q_XTHX.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
.hass=${this.hass}
.data=${this._formData}
.schema=${e}
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="ead0f4146471ab778119d7575ca6c0fae2c76260315828e505380a3e32910549";import{l as t,b4 as s,A as e,v as a,c as o,cn as l,co as i,cp as h,cq as c,b1 as n,cr as r,cw as p,cs as d,ct as _,cu as u,cv as g,cx as m,cy as b,dt as $,du as v,dv as f,b0 as y,b2 as w,dw as D}from"./houseplan-card-QCQsWhm9.js";import{c as k,e as S,r as C,a as M}from"./backdrop-pick-CHXO6wCC.js";const F=1e3,x=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},T="ead0f4146471ab778119d7575ca6c0fae2c76260315828e505380a3e32910549";class L{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(l){const i=`${l}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,l)&&s(h,i)?o`<hp-help data-help-key=${l}
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="09fae293e9dee5623085ca73035bb09914a27ad744cffaa70dab64fb29b96787";import{l as t,b4 as s,A as e,v as a,c as o,cn as l,co as i,cp as h,cq as c,b1 as n,cr as r,cw as p,cs as d,ct as _,cu as u,cv as g,cx as m,cy as b,dt as $,du as v,dv as f,b0 as y,b2 as w,dw as D}from"./houseplan-card-B0Q_XTHX.js";import{c as k,e as S,r as C,a as M}from"./backdrop-pick-CeEIa4lG.js";const F=1e3,x=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},T="09fae293e9dee5623085ca73035bb09914a27ad744cffaa70dab64fb29b96787";class L{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(l){const i=`${l}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,l)&&s(h,i)?o`<hp-help data-help-key=${l}
.text=${a(h,l)} .ariaLabel=${a(h,i)}></hp-help>`:e}_openSpaceDialog(t,s){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===t){const e=this.host._serverCfg.spaces.find(t=>t.id===s);if(!e)return;const a=l(e),o=e.settings?.custom_fill&&"object"==typeof e.settings.custom_fill?i(e.settings.custom_fill):null,p="none"===a.fill?{...o||h,a:0}:o;return void(this.host._spaceDialog={mode:t,spaceId:s,title:e.title,planUrl:e.plan_url||null,planFile:null,source:e.plan_url?"file":"draw",showBorders:a.showBorders,showNames:a.showNames,zeroWallStyle:r(e),displayTouched:!0,hideDecor:a.hideDecor,hideOpenings:a.hideOpenings,roomColor:a.color,roomOpacity:a.opacity,fillMode:"none"===a.fill?"custom":a.fill,customFill:p,glowEnabled:a.glow,bgColor:a.bgColor,bgMode:"static"===e.settings?.bg_mode||"daynight"===e.settings?.bg_mode?e.settings.bg_mode:null,northDeg:n({},e.settings),sunRays:"boolean"==typeof e.settings?.sun_rays?e.settings.sun_rays:null,tempMin:a.tempMin,tempMax:a.tempMax,showLqi:a.showLqi??this.host._config?.show_signal??!0,cardFontScale:a.cardFontScale,labelTemp:a.labelTemp,labelHum:a.labelHum,labelLqi:a.labelLqi,labelLight:a.labelLight,cellCm:Number(e.cell_cm)>0?Number(e.cell_cm):5,cellCmInput:c(Number(e.cell_cm)>0?Number(e.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const e=p(this.host._imperial);this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...m(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:g,roomOpacity:u,fillMode:"custom",customFill:{...h,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:_,tempMax:d,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:e,cellCmInput:c(e,this.host._imperial),cellCmTouched:!1,busy:!1}}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;s.value="";const a=await k(e);if("reject"===a.kind)return void this.host._showToast(this.host._t("toast.plan_formats"));if("guard"===a.kind)return void(this.host._backdropGuard=a.state);const o=await S(e,a.ext,e.name);this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:o})}_renderBackdropGuard(){return C(this.host,t=>{this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:t})},()=>{this.host._backdropGuard=null},this.host.hass)??e}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),a=this.host._spaceDialog;return a&&a.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...a,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){const s=this.host._spaceDialog,e=s?.saved?.find(s=>s.name===t);if(!s||!e||e.used_by.length||e.url===s.planUrl)return;const a=await this.host._confirmDanger({key:"delete-plan",kind:"destructive",title:this.host._t("confirm.delete_plan_title"),message:this.host._t("confirm.delete_plan_body"),objectName:t,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),o=this.host._spaceDialog,l=o?.saved?.find(s=>s.name===t);if(a&&o&&l&&l.url===e.url&&l.modified===e.modified&&!l.used_by.length&&l.url!==o.planUrl)try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return o`<div class="savedplans muted">${this.host._t("space.loading")}</div>`;const s=t.saved||[];if(!s.length)return o`<div class="savedplans muted">${this.host._t("space.no_saved")}</div>`;return o`<div class="savedplans">
${s.map(s=>{return o`
<div class="savedplan ${s.url===t.planUrl?"cur":""}">
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="ead0f4146471ab778119d7575ca6c0fae2c76260315828e505380a3e32910549";import{c as a,A as e}from"./houseplan-card-QCQsWhm9.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-Ci-uYIPy.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show">
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="09fae293e9dee5623085ca73035bb09914a27ad744cffaa70dab64fb29b96787";import{c as a,A as e}from"./houseplan-card-B0Q_XTHX.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-BLYtOezP.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show">
<span class="summary-switch-caption"><strong>${b("summary.show_local")}</strong>
<small id="summary-local-show-hint">${b("summary.show_local_hint")}</small></span>
<input id="summary-local-show" data-summary-local-show type="checkbox"
@@ -1 +0,0 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="ead0f4146471ab778119d7575ca6c0fae2c76260315828e505380a3e32910549";import{eb as e,P as t,a5 as n,M as i,aq as r,N as o,bs as s,br as a,a4 as c,a3 as l,aA as u,ec as d,ed as f,bu as m,ee as g}from"./houseplan-card-QCQsWhm9.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=u(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const r=String(i.binding||"").indexOf(":");if(r<1)continue;const o=i.binding.slice(0,r),s=i.binding.slice(r+1),a="device"===o?e.registry.devices?.[s]:null,c="entity"===o?e.registry.entities?.[s]:null,l="device"===o?s:c?.device_id,u="device"===o?a?.area_id:c?.area_id||l&&e.registry.devices?.[l]?.area_id,d="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||u||"",f=d&&e.areaToSpace[d]||i.space||e.firstSpaceId;l&&e.registry.devices?.[l]&&e.spaceIds.has(f)&&(!n.devices.has(l)||"entity"===o&&n.liveEntities.has(s))&&t.add(l)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=c(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,r,o);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:l(e.rooms,t.walls,t.openCuts,i,t.cellCm,r,o)}}function*h(c,l,u=_){try{let d=0;for(const f of l){const l=c.spaces.find(e=>String(e?.id)===f.id);if(!l)continue;const m=e(l,f),g=u(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const a=t(e);if(!a)continue;const c=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,r,o,g.roomGeom,g.multiWallNodes)||a;v=y(v,s(c,m.physicalBodies)),yield}const _=m.cellCm/r;d+=a(v)*_*_/1e4}return d}catch{return null}}function p(e,t,n=_){const i=h(e,t,n);let r=i.next();for(;!r.done;)r=i.next();return r.value}function b(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=d(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{h as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,b as summarySystemValue,p as totalCleanFloorAreaM2};
@@ -0,0 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="09fae293e9dee5623085ca73035bb09914a27ad744cffaa70dab64fb29b96787";import{eb as e,P as t,a5 as n,M as i,aq as r,N as o,bs as a,br as s,a4 as l,a3 as c,aA as u,ec as d,ed as f,bu as m,ee as g}from"./houseplan-card-B0Q_XTHX.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=u(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const r=String(i.binding||"").indexOf(":");if(r<1)continue;const o=i.binding.slice(0,r),a=i.binding.slice(r+1),s="device"===o?e.registry.devices?.[a]:null,l="entity"===o?e.registry.entities?.[a]:null,c="device"===o?a:l?.device_id,u="device"===o?s?.area_id:l?.area_id||c&&e.registry.devices?.[c]?.area_id,d="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||u||"",f=d&&e.areaToSpace[d]||i.space||e.firstSpaceId;c&&e.registry.devices?.[c]&&e.spaceIds.has(f)&&(!n.devices.has(c)||"entity"===o&&n.liveEntities.has(a))&&t.add(c)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=l(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,r,o);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:c(e.rooms,t.walls,t.openCuts,i,t.cellCm,r,o)}}function*b(l,c,u=_){try{let d=0;for(const f of c){const c=l.spaces.find(e=>String(e?.id)===f.id);if(!c)continue;const m=e(c,f),g=u(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const s=t(e);if(!s)continue;const l=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,r,o,g.roomGeom,g.multiWallNodes)||s;v=y(v,a(l,m.physicalBodies)),yield}const _=m.cellCm/r;d+=s(v)*_*_/1e4}return d}catch{return null}}function h(e,t,n=_){const i=b(e,t,n);let r=i.next();for(;!r.done;)r=i.next();return r.value}function p(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=d(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{b as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,p as summarySystemValue,h as totalCleanFloorAreaM2};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="ead0f4146471ab778119d7575ca6c0fae2c76260315828e505380a3e32910549";import{n as t,b as n}from"./zigbee-topology-df97gjoC.js";import{F as e}from"./houseplan-card-QCQsWhm9.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function p(t){if(!0!==t?.user?.is_admin)throw a("permission")}function f(n){const e=i(n);return e?c(e,"zha",async()=>{if(p(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function m(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function g(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(p(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,f=null,g=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{f=t,g=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const p=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&f?.(n):c&&g?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof p&&b.push(p),await m(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await m(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{f as readZhaTopology,g as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="09fae293e9dee5623085ca73035bb09914a27ad744cffaa70dab64fb29b96787";import{n as t,b as n}from"./zigbee-topology-D_LrAqE3.js";import{F as e}from"./houseplan-card-B0Q_XTHX.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function f(t){if(!0!==t?.user?.is_admin)throw a("permission")}function p(n){const e=i(n);return e?c(e,"zha",async()=>{if(f(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function m(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function g(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(f(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,p=null,g=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{p=t,g=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const f=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&p?.(n):c&&g?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof f&&b.push(f),await m(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await m(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{p as readZhaTopology,g as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="ead0f4146471ab778119d7575ca6c0fae2c76260315828e505380a3e32910549";try{await import("./houseplan-assets/houseplan-card-QCQsWhm9.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)}
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="09fae293e9dee5623085ca73035bb09914a27ad744cffaa70dab64fb29b96787";try{await import("./houseplan-assets/houseplan-card-B0Q_XTHX.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)}
File diff suppressed because one or more lines are too long
+69 -18
View File
@@ -5,13 +5,14 @@ import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { sourceFingerprint } from '../../scripts/source-fingerprint.mjs';
import { GOLDEN_MATRIX_VERSION, GOLDEN_SCENARIOS } from './matrix.mjs';
import { GOLDEN_BASELINE_MANIFEST } from './policy.mjs';
import { GOLDEN_BASELINE_MANIFEST, GOLDEN_INDEX_SCHEMA, indexCapturedOn } from './policy.mjs';
import {
goldenAcceptancePlan, goldenAcceptanceRefusal, goldenSilentDeclarations,
goldenWitnessRefusal,
} from '../../scripts/golden-acceptance.mjs';
import {
assertCaptureEnvironment, captureEnvironment, environmentNote,
CAPTURE_CANON_PLATFORM, captureEnvironment, environmentNote,
foreignCaptureAllowance, foreignCaptureRefusal, reportCaptureProvenance,
} from '../../scripts/capture-environment.mjs';
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../..');
@@ -41,21 +42,61 @@ if (typeof report.chromium !== 'string' || !report.chromium)
throw new Error('candidate report does not identify its Chromium build');
if (!Array.isArray(report.results)) throw new Error('candidate report has no scenario results');
// Среда приёмки (#455). Отчёт съёмки платформу не несёт — `run.mjs` входит в
// корпус sourceFingerprint, и его правка объявила бы устаревшими бандл,
// скриншоты документации и сам индекс эталонов. Но приёмка идёт там же, где
// лежат артефакты, поэтому её платформа — честный признак среды кадров.
const environment = captureEnvironment();
const foreignAllowed = assertCaptureEnvironment({ kind: 'golden', stage: 'accept' });
// Провенанс съёмки и приёмки — две разные вещи, и до #571 их путали.
//
// Прежняя редакция знала только свою платформу и записывала её в индекс как
// платформу КАДРОВ: артефакт Linux-прогона 34853080375, принятый на Windows,
// дал на `ad4000f9` запись `"platform": "win32"` у кадров, которых Windows не
// снимала. Причина осознанного обхода при этом осталась в stdout и в индекс не
// попала, хотя `AGENTS.md` обещает след в обоих местах.
//
// Теперь среда съёмки читается из отчёта, среда приёмки остаётся своей, и обе
// уезжают в индекс под разными именами. Гейт чужой среды стоит на обеих:
// съёмка вне канона — то, ради чего правило вообще есть; приёмка вне канона
// остаётся осознанным решением с записанной причиной.
const acceptance = captureEnvironment();
const { provenance, legacy } = reportCaptureProvenance(report);
const capturedOn = provenance?.platform || null;
const allowance = foreignCaptureAllowance();
for (const [platform, stageNote] of [
// Схема 1 платформы съёмки не несёт физически: судить нечего, и подставлять
// свою — ровно та ошибка, которую чинит задача. Такой отчёт принимается, но
// в индекс уедет `capturedOn: null`.
[capturedOn, 'съёмки'],
[acceptance.platform, 'приёмки'],
]) {
if (!platform) continue;
const { refusal } = foreignCaptureRefusal({
platform, kind: 'golden', stage: 'accept', allowance,
});
if (refusal) throw new Error(`${refusal}\n(среда ${stageNote}: ${platform})`);
}
const foreignAllowed = (capturedOn && capturedOn !== CAPTURE_CANON_PLATFORM)
|| acceptance.platform !== CAPTURE_CANON_PLATFORM
? allowance
: null;
if (legacy) {
console.log('Отчёт старой схемы: провенанса съёмки нет, в индекс уедет capturedOn=null (#571).');
}
if (foreignAllowed) {
console.log(`Чужая среда приёмки разрешена осознанно: ${foreignAllowed}`);
console.log(`Чужая среда разрешена осознанно: ${foreignAllowed}`);
}
const refusal = goldenAcceptanceRefusal(report.results, declared, declaredNew);
if (refusal) throw new Error(refusal);
const byId = new Map(report.results.map((result) => [result.id, result]));
const baselineRoot = resolve(ROOT, 'demo/golden/baselines');
/**
* Куда писать эталоны. По умолчанию — каталог репозитория; `--baselines=<dir>`
* нужен свидетелям (#571): иначе проверить «отказ произошёл ДО записи» можно
* было бы только порчей рабочего дерева, а значит никак. Тот же довод вынес
* разбор вердикта ревью в отдельный скрипт (#556): враждебные случаи должны
* быть исполнимы.
*/
const baselinesArg = process.argv.find((arg) => arg.startsWith('--baselines='));
const baselineRoot = baselinesArg
? resolve(baselinesArg.slice('--baselines='.length))
: resolve(ROOT, 'demo/golden/baselines');
mkdirSync(baselineRoot, { recursive: true });
/**
* Прежний индекс: источник хешей для сцен, которые остаются как были (#351).
@@ -89,11 +130,14 @@ if (witnessCheck.refusal) {
// Приписка про среду — то, чего не хватало отказу: «свидетелей 0 из 10» без
// неё читается как «объяви больше сцен», и обход в одну команду выглядит
// решением (#455).
const previousIndex = existsSync(manifestPath)
? JSON.parse(readFileSync(manifestPath, 'utf8'))
: null;
const note = environmentNote({
capturedOn: environment.platform,
acceptedOn: existsSync(manifestPath)
? JSON.parse(readFileSync(manifestPath, 'utf8')).platform || null
: null,
capturedOn,
// Индекс схемы 1 хранил платформу приёмщика под именем `platform`; читаем
// обе, но новую — первой.
acceptedOn: indexCapturedOn(previousIndex),
});
throw new Error(note ? `${witnessCheck.refusal}\n${note}` : witnessCheck.refusal);
}
@@ -121,14 +165,21 @@ for (const id of plan.replace) {
copyFileSync(resolve(from, 'actual', `${id}.png`), resolve(baselineRoot, `${id}.png`));
}
writeFileSync(resolve(baselineRoot, GOLDEN_BASELINE_MANIFEST), `${JSON.stringify({
schema: 1,
schema: GOLDEN_INDEX_SCHEMA,
matrixVersion: GOLDEN_MATRIX_VERSION,
acceptedAt: new Date().toISOString(),
sourceFingerprint: report.buildFingerprint,
chromium: report.chromium,
// Платформа рядом с версией браузера: провенанс среды, по которому следующая
// приёмка отличит «объявили не то» от «сняли не там» (#455).
platform: environment.platform,
// #571: две стороны провенанса, а не одна. `capturedOn` — где сняты кадры (из
// отчёта), `acceptedOn` — где их приняли. Раньше поле было одно, называлось
// `platform` и заполнялось платформой приёмщика, то есть отвечало на вопрос,
// которого никто не задавал.
capturedOn: capturedOn,
acceptedOn: acceptance.platform,
capture: provenance,
// Причина осознанного обхода живёт в индексе, а не только в stdout: через
// неделю stdout нет ни у кого, а индекс лежит в репозитории.
foreignCapture: foreignAllowed ? { reason: foreignAllowed } : null,
// #355: след приёмки в артефакте, не только в истории shell.
witnesses: skipWitnesses
? { skipped: true, reason: skipReason }
+15
View File
@@ -7,6 +7,21 @@ import {
// repository with more than one match (test/repo-hygiene.test.mjs).
export const GOLDEN_BASELINE_MANIFEST = 'baselines-index.json';
/**
* Версия индекса эталонов (#571).
*
* Схема 1 хранила одно поле `platform`, и заполнял его приёмщик своей
* платформой. Схема 2 различает `capturedOn` и `acceptedOn`, несёт раздел
* `capture` из отчёта съёмки и причину осознанного обхода. Читатели обязаны
* понимать обе: артефакты и индексы живут дольше схем.
*/
export const GOLDEN_INDEX_SCHEMA = 2;
/** Платформа кадров по индексу любой схемы: 2 — `capturedOn`, 1 — `platform`. */
export const indexCapturedOn = (index) => (index && typeof index === 'object'
? (index.capturedOn ?? (Number(index.schema) >= GOLDEN_INDEX_SCHEMA ? null : index.platform ?? null))
: null);
/**
* Проверка вызова — и заодно проверка среды съёмки (#455).
*
+6 -1
View File
@@ -7,6 +7,7 @@ import { launch } from '../serve.mjs';
import { assertFreshDemoBundle } from '../bundle-freshness.mjs';
import { goldenClip, prepareGoldenScenario } from './harness.mjs';
import { GOLDEN_MATRIX_VERSION, GOLDEN_SCENARIOS } from './matrix.mjs';
import { CAPTURE_PROVENANCE_SCHEMA, captureProvenance } from '../../scripts/capture-environment.mjs';
import {
assertGoldenInvocation,
GOLDEN_BASELINE_MANIFEST,
@@ -1203,8 +1204,12 @@ const manifestValid = !!baselineManifest
&& expectedScenarioIds.every((id) => typeof baselineManifest.scenarios?.[id] === 'string')
&& goldenScenarioSetsMatch(expectedScenarioIds, indexedScenarioIds, baselineScenarioIds);
const report = {
schema: 1,
// #571: схема 2 обязана нести провенанс съёмки. До неё отчёт платформу не
// нёс, и приёмщик записывал в индекс эталонов свою — на `ad4000f9` кадры
// Linux-прогона 34853080375 уехали в индекс как `win32`.
schema: CAPTURE_PROVENANCE_SCHEMA,
mode,
capture: captureProvenance({ chromium, buildFingerprint }),
generatedAt: new Date().toISOString(),
matrixVersion: GOLDEN_MATRIX_VERSION,
buildFingerprint,
+128 -128
View File
@@ -1,295 +1,295 @@
{
"schema": 1,
"fingerprint": "ead0f4146471ab778119d7575ca6c0fae2c76260315828e505380a3e32910549",
"fingerprint": "09fae293e9dee5623085ca73035bb09914a27ad744cffaa70dab64fb29b96787",
"entry": "houseplan-card.js",
"panelEntry": "houseplan-panel.js",
"initialViewFiles": [
"houseplan-assets/houseplan-card-QCQsWhm9.js",
"houseplan-assets/houseplan-card-B0Q_XTHX.js",
"houseplan-card.js"
],
"initialViewGzipBytes": 291158,
"initialViewGzipBytes": 291160,
"initialPanelFiles": [
"houseplan-assets/houseplan-card-QCQsWhm9.js",
"houseplan-assets/houseplan-card-B0Q_XTHX.js",
"houseplan-panel.js"
],
"initialPanelGzipBytes": 292680,
"initialPanelGzipBytes": 292683,
"initialPanelOnlyFiles": [
"houseplan-panel.js"
],
"initialPanelOnlyGzipBytes": 2327,
"lazyFiles": [
"houseplan-assets/backdrop-pick-CHXO6wCC.js",
"houseplan-assets/de-Ckd-utGr.js",
"houseplan-assets/editor-Cm8BzYup.js",
"houseplan-assets/fr-dTwY5e5m.js",
"houseplan-assets/furniture-plan-art.generated-DH4ULp8h.js",
"houseplan-assets/houseplan-editor-runtime-A7oaN5to.js",
"houseplan-assets/houseplan-onboarding-runtime-DF0pKq_1.js",
"houseplan-assets/hp-zigbee-topology-overlay-BLPQa5-z.js",
"houseplan-assets/iso-scene-render-B-LgWkof.js",
"houseplan-assets/live-interaction-runtime-B2_XndWb.js",
"houseplan-assets/pdf-export-Ddvg38aO.js",
"houseplan-assets/summary-panel-runtime-loaded-Ci-uYIPy.js",
"houseplan-assets/zigbee-topology-df97gjoC.js",
"houseplan-assets/zigbee-topology-runtime-BjT4xEwX.js"
"houseplan-assets/backdrop-pick-CeEIa4lG.js",
"houseplan-assets/de-BaSj7HzM.js",
"houseplan-assets/editor-D8B3OQYD.js",
"houseplan-assets/fr-4HoeVytE.js",
"houseplan-assets/furniture-plan-art.generated-CaYvEWnV.js",
"houseplan-assets/houseplan-editor-runtime-CXJl9W9o.js",
"houseplan-assets/houseplan-onboarding-runtime-BtkZ0Mkc.js",
"houseplan-assets/hp-zigbee-topology-overlay-CpQn86-U.js",
"houseplan-assets/iso-scene-render-BONN6ODJ.js",
"houseplan-assets/live-interaction-runtime-CgqWId3n.js",
"houseplan-assets/pdf-export-BPZM2cuP.js",
"houseplan-assets/summary-panel-runtime-loaded-BLYtOezP.js",
"houseplan-assets/zigbee-topology-D_LrAqE3.js",
"houseplan-assets/zigbee-topology-runtime-DJH5125h.js"
],
"lazyGzipBytes": 433657,
"lazyGzipBytes": 433647,
"lazyEditorFiles": [
"houseplan-assets/backdrop-pick-CHXO6wCC.js",
"houseplan-assets/editor-Cm8BzYup.js",
"houseplan-assets/furniture-plan-art.generated-DH4ULp8h.js",
"houseplan-assets/houseplan-editor-runtime-A7oaN5to.js",
"houseplan-assets/zigbee-topology-df97gjoC.js"
"houseplan-assets/backdrop-pick-CeEIa4lG.js",
"houseplan-assets/editor-D8B3OQYD.js",
"houseplan-assets/furniture-plan-art.generated-CaYvEWnV.js",
"houseplan-assets/houseplan-editor-runtime-CXJl9W9o.js",
"houseplan-assets/zigbee-topology-D_LrAqE3.js"
],
"lazyEditorGzipBytes": 218045,
"lazyEditorGzipBytes": 218051,
"lazyOnboardingFiles": [
"houseplan-assets/backdrop-pick-CHXO6wCC.js",
"houseplan-assets/houseplan-onboarding-runtime-DF0pKq_1.js"
"houseplan-assets/backdrop-pick-CeEIa4lG.js",
"houseplan-assets/houseplan-onboarding-runtime-BtkZ0Mkc.js"
],
"lazyOnboardingGzipBytes": 13919,
"lazyOnboardingGzipBytes": 13918,
"lazyLocaleFiles": [
"houseplan-assets/de-Ckd-utGr.js",
"houseplan-assets/fr-dTwY5e5m.js"
"houseplan-assets/de-BaSj7HzM.js",
"houseplan-assets/fr-4HoeVytE.js"
],
"lazyLocaleGzipBytes": 54937,
"lazyLocaleGzipBytes": 54921,
"lazyIsometricFiles": [
"houseplan-assets/iso-scene-render-B-LgWkof.js"
"houseplan-assets/iso-scene-render-BONN6ODJ.js"
],
"lazyIsometricGzipBytes": 15017,
"lazyIsometricGzipBytes": 15016,
"lazyFurnitureArtFiles": [
"houseplan-assets/furniture-plan-art.generated-DH4ULp8h.js"
"houseplan-assets/furniture-plan-art.generated-CaYvEWnV.js"
],
"lazyFurnitureArtGzipBytes": 23338,
"lazyFurnitureArtGzipBytes": 23346,
"lazyPdfFiles": [
"houseplan-assets/furniture-plan-art.generated-DH4ULp8h.js",
"houseplan-assets/pdf-export-Ddvg38aO.js"
"houseplan-assets/furniture-plan-art.generated-CaYvEWnV.js",
"houseplan-assets/pdf-export-BPZM2cuP.js"
],
"lazyPdfGzipBytes": 133208,
"lazyPdfGzipBytes": 133220,
"files": [
{
"path": "houseplan-assets/backdrop-pick-CHXO6wCC.js",
"sha256": "36465bc759532e306598d53a85050f0b74b1530c529da70f79216f4b69c9c373",
"path": "houseplan-assets/backdrop-pick-CeEIa4lG.js",
"sha256": "7366654abb5d7a9c273cbaf01b95bb5ce792f41a335dca6b520f8ef2e699ddf6",
"rawBytes": 19956,
"gzipBytes": 6880,
"gzipBytes": 6881,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/de-Ckd-utGr.js",
"sha256": "a57614e4a6cca92f90d763c0c1d1cda24b24d329a40a5ac3cad38a8aa78b5681",
"path": "houseplan-assets/de-BaSj7HzM.js",
"sha256": "104dd42e44f0a9fc7edd5d78bc7965dc706cb0722dd52a18347f1d738f3cf0b3",
"rawBytes": 91590,
"gzipBytes": 27751,
"gzipBytes": 27743,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/editor-Cm8BzYup.js",
"sha256": "517ff6fc16f3e51a610c957d66204d61314ee26fe77189e7d401f109abd3c46a",
"path": "houseplan-assets/editor-D8B3OQYD.js",
"sha256": "7785e1e4b736f6e3ed1fca97a2713b05bc52ee1199faf0ee7f7461f8c8669223",
"rawBytes": 3831,
"gzipBytes": 1583,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/fr-dTwY5e5m.js",
"sha256": "33b9690000ebb0bb53d91e00df0e105875ba1281e4b86d439e78dd98998d85a1",
"path": "houseplan-assets/fr-4HoeVytE.js",
"sha256": "b748e68e439550a6cad6a85b250ae32f16b8cf3cb83621e68b8c39a38d0c7746",
"rawBytes": 93884,
"gzipBytes": 27186,
"gzipBytes": 27178,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/furniture-plan-art.generated-DH4ULp8h.js",
"sha256": "0d6b8f7e60d366244931bfe015a94ed349689cf9d8ad21f1c7fae5efdaf4b73f",
"path": "houseplan-assets/furniture-plan-art.generated-CaYvEWnV.js",
"sha256": "5565fd38519ff3d7c57dbaacb38daf041c0d2b8b810dccb601bf518e348254c0",
"rawBytes": 90517,
"gzipBytes": 23338,
"gzipBytes": 23346,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-card-QCQsWhm9.js",
"sha256": "4326ca9b05e0d1383e94e4a6439af56b3746962c210ce93c87dba80df7e0db2a",
"path": "houseplan-assets/houseplan-card-B0Q_XTHX.js",
"sha256": "a2e6f4c2c11a06e9e93bd7bef54d179932f703c07e76141da18b82ad8c9de5dc",
"rawBytes": 1034124,
"gzipBytes": 290353,
"gzipBytes": 290356,
"isEntry": false,
"imports": [],
"dynamicImports": [
"houseplan-assets/de-Ckd-utGr.js",
"houseplan-assets/editor-Cm8BzYup.js",
"houseplan-assets/fr-dTwY5e5m.js",
"houseplan-assets/furniture-plan-art.generated-DH4ULp8h.js",
"houseplan-assets/houseplan-editor-runtime-A7oaN5to.js",
"houseplan-assets/houseplan-onboarding-runtime-DF0pKq_1.js",
"houseplan-assets/hp-zigbee-topology-overlay-BLPQa5-z.js",
"houseplan-assets/iso-scene-render-B-LgWkof.js",
"houseplan-assets/live-interaction-runtime-B2_XndWb.js",
"houseplan-assets/pdf-export-Ddvg38aO.js",
"houseplan-assets/summary-panel-runtime-loaded-Ci-uYIPy.js"
"houseplan-assets/de-BaSj7HzM.js",
"houseplan-assets/editor-D8B3OQYD.js",
"houseplan-assets/fr-4HoeVytE.js",
"houseplan-assets/furniture-plan-art.generated-CaYvEWnV.js",
"houseplan-assets/houseplan-editor-runtime-CXJl9W9o.js",
"houseplan-assets/houseplan-onboarding-runtime-BtkZ0Mkc.js",
"houseplan-assets/hp-zigbee-topology-overlay-CpQn86-U.js",
"houseplan-assets/iso-scene-render-BONN6ODJ.js",
"houseplan-assets/live-interaction-runtime-CgqWId3n.js",
"houseplan-assets/pdf-export-BPZM2cuP.js",
"houseplan-assets/summary-panel-runtime-loaded-BLYtOezP.js"
]
},
{
"path": "houseplan-assets/houseplan-editor-runtime-A7oaN5to.js",
"sha256": "d54628476b6722561afbdfc8d6dfa83b4bda516507f7ba33554637e39ef9bd47",
"path": "houseplan-assets/houseplan-editor-runtime-CXJl9W9o.js",
"sha256": "2414ce2d9561c61b6ada65dbe98cd3b65eb92f1c3b4ce5ea3a3e7ea37c20fa82",
"rawBytes": 670154,
"gzipBytes": 178817,
"gzipBytes": 178815,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-CHXO6wCC.js",
"houseplan-assets/furniture-plan-art.generated-DH4ULp8h.js",
"houseplan-assets/houseplan-card-QCQsWhm9.js",
"houseplan-assets/zigbee-topology-df97gjoC.js"
"houseplan-assets/backdrop-pick-CeEIa4lG.js",
"houseplan-assets/furniture-plan-art.generated-CaYvEWnV.js",
"houseplan-assets/houseplan-card-B0Q_XTHX.js",
"houseplan-assets/zigbee-topology-D_LrAqE3.js"
],
"dynamicImports": [
"houseplan-assets/zigbee-topology-runtime-BjT4xEwX.js"
"houseplan-assets/zigbee-topology-runtime-DJH5125h.js"
]
},
{
"path": "houseplan-assets/houseplan-onboarding-runtime-DF0pKq_1.js",
"sha256": "3b7e7fd5dc5c74fe8d8e7319e8ea922bab6966b7d4eb70805c1e90647d1c43d2",
"path": "houseplan-assets/houseplan-onboarding-runtime-BtkZ0Mkc.js",
"sha256": "a02a4c3f1ffea7b70b6c447cad51cd9b206a6eec646b56a2b2bef180f5c193e0",
"rawBytes": 28287,
"gzipBytes": 7039,
"gzipBytes": 7037,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-CHXO6wCC.js",
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/backdrop-pick-CeEIa4lG.js",
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/hp-zigbee-topology-overlay-BLPQa5-z.js",
"sha256": "b53bc8b0c7af9ed65be8efd205023d60f1561b95b10c47d9a3996a9c35b6b68c",
"path": "houseplan-assets/hp-zigbee-topology-overlay-CpQn86-U.js",
"sha256": "5ab766472675b105499354752c02924afc9c00da0daa510bf6ae4dcc1c167953",
"rawBytes": 10756,
"gzipBytes": 3686,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js",
"houseplan-assets/zigbee-topology-df97gjoC.js",
"houseplan-assets/zigbee-topology-runtime-BjT4xEwX.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js",
"houseplan-assets/zigbee-topology-D_LrAqE3.js",
"houseplan-assets/zigbee-topology-runtime-DJH5125h.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/iso-scene-render-B-LgWkof.js",
"sha256": "dcfdaee5d2b49794f00ebccffa269f275790cae594e4d06da6d52662ce13c336",
"path": "houseplan-assets/iso-scene-render-BONN6ODJ.js",
"sha256": "71729dc9c99e6f742751159f60a14c873713bea6b1bf1a0acd407addf4e459a9",
"rawBytes": 44439,
"gzipBytes": 15017,
"gzipBytes": 15016,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/live-interaction-runtime-B2_XndWb.js",
"sha256": "9146866e15503381f4aa648d077ed549fb278bd9f42561d5aa79ab6b52c2c773",
"path": "houseplan-assets/live-interaction-runtime-CgqWId3n.js",
"sha256": "f14c3b58a2c9745d237c1cb2a9ccb5ccbc41e780ea031ffa322ae33c3c76a9d6",
"rawBytes": 8216,
"gzipBytes": 3211,
"gzipBytes": 3208,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/pdf-export-Ddvg38aO.js",
"sha256": "abbfd9ad72786711fd60553b9c42a87a2b61b53ca00953f9df3c6cdcc5712a67",
"path": "houseplan-assets/pdf-export-BPZM2cuP.js",
"sha256": "8e53c48062204e7cff5a681a6ddb599e0477e98e5dfa1b777cee1ca5fe57ae14",
"rawBytes": 236244,
"gzipBytes": 109870,
"gzipBytes": 109874,
"isEntry": false,
"imports": [
"houseplan-assets/furniture-plan-art.generated-DH4ULp8h.js",
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/furniture-plan-art.generated-CaYvEWnV.js",
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-editor-BQEDzzj8.js",
"sha256": "c34475fa1a5eb4ca2d270d4f2751150d65ccf3d7f28a624ecdc11db41524d8e3",
"path": "houseplan-assets/summary-panel-editor-D4-1cfJa.js",
"sha256": "4000d940ce12e9dba008bb0f85a28d201deb2bb955ffa8a7c197c793ea7dc1fa",
"rawBytes": 14824,
"gzipBytes": 3402,
"gzipBytes": 3401,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js",
"houseplan-assets/summary-panel-runtime-loaded-Ci-uYIPy.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js",
"houseplan-assets/summary-panel-runtime-loaded-BLYtOezP.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-metrics-BAzt2V0V.js",
"sha256": "4a6f5b24ed4a5e2264a13f910e9d19454b0e04debf0dc3c771ca6dc11733b939",
"path": "houseplan-assets/summary-panel-metrics-DNBrlcVo.js",
"sha256": "b05e3dc25fd75f13c3463ecc212bb29ad30fa2e9c670e161bbf0d81aa14c0b31",
"rawBytes": 2610,
"gzipBytes": 1307,
"gzipBytes": 1306,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-runtime-loaded-Ci-uYIPy.js",
"sha256": "1d73ae628e53d078d195b6dfc460d97591ceba5a3cf9c98e904b093ff271e1f2",
"path": "houseplan-assets/summary-panel-runtime-loaded-BLYtOezP.js",
"sha256": "8daa20aafbb97a797f052f89a64a28e2acc284040ad9099fe0befa3fef92a2f0",
"rawBytes": 73366,
"gzipBytes": 20089,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": [
"houseplan-assets/summary-panel-editor-BQEDzzj8.js",
"houseplan-assets/summary-panel-metrics-BAzt2V0V.js"
"houseplan-assets/summary-panel-editor-D4-1cfJa.js",
"houseplan-assets/summary-panel-metrics-DNBrlcVo.js"
]
},
{
"path": "houseplan-assets/zigbee-topology-df97gjoC.js",
"sha256": "f2ee5f6443203a28589cbef4a052b04b6385292af9eec9a8442f4facb8e8f0ba",
"path": "houseplan-assets/zigbee-topology-D_LrAqE3.js",
"sha256": "fec21590ff7137d1f7ababf97f83fa30e91af3979ec5759e3d971587bcf96ef0",
"rawBytes": 18961,
"gzipBytes": 7427,
"gzipBytes": 7426,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/zigbee-topology-runtime-BjT4xEwX.js",
"sha256": "863961ec4a50885458b61718aa67ef149a04847c4ca7b734f1fb8e7190868392",
"path": "houseplan-assets/zigbee-topology-runtime-DJH5125h.js",
"sha256": "d16b09ae316f28f0704edc9ad893561bd4b2a8b3dd5c07051bcaceca17456c9c",
"rawBytes": 3941,
"gzipBytes": 1763,
"gzipBytes": 1765,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js",
"houseplan-assets/zigbee-topology-df97gjoC.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js",
"houseplan-assets/zigbee-topology-D_LrAqE3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-card.js",
"sha256": "3d3522bf22c00355dc51dd06610373920bf9cd3529a624be0f5776c1be27d1fc",
"sha256": "1204c95eabef5e07dfe73cfaf44226cbe18e85a5329836339090d36910941a52",
"rawBytes": 1205,
"gzipBytes": 805,
"gzipBytes": 804,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
},
{
"path": "houseplan-panel.js",
"sha256": "ff2f53182fa516127f9e85d7ebe2aab6708b4fd880c483f109bb4911527110b1",
"sha256": "cf3e9badfa13fcd73ee98adf32121a15676e848a90d5ee12a1f0472ad99233b6",
"rawBytes": 6165,
"gzipBytes": 2327,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-QCQsWhm9.js"
"houseplan-assets/houseplan-card-B0Q_XTHX.js"
],
"dynamicImports": []
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="ead0f4146471ab778119d7575ca6c0fae2c76260315828e505380a3e32910549";import{q as e,l as o,v as t,e5 as s,A as a,e6 as i,e7 as l,e8 as n,E as r,c}from"./houseplan-card-QCQsWhm9.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="09fae293e9dee5623085ca73035bb09914a27ad744cffaa70dab64fb29b96787";import{q as e,l as o,v as t,e5 as s,A as a,e6 as i,e7 as l,e8 as n,E as r,c}from"./houseplan-card-B0Q_XTHX.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
.hass=${this.hass}
.data=${this._formData}
.schema=${e}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="ead0f4146471ab778119d7575ca6c0fae2c76260315828e505380a3e32910549";import{l as t,b4 as s,A as e,v as a,c as o,cn as l,co as i,cp as h,cq as c,b1 as n,cr as r,cw as p,cs as d,ct as _,cu as u,cv as g,cx as m,cy as b,dt as $,du as v,dv as f,b0 as y,b2 as w,dw as D}from"./houseplan-card-QCQsWhm9.js";import{c as k,e as S,r as C,a as M}from"./backdrop-pick-CHXO6wCC.js";const F=1e3,x=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},T="ead0f4146471ab778119d7575ca6c0fae2c76260315828e505380a3e32910549";class L{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(l){const i=`${l}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,l)&&s(h,i)?o`<hp-help data-help-key=${l}
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="09fae293e9dee5623085ca73035bb09914a27ad744cffaa70dab64fb29b96787";import{l as t,b4 as s,A as e,v as a,c as o,cn as l,co as i,cp as h,cq as c,b1 as n,cr as r,cw as p,cs as d,ct as _,cu as u,cv as g,cx as m,cy as b,dt as $,du as v,dv as f,b0 as y,b2 as w,dw as D}from"./houseplan-card-B0Q_XTHX.js";import{c as k,e as S,r as C,a as M}from"./backdrop-pick-CeEIa4lG.js";const F=1e3,x=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},T="09fae293e9dee5623085ca73035bb09914a27ad744cffaa70dab64fb29b96787";class L{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(l){const i=`${l}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,l)&&s(h,i)?o`<hp-help data-help-key=${l}
.text=${a(h,l)} .ariaLabel=${a(h,i)}></hp-help>`:e}_openSpaceDialog(t,s){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===t){const e=this.host._serverCfg.spaces.find(t=>t.id===s);if(!e)return;const a=l(e),o=e.settings?.custom_fill&&"object"==typeof e.settings.custom_fill?i(e.settings.custom_fill):null,p="none"===a.fill?{...o||h,a:0}:o;return void(this.host._spaceDialog={mode:t,spaceId:s,title:e.title,planUrl:e.plan_url||null,planFile:null,source:e.plan_url?"file":"draw",showBorders:a.showBorders,showNames:a.showNames,zeroWallStyle:r(e),displayTouched:!0,hideDecor:a.hideDecor,hideOpenings:a.hideOpenings,roomColor:a.color,roomOpacity:a.opacity,fillMode:"none"===a.fill?"custom":a.fill,customFill:p,glowEnabled:a.glow,bgColor:a.bgColor,bgMode:"static"===e.settings?.bg_mode||"daynight"===e.settings?.bg_mode?e.settings.bg_mode:null,northDeg:n({},e.settings),sunRays:"boolean"==typeof e.settings?.sun_rays?e.settings.sun_rays:null,tempMin:a.tempMin,tempMax:a.tempMax,showLqi:a.showLqi??this.host._config?.show_signal??!0,cardFontScale:a.cardFontScale,labelTemp:a.labelTemp,labelHum:a.labelHum,labelLqi:a.labelLqi,labelLight:a.labelLight,cellCm:Number(e.cell_cm)>0?Number(e.cell_cm):5,cellCmInput:c(Number(e.cell_cm)>0?Number(e.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const e=p(this.host._imperial);this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...m(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:g,roomOpacity:u,fillMode:"custom",customFill:{...h,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:_,tempMax:d,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:e,cellCmInput:c(e,this.host._imperial),cellCmTouched:!1,busy:!1}}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;s.value="";const a=await k(e);if("reject"===a.kind)return void this.host._showToast(this.host._t("toast.plan_formats"));if("guard"===a.kind)return void(this.host._backdropGuard=a.state);const o=await S(e,a.ext,e.name);this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:o})}_renderBackdropGuard(){return C(this.host,t=>{this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:t})},()=>{this.host._backdropGuard=null},this.host.hass)??e}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),a=this.host._spaceDialog;return a&&a.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...a,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){const s=this.host._spaceDialog,e=s?.saved?.find(s=>s.name===t);if(!s||!e||e.used_by.length||e.url===s.planUrl)return;const a=await this.host._confirmDanger({key:"delete-plan",kind:"destructive",title:this.host._t("confirm.delete_plan_title"),message:this.host._t("confirm.delete_plan_body"),objectName:t,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),o=this.host._spaceDialog,l=o?.saved?.find(s=>s.name===t);if(a&&o&&l&&l.url===e.url&&l.modified===e.modified&&!l.used_by.length&&l.url!==o.planUrl)try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return o`<div class="savedplans muted">${this.host._t("space.loading")}</div>`;const s=t.saved||[];if(!s.length)return o`<div class="savedplans muted">${this.host._t("space.no_saved")}</div>`;return o`<div class="savedplans">
${s.map(s=>{return o`
<div class="savedplan ${s.url===t.planUrl?"cur":""}">
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="ead0f4146471ab778119d7575ca6c0fae2c76260315828e505380a3e32910549";import{c as a,A as e}from"./houseplan-card-QCQsWhm9.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-Ci-uYIPy.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show">
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="09fae293e9dee5623085ca73035bb09914a27ad744cffaa70dab64fb29b96787";import{c as a,A as e}from"./houseplan-card-B0Q_XTHX.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-BLYtOezP.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show">
<span class="summary-switch-caption"><strong>${b("summary.show_local")}</strong>
<small id="summary-local-show-hint">${b("summary.show_local_hint")}</small></span>
<input id="summary-local-show" data-summary-local-show type="checkbox"
@@ -1 +0,0 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="ead0f4146471ab778119d7575ca6c0fae2c76260315828e505380a3e32910549";import{eb as e,P as t,a5 as n,M as i,aq as r,N as o,bs as s,br as a,a4 as c,a3 as l,aA as u,ec as d,ed as f,bu as m,ee as g}from"./houseplan-card-QCQsWhm9.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=u(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const r=String(i.binding||"").indexOf(":");if(r<1)continue;const o=i.binding.slice(0,r),s=i.binding.slice(r+1),a="device"===o?e.registry.devices?.[s]:null,c="entity"===o?e.registry.entities?.[s]:null,l="device"===o?s:c?.device_id,u="device"===o?a?.area_id:c?.area_id||l&&e.registry.devices?.[l]?.area_id,d="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||u||"",f=d&&e.areaToSpace[d]||i.space||e.firstSpaceId;l&&e.registry.devices?.[l]&&e.spaceIds.has(f)&&(!n.devices.has(l)||"entity"===o&&n.liveEntities.has(s))&&t.add(l)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=c(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,r,o);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:l(e.rooms,t.walls,t.openCuts,i,t.cellCm,r,o)}}function*h(c,l,u=_){try{let d=0;for(const f of l){const l=c.spaces.find(e=>String(e?.id)===f.id);if(!l)continue;const m=e(l,f),g=u(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const a=t(e);if(!a)continue;const c=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,r,o,g.roomGeom,g.multiWallNodes)||a;v=y(v,s(c,m.physicalBodies)),yield}const _=m.cellCm/r;d+=a(v)*_*_/1e4}return d}catch{return null}}function p(e,t,n=_){const i=h(e,t,n);let r=i.next();for(;!r.done;)r=i.next();return r.value}function b(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=d(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{h as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,b as summarySystemValue,p as totalCleanFloorAreaM2};
@@ -0,0 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="09fae293e9dee5623085ca73035bb09914a27ad744cffaa70dab64fb29b96787";import{eb as e,P as t,a5 as n,M as i,aq as r,N as o,bs as a,br as s,a4 as l,a3 as c,aA as u,ec as d,ed as f,bu as m,ee as g}from"./houseplan-card-B0Q_XTHX.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=u(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const r=String(i.binding||"").indexOf(":");if(r<1)continue;const o=i.binding.slice(0,r),a=i.binding.slice(r+1),s="device"===o?e.registry.devices?.[a]:null,l="entity"===o?e.registry.entities?.[a]:null,c="device"===o?a:l?.device_id,u="device"===o?s?.area_id:l?.area_id||c&&e.registry.devices?.[c]?.area_id,d="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||u||"",f=d&&e.areaToSpace[d]||i.space||e.firstSpaceId;c&&e.registry.devices?.[c]&&e.spaceIds.has(f)&&(!n.devices.has(c)||"entity"===o&&n.liveEntities.has(a))&&t.add(c)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=l(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,r,o);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:c(e.rooms,t.walls,t.openCuts,i,t.cellCm,r,o)}}function*b(l,c,u=_){try{let d=0;for(const f of c){const c=l.spaces.find(e=>String(e?.id)===f.id);if(!c)continue;const m=e(c,f),g=u(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const s=t(e);if(!s)continue;const l=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,r,o,g.roomGeom,g.multiWallNodes)||s;v=y(v,a(l,m.physicalBodies)),yield}const _=m.cellCm/r;d+=s(v)*_*_/1e4}return d}catch{return null}}function h(e,t,n=_){const i=b(e,t,n);let r=i.next();for(;!r.done;)r=i.next();return r.value}function p(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=d(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{b as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,p as summarySystemValue,h as totalCleanFloorAreaM2};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="ead0f4146471ab778119d7575ca6c0fae2c76260315828e505380a3e32910549";import{n as t,b as n}from"./zigbee-topology-df97gjoC.js";import{F as e}from"./houseplan-card-QCQsWhm9.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function p(t){if(!0!==t?.user?.is_admin)throw a("permission")}function f(n){const e=i(n);return e?c(e,"zha",async()=>{if(p(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function m(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function g(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(p(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,f=null,g=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{f=t,g=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const p=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&f?.(n):c&&g?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof p&&b.push(p),await m(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await m(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{f as readZhaTopology,g as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="09fae293e9dee5623085ca73035bb09914a27ad744cffaa70dab64fb29b96787";import{n as t,b as n}from"./zigbee-topology-D_LrAqE3.js";import{F as e}from"./houseplan-card-B0Q_XTHX.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function f(t){if(!0!==t?.user?.is_admin)throw a("permission")}function p(n){const e=i(n);return e?c(e,"zha",async()=>{if(f(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function m(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function g(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(f(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,p=null,g=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{p=t,g=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const f=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&p?.(n):c&&g?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof f&&b.push(f),await m(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await m(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{p as readZhaTopology,g as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
+1 -1
View File
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="ead0f4146471ab778119d7575ca6c0fae2c76260315828e505380a3e32910549";try{await import("./houseplan-assets/houseplan-card-QCQsWhm9.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)}
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="09fae293e9dee5623085ca73035bb09914a27ad744cffaa70dab64fb29b96787";try{await import("./houseplan-assets/houseplan-card-B0Q_XTHX.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)}
+1 -1
View File
File diff suppressed because one or more lines are too long
+65
View File
@@ -48,6 +48,71 @@ export const captureEnvironment = (source = process) => ({
arch: String(source.arch || ''),
});
/** Версия схемы отчёта съёмки, в которой провенанс обязателен (#571). */
export const CAPTURE_PROVENANCE_SCHEMA = 2;
/**
* Провенанс СЪЁМКИ для отчёта (#571).
*
* До этой задачи отчёт платформу не нёс вовсе, и приёмщик записывал в индекс
* эталонов СВОЮ платформу как платформу кадров. На `ad4000f9` это дало
* `"platform": "win32"` у кадров, снятых Linux-прогоном 34853080375: индекс
* утверждал неправду, а причина осознанного обхода осталась только в stdout.
*
* Поэтому провенанс собирается там, где кадры снимаются, и уезжает в отчёт:
* платформа, архитектура, сборка Chromium, отпечаток материала и — если съёмка
* шла в CI — прогон с попыткой. Последнее не косметика: артефакт можно скачать
* и принять спустя сутки, и ссылка на прогон единственная, что связывает
* картинки с их происхождением.
*/
export const captureProvenance = ({
chromium = null, buildFingerprint = null, source = process, env = process.env,
} = {}) => {
const { platform, arch } = captureEnvironment(source);
const run = String(env?.GITHUB_RUN_ID ?? '').trim();
const attempt = String(env?.GITHUB_RUN_ATTEMPT ?? '').trim();
const repository = String(env?.GITHUB_REPOSITORY ?? '').trim();
const sha = String(env?.GITHUB_SHA ?? '').trim();
return {
platform,
arch,
chromium: chromium || null,
buildFingerprint: buildFingerprint || null,
// Пустой объект вместо `null` был бы ложью «CI известен, полей нет».
ci: run ? {
repository: repository || null,
run: Number(run) || null,
attempt: Number(attempt) || 1,
sha: sha || null,
} : null,
};
};
/**
* Провенанс отчёта в пригодном для решения виде: `{ provenance, legacy }`.
*
* `legacy: true` — отчёт старой схемы, платформы съёмки в нём нет физически.
* Такой отчёт не отвергается (артефакты живут дольше схемы), но и не выдаёт
* себя за проверенный: платформа съёмки остаётся `null`, и вызывающий обязан
* решить это явной веткой, а не молча подставить свою.
*/
export const reportCaptureProvenance = (report = {}) => {
const schema = Number(report?.schema) || 1;
const provenance = report?.capture;
if (schema >= CAPTURE_PROVENANCE_SCHEMA) {
// Fail-closed: схема обещает провенанс, значит его отсутствие — поломка
// инструмента съёмки, а не повод угадывать.
if (!provenance || typeof provenance !== 'object') {
throw new Error(`отчёт схемы ${schema} обязан нести раздел capture с провенансом съёмки (#571)`);
}
if (!provenance.platform) {
throw new Error(`отчёт схемы ${schema} не называет платформу съёмки (#571)`);
}
return { provenance, legacy: false };
}
return { provenance: null, legacy: true };
};
/**
* Разрешён ли осознанный обход. Возвращает причину или `null`.
* Пустая строка — не причина: обход без записанной причины неотличим от
+23
View File
@@ -9965,6 +9965,29 @@ const MUTANT_DEFINITIONS = [
replace: " if (settings?.fill_mode === 'never-a-fill-mode') return spaceFill;",
}],
},
{
id: 'golden-index-invents-capture-platform',
guard: 'node --test --test-name-pattern="#571" test/golden-capture-provenance.test.mjs',
because: '#571: платформу кадров знает только тот, кто их снял. Пока приёмщик писал в индекс '
+ 'свою, артефакт Linux-прогона 34853080375, принятый на Windows, оставил в `ad4000f9` '
+ 'запись «сняты на win32» — индекс утверждал неправду, и заметить это было нечем',
patches: [{
file: 'demo/golden/accept.mjs',
find: ' capturedOn: capturedOn,',
replace: ' capturedOn: acceptance.platform, // mutant: снова платформа приёмщика',
}],
},
{
id: 'golden-report-provenance-optional',
guard: 'node --test --test-name-pattern="#571 схема 2" test/golden-capture-provenance.test.mjs',
because: '#571: схема 2 обещает провенанс съёмки. Если его отсутствие перестаёт быть отказом, '
+ 'сломанный инструмент съёмки тихо вернёт индекс к догадкам вместо факта',
patches: [{
file: 'scripts/capture-environment.mjs',
find: " throw new Error(`отчёт схемы ${schema} обязан нести раздел capture с провенансом съёмки (#571)`);",
replace: " return { provenance: null, legacy: true }; // mutant: молча считаем отчёт старым",
}],
},
{
id: 'furniture-symbol-may-keep-inner-padding',
guard: 'node --test --test-name-pattern="AC1" test/furniture-visual-bounds.test.mjs',
+16 -6
View File
@@ -89,9 +89,14 @@ test('#455 гейт стоит во всех точках, где кадры п
// построению, поэтому «понизить отказ до печати» без правки этой строки
// нельзя. Первая редакция проверки смотрела лишь на импорт модуля — и
// молча проходила, когда отказ заменили на `void foreign`.
// #571 заменил бросающую обёртку на явную пару проверок: судить надо ДВЕ
// среды — съёмки (из отчёта) и приёмки (своя), а обёртка знала только свою.
// Форма остановки прежняя: `throw`, а не печать.
assert.match(source('demo/golden/accept.mjs'),
/assertCaptureEnvironment\(\{ kind: 'golden', stage: 'accept' \}\)/,
'приёмка golden обязана проверять среду бросающей обёрткой');
/for \(const \[platform, stageNote\] of \[[\s\S]*?\]\) \{[\s\S]*?if \(refusal\) throw new Error\(/,
'приёмка golden обязана отказывать по обеим средам, а не печатать');
assert.match(source('demo/golden/accept.mjs'), /reportCaptureProvenance\(report\)/,
'среда съёмки обязана читаться из отчёта, а не из process.platform приёмщика');
assert.match(source('scripts/docs-accept.mjs'),
/assertCaptureEnvironment\(\{ kind: 'docs', stage: 'accept' \}\)/,
'приёмка документации обязана проверять среду');
@@ -105,10 +110,15 @@ test('#455 гейт стоит во всех точках, где кадры п
assert.match(packageJson.scripts['docs:capture'] || '',
/assert-capture-env\.mjs docs/,
'у съёмки документации обязан быть npm-скрипт с проверкой среды');
// `run.mjs` трогать нельзя: он в корпусе sourceFingerprint, и его правка
// объявила бы устаревшими бандл, скриншоты документации и индекс эталонов.
assert.doesNotMatch(source('demo/golden/run.mjs'), /capture-environment\.mjs/,
'гейт обязан стоять в policy.mjs, а не в фингерпринтуемом run.mjs');
// До #571 `run.mjs` не трогали принципиально: он в корпусе sourceFingerprint,
// и правка объявляет устаревшими бандл и индекс скриншотов. Ради ГЕЙТА эта
// цена не окупалась — он прекрасно живёт в policy.mjs. Ради ПРОВЕНАНСА
// окупилась: платформу кадров знает только тот, кто их снял, и записать её
// больше негде. Цена заплачена один раз, осознанно (#571).
assert.doesNotMatch(source('demo/golden/run.mjs'), /assertGoldenInvocation\([^)]*platform/,
'гейт среды остаётся в policy.mjs: в run.mjs только сбор провенанса');
assert.match(source('demo/golden/run.mjs'), /capture: captureProvenance\(\{ chromium, buildFingerprint \}\)/,
'отчёт съёмки обязан нести провенанс среды (#571)');
});
test('#455 бросающая обёртка бросает и возвращает разрешённую причину', () => {
+152
View File
@@ -0,0 +1,152 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { execFileSync } from 'node:child_process';
import { copyFileSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
import { createHash } from 'node:crypto';
import { tmpdir } from 'node:os';
import { resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import {
CAPTURE_PROVENANCE_SCHEMA, captureProvenance, reportCaptureProvenance,
} from '../scripts/capture-environment.mjs';
import { GOLDEN_INDEX_SCHEMA, indexCapturedOn } from '../demo/golden/policy.mjs';
import { GOLDEN_MATRIX_VERSION, GOLDEN_SCENARIOS } from '../demo/golden/matrix.mjs';
import { sourceFingerprint } from '../scripts/source-fingerprint.mjs';
// #571. Отчёт съёмки не нёс платформу, и приёмщик записывал в индекс СВОЮ:
// артефакт Linux-прогона 34853080375, принятый на Windows, дал на `ad4000f9`
// запись `"platform": "win32"` у кадров, которых Windows не снимала. Причина
// осознанного обхода при этом жила только в stdout.
//
// Проверки гоняют НАСТОЯЩИЙ `accept.mjs` в отдельном каталоге эталонов: писать
// в рабочий репозиторий тест не имеет права, а подменять модуль — значит
// проверять не то, что исполняется на приёмке.
const ROOT = resolve(fileURLToPath(new URL('../', import.meta.url)));
const BASELINES = resolve(ROOT, 'demo/golden/baselines');
/** Артефакт съёмки: кадры равны принятым эталонам, отчёт — с нужным провенансом. */
function fixture({ platform = 'linux', schema = CAPTURE_PROVENANCE_SCHEMA, capture = undefined } = {}) {
const dir = mkdtempSync(resolve(tmpdir(), 'hp-golden-571-'));
mkdirSync(resolve(dir, 'actual'), { recursive: true });
const index = JSON.parse(readFileSync(resolve(BASELINES, 'baselines-index.json'), 'utf8'));
const results = GOLDEN_SCENARIOS.map((scenario) => {
const source = resolve(BASELINES, `${scenario.id}.png`);
const actual = resolve(dir, 'actual', `${scenario.id}.png`);
copyFileSync(source, actual);
const sha = createHash('sha256').update(readFileSync(actual)).digest('hex');
return { id: scenario.id, status: 'passed', actualSha256: sha, baselineSha256: sha, diffRatio: 0 };
});
const report = {
schema,
mode: 'verify',
generatedAt: new Date().toISOString(),
matrixVersion: GOLDEN_MATRIX_VERSION,
buildFingerprint: sourceFingerprint(ROOT),
chromium: index.chromium,
results,
};
if (schema >= CAPTURE_PROVENANCE_SCHEMA) {
report.capture = capture === undefined
? { ...captureProvenance({ chromium: index.chromium, buildFingerprint: report.buildFingerprint, env: {} }), platform }
: capture;
}
writeFileSync(resolve(dir, 'golden-report.json'), `${JSON.stringify(report, null, 2)}\n`);
return dir;
}
/** Приёмка в изолированный каталог эталонов: рабочий репозиторий не трогаем. */
function accept(from, { reason = '', expectFailure = false } = {}) {
const sandbox = mkdtempSync(resolve(tmpdir(), 'hp-golden-571-baselines-'));
execFileSync('cp', ['-r', BASELINES + '/.', sandbox]);
const env = { ...process.env };
if (reason) env.HP_ALLOW_FOREIGN_CAPTURE = reason; else delete env.HP_ALLOW_FOREIGN_CAPTURE;
try {
const stdout = execFileSync(process.execPath,
[resolve(ROOT, 'demo/golden/accept.mjs'), '--reviewed', `--from=${from}`, `--baselines=${sandbox}`],
{ cwd: ROOT, env, encoding: 'utf8' });
if (expectFailure) throw new Error('приёмка обязана была отказать, а прошла');
return { stdout, index: JSON.parse(readFileSync(resolve(sandbox, 'baselines-index.json'), 'utf8')), sandbox };
} catch (error) {
if (!expectFailure) throw error;
return {
error: String(error.stderr || error.message),
index: JSON.parse(readFileSync(resolve(sandbox, 'baselines-index.json'), 'utf8')),
sandbox,
};
}
}
test('#571 AC1: артефакт Linux принимается, обе стороны провенанса записаны', () => {
const from = fixture({ platform: 'linux' });
const { index } = accept(from);
assert.equal(index.schema, GOLDEN_INDEX_SCHEMA);
assert.equal(index.capturedOn, 'linux', 'платформа КАДРОВ — из отчёта');
assert.equal(index.acceptedOn, process.platform, 'платформа приёмки — своя');
assert.equal(indexCapturedOn(index), 'linux');
assert.equal(index.capture.chromium, index.chromium);
assert.equal(index.foreignCapture, null, 'канон обхода не требует');
rmSync(from, { recursive: true, force: true });
});
test('#571 AC2: чужая среда съёмки без причины — отказ до записи', () => {
const from = fixture({ platform: 'win32' });
const before = readFileSync(resolve(BASELINES, 'baselines-index.json'), 'utf8');
const { error, index } = accept(from, { expectFailure: true });
assert.match(error, /приёмка отказана/);
assert.match(error, /win32/);
assert.equal(index.capturedOn ?? null, JSON.parse(before).capturedOn ?? null,
'индекс обязан остаться нетронутым: отказ до записи');
rmSync(from, { recursive: true, force: true });
});
test('#571 AC1: чужая среда съёмки с причиной — причина уезжает в индекс', () => {
const from = fixture({ platform: 'win32' });
const reason = 'аудит #571: проверяю ветку осознанного обхода';
const { index, stdout } = accept(from, { reason });
assert.equal(index.capturedOn, 'win32');
assert.equal(index.acceptedOn, process.platform);
assert.deepEqual(index.foreignCapture, { reason });
assert.match(stdout, /Чужая среда разрешена осознанно/);
rmSync(from, { recursive: true, force: true });
});
test('#571 схема 2 fail-closed: раздел capture обязателен', () => {
assert.throws(() => reportCaptureProvenance({ schema: 2 }), /обязан нести раздел capture/);
assert.throws(() => reportCaptureProvenance({ schema: 2, capture: { arch: 'x64' } }), /не называет платформу/);
const from = fixture({ capture: { arch: 'x64', chromium: '1' } });
const { error } = accept(from, { expectFailure: true });
assert.match(error, /не называет платформу съёмки/);
rmSync(from, { recursive: true, force: true });
});
test('#571 старая схема — отдельная явная ветка, а не подстановка своей платформы', () => {
assert.deepEqual(reportCaptureProvenance({ schema: 1 }), { provenance: null, legacy: true });
const from = fixture({ schema: 1 });
const { index, stdout } = accept(from);
assert.equal(index.capturedOn, null, 'выдумывать платформу кадров нельзя');
assert.equal(index.acceptedOn, process.platform);
assert.match(stdout, /Отчёт старой схемы/);
rmSync(from, { recursive: true, force: true });
});
test('#571 индекс любой схемы читается одним правилом', () => {
assert.equal(indexCapturedOn({ schema: 1, platform: 'linux' }), 'linux', 'схема 1: platform — это кадры');
assert.equal(indexCapturedOn({ schema: 2, capturedOn: 'linux', acceptedOn: 'win32' }), 'linux');
assert.equal(indexCapturedOn({ schema: 2, acceptedOn: 'win32' }), null, 'схема 2 без capturedOn ничего не обещает');
assert.equal(indexCapturedOn(null), null);
});
test('#571 подмена PNG и неполный артефакт по-прежнему fail-closed', () => {
const tampered = fixture();
const victim = resolve(tampered, 'actual', `${GOLDEN_SCENARIOS[0].id}.png`);
writeFileSync(victim, Buffer.concat([readFileSync(victim), Buffer.from([0])]));
assert.match(accept(tampered, { expectFailure: true }).error, /candidate changed after capture/);
rmSync(tampered, { recursive: true, force: true });
const incomplete = fixture();
rmSync(resolve(incomplete, 'actual', `${GOLDEN_SCENARIOS[1].id}.png`));
assert.match(accept(incomplete, { expectFailure: true }).error, /review candidate missing/);
rmSync(incomplete, { recursive: true, force: true });
});