@camstack/ui-library 1.2.249 → 1.2.250

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -25,11 +25,11 @@ const require_theme_index = require("./theme/index.cjs");
25
25
  let react = require("react");
26
26
  let react$1 = __toESM(react, 1);
27
27
  react = __toESM(react);
28
+ let _camstack_types = require("@camstack/types");
28
29
  let _trpc_react_query = require("@trpc/react-query");
29
30
  _trpc_react_query = __toESM(_trpc_react_query, 1);
30
31
  let react_jsx_runtime = require("react/jsx-runtime");
31
32
  react_jsx_runtime = __toESM(react_jsx_runtime, 1);
32
- let _camstack_types = require("@camstack/types");
33
33
  let react_dom = require("react-dom");
34
34
  react_dom = __toESM(react_dom, 1);
35
35
  let _tanstack_react_query = require("@tanstack/react-query");
@@ -2454,6 +2454,26 @@ var Gauge = createLucideIcon("gauge", [["path", {
2454
2454
  * This source code is licensed under the ISC license.
2455
2455
  * See the LICENSE file in the root directory of this source tree.
2456
2456
  */
2457
+ var GraduationCap = createLucideIcon("graduation-cap", [
2458
+ ["path", {
2459
+ d: "M21.42 10.922a1 1 0 0 0-.019-1.838L12.83 5.18a2 2 0 0 0-1.66 0L2.6 9.08a1 1 0 0 0 0 1.832l8.57 3.908a2 2 0 0 0 1.66 0z",
2460
+ key: "j76jl0"
2461
+ }],
2462
+ ["path", {
2463
+ d: "M22 10v6",
2464
+ key: "1lu8f3"
2465
+ }],
2466
+ ["path", {
2467
+ d: "M6 12.5V16a6 3 0 0 0 12 0v-3.5",
2468
+ key: "1r8lef"
2469
+ }]
2470
+ ]);
2471
+ /**
2472
+ * @license lucide-react v0.576.0 - ISC
2473
+ *
2474
+ * This source code is licensed under the ISC license.
2475
+ * See the LICENSE file in the root directory of this source tree.
2476
+ */
2457
2477
  var Grid2x2 = createLucideIcon("grid-2x2", [
2458
2478
  ["path", {
2459
2479
  d: "M12 3v18",
@@ -7216,6 +7236,179 @@ function ConfigIconFieldControl({ label, value, defaultKey, disabled, onChange }
7216
7236
  });
7217
7237
  }
7218
7238
  //#endregion
7239
+ //#region src/composites/config-secret-field.tsx
7240
+ /**
7241
+ * A keychain-stored secret in a settings form (D787, D789).
7242
+ *
7243
+ * The form never holds the value. It receives the field's VIEW —
7244
+ * `{ $secret, v, set: true }` when something is stored, `null` when nothing
7245
+ * is — and sends back exactly one of three things:
7246
+ *
7247
+ * - the view, unchanged ........ KEEP (also what an untouched form saves);
7248
+ * - a non-empty typed string ... CHANGE (the owner stores it in the keychain);
7249
+ * - `{ $secretClear: true }` ... CLEAR (the only thing that removes it).
7250
+ *
7251
+ * `''` is never sent for "remove": the save path reads it as KEEP, because an
7252
+ * empty string is what a defaults fallback writes back.
7253
+ *
7254
+ * Reveal shows the stored value for a few seconds, through the host's audited
7255
+ * `keychain-admin.reveal` (provided with {@link SecretRevealProvider}); a host
7256
+ * that provides none has no Reveal button.
7257
+ */
7258
+ /** How long a revealed value stays on screen. */
7259
+ var SECRET_REVEAL_MS = 1e4;
7260
+ var SecretRevealContext = createSharedContext("camstack:secret-reveal", null);
7261
+ function SecretRevealProvider({ reveal, children }) {
7262
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SecretRevealContext.Provider, {
7263
+ value: reveal,
7264
+ children
7265
+ });
7266
+ }
7267
+ /** Does this value belong to the keychain rendering (a view, or "not set")? */
7268
+ function isKeychainFieldValue(value) {
7269
+ return value === null || (0, _camstack_types.isSecretFieldView)(value) || (0, _camstack_types.isSecretClear)(value);
7270
+ }
7271
+ var BUTTON$1 = "inline-flex items-center gap-1 rounded border border-border bg-surface px-2 py-0.5 text-[11px] font-medium text-foreground hover:border-primary/40 hover:bg-primary/5 disabled:opacity-40 disabled:cursor-not-allowed";
7272
+ var INPUT = "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-xs text-foreground focus:border-primary focus:ring-1 focus:ring-primary/30 outline-none disabled:opacity-50";
7273
+ function SecretFieldControl({ field, value, onChange, disabled, multiline }) {
7274
+ const reveal = (0, react$1.useContext)(SecretRevealContext);
7275
+ const [original] = (0, react$1.useState)(() => (0, _camstack_types.isSecretFieldView)(value) ? value : null);
7276
+ const [mode, setMode] = (0, react$1.useState)(() => typeof value === "string" && value.length > 0 ? {
7277
+ kind: "editing",
7278
+ text: value
7279
+ } : (0, _camstack_types.isSecretClear)(value) ? { kind: "clearing" } : { kind: "idle" });
7280
+ const [shown, setShown] = (0, react$1.useState)(null);
7281
+ const [revealError, setRevealError] = (0, react$1.useState)(null);
7282
+ const [showTyped, setShowTyped] = (0, react$1.useState)(false);
7283
+ (0, react$1.useEffect)(() => {
7284
+ if (shown === null) return;
7285
+ const timer = setTimeout(() => setShown(null), SECRET_REVEAL_MS);
7286
+ return () => clearTimeout(timer);
7287
+ }, [shown]);
7288
+ const isSet = original !== null;
7289
+ const ref = original?.$secret ?? null;
7290
+ const keep = () => {
7291
+ setMode({ kind: "idle" });
7292
+ onChange(original);
7293
+ };
7294
+ const label = "label" in field ? field.label : "";
7295
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7296
+ className: "space-y-1",
7297
+ "data-secret-field": "key" in field ? field.key : void 0,
7298
+ children: [
7299
+ mode.kind === "editing" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7300
+ className: "flex items-start gap-1.5",
7301
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7302
+ className: "relative flex-1",
7303
+ children: [multiline ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
7304
+ className: `${INPUT} min-h-[60px] font-mono`,
7305
+ "aria-label": label,
7306
+ value: mode.text,
7307
+ autoComplete: "off",
7308
+ spellCheck: false,
7309
+ disabled,
7310
+ onChange: (e) => {
7311
+ setMode({
7312
+ kind: "editing",
7313
+ text: e.target.value
7314
+ });
7315
+ onChange(e.target.value.length > 0 ? e.target.value : original);
7316
+ }
7317
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
7318
+ type: showTyped ? "text" : "password",
7319
+ className: `${INPUT} pr-8`,
7320
+ "aria-label": label,
7321
+ value: mode.text,
7322
+ autoComplete: "new-password",
7323
+ spellCheck: false,
7324
+ disabled,
7325
+ autoFocus: true,
7326
+ onChange: (e) => {
7327
+ setMode({
7328
+ kind: "editing",
7329
+ text: e.target.value
7330
+ });
7331
+ onChange(e.target.value.length > 0 ? e.target.value : original);
7332
+ }
7333
+ }), !multiline && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7334
+ type: "button",
7335
+ className: "absolute right-2 top-1/2 -translate-y-1/2 text-foreground-subtle hover:text-foreground",
7336
+ tabIndex: -1,
7337
+ "aria-label": showTyped ? "Hide" : "Show",
7338
+ onClick: () => setShowTyped((s) => !s),
7339
+ children: showTyped ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EyeOff, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Eye, { className: "h-3.5 w-3.5" })
7340
+ })]
7341
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7342
+ type: "button",
7343
+ className: BUTTON$1,
7344
+ onClick: keep,
7345
+ disabled,
7346
+ children: "Cancel"
7347
+ })]
7348
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7349
+ className: "flex flex-wrap items-center gap-1.5",
7350
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7351
+ className: `inline-flex items-center gap-1 rounded-md border px-2 py-1 text-xs ${mode.kind === "clearing" ? "border-danger/40 text-danger" : isSet ? "border-border text-foreground" : "border-dashed border-border text-foreground-subtle"}`,
7352
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(KeyRound, { className: "h-3 w-3" }), mode.kind === "clearing" ? "will be removed on save" : shown !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
7353
+ className: "font-mono break-all",
7354
+ children: shown
7355
+ }) : isSet ? "●●●●●● set" : "not set"]
7356
+ }), mode.kind === "clearing" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7357
+ type: "button",
7358
+ className: BUTTON$1,
7359
+ onClick: keep,
7360
+ disabled,
7361
+ children: "Undo"
7362
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
7363
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7364
+ type: "button",
7365
+ className: BUTTON$1,
7366
+ disabled,
7367
+ onClick: () => setMode({
7368
+ kind: "editing",
7369
+ text: ""
7370
+ }),
7371
+ children: isSet ? "Change" : "Set"
7372
+ }),
7373
+ isSet && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7374
+ type: "button",
7375
+ className: BUTTON$1,
7376
+ disabled,
7377
+ onClick: () => {
7378
+ setShown(null);
7379
+ setMode({ kind: "clearing" });
7380
+ onChange(_camstack_types.SECRET_CLEAR);
7381
+ },
7382
+ children: "Clear"
7383
+ }),
7384
+ isSet && ref !== null && reveal !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7385
+ type: "button",
7386
+ className: BUTTON$1,
7387
+ disabled,
7388
+ onClick: () => {
7389
+ if (shown !== null) {
7390
+ setShown(null);
7391
+ return;
7392
+ }
7393
+ setRevealError(null);
7394
+ reveal(ref).then(setShown, (err) => setRevealError(err instanceof Error ? err.message : String(err)));
7395
+ },
7396
+ children: shown !== null ? "Hide" : "Reveal"
7397
+ })
7398
+ ] })]
7399
+ }),
7400
+ original?.inline === true && mode.kind === "idle" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7401
+ className: "text-[10px] text-foreground-subtle",
7402
+ children: "Stored before the keychain; it moves there the next time it is changed."
7403
+ }),
7404
+ revealError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7405
+ className: "text-[10px] text-danger",
7406
+ children: revealError
7407
+ })
7408
+ ]
7409
+ });
7410
+ }
7411
+ //#endregion
7219
7412
  //#region src/generated/system-hooks.ts
7220
7413
  /**
7221
7414
  * Per-method React-Query hooks for every `scope: 'system'` capability.
@@ -8017,6 +8210,24 @@ var useIntercomPushTalkAudio = trpc.intercom.pushTalkAudio.useMutation;
8017
8210
  var useIntercomEndTalkSession = trpc.intercom.endTalkSession.useMutation;
8018
8211
  /** Generated alias around `trpc.intercom.getStatus.useQuery`. */
8019
8212
  var useIntercomGetStatus = trpc.intercom.getStatus.useQuery;
8213
+ /** Generated alias around `trpc.keychainAdmin.status.useQuery`. */
8214
+ var useKeychainAdminStatus = trpc.keychainAdmin.status.useQuery;
8215
+ /** Generated alias around `trpc.keychainAdmin.listSecrets.useQuery`. */
8216
+ var useKeychainAdminListSecrets = trpc.keychainAdmin.listSecrets.useQuery;
8217
+ /** Generated alias around `trpc.keychainAdmin.listAudit.useQuery`. */
8218
+ var useKeychainAdminListAudit = trpc.keychainAdmin.listAudit.useQuery;
8219
+ /** Generated alias around `trpc.keychainAdmin.reveal.useMutation`. */
8220
+ var useKeychainAdminReveal = trpc.keychainAdmin.reveal.useMutation;
8221
+ /** Generated alias around `trpc.keychainAdmin.deleteOrphans.useMutation`. */
8222
+ var useKeychainAdminDeleteOrphans = trpc.keychainAdmin.deleteOrphans.useMutation;
8223
+ /** Generated alias around `trpc.keychainAdmin.rotateMasterKey.useMutation`. */
8224
+ var useKeychainAdminRotateMasterKey = trpc.keychainAdmin.rotateMasterKey.useMutation;
8225
+ /** Generated alias around `trpc.keychainAdmin.purgeRetiredKeys.useMutation`. */
8226
+ var useKeychainAdminPurgeRetiredKeys = trpc.keychainAdmin.purgeRetiredKeys.useMutation;
8227
+ /** Generated alias around `trpc.keychainAdmin.downloadRecoveryKey.useMutation`. */
8228
+ var useKeychainAdminDownloadRecoveryKey = trpc.keychainAdmin.downloadRecoveryKey.useMutation;
8229
+ /** Generated alias around `trpc.keychainAdmin.resetKeychain.useMutation`. */
8230
+ var useKeychainAdminResetKeychain = trpc.keychainAdmin.resetKeychain.useMutation;
8020
8231
  /** Generated alias around `trpc.lawnMowerControl.startMowing.useMutation`. */
8021
8232
  var useLawnMowerControlStartMowing = trpc.lawnMowerControl.startMowing.useMutation;
8022
8233
  /** Generated alias around `trpc.lawnMowerControl.pause.useMutation`. */
@@ -8557,6 +8768,26 @@ var usePipelineAnalyticsGetRetrainExportUrl = trpc.pipelineAnalytics.getRetrainE
8557
8768
  var usePipelineAnalyticsSetRetrainFrameComplete = trpc.pipelineAnalytics.setRetrainFrameComplete.useMutation;
8558
8769
  /** Generated alias around `trpc.pipelineAnalytics.writeRetrainArchive.useMutation`. */
8559
8770
  var usePipelineAnalyticsWriteRetrainArchive = trpc.pipelineAnalytics.writeRetrainArchive.useMutation;
8771
+ /** Generated alias around `trpc.pipelineAnalytics.listRetrainAssistProfiles.useQuery`. */
8772
+ var usePipelineAnalyticsListRetrainAssistProfiles = trpc.pipelineAnalytics.listRetrainAssistProfiles.useQuery;
8773
+ /** Generated alias around `trpc.pipelineAnalytics.proposeRetrainAnnotationsWithLlm.useMutation`. */
8774
+ var usePipelineAnalyticsProposeRetrainAnnotationsWithLlm = trpc.pipelineAnalytics.proposeRetrainAnnotationsWithLlm.useMutation;
8775
+ /** Generated alias around `trpc.pipelineAnalytics.createRetrainCollection.useMutation`. */
8776
+ var usePipelineAnalyticsCreateRetrainCollection = trpc.pipelineAnalytics.createRetrainCollection.useMutation;
8777
+ /** Generated alias around `trpc.pipelineAnalytics.listRetrainCollections.useQuery`. */
8778
+ var usePipelineAnalyticsListRetrainCollections = trpc.pipelineAnalytics.listRetrainCollections.useQuery;
8779
+ /** Generated alias around `trpc.pipelineAnalytics.renameRetrainCollection.useMutation`. */
8780
+ var usePipelineAnalyticsRenameRetrainCollection = trpc.pipelineAnalytics.renameRetrainCollection.useMutation;
8781
+ /** Generated alias around `trpc.pipelineAnalytics.deleteRetrainCollection.useMutation`. */
8782
+ var usePipelineAnalyticsDeleteRetrainCollection = trpc.pipelineAnalytics.deleteRetrainCollection.useMutation;
8783
+ /** Generated alias around `trpc.pipelineAnalytics.addRetrainFrameFromRecording.useMutation`. */
8784
+ var usePipelineAnalyticsAddRetrainFrameFromRecording = trpc.pipelineAnalytics.addRetrainFrameFromRecording.useMutation;
8785
+ /** Generated alias around `trpc.pipelineAnalytics.addRetrainFramesToCollection.useMutation`. */
8786
+ var usePipelineAnalyticsAddRetrainFramesToCollection = trpc.pipelineAnalytics.addRetrainFramesToCollection.useMutation;
8787
+ /** Generated alias around `trpc.pipelineAnalytics.removeRetrainFrameFromCollection.useMutation`. */
8788
+ var usePipelineAnalyticsRemoveRetrainFrameFromCollection = trpc.pipelineAnalytics.removeRetrainFrameFromCollection.useMutation;
8789
+ /** Generated alias around `trpc.pipelineAnalytics.listRetrainCollectionFrames.useQuery`. */
8790
+ var usePipelineAnalyticsListRetrainCollectionFrames = trpc.pipelineAnalytics.listRetrainCollectionFrames.useQuery;
8560
8791
  /** Generated alias around `trpc.pipelineAnalytics.getEventMedia.useQuery`. */
8561
8792
  var usePipelineAnalyticsGetEventMedia = trpc.pipelineAnalytics.getEventMedia.useQuery;
8562
8793
  /** Generated alias around `trpc.pipelineAnalytics.getTrackMedia.useQuery`. */
@@ -8729,6 +8960,20 @@ var usePipelineOrchestratorSuggestShares = trpc.pipelineOrchestrator.suggestShar
8729
8960
  var usePipelineOrchestratorGetEffectiveShares = trpc.pipelineOrchestrator.getEffectiveShares.useQuery;
8730
8961
  /** Generated alias around `trpc.pipelineOrchestrator.setShareSource.useMutation`. */
8731
8962
  var usePipelineOrchestratorSetShareSource = trpc.pipelineOrchestrator.setShareSource.useMutation;
8963
+ /** Generated alias around `trpc.pipelineOrchestrator.getNodeBenchmarkPreflight.useQuery`. */
8964
+ var usePipelineOrchestratorGetNodeBenchmarkPreflight = trpc.pipelineOrchestrator.getNodeBenchmarkPreflight.useQuery;
8965
+ /** Generated alias around `trpc.pipelineOrchestrator.startNodeBenchmark.useMutation`. */
8966
+ var usePipelineOrchestratorStartNodeBenchmark = trpc.pipelineOrchestrator.startNodeBenchmark.useMutation;
8967
+ /** Generated alias around `trpc.pipelineOrchestrator.getNodeBenchmarkStatus.useQuery`. */
8968
+ var usePipelineOrchestratorGetNodeBenchmarkStatus = trpc.pipelineOrchestrator.getNodeBenchmarkStatus.useQuery;
8969
+ /** Generated alias around `trpc.pipelineOrchestrator.abortNodeBenchmark.useMutation`. */
8970
+ var usePipelineOrchestratorAbortNodeBenchmark = trpc.pipelineOrchestrator.abortNodeBenchmark.useMutation;
8971
+ /** Generated alias around `trpc.pipelineOrchestrator.getNodeBenchmarkCandidates.useQuery`. */
8972
+ var usePipelineOrchestratorGetNodeBenchmarkCandidates = trpc.pipelineOrchestrator.getNodeBenchmarkCandidates.useQuery;
8973
+ /** Generated alias around `trpc.pipelineOrchestrator.listNodeBenchmarkResults.useQuery`. */
8974
+ var usePipelineOrchestratorListNodeBenchmarkResults = trpc.pipelineOrchestrator.listNodeBenchmarkResults.useQuery;
8975
+ /** Generated alias around `trpc.pipelineOrchestrator.deleteNodeBenchmarkResult.useMutation`. */
8976
+ var usePipelineOrchestratorDeleteNodeBenchmarkResult = trpc.pipelineOrchestrator.deleteNodeBenchmarkResult.useMutation;
8732
8977
  /** Generated alias around `trpc.pipelineOrchestrator.getCameraSettings.useQuery`. */
8733
8978
  var usePipelineOrchestratorGetCameraSettings = trpc.pipelineOrchestrator.getCameraSettings.useQuery;
8734
8979
  /** Generated alias around `trpc.pipelineOrchestrator.setCameraStepToggle.useMutation`. */
@@ -8793,6 +9038,12 @@ var usePipelineRunnerParkTrackFrame = trpc.pipelineRunner.parkTrackFrame.useMuta
8793
9038
  var usePipelineRunnerGetParkedTrackFrame = trpc.pipelineRunner.getParkedTrackFrame.useQuery;
8794
9039
  /** Generated alias around `trpc.pipelineRunner.releaseParkedTrackFrames.useMutation`. */
8795
9040
  var usePipelineRunnerReleaseParkedTrackFrames = trpc.pipelineRunner.releaseParkedTrackFrames.useMutation;
9041
+ /** Generated alias around `trpc.pipelineRunner.startNodeBench.useMutation`. */
9042
+ var usePipelineRunnerStartNodeBench = trpc.pipelineRunner.startNodeBench.useMutation;
9043
+ /** Generated alias around `trpc.pipelineRunner.getNodeBenchStatus.useQuery`. */
9044
+ var usePipelineRunnerGetNodeBenchStatus = trpc.pipelineRunner.getNodeBenchStatus.useQuery;
9045
+ /** Generated alias around `trpc.pipelineRunner.abortNodeBench.useMutation`. */
9046
+ var usePipelineRunnerAbortNodeBench = trpc.pipelineRunner.abortNodeBench.useMutation;
8796
9047
  /** Generated alias around `trpc.plateGallery.listPlates.useQuery`. */
8797
9048
  var usePlateGalleryListPlates = trpc.plateGallery.listPlates.useQuery;
8798
9049
  /** Generated alias around `trpc.plateGallery.getPlateByTrack.useQuery`. */
@@ -21638,7 +21889,7 @@ function formatDurationMs(ms) {
21638
21889
  * firmware inventing a refusal reaches the operator rather than becoming a
21639
21890
  * blank tile.
21640
21891
  */
21641
- var REFUSAL_TEXT = {
21892
+ var REFUSAL_TEXT$1 = {
21642
21893
  sleeping: () => "The camera is asleep — a still would cost a wake",
21643
21894
  "camera-refused": (reason) => `The camera refused — ${reason}`,
21644
21895
  "no-keyframe": () => "No decodable frame inside this window",
@@ -21650,7 +21901,7 @@ var REFUSAL_TEXT = {
21650
21901
  "uid-missing": () => "The camera’s id is not known yet"
21651
21902
  };
21652
21903
  function wordsFor(code, reason) {
21653
- const known = code === void 0 ? void 0 : REFUSAL_TEXT[code];
21904
+ const known = code === void 0 ? void 0 : REFUSAL_TEXT$1[code];
21654
21905
  return known === void 0 ? reason : known(reason);
21655
21906
  }
21656
21907
  function refusal(reason, code) {
@@ -25233,6 +25484,426 @@ function useScrubController(sink, isPlayerLive = () => false) {
25233
25484
  };
25234
25485
  }
25235
25486
  //#endregion
25487
+ //#region src/primitives/dialog.tsx
25488
+ var DialogContext = (0, react$1.createContext)(null);
25489
+ function useDialogContext() {
25490
+ const ctx = (0, react$1.useContext)(DialogContext);
25491
+ if (!ctx) throw new Error("Dialog compound components must be used within <Dialog>");
25492
+ return ctx;
25493
+ }
25494
+ function Dialog({ children, open: controlledOpen, onOpenChange }) {
25495
+ const [uncontrolledOpen, setUncontrolledOpen] = (0, react$1.useState)(false);
25496
+ const open = controlledOpen ?? uncontrolledOpen;
25497
+ const contentId = (0, react$1.useId)();
25498
+ const setOpen = (0, react$1.useCallback)((next) => {
25499
+ onOpenChange?.(next);
25500
+ if (controlledOpen === void 0) setUncontrolledOpen(next);
25501
+ }, [controlledOpen, onOpenChange]);
25502
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DialogContext.Provider, {
25503
+ value: {
25504
+ open,
25505
+ setOpen,
25506
+ contentId
25507
+ },
25508
+ children
25509
+ });
25510
+ }
25511
+ function DialogTrigger({ children, ...props }) {
25512
+ const { setOpen } = useDialogContext();
25513
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
25514
+ type: "button",
25515
+ onClick: () => setOpen(true),
25516
+ ...props,
25517
+ children
25518
+ });
25519
+ }
25520
+ /**
25521
+ * A native <dialog> opened with showModal() is promoted to the top layer, so
25522
+ * ancestor transform/overflow can't clip it — but it relies on the UA
25523
+ * stylesheet's `dialog { margin: auto }` for modal centering. Tailwind's
25524
+ * preflight resets `margin: 0` on every element, which defeats that centering
25525
+ * and pins the modal to the top-left. We therefore center deterministically:
25526
+ * a top-layer dialog with `position: fixed` is viewport-relative, and a
25527
+ * self-transform is fine, so `fixed left-1/2 top-1/2 -translate-x-1/2
25528
+ * -translate-y-1/2 m-0` always centers regardless of any margin reset. Width
25529
+ * is capped to the viewport (`w-[calc(100vw-2rem)]`) rather than a bare
25530
+ * `w-full` (which would overflow/clip a centered dialog); the per-variant
25531
+ * `max-w-*` keeps small dialogs small while the cap prevents overflow.
25532
+ *
25533
+ * Height is capped against the SAFE viewport, not the raw one. A top-layer
25534
+ * `fixed` dialog is viewport-relative, and under `viewport-fit=cover` the
25535
+ * viewport extends behind the iOS notch/Dynamic Island and home indicator —
25536
+ * so a dialog tall enough to hit its `max-h` put its header under the clock.
25537
+ * Because the box is centred on the viewport (not on the safe area), the cap
25538
+ * has to subtract TWICE the LARGER of the two insets for the box to clear
25539
+ * both edges; using each inset once would still overflow the taller side
25540
+ * whenever they are asymmetric (they are: ~59px top vs ~34px bottom). Every
25541
+ * term collapses to the previous `100dvh - 2rem` where the insets are 0.
25542
+ */
25543
+ var contentVariants = cva("fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 m-0 w-[calc(100vw-2rem)] bg-background-elevated text-foreground border border-border rounded-lg p-4 backdrop:bg-black/50 backdrop:backdrop-blur-sm max-h-[calc(100dvh-2rem-2*max(env(safe-area-inset-top),env(safe-area-inset-bottom)))] [&:not([open])]:hidden", {
25544
+ variants: {
25545
+ width: {
25546
+ sm: "max-w-sm",
25547
+ md: "max-w-md",
25548
+ lg: "max-w-lg"
25549
+ },
25550
+ /**
25551
+ * WHICH box scrolls when the content is taller than the height cap.
25552
+ *
25553
+ * `content` (default) scrolls the whole dialog: the title, any tab strip
25554
+ * and the Save/Cancel row travel with the fields. That is fine for a
25555
+ * short form and wrong for a long one — the operator scrolls to the
25556
+ * bottom of a rule editor and the buttons are somewhere above him, the
25557
+ * tab strip is gone, and the only way back to either is to scroll the
25558
+ * form he was reading.
25559
+ *
25560
+ * `body` makes the dialog a flex column that does not scroll at all and
25561
+ * hands the scrolling to `<DialogBody>`. The chrome around the body —
25562
+ * header, tab strip, footer — stays put at every height. The dialog
25563
+ * keeps its own padding either way, so `sheet-on-mobile`'s
25564
+ * safe-area bottom padding still applies to the footer.
25565
+ *
25566
+ * `body` also takes a DEFINITE height below `md` — see the
25567
+ * `scroll: 'body'` compound variants. That is not a style choice; the
25568
+ * flex chain does not resolve without it on iOS Safari.
25569
+ */
25570
+ scroll: {
25571
+ content: "overflow-y-auto",
25572
+ body: "flex flex-col overflow-hidden"
25573
+ },
25574
+ placement: {
25575
+ center: "",
25576
+ "sheet-on-mobile": "bottom-0 left-0 right-0 top-auto w-full max-w-full translate-x-0 translate-y-0 rounded-b-none max-h-[92dvh] pb-[calc(1rem+env(safe-area-inset-bottom))] md:left-1/2 md:top-1/2 md:-translate-x-1/2 md:-translate-y-1/2 md:rounded-lg md:bottom-auto md:pb-4 md:max-h-[calc(100dvh-2rem-2*max(env(safe-area-inset-top),env(safe-area-inset-bottom)))]"
25577
+ }
25578
+ },
25579
+ compoundVariants: [
25580
+ {
25581
+ placement: "sheet-on-mobile",
25582
+ width: "sm",
25583
+ class: "md:w-[calc(100vw-2rem)] md:max-w-sm"
25584
+ },
25585
+ {
25586
+ placement: "sheet-on-mobile",
25587
+ width: "md",
25588
+ class: "md:w-[calc(100vw-2rem)] md:max-w-md"
25589
+ },
25590
+ {
25591
+ placement: "sheet-on-mobile",
25592
+ width: "lg",
25593
+ class: "md:w-[calc(100vw-2rem)] md:max-w-lg"
25594
+ },
25595
+ {
25596
+ scroll: "body",
25597
+ placement: "sheet-on-mobile",
25598
+ class: "h-[92dvh] md:h-auto"
25599
+ },
25600
+ {
25601
+ scroll: "body",
25602
+ placement: "center",
25603
+ class: "h-[calc(100dvh-2rem-2*max(env(safe-area-inset-top),env(safe-area-inset-bottom)))] md:h-auto"
25604
+ }
25605
+ ],
25606
+ defaultVariants: {
25607
+ width: "md",
25608
+ placement: "center",
25609
+ scroll: "content"
25610
+ }
25611
+ });
25612
+ var DialogContent = (0, react$1.forwardRef)(({ className, width, placement, scroll, children, ...props }, ref) => {
25613
+ const { open, setOpen, contentId } = useDialogContext();
25614
+ const innerRef = (0, react$1.useRef)(null);
25615
+ const dialogRef = ref ?? innerRef;
25616
+ (0, react$1.useEffect)(() => {
25617
+ const el = dialogRef.current;
25618
+ if (!el) return;
25619
+ if (open && !el.open) el.showModal();
25620
+ if (!open && el.open) el.close();
25621
+ }, [open, dialogRef]);
25622
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dialog", {
25623
+ ref: dialogRef,
25624
+ id: contentId,
25625
+ className: cn(contentVariants({
25626
+ width,
25627
+ placement,
25628
+ scroll
25629
+ }), className),
25630
+ onClose: () => setOpen(false),
25631
+ ...props,
25632
+ children
25633
+ });
25634
+ });
25635
+ DialogContent.displayName = "DialogContent";
25636
+ /** `shrink-0` is inert outside a flex column and load-bearing inside one:
25637
+ * under `scroll="body"` the header must keep its height while the body gives
25638
+ * ground, or a long form squeezes its own title to nothing. */
25639
+ function DialogHeader({ className, ...props }) {
25640
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
25641
+ className: cn("flex flex-col gap-1 mb-3 shrink-0", className),
25642
+ ...props
25643
+ });
25644
+ }
25645
+ /**
25646
+ * The scrolling middle of a `scroll="body"` dialog.
25647
+ *
25648
+ * `min-h-0` is what makes it work: a flex item's default `min-height: auto`
25649
+ * refuses to shrink below its content, so without it the body pushes the
25650
+ * footer out of the dialog instead of scrolling — the exact failure this
25651
+ * variant exists to remove. Anything sticky INSIDE a dialog body pins against
25652
+ * this element, since it is the scroll container.
25653
+ *
25654
+ * It only bounds a scroll area if every ancestor up to the dialog has a
25655
+ * resolved height. `DialogContent` supplies the top of that chain (see the
25656
+ * `scroll: 'body'` compound variants); an intermediate wrapper between them —
25657
+ * a `<Tabs>` that owns the tab strip, say — must carry `flex-1 min-h-0` too,
25658
+ * or it collapses and takes the body with it.
25659
+ */
25660
+ function DialogBody({ className, ...props }) {
25661
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
25662
+ className: cn("flex-1 min-h-0 overflow-y-auto", className),
25663
+ ...props
25664
+ });
25665
+ }
25666
+ function DialogFooter({ className, ...props }) {
25667
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
25668
+ className: cn("flex justify-end gap-2 mt-4 shrink-0", className),
25669
+ ...props
25670
+ });
25671
+ }
25672
+ function DialogTitle({ className, ...props }) {
25673
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
25674
+ className: cn("text-sm font-semibold text-foreground", className),
25675
+ ...props
25676
+ });
25677
+ }
25678
+ function DialogDescription({ className, ...props }) {
25679
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
25680
+ className: cn("text-xs text-foreground-muted", className),
25681
+ ...props
25682
+ });
25683
+ }
25684
+ //#endregion
25685
+ //#region src/primitives/input.tsx
25686
+ /**
25687
+ * `disabled:opacity-50 disabled:cursor-not-allowed` for the same reason as
25688
+ * `Select` — an explicit `bg-surface` / `text-foreground` overrides the greying
25689
+ * a browser would otherwise apply, leaving an inert field indistinguishable
25690
+ * from a live one. See `disabled-affordance.test.tsx`.
25691
+ */
25692
+ var inputVariants = cva("h-7 w-full px-2.5 text-xs bg-surface border rounded-md text-foreground placeholder:text-foreground-subtle focus:outline-none focus:ring-1 focus:ring-primary transition-colors disabled:opacity-50 disabled:cursor-not-allowed", {
25693
+ variants: { state: {
25694
+ default: "border-border",
25695
+ error: "border-danger"
25696
+ } },
25697
+ defaultVariants: { state: "default" }
25698
+ });
25699
+ var Input = (0, react$1.forwardRef)(({ className, state, leftSlot, rightSlot, ...props }, ref) => {
25700
+ if (leftSlot || rightSlot) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
25701
+ className: "relative flex items-center w-full",
25702
+ children: [
25703
+ leftSlot && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
25704
+ className: "absolute left-2.5 flex items-center pointer-events-none",
25705
+ children: leftSlot
25706
+ }),
25707
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
25708
+ ref,
25709
+ className: cn(inputVariants({ state }), leftSlot ? "pl-7" : "", rightSlot ? "pr-7" : "", className),
25710
+ ...props
25711
+ }),
25712
+ rightSlot && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
25713
+ className: "absolute right-2.5 flex items-center pointer-events-none",
25714
+ children: rightSlot
25715
+ })
25716
+ ]
25717
+ });
25718
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
25719
+ ref,
25720
+ className: cn(inputVariants({ state }), className),
25721
+ ...props
25722
+ });
25723
+ });
25724
+ Input.displayName = "Input";
25725
+ //#endregion
25726
+ //#region src/composites/training/training-collection-picker.tsx
25727
+ /**
25728
+ * <TrainingCollectionPicker> — choose a named training collection, or create
25729
+ * one in place.
25730
+ *
25731
+ * A collection is a named set over the retrain corpus ("packages porch
25732
+ * night"). The picker lists them (newest first, with their frame counts) and
25733
+ * offers a name field for a new one; the hub refuses an empty or duplicate
25734
+ * name, and the refusal is shown here rather than swallowed.
25735
+ */
25736
+ var CREATE_REFUSAL = {
25737
+ "empty-name": "Give the collection a name.",
25738
+ "duplicate-name": "A collection with that name already exists."
25739
+ };
25740
+ function TrainingCollectionPicker({ value, onChange }) {
25741
+ const collections = usePipelineAnalyticsListRetrainCollections({});
25742
+ const create = usePipelineAnalyticsCreateRetrainCollection();
25743
+ const [name, setName] = (0, react$1.useState)("");
25744
+ const [error, setError] = (0, react$1.useState)(null);
25745
+ const list = collections.data ?? [];
25746
+ const onCreate = async () => {
25747
+ setError(null);
25748
+ const result = await create.mutateAsync({ name });
25749
+ if (result.kind === "refused") {
25750
+ setError(CREATE_REFUSAL[result.reason]);
25751
+ return;
25752
+ }
25753
+ setName("");
25754
+ await collections.refetch();
25755
+ onChange(result.collection.id);
25756
+ };
25757
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
25758
+ className: "space-y-2",
25759
+ "data-testid": "training-collection-picker",
25760
+ children: [
25761
+ list.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Select, {
25762
+ "aria-label": "Collection",
25763
+ value: value ?? "",
25764
+ options: [{
25765
+ value: "",
25766
+ label: "Choose a collection…"
25767
+ }, ...list.map((c) => ({
25768
+ value: c.id,
25769
+ label: `${c.name} (${String(c.frameCount)})`
25770
+ }))],
25771
+ onChange: (event) => {
25772
+ if (event.target.value !== "") onChange(event.target.value);
25773
+ }
25774
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
25775
+ className: "text-xs text-foreground-subtle",
25776
+ children: collections.isLoading ? "Reading the collections…" : "No collection yet — create one."
25777
+ }),
25778
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
25779
+ className: "flex items-center gap-2",
25780
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Input, {
25781
+ className: "flex-1",
25782
+ "aria-label": "New collection name",
25783
+ placeholder: "New collection (e.g. missed at night)",
25784
+ value: name,
25785
+ onChange: (event) => {
25786
+ setName(event.target.value);
25787
+ }
25788
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Button, {
25789
+ type: "button",
25790
+ variant: "secondary",
25791
+ size: "sm",
25792
+ disabled: create.isPending || name.trim() === "",
25793
+ onClick: () => void onCreate(),
25794
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Plus, { className: "h-3 w-3" }), "Create"]
25795
+ })]
25796
+ }),
25797
+ error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
25798
+ className: "text-xs text-danger",
25799
+ children: error
25800
+ })
25801
+ ]
25802
+ });
25803
+ }
25804
+ //#endregion
25805
+ //#region src/composites/training/training-refusal-text.ts
25806
+ var REFUSAL_TEXT = {
25807
+ "unknown-collection": "That collection no longer exists — pick another one.",
25808
+ "still-unavailable": "No frame could be taken from the recording at that moment.",
25809
+ "still-busy": "The recorder is busy decoding other frames. Try again in a moment.",
25810
+ "unreadable-image": "The recorder returned something that is not a picture.",
25811
+ "write-failed": "The frame could not be stored. Check the artifacts storage."
25812
+ };
25813
+ /** One sentence for a refusal, with the hub's own detail appended. */
25814
+ function trainingRefusalText(reason, detail) {
25815
+ const base = REFUSAL_TEXT[reason];
25816
+ return detail !== void 0 && detail !== "" ? `${base} (${detail})` : base;
25817
+ }
25818
+ //#endregion
25819
+ //#region src/composites/training/send-frame-to-training.tsx
25820
+ /**
25821
+ * <SendFrameToTrainingButton> — "Send frame to training" from a recording
25822
+ * playhead.
25823
+ *
25824
+ * The frame a detector most needs to learn from is often one where it saw
25825
+ * NOTHING — no event, no track, nothing to mark. From the recording, the
25826
+ * operator stops on that moment and sends it: the hub re-decodes the native
25827
+ * frame at the playhead instant and adds it to a named training collection,
25828
+ * where the Retrain page annotates it like any other frame.
25829
+ *
25830
+ * Draws NOTHING for a session that cannot curate training data: the
25831
+ * collection list is admin-only, and a button that 403s is worse than no
25832
+ * button. It is disabled, with the reason, while there is no playhead.
25833
+ */
25834
+ function SendFrameToTrainingButton({ deviceId, epochMs }) {
25835
+ const collections = usePipelineAnalyticsListRetrainCollections({}, { retry: false });
25836
+ const send = usePipelineAnalyticsAddRetrainFrameFromRecording();
25837
+ const [open, setOpen] = (0, react$1.useState)(false);
25838
+ const [collectionId, setCollectionId] = (0, react$1.useState)(null);
25839
+ const [instant, setInstant] = (0, react$1.useState)(null);
25840
+ const [outcome, setOutcome] = (0, react$1.useState)(null);
25841
+ if (collections.isError) return null;
25842
+ const onSend = async () => {
25843
+ if (collectionId === null || instant === null) return;
25844
+ const result = await send.mutateAsync({
25845
+ collectionId,
25846
+ deviceId,
25847
+ epochMs: instant
25848
+ });
25849
+ const name = collections.data?.find((c) => c.id === collectionId)?.name ?? "the collection";
25850
+ setOutcome(result.kind === "added" ? {
25851
+ kind: "added",
25852
+ reused: result.reused,
25853
+ collection: name
25854
+ } : {
25855
+ kind: "refused",
25856
+ text: trainingRefusalText(result.reason, result.detail)
25857
+ });
25858
+ if (result.kind === "added") await collections.refetch();
25859
+ };
25860
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Button, {
25861
+ type: "button",
25862
+ variant: "secondary",
25863
+ size: "sm",
25864
+ "data-testid": "send-frame-to-training",
25865
+ disabled: epochMs === null,
25866
+ title: epochMs === null ? "Play back a recording first — the frame at the playhead is the one sent" : "Add the frame at the playhead to a training collection",
25867
+ onClick: () => {
25868
+ setInstant(epochMs);
25869
+ setOutcome(null);
25870
+ setOpen(true);
25871
+ },
25872
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(GraduationCap, { className: "h-3.5 w-3.5" }), "Send frame to training"]
25873
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dialog, {
25874
+ open,
25875
+ onOpenChange: (next) => !send.isPending && setOpen(next),
25876
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(DialogContent, { children: [
25877
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(DialogHeader, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DialogTitle, { children: "Send this frame to training" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DialogDescription, { children: instant !== null ? `The camera's frame at ${new Date(instant).toLocaleString()} is taken from the recording at full resolution and added to the collection. Annotate it on the Retrain page — including what the model missed.` : "" })] }),
25878
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrainingCollectionPicker, {
25879
+ value: collectionId,
25880
+ onChange: setCollectionId
25881
+ }),
25882
+ outcome !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
25883
+ className: `mt-2 text-xs ${outcome.kind === "added" ? "text-success" : "text-danger"}`,
25884
+ role: "status",
25885
+ children: outcome.kind === "added" ? outcome.reused ? `That moment was already in the dataset; it is now in ${outcome.collection}.` : `Added to ${outcome.collection}.` : outcome.text
25886
+ }),
25887
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(DialogFooter, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
25888
+ type: "button",
25889
+ variant: "ghost",
25890
+ size: "sm",
25891
+ disabled: send.isPending,
25892
+ onClick: () => {
25893
+ setOpen(false);
25894
+ },
25895
+ children: outcome?.kind === "added" ? "Done" : "Cancel"
25896
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Button, {
25897
+ type: "button",
25898
+ size: "sm",
25899
+ disabled: collectionId === null || send.isPending || outcome?.kind === "added",
25900
+ onClick: () => void onSend(),
25901
+ children: [send.isPending && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LoaderCircle, { className: "h-3.5 w-3.5 animate-spin" }), "Send"]
25902
+ })] })
25903
+ ] })
25904
+ })] });
25905
+ }
25906
+ //#endregion
25236
25907
  //#region src/composites/cap-settings/CoverageTrack.tsx
25237
25908
  function CoverageTrack({ windowFrom, windowTo, spans, playheadMs, onSeek, onScrubStart, onScrubMove, onScrubEnd }) {
25238
25909
  const [hoverInfo, setHoverInfo] = (0, react$1.useState)(null);
@@ -25811,6 +26482,13 @@ function RecordingTimeline({ deviceId }) {
25811
26482
  dayBounds: computedDayBounds,
25812
26483
  onViewChange: handleViewChange
25813
26484
  }),
26485
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
26486
+ className: "flex justify-end",
26487
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SendFrameToTrainingButton, {
26488
+ deviceId,
26489
+ epochMs: displayPlayheadMs
26490
+ })
26491
+ }),
25814
26492
  recorded.channelOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
25815
26493
  "data-testid": "frame-push-status-row",
25816
26494
  className: "flex flex-wrap items-center gap-2 text-[10px]",
@@ -27408,6 +28086,32 @@ function FieldWrapper({ label, description, required, span, children, translatio
27408
28086
  ]
27409
28087
  });
27410
28088
  }
28089
+ /**
28090
+ * A keychain-stored secret (D787) arrives as its VIEW — `{ $secret, set }` —
28091
+ * or `null`, never as a value; it renders as "set · Change · Clear · Reveal".
28092
+ * Decided ONCE, at mount, from what the form was hydrated with: once the
28093
+ * operator types, the value is a plain string and the field must stay the
28094
+ * same control. A form that was not hydrated from a keychain-aware store (a
28095
+ * create dialog seeding `''`) keeps the plain input.
28096
+ */
28097
+ function KeychainOr({ field, value, onChange, disabled, translationFn, multiline, children }) {
28098
+ const [keychain] = (0, react$1.useState)(() => (0, _camstack_types.isKeychainStoredField)(field) && isKeychainFieldValue(value));
28099
+ if (!keychain) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children });
28100
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldWrapper, {
28101
+ label: "label" in field ? field.label : void 0,
28102
+ description: "description" in field ? field.description : void 0,
28103
+ required: "required" in field ? field.required : void 0,
28104
+ span: "span" in field ? field.span : void 0,
28105
+ translationFn,
28106
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SecretFieldControl, {
28107
+ field,
28108
+ value,
28109
+ onChange,
28110
+ disabled,
28111
+ multiline
28112
+ })
28113
+ });
28114
+ }
27411
28115
  function TextField({ field, value, onChange, disabled, translationFn }) {
27412
28116
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldWrapper, {
27413
28117
  label: field.label,
@@ -28480,7 +29184,7 @@ function resolveActionParams(field, values) {
28480
29184
  const params = { ...field.paramsStatic };
28481
29185
  if (field.paramsFromForm) for (const [paramKey, formKey] of Object.entries(field.paramsFromForm)) {
28482
29186
  const v = values[formKey];
28483
- if (v !== void 0 && v !== null && v !== "") params[paramKey] = v;
29187
+ if (v !== void 0 && v !== null && v !== "" && !(0, _camstack_types.isSecretClear)(v)) params[paramKey] = v;
28484
29188
  }
28485
29189
  return params;
28486
29190
  }
@@ -28976,12 +29680,19 @@ function FormField({ field, values, onChange, disabled, translationFn, onTestFie
28976
29680
  const handleChange = (v) => onChange(field.key, v);
28977
29681
  const customRenderer = useCustomFieldRenderer(field.type);
28978
29682
  switch (field.type) {
28979
- case "text": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
29683
+ case "text": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KeychainOr, {
28980
29684
  field,
28981
29685
  value,
28982
29686
  onChange: handleChange,
28983
29687
  disabled,
28984
- translationFn
29688
+ translationFn,
29689
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
29690
+ field,
29691
+ value,
29692
+ onChange: handleChange,
29693
+ disabled,
29694
+ translationFn
29695
+ })
28985
29696
  });
28986
29697
  case "number": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NumberField, {
28987
29698
  field,
@@ -29025,19 +29736,34 @@ function FormField({ field, values, onChange, disabled, translationFn, onTestFie
29025
29736
  disabled,
29026
29737
  translationFn
29027
29738
  });
29028
- case "password": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PasswordField, {
29739
+ case "password": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KeychainOr, {
29029
29740
  field,
29030
29741
  value,
29031
29742
  onChange: handleChange,
29032
29743
  disabled,
29033
- translationFn
29744
+ translationFn,
29745
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PasswordField, {
29746
+ field,
29747
+ value,
29748
+ onChange: handleChange,
29749
+ disabled,
29750
+ translationFn
29751
+ })
29034
29752
  });
29035
- case "textarea": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextAreaField, {
29753
+ case "textarea": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KeychainOr, {
29036
29754
  field,
29037
29755
  value,
29038
29756
  onChange: handleChange,
29039
29757
  disabled,
29040
- translationFn
29758
+ translationFn,
29759
+ multiline: true,
29760
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextAreaField, {
29761
+ field,
29762
+ value,
29763
+ onChange: handleChange,
29764
+ disabled,
29765
+ translationFn
29766
+ })
29041
29767
  });
29042
29768
  case "slider": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SliderField, {
29043
29769
  field,
@@ -30839,47 +31565,6 @@ var Separator = (0, react$1.forwardRef)(({ className, orientation, ...props }, r
30839
31565
  });
30840
31566
  Separator.displayName = "Separator";
30841
31567
  //#endregion
30842
- //#region src/primitives/input.tsx
30843
- /**
30844
- * `disabled:opacity-50 disabled:cursor-not-allowed` for the same reason as
30845
- * `Select` — an explicit `bg-surface` / `text-foreground` overrides the greying
30846
- * a browser would otherwise apply, leaving an inert field indistinguishable
30847
- * from a live one. See `disabled-affordance.test.tsx`.
30848
- */
30849
- var inputVariants = cva("h-7 w-full px-2.5 text-xs bg-surface border rounded-md text-foreground placeholder:text-foreground-subtle focus:outline-none focus:ring-1 focus:ring-primary transition-colors disabled:opacity-50 disabled:cursor-not-allowed", {
30850
- variants: { state: {
30851
- default: "border-border",
30852
- error: "border-danger"
30853
- } },
30854
- defaultVariants: { state: "default" }
30855
- });
30856
- var Input = (0, react$1.forwardRef)(({ className, state, leftSlot, rightSlot, ...props }, ref) => {
30857
- if (leftSlot || rightSlot) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
30858
- className: "relative flex items-center w-full",
30859
- children: [
30860
- leftSlot && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
30861
- className: "absolute left-2.5 flex items-center pointer-events-none",
30862
- children: leftSlot
30863
- }),
30864
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
30865
- ref,
30866
- className: cn(inputVariants({ state }), leftSlot ? "pl-7" : "", rightSlot ? "pr-7" : "", className),
30867
- ...props
30868
- }),
30869
- rightSlot && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
30870
- className: "absolute right-2.5 flex items-center pointer-events-none",
30871
- children: rightSlot
30872
- })
30873
- ]
30874
- });
30875
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
30876
- ref,
30877
- className: cn(inputVariants({ state }), className),
30878
- ...props
30879
- });
30880
- });
30881
- Input.displayName = "Input";
30882
- //#endregion
30883
31568
  //#region src/primitives/checkbox.tsx
30884
31569
  var Checkbox = (0, react$1.forwardRef)(({ className, ...props }, ref) => {
30885
31570
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -30912,204 +31597,6 @@ var Switch = (0, react$1.forwardRef)(({ className, checked, onCheckedChange, lab
30912
31597
  });
30913
31598
  Switch.displayName = "Switch";
30914
31599
  //#endregion
30915
- //#region src/primitives/dialog.tsx
30916
- var DialogContext = (0, react$1.createContext)(null);
30917
- function useDialogContext() {
30918
- const ctx = (0, react$1.useContext)(DialogContext);
30919
- if (!ctx) throw new Error("Dialog compound components must be used within <Dialog>");
30920
- return ctx;
30921
- }
30922
- function Dialog({ children, open: controlledOpen, onOpenChange }) {
30923
- const [uncontrolledOpen, setUncontrolledOpen] = (0, react$1.useState)(false);
30924
- const open = controlledOpen ?? uncontrolledOpen;
30925
- const contentId = (0, react$1.useId)();
30926
- const setOpen = (0, react$1.useCallback)((next) => {
30927
- onOpenChange?.(next);
30928
- if (controlledOpen === void 0) setUncontrolledOpen(next);
30929
- }, [controlledOpen, onOpenChange]);
30930
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DialogContext.Provider, {
30931
- value: {
30932
- open,
30933
- setOpen,
30934
- contentId
30935
- },
30936
- children
30937
- });
30938
- }
30939
- function DialogTrigger({ children, ...props }) {
30940
- const { setOpen } = useDialogContext();
30941
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
30942
- type: "button",
30943
- onClick: () => setOpen(true),
30944
- ...props,
30945
- children
30946
- });
30947
- }
30948
- /**
30949
- * A native <dialog> opened with showModal() is promoted to the top layer, so
30950
- * ancestor transform/overflow can't clip it — but it relies on the UA
30951
- * stylesheet's `dialog { margin: auto }` for modal centering. Tailwind's
30952
- * preflight resets `margin: 0` on every element, which defeats that centering
30953
- * and pins the modal to the top-left. We therefore center deterministically:
30954
- * a top-layer dialog with `position: fixed` is viewport-relative, and a
30955
- * self-transform is fine, so `fixed left-1/2 top-1/2 -translate-x-1/2
30956
- * -translate-y-1/2 m-0` always centers regardless of any margin reset. Width
30957
- * is capped to the viewport (`w-[calc(100vw-2rem)]`) rather than a bare
30958
- * `w-full` (which would overflow/clip a centered dialog); the per-variant
30959
- * `max-w-*` keeps small dialogs small while the cap prevents overflow.
30960
- *
30961
- * Height is capped against the SAFE viewport, not the raw one. A top-layer
30962
- * `fixed` dialog is viewport-relative, and under `viewport-fit=cover` the
30963
- * viewport extends behind the iOS notch/Dynamic Island and home indicator —
30964
- * so a dialog tall enough to hit its `max-h` put its header under the clock.
30965
- * Because the box is centred on the viewport (not on the safe area), the cap
30966
- * has to subtract TWICE the LARGER of the two insets for the box to clear
30967
- * both edges; using each inset once would still overflow the taller side
30968
- * whenever they are asymmetric (they are: ~59px top vs ~34px bottom). Every
30969
- * term collapses to the previous `100dvh - 2rem` where the insets are 0.
30970
- */
30971
- var contentVariants = cva("fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 m-0 w-[calc(100vw-2rem)] bg-background-elevated text-foreground border border-border rounded-lg p-4 backdrop:bg-black/50 backdrop:backdrop-blur-sm max-h-[calc(100dvh-2rem-2*max(env(safe-area-inset-top),env(safe-area-inset-bottom)))] [&:not([open])]:hidden", {
30972
- variants: {
30973
- width: {
30974
- sm: "max-w-sm",
30975
- md: "max-w-md",
30976
- lg: "max-w-lg"
30977
- },
30978
- /**
30979
- * WHICH box scrolls when the content is taller than the height cap.
30980
- *
30981
- * `content` (default) scrolls the whole dialog: the title, any tab strip
30982
- * and the Save/Cancel row travel with the fields. That is fine for a
30983
- * short form and wrong for a long one — the operator scrolls to the
30984
- * bottom of a rule editor and the buttons are somewhere above him, the
30985
- * tab strip is gone, and the only way back to either is to scroll the
30986
- * form he was reading.
30987
- *
30988
- * `body` makes the dialog a flex column that does not scroll at all and
30989
- * hands the scrolling to `<DialogBody>`. The chrome around the body —
30990
- * header, tab strip, footer — stays put at every height. The dialog
30991
- * keeps its own padding either way, so `sheet-on-mobile`'s
30992
- * safe-area bottom padding still applies to the footer.
30993
- *
30994
- * `body` also takes a DEFINITE height below `md` — see the
30995
- * `scroll: 'body'` compound variants. That is not a style choice; the
30996
- * flex chain does not resolve without it on iOS Safari.
30997
- */
30998
- scroll: {
30999
- content: "overflow-y-auto",
31000
- body: "flex flex-col overflow-hidden"
31001
- },
31002
- placement: {
31003
- center: "",
31004
- "sheet-on-mobile": "bottom-0 left-0 right-0 top-auto w-full max-w-full translate-x-0 translate-y-0 rounded-b-none max-h-[92dvh] pb-[calc(1rem+env(safe-area-inset-bottom))] md:left-1/2 md:top-1/2 md:-translate-x-1/2 md:-translate-y-1/2 md:rounded-lg md:bottom-auto md:pb-4 md:max-h-[calc(100dvh-2rem-2*max(env(safe-area-inset-top),env(safe-area-inset-bottom)))]"
31005
- }
31006
- },
31007
- compoundVariants: [
31008
- {
31009
- placement: "sheet-on-mobile",
31010
- width: "sm",
31011
- class: "md:w-[calc(100vw-2rem)] md:max-w-sm"
31012
- },
31013
- {
31014
- placement: "sheet-on-mobile",
31015
- width: "md",
31016
- class: "md:w-[calc(100vw-2rem)] md:max-w-md"
31017
- },
31018
- {
31019
- placement: "sheet-on-mobile",
31020
- width: "lg",
31021
- class: "md:w-[calc(100vw-2rem)] md:max-w-lg"
31022
- },
31023
- {
31024
- scroll: "body",
31025
- placement: "sheet-on-mobile",
31026
- class: "h-[92dvh] md:h-auto"
31027
- },
31028
- {
31029
- scroll: "body",
31030
- placement: "center",
31031
- class: "h-[calc(100dvh-2rem-2*max(env(safe-area-inset-top),env(safe-area-inset-bottom)))] md:h-auto"
31032
- }
31033
- ],
31034
- defaultVariants: {
31035
- width: "md",
31036
- placement: "center",
31037
- scroll: "content"
31038
- }
31039
- });
31040
- var DialogContent = (0, react$1.forwardRef)(({ className, width, placement, scroll, children, ...props }, ref) => {
31041
- const { open, setOpen, contentId } = useDialogContext();
31042
- const innerRef = (0, react$1.useRef)(null);
31043
- const dialogRef = ref ?? innerRef;
31044
- (0, react$1.useEffect)(() => {
31045
- const el = dialogRef.current;
31046
- if (!el) return;
31047
- if (open && !el.open) el.showModal();
31048
- if (!open && el.open) el.close();
31049
- }, [open, dialogRef]);
31050
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dialog", {
31051
- ref: dialogRef,
31052
- id: contentId,
31053
- className: cn(contentVariants({
31054
- width,
31055
- placement,
31056
- scroll
31057
- }), className),
31058
- onClose: () => setOpen(false),
31059
- ...props,
31060
- children
31061
- });
31062
- });
31063
- DialogContent.displayName = "DialogContent";
31064
- /** `shrink-0` is inert outside a flex column and load-bearing inside one:
31065
- * under `scroll="body"` the header must keep its height while the body gives
31066
- * ground, or a long form squeezes its own title to nothing. */
31067
- function DialogHeader({ className, ...props }) {
31068
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
31069
- className: cn("flex flex-col gap-1 mb-3 shrink-0", className),
31070
- ...props
31071
- });
31072
- }
31073
- /**
31074
- * The scrolling middle of a `scroll="body"` dialog.
31075
- *
31076
- * `min-h-0` is what makes it work: a flex item's default `min-height: auto`
31077
- * refuses to shrink below its content, so without it the body pushes the
31078
- * footer out of the dialog instead of scrolling — the exact failure this
31079
- * variant exists to remove. Anything sticky INSIDE a dialog body pins against
31080
- * this element, since it is the scroll container.
31081
- *
31082
- * It only bounds a scroll area if every ancestor up to the dialog has a
31083
- * resolved height. `DialogContent` supplies the top of that chain (see the
31084
- * `scroll: 'body'` compound variants); an intermediate wrapper between them —
31085
- * a `<Tabs>` that owns the tab strip, say — must carry `flex-1 min-h-0` too,
31086
- * or it collapses and takes the body with it.
31087
- */
31088
- function DialogBody({ className, ...props }) {
31089
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
31090
- className: cn("flex-1 min-h-0 overflow-y-auto", className),
31091
- ...props
31092
- });
31093
- }
31094
- function DialogFooter({ className, ...props }) {
31095
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
31096
- className: cn("flex justify-end gap-2 mt-4 shrink-0", className),
31097
- ...props
31098
- });
31099
- }
31100
- function DialogTitle({ className, ...props }) {
31101
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
31102
- className: cn("text-sm font-semibold text-foreground", className),
31103
- ...props
31104
- });
31105
- }
31106
- function DialogDescription({ className, ...props }) {
31107
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
31108
- className: cn("text-xs text-foreground-muted", className),
31109
- ...props
31110
- });
31111
- }
31112
- //#endregion
31113
31600
  //#region src/primitives/tooltip.tsx
31114
31601
  var TooltipContext = (0, react$1.createContext)(null);
31115
31602
  function useTooltipContext() {
@@ -61463,6 +61950,7 @@ exports.RotateCcw = RotateCcw;
61463
61950
  exports.RunReport = RunReport;
61464
61951
  exports.SCENE_CAPTURE_VARIANTS = SCENE_CAPTURE_VARIANTS;
61465
61952
  exports.SCENE_CAPTURE_VARIANTS$1 = SCENE_CAPTURE_VARIANTS;
61953
+ exports.SECRET_REVEAL_MS = SECRET_REVEAL_MS;
61466
61954
  exports.SECTION_BODY = SECTION_BODY;
61467
61955
  exports.SECTION_CARD = SECTION_CARD;
61468
61956
  exports.SECTION_HEADER = SECTION_HEADER;
@@ -61482,11 +61970,14 @@ exports.ScopePicker = ScopePicker;
61482
61970
  exports.ScriptHeroCard = ScriptHeroCard;
61483
61971
  exports.ScriptInlineControl = ScriptInlineControl;
61484
61972
  exports.ScrollArea = ScrollArea;
61973
+ exports.SecretFieldControl = SecretFieldControl;
61974
+ exports.SecretRevealProvider = SecretRevealProvider;
61485
61975
  exports.SectionCard = SectionCard;
61486
61976
  exports.SegmentedChoice = SegmentedChoice;
61487
61977
  exports.Select = Select;
61488
61978
  exports.SelectedChip = SelectedChip;
61489
61979
  exports.SemanticBadge = SemanticBadge;
61980
+ exports.SendFrameToTrainingButton = SendFrameToTrainingButton;
61490
61981
  exports.SensorHeroCard = SensorHeroCard;
61491
61982
  exports.SensorInlineControl = SensorInlineControl;
61492
61983
  exports.SensorValueAtom = SensorValueAtom;
@@ -61534,6 +62025,7 @@ exports.TimezoneSelector = TimezoneSelector;
61534
62025
  exports.Tooltip = Tooltip;
61535
62026
  exports.TooltipContent = TooltipContent;
61536
62027
  exports.TooltipTrigger = TooltipTrigger;
62028
+ exports.TrainingCollectionPicker = TrainingCollectionPicker;
61537
62029
  exports.Trash2 = Trash2;
61538
62030
  exports.UnitPicker = UnitPicker;
61539
62031
  exports.VacuumHeroCard = VacuumHeroCard;
@@ -61644,6 +62136,7 @@ exports.isAbsentProvider$1 = isAbsentProvider;
61644
62136
  exports.isDataTableFilterActive = isDataTableFilterActive;
61645
62137
  exports.isFieldVisible = isFieldVisible;
61646
62138
  exports.isGroupExpanded = isGroupExpanded;
62139
+ exports.isKeychainFieldValue = isKeychainFieldValue;
61647
62140
  exports.isValueField = isValueField;
61648
62141
  exports.lawnMowerActivityMeta = lawnMowerActivityMeta;
61649
62142
  exports.lightColors = require_theme_index.lightColors$1;
@@ -61740,6 +62233,7 @@ exports.toStationaryOverlayBox = toStationaryOverlayBox;
61740
62233
  exports.toggleDataTableFacet = toggleDataTableFacet;
61741
62234
  exports.togglePickerDevice = togglePickerDevice;
61742
62235
  exports.togglePickerKey = togglePickerKey;
62236
+ exports.trainingRefusalText = trainingRefusalText;
61743
62237
  exports.trpc = trpc;
61744
62238
  exports.typeLabel = typeLabel;
61745
62239
  exports.useAccessoriesGetStatus = useAccessoriesGetStatus;
@@ -62172,6 +62666,15 @@ exports.useIntercomStartTalkSession = useIntercomStartTalkSession;
62172
62666
  exports.useIntercomStopSession = useIntercomStopSession;
62173
62667
  exports.useIsMidWidth = useIsMidWidth;
62174
62668
  exports.useIsMobile = useIsMobile;
62669
+ exports.useKeychainAdminDeleteOrphans = useKeychainAdminDeleteOrphans;
62670
+ exports.useKeychainAdminDownloadRecoveryKey = useKeychainAdminDownloadRecoveryKey;
62671
+ exports.useKeychainAdminListAudit = useKeychainAdminListAudit;
62672
+ exports.useKeychainAdminListSecrets = useKeychainAdminListSecrets;
62673
+ exports.useKeychainAdminPurgeRetiredKeys = useKeychainAdminPurgeRetiredKeys;
62674
+ exports.useKeychainAdminResetKeychain = useKeychainAdminResetKeychain;
62675
+ exports.useKeychainAdminReveal = useKeychainAdminReveal;
62676
+ exports.useKeychainAdminRotateMasterKey = useKeychainAdminRotateMasterKey;
62677
+ exports.useKeychainAdminStatus = useKeychainAdminStatus;
62175
62678
  exports.useLawnMowerControlDock = useLawnMowerControlDock;
62176
62679
  exports.useLawnMowerControlGetStatus = useLawnMowerControlGetStatus;
62177
62680
  exports.useLawnMowerControlPause = useLawnMowerControlPause;
@@ -62390,6 +62893,8 @@ exports.usePetFeederSetFeedSound = usePetFeederSetFeedSound;
62390
62893
  exports.usePetFeederSetIndicatorLight = usePetFeederSetIndicatorLight;
62391
62894
  exports.usePetFeederSetVolume = usePetFeederSetVolume;
62392
62895
  exports.usePickerSiteZones = usePickerSiteZones;
62896
+ exports.usePipelineAnalyticsAddRetrainFrameFromRecording = usePipelineAnalyticsAddRetrainFrameFromRecording;
62897
+ exports.usePipelineAnalyticsAddRetrainFramesToCollection = usePipelineAnalyticsAddRetrainFramesToCollection;
62393
62898
  exports.usePipelineAnalyticsApplyDeviceSettingsPatch = usePipelineAnalyticsApplyDeviceSettingsPatch;
62394
62899
  exports.usePipelineAnalyticsCancelRelocateMedia = usePipelineAnalyticsCancelRelocateMedia;
62395
62900
  exports.usePipelineAnalyticsCancelStorageMigrationMove = usePipelineAnalyticsCancelStorageMigrationMove;
@@ -62398,7 +62903,9 @@ exports.usePipelineAnalyticsClearTracks = usePipelineAnalyticsClearTracks;
62398
62903
  exports.usePipelineAnalyticsCompleteRetrainTrack = usePipelineAnalyticsCompleteRetrainTrack;
62399
62904
  exports.usePipelineAnalyticsCountRelocatableMedia = usePipelineAnalyticsCountRelocatableMedia;
62400
62905
  exports.usePipelineAnalyticsCountUnstampedEventMedia = usePipelineAnalyticsCountUnstampedEventMedia;
62906
+ exports.usePipelineAnalyticsCreateRetrainCollection = usePipelineAnalyticsCreateRetrainCollection;
62401
62907
  exports.usePipelineAnalyticsDeleteDeviceEvents = usePipelineAnalyticsDeleteDeviceEvents;
62908
+ exports.usePipelineAnalyticsDeleteRetrainCollection = usePipelineAnalyticsDeleteRetrainCollection;
62402
62909
  exports.usePipelineAnalyticsDeleteTracks = usePipelineAnalyticsDeleteTracks;
62403
62910
  exports.usePipelineAnalyticsDeselectRetrainFrame = usePipelineAnalyticsDeselectRetrainFrame;
62404
62911
  exports.usePipelineAnalyticsGetActiveTracks = usePipelineAnalyticsGetActiveTracks;
@@ -62433,6 +62940,9 @@ exports.usePipelineAnalyticsListOpsLog = usePipelineAnalyticsListOpsLog;
62433
62940
  exports.usePipelineAnalyticsListRecentTracks = usePipelineAnalyticsListRecentTracks;
62434
62941
  exports.usePipelineAnalyticsListRelocateMediaJobs = usePipelineAnalyticsListRelocateMediaJobs;
62435
62942
  exports.usePipelineAnalyticsListRetrainAnnotations = usePipelineAnalyticsListRetrainAnnotations;
62943
+ exports.usePipelineAnalyticsListRetrainAssistProfiles = usePipelineAnalyticsListRetrainAssistProfiles;
62944
+ exports.usePipelineAnalyticsListRetrainCollectionFrames = usePipelineAnalyticsListRetrainCollectionFrames;
62945
+ exports.usePipelineAnalyticsListRetrainCollections = usePipelineAnalyticsListRetrainCollections;
62436
62946
  exports.usePipelineAnalyticsListRetrainFrames = usePipelineAnalyticsListRetrainFrames;
62437
62947
  exports.usePipelineAnalyticsListRetrainStaging = usePipelineAnalyticsListRetrainStaging;
62438
62948
  exports.usePipelineAnalyticsListTrackMedia = usePipelineAnalyticsListTrackMedia;
@@ -62441,6 +62951,7 @@ exports.usePipelineAnalyticsListTracks = usePipelineAnalyticsListTracks;
62441
62951
  exports.usePipelineAnalyticsOwnersWithMedia = usePipelineAnalyticsOwnersWithMedia;
62442
62952
  exports.usePipelineAnalyticsPauseForStorageMigration = usePipelineAnalyticsPauseForStorageMigration;
62443
62953
  exports.usePipelineAnalyticsProposeRetrainAnnotations = usePipelineAnalyticsProposeRetrainAnnotations;
62954
+ exports.usePipelineAnalyticsProposeRetrainAnnotationsWithLlm = usePipelineAnalyticsProposeRetrainAnnotationsWithLlm;
62444
62955
  exports.usePipelineAnalyticsPruneEvents = usePipelineAnalyticsPruneEvents;
62445
62956
  exports.usePipelineAnalyticsPruneEventsBefore = usePipelineAnalyticsPruneEventsBefore;
62446
62957
  exports.usePipelineAnalyticsPruneTracksBefore = usePipelineAnalyticsPruneTracksBefore;
@@ -62450,6 +62961,8 @@ exports.usePipelineAnalyticsReclaimDebugMedia = usePipelineAnalyticsReclaimDebug
62450
62961
  exports.usePipelineAnalyticsReconcileFromDisk = usePipelineAnalyticsReconcileFromDisk;
62451
62962
  exports.usePipelineAnalyticsRefreshStorageLocationsForMigration = usePipelineAnalyticsRefreshStorageLocationsForMigration;
62452
62963
  exports.usePipelineAnalyticsRelocateMedia = usePipelineAnalyticsRelocateMedia;
62964
+ exports.usePipelineAnalyticsRemoveRetrainFrameFromCollection = usePipelineAnalyticsRemoveRetrainFrameFromCollection;
62965
+ exports.usePipelineAnalyticsRenameRetrainCollection = usePipelineAnalyticsRenameRetrainCollection;
62453
62966
  exports.usePipelineAnalyticsRestageRetrainTrack = usePipelineAnalyticsRestageRetrainTrack;
62454
62967
  exports.usePipelineAnalyticsResumeForStorageMigration = usePipelineAnalyticsResumeForStorageMigration;
62455
62968
  exports.usePipelineAnalyticsSaveRetrainAnnotations = usePipelineAnalyticsSaveRetrainAnnotations;
@@ -62498,10 +63011,12 @@ exports.usePipelineExecutorSetVideoPipelineSteps = usePipelineExecutorSetVideoPi
62498
63011
  exports.usePipelineExecutorSpinEngine = usePipelineExecutorSpinEngine;
62499
63012
  exports.usePipelineExecutorUncacheFrame = usePipelineExecutorUncacheFrame;
62500
63013
  exports.usePipelineExecutorValidatePipeline = usePipelineExecutorValidatePipeline;
63014
+ exports.usePipelineOrchestratorAbortNodeBenchmark = usePipelineOrchestratorAbortNodeBenchmark;
62501
63015
  exports.usePipelineOrchestratorApplyAutoTune = usePipelineOrchestratorApplyAutoTune;
62502
63016
  exports.usePipelineOrchestratorApplyDeviceSettingsPatch = usePipelineOrchestratorApplyDeviceSettingsPatch;
62503
63017
  exports.usePipelineOrchestratorAssignAudio = usePipelineOrchestratorAssignAudio;
62504
63018
  exports.usePipelineOrchestratorAssignPipeline = usePipelineOrchestratorAssignPipeline;
63019
+ exports.usePipelineOrchestratorDeleteNodeBenchmarkResult = usePipelineOrchestratorDeleteNodeBenchmarkResult;
62505
63020
  exports.usePipelineOrchestratorGetAgentLoad = usePipelineOrchestratorGetAgentLoad;
62506
63021
  exports.usePipelineOrchestratorGetAgentSettings = usePipelineOrchestratorGetAgentSettings;
62507
63022
  exports.usePipelineOrchestratorGetAudioAssignment = usePipelineOrchestratorGetAudioAssignment;
@@ -62520,6 +63035,9 @@ exports.usePipelineOrchestratorGetDeviceSettingsContribution = usePipelineOrches
62520
63035
  exports.usePipelineOrchestratorGetEffectiveShares = usePipelineOrchestratorGetEffectiveShares;
62521
63036
  exports.usePipelineOrchestratorGetGlobalMetrics = usePipelineOrchestratorGetGlobalMetrics;
62522
63037
  exports.usePipelineOrchestratorGetIngestOwner = usePipelineOrchestratorGetIngestOwner;
63038
+ exports.usePipelineOrchestratorGetNodeBenchmarkCandidates = usePipelineOrchestratorGetNodeBenchmarkCandidates;
63039
+ exports.usePipelineOrchestratorGetNodeBenchmarkPreflight = usePipelineOrchestratorGetNodeBenchmarkPreflight;
63040
+ exports.usePipelineOrchestratorGetNodeBenchmarkStatus = usePipelineOrchestratorGetNodeBenchmarkStatus;
62523
63041
  exports.usePipelineOrchestratorGetNodeInferenceDevices = usePipelineOrchestratorGetNodeInferenceDevices;
62524
63042
  exports.usePipelineOrchestratorGetPipelineAssignment = usePipelineOrchestratorGetPipelineAssignment;
62525
63043
  exports.usePipelineOrchestratorGetPipelineAssignments = usePipelineOrchestratorGetPipelineAssignments;
@@ -62527,6 +63045,7 @@ exports.usePipelineOrchestratorGetPipelineDevicePin = usePipelineOrchestratorGet
62527
63045
  exports.usePipelineOrchestratorGetPlacementStats = usePipelineOrchestratorGetPlacementStats;
62528
63046
  exports.usePipelineOrchestratorGetReconcileFromDiskStatus = usePipelineOrchestratorGetReconcileFromDiskStatus;
62529
63047
  exports.usePipelineOrchestratorListAgentSettings = usePipelineOrchestratorListAgentSettings;
63048
+ exports.usePipelineOrchestratorListNodeBenchmarkResults = usePipelineOrchestratorListNodeBenchmarkResults;
62530
63049
  exports.usePipelineOrchestratorPauseForStorageMigration = usePipelineOrchestratorPauseForStorageMigration;
62531
63050
  exports.usePipelineOrchestratorPlanAutoTune = usePipelineOrchestratorPlanAutoTune;
62532
63051
  exports.usePipelineOrchestratorRebalance = usePipelineOrchestratorRebalance;
@@ -62551,9 +63070,11 @@ exports.usePipelineOrchestratorSetCapabilityBinding = usePipelineOrchestratorSet
62551
63070
  exports.usePipelineOrchestratorSetLoadBalancingShares = usePipelineOrchestratorSetLoadBalancingShares;
62552
63071
  exports.usePipelineOrchestratorSetPipelineDevicePin = usePipelineOrchestratorSetPipelineDevicePin;
62553
63072
  exports.usePipelineOrchestratorSetShareSource = usePipelineOrchestratorSetShareSource;
63073
+ exports.usePipelineOrchestratorStartNodeBenchmark = usePipelineOrchestratorStartNodeBenchmark;
62554
63074
  exports.usePipelineOrchestratorSuggestShares = usePipelineOrchestratorSuggestShares;
62555
63075
  exports.usePipelineOrchestratorUnassignAudio = usePipelineOrchestratorUnassignAudio;
62556
63076
  exports.usePipelineOrchestratorUnassignPipeline = usePipelineOrchestratorUnassignPipeline;
63077
+ exports.usePipelineRunnerAbortNodeBench = usePipelineRunnerAbortNodeBench;
62557
63078
  exports.usePipelineRunnerAttachCamera = usePipelineRunnerAttachCamera;
62558
63079
  exports.usePipelineRunnerDetachCamera = usePipelineRunnerDetachCamera;
62559
63080
  exports.usePipelineRunnerGetAllCameraMetrics = usePipelineRunnerGetAllCameraMetrics;
@@ -62562,6 +63083,7 @@ exports.usePipelineRunnerGetLocalCameras = usePipelineRunnerGetLocalCameras;
62562
63083
  exports.usePipelineRunnerGetLocalLoad = usePipelineRunnerGetLocalLoad;
62563
63084
  exports.usePipelineRunnerGetLocalMetrics = usePipelineRunnerGetLocalMetrics;
62564
63085
  exports.usePipelineRunnerGetNativeCrop = usePipelineRunnerGetNativeCrop;
63086
+ exports.usePipelineRunnerGetNodeBenchStatus = usePipelineRunnerGetNodeBenchStatus;
62565
63087
  exports.usePipelineRunnerGetParkedTrackFrame = usePipelineRunnerGetParkedTrackFrame;
62566
63088
  exports.usePipelineRunnerParkTrackFrame = usePipelineRunnerParkTrackFrame;
62567
63089
  exports.usePipelineRunnerReleaseParkedTrackFrames = usePipelineRunnerReleaseParkedTrackFrames;
@@ -62569,6 +63091,7 @@ exports.usePipelineRunnerReportMotion = usePipelineRunnerReportMotion;
62569
63091
  exports.usePipelineRunnerRequestOccupancyBurst = usePipelineRunnerRequestOccupancyBurst;
62570
63092
  exports.usePipelineRunnerRunDetailSubtree = usePipelineRunnerRunDetailSubtree;
62571
63093
  exports.usePipelineRunnerRunStatelessStep = usePipelineRunnerRunStatelessStep;
63094
+ exports.usePipelineRunnerStartNodeBench = usePipelineRunnerStartNodeBench;
62572
63095
  exports.usePlateGalleryAssignPlate = usePlateGalleryAssignPlate;
62573
63096
  exports.usePlateGalleryAssignPlates = usePlateGalleryAssignPlates;
62574
63097
  exports.usePlateGalleryCorrectPlateText = usePlateGalleryCorrectPlateText;