@camstack/addon-admin-ui 1.2.150 → 1.2.152
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{AddLocationWizard-Cygq281h.js → AddLocationWizard-CRSMsK9p.js} +1 -1
- package/dist/assets/{AddonCollectionPage-DzYy61Rn.js → AddonCollectionPage-Cvpydgls.js} +1 -1
- package/dist/assets/Addons-BfHTJdu9.js +1 -0
- package/dist/assets/{AdminTabs-C6Txjg4K.js → AdminTabs-C8fYCzUp.js} +1 -1
- package/dist/assets/AiProfiles-DP4XbxUn.js +3 -0
- package/dist/assets/{BrokerForm-CsDjlHsn.js → BrokerForm-CSIOM0Q9.js} +1 -1
- package/dist/assets/{Build-CQJnyRvg.js → Build-LV-4tjzd.js} +4 -4
- package/dist/assets/{Capabilities-Blgw3qT5.js → Capabilities-DPDAS0F9.js} +1 -1
- package/dist/assets/{CapabilityBadges-B-Zdhd_g.js → CapabilityBadges-Ne3fsTPo.js} +1 -1
- package/dist/assets/Cluster-_oYtW6DA.js +11 -0
- package/dist/assets/{Data-iwAR2n2x.js → Data-BtisI6aU.js} +1 -1
- package/dist/assets/DetectionIntelligence-CkddQvcD.js +1 -0
- package/dist/assets/{DeviceAggregateSection-C0TlHGhr.js → DeviceAggregateSection-DQQ3we6r.js} +1 -1
- package/dist/assets/DeviceDetail-W0aLcU9f.js +2 -0
- package/dist/assets/{Devices-CpUPoeSV.js → Devices-DuqE2S99.js} +1 -1
- package/dist/assets/EmbedPlayerPage-Vetle0eq.js +1 -0
- package/dist/assets/Events-BrMgdc2c.js +1 -0
- package/dist/assets/{FormBuilder-CTAWt-d7.js → FormBuilder-DZAD7rsy.js} +1 -1
- package/dist/assets/Identity-ByY0AcqN.js +1 -0
- package/dist/assets/IntegrationDetail-CZCnR1qq.js +1 -0
- package/dist/assets/{Integrations-kmN1gZpw.js → Integrations-CH7r6Rna.js} +1 -1
- package/dist/assets/Integrations-DdTsI5Ro.js +1 -0
- package/dist/assets/{Locations-YluUYbPN.js → Locations-BTfQ9DXU.js} +1 -1
- package/dist/assets/{Logs-CgmgrJDp.js → Logs-C3LihNTL.js} +1 -1
- package/dist/assets/{MotionZonesSettings-U9GLdP13.js → MotionZonesSettings-cYzPB2HU.js} +1 -1
- package/dist/assets/{MyAccess-B5lQZvEA.js → MyAccess-8609SF9m.js} +1 -1
- package/dist/assets/Network-f6kHY_5t.js +1 -0
- package/dist/assets/{NodeAddonsSettingsPanel-C1qpOXdE.js → NodeAddonsSettingsPanel-CxcrZcXQ.js} +1 -1
- package/dist/assets/{NodeInferenceDevices-CyRmZRNQ.js → NodeInferenceDevices-CQHXi0JA.js} +1 -1
- package/dist/assets/{Notifications-CAnCouUA.js → Notifications-BI6I75Ep.js} +1 -1
- package/dist/assets/Pipeline-BZcuPoPD.js +1 -0
- package/dist/assets/Plates-DENjhZyd.js +1 -0
- package/dist/assets/{PrivacyMaskSettings-CWfERTWr.js → PrivacyMaskSettings-BEgxFW6t.js} +1 -1
- package/dist/assets/{ProviderIcon-sJ2yQ7k5.js → ProviderIcon-XR91l--m.js} +1 -1
- package/dist/assets/Recordings-Cv1htCoz.js +1 -0
- package/dist/assets/{ScanNetworkModal-C6VMJXCP.js → ScanNetworkModal-D5saxFAm.js} +1 -1
- package/dist/assets/{SceneMonitorEditor-B7tgtd0X.js → SceneMonitorEditor-L4YkkW7x.js} +1 -1
- package/dist/assets/{Scenes-DAdgWq5F.js → Scenes-Be-FJRmb.js} +1 -1
- package/dist/assets/{Settings-CfThFogU.js → Settings-Cmw6FXk4.js} +1 -1
- package/dist/assets/{Showroom-ByPAETrz.js → Showroom-B2qPnvyR.js} +1 -1
- package/dist/assets/{StorageLocationsPanel-HmQIB_Vb.js → StorageLocationsPanel-MknZ7IHh.js} +1 -1
- package/dist/assets/{Terminal-DuCZUxxn.js → Terminal-CsMWo1fT.js} +3 -3
- package/dist/assets/{_virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-CuD0Cawh.js → _virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-DInKaMJ1.js} +1 -1
- package/dist/assets/{bell-off-Bk5AAH07.js → bell-off-CmttlQXo.js} +1 -1
- package/dist/assets/{bell-ring-C1kUJndA.js → bell-ring-DOJ_zaJV.js} +1 -1
- package/dist/assets/{boxes-pBOk19g7.js → boxes-BojwLWqP.js} +1 -1
- package/dist/assets/circle-check-big-CYqYb18l.js +1 -0
- package/dist/assets/circle-dot-DrKitvFX.js +1 -0
- package/dist/assets/circle-slash-B-geGlOr.js +1 -0
- package/dist/assets/{circle-x-CAhZI9-Z.js → circle-x-wZc8rg_f.js} +1 -1
- package/dist/assets/clock-DYGPpHoA.js +1 -0
- package/dist/assets/{copy-CBN-3t7U.js → copy-3HXArcO0.js} +1 -1
- package/dist/assets/{debounced-invalidate-D3QWowRZ.js → debounced-invalidate-6vIgVJmX.js} +1 -1
- package/dist/assets/dist-CbUtPKh7.js +349 -0
- package/dist/assets/{dist-DAR8MsD0.js → dist-CjmKzQHq.js} +1 -1
- package/dist/assets/{download-BO2bWpuB.js → download-DXqx7-8w.js} +1 -1
- package/dist/assets/{face-bbox-BJyMDEB2.js → face-bbox-DFou7csi.js} +1 -1
- package/dist/assets/{flame-CbasE8zE.js → flame-eamTVW8N.js} +1 -1
- package/dist/assets/{hard-drive-BZoL5PO_.js → hard-drive-7Y2Mg0GE.js} +1 -1
- package/dist/assets/{hard-drive-download-Dy3MSxTR.js → hard-drive-download-BP4ESn9-.js} +1 -1
- package/dist/assets/{hostInit-D9dV-3dF.js → hostInit-BVouzqij.js} +1 -1
- package/dist/assets/index-BnFm_Imc.js +4 -0
- package/dist/assets/{key-round-Dq5tsceV.js → key-round-DufzqLg-.js} +1 -1
- package/dist/assets/{layers-CA52-zkw.js → layers-Byjsc3yg.js} +1 -1
- package/dist/assets/{mf-entry-bootstrap-0-dafa8f15.js → mf-entry-bootstrap-0-7a2fbc17.js} +2 -2
- package/dist/assets/{pencil-B3W7yf67.js → pencil-ChcKS9qp.js} +1 -1
- package/dist/assets/play-DBZIwx8l.js +1 -0
- package/dist/assets/{player-overlays-CZoMxbfX.js → player-overlays-CkGjHNDd.js} +1 -1
- package/dist/assets/plus-BsofUp-H.js +1 -0
- package/dist/assets/power-DcQdan7Q.js +1 -0
- package/dist/assets/{radio-mrrSsTIU.js → radio-CiQlJZot.js} +1 -1
- package/dist/assets/{refresh-cw-BzYEnhKV.js → refresh-cw-3OpAwqdC.js} +1 -1
- package/dist/assets/remoteEntry-Dt9hV0IH.js +1 -0
- package/dist/assets/rotate-ccw-3CkYaWob.js +1 -0
- package/dist/assets/rotate-cw-C_E5zarw.js +1 -0
- package/dist/assets/{send-BALBLr9E.js → send-3XacUFua.js} +1 -1
- package/dist/assets/{server-D4gG6ibk.js → server-DgTF3xCo.js} +1 -1
- package/dist/assets/{shield-fn3DscNj.js → shield-S-fgWPwd.js} +1 -1
- package/dist/assets/{shield-alert-3IVfz-zv.js → shield-alert-TESCMM1U.js} +1 -1
- package/dist/assets/square-BaJ4GXIK.js +1 -0
- package/dist/assets/{square-check-big-h44-BB01.js → square-check-big-bLYnUb2_.js} +1 -1
- package/dist/assets/src-DBCz_Wul.js +67 -0
- package/dist/assets/src-snbHLEEO.js +349 -0
- package/dist/assets/{undo-2-CCRS1A6P.js → undo-2-CGA8VTns.js} +1 -1
- package/dist/assets/{use-scenes-feed-D1R0HooM.js → use-scenes-feed-DslCcTRx.js} +1 -1
- package/dist/assets/useEventInvalidation-83aCjx1L.js +1 -0
- package/dist/assets/{useNodeUrlSelection-B_AUHOMQ.js → useNodeUrlSelection-DKpFEH0I.js} +1 -1
- package/dist/assets/user-round-B8d-cExM.js +1 -0
- package/dist/assets/{video-C4ev2Wfq.js → video-Du_T1Juf.js} +1 -1
- package/dist/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-Cee58BQv.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-CD6cm9GI.js} +2 -2
- package/dist/assets/{wifi-D0POhWlD.js → wifi-DFeftdlE.js} +1 -1
- package/dist/assets/{zap-Uymmrarp.js → zap-qfpb65Ko.js} +1 -1
- package/dist/index.html +5 -5
- package/dist/server/addon.js +349 -2
- package/package.json +1 -1
- package/dist/assets/Addons-CafwvZRt.js +0 -1
- package/dist/assets/AiProfiles-u3weKAzd.js +0 -3
- package/dist/assets/Cluster-BvDBA4z3.js +0 -11
- package/dist/assets/DetectionIntelligence-rq9e-djO.js +0 -1
- package/dist/assets/DeviceDetail-CRC0ZJte.js +0 -2
- package/dist/assets/EmbedPlayerPage-yZezZbVt.js +0 -1
- package/dist/assets/Events-kj2pMyST.js +0 -1
- package/dist/assets/Identity-BQWsI2gX.js +0 -1
- package/dist/assets/IntegrationDetail-UsEEY1i_.js +0 -1
- package/dist/assets/Integrations-tiLbVf0u.js +0 -1
- package/dist/assets/Network-CrQFpUU3.js +0 -1
- package/dist/assets/Pipeline-B2MjX_0o.js +0 -1
- package/dist/assets/Plates-CzkRRxQI.js +0 -1
- package/dist/assets/Recordings-ICHkgSMH.js +0 -1
- package/dist/assets/circle-check-big-C_Y6Vlxm.js +0 -1
- package/dist/assets/circle-dot-9xHGX09F.js +0 -1
- package/dist/assets/circle-slash-Dm33z33z.js +0 -1
- package/dist/assets/clock-B2c2NvPX.js +0 -1
- package/dist/assets/dist-CejD4EtJ.js +0 -349
- package/dist/assets/index-Ni_XmFA2.js +0 -4
- package/dist/assets/play-Bh6S9yKU.js +0 -1
- package/dist/assets/plus-B6XLLrt6.js +0 -1
- package/dist/assets/power-BJT7ky5f.js +0 -1
- package/dist/assets/remoteEntry-aArvVD5f.js +0 -1
- package/dist/assets/rotate-ccw-DoSIpKLh.js +0 -1
- package/dist/assets/rotate-cw-B3VMz5IH.js +0 -1
- package/dist/assets/square-DnnUsoaE.js +0 -1
- package/dist/assets/src-DAFoNsA_.js +0 -67
- package/dist/assets/src-TPXNmZuu.js +0 -349
- package/dist/assets/useEventInvalidation-DhyGa1qR.js +0 -1
- package/dist/assets/user-round-B7KGgAcJ.js +0 -1
package/dist/server/addon.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
//#region ../types/dist/event-category-
|
|
3
|
+
//#region ../types/dist/event-category-zAv7pMUz.mjs
|
|
4
4
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
5
5
|
EventCategory["SystemBoot"] = "system.boot";
|
|
6
6
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -372,6 +372,13 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
372
372
|
*/
|
|
373
373
|
EventCategory["BatteryOnStatusChanged"] = "battery.onStatusChanged";
|
|
374
374
|
/**
|
|
375
|
+
* Cap event fired by every device that registers the `network-link`
|
|
376
|
+
* capability. Mirrors the cap definition's `onStatusChanged`. Carries
|
|
377
|
+
* `{ deviceId, status: NetworkLinkStatus }` — a link switch or a signal
|
|
378
|
+
* reading that moved.
|
|
379
|
+
*/
|
|
380
|
+
EventCategory["NetworkLinkOnStatusChanged"] = "network-link.onStatusChanged";
|
|
381
|
+
/**
|
|
375
382
|
* Emitted by the battery cap provider WHEN `wakeForStream` enters the
|
|
376
383
|
* "wake in progress" window — between the Baichuan wake-up issue and
|
|
377
384
|
* the camera's first dialed-back RTP packet. The stream-broker
|
|
@@ -23184,6 +23191,39 @@ DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, meth
|
|
|
23184
23191
|
deviceId: number(),
|
|
23185
23192
|
status: BatteryStatusSchema
|
|
23186
23193
|
});
|
|
23194
|
+
/**
|
|
23195
|
+
* Network-link snapshot. Same shape for every provider (a Reolink wifi
|
|
23196
|
+
* camera, a Home Assistant device with a signal-strength sensor, a Tapo
|
|
23197
|
+
* plug): one slice under `device.runtimeState['network-link']`, one badge,
|
|
23198
|
+
* one Home Assistant projection.
|
|
23199
|
+
*/
|
|
23200
|
+
var NetworkLinkStatusSchema = object({
|
|
23201
|
+
/** The link the device is on. `'unknown'` = not read yet, not "no link". */
|
|
23202
|
+
type: _enum([
|
|
23203
|
+
"wifi",
|
|
23204
|
+
"ethernet",
|
|
23205
|
+
"cellular",
|
|
23206
|
+
"unknown"
|
|
23207
|
+
]),
|
|
23208
|
+
/**
|
|
23209
|
+
* Link quality, 0..100 inclusive, normalised by the provider from whatever
|
|
23210
|
+
* the firmware reports (bars, RSSI, a vendor scale). **`null` means NOT
|
|
23211
|
+
* KNOWN or NOT APPLICABLE** — a wired link has no signal, and a wireless
|
|
23212
|
+
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
23213
|
+
* SKIP a null rather than coerce it.
|
|
23214
|
+
*/
|
|
23215
|
+
signalPercent: number().min(0).max(100).nullable(),
|
|
23216
|
+
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
23217
|
+
rssiDbm: number().optional(),
|
|
23218
|
+
/** Network name of a wireless link, when the firmware reports it. */
|
|
23219
|
+
ssid: string().optional(),
|
|
23220
|
+
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
23221
|
+
lastUpdated: number()
|
|
23222
|
+
});
|
|
23223
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.Light, DeviceType.Lock, DeviceType.Siren, object({
|
|
23224
|
+
deviceId: number(),
|
|
23225
|
+
status: NetworkLinkStatusSchema
|
|
23226
|
+
});
|
|
23187
23227
|
object({
|
|
23188
23228
|
on: boolean(),
|
|
23189
23229
|
/** Ms epoch of the last transition. 0 if never observed. */
|
|
@@ -26778,6 +26818,203 @@ DeviceType.Camera, method(object({ deviceId: number() }), PtzAutotrackStatusSche
|
|
|
26778
26818
|
deviceId: number(),
|
|
26779
26819
|
status: PtzAutotrackStatusSchema
|
|
26780
26820
|
});
|
|
26821
|
+
/**
|
|
26822
|
+
* `navigation` — a device-scoped capability that natively expresses the FULL
|
|
26823
|
+
* navigation / action surface of a robot that DRIVES ITSELF and carries an
|
|
26824
|
+
* on-board camera (the Dreame robot-vacuum camera is the first provider).
|
|
26825
|
+
*
|
|
26826
|
+
* Why a NEW cap rather than overloading `ptz`:
|
|
26827
|
+
* - `ptz` moves a *gimbal* on a fixed camera (pan/tilt/zoom of the lens). A
|
|
26828
|
+
* robot vacuum has no gimbal — the whole chassis drives, turns and spins.
|
|
26829
|
+
* The two are different physical models: PTZ is absolute-position + presets,
|
|
26830
|
+
* navigation is momentary drive nudges + discrete robot ACTIONS
|
|
26831
|
+
* (dock / spot-clean / follow-pet / go-to-point / …).
|
|
26832
|
+
* - This cap is the SOURCE OF TRUTH. Two consumers adapt from it rather than
|
|
26833
|
+
* the reverse:
|
|
26834
|
+
* 1. a native CamStack navigation panel (data-driven from `listActions`
|
|
26835
|
+
* / `getOptions`), and
|
|
26836
|
+
* 2. the PTZ surface — a thin adapter mimics `ptz` from `navigation` so a
|
|
26837
|
+
* robot camera shows up in the existing PTZ control path without every
|
|
26838
|
+
* PTZ provider learning about robots. The mapping lives in the adapter,
|
|
26839
|
+
* not here (see the addon design note):
|
|
26840
|
+
* ptz.continuousMove({pan,tilt}) → navigation.move({pan,tilt})
|
|
26841
|
+
* ptz.stop() → navigation.stop()
|
|
26842
|
+
* ptz.goHome() → navigation.runAction('goHome')
|
|
26843
|
+
* ptz.getPresets() → navigation.listActions() (id→preset)
|
|
26844
|
+
* ptz.goToPreset(id) → navigation.runAction(id)
|
|
26845
|
+
*
|
|
26846
|
+
* ## Continuous drive
|
|
26847
|
+
*
|
|
26848
|
+
* `move` is MOMENTARY. Fluid navigation comes from the UI (or the PTZ adapter)
|
|
26849
|
+
* sending `move({pan,tilt})` REPEATEDLY at ~1 Hz while a direction is held, and
|
|
26850
|
+
* one `stop()` on release — exactly like the robot app's remote-drive joystick.
|
|
26851
|
+
* The provider forwards EACH `move` to one drive write; it must NOT debounce or
|
|
26852
|
+
* coalesce them. The UI owns the cadence.
|
|
26853
|
+
*
|
|
26854
|
+
* ## The action dictionary
|
|
26855
|
+
*
|
|
26856
|
+
* The discrete controls (dock / locate / spot-clean / follow / flash / sounds)
|
|
26857
|
+
* are a DATA-DRIVEN dictionary the cap exposes via `listActions()`. Each entry
|
|
26858
|
+
* carries `{ id, kind, label, icon }` (plus `soundId` for sound entries) so the
|
|
26859
|
+
* native panel AND the PTZ mimic render buttons WITHOUT hardcoding a
|
|
26860
|
+
* vendor-specific list. `kind: 'action'` entries are triggered with
|
|
26861
|
+
* `runAction({ actionId })`; `kind: 'sound'` entries with `playSound({ soundId })`
|
|
26862
|
+
* (the entry carries the `soundId` to pass). The general primitives — `move`,
|
|
26863
|
+
* `stop`, `goToPoint` — stay as first-class methods, not dictionary entries.
|
|
26864
|
+
*
|
|
26865
|
+
* NOTE (provider wiring): the first provider (Dreame) drives this with the RAW
|
|
26866
|
+
* `callAction(siid,aiid,in)` / `setProperty({siid,piid,value})` MIoT primitives
|
|
26867
|
+
* that the currently-published `@apocaliss92/nodedreame` already exposes on
|
|
26868
|
+
* every device handle. A future nodedreame publish adds a typed
|
|
26869
|
+
* `DreameCameraController` (drive / playPetSound / spotClean / findPet / …); the
|
|
26870
|
+
* provider can then swap the raw calls for the typed methods with no change to
|
|
26871
|
+
* THIS contract.
|
|
26872
|
+
*/
|
|
26873
|
+
/**
|
|
26874
|
+
* A momentary drive nudge. The robot MOVES (no gimbal) for as long as the caller
|
|
26875
|
+
* keeps sending nudges (~1 Hz); an explicit `stop` (or letting the nudges lapse)
|
|
26876
|
+
* halts it.
|
|
26877
|
+
*
|
|
26878
|
+
* - `pan` — turn: negative = left, positive = right, 0 = straight.
|
|
26879
|
+
* - `tilt` — throttle: positive = forward, negative = spin / turn-around.
|
|
26880
|
+
* - `speed` — optional intensity hint [0, 1]; the provider may scale the drive
|
|
26881
|
+
* vector by it (drivers without proportional drive ignore it).
|
|
26882
|
+
*
|
|
26883
|
+
* `pan` / `tilt` are normalized [-1, 1]. Both optional so a caller can nudge one
|
|
26884
|
+
* axis alone; an all-undefined nudge is a no-op.
|
|
26885
|
+
*/
|
|
26886
|
+
var NavigationMoveCommandSchema = object({
|
|
26887
|
+
pan: number().min(-1).max(1).optional(),
|
|
26888
|
+
tilt: number().min(-1).max(1).optional(),
|
|
26889
|
+
speed: number().min(0).max(1).optional()
|
|
26890
|
+
});
|
|
26891
|
+
/**
|
|
26892
|
+
* The enumerated discrete actions a navigation-capable robot can perform via
|
|
26893
|
+
* `runAction`. This is the CLOSED vocabulary; a given device advertises the
|
|
26894
|
+
* subset it supports through `listActions`. Sounds are NOT here — they go through
|
|
26895
|
+
* `playSound` (see the `sound` dictionary entries).
|
|
26896
|
+
*/
|
|
26897
|
+
var NavigationActionIdSchema = _enum([
|
|
26898
|
+
"goHome",
|
|
26899
|
+
"locate",
|
|
26900
|
+
"spotClean",
|
|
26901
|
+
"findPet",
|
|
26902
|
+
"personFollow",
|
|
26903
|
+
"stop",
|
|
26904
|
+
"startClean",
|
|
26905
|
+
"pauseClean",
|
|
26906
|
+
"dockWash",
|
|
26907
|
+
"autoEmpty",
|
|
26908
|
+
"flashOn",
|
|
26909
|
+
"flashOff"
|
|
26910
|
+
]);
|
|
26911
|
+
/** Whether a dictionary entry is a `runAction` action or a `playSound` sound. */
|
|
26912
|
+
var NavigationEntryKindSchema = _enum(["action", "sound"]);
|
|
26913
|
+
/**
|
|
26914
|
+
* One entry in the navigation action dictionary — the DATA-DRIVEN unit both the
|
|
26915
|
+
* native panel and the PTZ mimic render as a button.
|
|
26916
|
+
*
|
|
26917
|
+
* - `id` — stable id. For `kind:'action'` it is a {@link NavigationActionId}
|
|
26918
|
+
* (pass to `runAction`); for `kind:'sound'` it is a namespaced id
|
|
26919
|
+
* (`sound:meow`) whose `soundId` is passed to `playSound`.
|
|
26920
|
+
* - `icon` — icon HINT (lucide-style name; the UI maps it to its own set).
|
|
26921
|
+
* - `label` — operator-facing English label.
|
|
26922
|
+
* - `soundId` — wire sound id, present only on `kind:'sound'` entries.
|
|
26923
|
+
* - `enabled` — per-device FEATURE FLAG. `listActions` reports it so the UI /
|
|
26924
|
+
* PTZ render ONLY enabled entries. Data-driven: the provider
|
|
26925
|
+
* flips it from config, never by editing code.
|
|
26926
|
+
*/
|
|
26927
|
+
var NavigationActionEntrySchema = object({
|
|
26928
|
+
id: string(),
|
|
26929
|
+
kind: NavigationEntryKindSchema,
|
|
26930
|
+
label: string(),
|
|
26931
|
+
icon: string(),
|
|
26932
|
+
/** Present only on `kind:'sound'` entries — the id to pass to `playSound`. */
|
|
26933
|
+
soundId: number().int().optional(),
|
|
26934
|
+
/** Per-device feature flag — render this entry only when true. */
|
|
26935
|
+
enabled: boolean()
|
|
26936
|
+
});
|
|
26937
|
+
/** Coordinates for `goToPoint` — a point on the robot's live map. */
|
|
26938
|
+
var NavigationPointSchema = object({
|
|
26939
|
+
x: number(),
|
|
26940
|
+
y: number()
|
|
26941
|
+
});
|
|
26942
|
+
/**
|
|
26943
|
+
* Per-device FEATURE-FLAG report for the general (non-dictionary) primitives.
|
|
26944
|
+
* The cap reports which are enabled so the UI / PTZ render only the controls
|
|
26945
|
+
* that are turned on for THIS device. Data-driven: the provider derives these
|
|
26946
|
+
* from config + probe, never hardcoded in the UI. The per-DICTIONARY-entry flags
|
|
26947
|
+
* live on {@link NavigationActionEntrySchema.enabled}; these gate the primitives
|
|
26948
|
+
* that are not dictionary entries.
|
|
26949
|
+
*
|
|
26950
|
+
* - `move` / `stop` — the momentary drive joystick.
|
|
26951
|
+
* - `goToPoint` — send-to-map-coordinate. Ships OFF on Dreame until the
|
|
26952
|
+
* map-coordinate plumbing is wired.
|
|
26953
|
+
* - `runAction` — the discrete action buttons (dictionary `kind:'action'`).
|
|
26954
|
+
* - `playSound` — the sound buttons (dictionary `kind:'sound'`).
|
|
26955
|
+
* - `light` — the on/off fill-light toggle (works anytime).
|
|
26956
|
+
* - `lightMode` — the auto/manual selector + manual level slider (a
|
|
26957
|
+
* camera-service control; needs an active stream).
|
|
26958
|
+
*/
|
|
26959
|
+
var NavigationFeaturesSchema = object({
|
|
26960
|
+
move: boolean(),
|
|
26961
|
+
stop: boolean(),
|
|
26962
|
+
goToPoint: boolean(),
|
|
26963
|
+
runAction: boolean(),
|
|
26964
|
+
playSound: boolean(),
|
|
26965
|
+
light: boolean(),
|
|
26966
|
+
lightMode: boolean()
|
|
26967
|
+
});
|
|
26968
|
+
/** Light mode: `auto` lets the camera choose brightness; `manual` uses `level`. */
|
|
26969
|
+
var NavigationLightModeSchema = _enum(["auto", "manual"]);
|
|
26970
|
+
/**
|
|
26971
|
+
* Live navigation state so the UI can reflect what the robot is doing:
|
|
26972
|
+
* - `mode` — coarse activity (idle / cleaning / following / …).
|
|
26973
|
+
* - `following` — person/pet follow is currently armed.
|
|
26974
|
+
* - `flash` — the on-camera fill light is on.
|
|
26975
|
+
* - `lightMode` — auto vs manual fill-light mode.
|
|
26976
|
+
* - `lightLevel` — manual fill-light level (40..100); meaningful when
|
|
26977
|
+
* `lightMode === 'manual'`.
|
|
26978
|
+
*/
|
|
26979
|
+
var NavigationStatusSchema = object({
|
|
26980
|
+
mode: _enum([
|
|
26981
|
+
"idle",
|
|
26982
|
+
"cleaning",
|
|
26983
|
+
"spot",
|
|
26984
|
+
"following",
|
|
26985
|
+
"goto",
|
|
26986
|
+
"returning",
|
|
26987
|
+
"paused",
|
|
26988
|
+
"unknown"
|
|
26989
|
+
]),
|
|
26990
|
+
following: boolean(),
|
|
26991
|
+
flash: boolean(),
|
|
26992
|
+
lightMode: NavigationLightModeSchema,
|
|
26993
|
+
lightLevel: number().min(40).max(100),
|
|
26994
|
+
/** Ms epoch when the slice was last updated. */
|
|
26995
|
+
lastChangedAt: number()
|
|
26996
|
+
});
|
|
26997
|
+
NavigationStatusSchema.extend({ lastFetchedAt: number() });
|
|
26998
|
+
DeviceType.Camera, method(NavigationMoveCommandSchema.extend({ deviceId: number() }), _void(), { kind: "mutation" }), method(object({ deviceId: number() }), _void(), { kind: "mutation" }), method(NavigationPointSchema.extend({ deviceId: number() }), _void(), { kind: "mutation" }), method(object({ deviceId: number() }), array(NavigationActionEntrySchema)), method(object({
|
|
26999
|
+
deviceId: number(),
|
|
27000
|
+
actionId: NavigationActionIdSchema
|
|
27001
|
+
}), _void(), { kind: "mutation" }), method(object({
|
|
27002
|
+
deviceId: number(),
|
|
27003
|
+
soundId: number().int()
|
|
27004
|
+
}), _void(), { kind: "mutation" }), method(object({
|
|
27005
|
+
deviceId: number(),
|
|
27006
|
+
on: boolean()
|
|
27007
|
+
}), _void(), { kind: "mutation" }), method(object({
|
|
27008
|
+
deviceId: number(),
|
|
27009
|
+
mode: NavigationLightModeSchema,
|
|
27010
|
+
level: number().min(40).max(100).optional()
|
|
27011
|
+
}), _void(), { kind: "mutation" }), method(object({
|
|
27012
|
+
deviceId: number(),
|
|
27013
|
+
level: number().min(40).max(100)
|
|
27014
|
+
}), _void(), { kind: "mutation" }), method(object({ deviceId: number() }), NavigationFeaturesSchema), object({
|
|
27015
|
+
deviceId: number(),
|
|
27016
|
+
status: NavigationStatusSchema
|
|
27017
|
+
});
|
|
26781
27018
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
|
|
26782
27019
|
kind: "mutation",
|
|
26783
27020
|
auth: "admin"
|
|
@@ -31842,6 +32079,66 @@ Object.freeze({
|
|
|
31842
32079
|
addonId: null,
|
|
31843
32080
|
access: "create"
|
|
31844
32081
|
},
|
|
32082
|
+
"navigation.getFeatures": {
|
|
32083
|
+
capName: "navigation",
|
|
32084
|
+
capScope: "device",
|
|
32085
|
+
addonId: null,
|
|
32086
|
+
access: "view"
|
|
32087
|
+
},
|
|
32088
|
+
"navigation.goToPoint": {
|
|
32089
|
+
capName: "navigation",
|
|
32090
|
+
capScope: "device",
|
|
32091
|
+
addonId: null,
|
|
32092
|
+
access: "create"
|
|
32093
|
+
},
|
|
32094
|
+
"navigation.listActions": {
|
|
32095
|
+
capName: "navigation",
|
|
32096
|
+
capScope: "device",
|
|
32097
|
+
addonId: null,
|
|
32098
|
+
access: "view"
|
|
32099
|
+
},
|
|
32100
|
+
"navigation.move": {
|
|
32101
|
+
capName: "navigation",
|
|
32102
|
+
capScope: "device",
|
|
32103
|
+
addonId: null,
|
|
32104
|
+
access: "create"
|
|
32105
|
+
},
|
|
32106
|
+
"navigation.playSound": {
|
|
32107
|
+
capName: "navigation",
|
|
32108
|
+
capScope: "device",
|
|
32109
|
+
addonId: null,
|
|
32110
|
+
access: "create"
|
|
32111
|
+
},
|
|
32112
|
+
"navigation.runAction": {
|
|
32113
|
+
capName: "navigation",
|
|
32114
|
+
capScope: "device",
|
|
32115
|
+
addonId: null,
|
|
32116
|
+
access: "create"
|
|
32117
|
+
},
|
|
32118
|
+
"navigation.setLightLevel": {
|
|
32119
|
+
capName: "navigation",
|
|
32120
|
+
capScope: "device",
|
|
32121
|
+
addonId: null,
|
|
32122
|
+
access: "create"
|
|
32123
|
+
},
|
|
32124
|
+
"navigation.setLightMode": {
|
|
32125
|
+
capName: "navigation",
|
|
32126
|
+
capScope: "device",
|
|
32127
|
+
addonId: null,
|
|
32128
|
+
access: "create"
|
|
32129
|
+
},
|
|
32130
|
+
"navigation.setLightOn": {
|
|
32131
|
+
capName: "navigation",
|
|
32132
|
+
capScope: "device",
|
|
32133
|
+
addonId: null,
|
|
32134
|
+
access: "create"
|
|
32135
|
+
},
|
|
32136
|
+
"navigation.stop": {
|
|
32137
|
+
capName: "navigation",
|
|
32138
|
+
capScope: "device",
|
|
32139
|
+
addonId: null,
|
|
32140
|
+
access: "create"
|
|
32141
|
+
},
|
|
31845
32142
|
"networkAccess.getEndpoint": {
|
|
31846
32143
|
capName: "network-access",
|
|
31847
32144
|
capScope: "system",
|
|
@@ -35937,6 +36234,56 @@ Object.freeze({
|
|
|
35937
36234
|
form: "single",
|
|
35938
36235
|
optional: false
|
|
35939
36236
|
}],
|
|
36237
|
+
"navigation.getFeatures": [{
|
|
36238
|
+
name: "deviceId",
|
|
36239
|
+
form: "single",
|
|
36240
|
+
optional: false
|
|
36241
|
+
}],
|
|
36242
|
+
"navigation.goToPoint": [{
|
|
36243
|
+
name: "deviceId",
|
|
36244
|
+
form: "single",
|
|
36245
|
+
optional: false
|
|
36246
|
+
}],
|
|
36247
|
+
"navigation.listActions": [{
|
|
36248
|
+
name: "deviceId",
|
|
36249
|
+
form: "single",
|
|
36250
|
+
optional: false
|
|
36251
|
+
}],
|
|
36252
|
+
"navigation.move": [{
|
|
36253
|
+
name: "deviceId",
|
|
36254
|
+
form: "single",
|
|
36255
|
+
optional: false
|
|
36256
|
+
}],
|
|
36257
|
+
"navigation.playSound": [{
|
|
36258
|
+
name: "deviceId",
|
|
36259
|
+
form: "single",
|
|
36260
|
+
optional: false
|
|
36261
|
+
}],
|
|
36262
|
+
"navigation.runAction": [{
|
|
36263
|
+
name: "deviceId",
|
|
36264
|
+
form: "single",
|
|
36265
|
+
optional: false
|
|
36266
|
+
}],
|
|
36267
|
+
"navigation.setLightLevel": [{
|
|
36268
|
+
name: "deviceId",
|
|
36269
|
+
form: "single",
|
|
36270
|
+
optional: false
|
|
36271
|
+
}],
|
|
36272
|
+
"navigation.setLightMode": [{
|
|
36273
|
+
name: "deviceId",
|
|
36274
|
+
form: "single",
|
|
36275
|
+
optional: false
|
|
36276
|
+
}],
|
|
36277
|
+
"navigation.setLightOn": [{
|
|
36278
|
+
name: "deviceId",
|
|
36279
|
+
form: "single",
|
|
36280
|
+
optional: false
|
|
36281
|
+
}],
|
|
36282
|
+
"navigation.stop": [{
|
|
36283
|
+
name: "deviceId",
|
|
36284
|
+
form: "single",
|
|
36285
|
+
optional: false
|
|
36286
|
+
}],
|
|
35940
36287
|
"networkQuality.getDeviceStats": [{
|
|
35941
36288
|
name: "deviceId",
|
|
35942
36289
|
form: "single",
|
|
@@ -37478,7 +37825,7 @@ var AdminUIAddon = class extends BaseAddon {
|
|
|
37478
37825
|
capability: adminUiCapability,
|
|
37479
37826
|
provider: {
|
|
37480
37827
|
getStaticDir: async () => ({ staticDir: resolveAdminUiDistDir() }),
|
|
37481
|
-
getVersion: async () => ({ version: "1.2.
|
|
37828
|
+
getVersion: async () => ({ version: "1.2.152" })
|
|
37482
37829
|
}
|
|
37483
37830
|
}];
|
|
37484
37831
|
}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{I as e,K as t,Q as n,R as r,S as i,W as a,b as o,o as s,q as c,x as l,z as u}from"./_virtual_mf___mfe_internal__admin_ui_host__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-DhP-Lgiq.js";import{C as d,Cn as f,Dn as p,En as m,Hn as h,In as g,J as ee,Ln as _,Mn as v,Nn as y,On as b,Pn as x,Qs as S,Rn as C,Tn as te,Un as ne,Vn as re,Ys as w,an as ie,g as T,jn as ae,kn as E,oa as D,q as oe,wn as O,xn as se,zn as ce}from"./src-DAFoNsA_.js";import{Gt as k}from"./src-TPXNmZuu.js";import{t as A}from"./clock-B2c2NvPX.js";import{t as j}from"./download-BO2bWpuB.js";import{t as le}from"./plus-B6XLLrt6.js";import{t as M}from"./refresh-cw-BzYEnhKV.js";import{B as N,F as ue,J as P,Q as F,X as de,_ as I,f as L,m as R,o as fe,p as pe,r as z,w as B,z as V}from"./index-Ni_XmFA2.js";import{t as H}from"./AdminPage-CCD07UMs.js";import{t as U}from"./NodeAddonsSettingsPanel-C1qpOXdE.js";import{r as W,t as me}from"./useNodeUrlSelection-B_AUHOMQ.js";var he=P(`chevron-up`,[[`path`,{d:`m18 15-6-6-6 6`,key:`153udz`}]]),ge=P(`octagon-alert`,[[`path`,{d:`M12 16h.01`,key:`1drbdi`}],[`path`,{d:`M12 8v4`,key:`1got3b`}],[`path`,{d:`M15.312 2a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586l-4.688-4.688A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2z`,key:`1fd625`}]]),_e=P(`package`,[[`path`,{d:`M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z`,key:`1a0edw`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}],[`polyline`,{points:`3.29 7 12 12 20.71 7`,key:`ousv84`}],[`path`,{d:`m7.5 4.27 9 5.15`,key:`1c824w`}]]),G=P(`skip-forward`,[[`polygon`,{points:`5 4 15 12 5 20 5 4`,key:`16p6eg`}],[`line`,{x1:`19`,x2:`19`,y1:`5`,y2:`19`,key:`futhcm`}]]),K=P(`upload`,[[`path`,{d:`M12 3v12`,key:`1x0j5s`}],[`path`,{d:`m17 8-5-5-5 5`,key:`7q97r8`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}]]);n();var q=new Set([`completed`,`failed`,`partially-failed`,`cancelled`]),J=new Set([`done`,`failed`,`skipped`]);function ve(e){return!J.has(e.phase)&&!q.has(e.jobState)}function Y(e,t){let n=new Map,r=[...e].sort((e,t)=>e.createdAtMs-t.createdAtMs);for(let e of r){let r=q.has(e.state);for(let i of e.tasks)r&&i.finishedAtMs!==null&&t-i.finishedAtMs>6e4||n.set(i.packageName,{jobId:e.jobId,packageName:i.packageName,phase:i.phase,fromVersion:i.fromVersion,toVersion:i.toVersion,error:i.error,jobState:e.state,finishedAtMs:i.finishedAtMs})}return n}function X(){let{data:e}=ae({activeOnly:!0},{refetchOnWindowFocus:!1,refetchInterval:e=>(e.state.data?.length??0)>0?3e3:!1}),{map:t}=S(k.AddonsJobProgress,e=>e.job.jobId);return a(()=>{let n=new Map;for(let t of e??[])n.set(t.jobId,t);for(let[e,r]of t)n.set(e,r.job);return Y([...n.values()],Date.now())},[e,t])}var Z={queued:{icon:A,cls:`bg-muted text-foreground-subtle`,label:`queued`},fetching:{icon:B,cls:`bg-primary/10 text-primary`,label:`fetching`,spin:!0},staged:{icon:B,cls:`bg-primary/10 text-primary`,label:`staged`,spin:!0},validating:{icon:B,cls:`bg-primary/10 text-primary`,label:`validating`,spin:!0},applying:{icon:B,cls:`bg-primary/10 text-primary`,label:`applying`,spin:!0},restarting:{icon:B,cls:`bg-amber-500/10 text-amber-600 dark:text-amber-400`,label:`restarting`,spin:!0},applied:{icon:B,cls:`bg-primary/10 text-primary`,label:`finalizing`,spin:!0},done:{icon:N,cls:`bg-success/10 text-success`,label:`updated`},failed:{icon:ge,cls:`bg-danger/10 text-danger`,label:`failed`},skipped:{icon:G,cls:`bg-muted text-foreground-subtle`,label:`skipped`}};function ye({progress:e}){let t=Z[e.phase],n=t.icon,r=e.error??`${e.packageName}: ${e.fromVersion??`?`} → ${e.toVersion}`;return i(`span`,{"data-testid":`addon-job-progress`,className:`inline-flex items-center gap-1 px-1.5 py-0.5 text-[10px] rounded shrink-0 ${t.cls}`,title:r,children:[l(n,{className:`w-2.5 h-2.5 ${t.spin?`animate-spin`:``}`}),t.label,i(`span`,{className:`font-mono`,children:[`→ `,e.toVersion]})]})}function be({packageName:e,currentVersion:t,installSource:n,onInstall:r,onClose:a,onSelect:s,selectedVersion:c}){let u=n===`upload`||n===`local`,{data:d,isLoading:f}=p({name:e});return i(`div`,{className:`fixed z-50 w-72 rounded-lg border border-border bg-surface shadow-xl overflow-hidden`,style:{top:`auto`,bottom:`auto`},ref:e=>{if(!e)return;let t=e.parentElement?.getBoundingClientRect();if(!t)return;let n=window.innerHeight-t.bottom,r=t.top;n<280&&r>n?(e.style.bottom=`${window.innerHeight-t.top+4}px`,e.style.top=`auto`):(e.style.top=`${t.bottom+4}px`,e.style.bottom=`auto`),e.style.right=`${window.innerWidth-t.right}px`},onClick:e=>e.stopPropagation(),children:[i(`div`,{className:`flex items-center justify-between px-3 py-2 border-b border-border`,children:[l(`span`,{className:`text-[10px] uppercase tracking-wide text-foreground-subtle font-medium`,children:`Versions`}),l(`button`,{type:`button`,onClick:a,className:`text-foreground-subtle hover:text-foreground`,children:l(z,{className:`h-3 w-3`})})]}),u&&i(`div`,{className:`flex items-start gap-2 px-3 py-2 border-b border-border bg-cyan-500/10 text-[10px]`,children:[l(K,{className:`h-3 w-3 mt-0.5 text-cyan-500 shrink-0`}),i(`div`,{className:`text-cyan-700 dark:text-cyan-200`,children:[i(`span`,{className:`font-semibold`,children:[n===`upload`?`Uploaded copy`:`Local copy`,` in place.`]}),` `,`Re-install `,l(`span`,{className:`font-mono`,children:t}),` from npm to track upstream releases again.`]})]}),f&&i(`div`,{className:`flex items-center justify-center gap-2 py-6 text-[10px] text-foreground-subtle`,children:[l(B,{className:`h-3.5 w-3.5 animate-spin`}),`Loading versions...`]}),d&&l(`div`,{className:`max-h-64 overflow-auto divide-y divide-border`,children:d.map(e=>{let n=e.version===t,a=s!==void 0&&e.version===c,d=/-(alpha|beta|rc|dev|canary|next)/i.test(e.version),f=i(o,{children:[l(`span`,{className:`font-mono flex-1 text-left ${n?`text-primary font-semibold`:d?`text-amber-400`:`text-foreground`}`,children:e.version}),n&&l(`span`,{className:`text-[9px] rounded-full px-1.5 py-0.5 font-medium bg-primary/10 text-primary`,children:`current`}),e.distTags.map(e=>l(`span`,{className:`text-[9px] rounded-full px-1.5 py-0.5 font-medium ${e===`latest`?`bg-emerald-500/15 text-emerald-400`:e===`beta`?`bg-amber-500/15 text-amber-400`:`bg-gray-500/15 text-gray-400`}`,children:e},e)),e.deprecated&&l(`span`,{className:`text-[9px] text-red-400 line-through`,children:`deprecated`}),l(`span`,{className:`text-[9px] text-foreground-subtle shrink-0`,children:new Date(e.publishedAt).toLocaleDateString()})]});return s?i(`button`,{type:`button`,"aria-label":`Select ${e.version}`,onClick:()=>s(e.version),className:`w-full flex items-center gap-2 px-3 py-2 text-[11px] ${a?`bg-primary/5`:`hover:bg-surface-hover`} transition-colors`,children:[f,a?l(N,{className:`h-3 w-3 text-primary shrink-0`}):l(`span`,{className:`w-3 shrink-0`})]},e.version):i(`div`,{className:`flex items-center gap-2 px-3 py-2 text-[11px] ${n?`bg-primary/5`:`hover:bg-surface-hover`} transition-colors`,children:[f,n&&!u?l(N,{className:`h-3 w-3 text-primary shrink-0`}):l(`button`,{type:`button`,onClick:()=>r(e.version),className:`shrink-0 rounded p-0.5 hover:bg-primary/20 text-foreground-subtle hover:text-primary transition-colors`,title:n?`Re-install ${e.version} from npm`:`Install ${e.version}`,children:l(j,{className:`h-3 w-3`})})]},e.version)})}),d&&d.length===0&&l(`div`,{className:`py-4 text-center text-[10px] text-foreground-subtle`,children:`No versions found`})]})}var xe={queued:{icon:A,bg:`bg-muted text-foreground-subtle`,label:`queued`},updating:{icon:B,bg:`bg-primary/10 text-primary`,label:`updating`,spin:!0},"done-pending-restart":{icon:M,bg:`bg-amber-500/10 text-amber-700`,label:`pending restart`},done:{icon:N,bg:`bg-success/10 text-success`,label:`done`},failed:{icon:ge,bg:`bg-danger/10 text-danger`,label:`failed`}};function Se({item:e}){let t=xe[e.status],n=t.icon;return i(`span`,{className:`inline-flex items-center gap-1 px-1.5 py-0.5 text-[10px] rounded ${t.bg}`,title:e.error,children:[l(n,{className:`w-2.5 h-2.5 ${t.spin?`animate-spin`:``}`}),t.label]})}n();var Q=`device-export`;function Ce(e){return e.capabilities.some(e=>(typeof e==`string`?e:e.name)===Q)}function we({isBundle:e,installSource:t,addonId:n,iconPath:r,color:a}){let[o,s]=c(!1),u=a?{backgroundColor:`${a.startsWith(`#`)?a:`#${a}`}26`}:void 0,d=e?`bg-indigo-500/20 text-indigo-700 dark:text-indigo-300`:`bg-purple-500/20 text-purple-700 dark:text-purple-300`,f=n&&r?`/api/addon-assets/${n}/${r}`:null,p=!!f&&!o;return i(`div`,{className:`relative flex-shrink-0`,children:[l(`div`,{className:`h-9 w-9 rounded-lg flex items-center justify-center ${u?``:d}`,style:u,children:p?l(`img`,{src:f,alt:n,className:`h-5 w-5`,onError:()=>s(!0)}):l(e?_e:I,{className:`h-4 w-4`})}),t===`local`&&l(`span`,{className:`absolute -top-1.5 -left-1.5 text-[7px] font-bold leading-none bg-orange-500 text-white px-1 py-0.5 rounded -rotate-12 shadow-sm`,children:`DEV`}),t===`npm`&&l(`span`,{className:`absolute -top-1 -left-1 w-4 h-4 rounded bg-[#cb3837] flex items-center justify-center -rotate-12 shadow-sm`,children:l(`svg`,{viewBox:`0 0 780 250`,className:`w-[11px] h-[11px]`,children:l(`path`,{fill:`#fff`,d:`M240 250h100V50h100v200h340V0H0v250z`})})}),t===`upload`&&l(`span`,{className:`absolute -top-1.5 -left-1.5 flex items-center justify-center h-4 w-4 rounded bg-cyan-500 -rotate-12 shadow-sm`,children:l(K,{className:`h-2.5 w-2.5 text-white`})})]})}function Te({version:e,availableUpdate:t,selectedVersion:n,isUpdating:r,installSource:a,disabled:o,onUpdate:s,onOpenPicker:c,children:u}){if(r)return i(`span`,{className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium border border-blue-500/30 bg-blue-500/10 text-blue-400 shrink-0`,children:[l(B,{className:`h-3 w-3 animate-spin`}),`Updating…`]});if(t){let r=n??t;return i(`div`,{className:`relative inline-flex items-center gap-1 shrink-0`,children:[s&&i(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),s()},disabled:o,className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-semibold border border-blue-500/30 bg-blue-500/10 text-blue-400 hover:bg-blue-500/20 disabled:opacity-50 disabled:cursor-not-allowed transition-colors`,title:`Update to ${r}`,children:[l(j,{className:`h-3 w-3`}),`Update`]}),i(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),c()},disabled:o,"aria-label":`Select version to install`,title:`Installed ${e} — update available. Selected ${r}; tap to choose another version.`,className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-bold font-mono border border-amber-500/40 bg-amber-500/15 text-amber-500 hover:bg-amber-500/25 animate-pulse disabled:opacity-50 disabled:cursor-not-allowed transition-colors`,children:[l(`span`,{className:`font-normal opacity-70`,children:e}),l(`span`,{className:`font-normal opacity-70`,children:`→`}),r,l(V,{className:`h-3 w-3`})]}),u]})}return i(`div`,{className:`relative inline-flex items-center gap-1 shrink-0`,children:[i(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),c()},disabled:o,className:[`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-bold font-mono border transition-colors disabled:opacity-50 disabled:cursor-not-allowed`,a===`local`?`border-orange-500/30 bg-orange-500/10 text-orange-400 hover:bg-orange-500/20`:`border-emerald-500/30 bg-emerald-500/10 text-emerald-400 hover:bg-emerald-500/20`].join(` `),title:`Version ${e} — tap to view all versions`,children:[e,l(V,{className:`h-3 w-3 opacity-50`})]}),u]})}function Ee({addonId:e}){let t=s(),{data:n=`inherit`}=O({addonId:e}),r=C({onSuccess:()=>{t.invalidateQueries({queryKey:[[`addons`,`getAddonAutoUpdate`]]})}});return l(`div`,{className:`flex rounded-lg border border-border overflow-hidden text-[10px] font-medium`,children:[`inherit`,`off`,`latest`,`beta`].map(t=>l(`button`,{type:`button`,onClick:n=>{n.stopPropagation(),r.mutate({addonId:e,channel:t})},disabled:r.isPending,className:`px-2.5 py-1 transition-colors capitalize ${n===t?t===`inherit`?`bg-gray-700/50 text-gray-700 dark:text-gray-300`:t===`off`?`bg-gray-700 text-gray-700 dark:text-gray-300`:t===`latest`?`bg-blue-500/20 text-blue-400`:`bg-amber-500/20 text-amber-400`:`bg-transparent text-foreground-subtle hover:bg-surface-hover`} ${t===`inherit`?``:`border-l border-border`}`,children:t},t))})}function De({addon:e,agents:t=[],clusterStatus:n,hideVersion:r,availableUpdate:a,onUpdate:f,isUpdating:p,jobProgress:m,bundle:_,bulkItem:v,disabledByBulk:y,isSystem:S}){let[C,te]=c(!1),[ne,re]=c(!1),[w,T]=c(!1),[ae,E]=c(null);u(()=>{E(null)},[a]);let D=ae??a,[O,se]=c(!1),[ce,k]=c(!1),[A,j]=c(`logs`),N=s(),ue=de(),P=ie(),{manifest:F}=e,I=e.installedOn??[],pe=!_&&!F.protected&&F.removable!==!1,B=!!_,H=_?.displayName??F.name,W=_?.packageName??F.packageName,me=_?.version??F.packageVersion??F.version,G=_?.installSource??e.installSource,K=_?_.bundle?.description??_.addons[0]?.manifest.description:F.description,q=h({onSuccess:()=>{N.invalidateQueries({queryKey:[[`addons`]]}),N.invalidateQueries({queryKey:[[`addonPages`]]}),N.invalidateQueries({queryKey:[[`capabilities`]]})}}),J=x({onSuccess:()=>{N.invalidateQueries({queryKey:[[`addons`]]})}}),ve=b({onSuccess:()=>{N.invalidateQueries({queryKey:[[`addons`]]}),N.invalidateQueries({queryKey:[[`addonPages`]]}),N.invalidateQueries({queryKey:[[`capabilities`]]}),N.invalidateQueries({queryKey:[[`integrations`]]})}}),Y=g({onSuccess:()=>{N.invalidateQueries({queryKey:[[`addons`]]}),N.invalidateQueries({queryKey:[[`alerts`]]})}}),X=e.health,Z=X?.phase===`failed`&&!X.inGracePeriod,xe=Z&&X?.nextRetryAt&&!X.retrying;return i(`div`,{className:`rounded-lg border bg-surface overflow-hidden ${Z?`border-red-500/50`:`border-border`}`,children:[Z&&X&&i(`div`,{className:`bg-danger/10 border-b border-danger/30 px-4 py-2.5 flex items-start gap-2.5`,children:[l(ge,{className:`h-4 w-4 text-danger shrink-0 mt-0.5`}),i(`div`,{className:`flex-1 min-w-0`,children:[i(`div`,{className:`text-xs font-semibold text-danger`,children:[`Failed to load (attempt #`,X.retryCount,`)`]}),l(`div`,{className:`text-[11px] text-foreground mt-0.5 break-words font-mono`,children:X.lastError?.message??`Unknown error`}),xe&&X.nextRetryAt&&i(`div`,{className:`text-[10px] text-foreground-subtle mt-1`,children:[`Auto-retry at `,new Date(X.nextRetryAt).toLocaleTimeString()]})]}),i(`button`,{type:`button`,disabled:Y.isPending||X.retrying,onClick:e=>{e.stopPropagation(),Y.mutate({packageName:W})},className:`inline-flex items-center gap-1.5 rounded-md px-2.5 py-1 text-[11px] font-semibold border border-red-400/40 bg-red-400/10 text-red-700 dark:text-red-300 hover:bg-red-400/20 disabled:opacity-50 disabled:cursor-not-allowed transition-colors shrink-0`,title:`Reset retry counter and force immediate reload`,children:[l(M,{className:`h-3 w-3 ${Y.isPending||X.retrying?`animate-spin`:``}`}),`Retry now`]})]}),i(`div`,{className:`flex items-start gap-3 px-4 py-3`,children:[l(we,{isBundle:B||!!F.components&&F.components.length>1,installSource:G,addonId:B?_.addons[0]?.manifest.id:F.id,iconPath:B?_.bundle?.icon??_.addons[0]?.manifest.icon:F.icon,color:B?_.addons[0]?.manifest.color:F.color}),i(`div`,{className:`flex-1 min-w-0`,children:[i(`div`,{className:`flex items-start justify-between gap-2`,children:[l(`span`,{className:`text-sm font-semibold text-foreground truncate min-w-0`,children:H}),!r&&l(Te,{version:me,availableUpdate:a,...D===void 0?{}:{selectedVersion:D},isUpdating:p,installSource:G,disabled:y,...f&&D!==void 0?{onUpdate:()=>f(D)}:{},onOpenPicker:()=>T(e=>!e),children:w&&l(be,{packageName:W,currentVersion:me,...G?{installSource:G}:{},...a!==void 0&&D!==void 0?{selectedVersion:D,onSelect:e=>{E(e),T(!1)}}:{},onInstall:e=>{T(!1),ve.mutate({packageName:W,version:e})},onClose:()=>T(!1)})})]}),i(`div`,{className:`flex flex-wrap items-center gap-x-1.5 gap-y-1 mt-0.5`,children:[W!==H&&l(`span`,{className:`text-[10px] text-foreground-subtle font-mono truncate max-w-full`,children:W}),B&&i(`span`,{className:`text-[10px] rounded-full bg-primary/10 text-primary px-2 py-0.5 font-medium shrink-0 inline-flex items-center gap-1`,children:[l(_e,{className:`h-3 w-3`}),_.addons.length]}),S&&i(`span`,{className:`text-[10px] rounded-full bg-amber-500/15 text-amber-700 dark:text-amber-300 px-2 py-0.5 font-medium shrink-0 inline-flex items-center gap-1`,title:`System package — updating restarts the hub`,children:[l(M,{className:`h-3 w-3`}),`System`]}),v!=null&&l(Se,{item:v}),m!=null&&l(ye,{progress:m})]}),K&&l(`p`,{className:`text-[10px] text-foreground-subtle mt-1 line-clamp-1`,children:K}),!B&&e.process&&i(`div`,{className:`flex flex-wrap items-center gap-1.5 mt-1`,children:[l(`span`,{className:`text-[9px] rounded-full px-1.5 py-0.5 font-medium ${e.process.mode===`forked`?`bg-blue-500/15 text-blue-400`:`bg-gray-500/15 text-gray-400`}`,children:e.process.mode===`forked`?`forked`:`in-process`}),e.process.pid!=null&&i(`span`,{className:`text-[9px] font-mono text-foreground-subtle`,children:[`PID `,e.process.pid]}),l(`span`,{className:`text-[9px] rounded-full px-1.5 py-0.5 font-medium ${e.process.state===`running`?`bg-emerald-500/15 text-emerald-400`:e.process.state===`crashed`||e.process.state===`failed`?`bg-red-500/15 text-red-400`:`bg-gray-500/15 text-gray-400`}`,children:e.process.state})]})]})]}),!B&&i(`div`,{className:`flex items-center gap-1 px-4 py-1.5 border-t border-border/50 bg-surface-hover/20`,children:[i(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),J.mutate({addonId:F.id})},disabled:J.isPending||y,className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium border border-border text-foreground-subtle hover:text-blue-400 hover:border-blue-500/30 hover:bg-blue-500/10 disabled:opacity-50 transition-colors`,children:[l(M,{className:`h-3 w-3 ${J.isPending?`animate-spin`:``}`}),`Restart`]}),i(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),se(e=>!e)},className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium border transition-colors ${O?`border-primary/30 bg-primary/10 text-primary`:`border-border text-foreground-subtle hover:text-foreground hover:border-primary/30 hover:bg-primary/10`}`,children:[l(R,{className:`h-3 w-3`}),`Logs`]}),!B&&i(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),k(!0)},className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium border transition-colors ${ce?`border-primary/30 bg-primary/10 text-primary`:`border-border text-foreground-subtle hover:text-foreground hover:border-primary/30 hover:bg-primary/10`}`,children:[l(L,{className:`h-3 w-3`}),`Settings`]}),l(`div`,{className:`flex-1`}),pe&&i(`button`,{type:`button`,onClick:async e=>{e.stopPropagation(),await P({title:`Uninstall ${F.name}?`,message:`This will remove the addon package and all its data. This action cannot be undone.`,confirmLabel:`Uninstall`,variant:`danger`})&&q.mutate({packageName:F.packageName})},disabled:q.isPending||y,className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium border border-border text-foreground-subtle hover:text-red-400 hover:border-red-500/30 hover:bg-red-500/10 disabled:opacity-50 transition-colors`,children:[l(fe,{className:`h-3 w-3`}),q.isPending?`Removing...`:`Uninstall`]})]}),n&&n.nodes.length>1&&!B&&i(`div`,{className:`border-t border-border px-4 py-2 bg-muted/10`,children:[l(`div`,{className:`text-[10px] font-medium text-foreground-subtle mb-1.5`,children:`Cluster Deployment`}),l(`div`,{className:`space-y-1`,children:n.nodes.map(e=>i(`div`,{className:`flex items-center gap-2 text-[10px]`,children:[l(`div`,{className:`h-1.5 w-1.5 rounded-full shrink-0 ${e.status===`offline`?`bg-muted-foreground/30`:e.synced?`bg-success`:`bg-amber-500`}`}),l(`span`,{className:`font-medium text-foreground min-w-[60px]`,children:e.name}),l(`span`,{className:`font-mono text-foreground-subtle`,children:e.version}),!e.synced&&e.status!==`offline`&&l(`span`,{className:`text-[9px] px-1 py-0.5 rounded bg-amber-500/10 text-amber-400 border border-amber-500/20`,children:`outdated`}),e.status===`offline`&&l(`span`,{className:`text-[9px] px-1 py-0.5 rounded bg-muted text-muted-foreground`,children:`offline`}),e.synced&&e.status!==`offline`&&l(`span`,{className:`text-[9px] text-success`,children:`synced`})]},e.nodeId))})]}),O&&!B&&i(`div`,{className:`border-t border-border`,children:[i(`div`,{className:`flex items-center px-4 py-1 bg-surface-hover/20 border-b border-border/50`,children:[i(`div`,{className:`flex rounded border border-border overflow-hidden text-[9px]`,children:[l(`button`,{type:`button`,onClick:()=>j(`logs`),className:`px-2 py-0.5 transition-colors ${A===`logs`?`bg-primary/10 text-primary`:`text-foreground-subtle hover:bg-surface-hover`}`,children:`Logs`}),l(`button`,{type:`button`,onClick:()=>j(`events`),className:`px-2 py-0.5 border-l border-border transition-colors ${A===`events`?`bg-primary/10 text-primary`:`text-foreground-subtle hover:bg-surface-hover`}`,children:`Events`})]}),l(`div`,{className:`flex-1`}),l(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),se(!1)},className:`text-foreground-subtle hover:text-foreground`,children:l(z,{className:`h-3.5 w-3.5`})})]}),A===`logs`&&l(ee,{addonId:F.id,maxHeight:`max-h-64`,showFilters:!1}),A===`events`&&l(oe,{addonId:F.id,category:`addon.*`,maxHeight:`max-h-64`})]}),B&&i(o,{children:[l(`button`,{type:`button`,onClick:()=>te(e=>!e),className:`w-full flex items-center justify-center border-t border-border py-1 hover:bg-surface-hover/50 transition-colors`,children:l(C?he:V,{className:`h-3.5 w-3.5 text-foreground-subtle`})}),C&&l(`div`,{className:`border-t border-border px-3 py-2 space-y-2`,children:_.addons.map(e=>l(De,{addon:e,agents:t,hideVersion:!0},e.manifest.id))})]}),ce&&!B&&l(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm p-4`,onClick:()=>k(!1),children:i(`div`,{className:`w-full max-w-lg max-h-[80vh] rounded-xl border border-border bg-surface shadow-2xl flex flex-col overflow-hidden`,onClick:e=>e.stopPropagation(),children:[i(`div`,{className:`flex items-center justify-between px-5 py-3 border-b border-border flex-shrink-0`,children:[i(`div`,{className:`flex items-center gap-2`,children:[l(L,{className:`h-4 w-4 text-primary`}),i(`h2`,{className:`text-sm font-semibold text-foreground`,children:[H,` Settings`]})]}),l(`button`,{onClick:()=>k(!1),className:`text-foreground-subtle hover:text-foreground transition-colors p-1 rounded`,children:l(z,{className:`h-4 w-4`})})]}),i(`div`,{className:`flex-1 overflow-y-auto px-5 py-4 space-y-4`,children:[l(`div`,{className:`text-[10px] text-foreground-subtle mb-2`,children:`Cluster-wide settings — one value for every node. Per-node settings live under Cluster → the node → Settings.`}),l(U,{nodeId:null,addonIds:[F.id],level:`global`,fieldScope:`cluster`,emptyMessage:`This addon exposes no cluster-wide settings. Anything it can configure is per-node — open it from Cluster → the node → Settings.`}),Ce(F)&&i(`div`,{children:[l(`div`,{className:`text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-2`,children:`Device export`}),l(d,{addonId:F.id,onOpenDevice:e=>ue(`/devices/${e}`)})]}),G===`npm`&&i(`div`,{children:[l(`div`,{className:`text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-2`,children:`Auto-Update`}),l(Ee,{addonId:F.id})]}),F.components&&F.components.length>0&&i(`div`,{children:[i(`div`,{className:`text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-2`,children:[`Components (`,F.components.length,`)`]}),l(`div`,{className:`flex flex-wrap gap-1`,children:F.components.map(e=>l(`span`,{className:`text-[10px] rounded bg-background border border-border px-1.5 py-0.5 text-foreground-subtle font-mono`,children:e},e))})]}),t.length>=2&&i(`div`,{children:[l(`div`,{className:`text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-2`,children:`Installed on`}),i(`div`,{className:`flex items-center gap-1.5 flex-wrap`,children:[I.length===0&&l(`span`,{className:`text-[10px] text-foreground-subtle`,children:`Hub (local)`}),I.map(e=>l(`span`,{className:`rounded-full bg-surface-hover border border-border px-2 py-0.5 text-[10px] text-foreground-subtle`,children:e},e)),i(`div`,{className:`relative`,children:[i(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),re(e=>!e)},className:`inline-flex items-center gap-1 rounded-full border border-dashed border-border px-2 py-0.5 text-[10px] text-foreground-subtle hover:text-foreground hover:border-primary transition-colors`,title:`Install on more agents`,children:[l(le,{className:`h-3 w-3`}),`Add agent`]}),ne&&i(`div`,{className:`absolute left-0 top-full mt-1 z-10 min-w-[160px] rounded-md border border-border bg-surface shadow-lg overflow-hidden`,children:[t.filter(e=>!e.isHub&&!I.includes(e.name)).map(e=>l(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),re(!1)},className:`w-full text-left px-3 py-1.5 text-[10px] text-foreground hover:bg-surface-hover transition-colors`,children:e.name},e.id)),t.filter(e=>!e.isHub&&!I.includes(e.name)).length===0&&l(`div`,{className:`px-3 py-1.5 text-[10px] text-foreground-subtle`,children:`No available agents`})]})]})]})]})]}),l(`div`,{className:`flex items-center justify-end px-5 py-3 border-t border-border flex-shrink-0`,children:l(`button`,{type:`button`,onClick:()=>k(!1),className:`rounded-lg border border-border px-3 py-1.5 text-xs font-medium text-foreground-subtle hover:text-foreground hover:bg-surface-hover transition-colors`,children:`Close`})})]})})]})}n();var Oe=`.tgz,.tar.gz,.zip`;function ke({onUploadSuccess:n}){let[r,a]=c(!1),s=t(null),u=e(async e=>{a(!0);let t=new FormData;t.append(`file`,e);let r=localStorage.getItem(`camstack_admin_token`)??``;try{(await(await fetch(`/api/addons/upload`,{method:`POST`,headers:{Authorization:`Bearer ${r}`},body:t})).json()).success&&n()}finally{a(!1)}},[n]);return i(o,{children:[l(`input`,{ref:s,type:`file`,accept:Oe,onChange:e(e=>{let t=e.target.files?.[0];t&&u(t),e.target.value=``},[u]),className:`hidden`}),i(`button`,{type:`button`,onClick:()=>s.current?.click(),disabled:r,className:`flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md bg-surface hover:bg-surface-hover border border-border disabled:opacity-50 transition-colors`,children:[r?l(B,{className:`w-3.5 h-3.5 animate-spin`}):l(K,{className:`w-3.5 h-3.5`}),r?`Uploading...`:`Upload`]})]})}n();var Ae=[{seconds:900,label:`15m`},{seconds:3600,label:`1h`},{seconds:21600,label:`6h`},{seconds:43200,label:`12h`},{seconds:86400,label:`24h`}],je=new Set([`@camstack/system`,`@camstack/types`,`@camstack/sdk`,`@camstack/shm-ring`,`@camstack/ui-library`]);function Me(e){return e!==void 0&&je.has(e)}var Ne={id:`hub`,name:`Hub`,isHub:!0,isOnline:!0};function Pe(e,t){let n=e??`hub-only`;return n===`any-node`?!0:n===`hub-only`?t:!t}function Fe(e){let t=e;if(!t?.manifest)return null;let n={...t.manifest,name:t.manifest.name??t.manifest.id,version:t.manifest.version??`0.0.0`,capabilities:t.manifest.capabilities??[]},r=t.process,i=r?{pid:r.pid,mode:r.mode===`forked`?`forked`:`in-process`,state:r.state??`unknown`}:void 0,a=t.health,o=t.declaration?.execution,s=t.manifest.execution,c=o?.placement??s?.placement;return{manifest:n,enabled:!0,source:t.source,installSource:t.installSource,installedOn:[],...i?{process:i}:{},hasBackup:t.hasBackup,...a?{health:a}:{},...c?{placement:c}:{}}}function Ie(e){let t=new Map,n=[];for(let r of e){let e=r.manifest.packageName;if(!e){n.push(r);continue}let i=t.get(e);if(i)i.addons.push(r);else{let n=r.manifest.bundle,i={packageName:e,displayName:n?.displayName??r.manifest.packageDisplayName??r.manifest.name,version:r.manifest.packageVersion,addons:[r],...r.installSource===void 0?{}:{installSource:r.installSource},...n===void 0?{}:{bundle:n}};t.set(e,i)}}let r=[];for(let e of t.values())e.bundle!==void 0||e.addons.length>=2?r.push({bundle:e,representative:e.addons[0]}):r.push(e.addons[0]);return r.push(...n),r}function $(e){return`bundle`in e}function Le({addons:n,clusterStatus:o,selectedNode:d,onRefresh:f,isRefreshing:p}){let h=s(),[g,ee]=c(``),y=r(g),[x,S]=c(!1),C=t(null);u(()=>{if(!x)return;let e=e=>{C.current&&!C.current.contains(e.target)&&S(!1)};return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)},[x]);let{data:w}=v({nodeId:d.id}),T=a(()=>{let e=new Map;for(let t of w??[])e.set(t.name,t.latestVersion);return e},[w]),ae=a(()=>(w??[]).filter(e=>!e.isSystem).length,[w]),[E,D]=c(()=>new Set),[oe,O]=c(()=>new Map),k=e(e=>{D(t=>new Set(t).add(e))},[]),A=e(e=>{D(t=>{if(!t.has(e))return t;let n=new Set(t);return n.delete(e),n})},[]),le=e((e,t)=>{O(n=>new Map(n).set(e,t))},[]),P=e(e=>{O(t=>{if(!t.has(e))return t;let n=new Map(t);return n.delete(e),n})},[]),de=ne({onMutate:e=>{k(e.name),P(e.name)},onSuccess:(e,t)=>{A(t.name);let n=e;if(n&&n.success===!1){le(t.name,n.error??`Update failed (no error message returned by server)`);return}h.invalidateQueries({queryKey:[[`addons`]]}),h.invalidateQueries({queryKey:[[`addons`,`listUpdates`]]})},onError:(e,t)=>{A(t.name),le(t.name,e instanceof Error?e.message:String(e))}}),I=X(),L=t(new Set);u(()=>{let e=new Set;for(let[t,n]of I)ve(n)&&e.add(t);let t=[...L.current].some(t=>!e.has(t));L.current=e,t&&(h.invalidateQueries({queryKey:[[`addons`]]}),h.invalidateQueries({queryKey:[[`addons`,`listUpdates`]]}))},[I,h]);let{data:R}=te(void 0),fe=se({onSuccess:()=>{h.invalidateQueries({queryKey:[[`addons`,`getAutoUpdateSettings`]]})}}),z=ce({onSuccess:()=>{h.invalidateQueries({queryKey:[[`addons`,`getAutoUpdateSettings`]]})}}),{data:V,isFetching:H}=_({query:y||void 0},{enabled:x}),U=re(),{data:W}=m(void 0),me=W?.requestedAt,[he,ge]=c(null),[_e,G]=c(!1);u(()=>{if(W?.kind===`framework-bulk-update`&&W.requestedAt!==he){ge(W.requestedAt),G(!0);let e=window.setTimeout(()=>G(!1),6e3);return()=>window.clearTimeout(e)}},[me,he,W]),ie();let K=e(async()=>{let e=(w??[]).filter(e=>!e.isSystem);if(e.length!==0){if(!d.isHub){for(let t of e)await de.mutateAsync({name:t.name,version:t.latestVersion,nodeId:d.id});return}await U.mutateAsync({kind:`update`,targets:e.map(e=>({name:e.name,version:e.latestVersion})),nodeIds:[d.id]})}},[w,d.id,d.isHub,U,de]),q=b({onSuccess:()=>{h.invalidateQueries({queryKey:[[`addons`]]}),h.invalidateQueries({queryKey:[[`addonPages`]]}),h.invalidateQueries({queryKey:[[`capabilities`]]}),h.invalidateQueries({queryKey:[[`integrations`]]})}}),[J,Y]=c(`type`),[Z,ye]=c(()=>typeof window>`u`?`grouped`:window.localStorage.getItem(`camstack.addons.viewMode`)===`flat`?`flat`:`grouped`),be=e=>{ye(e),typeof window<`u`&&window.localStorage.setItem(`camstack.addons.viewMode`,e)},[xe,Se]=F(),Q=xe.get(`capability`),Ce=a(()=>{let e=n.filter(e=>!Me(e.manifest.packageName));return d.isHub||(e=e.filter(e=>Pe(e.placement,d.isHub))),Q&&(e=e.filter(e=>(e.manifest.capabilities??[]).some(e=>(typeof e==`string`?e:e.name)===Q))),e},[n,d.isHub,Q]),we=()=>{let e=new URLSearchParams(xe);e.delete(`capability`),Se(e,{replace:!0})},Te=Z===`flat`?Ce:Ie(Ce),Ee=a(()=>{let e=[...Te];switch(J){case`type`:e.sort((e,t)=>{let n=+!$(e),r=+!$(t);if(n!==r)return n-r;let i=$(e)?e.bundle.displayName:e.manifest.name,a=$(t)?t.bundle.displayName:t.manifest.name;return i.localeCompare(a)});break;case`name`:e.sort((e,t)=>{let n=$(e)?e.bundle.displayName:e.manifest.name,r=$(t)?t.bundle.displayName:t.manifest.name;return n.localeCompare(r)});break;case`source`:e.sort((e,t)=>{let n=$(e)?e.bundle.installSource??``:e.installSource??``,r=$(t)?t.bundle.installSource??``:t.installSource??``;return n.localeCompare(r)});break}return e},[Te,J]);return i(`div`,{className:`space-y-4`,children:[[...oe.entries()].map(([e,t])=>l(`div`,{className:`rounded-md border border-danger/30 bg-danger/5 px-3 py-2 text-[11px]`,children:i(`div`,{className:`flex items-start justify-between gap-3`,children:[i(`div`,{className:`space-y-0.5`,children:[i(`div`,{className:`font-medium text-danger`,children:[`Failed to update `,e]}),l(`div`,{className:`text-foreground-subtle font-mono`,children:t})]}),l(`button`,{type:`button`,onClick:()=>P(e),className:`text-foreground-subtle hover:text-foreground text-[10px]`,children:`dismiss`})]})},e)),i(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[i(`div`,{className:`flex items-center gap-1.5`,children:[l(`span`,{className:`text-[10px] text-foreground-subtle`,children:`Sort:`}),i(`select`,{value:J,onChange:e=>Y(e.target.value),className:`rounded-md border border-border bg-surface px-2 py-1.5 text-[11px] text-foreground focus:outline-none focus:border-primary/50`,children:[l(`option`,{value:`type`,children:`Bundles first`}),l(`option`,{value:`name`,children:`Name`}),l(`option`,{value:`source`,children:`Install source`})]})]}),i(`div`,{className:`flex items-center gap-1.5`,children:[l(`span`,{className:`text-[10px] text-foreground-subtle`,children:`View:`}),l(`div`,{className:`flex rounded-md border border-border overflow-hidden text-[10px] font-medium`,children:[`grouped`,`flat`].map(e=>l(`button`,{type:`button`,onClick:()=>be(e),className:`px-2.5 py-1.5 transition-colors capitalize ${Z===e?`bg-primary/10 text-primary`:`bg-transparent text-foreground-subtle hover:bg-surface-hover`}`,title:e===`grouped`?`Group multi-addon packages into a bundle card`:`Show every addon as its own card`,children:e},e))})]}),d.isHub&&i(`div`,{className:`flex items-center gap-1.5`,children:[l(M,{className:`h-3 w-3 text-foreground-subtle`}),l(`span`,{className:`text-[10px] text-foreground-subtle`,children:`Auto-Update:`}),l(`div`,{className:`flex rounded-md border border-border overflow-hidden text-[10px] font-medium`,children:[`off`,`latest`,`beta`].map(e=>l(`button`,{type:`button`,onClick:()=>fe.mutate({channel:e}),disabled:fe.isPending,className:`px-2.5 py-1.5 transition-colors capitalize ${R?.channel===e?e===`off`?`bg-gray-700 text-gray-200`:e===`latest`?`bg-blue-500/20 text-blue-400`:`bg-amber-500/20 text-amber-400`:`bg-transparent text-foreground-subtle hover:bg-surface-hover`} ${e===`off`?``:`border-l border-border`}`,children:e},e))})]}),d.isHub&&i(`div`,{className:`flex items-center gap-1.5`,children:[l(`span`,{className:`text-[10px] text-foreground-subtle`,children:`Check every:`}),l(`select`,{className:`rounded-md border border-border bg-transparent px-1.5 py-1 text-[10px] font-medium text-foreground-subtle`,value:R?.updateCheckIntervalSeconds??21600,disabled:z.isPending||R===void 0,onChange:e=>{R!==void 0&&z.mutate({channel:R.channel,updateCheckIntervalSeconds:Number(e.target.value)})},children:Ae.map(e=>l(`option`,{value:e.seconds,children:e.label},e.seconds))})]}),ae>0&&i(`button`,{type:`button`,onClick:()=>void K(),disabled:U.isPending,className:`flex items-center gap-1.5 px-2.5 py-1.5 text-[11px] rounded-md bg-blue-500/10 text-blue-400 hover:bg-blue-500/20 border border-blue-500/30 disabled:opacity-50 transition-colors font-medium`,children:[U.isPending?l(B,{className:`w-3 h-3 animate-spin`}):l(j,{className:`w-3 h-3`}),U.isPending?`Updating…`:`Update All (${ae})`]}),i(`button`,{type:`button`,onClick:f,disabled:p||U.isPending,className:`flex items-center gap-1.5 px-2.5 py-1.5 text-[11px] rounded-md bg-surface hover:bg-surface-hover border border-border disabled:opacity-50 transition-colors`,children:[l(M,{className:`w-3 h-3 ${p?`animate-spin`:``}`}),`Refresh`]})]}),i(`div`,{className:`flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3`,children:[i(`div`,{className:`relative flex-1 min-w-0 sm:min-w-[200px]`,ref:C,children:[l(pe,{className:`absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-foreground-subtle`}),l(`input`,{type:`text`,value:g,onChange:e=>{ee(e.target.value),S(!0)},onFocus:()=>S(!0),placeholder:`Search addons on npm...`,disabled:U.isPending,className:`w-full rounded-lg border border-border bg-background pl-9 pr-3 py-2 text-xs text-foreground placeholder:text-foreground-subtle focus:outline-none focus:ring-1 focus:ring-primary disabled:opacity-50 disabled:cursor-not-allowed`}),H&&l(B,{className:`absolute right-2.5 top-1/2 -translate-y-1/2 h-3 w-3 text-foreground-subtle animate-spin`}),x&&V&&V.length>0&&i(`div`,{className:`absolute left-0 right-0 top-full mt-1 z-40 rounded-lg border border-border bg-surface shadow-xl overflow-hidden`,children:[V.length>0&&i(`div`,{className:`px-3 py-1.5 text-[10px] uppercase tracking-wide text-foreground-subtle border-b border-border`,children:[`npm results (`,V.length,`)`]}),V&&V.length>0&&l(`div`,{className:`max-h-72 overflow-auto divide-y divide-border`,children:V.map(e=>i(`div`,{className:`flex items-center gap-3 px-3 py-2 hover:bg-surface-hover transition-colors`,children:[l(`div`,{className:`w-6 h-6 rounded-md bg-primary/10 flex items-center justify-center text-primary text-[9px] font-bold shrink-0`,children:e.name.replace(`@camstack/addon-`,``).charAt(0).toUpperCase()}),i(`div`,{className:`flex-1 min-w-0`,children:[i(`div`,{className:`flex items-baseline gap-2 min-w-0`,children:[l(`span`,{className:`text-[11px] font-semibold break-words`,children:e.name.replace(/^@camstack\/(addon-)?/,``)}),i(`span`,{className:`text-[10px] text-foreground-subtle shrink-0`,children:[`v`,e.version]})]}),l(`div`,{className:`font-mono text-[9px] text-foreground-subtle/80 truncate`,children:e.name}),e.description&&l(`div`,{className:`text-[10px] text-foreground-subtle truncate`,children:e.description})]}),e.installed?i(`span`,{className:`inline-flex items-center gap-1 px-2 py-1 text-[10px] font-medium rounded-md border border-emerald-500/30 bg-emerald-500/10 text-emerald-400 shrink-0`,children:[l(N,{className:`h-3 w-3`}),e.installedVersion??`Installed`]}):i(`button`,{type:`button`,onClick:()=>q.mutate({packageName:e.name}),disabled:q.isPending,className:`inline-flex items-center gap-1 px-2 py-1 text-[10px] font-medium rounded-md bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50 transition-colors shrink-0`,children:[q.isPending?l(B,{className:`h-3 w-3 animate-spin`}):l(j,{className:`h-3 w-3`}),`Install`]})]},e.name))})]})]}),l(ke,{onUploadSuccess:()=>{h.invalidateQueries({queryKey:[[`addons`]]}),f()}})]}),Q&&i(`div`,{className:`flex items-center gap-2 px-3 py-2 rounded-lg bg-primary/10 border border-primary/30 text-sm`,children:[l(`span`,{className:`text-foreground-subtle`,children:`Filtering by capability:`}),l(`span`,{className:`font-mono text-primary font-semibold`,children:Q}),l(`button`,{type:`button`,onClick:we,className:`ml-auto text-xs text-foreground-subtle hover:text-foreground underline`,children:`Clear`})]}),_e&&i(`div`,{className:`fixed top-[calc(env(safe-area-inset-top)+1rem)] right-[calc(env(safe-area-inset-right)+1rem)] z-50 flex items-start gap-2 px-3 py-2.5 rounded-md border border-green-500/30 bg-green-500/10 shadow-lg backdrop-blur-sm max-w-sm pointer-events-auto`,children:[l(ue,{className:`w-4 h-4 shrink-0 mt-0.5 text-green-400`}),i(`div`,{children:[l(`div`,{className:`text-[11px] font-semibold text-foreground`,children:`Bulk update completed`}),l(`div`,{className:`text-[10px] text-foreground-subtle mt-0.5`,children:`System packages updated — hub restarted successfully.`})]})]}),Ce.length===0&&l(`div`,{className:`text-xs text-foreground-subtle`,children:n.length===0?`No addons installed`:Q?`No installed addons declare the "${Q}" capability. Browse the npm catalog above to find a compatible addon.`:`No addons compatible with ${d.name} (placement filter active)`}),l(`div`,{className:`space-y-2`,children:Ee.map(e=>{let t=$(e)?e.bundle.packageName:e.manifest.packageName,n=T.get(t),r=$(e)?e.representative:e,i=n?e=>de.mutate({name:t,version:e,nodeId:d.id}):void 0,a=I.get(t)??null,s=a!==null&&ve(a);return l(De,{addon:r,clusterStatus:o?.[r.manifest.id],bundle:$(e)?e.bundle:void 0,availableUpdate:n,isUpdating:E.has(t)||s,jobProgress:a,onUpdate:i,disabledByBulk:U.isPending},$(e)?t:e.manifest.id)})})]})}function Re(){let e=s(),{data:n,isLoading:r,isError:a}=E(),{data:o}=D(void 0),{nodes:c}=w(),{selection:d,selectNode:p,requestedNodeId:m}=me(c.length>0?c:[Ne]),h=d.node??Ne,g=h.id,ee=c.length>0?d.staleNodeId:null,_=f(),v=y(),b=_.isPending||v.isPending,x=async()=>{await _.mutateAsync({nodeId:g}),await v.mutateAsync(),e.invalidateQueries({queryKey:[[`addons`]]})},S=t(_);S.current=_;let C=t(m??`hub`);u(()=>{S.current.mutate({nodeId:C.current})},[]);let te=(n??[]).map(Fe).filter(e=>e!==null);return i(H,{children:[i(`div`,{className:`flex items-center justify-between gap-3 flex-wrap`,children:[l(T,{selectedNodeId:g,onSelect:p}),i(`div`,{className:`flex items-center gap-3 flex-wrap`,children:[!r&&!a&&i(`span`,{className:`text-[10px] rounded-full bg-primary/10 text-primary px-2 py-0.5 font-medium`,children:[te.length,` installed`]}),i(`button`,{type:`button`,onClick:()=>void x(),disabled:b,className:`inline-flex items-center gap-1.5 px-2.5 py-1.5 text-[11px] rounded-md bg-surface hover:bg-surface-hover border border-border disabled:opacity-50 transition-colors`,title:`Re-fetch addons + check npm for new versions`,children:[l(M,{className:`w-3 h-3 ${b?`animate-spin`:``}`}),`Check for updates`]})]})]}),l(W,{staleNodeId:ee,shownNodeName:h.name}),!h.isHub&&i(`div`,{className:`rounded-md border border-warning/30 bg-warning/5 px-3 py-2 text-[11px] text-foreground-subtle`,children:[`Showing only addons compatible with`,` `,l(`span`,{className:`font-medium text-foreground`,children:h.name}),` — agents only run`,` `,l(`code`,{className:`font-mono`,children:`agent-only`}),` and`,` `,l(`code`,{className:`font-mono`,children:`any-node`}),` addons. Install / uninstall is hub-driven; agents auto-sync from the hub.`]}),r&&l(`div`,{className:`text-xs text-foreground-subtle animate-pulse`,children:`Loading…`}),a&&l(`div`,{className:`text-xs text-danger`,children:`Failed to load addons`}),!r&&!a&&l(Le,{addons:te,clusterStatus:o,selectedNode:h,onRefresh:()=>void x(),isRefreshing:b})]})}export{Re as AddonsPage};
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{I as e,K as t,Q as n,S as r,W as i,a,b as o,q as s,t as c,x as l,z as u}from"./_virtual_mf___mfe_internal__admin_ui_host__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-DhP-Lgiq.js";import{Q as d,s as f}from"./player-overlays-CZoMxbfX.js";import{At as p,Ct as m,Dt as h,Et as g,Ht as _,Kr as v,Kt as y,Mt as b,Nt as x,Ot as S,Pt as C,St as w,Tt as T,g as E,jt as D,nt as O,tt as k,xt as A}from"./src-DAFoNsA_.js";import{lt as j}from"./src-TPXNmZuu.js";import{t as M}from"./boxes-pBOk19g7.js";import{t as N}from"./download-BO2bWpuB.js";import{n as P,t as ee}from"./send-BALBLr9E.js";import{t as te}from"./pencil-B3W7yf67.js";import{t as F}from"./plus-B6XLLrt6.js";import{t as I}from"./server-D4gG6ibk.js";import{t as ne}from"./square-DnnUsoaE.js";import{H as L,J as R,O as z,P as B,U as V,c as H,o as re,p as U,r as ie,t as W,v as G,w as K}from"./index-Ni_XmFA2.js";import{t as q}from"./AdminPage-CCD07UMs.js";import{t as ae}from"./AdminTabs-C6Txjg4K.js";var J=R(`cloud`,[[`path`,{d:`M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z`,key:`p7xjir`}]]),oe=R(`message-square-plus`,[[`path`,{d:`M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z`,key:`1lielz`}],[`path`,{d:`M12 7v6`,key:`lw1j43`}],[`path`,{d:`M9 10h6`,key:`9gxzsh`}]]);n();var se=[`llm`,`listProfiles`],ce=[`llm`,`listProfileKinds`],le=[`llm`,`getDefaults`],ue=[`llm`,`listRuntimeNodes`],de=[`llm`,`listModelCatalog`],fe=[`llm`,`getUsage`],pe=[{purpose:`vision`,visionOnly:!0},{purpose:`text`,visionOnly:!1}],me=new Map(Object.entries({openai:J,anthropic:J,google:J,"openai-compatible":G,"managed-local":B}));function he(e){return me.get(e)??null}function Y(e){return typeof e==`string`&&e.length>0?e:void 0}function X(e){if(typeof e==`number`&&Number.isFinite(e))return e;if(typeof e==`string`&&e.trim()!==``){let t=Number(e);return Number.isFinite(t)?t:void 0}}function Z(e){return e===!0}function ge(e){return{model:e.model,baseUrl:e.baseUrl,apiKey:e.apiKey,supportsVision:e.supportsVision,temperature:e.temperature,topP:e.topP,topK:e.topK,maxTokens:e.maxTokens,contextLength:e.contextLength,systemPrompt:e.systemPrompt,timeoutMs:e.timeoutMs,connectTimeoutMs:e.connectTimeoutMs,firstTokenTimeoutMs:e.firstTokenTimeoutMs,idleTimeoutMs:e.idleTimeoutMs,retryEnabled:e.retry.enabled,retryMaxAttempts:e.retry.maxAttempts,toolsEnabled:e.toolsEnabled,contextSize:e.runtime?.contextSize,gpuLayers:e.runtime?.gpuLayers,threads:e.runtime?.threads,parallel:e.runtime?.parallel,idleStopMinutes:e.runtime?.idleStopMinutes,batchSize:e.runtime?.batchSize,ubatchSize:e.runtime?.ubatchSize,flashAttention:e.runtime?.flashAttention,mlock:e.runtime?.mlock,noMmap:e.runtime?.noMmap,cacheTypeK:e.runtime?.cacheTypeK,cacheTypeV:e.runtime?.cacheTypeV,extraArgs:be(e.runtime?.extraArgs??[])}}var _e=[`f32`,`f16`,`q8_0`,`q5_1`,`q5_0`,`q4_1`,`q4_0`];function ve(e){return typeof e==`string`&&_e.includes(e)?e:void 0}function ye(e){let t=[],n=``,r=null;for(let i of e){if(r!==null){i===r?r=null:n+=i;continue}if(i===`"`||i===`'`){r=i;continue}if(/\s/.test(i)){n!==``&&t.push(n),n=``;continue}n+=i}return n!==``&&t.push(n),t}function be(e){return e.map(e=>/\s/.test(e)?`"${e}"`:e).join(` `)}var xe=[`--jinja`,`--cont-batching`];function Se(e,t,n){let r=X(e.threads),i=X(e.batchSize),a=X(e.ubatchSize),o=ve(e.cacheTypeK),s=ve(e.cacheTypeV);return{nodeId:t,engine:`llama-cpp`,model:n,extraArgs:[...ye(Y(e.extraArgs)??``)],contextSize:X(e.contextSize)??4096,gpuLayers:X(e.gpuLayers)??0,...r===void 0?{}:{threads:r},parallel:X(e.parallel)??1,...i===void 0?{}:{batchSize:i},...a===void 0?{}:{ubatchSize:a},flashAttention:Z(e.flashAttention),mlock:Z(e.mlock),noMmap:Z(e.noMmap),...o===void 0?{}:{cacheTypeK:o},...s===void 0?{}:{cacheTypeV:s},autoStart:Z(e.autoStart),idleStopMinutes:X(e.idleStopMinutes)??30}}function Ce(e,t,n,r,i){let a={id:n?.id??crypto.randomUUID(),name:t,kind:e,addonId:`ai`,enabled:n?.enabled??!0,model:Y(r.model)??n?.model??``,supportsVision:i?.supportsVision??Z(r.supportsVision),timeoutMs:X(r.timeoutMs)??j.totalMs,connectTimeoutMs:X(r.connectTimeoutMs)??j.connectMs,firstTokenTimeoutMs:X(r.firstTokenTimeoutMs)??j.firstTokenMs,idleTimeoutMs:X(r.idleTimeoutMs)??j.idleMs,retry:{enabled:Z(r.retryEnabled),maxAttempts:X(r.retryMaxAttempts)??1},toolsEnabled:Z(r.toolsEnabled)},o=Y(r.baseUrl),s=Y(r.apiKey),c=X(r.temperature),l=X(r.topP),u=X(r.topK),d=X(r.maxTokens),f=X(r.contextLength),p=Y(r.systemPrompt);return{...a,...o===void 0?{}:{baseUrl:o},...s===void 0?{}:{apiKey:s},...c===void 0?{}:{temperature:c},...l===void 0?{}:{topP:l},...u===void 0?{}:{topK:u},...d===void 0?{}:{maxTokens:d},...f===void 0?{}:{contextLength:f},...p===void 0?{}:{systemPrompt:p},...i===void 0?{}:{model:i.modelId,runtime:Se(r,i.nodeId,i.model)}}}function we(e){let t=new Map;for(let n of e){let e=t.get(n.addonId)??[];e.push(n),t.set(n.addonId,e)}return[...t.entries()].map(([e,t])=>({addonId:e,kinds:t}))}var Te=2e3;function Q(e){return`${(e/1e9).toFixed(2)} GB`}function Ee(e){return e===null?``:e.model.kind===`catalog`?`catalog:${e.model.catalogId}`:e.model.kind===`path`?`node:${e.modelId}`:`custom`}function De({nodeId:e,value:t,onChange:n}){let{t:o}=W(),u=d(),[f,m]=s(``),[h,g]=s(null),[_,v]=s(!1),y=a({queryKey:de,queryFn:()=>u.trpcClient.llm.listModelCatalog.query({})}),b=a({queryKey:[`llm`,`listNodeModels`,e],queryFn:()=>u.trpcClient.llm.listNodeModels.query({nodeId:e})}),S=c({mutationFn:e=>u.trpcClient.llm.resolveModelRef.mutate(e),onSuccess:e=>{g(e),v(!1),e.ok&&n({model:e.model,modelId:e.label,supportsVision:e.purpose===`vision`})}}),w=c({mutationFn:t=>u.trpcClient.llm.installModel.mutate({nodeId:e,model:t}),onSuccess:()=>{v(!0),b.refetch()}}),T=a({queryKey:ue,enabled:w.isPending,refetchInterval:w.isPending?Te:!1,queryFn:()=>u.trpcClient.llm.listRuntimeNodes.query({})}).data?.find(t=>t.nodeId===e)?.status?.download,E=i(()=>{let t=(y.data??[]).map(e=>({value:`catalog:${e.id}`,label:`${e.label} · ${e.quantization} · ${Q(e.sizeBytes)}`})),n=(b.data??[]).filter(e=>e.catalogId===void 0&&e.path!==void 0).map(t=>({value:`node:${t.file}`,label:o(`ai.onNode`,`{{file}} · {{size}} · on {{node}}`,{file:t.file,size:Q(t.sizeBytes),node:e})})),r=h?.ok===!0?[{value:`custom`,label:`${h.label} · ${Q(h.totalBytes)}`}]:[];return[{value:``,label:o(`ai.selectModel`,`Select a model…`)},...t,...n,...r]},[y.data,b.data,h,e,o]),O=e=>{if(e===``){n(null);return}if(e===`custom`){if(h?.ok!==!0)return;n({model:h.model,modelId:h.label,supportsVision:h.purpose===`vision`});return}if(e.startsWith(`catalog:`)){let t=e.slice(8),r=y.data?.find(e=>e.id===t);n({model:{kind:`catalog`,catalogId:t},modelId:t,supportsVision:r?.purpose===`vision`});return}let t=e.slice(5),r=b.data?.find(e=>e.file===t);r?.path!==void 0&&n({model:{kind:`path`,path:r.path},modelId:t,supportsVision:!1})},k=e=>{f.trim()!==``&&S.mutate({ref:f.trim(),...e===void 0?{}:{maxBytes:e}})};return r(`div`,{className:`space-y-2`,children:[r(`div`,{children:[l(`label`,{className:`mb-1 block text-[11px] font-medium text-foreground`,htmlFor:`ai-model`,children:o(`ai.model`,`Model`)}),l(p,{id:`ai-model`,value:Ee(t),options:E,onChange:e=>O(e.target.value)})]}),r(`div`,{className:`rounded-md border border-border bg-surface-subtle px-3 py-2.5`,children:[l(`div`,{className:`mb-1 text-[11px] font-medium text-foreground`,children:o(`ai.hfTitle`,`Add a model from Hugging Face`)}),l(`p`,{className:`mb-2 text-[10px] leading-relaxed text-foreground-subtle`,children:o(`ai.hfHint`,`Paste a GGUF file URL, or type org/repo — add :QUANT (e.g. unsloth/Qwen3.6-35B-A3B-GGUF:UD-Q4_K_M) when the repo publishes more than one quantization.`)}),r(`div`,{className:`flex gap-2`,children:[l(D,{value:f,onChange:e=>m(e.target.value),placeholder:`unsloth/Qwen3.6-35B-A3B-GGUF:UD-Q4_K_M`,onKeyDown:e=>{e.key===`Enter`&&(e.preventDefault(),k())}}),r(C,{size:`sm`,variant:`secondary`,type:`button`,disabled:f.trim()===``||S.isPending,onClick:()=>k(),children:[S.isPending?l(K,{className:`h-3.5 w-3.5 animate-spin`}):l(U,{className:`h-3.5 w-3.5`}),o(`ai.hfCheck`,`Check`)]})]}),S.isError&&l(`p`,{className:`mt-2 text-[11px] text-danger`,children:S.error instanceof Error?S.error.message:o(`common.error`,`Error`)}),h?.ok===!1&&r(`div`,{className:`mt-2 rounded-md border border-danger/40 bg-danger/10 px-2.5 py-2`,children:[l(`p`,{className:`text-[11px] text-danger`,children:h.message}),h.candidates!==void 0&&h.candidates.length>0&&l(`div`,{className:`mt-1.5 flex flex-wrap gap-1`,children:h.candidates.map(e=>l(`button`,{type:`button`,className:`rounded border border-border bg-surface px-1.5 py-0.5 text-[10px] text-foreground hover:border-primary/50`,onClick:()=>{let t=`${f.trim().split(`:`)[0]??``}:${e}`;m(t),S.mutate({ref:t})},children:e},e))}),h.requiredBytes!==void 0&&l(C,{size:`sm`,variant:`secondary`,type:`button`,className:`mt-2`,onClick:()=>k(h.requiredBytes),children:o(`ai.hfOverride`,`Install anyway ({{size}})`,{size:Q(h.requiredBytes)})})]}),h?.ok===!0&&r(`div`,{className:`mt-2 rounded-md border border-border bg-surface px-2.5 py-2`,children:[r(`div`,{className:`flex flex-wrap items-center gap-1.5`,children:[l(`span`,{className:`text-[11px] font-medium text-foreground`,children:h.label}),l(x,{variant:h.purpose===`vision`?`info`:`default`,children:h.purpose}),l(x,{variant:`default`,children:Q(h.totalBytes)})]}),h.extraFilenames.length>0&&l(`p`,{className:`mt-1 text-[10px] text-foreground-subtle`,children:o(`ai.hfExtras`,`Also downloads: {{files}}`,{files:h.extraFilenames.join(`, `)})}),r(`div`,{className:`mt-2 flex items-center gap-2`,children:[r(C,{size:`sm`,type:`button`,disabled:w.isPending||_,onClick:()=>w.mutate(h.model),children:[w.isPending?l(K,{className:`h-3.5 w-3.5 animate-spin`}):l(N,{className:`h-3.5 w-3.5`}),_?o(`ai.hfInstalled`,`Downloaded`):o(`ai.hfInstall`,`Download to {{node}}`,{node:e})]}),T!==void 0&&l(`span`,{className:`text-[10px] text-foreground-subtle`,children:T.phase===`verifying`?o(`ai.hfVerifying`,`verifying {{file}}…`,{file:T.file}):o(`ai.hfDownloading`,`{{file}} ({{index}}/{{count}}) — {{done}}{{total}}`,{file:T.file,index:T.fileIndex,count:T.fileCount,done:Q(T.downloadedBytes),total:T.totalBytes===void 0?``:` / ${Q(T.totalBytes)}`})})]}),w.isError&&l(`p`,{className:`mt-1.5 text-[11px] text-danger`,children:w.error instanceof Error?w.error.message:o(`common.error`,`Error`)})]})]})]})}n();function Oe({kind:e,className:t}){let n=he(e.kind);return n===null?l(`span`,{className:t,children:e.icon}):l(n,{className:t})}function ke({kinds:e,onPick:t,onCancel:n}){let{t:a}=W(),o=i(()=>we(e),[e]);return l(A,{open:!0,onOpenChange:e=>!e&&n(),children:r(m,{width:`lg`,placement:`sheet-on-mobile`,scroll:`body`,children:[l(g,{children:l(h,{children:a(`ai.chooseKind`,`Choose a profile type`)})}),r(w,{className:`space-y-4 pr-1`,children:[o.length===0&&l(`p`,{className:`text-xs text-foreground-subtle`,children:a(`ai.noKinds`,`No AI provider is installed.`)}),o.map(e=>r(`div`,{children:[l(`div`,{className:`mb-1.5 text-[10px] font-semibold uppercase tracking-wider text-foreground-subtle`,children:e.addonId}),l(`div`,{className:`grid grid-cols-2 gap-2 sm:grid-cols-3`,children:e.kinds.map(n=>r(`button`,{type:`button`,onClick:()=>t(n),className:`flex flex-col items-center gap-1.5 rounded-lg border border-border bg-surface px-3 py-3 text-xs transition-colors hover:border-primary/50 hover:bg-surface-hover`,children:[l(Oe,{kind:n,className:`h-5 w-5 text-foreground-subtle`}),l(`span`,{className:`font-medium text-foreground`,children:n.label})]},`${e.addonId}:${n.kind}`))})]},e.addonId))]}),l(T,{children:l(C,{size:`sm`,variant:`secondary`,type:`button`,onClick:n,children:a(`common.cancel`,`Cancel`)})})]})})}function Ae({kind:e,existing:t,onSave:n,onCancel:a,saving:c,error:u}){let{t:d}=W(),f=e.kind===`managed-local`,[p,v]=s(t?.name??e.label),[y,b]=s(()=>t===null?{}:ge(t)),[S,O]=s(t?.runtime?.nodeId??`hub`),[k,j]=s(()=>t?.runtime===void 0?null:{model:t.runtime.model,modelId:t.model,supportsVision:t.supportsVision}),M=i(()=>ye(Y(y.extraArgs)??``),[y.extraArgs]),N=()=>{if(!f){n(Ce(e.kind,p,t,y));return}k!==null&&n(Ce(e.kind,p,t,y,{nodeId:S,model:k.model,modelId:k.modelId,supportsVision:k.supportsVision}))},P=c||p.trim()===``||f&&k===null;return l(A,{open:!0,onOpenChange:e=>!e&&a(),children:r(m,{width:`lg`,placement:`sheet-on-mobile`,scroll:`body`,children:[l(g,{children:r(h,{className:`flex items-center gap-2`,children:[l(Oe,{kind:e,className:`h-4 w-4 text-foreground-subtle`}),t===null?d(`ai.newProfile`,`New {{kind}} profile`,{kind:e.label}):d(`ai.editProfile`,`Edit {{name}}`,{name:t.name})]})}),r(w,{className:`space-y-3 pr-1`,children:[u!==null&&l(`div`,{className:`rounded-md border border-danger/40 bg-danger/10 px-3 py-2 text-xs text-danger`,children:u}),r(`div`,{children:[l(`label`,{className:`mb-1 block text-[11px] font-medium text-foreground`,htmlFor:`ai-profile-name`,children:d(`ai.name`,`Name`)}),l(D,{id:`ai-profile-name`,value:p,onChange:e=>v(e.target.value),placeholder:e.label})]}),f&&r(o,{children:[l(E,{selectedNodeId:S,onSelect:O,label:d(`ai.runtimeNode`,`Runtime node`),alwaysShow:!0}),l(De,{nodeId:S,value:k,onChange:j}),r(`div`,{children:[l(`label`,{className:`mb-1 block text-[11px] font-medium text-foreground`,htmlFor:`ai-extra-args`,children:d(`ai.extraArgs`,`Additional llama-server arguments`)}),l(D,{id:`ai-extra-args`,value:Y(y.extraArgs)??``,onChange:e=>b({...y,extraArgs:e.target.value}),placeholder:xe.join(` `)}),M.length>0&&l(`div`,{className:`mt-1 flex flex-wrap gap-1`,children:M.map((e,t)=>l(x,{variant:`default`,children:e},`${e}-${String(t)}`))}),l(`p`,{className:`mt-1 text-[10px] leading-relaxed text-foreground-subtle`,children:d(`ai.extraArgsHint`,`Flags this form does not already own. Vision models generally need --jinja; some language-only models do not like it. Context size, GPU layers, parallel slots, flash attention and the KV-cache types are set in the fields below — repeating one here is rejected at start.`)})]})]}),l(_,{schema:e.configSchema,values:y,onChange:b}),t!==null&&l(`p`,{className:`text-[10px] text-foreground-subtle`,children:d(`ai.secretHint`,`A stored API key is never shown. Leave it as-is to keep it; type a new value to replace it.`)})]}),r(T,{children:[f&&k===null&&l(x,{variant:`warning`,children:d(`ai.pickModelFirst`,`pick a model`)}),l(C,{size:`sm`,variant:`secondary`,type:`button`,onClick:a,children:d(`common.cancel`,`Cancel`)}),r(C,{size:`sm`,type:`button`,disabled:P,onClick:N,children:[c&&l(K,{className:`h-3.5 w-3.5 animate-spin`}),t===null?d(`ai.createProfile`,`Create profile`):d(`ai.saveChanges`,`Save changes`)]})]})]})})}n();function je(e){return[{key:`name`,header:e.t(`ai.colProfile`,`Profile`),render:t=>{let n=e.kindByName.get(t.kind);return r(`span`,{className:`flex items-center gap-2`,children:[l(`span`,{className:`flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-surface`,title:n?.label??t.kind,children:n===void 0?l(`span`,{className:`text-xs text-foreground-subtle`,children:`?`}):l(Oe,{kind:n,className:`h-4 w-4 text-foreground-subtle`})}),r(`span`,{className:`min-w-0`,children:[l(`span`,{className:`block truncate text-sm font-medium text-foreground`,children:t.name}),e.testResult?.id===t.id&&l(`span`,{className:`block truncate text-[10px] ${e.testResult.ok?`text-success`:`text-danger`}`,children:e.testResult.text})]})]})}},{key:`kind`,header:e.t(`ai.colKind`,`Kind`),nowrap:!0,render:t=>l(`span`,{className:`text-[11px] text-foreground-subtle`,children:e.kindByName.get(t.kind)?.label??t.kind})},{key:`model`,header:e.t(`ai.colModel`,`Model`),render:e=>l(`span`,{className:`text-[11px] text-foreground`,children:e.model})},{key:`vision`,header:e.t(`ai.colVision`,`Vision`),align:`center`,nowrap:!0,render:t=>t.supportsVision?l(x,{variant:`info`,style:`outline`,children:e.t(`ai.vision`,`vision`)}):l(`span`,{className:`text-[11px] text-foreground-subtle`,children:`—`})},{key:`node`,header:e.t(`ai.colNode`,`Node`),nowrap:!0,render:e=>e.runtime===void 0?l(`span`,{className:`text-[11px] text-foreground-subtle`,children:`—`}):l(x,{variant:`default`,children:e.runtime.nodeId})},{key:`enabled`,header:e.t(`ai.colOn`,`On`),align:`center`,nowrap:!0,render:t=>l(S,{checked:t.enabled,onCheckedChange:()=>e.onToggle(t),"aria-label":`toggle ${t.name}`})},{key:`actions`,header:``,align:`right`,nowrap:!0,render:t=>r(`span`,{className:`flex items-center justify-end gap-1`,children:[l(C,{size:`sm`,variant:`ghost`,type:`button`,onClick:()=>e.onTest(t),title:e.t(`ai.test`,`Test`),children:e.testingId===t.id?l(K,{className:`h-3.5 w-3.5 animate-spin`}):l(ee,{className:`h-3.5 w-3.5`})}),l(C,{size:`sm`,variant:`ghost`,type:`button`,disabled:!e.kindByName.has(t.kind),onClick:()=>e.onEdit(t),title:e.t(`common.edit`,`Edit`),children:l(te,{className:`h-3.5 w-3.5`})}),l(C,{size:`sm`,variant:`ghost`,type:`button`,onClick:()=>e.onDelete(t),title:e.t(`common.delete`,`Delete`),children:l(re,{className:`h-3.5 w-3.5 text-danger`})})]})}]}function Me(){let{t:e}=W(),t=d(),[n,o]=s({mode:`closed`}),[u,f]=s(null),[p,m]=s(null),h=a({queryKey:se,queryFn:()=>t.trpcClient.llm.listProfiles.query({})}),g=a({queryKey:ce,queryFn:async()=>(await t.trpcClient.llm.listProfileKinds.query({})).map(e=>({...e,configSchema:e.configSchema}))}),_=()=>{h.refetch()},v=c({mutationFn:e=>t.trpcClient.llm.upsertProfile.mutate({profile:e}),onSuccess:()=>{o({mode:`closed`}),m(null),_()},onError:t=>m(t instanceof Error?t.message:e(`ai.saveFailed`,`Save failed`))}),x=c({mutationFn:e=>t.trpcClient.llm.deleteProfile.mutate({addonId:e.addonId,profileId:e.id}),onSuccess:_}),S=c({mutationFn:e=>t.trpcClient.llm.testProfile.mutate({addonId:e.addonId,profileId:e.id}),onSuccess:(e,t)=>f({id:t.id,ok:e.ok,text:e.ok?`${e.text} (${String(e.usage.outputTokens)} tok, ${String(e.latencyMs)}ms)`:`${e.code}: ${e.message}`})}),w=h.data??[],T=i(()=>g.data??[],[g.data]),E=i(()=>{let e=new Map;for(let t of T)e.set(t.kind,t);return e},[T]);return r(q,{icon:H,title:e(`ai.profilesTitle`,`AI profiles`),subtitle:e(`ai.profilesSubtitle`,`One row = one usable model endpoint. The defaults below decide who answers when a feature names no profile.`),actions:r(C,{size:`sm`,type:`button`,onClick:()=>{m(null),o({mode:`pick-kind`})},children:[l(F,{className:`h-3.5 w-3.5`}),e(`ai.addProfile`,`Add profile`)]}),children:[h.isError&&l(y,{title:e(`ai.loadFailed`,`Failed to load profiles`),message:h.error instanceof Error?h.error.message:e(`common.error`,`Error`),onRetry:()=>void h.refetch()}),l(Ne,{profiles:w}),h.isLoading&&l(`div`,{className:`flex items-center justify-center py-16`,children:l(K,{className:`h-6 w-6 animate-spin text-primary`})}),!h.isLoading&&w.length===0&&l(`div`,{className:`py-16 text-center text-xs text-foreground-subtle`,children:e(`ai.noProfiles`,`No AI profiles yet. Click "Add profile" to configure one.`)}),w.length>0&&l(b,{children:l(k,{columns:je({kindByName:E,testResult:u,testingId:S.isPending?S.variables?.id??null:null,t:e,onToggle:e=>v.mutate({...e,enabled:!e.enabled,apiKey:`__redacted__`}),onTest:e=>S.mutate(e),onEdit:e=>{let t=E.get(e.kind);t!==void 0&&(m(null),o({mode:`form`,kind:t,profile:e}))},onDelete:e=>x.mutate(e)}),rows:w,rowKey:e=>e.id,minWidthPx:760,bordered:!1,mobileMode:`scroll`,maxBodyHeight:`max-h-[60vh]`})}),n.mode===`pick-kind`&&l(ke,{kinds:T,onCancel:()=>o({mode:`closed`}),onPick:e=>o({mode:`form`,kind:e,profile:null})}),n.mode===`form`&&l(Ae,{kind:n.kind,existing:n.profile,saving:v.isPending,error:p,onSave:e=>v.mutate(e),onCancel:()=>o({mode:`closed`})})]})}function Ne({profiles:e}){let{t}=W(),n=d(),i=a({queryKey:le,queryFn:()=>n.trpcClient.llm.getDefaults.query({})}),o=c({mutationFn:e=>n.trpcClient.llm.setDefault.mutate({selector:{purpose:e.purpose},profileId:e.profileId}),onSuccess:()=>{i.refetch()}}),s=e=>(i.data??[]).find(t=>`purpose`in t.selector&&t.selector.purpose===e)?.profileId??``,u=e=>e===`vision`?t(`ai.defaultVision`,`Default vision profile`):t(`ai.defaultText`,`Default text profile`);return l(b,{children:l(`div`,{className:`grid gap-4 p-4 sm:grid-cols-2`,children:pe.map(({purpose:n,visionOnly:i})=>{let a=i?e.filter(e=>e.supportsVision):e,c=s(n),d=e.find(e=>e.id===c);return r(`div`,{children:[l(`label`,{className:`mb-1 block text-[11px] font-medium text-foreground`,htmlFor:`llm-default-${n}`,children:u(n)}),r(`select`,{id:`llm-default-${n}`,"aria-label":u(n),className:`h-7 w-full rounded-md border border-border bg-surface px-2.5 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-primary`,value:c,onChange:e=>o.mutate({purpose:n,profileId:e.target.value===``?null:e.target.value}),children:[l(`option`,{value:``,children:t(`ai.none`,`None`)}),c!==``&&!a.some(e=>e.id===c)&&l(`option`,{value:c,children:d?.name??c}),a.map(e=>r(`option`,{value:e.id,children:[e.name,` · `,e.model]},e.id))]}),c!==``&&d===void 0&&l(`p`,{className:`mt-1 text-[10px] text-danger`,children:t(`ai.defaultMissing`,`This default names a profile that no longer exists.`)}),d!==void 0&&!d.enabled&&l(`p`,{className:`mt-1 text-[10px] text-warning`,children:t(`ai.defaultDisabled`,`This default profile is disabled — callers resolve to no profile.`)}),o.error!=null&&l(`p`,{className:`mt-1 text-[10px] text-danger`,children:String(o.error)})]},n)})})})}n();var Pe=5e3;function Fe(e){return`${(e/1e9).toFixed(1)} GB`}function Ie(){let{t:e}=W(),t=d(),n=a({queryKey:ue,refetchInterval:Pe,queryFn:()=>t.trpcClient.llm.listRuntimeNodes.query({})}),o=i(()=>[{key:`node`,header:e(`ai.colNode`,`Node`),render:e=>l(`span`,{className:`text-sm font-medium text-foreground`,children:e.nodeId})},{key:`state`,header:e(`ai.colState`,`State`),nowrap:!0,render:t=>r(`span`,{className:`flex items-center gap-1.5`,children:[l(x,{variant:t.reachable?`success`:`danger`,children:t.reachable?t.status?.state??e(`ai.ready`,`ready`):e(`ai.unreachable`,`unreachable`)}),t.status?.downloadProgress!==void 0&&l(x,{variant:`info`,children:`${String(Math.round(t.status.downloadProgress*100))}%`})]})},{key:`model`,header:e(`ai.colModel`,`Model`),render:e=>l(`span`,{className:`text-[11px] text-foreground`,children:e.status?.modelId??`—`})},{key:`disk`,header:e(`ai.colDisk`,`On disk`),align:`right`,nowrap:!0,render:e=>l(`span`,{className:`text-[11px] text-foreground-subtle`,children:e.disk===void 0?`—`:Fe(e.disk.modelsBytes)})},{key:`error`,header:e(`ai.colError`,`Error`),render:e=>e.error===void 0?l(`span`,{className:`text-[11px] text-foreground-subtle`,children:`—`}):l(`span`,{className:`text-[11px] text-danger`,children:e.error})}],[e]),s=n.data??[];return r(q,{icon:I,title:e(`ai.runtimesTitle`,`Managed runtimes`),subtitle:e(`ai.runtimesSubtitle`,`Nodes advertising the llm-runtime capability: what each has loaded, what it is downloading, and how much model data sits on its disk.`),children:[n.isError&&l(y,{title:e(`ai.runtimesFailed`,`Failed to read runtime nodes`),message:n.error instanceof Error?n.error.message:e(`common.error`,`Error`),onRetry:()=>void n.refetch()}),s.length===0?l(`div`,{className:`py-16 text-center text-xs text-foreground-subtle`,children:e(`ai.noRuntimes`,`No node advertises the llm-runtime capability.`)}):l(b,{children:l(k,{columns:o,rows:s,rowKey:e=>e.nodeId,minWidthPx:640,bordered:!1,mobileMode:`scroll`,maxBodyHeight:O})})]})}var Le=`/addon/ai/test-chat`,Re=`/addon/ai/test-chat/chats`,ze=6e5;function Be(e){let t=e.firstTokenTimeoutMs;if(!(typeof t!=`number`||!Number.isFinite(t)||t<=0))return Math.min(Math.round(t),ze)}function Ve(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function He(e){if(!Ve(e))return null;let t=e.kind;return t!==`snapshot`&&t!==`track`||typeof e.mimeType!=`string`||typeof e.sizeBytes!=`number`?null:{kind:t,mimeType:e.mimeType,sizeBytes:e.sizeBytes,...typeof e.mediaKind==`string`?{mediaKind:e.mediaKind}:{},...typeof e.capturedAt==`number`?{capturedAt:e.capturedAt}:{},...typeof e.thumbnailBase64==`string`?{thumbnailBase64:e.thumbnailBase64}:{}}}var Ue=[`resolving-image`,`connecting`,`first-token-wait`,`streaming`];function We(e){let t;try{t=JSON.parse(e)}catch{return null}if(!Ve(t))return null;switch(t.kind){case`status`:{let e=Ue.find(e=>e===t.phase);return e===void 0?null:{kind:`status`,phase:e}}case`meta`:return typeof t.profileName!=`string`||typeof t.model!=`string`?null:{kind:`meta`,profileName:t.profileName,model:t.model,mediaSent:He(t.mediaSent),streamed:t.streamed===!0,firstTokenTimeoutMs:typeof t.firstTokenTimeoutMs==`number`?t.firstTokenTimeoutMs:0};case`token`:return typeof t.text==`string`?{kind:`token`,text:t.text}:null;case`done`:return{kind:`done`,inputTokens:typeof t.inputTokens==`number`?t.inputTokens:0,outputTokens:typeof t.outputTokens==`number`?t.outputTokens:0,latencyMs:typeof t.latencyMs==`number`?t.latencyMs:0,truncated:t.truncated===!0,...typeof t.conversationId==`string`?{conversationId:t.conversationId}:{}};case`error`:return{kind:`error`,code:typeof t.code==`string`?t.code:`adapter-error`,message:typeof t.message==`string`?t.message:`the provider returned an error`};default:return null}}async function*Ge(e){let t=e.getReader(),n=new TextDecoder,r=``;try{for(;;){let{done:e,value:i}=await t.read();if(e)break;r+=n.decode(i,{stream:!0});let a=r.indexOf(`
|
|
2
|
-
`);for(;a>=0;){let e=r.slice(0,a).trim();if(r=r.slice(a+1),e.length>0){let t=We(e);t!==null&&(yield t)}a=r.indexOf(`
|
|
3
|
-
`)}}let e=r.trim();if(e.length>0){let t=We(e);t!==null&&(yield t)}}finally{t.releaseLock()}}function Ke(e){return e.filter(e=>e.failed!==!0&&e.content.length>0).map(e=>({role:e.role,content:e.content}))}function qe(e){return e.thumbnailBase64===void 0||e.thumbnailBase64.length===0?null:`data:${e.mimeType};base64,${e.thumbnailBase64}`}function Je(e){return e.messages.map((t,n)=>{let r=t.mediaSent??void 0;return{id:`${e.id}-${String(n)}`,role:t.role,content:t.content,...t.attachment===void 0?{}:{attachmentRef:t.attachment,attachmentKind:t.attachment.kind},...r===void 0?{}:{attachment:r}}})}function Ye(e){let t=e.sizeBytes<1024*1024?`${(e.sizeBytes/1024).toFixed(0)} KB`:`${(e.sizeBytes/(1024*1024)).toFixed(1)} MB`,n=[e.kind===`snapshot`?`camera snapshot`:`track best-shot`,t];return e.mediaKind!==void 0&&n.push(e.mediaKind),e.capturedAt!==void 0&&n.push(new Date(e.capturedAt).toLocaleTimeString()),n.join(` · `)}function Xe(e,t){switch(e){case`resolving-image`:return`fetching the picture…`;case`connecting`:return`connecting to the provider…`;case`first-token-wait`:return t>0?`the model is loading / thinking — a cold load can take minutes (up to ${String(Math.round(t/1e3))}s)`:`the model is loading / thinking — a cold load can take minutes`;case`streaming`:return`answering…`}}n();var Ze=[`pipelineAnalytics`,`listRecentTracks`,`ai-test`],Qe=360*60*1e3,$e=40,et=160,$={phase:`connecting`,firstTokenTimeoutMs:0,text:``,mediaSent:null};function tt(){let{t:n}=W(),o=d(),[c,f]=s(``),[m,h]=s(``),[g,_]=s(``),[v,x]=s([]),[S,w]=s(null),[T,E]=s(`none`),[O,k]=s(`throwaway`),[A,j]=s(null),[M,N]=s([]),[te,F]=s(null),[I,R]=s(null),z=t(null);u(()=>()=>z.current?.abort(),[]);let B=e(async()=>{let e=await fetch(Re,{credentials:`same-origin`});e.ok&&N((await e.json()).chats??[])},[]);u(()=>{O===`persistent`&&B()},[O,B]);let H=a({queryKey:se,queryFn:()=>o.trpcClient.llm.listProfiles.query({})}),U=i(()=>(H.data??[]).filter(e=>e.enabled),[H.data]),G=U.find(e=>e.id===c)??null,K=I!==null,ae=e(async(e,t)=>{let r=new AbortController;z.current=r,F(null);let i=Be(G??{});R({...$,firstTokenTimeoutMs:i??0});let a=``,o=null,s,l=null,u=null,d;try{let n=await fetch(Le,{method:`POST`,headers:{"content-type":`application/json`},credentials:`same-origin`,signal:r.signal,body:JSON.stringify({profileId:c,messages:e,...m.trim()===``?{}:{system:m.trim()},...t===void 0?{}:{attachment:t},...i===void 0?{}:{firstTokenTimeoutMs:i},...O===`persistent`?{persist:!0,...A===null?{}:{conversationId:A}}:{}})});if(!n.ok||n.body===null){let e=await n.text().catch(()=>``);throw Error(e.length>0?e:`HTTP ${String(n.status)}`)}for await(let e of Ge(n.body))switch(e.kind){case`status`:R(t=>({...t??$,phase:e.phase}));break;case`meta`:o=e.mediaSent,s=e.model,R(t=>({...t??$,firstTokenTimeoutMs:e.firstTokenTimeoutMs,mediaSent:e.mediaSent}));break;case`token`:a+=e.text,R(e=>({...e??$,text:a}));break;case`done`:u={outputTokens:e.outputTokens,latencyMs:e.latencyMs},d=e.conversationId;break;case`error`:l=`${e.code}: ${e.message}`;break}}catch(e){r.signal.aborted||F(e instanceof Error?e.message:n(`common.error`,`Error`))}finally{z.current=null,R(null)}d!==void 0&&(j(d),B());let f=r.signal.aborted&&a.length>0;l===null&&a.length===0&&!f||x(e=>[...e,{id:`a-${String(Date.now())}`,role:`assistant`,content:l??a,...l===null?{}:{failed:!0},...o===null?{}:{attachment:o},...s!==void 0&&l===null?{model:s}:{},...u===null?{}:u}])},[O,A,G,c,B,m,n]),J=e(()=>{let e=g.trim();if(e===``||c===``||K)return;let t={id:`u-${String(Date.now())}`,role:`user`,content:e,...S===null?{}:{attachmentLabel:S.label,attachmentKind:S.ref.kind}},n=[...v,t];x(n),_(``);let r=S?.ref;w(null),E(`none`),ae(O===`persistent`&&A!==null?[{role:`user`,content:e}]:Ke(n),r)},[O,A,g,S,c,ae,K,v]),ce=()=>z.current?.abort(),le=()=>{z.current?.abort(),x([]),w(null),_(``),F(null),R(null),j(null)},ue=async e=>{z.current?.abort();let t=await fetch(`${Re}/${e}`,{credentials:`same-origin`});if(!t.ok)return;let n=await t.json();j(e),x(Je(n)),R(null),F(null)};return r(q,{icon:P,title:n(`ai.testTitle`,`Test chat`),subtitle:n(O===`persistent`?`ai.testSubtitlePersistent`:`ai.testSubtitle`,O===`persistent`?`Conversations are saved for you and can be reopened. Throwaway mode is still available.`:`A throwaway conversation with one profile. Attach a live camera snapshot or a recent track to check the model can actually read a picture. Nothing is saved — only the usage row.`),actions:r(C,{size:`sm`,variant:`secondary`,type:`button`,disabled:v.length===0&&S===null,onClick:le,children:[l(re,{className:`h-3.5 w-3.5`}),n(`ai.clearChat`,`Clear`)]}),children:[r(b,{className:`space-y-3 p-4`,children:[r(`div`,{className:`grid gap-3 sm:grid-cols-2`,children:[r(`div`,{children:[l(`label`,{className:`mb-1 block text-[11px] font-medium text-foreground`,htmlFor:`ai-test-profile`,children:n(`ai.profile`,`Profile`)}),l(p,{id:`ai-test-profile`,value:c,onChange:e=>f(e.target.value),options:[{value:``,label:n(`ai.selectProfile`,`Select a profile…`)},...U.map(e=>({value:e.id,label:`${e.name} · ${e.model}${e.supportsVision?` · vision`:``}`}))]}),U.length===0&&!H.isLoading&&l(`p`,{className:`mt-1 text-[10px] text-foreground-subtle`,children:n(`ai.noEnabledProfiles`,`No enabled profile. Add one on the Profiles tab.`)})]}),r(`div`,{children:[l(`label`,{className:`mb-1 block text-[11px] font-medium text-foreground`,htmlFor:`ai-test-system`,children:n(`ai.systemPrompt`,`System prompt (optional)`)}),l(D,{id:`ai-test-system`,value:m,onChange:e=>h(e.target.value),placeholder:n(`ai.systemPlaceholder`,`Answer in one short sentence.`)})]})]}),r(`div`,{className:`flex flex-wrap items-center gap-2`,children:[l(C,{size:`sm`,variant:O===`throwaway`?`primary`:`outline`,type:`button`,onClick:()=>{k(`throwaway`),j(null)},children:n(`ai.throwawayMode`,`Throwaway`)}),l(C,{size:`sm`,variant:O===`persistent`?`primary`:`outline`,type:`button`,onClick:()=>k(`persistent`),children:n(`ai.saveConversation`,`Save conversation`)})]}),O===`persistent`&&r(`div`,{className:`space-y-2`,children:[l(`div`,{className:`flex items-center gap-2`,children:r(C,{size:`sm`,variant:`secondary`,type:`button`,onClick:le,children:[l(oe,{className:`h-3.5 w-3.5`}),n(`ai.newChat`,`New chat`)]})}),M.length>0&&l(`div`,{className:`max-h-36 divide-y divide-border overflow-y-auto rounded-md border border-border`,children:M.map(e=>l(`button`,{type:`button`,onClick:()=>void ue(e.id),className:`flex w-full px-2.5 py-1.5 text-left text-[11px] hover:bg-surface-hover ${e.id===A?`bg-primary/10`:``}`,children:l(`span`,{className:`min-w-0 flex-1 truncate text-foreground`,children:e.title})},e.id))})]}),l(`p`,{className:`text-[10px] text-foreground-subtle`,children:n(`ai.streamNote`,`The answer streams as the model produces it. A cold model can take a while to load — the status line says which phase it is in.`)}),G!==null&&!G.supportsVision&&l(`p`,{className:`text-[10px] text-warning`,children:n(`ai.notVision`,`This profile is not vision-capable — an attached image will be refused before anything is read.`)})]}),te!==null&&l(y,{title:n(`ai.chatFailed`,`The test call failed`),message:te}),l(nt,{turns:v,live:I}),r(b,{className:`space-y-2 p-3`,children:[S!==null&&r(`div`,{className:`flex items-center gap-2 rounded-md border border-border bg-surface px-2.5 py-1.5`,children:[S.ref.kind===`snapshot`?l(L,{className:`h-3.5 w-3.5 text-foreground-subtle`}):l(V,{className:`h-3.5 w-3.5 text-foreground-subtle`}),l(`span`,{className:`min-w-0 flex-1 truncate text-[11px] text-foreground`,children:S.label}),l(C,{size:`sm`,variant:`ghost`,type:`button`,onClick:()=>w(null),children:l(ie,{className:`h-3.5 w-3.5`})})]}),r(`div`,{className:`flex flex-wrap items-center gap-2`,children:[r(C,{size:`sm`,variant:T===`snapshot`?`primary`:`outline`,type:`button`,onClick:()=>E(T===`snapshot`?`none`:`snapshot`),children:[l(L,{className:`h-3.5 w-3.5`}),n(`ai.attachSnapshot`,`Camera snapshot`)]}),r(C,{size:`sm`,variant:T===`track`?`primary`:`outline`,type:`button`,onClick:()=>E(T===`track`?`none`:`track`),children:[l(V,{className:`h-3.5 w-3.5`}),n(`ai.attachTrack`,`Recent track`)]})]}),T===`snapshot`&&l(at,{onPick:e=>{w({ref:{kind:`snapshot`,deviceId:e.id},label:n(`ai.snapshotOf`,`Snapshot of {{name}}`,{name:e.name})}),E(`none`)}}),T===`track`&&l(st,{onPick:(e,t)=>{w({ref:{kind:`track`,trackId:e.trackId,deviceId:e.deviceId},label:n(`ai.trackOf`,`{{class}} on {{name}}`,{class:e.label??e.className,name:t})}),E(`none`)}}),r(`div`,{className:`flex items-center gap-2`,children:[l(D,{value:g,onChange:e=>_(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),J())},placeholder:n(`ai.messagePlaceholder`,`Ask the model something…`),"aria-label":n(`ai.message`,`Message`)}),K?r(C,{size:`sm`,variant:`secondary`,type:`button`,onClick:ce,children:[l(ne,{className:`h-3.5 w-3.5`}),n(`ai.stop`,`Stop`)]}):r(C,{size:`sm`,type:`button`,disabled:g.trim()===``||c===``,onClick:J,children:[l(ee,{className:`h-3.5 w-3.5`}),n(`ai.send`,`Send`)]})]})]})]})}function nt({turns:e,live:t}){let{t:n}=W();return e.length===0&&t===null?l(`div`,{className:`py-12 text-center text-xs text-foreground-subtle`,children:n(`ai.chatEmpty`,`Pick a profile, optionally attach a camera snapshot or a recent track, and send a message. Nothing here is saved.`)}):l(b,{children:r(`div`,{className:`max-h-[50vh] space-y-2 overflow-y-auto p-3`,children:[e.map(e=>l(rt,{turn:e},e.id)),t!==null&&r(`div`,{className:`space-y-1`,children:[t.mediaSent!==null&&l(it,{attachment:t.mediaSent}),t.text.length>0&&l(rt,{turn:{id:`live`,role:`assistant`,content:t.text},streaming:!0}),r(`div`,{className:`flex items-center gap-2 text-[11px] text-foreground-subtle`,children:[l(K,{className:`h-3.5 w-3.5 animate-spin`}),Xe(t.phase,t.firstTokenTimeoutMs)]})]})]})})}function rt({turn:e,streaming:t=!1}){let n=e.role===`user`,i=e.failed===!0?`border-danger/40 bg-danger/10`:`border-border bg-surface`;return l(`div`,{className:`flex ${n?`justify-end`:`justify-start`}`,children:r(`div`,{className:`max-w-[85%] rounded-lg border px-3 py-2 ${n?`border-primary/40 bg-primary/10`:i}`,children:[r(`p`,{className:`whitespace-pre-wrap break-words text-xs text-foreground`,children:[e.content,t&&l(`span`,{className:`ml-0.5 animate-pulse text-primary`,children:`▌`})]}),e.attachment!==void 0&&l(it,{attachment:e.attachment}),e.attachmentLabel!==void 0&&r(`p`,{className:`mt-1 flex items-center gap-1 text-[10px] text-foreground-subtle`,children:[e.attachmentKind===`track`?l(V,{className:`h-3 w-3`}):l(L,{className:`h-3 w-3`}),e.attachmentLabel]}),e.attachment!==void 0&&r(`p`,{className:`mt-1 flex items-center gap-1 text-[10px] text-foreground-subtle`,children:[e.attachment.kind===`snapshot`?l(L,{className:`h-3 w-3`}):l(V,{className:`h-3 w-3`}),Ye(e.attachment)]}),e.model!==void 0&&l(`p`,{className:`mt-1 text-[10px] text-foreground-subtle`,children:`${e.model} · ${String(e.outputTokens??0)} tok · ${String(e.latencyMs??0)} ms`})]})})}function it({attachment:e}){let t=qe(e);return t===null?null:l(`img`,{src:t,alt:`sent to the model`,className:`mt-1 max-h-32 rounded-md border border-border object-contain`})}function at({onPick:e}){let{t}=W(),n=v({isCamera:!0,projection:`slim`}),r=(n.data??[]).filter(e=>!e.disabled);return n.isLoading?l(K,{className:`h-4 w-4 animate-spin text-foreground-subtle`}):r.length===0?l(`p`,{className:`text-[11px] text-foreground-subtle`,children:t(`ai.noCameras`,`No camera found.`)}):l(`div`,{className:`grid max-h-56 grid-cols-2 gap-2 overflow-y-auto sm:grid-cols-4`,children:r.map(t=>l(ot,{device:t,onPick:e},t.id))})}function ot({device:e,onPick:t}){let{src:n}=f(e.id,{width:et});return r(`button`,{type:`button`,onClick:()=>t(e),className:`overflow-hidden rounded-md border border-border bg-surface text-left transition-colors hover:border-primary/50`,children:[l(`span`,{className:`block aspect-video w-full bg-background-elevated`,children:n!==null&&l(`img`,{src:n,alt:``,className:`h-full w-full object-cover`,loading:`lazy`})}),r(`span`,{className:`flex items-center gap-1 px-2 py-1`,children:[!e.online&&l(x,{variant:`warning`,children:`off`}),l(`span`,{className:`truncate text-[10px] text-foreground`,children:e.name})]})]})}function st({onPick:e}){let{t}=W(),n=d(),o=v({isCamera:!0,projection:`slim`}),s=i(()=>(o.data??[]).map(e=>e.id),[o.data]),c=i(()=>{let e=new Map;for(let t of o.data??[])e.set(t.id,t.name);return e},[o.data]),u=a({queryKey:[...Ze,s.length],enabled:s.length>0,queryFn:()=>n.trpcClient.pipelineAnalytics.listRecentTracks.query({deviceIds:[...s],since:Date.now()-Qe,limit:$e,projection:`slim`})});if(o.isLoading||u.isLoading)return l(K,{className:`h-4 w-4 animate-spin text-foreground-subtle`});let f=u.data?.tracks??[];return f.length===0?l(`p`,{className:`text-[11px] text-foreground-subtle`,children:t(`ai.noTracks`,`No track in the last 6 hours.`)}):l(`div`,{className:`max-h-56 divide-y divide-border overflow-y-auto rounded-md border border-border`,children:f.map(t=>r(`button`,{type:`button`,onClick:()=>e(t,c.get(t.deviceId)??String(t.deviceId)),className:`flex w-full items-center gap-2 px-2.5 py-1.5 text-left text-[11px] hover:bg-surface-hover`,children:[l(V,{className:`h-3.5 w-3.5 shrink-0 text-foreground-subtle`}),l(`span`,{className:`min-w-0 flex-1 truncate text-foreground`,children:t.label??t.className}),l(`span`,{className:`shrink-0 text-foreground-subtle`,children:c.get(t.deviceId)??t.deviceId}),l(`span`,{className:`shrink-0 text-foreground-subtle`,children:new Date(t.lastSeen).toLocaleTimeString()})]},t.trackId))})}n();var ct=1440*60*1e3,lt=[1,7,30,90];function ut(){let{t:e}=W(),t=d(),[n,o]=s(7),c=i(()=>{let e=new Date;return e.setHours(0,0,0,0),e.getTime()-(n-1)*ct},[n]),u=a({queryKey:se,queryFn:()=>t.trpcClient.llm.listProfiles.query({})}),f=a({queryKey:[...fe,n],queryFn:()=>t.trpcClient.llm.getUsage.query({since:c})}),m=i(()=>{let e=new Map;for(let t of u.data??[])e.set(t.id,t.name);return e},[u.data]),h=i(()=>[{key:`day`,header:e(`ai.colDay`,`Day`),nowrap:!0,render:e=>e.day},{key:`consumer`,header:e(`ai.colConsumer`,`Consumer`),nowrap:!0,render:e=>l(`span`,{className:`text-[11px] text-foreground`,children:e.consumer})},{key:`profile`,header:e(`ai.colProfile`,`Profile`),render:e=>l(`span`,{className:`text-[11px] text-foreground`,children:m.get(e.profileId)??e.profileId})},{key:`calls`,header:e(`ai.colCalls`,`Calls`),align:`right`,nowrap:!0,render:e=>String(e.calls)},{key:`okErr`,header:e(`ai.colOkErr`,`OK / err`),align:`right`,nowrap:!0,render:e=>l(`span`,{className:e.errorCalls>0?`text-danger`:void 0,children:`${String(e.okCalls)} / ${String(e.errorCalls)}`})},{key:`tokens`,header:e(`ai.colTokens`,`In / out tok`),align:`right`,nowrap:!0,render:e=>`${String(e.inputTokens)} / ${String(e.outputTokens)}`},{key:`latency`,header:e(`ai.colAvgMs`,`Avg ms`),align:`right`,nowrap:!0,render:e=>String(Math.round(e.avgLatencyMs))}],[m,e]),g=f.data??[];return r(q,{icon:z,title:e(`ai.usageTitle`,`Usage`),subtitle:e(`ai.usageSubtitle`,`Server-side rollup per day, consumer and profile — never raw call rows. Errors are counted, so a profile that always fails is visible here before a feature reports it.`),actions:l(`div`,{className:`w-40`,children:l(p,{"aria-label":e(`ai.window`,`Window`),value:String(n),options:lt.map(t=>({value:String(t),label:e(`ai.lastDays`,`Last {{days}} days`,{days:t})})),onChange:e=>o(Number(e.target.value))})}),children:[f.isError&&l(y,{title:e(`ai.usageFailed`,`Failed to read usage`),message:f.error instanceof Error?f.error.message:e(`common.error`,`Error`),onRetry:()=>void f.refetch()}),g.length===0?l(`div`,{className:`py-16 text-center text-xs text-foreground-subtle`,children:e(`ai.noUsage`,`No AI calls in this window.`)}):l(b,{children:l(k,{columns:h,rows:g,rowKey:e=>`${e.day}|${e.consumer}|${e.profileId}`,minWidthPx:720,bordered:!1,mobileMode:`scroll`,maxBodyHeight:O})})]})}function dt(){let{t:e}=W();return l(`div`,{className:`flex flex-col p-4`,children:l(ae,{tabs:[{id:`profiles`,label:e(`ai.tabProfiles`,`Profiles`),icon:M,content:l(Me,{})},{id:`runtimes`,label:e(`ai.tabRuntimes`,`Runtimes`),icon:I,content:l(Ie,{})},{id:`usage`,label:e(`ai.tabUsage`,`Usage`),icon:z,content:l(ut,{})},{id:`test`,label:e(`ai.tabTest`,`Test`),icon:P,content:l(tt,{})}]})})}export{dt as AiProfilesPage,dt as default};
|