@camstack/addon-admin-ui 1.2.258 → 1.2.260

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.
Files changed (97) hide show
  1. package/dist/assets/{AddonCollectionPage-BX0XnPQb.js → AddonCollectionPage-CS0TnWg9.js} +1 -1
  2. package/dist/assets/Addons-C30etjze.js +1 -0
  3. package/dist/assets/{AdminTabs-CSovnIie.js → AdminTabs-FTjDtV3h.js} +1 -1
  4. package/dist/assets/AiProfiles-mbAsm8w-.js +3 -0
  5. package/dist/assets/{BrokerForm-zK_8Dcox.js → BrokerForm-Q6_-XEV6.js} +1 -1
  6. package/dist/assets/Build-DEIHGbUT.js +32 -0
  7. package/dist/assets/{Capabilities-DZdGmm1p.js → Capabilities-BBNd5xr5.js} +1 -1
  8. package/dist/assets/{CapabilityBadges-dLW1TjJs.js → CapabilityBadges-CrEM9xUa.js} +1 -1
  9. package/dist/assets/Cluster-Bzkxl6x3.js +11 -0
  10. package/dist/assets/{Data-cuCuoZJZ.js → Data-TtTvLPLA.js} +1 -1
  11. package/dist/assets/DetectionIntelligence-DfTa4lpL.js +1 -0
  12. package/dist/assets/{DeviceAggregateSection-BgIHM0MP.js → DeviceAggregateSection-f6elW-hA.js} +1 -1
  13. package/dist/assets/DeviceDetail-2sfyugFO.js +2 -0
  14. package/dist/assets/{Devices-Ch6FOfuB.js → Devices-Co8wNAQR.js} +1 -1
  15. package/dist/assets/{EmbedPlayerPage-BErA2z2-.js → EmbedPlayerPage-C-PGfe8W.js} +1 -1
  16. package/dist/assets/Events-BoiEuALN.js +1 -0
  17. package/dist/assets/{FormBuilder-jIqGNdKD.js → FormBuilder-B3mdR0Gk.js} +1 -1
  18. package/dist/assets/Identity-CYZ21kQd.js +1 -0
  19. package/dist/assets/IntegrationDetail-DkvBX9o8.js +1 -0
  20. package/dist/assets/Integrations-CZio9vzA.js +1 -0
  21. package/dist/assets/Integrations-CxQSQ9fW.js +1 -0
  22. package/dist/assets/Locations-D0BRCdcK.js +2 -0
  23. package/dist/assets/{Logs-BM6XTKrt.js → Logs-zkWqa-Zv.js} +1 -1
  24. package/dist/assets/{MotionZonesSettings-CQX7yV3y.js → MotionZonesSettings-DPp47_Em.js} +1 -1
  25. package/dist/assets/{MyAccess-CJbXiIW5.js → MyAccess-BISLeGOK.js} +1 -1
  26. package/dist/assets/{Network-DPbXs8WB.js → Network-CopgOYrO.js} +1 -1
  27. package/dist/assets/{NodeAddonsSettingsPanel-D1mmPw8E.js → NodeAddonsSettingsPanel-B5y6dSOO.js} +1 -1
  28. package/dist/assets/{NodeInferenceDevices-BZT90g18.js → NodeInferenceDevices-MUCKntIr.js} +1 -1
  29. package/dist/assets/Notifications-C-euUn8Y.js +1 -0
  30. package/dist/assets/Pipeline-CRvLk6_r.js +1 -0
  31. package/dist/assets/Plates-ChoLztf-.js +1 -0
  32. package/dist/assets/{PrivacyMaskSettings-BAmYAzaT.js → PrivacyMaskSettings-Bt6X63Rt.js} +1 -1
  33. package/dist/assets/{ProviderIcon-DCDpuWgi.js → ProviderIcon-D9PLOXMZ.js} +1 -1
  34. package/dist/assets/Recordings-TgH0kxt8.js +1 -0
  35. package/dist/assets/{ScanNetworkModal-Cz8wK3Sf.js → ScanNetworkModal-lEnThbrW.js} +1 -1
  36. package/dist/assets/{SceneMonitorEditor-DxBU0nwK.js → SceneMonitorEditor-Coey7DkB.js} +1 -1
  37. package/dist/assets/{Scenes--ADmPstY.js → Scenes-DCGaMi0H.js} +1 -1
  38. package/dist/assets/{Settings-C9a74W-U.js → Settings-Cya6w94r.js} +1 -1
  39. package/dist/assets/{Showroom-JqyYWh5s.js → Showroom-CEIjIU3D.js} +1 -1
  40. package/dist/assets/{StorageLocationsPanel-Ch5YTeaG.js → StorageLocationsPanel-dpSl2bc_.js} +1 -1
  41. package/dist/assets/{Terminal-WhJmXhAV.js → Terminal-DYbduyac.js} +5 -5
  42. package/dist/assets/{Viewer-BUVuTunJ.js → Viewer-BCs5TInB.js} +1 -1
  43. package/dist/assets/{_virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-D3L9YkaA.js → _virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-BAEaiPOS.js} +1 -1
  44. package/dist/assets/{archive-BBd9Y5og.js → archive-BDAG8ZtC.js} +1 -1
  45. package/dist/assets/{authed-media-Cp17W-pc.js → authed-media-BgHAN7mo.js} +1 -1
  46. package/dist/assets/{boxes-B2dkI7tE.js → boxes-CGA7dQAX.js} +1 -1
  47. package/dist/assets/circle-slash-xqjuzvya.js +1 -0
  48. package/dist/assets/{debounced-invalidate-CL0RRPMu.js → debounced-invalidate-DUhUAjlV.js} +1 -1
  49. package/dist/assets/{dist-C9Mb2vEn.js → dist-CIB8yuhW.js} +1 -1
  50. package/dist/assets/dist-Cxb_X-h6.js +349 -0
  51. package/dist/assets/{face-bbox-CRCCB2nD.js → face-bbox-q-9rvLF7.js} +1 -1
  52. package/dist/assets/{hard-drive-download-CIHN2VkD.js → hard-drive-download-DXfQNx7b.js} +1 -1
  53. package/dist/assets/{hostInit-BsyyQBn2.js → hostInit-DHzuQRJh.js} +1 -1
  54. package/dist/assets/index-Dx7jiq4X.js +4 -0
  55. package/dist/assets/{layers-cSbXjXdl.js → layers-D-Qb89PK.js} +1 -1
  56. package/dist/assets/{location-owned-usage-BT2pmQo5.js → location-owned-usage-C-JLRZgq.js} +1 -1
  57. package/dist/assets/{mf-entry-bootstrap-0-0e59474f.js → mf-entry-bootstrap-0-19449b84.js} +2 -2
  58. package/dist/assets/{player-overlays-B82OVd2b.js → player-overlays-BHhXtyqA.js} +1 -1
  59. package/dist/assets/remoteEntry-BnoRpCyV.js +1 -0
  60. package/dist/assets/{send-BUidPUKy.js → send-DtWddy40.js} +1 -1
  61. package/dist/assets/{settings-2-CoiJ1-tg.js → settings-2-a-fUhkjD.js} +1 -1
  62. package/dist/assets/{square-check-big-BeLRKn52.js → square-check-big-DBadJoiu.js} +1 -1
  63. package/dist/assets/src-D1KVMjXF.js +67 -0
  64. package/dist/assets/src-DJhS86y-.js +349 -0
  65. package/dist/assets/{use-scenes-feed-BOjzOiOU.js → use-scenes-feed-Cgbz38uA.js} +1 -1
  66. package/dist/assets/{use-stationary-objects-Bd9Ou1yp.js → use-stationary-objects-NIqG_ma3.js} +1 -1
  67. package/dist/assets/useEventInvalidation-DE-QGHTV.js +1 -0
  68. package/dist/assets/{useNodeUrlSelection-GaFsaq3Y.js → useNodeUrlSelection-CjOpKTO_.js} +1 -1
  69. package/dist/assets/user-round-BFvKN2vL.js +1 -0
  70. package/dist/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-ta66_Q-u.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-CXmVBdRr.js} +2 -2
  71. package/dist/index.html +5 -5
  72. package/dist/server/addon.js +243 -21
  73. package/package.json +1 -1
  74. package/dist/assets/Addons-BDOOkMuS.js +0 -1
  75. package/dist/assets/AiProfiles-E5IAsm2S.js +0 -3
  76. package/dist/assets/Build-BtjCenWS.js +0 -32
  77. package/dist/assets/Cluster-BbNceUht.js +0 -11
  78. package/dist/assets/DetectionIntelligence-G7lCcALp.js +0 -1
  79. package/dist/assets/DeviceDetail-BdOqOqTl.js +0 -2
  80. package/dist/assets/Events-CgOvlHhY.js +0 -1
  81. package/dist/assets/Identity-BWdkMiVS.js +0 -1
  82. package/dist/assets/IntegrationDetail-BIjcJOw8.js +0 -1
  83. package/dist/assets/Integrations-5qB154Mm.js +0 -1
  84. package/dist/assets/Integrations-CR7lMMFk.js +0 -1
  85. package/dist/assets/Locations-BCTsz8p1.js +0 -1
  86. package/dist/assets/Notifications-Df8BJ8WO.js +0 -1
  87. package/dist/assets/Pipeline-DAOklLn2.js +0 -1
  88. package/dist/assets/Plates-CQi1FcSU.js +0 -1
  89. package/dist/assets/Recordings-CqoxOlE1.js +0 -1
  90. package/dist/assets/circle-slash-Beg_P0an.js +0 -1
  91. package/dist/assets/dist-B8NLJMCh.js +0 -349
  92. package/dist/assets/index-BpiZqZOx.js +0 -4
  93. package/dist/assets/remoteEntry-Boe6tAc9.js +0 -1
  94. package/dist/assets/src-8XVcukAG.js +0 -349
  95. package/dist/assets/src-jk2FdB5v.js +0 -67
  96. package/dist/assets/useEventInvalidation-WjkWP5Gl.js +0 -1
  97. package/dist/assets/user-round-C782gYyr.js +0 -1
@@ -5361,7 +5361,7 @@ var ZodIssueCode = {
5361
5361
  var ZodFirstPartyTypeKind;
5362
5362
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5363
5363
  //#endregion
5364
- //#region ../types/dist/sleep-PEo0-Fz9.mjs
5364
+ //#region ../types/dist/sleep-pM_J7YnY.mjs
5365
5365
  /**
5366
5366
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5367
5367
  * window to float samples (D455).
@@ -16553,6 +16553,7 @@ sub("presence", "sensor", "sensor", "#22c55e", "presence", "Presence");
16553
16553
  sub("enum-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "generic", "Sensor state");
16554
16554
  sub("device-event", "sensor", "sensor", "#10b981", "button", "Device event");
16555
16555
  sub("lock", "control", "control", "#0ea5e9", "lock", "Lock");
16556
+ sub("cover", "control", "control", "#0ea5e9", "door", "Cover");
16556
16557
  sub("switch", "control", "control", TAXONOMY_COLORS.control, "switch", "Switch");
16557
16558
  sub("siren", "control", "control", "#dc2626", "siren", "Siren");
16558
16559
  sub("button", "control", "control", "#10b981", "button", "Button");
@@ -16833,6 +16834,10 @@ var NcSystemEventKindSchema = _enum([
16833
16834
  "alarm-disarmed",
16834
16835
  "alarm-arming",
16835
16836
  "alarm-arm-refused",
16837
+ "alarm-pending",
16838
+ "alarm-rearmed",
16839
+ "alarm-sensor-bypass",
16840
+ "alarm-check-failed",
16836
16841
  "addon-updated",
16837
16842
  "server-updated",
16838
16843
  "export-completed",
@@ -17428,6 +17433,19 @@ var NcMediaFrameSchema = _enum([
17428
17433
  "full",
17429
17434
  "boxed"
17430
17435
  ]);
17436
+ /**
17437
+ * How a SENSOR notification shows the cameras that link the sensor.
17438
+ *
17439
+ * `mosaic` — one image composed of every linked camera's photograph, taken at
17440
+ * the trigger. `each` — one image per camera where the target takes several
17441
+ * attachments; a target that takes one keeps the first camera's (the degrade
17442
+ * engine drops the rest by order). Either way ONE notification per event.
17443
+ * Absent = `mosaic`, applied by the Notification Center and deliberately NOT
17444
+ * a Zod default (see NcRulePatchSchema: a default materialises on every
17445
+ * partial patch). Meaningless for a rule whose subject is not a sensor, and a
17446
+ * sensor linked to one camera ships that camera's plain snapshot either way.
17447
+ */
17448
+ var NcLinkedCameraModeSchema = _enum(["mosaic", "each"]);
17431
17449
  var NcMediaPolicySchema = object({
17432
17450
  attach: _enum([
17433
17451
  "best",
@@ -17473,7 +17491,9 @@ var NcMediaPolicySchema = object({
17473
17491
  * A profile that is not assigned falls back to the cheapest, and the render
17474
17492
  * reports which one actually ran.
17475
17493
  */
17476
- profile: CamProfileSchema.optional()
17494
+ profile: CamProfileSchema.optional(),
17495
+ /** See {@link NcLinkedCameraModeSchema}. */
17496
+ linkedCameras: NcLinkedCameraModeSchema.optional()
17477
17497
  });
17478
17498
  /**
17479
17499
  * Cooldown GRANULARITY over the subject's class — how much a fired
@@ -17593,7 +17613,7 @@ var NcRuleInputSchema = object({
17593
17613
  cooldownSec: 60,
17594
17614
  scope: "rule-device"
17595
17615
  }),
17596
- /** `{{var}}` templating over camera/class/label/zones/confidence/time. */
17616
+ /** `{{var}}` title/body. The variables are declared in `NC_TEMPLATE_VARS` (@camstack/types) and depend on the rule kind — see `templateVarsFor`. */
17597
17617
  template: object({
17598
17618
  title: string().max(500).optional(),
17599
17619
  body: string().max(2e3).optional()
@@ -17773,6 +17793,22 @@ var NcRulePatchSchema = NcRuleInputSchema.partial().extend({
17773
17793
  throttle: NcThrottleSchema.optional(),
17774
17794
  priority: number().int().min(1).max(5).optional()
17775
17795
  });
17796
+ var NcRuleClearableKeySchema = _enum([
17797
+ "template",
17798
+ "schedule",
17799
+ "targetUsers",
17800
+ "snoozeOptions",
17801
+ "snoozeAllowGlobal",
17802
+ "waitForEnhancement",
17803
+ "actions",
17804
+ "confirm",
17805
+ "groupIdleSec"
17806
+ ]);
17807
+ var NcRuleUpdateInputSchema = object({
17808
+ ruleId: string(),
17809
+ patch: NcRulePatchSchema,
17810
+ clear: array(NcRuleClearableKeySchema).optional()
17811
+ });
17776
17812
  /** A persisted rule. */
17777
17813
  var NcRuleSchema = NcRuleInputSchema.extend({
17778
17814
  id: string(),
@@ -17804,6 +17840,85 @@ var NcTestResultSchema = object({
17804
17840
  className: string().optional(),
17805
17841
  label: string().optional()
17806
17842
  });
17843
+ /** The five rule kinds, as data. `NcRuleKind` in `notification/rule-kinds.ts`
17844
+ * is the same union; the template-vars spec pins the two together. */
17845
+ var NcRuleKindSchema = _enum([
17846
+ "detection",
17847
+ "sensor",
17848
+ "occupancy",
17849
+ "sound",
17850
+ "system"
17851
+ ]);
17852
+ /** Which producer renders a template: an ordinary rule, a timelapse, a digest. */
17853
+ var NcTemplateFamilySchema = _enum([
17854
+ "rule",
17855
+ "timelapse",
17856
+ "summary"
17857
+ ]);
17858
+ /** Which text field of that producer. `previewText` is the timelapse frame
17859
+ * caption, `captionText` the digest mosaic caption — both see fewer vars. */
17860
+ var NcTemplateFieldSchema = _enum([
17861
+ "title",
17862
+ "body",
17863
+ "previewText",
17864
+ "captionText"
17865
+ ]);
17866
+ var NcTemplateVarGroupSchema = _enum([
17867
+ "subject",
17868
+ "place",
17869
+ "time",
17870
+ "rule",
17871
+ "occupancy",
17872
+ "sound",
17873
+ "sensor",
17874
+ "system",
17875
+ "digest",
17876
+ "ai"
17877
+ ]);
17878
+ /**
17879
+ * ONE `{{var}}` a notification template may name.
17880
+ *
17881
+ * `families` / `fields` / `kinds` / `deliveries` / `systemEventKinds` say WHERE
17882
+ * it has a value; absent = no restriction on that axis. `systemEventKinds` is
17883
+ * read only for a `system` rule. `dynamic` declares a FAMILY of names
17884
+ * (`count_<class>`): the descriptor's `name` is the example member.
17885
+ */
17886
+ var NcTemplateVarDescriptorSchema = object({
17887
+ name: string().regex(/^\w+$/),
17888
+ label: string(),
17889
+ description: string().optional(),
17890
+ example: string(),
17891
+ group: NcTemplateVarGroupSchema,
17892
+ families: array(NcTemplateFamilySchema).min(1),
17893
+ fields: array(NcTemplateFieldSchema).optional(),
17894
+ kinds: array(NcRuleKindSchema).optional(),
17895
+ deliveries: array(NcDeliverySchema).optional(),
17896
+ systemEventKinds: array(NcSystemEventKindSchema).optional(),
17897
+ dynamic: object({
17898
+ prefix: literal("count_"),
17899
+ from: literal("classes")
17900
+ }).optional()
17901
+ });
17902
+ /** Input to `previewTemplate` — the editor's own context, plus the draft text. */
17903
+ var NcTemplatePreviewInputSchema = object({
17904
+ context: object({
17905
+ family: NcTemplateFamilySchema,
17906
+ field: NcTemplateFieldSchema,
17907
+ kind: NcRuleKindSchema.optional(),
17908
+ delivery: NcDeliverySchema.optional(),
17909
+ systemEventKinds: array(NcSystemEventKindSchema).optional()
17910
+ }),
17911
+ template: object({
17912
+ title: string().max(500).optional(),
17913
+ body: string().max(2e3).optional()
17914
+ })
17915
+ });
17916
+ var NcTemplatePreviewSchema = object({
17917
+ title: string().nullable(),
17918
+ body: string().nullable(),
17919
+ /** Names the template uses that this context never fills — they render empty. */
17920
+ unknown: array(string())
17921
+ });
17807
17922
  var NcConditionDescriptorSchema = object({
17808
17923
  /** Field id inside `NcConditions` (or `'schedule'` for the rule-level group). */
17809
17924
  id: string(),
@@ -18069,8 +18184,17 @@ object({
18069
18184
  lastAt: number()
18070
18185
  });
18071
18186
  /**
18072
- * The three durations the panel's state machine runs on, plus who hears about
18073
- * an arm.
18187
+ * The per-mode lists, at most one per mode. Two lists for one mode have no
18188
+ * meaning a reader could agree on (union? the last one?), so they are refused
18189
+ * at the boundary rather than interpreted.
18190
+ */
18191
+ var NcAlarmNonBlockingListSchema = array(object({
18192
+ mode: AlarmArmModeSchema,
18193
+ deviceIds: array(number().int()).max(200)
18194
+ })).max(8).refine((lists) => new Set(lists.map((l) => l.mode)).size === lists.length, { message: "nonBlocking: at most one list per arm mode" });
18195
+ /**
18196
+ * The three durations the panel's state machine runs on, who hears about its
18197
+ * transitions, and which openings each mode tolerates.
18074
18198
  *
18075
18199
  * They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
18076
18200
  * `alarm-panel` is `deviceNative` and its other provider mirrors somebody
@@ -18089,21 +18213,39 @@ var NcAlarmSettingsSchema = object({
18089
18213
  * existed, and therefore what an untouched install keeps doing.
18090
18214
  */
18091
18215
  triggeredDurationSec: number().int().min(0).max(3600),
18092
- /** Send a notification when a mode takes effect. */
18093
- announceArm: boolean(),
18094
18216
  /**
18095
- * Where that notification goes. Target ids from `notification-output`.
18217
+ * Deprecated by D630 — every transition is announced. Parsed, never read;
18218
+ * remove after one release. Optional so an older admin's patch (which still
18219
+ * sends it) parses rather than failing the whole save.
18220
+ */
18221
+ announceArm: boolean().optional(),
18222
+ /**
18223
+ * Target ids from `notification-output`: every alarm transition goes here.
18096
18224
  *
18097
- * Explicit rather than "everyone": an arm announcement is a household
18225
+ * Explicit rather than "everyone": an alarm announcement is a household
18098
18226
  * message, and broadcasting it to every configured endpoint (including a
18099
18227
  * webhook wired to something else) is not a default anybody would choose.
18100
- * Empty with `announceArm: true` sends nothing, and the server logs that —
18101
- * silence must be attributable.
18228
+ * Empty sends nothing, and the server logs that — silence must be
18229
+ * attributable.
18102
18230
  */
18103
- announceTargets: array(string().min(1)).max(16)
18231
+ announceTargets: array(string().min(1)).max(16),
18232
+ /**
18233
+ * Per arm mode, the covered devices whose being OPEN does not refuse the
18234
+ * arm (a window left ajar for the cat under `home`, say). At most one entry
18235
+ * per mode is meaningful. Defaulted to `[]` so a blob stored before D630
18236
+ * parses as "every opening blocks" — the behaviour it was written under.
18237
+ */
18238
+ nonBlocking: NcAlarmNonBlockingListSchema.default([])
18104
18239
  });
18105
- /** Every field optional — a tab edits one control at a time. */
18106
- var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.partial();
18240
+ /**
18241
+ * Every field optional — a tab edits one control at a time.
18242
+ *
18243
+ * `nonBlocking` is re-declared WITHOUT its default: `.partial()` does not
18244
+ * remove an inner `.default()`, so a patch that never named the field would
18245
+ * parse to `nonBlocking: []` and wipe every mode's list on an unrelated edit
18246
+ * (the same trap {@link NcRulePatchSchema} documents).
18247
+ */
18248
+ var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({ nonBlocking: NcAlarmNonBlockingListSchema }).partial();
18107
18249
  /**
18108
18250
  * What one arm mode actually arms, DERIVED from the enabled rules gated on it.
18109
18251
  * Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
@@ -18148,6 +18290,36 @@ var NcAlarmModeCoverageSchema = object({
18148
18290
  */
18149
18291
  skippedDevices: array(NcAlarmSkippedDeviceSchema).default([])
18150
18292
  });
18293
+ /** One covered device that reads open, and whether that refuses the arm. */
18294
+ var NcAlarmOpeningSchema = object({
18295
+ deviceId: number().int(),
18296
+ name: string(),
18297
+ /** The device's state word as read (`open`, `unlocked`, …). */
18298
+ state: string(),
18299
+ /** False when the mode's non-blocking list names this device. */
18300
+ blocking: boolean()
18301
+ });
18302
+ /** A device the panel is currently ignoring, and which side of it it is on. */
18303
+ var NcAlarmExclusionViewSchema = object({
18304
+ deviceId: number().int(),
18305
+ name: string(),
18306
+ phase: _enum(["open", "closed"])
18307
+ });
18308
+ /** One mode's openings: devices read open, plus those whose state is unknown. */
18309
+ var NcAlarmModeOpeningsSchema = object({
18310
+ mode: AlarmArmModeSchema,
18311
+ devices: array(NcAlarmOpeningSchema),
18312
+ /** Covered devices whose state could not be read (D49): neither open nor closed. */
18313
+ unknown: array(number().int())
18314
+ });
18315
+ var NcAlarmLiveSchema = object({
18316
+ state: AlarmStateSchema,
18317
+ /** The mode being armed into (exit delay) or held; null when disarmed. */
18318
+ targetMode: AlarmArmModeSchema.nullable(),
18319
+ availableModes: array(AlarmArmModeSchema),
18320
+ openings: array(NcAlarmModeOpeningsSchema),
18321
+ exclusions: array(NcAlarmExclusionViewSchema)
18322
+ });
18151
18323
  var NcAlarmConfigSchema = object({
18152
18324
  /**
18153
18325
  * The panel's device id, or null when this install has no panel (the ensure
@@ -18157,7 +18329,13 @@ var NcAlarmConfigSchema = object({
18157
18329
  */
18158
18330
  deviceId: number().int().nullable(),
18159
18331
  settings: NcAlarmSettingsSchema,
18160
- coverage: array(NcAlarmModeCoverageSchema)
18332
+ coverage: array(NcAlarmModeCoverageSchema),
18333
+ /**
18334
+ * The panel as it is NOW — state, what each mode would find open, what is
18335
+ * excluded. Optional: a panel-less hub answers without it, and a client
18336
+ * must not read its absence as "nothing is open".
18337
+ */
18338
+ live: NcAlarmLiveSchema.optional()
18161
18339
  });
18162
18340
  /**
18163
18341
  * ONE rule's demand on ONE camera's clip ring.
@@ -18205,10 +18383,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
18205
18383
  kind: "mutation",
18206
18384
  auth: "admin",
18207
18385
  caller: "required"
18208
- }), method(object({
18209
- ruleId: string(),
18210
- patch: NcRulePatchSchema
18211
- }), object({ rule: NcRuleSchema }), {
18386
+ }), method(NcRuleUpdateInputSchema, object({ rule: NcRuleSchema }), {
18212
18387
  kind: "mutation",
18213
18388
  auth: "admin",
18214
18389
  caller: "required"
@@ -18236,7 +18411,10 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
18236
18411
  }), method(object({}), object({
18237
18412
  catalog: array(NcConditionDescriptorSchema),
18238
18413
  taxonomy: NcTaxonomySchema.optional()
18239
- })), method(object({ filter: NcHistoryFilterSchema.default({ limit: 100 }) }), object({ entries: array(NcHistoryEntrySchema) }), { auth: "admin" }), method(object({ artifactId: string().min(1) }), object({ url: string().nullable() }), { auth: "admin" }), method(object({}), object({ snoozes: array(NcSnoozeSchema) }), { caller: "required" }), method(object({ snooze: NcSnoozeInputSchema }), object({ snooze: NcSnoozeSchema }), {
18414
+ })), method(object({}), object({ vars: array(NcTemplateVarDescriptorSchema) })), method(NcTemplatePreviewInputSchema, NcTemplatePreviewSchema, {
18415
+ kind: "mutation",
18416
+ access: "view"
18417
+ }), method(object({ filter: NcHistoryFilterSchema.default({ limit: 100 }) }), object({ entries: array(NcHistoryEntrySchema) }), { auth: "admin" }), method(object({ artifactId: string().min(1) }), object({ url: string().nullable() }), { auth: "admin" }), method(object({}), object({ snoozes: array(NcSnoozeSchema) }), { caller: "required" }), method(object({ snooze: NcSnoozeInputSchema }), object({ snooze: NcSnoozeSchema }), {
18240
18418
  kind: "mutation",
18241
18419
  caller: "required"
18242
18420
  }), method(object({ snoozeId: string() }), object({ success: literal(true) }), {
@@ -22669,6 +22847,7 @@ var CAP_TO_KIND = {
22669
22847
  "enum-sensor": "enum-sensor",
22670
22848
  "event-emitter": "device-event",
22671
22849
  "lock-control": "lock",
22850
+ cover: "cover",
22672
22851
  switch: "switch",
22673
22852
  button: "button",
22674
22853
  doorbell: "doorbell"
@@ -37995,6 +38174,12 @@ Object.freeze({
37995
38174
  addonId: null,
37996
38175
  access: "view"
37997
38176
  },
38177
+ "notificationRules.getTemplateCatalog": {
38178
+ capName: "notification-rules",
38179
+ capScope: "system",
38180
+ addonId: null,
38181
+ access: "view"
38182
+ },
37998
38183
  "notificationRules.listDeviceMutes": {
37999
38184
  capName: "notification-rules",
38000
38185
  capScope: "system",
@@ -38013,6 +38198,12 @@ Object.freeze({
38013
38198
  addonId: null,
38014
38199
  access: "view"
38015
38200
  },
38201
+ "notificationRules.previewTemplate": {
38202
+ capName: "notification-rules",
38203
+ capScope: "system",
38204
+ addonId: null,
38205
+ access: "view"
38206
+ },
38016
38207
  "notificationRules.resolveArtifactUrl": {
38017
38208
  capName: "notification-rules",
38018
38209
  capScope: "system",
@@ -43580,6 +43771,37 @@ var NC_AUDIO_DEFAULTS = {
43580
43771
  };
43581
43772
  new Set(["devices", "classes"]);
43582
43773
  NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
43774
+ var RULE_BODY_ONLY = ["body"];
43775
+ var RULE_TEXT = ["title", "body"];
43776
+ var BATTERY = ["device-battery-low", "device-battery-normal"];
43777
+ var CONSUMABLE = ["device-consumable-low", "device-consumable-normal"];
43778
+ var UPDATES = [
43779
+ "addon-update-available",
43780
+ "server-update-available",
43781
+ "wrapper-update-available"
43782
+ ];
43783
+ var PACKAGE_UPDATES = ["addon-update-available", "server-update-available"];
43784
+ var ALARM = [
43785
+ "alarm-triggered",
43786
+ "alarm-armed",
43787
+ "alarm-disarmed",
43788
+ "alarm-arming",
43789
+ "alarm-arm-refused"
43790
+ ];
43791
+ var COMBINED_ALARM = ["alarm-triggered"];
43792
+ var DEVICE_EVENTS = [
43793
+ "device-online",
43794
+ "device-offline",
43795
+ "device-disabled",
43796
+ "device-enabled",
43797
+ ...BATTERY,
43798
+ ...CONSUMABLE,
43799
+ "stream-online",
43800
+ "stream-offline",
43801
+ "detection-blind",
43802
+ ...ALARM
43803
+ ];
43804
+ [...DEVICE_EVENTS], [...RULE_TEXT], [...COMBINED_ALARM], [...RULE_TEXT], [...COMBINED_ALARM], [...RULE_TEXT], [...RULE_TEXT], [...COMBINED_ALARM], [...RULE_TEXT], [...PACKAGE_UPDATES], [...RULE_TEXT], [...RULE_TEXT], [...COMBINED_ALARM], [...RULE_TEXT], [...COMBINED_ALARM], [...RULE_TEXT], [...COMBINED_ALARM], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_BODY_ONLY], [...RULE_TEXT], [...RULE_TEXT], [...DEVICE_EVENTS], [...RULE_TEXT], [...DEVICE_EVENTS], [...RULE_TEXT], [...BATTERY, ...CONSUMABLE], [...RULE_TEXT], [...CONSUMABLE], [...RULE_TEXT], [...RULE_TEXT], [...UPDATES], [...RULE_TEXT], [...UPDATES], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...UPDATES], [...RULE_TEXT], [...PACKAGE_UPDATES], [...RULE_TEXT], [...PACKAGE_UPDATES], [...RULE_TEXT], [...UPDATES], [...RULE_TEXT], [...UPDATES], [...RULE_TEXT], [...PACKAGE_UPDATES], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT], [...RULE_TEXT];
43583
43805
  /**
43584
43806
  * TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
43585
43807
  *
@@ -44074,7 +44296,7 @@ var AdminUIAddon = class extends BaseAddon {
44074
44296
  capability: adminUiCapability,
44075
44297
  provider: {
44076
44298
  getStaticDir: async () => ({ staticDir: resolveAdminUiDistDir() }),
44077
- getVersion: async () => ({ version: "1.2.258" })
44299
+ getVersion: async () => ({ version: "1.2.260" })
44078
44300
  }
44079
44301
  }];
44080
44302
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-admin-ui",
3
- "version": "1.2.258",
3
+ "version": "1.2.260",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Admin UI — Vite frontend build and server-side addon",
@@ -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{Z as d,gt as f,st as p,vt as m}from"./player-overlays-B82OVd2b.js";import{$ as h,$n as ee,Bn as g,Ea as _,Ec as v,Fn as y,Gn as b,Hn as x,Il as S,In as C,Jn as w,Ln as te,Mn as ne,Pn as re,Q as ie,Qn as T,Rc as E,Rn as D,Sc as O,Sl as ae,Su as k,T as oe,Tl as A,Un as se,Wn as j,Xn as M,Yn as N,_ as P,_l as F,_u as I,bu as ce,cl as L,dl as le,er as ue,fu as R,hn as de,iu as z,qn as B,tl as V,ul as fe,yc as H,zn as pe}from"./src-jk2FdB5v.js";import{nn as U}from"./src-8XVcukAG.js";import{a as me,d as W,s as he}from"./index-BpiZqZOx.js";import{t as G}from"./AdminPage-CiKtOLQm.js";import{t as ge}from"./NodeAddonsSettingsPanel-D1mmPw8E.js";import{r as K,t as q}from"./useNodeUrlSelection-GaFsaq3Y.js";var J=m(`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`}]]);n();var Y=new Set([`completed`,`failed`,`partially-failed`,`cancelled`]),_e=new Set([`done`,`failed`,`skipped`]);function X(e){return!_e.has(e.phase)&&!Y.has(e.jobState)}function Z(e,t){let n=new Map,r=[...e].sort((e,t)=>e.createdAtMs-t.createdAtMs);for(let e of r){let r=Y.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 ve(){let{data:e}=x({activeOnly:!0},{refetchOnWindowFocus:!1,refetchInterval:e=>(e.state.data?.length??0)>0?3e3:!1}),{map:t}=O(U.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 Z([...n.values()],Date.now())},[e,t])}var ye={queued:{icon:R,cls:`bg-muted text-foreground-subtle`,label:`queued`},fetching:{icon:S,cls:`bg-primary/10 text-primary`,label:`fetching`,spin:!0},staged:{icon:S,cls:`bg-primary/10 text-primary`,label:`staged`,spin:!0},validating:{icon:S,cls:`bg-primary/10 text-primary`,label:`validating`,spin:!0},applying:{icon:S,cls:`bg-primary/10 text-primary`,label:`applying`,spin:!0},restarting:{icon:S,cls:`bg-amber-500/10 text-amber-600 dark:text-amber-400`,label:`restarting`,spin:!0},applied:{icon:S,cls:`bg-primary/10 text-primary`,label:`finalizing`,spin:!0},done:{icon:k,cls:`bg-success/10 text-success`,label:`updated`},failed:{icon:J,cls:`bg-danger/10 text-danger`,label:`failed`},skipped:{icon:V,cls:`bg-muted text-foreground-subtle`,label:`skipped`}};function be({progress:e}){let t=ye[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 xe({packageName:e,currentVersion:t,installSource:n,onInstall:r,onClose:a,onSelect:s,selectedVersion:c}){let u=n===`upload`||n===`local`,{data:d,isLoading:f}=D({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(v,{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(E,{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(S,{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(k,{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(k,{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(z,{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 Se={queued:{icon:R,bg:`bg-muted text-foreground-subtle`,label:`queued`},updating:{icon:S,bg:`bg-primary/10 text-primary`,label:`updating`,spin:!0},"done-pending-restart":{icon:F,bg:`bg-amber-500/10 text-amber-700`,label:`pending restart`},done:{icon:k,bg:`bg-success/10 text-success`,label:`done`},failed:{icon:J,bg:`bg-danger/10 text-danger`,label:`failed`}};function Q({item:e}){let t=Se[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 Ce=`device-export`;function we(e){return e.capabilities.some(e=>(typeof e==`string`?e:e.name)===Ce)}function Te({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,f=e?`bg-indigo-500/20 text-indigo-700 dark:text-indigo-300`:`bg-purple-500/20 text-purple-700 dark:text-purple-300`,p=n&&r?d(`/api/addon-assets/${n}/${r}`):null,m=!!p&&!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?``:f}`,style:u,children:m?l(`img`,{src:p,alt:n,className:`h-5 w-5`,onError:()=>s(!0)}):l(e?A:W,{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(E,{className:`h-2.5 w-2.5 text-white`})})]})}function Ee({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(S,{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(z,{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(f,{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(f,{className:`h-3 w-3 opacity-50`})]}),u]})}function De({addonId:e}){let t=s(),{data:n=`inherit`}=y({addonId:e}),r=N({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 Oe({addon:e,agents:t=[],clusterStatus:n,hideVersion:r,availableUpdate:a,onUpdate:d,isUpdating:m,jobProgress:g,bundle:_,bulkItem:y,disabledByBulk:x,isSystem:S}){let[C,w]=c(!1),[te,ne]=c(!1),[re,T]=c(!1),[E,D]=c(null);u(()=>{D(null)},[a]);let O=E??a,[k,se]=c(!1),[j,M]=c(!1),[N,P]=c(`logs`),I=s(),ue=me(),R=de(),{manifest:z}=e,V=e.installedOn??[],fe=!_&&!z.protected&&z.removable!==!1,H=!!_,U=_?.displayName??z.name,W=_?.packageName??z.packageName,he=_?.version??z.packageVersion??z.version,G=_?.installSource??e.installSource,K=_?_.bundle?.description??_.addons[0]?.manifest.description:z.description,q=ee({onSuccess:()=>{I.invalidateQueries({queryKey:[[`addons`]]}),I.invalidateQueries({queryKey:[[`addonPages`]]}),I.invalidateQueries({queryKey:[[`capabilities`]]})}}),Y=b({onSuccess:()=>{I.invalidateQueries({queryKey:[[`addons`]]})}}),_e=pe({onSuccess:()=>{I.invalidateQueries({queryKey:[[`addons`]]}),I.invalidateQueries({queryKey:[[`addonPages`]]}),I.invalidateQueries({queryKey:[[`capabilities`]]}),I.invalidateQueries({queryKey:[[`integrations`]]})}}),X=B({onSuccess:()=>{I.invalidateQueries({queryKey:[[`addons`]]}),I.invalidateQueries({queryKey:[[`alerts`]]})}}),Z=e.health,ve=Z?.phase===`failed`&&!Z.inGracePeriod,ye=ve&&Z?.nextRetryAt&&!Z.retrying;return i(`div`,{className:`rounded-lg border bg-surface overflow-hidden ${ve?`border-red-500/50`:`border-border`}`,children:[ve&&Z&&i(`div`,{className:`bg-danger/10 border-b border-danger/30 px-4 py-2.5 flex items-start gap-2.5`,children:[l(J,{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 #`,Z.retryCount,`)`]}),l(`div`,{className:`text-[11px] text-foreground mt-0.5 break-words font-mono`,children:Z.lastError?.message??`Unknown error`}),ye&&Z.nextRetryAt&&i(`div`,{className:`text-[10px] text-foreground-subtle mt-1`,children:[`Auto-retry at `,new Date(Z.nextRetryAt).toLocaleTimeString()]})]}),i(`button`,{type:`button`,disabled:X.isPending||Z.retrying,onClick:e=>{e.stopPropagation(),X.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(F,{className:`h-3 w-3 ${X.isPending||Z.retrying?`animate-spin`:``}`}),`Retry now`]})]}),i(`div`,{className:`flex items-start gap-3 px-4 py-3`,children:[l(Te,{isBundle:H||!!z.components&&z.components.length>1,installSource:G,addonId:H?_.addons[0]?.manifest.id:z.id,iconPath:H?_.bundle?.icon??_.addons[0]?.manifest.icon:z.icon,color:H?_.addons[0]?.manifest.color:z.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:U}),!r&&l(Ee,{version:he,availableUpdate:a,...O===void 0?{}:{selectedVersion:O},isUpdating:m,installSource:G,disabled:x,...d&&O!==void 0?{onUpdate:()=>d(O)}:{},onOpenPicker:()=>T(e=>!e),children:re&&l(xe,{packageName:W,currentVersion:he,...G?{installSource:G}:{},...a!==void 0&&O!==void 0?{selectedVersion:O,onSelect:e=>{D(e),T(!1)}}:{},onInstall:e=>{T(!1),_e.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!==U&&l(`span`,{className:`text-[10px] text-foreground-subtle font-mono truncate max-w-full`,children:W}),H&&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(A,{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(F,{className:`h-3 w-3`}),`System`]}),y!=null&&l(Q,{item:y}),g!=null&&l(be,{progress:g})]}),K&&l(`p`,{className:`text-[10px] text-foreground-subtle mt-1 line-clamp-1`,children:K}),!H&&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})]})]})]}),!H&&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(),Y.mutate({addonId:z.id})},disabled:Y.isPending||x,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(F,{className:`h-3 w-3 ${Y.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 ${k?`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(le,{className:`h-3 w-3`}),`Logs`]}),!H&&i(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),M(!0)},className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium border transition-colors ${j?`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`}),fe&&i(`button`,{type:`button`,onClick:async e=>{e.stopPropagation(),await R({title:`Uninstall ${z.name}?`,message:`This will remove the addon package and all its data. This action cannot be undone.`,confirmLabel:`Uninstall`,variant:`danger`})&&q.mutate({packageName:z.packageName})},disabled:q.isPending||x,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(p,{className:`h-3 w-3`}),q.isPending?`Removing...`:`Uninstall`]})]}),n&&n.nodes.length>1&&!H&&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))})]}),k&&!H&&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:()=>P(`logs`),className:`px-2 py-0.5 transition-colors ${N===`logs`?`bg-primary/10 text-primary`:`text-foreground-subtle hover:bg-surface-hover`}`,children:`Logs`}),l(`button`,{type:`button`,onClick:()=>P(`events`),className:`px-2 py-0.5 border-l border-border transition-colors ${N===`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(v,{className:`h-3.5 w-3.5`})})]}),N===`logs`&&l(h,{addonId:z.id,maxHeight:`max-h-64`,showFilters:!1}),N===`events`&&l(ie,{addonId:z.id,category:`addon.*`,maxHeight:`max-h-64`})]}),H&&i(o,{children:[l(`button`,{type:`button`,onClick:()=>w(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?ce:f,{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(Oe,{addon:e,agents:t,hideVersion:!0},e.manifest.id))})]}),j&&!H&&l(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm p-4`,onClick:()=>M(!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:[U,` Settings`]})]}),l(`button`,{onClick:()=>M(!1),className:`text-foreground-subtle hover:text-foreground transition-colors p-1 rounded`,children:l(v,{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(ge,{nodeId:null,addonIds:[z.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.`}),we(z)&&i(`div`,{children:[l(`div`,{className:`text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-2`,children:`Device export`}),l(oe,{addonId:z.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(De,{addonId:z.id})]}),z.components&&z.components.length>0&&i(`div`,{children:[i(`div`,{className:`text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-2`,children:[`Components (`,z.components.length,`)`]}),l(`div`,{className:`flex flex-wrap gap-1`,children:z.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:[V.length===0&&l(`span`,{className:`text-[10px] text-foreground-subtle`,children:`Hub (local)`}),V.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(),ne(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(ae,{className:`h-3 w-3`}),`Add agent`]}),te&&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&&!V.includes(e.name)).map(e=>l(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),ne(!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&&!V.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:()=>M(!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 ke=`.tgz,.tar.gz,.zip`;function Ae({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(d(`/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:ke,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(S,{className:`w-3.5 h-3.5 animate-spin`}):l(E,{className:`w-3.5 h-3.5`}),r?`Uploading...`:`Upload`]})]})}n();var je=[{seconds:900,label:`15m`},{seconds:3600,label:`1h`},{seconds:21600,label:`6h`},{seconds:43200,label:`12h`},{seconds:86400,label:`24h`}],Me=new Set([`@camstack/system`,`@camstack/types`,`@camstack/sdk`,`@camstack/shm-ring`,`@camstack/ui-library`]);function Ne(e){return e!==void 0&&Me.has(e)}var Pe={id:`hub`,name:`Hub`,isHub:!0,isOnline:!0};function Fe(e,t){let n=e??`hub-only`;return n===`any-node`?!0:n===`hub-only`?t:!t}function Ie(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 Le(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 Re({addons:n,clusterStatus:o,selectedNode:d,onRefresh:f,isRefreshing:p}){let m=s(),[h,ee]=c(``),g=r(h),[_,v]=c(!1),y=t(null);u(()=>{if(!_)return;let e=e=>{y.current&&!y.current.contains(e.target)&&v(!1)};return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)},[_]);let{data:b}=se({nodeId:d.id}),x=a(()=>{let e=new Map;for(let t of b??[])e.set(t.name,t.latestVersion);return e},[b]),re=a(()=>(b??[]).filter(e=>!e.isSystem).length,[b]),[ie,E]=c(()=>new Set),[D,O]=c(()=>new Map),ae=e(e=>{E(t=>new Set(t).add(e))},[]),oe=e(e=>{E(t=>{if(!t.has(e))return t;let n=new Set(t);return n.delete(e),n})},[]),A=e((e,t)=>{O(n=>new Map(n).set(e,t))},[]),j=e(e=>{O(t=>{if(!t.has(e))return t;let n=new Map(t);return n.delete(e),n})},[]),N=ue({onMutate:e=>{ae(e.name),j(e.name)},onSuccess:(e,t)=>{oe(t.name);let n=e;if(n&&n.success===!1){A(t.name,n.error??`Update failed (no error message returned by server)`);return}m.invalidateQueries({queryKey:[[`addons`]]}),m.invalidateQueries({queryKey:[[`addons`,`listUpdates`]]})},onError:(e,t)=>{oe(t.name),A(t.name,e instanceof Error?e.message:String(e))}}),P=ve(),ce=t(new Set);u(()=>{let e=new Set;for(let[t,n]of P)X(n)&&e.add(t);let t=[...ce.current].some(t=>!e.has(t));ce.current=e,t&&(m.invalidateQueries({queryKey:[[`addons`]]}),m.invalidateQueries({queryKey:[[`addons`,`listUpdates`]]}))},[P,m]);let{data:L}=C(void 0),le=ne({onSuccess:()=>{m.invalidateQueries({queryKey:[[`addons`,`getAutoUpdateSettings`]]})}}),R=M({onSuccess:()=>{m.invalidateQueries({queryKey:[[`addons`,`getAutoUpdateSettings`]]})}}),{data:B,isFetching:V}=w({query:g||void 0},{enabled:_}),H=T(),{data:U}=te(void 0),me=U?.requestedAt,[W,G]=c(null),[ge,K]=c(!1);u(()=>{if(U?.kind===`framework-bulk-update`&&U.requestedAt!==W){G(U.requestedAt),K(!0);let e=window.setTimeout(()=>K(!1),6e3);return()=>window.clearTimeout(e)}},[me,W,U]),de();let q=e(async()=>{let e=(b??[]).filter(e=>!e.isSystem);if(e.length!==0){if(!d.isHub){for(let t of e)await N.mutateAsync({name:t.name,version:t.latestVersion,nodeId:d.id});return}await H.mutateAsync({kind:`update`,targets:e.map(e=>({name:e.name,version:e.latestVersion})),nodeIds:[d.id]})}},[b,d.id,d.isHub,H,N]),J=pe({onSuccess:()=>{m.invalidateQueries({queryKey:[[`addons`]]}),m.invalidateQueries({queryKey:[[`addonPages`]]}),m.invalidateQueries({queryKey:[[`capabilities`]]}),m.invalidateQueries({queryKey:[[`integrations`]]})}}),[Y,_e]=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]=he(),Q=xe.get(`capability`),Ce=a(()=>{let e=n.filter(e=>!Ne(e.manifest.packageName));return d.isHub||(e=e.filter(e=>Fe(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:Le(Ce),Ee=a(()=>{let e=[...Te];switch(Y){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,Y]);return i(`div`,{className:`space-y-4`,children:[[...D.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:()=>j(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:Y,onChange:e=>_e(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(F,{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:()=>le.mutate({channel:e}),disabled:le.isPending,className:`px-2.5 py-1.5 transition-colors capitalize ${L?.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:L?.updateCheckIntervalSeconds??21600,disabled:R.isPending||L===void 0,onChange:e=>{L!==void 0&&R.mutate({channel:L.channel,updateCheckIntervalSeconds:Number(e.target.value)})},children:je.map(e=>l(`option`,{value:e.seconds,children:e.label},e.seconds))})]}),re>0&&i(`button`,{type:`button`,onClick:()=>void q(),disabled:H.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:[H.isPending?l(S,{className:`w-3 h-3 animate-spin`}):l(z,{className:`w-3 h-3`}),H.isPending?`Updating…`:`Update All (${re})`]}),i(`button`,{type:`button`,onClick:f,disabled:p||H.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(F,{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:y,children:[l(fe,{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:h,onChange:e=>{ee(e.target.value),v(!0)},onFocus:()=>v(!0),placeholder:`Search addons on npm...`,disabled:H.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`}),V&&l(S,{className:`absolute right-2.5 top-1/2 -translate-y-1/2 h-3 w-3 text-foreground-subtle animate-spin`}),_&&B&&B.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:[B.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 (`,B.length,`)`]}),B&&B.length>0&&l(`div`,{className:`max-h-72 overflow-auto divide-y divide-border`,children:B.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(k,{className:`h-3 w-3`}),e.installedVersion??`Installed`]}):i(`button`,{type:`button`,onClick:()=>J.mutate({packageName:e.name}),disabled:J.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:[J.isPending?l(S,{className:`h-3 w-3 animate-spin`}):l(z,{className:`h-3 w-3`}),`Install`]})]},e.name))})]})]}),l(Ae,{onUploadSuccess:()=>{m.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`})]}),ge&&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(I,{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=x.get(t),r=$(e)?e.representative:e,i=n?e=>N.mutate({name:t,version:e,nodeId:d.id}):void 0,a=P.get(t)??null,s=a!==null&&X(a);return l(Oe,{addon:r,clusterStatus:o?.[r.manifest.id],bundle:$(e)?e.bundle:void 0,availableUpdate:n,isUpdating:ie.has(t)||s,jobProgress:a,onUpdate:i,disabledByBulk:H.isPending},$(e)?t:e.manifest.id)})})]})}function ze(){let e=s(),{data:n,isLoading:r,isError:a}=g(),{data:o}=_(void 0),{nodes:c}=H(),{selection:d,selectNode:f,requestedNodeId:p}=q(c.length>0?c:[Pe]),m=d.node??Pe,h=m.id,ee=c.length>0?d.staleNodeId:null,v=re(),y=j(),b=v.isPending||y.isPending,x=async()=>{await v.mutateAsync({nodeId:h}),await y.mutateAsync(),e.invalidateQueries({queryKey:[[`addons`]]})},S=t(v);S.current=v;let C=t(p??`hub`);u(()=>{S.current.mutate({nodeId:C.current})},[]);let w=(n??[]).map(Ie).filter(e=>e!==null);return i(G,{children:[i(`div`,{className:`flex items-center justify-between gap-3 flex-wrap`,children:[l(P,{selectedNodeId:h,onSelect:f}),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:[w.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(F,{className:`w-3 h-3 ${b?`animate-spin`:``}`}),`Check for updates`]})]})]}),l(K,{staleNodeId:ee,shownNodeName:m.name}),!m.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:m.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(Re,{addons:w,clusterStatus:o,selectedNode:m,onRefresh:()=>void x(),isRefreshing:b})]})}export{ze 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{W as d,Z as f,_t as p,at as m,ct as h,st as g,vt as _}from"./player-overlays-B82OVd2b.js";import{At as v,Ec as y,Eu as b,Ft as x,Il as S,It as C,Jl as w,Kt as T,Nt as E,Pt as D,Qt as O,Rt as k,Sl as A,Xc as j,Zt as M,_ as N,ct as P,in as F,iu as ee,jt as te,kt as I,ll as L,lt as R,ql as z,ri as B,rn as ne,su as V,tn as H,ul as re,uu as U,wl as W,xl as G}from"./src-jk2FdB5v.js";import{t as ie}from"./boxes-B2dkI7tE.js";import{t as ae}from"./send-BUidPUKy.js";import{gt as K}from"./src-8XVcukAG.js";import{n as q}from"./index-BpiZqZOx.js";import{t as J}from"./AdminPage-CiKtOLQm.js";import{t as oe}from"./AdminTabs-CSovnIie.js";var se=_(`message-square-plus`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}],[`path`,{d:`M12 8v6`,key:`1ib9pf`}],[`path`,{d:`M9 11h6`,key:`1fldmi`}]]);n();var ce=[`llm`,`listProfiles`],le=[`llm`,`listProfileKinds`],ue=[`llm`,`getDefaults`],de=[`llm`,`listRuntimeNodes`],fe=[`llm`,`listModelCatalog`],pe=[`llm`,`getUsage`],me=[{purpose:`vision`,visionOnly:!0},{purpose:`text`,visionOnly:!1}],he=new Map(Object.entries({openai:U,anthropic:U,google:U,"openai-compatible":G,"managed-local":V}));function ge(e){return he.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 _e(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:xe(e.runtime?.extraArgs??[])}}var ve=[`f32`,`f16`,`q8_0`,`q5_1`,`q5_0`,`q4_1`,`q4_0`];function ye(e){return typeof e==`string`&&ve.includes(e)?e:void 0}function be(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 xe(e){return e.map(e=>/\s/.test(e)?`"${e}"`:e).join(` `)}var Se=[`--jinja`,`--cont-batching`];function Ce(e,t,n){let r=X(e.threads),i=X(e.batchSize),a=X(e.ubatchSize),o=ye(e.cacheTypeK),s=ye(e.cacheTypeV);return{nodeId:t,engine:`llama-cpp`,model:n,extraArgs:[...be(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 we(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)??K.totalMs,connectTimeoutMs:X(r.connectTimeoutMs)??K.connectMs,firstTokenTimeoutMs:X(r.firstTokenTimeoutMs)??K.firstTokenMs,idleTimeoutMs:X(r.idleTimeoutMs)??K.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:Ce(r,i.nodeId,i.model)}}}function Te(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 Ee=2e3;function Q(e){return`${(e/1e9).toFixed(2)} GB`}function De(e){return e===null?``:e.model.kind===`catalog`?`catalog:${e.model.catalogId}`:e.model.kind===`path`?`node:${e.modelId}`:`custom`}function Oe({nodeId:e,value:t,onChange:n}){let{t:o}=q(),u=m(),[d,f]=s(``),[p,h]=s(null),[g,_]=s(!1),v=a({queryKey:fe,queryFn:()=>u.trpcClient.llm.listModelCatalog.query({})}),y=a({queryKey:[`llm`,`listNodeModels`,e],queryFn:()=>u.trpcClient.llm.listNodeModels.query({nodeId:e})}),b=c({mutationFn:e=>u.trpcClient.llm.resolveModelRef.mutate(e),onSuccess:e=>{h(e),_(!1),e.ok&&n({model:e.model,modelId:e.label,supportsVision:e.purpose===`vision`})}}),x=c({mutationFn:t=>u.trpcClient.llm.installModel.mutate({nodeId:e,model:t}),onSuccess:()=>{_(!0),y.refetch()}}),C=a({queryKey:de,enabled:x.isPending,refetchInterval:x.isPending?Ee:!1,queryFn:()=>u.trpcClient.llm.listRuntimeNodes.query({})}).data?.find(t=>t.nodeId===e)?.status?.download,w=i(()=>{let t=(v.data??[]).map(e=>({value:`catalog:${e.id}`,label:`${e.label} · ${e.quantization} · ${Q(e.sizeBytes)}`})),n=(y.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=p?.ok===!0?[{value:`custom`,label:`${p.label} · ${Q(p.totalBytes)}`}]:[];return[{value:``,label:o(`ai.selectModel`,`Select a model…`)},...t,...n,...r]},[v.data,y.data,p,e,o]),T=e=>{if(e===``){n(null);return}if(e===`custom`){if(p?.ok!==!0)return;n({model:p.model,modelId:p.label,supportsVision:p.purpose===`vision`});return}if(e.startsWith(`catalog:`)){let t=e.slice(8),r=v.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=y.data?.find(e=>e.file===t);r?.path!==void 0&&n({model:{kind:`path`,path:r.path},modelId:t,supportsVision:!1})},E=e=>{d.trim()!==``&&b.mutate({ref:d.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(ne,{id:`ai-model`,value:De(t),options:w,onChange:e=>T(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(k,{value:d,onChange:e=>f(e.target.value),placeholder:`unsloth/Qwen3.6-35B-A3B-GGUF:UD-Q4_K_M`,onKeyDown:e=>{e.key===`Enter`&&(e.preventDefault(),E())}}),r(F,{size:`sm`,variant:`secondary`,type:`button`,disabled:d.trim()===``||b.isPending,onClick:()=>E(),children:[b.isPending?l(S,{className:`h-3.5 w-3.5 animate-spin`}):l(re,{className:`h-3.5 w-3.5`}),o(`ai.hfCheck`,`Check`)]})]}),b.isError&&l(`p`,{className:`mt-2 text-[11px] text-danger`,children:b.error instanceof Error?b.error.message:o(`common.error`,`Error`)}),p?.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:p.message}),p.candidates!==void 0&&p.candidates.length>0&&l(`div`,{className:`mt-1.5 flex flex-wrap gap-1`,children:p.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=`${d.trim().split(`:`)[0]??``}:${e}`;f(t),b.mutate({ref:t})},children:e},e))}),p.requiredBytes!==void 0&&l(F,{size:`sm`,variant:`secondary`,type:`button`,className:`mt-2`,onClick:()=>E(p.requiredBytes),children:o(`ai.hfOverride`,`Install anyway ({{size}})`,{size:Q(p.requiredBytes)})})]}),p?.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:p.label}),l(M,{variant:p.purpose===`vision`?`info`:`default`,children:p.purpose}),l(M,{variant:`default`,children:Q(p.totalBytes)})]}),p.extraFilenames.length>0&&l(`p`,{className:`mt-1 text-[10px] text-foreground-subtle`,children:o(`ai.hfExtras`,`Also downloads: {{files}}`,{files:p.extraFilenames.join(`, `)})}),r(`div`,{className:`mt-2 flex items-center gap-2`,children:[r(F,{size:`sm`,type:`button`,disabled:x.isPending||g,onClick:()=>x.mutate(p.model),children:[x.isPending?l(S,{className:`h-3.5 w-3.5 animate-spin`}):l(ee,{className:`h-3.5 w-3.5`}),g?o(`ai.hfInstalled`,`Downloaded`):o(`ai.hfInstall`,`Download to {{node}}`,{node:e})]}),C!==void 0&&l(`span`,{className:`text-[10px] text-foreground-subtle`,children:C.phase===`verifying`?o(`ai.hfVerifying`,`verifying {{file}}…`,{file:C.file}):o(`ai.hfDownloading`,`{{file}} ({{index}}/{{count}}) — {{done}}{{total}}`,{file:C.file,index:C.fileIndex,count:C.fileCount,done:Q(C.downloadedBytes),total:C.totalBytes===void 0?``:` / ${Q(C.totalBytes)}`})})]}),x.isError&&l(`p`,{className:`mt-1.5 text-[11px] text-danger`,children:x.error instanceof Error?x.error.message:o(`common.error`,`Error`)})]})]})]})}n();function ke({kind:e,className:t}){let n=ge(e.kind);return n===null?l(`span`,{className:t,children:e.icon}):l(n,{className:t})}function Ae({kinds:e,onPick:t,onCancel:n}){let{t:a}=q(),o=i(()=>Te(e),[e]);return l(I,{open:!0,onOpenChange:e=>!e&&n(),children:r(te,{width:`lg`,placement:`sheet-on-mobile`,scroll:`body`,children:[l(D,{children:l(x,{children:a(`ai.chooseKind`,`Choose a profile type`)})}),r(v,{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(ke,{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(E,{children:l(F,{size:`sm`,variant:`secondary`,type:`button`,onClick:n,children:a(`common.cancel`,`Cancel`)})})]})})}function je({kind:e,existing:t,onSave:n,onCancel:a,saving:c,error:u}){let{t:d}=q(),f=e.kind===`managed-local`,[p,m]=s(t?.name??e.label),[h,g]=s(()=>t===null?{}:_e(t)),[_,y]=s(t?.runtime?.nodeId??`hub`),[b,C]=s(()=>t?.runtime===void 0?null:{model:t.runtime.model,modelId:t.model,supportsVision:t.supportsVision}),w=i(()=>be(Y(h.extraArgs)??``),[h.extraArgs]),O=()=>{if(!f){n(we(e.kind,p,t,h));return}b!==null&&n(we(e.kind,p,t,h,{nodeId:_,model:b.model,modelId:b.modelId,supportsVision:b.supportsVision}))},A=c||p.trim()===``||f&&b===null;return l(I,{open:!0,onOpenChange:e=>!e&&a(),children:r(te,{width:`lg`,placement:`sheet-on-mobile`,scroll:`body`,children:[l(D,{children:r(x,{className:`flex items-center gap-2`,children:[l(ke,{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(v,{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(k,{id:`ai-profile-name`,value:p,onChange:e=>m(e.target.value),placeholder:e.label})]}),f&&r(o,{children:[l(N,{selectedNodeId:_,onSelect:y,label:d(`ai.runtimeNode`,`Runtime node`),alwaysShow:!0}),l(Oe,{nodeId:_,value:b,onChange:C}),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(k,{id:`ai-extra-args`,value:Y(h.extraArgs)??``,onChange:e=>g({...h,extraArgs:e.target.value}),placeholder:Se.join(` `)}),w.length>0&&l(`div`,{className:`mt-1 flex flex-wrap gap-1`,children:w.map((e,t)=>l(M,{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(T,{schema:e.configSchema,values:h,onChange:g}),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(E,{children:[f&&b===null&&l(M,{variant:`warning`,children:d(`ai.pickModelFirst`,`pick a model`)}),l(F,{size:`sm`,variant:`secondary`,type:`button`,onClick:a,children:d(`common.cancel`,`Cancel`)}),r(F,{size:`sm`,type:`button`,disabled:A,onClick:O,children:[c&&l(S,{className:`h-3.5 w-3.5 animate-spin`}),t===null?d(`ai.createProfile`,`Create profile`):d(`ai.saveChanges`,`Save changes`)]})]})]})})}n();function Me(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(ke,{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(M,{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(M,{variant:`default`,children:e.runtime.nodeId})},{key:`enabled`,header:e.t(`ai.colOn`,`On`),align:`center`,nowrap:!0,render:t=>l(C,{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(F,{size:`sm`,variant:`ghost`,type:`button`,onClick:()=>e.onTest(t),title:e.t(`ai.test`,`Test`),children:e.testingId===t.id?l(S,{className:`h-3.5 w-3.5 animate-spin`}):l(ae,{className:`h-3.5 w-3.5`})}),l(F,{size:`sm`,variant:`ghost`,type:`button`,disabled:!e.kindByName.has(t.kind),onClick:()=>e.onEdit(t),title:e.t(`common.edit`,`Edit`),children:l(W,{className:`h-3.5 w-3.5`})}),l(F,{size:`sm`,variant:`ghost`,type:`button`,onClick:()=>e.onDelete(t),title:e.t(`common.delete`,`Delete`),children:l(g,{className:`h-3.5 w-3.5 text-danger`})})]})}]}function Ne(){let{t:e}=q(),t=m(),[n,o]=s({mode:`closed`}),[u,d]=s(null),[f,p]=s(null),h=a({queryKey:ce,queryFn:()=>t.trpcClient.llm.listProfiles.query({})}),g=a({queryKey:le,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`}),p(null),_()},onError:t=>p(t instanceof Error?t.message:e(`ai.saveFailed`,`Save failed`))}),y=c({mutationFn:e=>t.trpcClient.llm.deleteProfile.mutate({addonId:e.addonId,profileId:e.id}),onSuccess:_}),b=c({mutationFn:e=>t.trpcClient.llm.testProfile.mutate({addonId:e.addonId,profileId:e.id}),onSuccess:(e,t)=>d({id:t.id,ok:e.ok,text:e.ok?`${e.text} (${String(e.usage.outputTokens)} tok, ${String(e.latencyMs)}ms)`:`${e.code}: ${e.message}`})}),x=h.data??[],C=i(()=>g.data??[],[g.data]),w=i(()=>{let e=new Map;for(let t of C)e.set(t.kind,t);return e},[C]);return r(J,{icon:j,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(F,{size:`sm`,type:`button`,onClick:()=>{p(null),o({mode:`pick-kind`})},children:[l(A,{className:`h-3.5 w-3.5`}),e(`ai.addProfile`,`Add profile`)]}),children:[h.isError&&l(H,{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(Pe,{profiles:x}),h.isLoading&&l(`div`,{className:`flex items-center justify-center py-16`,children:l(S,{className:`h-6 w-6 animate-spin text-primary`})}),!h.isLoading&&x.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.`)}),x.length>0&&l(O,{children:l(P,{columns:Me({kindByName:w,testResult:u,testingId:b.isPending?b.variables?.id??null:null,t:e,onToggle:e=>v.mutate({...e,enabled:!e.enabled,apiKey:`__redacted__`}),onTest:e=>b.mutate(e),onEdit:e=>{let t=w.get(e.kind);t!==void 0&&(p(null),o({mode:`form`,kind:t,profile:e}))},onDelete:e=>y.mutate(e)}),rows:x,rowKey:e=>e.id,minWidthPx:760,bordered:!1,mobileMode:`scroll`,maxBodyHeight:`max-h-[60vh]`})}),n.mode===`pick-kind`&&l(Ae,{kinds:C,onCancel:()=>o({mode:`closed`}),onPick:e=>o({mode:`form`,kind:e,profile:null})}),n.mode===`form`&&l(je,{kind:n.kind,existing:n.profile,saving:v.isPending,error:f,onSave:e=>v.mutate(e),onCancel:()=>o({mode:`closed`})})]})}function Pe({profiles:e}){let{t}=q(),n=m(),i=a({queryKey:ue,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(O,{children:l(`div`,{className:`grid gap-4 p-4 sm:grid-cols-2`,children:me.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 Fe=5e3;function Ie(e){return`${(e/1e9).toFixed(1)} GB`}function Le(){let{t:e}=q(),t=m(),n=a({queryKey:de,refetchInterval:Fe,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(M,{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(M,{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?`—`:Ie(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(J,{icon:L,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(H,{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(O,{children:l(P,{columns:o,rows:s,rowKey:e=>e.nodeId,minWidthPx:640,bordered:!1,mobileMode:`scroll`,maxBodyHeight:R})})]})}var Re=f(`/addon/ai/test-chat`),ze=f(`/addon/ai/test-chat/chats`),Be=6e5;function Ve(e){let t=e.firstTokenTimeoutMs;if(!(typeof t!=`number`||!Number.isFinite(t)||t<=0))return Math.min(Math.round(t),Be)}function He(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function Ue(e){if(!He(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 We=[`resolving-image`,`connecting`,`first-token-wait`,`streaming`];function Ge(e){let t;try{t=JSON.parse(e)}catch{return null}if(!He(t))return null;switch(t.kind){case`status`:{let e=We.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:Ue(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*Ke(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=Ge(e);t!==null&&(yield t)}a=r.indexOf(`
3
- `)}}let e=r.trim();if(e.length>0){let t=Ge(e);t!==null&&(yield t)}}finally{t.releaseLock()}}function qe(e){return e.filter(e=>e.failed!==!0&&e.content.length>0).map(e=>({role:e.role,content:e.content}))}function Je(e){return e.thumbnailBase64===void 0||e.thumbnailBase64.length===0?null:`data:${e.mimeType};base64,${e.thumbnailBase64}`}function Ye(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 Xe(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 Ze(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 Qe=[`pipelineAnalytics`,`listRecentTracks`,`ai-test`],$e=360*60*1e3,et=40,tt=160,$={phase:`connecting`,firstTokenTimeoutMs:0,text:``,mediaSent:null};function nt(){let{t:n}=q(),o=m(),[c,d]=s(``),[f,_]=s(``),[v,x]=s(``),[S,C]=s([]),[T,E]=s(null),[D,A]=s(`none`),[j,M]=s(`throwaway`),[N,P]=s(null),[ee,te]=s([]),[I,L]=s(null),[R,z]=s(null),B=t(null);u(()=>()=>B.current?.abort(),[]);let V=e(async()=>{let e=await fetch(ze,{credentials:`same-origin`});e.ok&&te((await e.json()).chats??[])},[]);u(()=>{j===`persistent`&&V()},[j,V]);let re=a({queryKey:ce,queryFn:()=>o.trpcClient.llm.listProfiles.query({})}),U=i(()=>(re.data??[]).filter(e=>e.enabled),[re.data]),W=U.find(e=>e.id===c)??null,G=R!==null,ie=e(async(e,t)=>{let r=new AbortController;B.current=r,L(null);let i=Ve(W??{});z({...$,firstTokenTimeoutMs:i??0});let a=``,o=null,s,l=null,u=null,d;try{let n=await fetch(Re,{method:`POST`,headers:{"content-type":`application/json`},credentials:`same-origin`,signal:r.signal,body:JSON.stringify({profileId:c,messages:e,...f.trim()===``?{}:{system:f.trim()},...t===void 0?{}:{attachment:t},...i===void 0?{}:{firstTokenTimeoutMs:i},...j===`persistent`?{persist:!0,...N===null?{}:{conversationId:N}}:{}})});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 Ke(n.body))switch(e.kind){case`status`:z(t=>({...t??$,phase:e.phase}));break;case`meta`:o=e.mediaSent,s=e.model,z(t=>({...t??$,firstTokenTimeoutMs:e.firstTokenTimeoutMs,mediaSent:e.mediaSent}));break;case`token`:a+=e.text,z(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||L(e instanceof Error?e.message:n(`common.error`,`Error`))}finally{B.current=null,z(null)}d!==void 0&&(P(d),V());let p=r.signal.aborted&&a.length>0;l===null&&a.length===0&&!p||C(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}])},[j,N,W,c,V,f,n]),K=e(()=>{let e=v.trim();if(e===``||c===``||G)return;let t={id:`u-${String(Date.now())}`,role:`user`,content:e,...T===null?{}:{attachmentLabel:T.label,attachmentKind:T.ref.kind}},n=[...S,t];C(n),x(``);let r=T?.ref;E(null),A(`none`),ie(j===`persistent`&&N!==null?[{role:`user`,content:e}]:qe(n),r)},[j,N,v,T,c,ie,G,S]),oe=()=>B.current?.abort(),le=()=>{B.current?.abort(),C([]),E(null),x(``),L(null),z(null),P(null)},ue=async e=>{B.current?.abort();let t=await fetch(`${ze}/${e}`,{credentials:`same-origin`});if(!t.ok)return;let n=await t.json();P(e),C(Ye(n)),z(null),L(null)};return r(J,{icon:w,title:n(`ai.testTitle`,`Test chat`),subtitle:n(j===`persistent`?`ai.testSubtitlePersistent`:`ai.testSubtitle`,j===`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(F,{size:`sm`,variant:`secondary`,type:`button`,disabled:S.length===0&&T===null,onClick:le,children:[l(g,{className:`h-3.5 w-3.5`}),n(`ai.clearChat`,`Clear`)]}),children:[r(O,{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(ne,{id:`ai-test-profile`,value:c,onChange:e=>d(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&&!re.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(k,{id:`ai-test-system`,value:f,onChange:e=>_(e.target.value),placeholder:n(`ai.systemPlaceholder`,`Answer in one short sentence.`)})]})]}),r(`div`,{className:`flex flex-wrap items-center gap-2`,children:[l(F,{size:`sm`,variant:j===`throwaway`?`primary`:`outline`,type:`button`,onClick:()=>{M(`throwaway`),P(null)},children:n(`ai.throwawayMode`,`Throwaway`)}),l(F,{size:`sm`,variant:j===`persistent`?`primary`:`outline`,type:`button`,onClick:()=>M(`persistent`),children:n(`ai.saveConversation`,`Save conversation`)})]}),j===`persistent`&&r(`div`,{className:`space-y-2`,children:[l(`div`,{className:`flex items-center gap-2`,children:r(F,{size:`sm`,variant:`secondary`,type:`button`,onClick:le,children:[l(se,{className:`h-3.5 w-3.5`}),n(`ai.newChat`,`New chat`)]})}),ee.length>0&&l(`div`,{className:`max-h-36 divide-y divide-border overflow-y-auto rounded-md border border-border`,children:ee.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===N?`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.`)}),W!==null&&!W.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.`)})]}),I!==null&&l(H,{title:n(`ai.chatFailed`,`The test call failed`),message:I}),l(rt,{turns:S,live:R}),r(O,{className:`space-y-2 p-3`,children:[T!==null&&r(`div`,{className:`flex items-center gap-2 rounded-md border border-border bg-surface px-2.5 py-1.5`,children:[T.ref.kind===`snapshot`?l(p,{className:`h-3.5 w-3.5 text-foreground-subtle`}):l(b,{className:`h-3.5 w-3.5 text-foreground-subtle`}),l(`span`,{className:`min-w-0 flex-1 truncate text-[11px] text-foreground`,children:T.label}),l(F,{size:`sm`,variant:`ghost`,type:`button`,onClick:()=>E(null),children:l(y,{className:`h-3.5 w-3.5`})})]}),r(`div`,{className:`flex flex-wrap items-center gap-2`,children:[r(F,{size:`sm`,variant:D===`snapshot`?`primary`:`outline`,type:`button`,onClick:()=>A(D===`snapshot`?`none`:`snapshot`),children:[l(p,{className:`h-3.5 w-3.5`}),n(`ai.attachSnapshot`,`Camera snapshot`)]}),r(F,{size:`sm`,variant:D===`track`?`primary`:`outline`,type:`button`,onClick:()=>A(D===`track`?`none`:`track`),children:[l(b,{className:`h-3.5 w-3.5`}),n(`ai.attachTrack`,`Recent track`)]})]}),D===`snapshot`&&l(ot,{onPick:e=>{E({ref:{kind:`snapshot`,deviceId:e.id},label:n(`ai.snapshotOf`,`Snapshot of {{name}}`,{name:e.name})}),A(`none`)}}),D===`track`&&l(ct,{onPick:(e,t)=>{E({ref:{kind:`track`,trackId:e.trackId,deviceId:e.deviceId},label:n(`ai.trackOf`,`{{class}} on {{name}}`,{class:e.label??e.className,name:t})}),A(`none`)}}),r(`div`,{className:`flex items-center gap-2`,children:[l(k,{value:v,onChange:e=>x(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),K())},placeholder:n(`ai.messagePlaceholder`,`Ask the model something…`),"aria-label":n(`ai.message`,`Message`)}),G?r(F,{size:`sm`,variant:`secondary`,type:`button`,onClick:oe,children:[l(h,{className:`h-3.5 w-3.5`}),n(`ai.stop`,`Stop`)]}):r(F,{size:`sm`,type:`button`,disabled:v.trim()===``||c===``,onClick:K,children:[l(ae,{className:`h-3.5 w-3.5`}),n(`ai.send`,`Send`)]})]})]})]})}function rt({turns:e,live:t}){let{t:n}=q();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(O,{children:r(`div`,{className:`max-h-[50vh] space-y-2 overflow-y-auto p-3`,children:[e.map(e=>l(it,{turn:e},e.id)),t!==null&&r(`div`,{className:`space-y-1`,children:[t.mediaSent!==null&&l(at,{attachment:t.mediaSent}),t.text.length>0&&l(it,{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(S,{className:`h-3.5 w-3.5 animate-spin`}),Ze(t.phase,t.firstTokenTimeoutMs)]})]})]})})}function it({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(at,{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(b,{className:`h-3 w-3`}):l(p,{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(p,{className:`h-3 w-3`}):l(b,{className:`h-3 w-3`}),Xe(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 at({attachment:e}){let t=Je(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 ot({onPick:e}){let{t}=q(),n=B({isCamera:!0,projection:`slim`}),r=(n.data??[]).filter(e=>!e.disabled);return n.isLoading?l(S,{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(st,{device:t,onPick:e},t.id))})}function st({device:e,onPick:t}){let{src:n}=d(e.id,{width:tt});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(M,{variant:`warning`,children:`off`}),l(`span`,{className:`truncate text-[10px] text-foreground`,children:e.name})]})]})}function ct({onPick:e}){let{t}=q(),n=m(),o=B({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:[...Qe,s.length],enabled:s.length>0,queryFn:()=>n.trpcClient.pipelineAnalytics.listRecentTracks.query({deviceIds:[...s],since:Date.now()-$e,limit:et,projection:`slim`})});if(o.isLoading||u.isLoading)return l(S,{className:`h-4 w-4 animate-spin text-foreground-subtle`});let d=u.data?.tracks??[];return d.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:d.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(b,{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 lt=1440*60*1e3,ut=[1,7,30,90];function dt(){let{t:e}=q(),t=m(),[n,o]=s(7),c=i(()=>{let e=new Date;return e.setHours(0,0,0,0),e.getTime()-(n-1)*lt},[n]),u=a({queryKey:ce,queryFn:()=>t.trpcClient.llm.listProfiles.query({})}),d=a({queryKey:[...pe,n],queryFn:()=>t.trpcClient.llm.getUsage.query({since:c})}),f=i(()=>{let e=new Map;for(let t of u.data??[])e.set(t.id,t.name);return e},[u.data]),p=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:f.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))}],[f,e]),h=d.data??[];return r(J,{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(ne,{"aria-label":e(`ai.window`,`Window`),value:String(n),options:ut.map(t=>({value:String(t),label:e(`ai.lastDays`,`Last {{days}} days`,{days:t})})),onChange:e=>o(Number(e.target.value))})}),children:[d.isError&&l(H,{title:e(`ai.usageFailed`,`Failed to read usage`),message:d.error instanceof Error?d.error.message:e(`common.error`,`Error`),onRetry:()=>void d.refetch()}),h.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(O,{children:l(P,{columns:p,rows:h,rowKey:e=>`${e.day}|${e.consumer}|${e.profileId}`,minWidthPx:720,bordered:!1,mobileMode:`scroll`,maxBodyHeight:R})})]})}function ft(){let{t:e}=q();return l(`div`,{className:`flex flex-col p-4`,children:l(oe,{tabs:[{id:`profiles`,label:e(`ai.tabProfiles`,`Profiles`),icon:ie,content:l(Ne,{})},{id:`runtimes`,label:e(`ai.tabRuntimes`,`Runtimes`),icon:L,content:l(Le,{})},{id:`usage`,label:e(`ai.tabUsage`,`Usage`),icon:z,content:l(dt,{})},{id:`test`,label:e(`ai.tabTest`,`Test`),icon:w,content:l(nt,{})}]})})}export{ft as AiProfilesPage,ft as default};