@camstack/ui-library 1.2.249 → 1.2.251

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,36 @@ 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.previewRetrainDataset.useQuery`. */
8772
+ var usePipelineAnalyticsPreviewRetrainDataset = trpc.pipelineAnalytics.previewRetrainDataset.useQuery;
8773
+ /** Generated alias around `trpc.pipelineAnalytics.createRetrainDatasetVersion.useMutation`. */
8774
+ var usePipelineAnalyticsCreateRetrainDatasetVersion = trpc.pipelineAnalytics.createRetrainDatasetVersion.useMutation;
8775
+ /** Generated alias around `trpc.pipelineAnalytics.listRetrainDatasetVersions.useQuery`. */
8776
+ var usePipelineAnalyticsListRetrainDatasetVersions = trpc.pipelineAnalytics.listRetrainDatasetVersions.useQuery;
8777
+ /** Generated alias around `trpc.pipelineAnalytics.deleteRetrainDatasetVersion.useMutation`. */
8778
+ var usePipelineAnalyticsDeleteRetrainDatasetVersion = trpc.pipelineAnalytics.deleteRetrainDatasetVersion.useMutation;
8779
+ /** Generated alias around `trpc.pipelineAnalytics.verifyRetrainDatasetVersion.useQuery`. */
8780
+ var usePipelineAnalyticsVerifyRetrainDatasetVersion = trpc.pipelineAnalytics.verifyRetrainDatasetVersion.useQuery;
8781
+ /** Generated alias around `trpc.pipelineAnalytics.listRetrainAssistProfiles.useQuery`. */
8782
+ var usePipelineAnalyticsListRetrainAssistProfiles = trpc.pipelineAnalytics.listRetrainAssistProfiles.useQuery;
8783
+ /** Generated alias around `trpc.pipelineAnalytics.proposeRetrainAnnotationsWithLlm.useMutation`. */
8784
+ var usePipelineAnalyticsProposeRetrainAnnotationsWithLlm = trpc.pipelineAnalytics.proposeRetrainAnnotationsWithLlm.useMutation;
8785
+ /** Generated alias around `trpc.pipelineAnalytics.createRetrainCollection.useMutation`. */
8786
+ var usePipelineAnalyticsCreateRetrainCollection = trpc.pipelineAnalytics.createRetrainCollection.useMutation;
8787
+ /** Generated alias around `trpc.pipelineAnalytics.listRetrainCollections.useQuery`. */
8788
+ var usePipelineAnalyticsListRetrainCollections = trpc.pipelineAnalytics.listRetrainCollections.useQuery;
8789
+ /** Generated alias around `trpc.pipelineAnalytics.renameRetrainCollection.useMutation`. */
8790
+ var usePipelineAnalyticsRenameRetrainCollection = trpc.pipelineAnalytics.renameRetrainCollection.useMutation;
8791
+ /** Generated alias around `trpc.pipelineAnalytics.deleteRetrainCollection.useMutation`. */
8792
+ var usePipelineAnalyticsDeleteRetrainCollection = trpc.pipelineAnalytics.deleteRetrainCollection.useMutation;
8793
+ /** Generated alias around `trpc.pipelineAnalytics.addRetrainFrameFromRecording.useMutation`. */
8794
+ var usePipelineAnalyticsAddRetrainFrameFromRecording = trpc.pipelineAnalytics.addRetrainFrameFromRecording.useMutation;
8795
+ /** Generated alias around `trpc.pipelineAnalytics.addRetrainFramesToCollection.useMutation`. */
8796
+ var usePipelineAnalyticsAddRetrainFramesToCollection = trpc.pipelineAnalytics.addRetrainFramesToCollection.useMutation;
8797
+ /** Generated alias around `trpc.pipelineAnalytics.removeRetrainFrameFromCollection.useMutation`. */
8798
+ var usePipelineAnalyticsRemoveRetrainFrameFromCollection = trpc.pipelineAnalytics.removeRetrainFrameFromCollection.useMutation;
8799
+ /** Generated alias around `trpc.pipelineAnalytics.listRetrainCollectionFrames.useQuery`. */
8800
+ var usePipelineAnalyticsListRetrainCollectionFrames = trpc.pipelineAnalytics.listRetrainCollectionFrames.useQuery;
8560
8801
  /** Generated alias around `trpc.pipelineAnalytics.getEventMedia.useQuery`. */
8561
8802
  var usePipelineAnalyticsGetEventMedia = trpc.pipelineAnalytics.getEventMedia.useQuery;
8562
8803
  /** Generated alias around `trpc.pipelineAnalytics.getTrackMedia.useQuery`. */
@@ -8729,6 +8970,20 @@ var usePipelineOrchestratorSuggestShares = trpc.pipelineOrchestrator.suggestShar
8729
8970
  var usePipelineOrchestratorGetEffectiveShares = trpc.pipelineOrchestrator.getEffectiveShares.useQuery;
8730
8971
  /** Generated alias around `trpc.pipelineOrchestrator.setShareSource.useMutation`. */
8731
8972
  var usePipelineOrchestratorSetShareSource = trpc.pipelineOrchestrator.setShareSource.useMutation;
8973
+ /** Generated alias around `trpc.pipelineOrchestrator.getNodeBenchmarkPreflight.useQuery`. */
8974
+ var usePipelineOrchestratorGetNodeBenchmarkPreflight = trpc.pipelineOrchestrator.getNodeBenchmarkPreflight.useQuery;
8975
+ /** Generated alias around `trpc.pipelineOrchestrator.startNodeBenchmark.useMutation`. */
8976
+ var usePipelineOrchestratorStartNodeBenchmark = trpc.pipelineOrchestrator.startNodeBenchmark.useMutation;
8977
+ /** Generated alias around `trpc.pipelineOrchestrator.getNodeBenchmarkStatus.useQuery`. */
8978
+ var usePipelineOrchestratorGetNodeBenchmarkStatus = trpc.pipelineOrchestrator.getNodeBenchmarkStatus.useQuery;
8979
+ /** Generated alias around `trpc.pipelineOrchestrator.abortNodeBenchmark.useMutation`. */
8980
+ var usePipelineOrchestratorAbortNodeBenchmark = trpc.pipelineOrchestrator.abortNodeBenchmark.useMutation;
8981
+ /** Generated alias around `trpc.pipelineOrchestrator.getNodeBenchmarkCandidates.useQuery`. */
8982
+ var usePipelineOrchestratorGetNodeBenchmarkCandidates = trpc.pipelineOrchestrator.getNodeBenchmarkCandidates.useQuery;
8983
+ /** Generated alias around `trpc.pipelineOrchestrator.listNodeBenchmarkResults.useQuery`. */
8984
+ var usePipelineOrchestratorListNodeBenchmarkResults = trpc.pipelineOrchestrator.listNodeBenchmarkResults.useQuery;
8985
+ /** Generated alias around `trpc.pipelineOrchestrator.deleteNodeBenchmarkResult.useMutation`. */
8986
+ var usePipelineOrchestratorDeleteNodeBenchmarkResult = trpc.pipelineOrchestrator.deleteNodeBenchmarkResult.useMutation;
8732
8987
  /** Generated alias around `trpc.pipelineOrchestrator.getCameraSettings.useQuery`. */
8733
8988
  var usePipelineOrchestratorGetCameraSettings = trpc.pipelineOrchestrator.getCameraSettings.useQuery;
8734
8989
  /** Generated alias around `trpc.pipelineOrchestrator.setCameraStepToggle.useMutation`. */
@@ -8793,6 +9048,12 @@ var usePipelineRunnerParkTrackFrame = trpc.pipelineRunner.parkTrackFrame.useMuta
8793
9048
  var usePipelineRunnerGetParkedTrackFrame = trpc.pipelineRunner.getParkedTrackFrame.useQuery;
8794
9049
  /** Generated alias around `trpc.pipelineRunner.releaseParkedTrackFrames.useMutation`. */
8795
9050
  var usePipelineRunnerReleaseParkedTrackFrames = trpc.pipelineRunner.releaseParkedTrackFrames.useMutation;
9051
+ /** Generated alias around `trpc.pipelineRunner.startNodeBench.useMutation`. */
9052
+ var usePipelineRunnerStartNodeBench = trpc.pipelineRunner.startNodeBench.useMutation;
9053
+ /** Generated alias around `trpc.pipelineRunner.getNodeBenchStatus.useQuery`. */
9054
+ var usePipelineRunnerGetNodeBenchStatus = trpc.pipelineRunner.getNodeBenchStatus.useQuery;
9055
+ /** Generated alias around `trpc.pipelineRunner.abortNodeBench.useMutation`. */
9056
+ var usePipelineRunnerAbortNodeBench = trpc.pipelineRunner.abortNodeBench.useMutation;
8796
9057
  /** Generated alias around `trpc.plateGallery.listPlates.useQuery`. */
8797
9058
  var usePlateGalleryListPlates = trpc.plateGallery.listPlates.useQuery;
8798
9059
  /** Generated alias around `trpc.plateGallery.getPlateByTrack.useQuery`. */
@@ -21638,7 +21899,7 @@ function formatDurationMs(ms) {
21638
21899
  * firmware inventing a refusal reaches the operator rather than becoming a
21639
21900
  * blank tile.
21640
21901
  */
21641
- var REFUSAL_TEXT = {
21902
+ var REFUSAL_TEXT$1 = {
21642
21903
  sleeping: () => "The camera is asleep — a still would cost a wake",
21643
21904
  "camera-refused": (reason) => `The camera refused — ${reason}`,
21644
21905
  "no-keyframe": () => "No decodable frame inside this window",
@@ -21650,7 +21911,7 @@ var REFUSAL_TEXT = {
21650
21911
  "uid-missing": () => "The camera’s id is not known yet"
21651
21912
  };
21652
21913
  function wordsFor(code, reason) {
21653
- const known = code === void 0 ? void 0 : REFUSAL_TEXT[code];
21914
+ const known = code === void 0 ? void 0 : REFUSAL_TEXT$1[code];
21654
21915
  return known === void 0 ? reason : known(reason);
21655
21916
  }
21656
21917
  function refusal(reason, code) {
@@ -25233,6 +25494,426 @@ function useScrubController(sink, isPlayerLive = () => false) {
25233
25494
  };
25234
25495
  }
25235
25496
  //#endregion
25497
+ //#region src/primitives/dialog.tsx
25498
+ var DialogContext = (0, react$1.createContext)(null);
25499
+ function useDialogContext() {
25500
+ const ctx = (0, react$1.useContext)(DialogContext);
25501
+ if (!ctx) throw new Error("Dialog compound components must be used within <Dialog>");
25502
+ return ctx;
25503
+ }
25504
+ function Dialog({ children, open: controlledOpen, onOpenChange }) {
25505
+ const [uncontrolledOpen, setUncontrolledOpen] = (0, react$1.useState)(false);
25506
+ const open = controlledOpen ?? uncontrolledOpen;
25507
+ const contentId = (0, react$1.useId)();
25508
+ const setOpen = (0, react$1.useCallback)((next) => {
25509
+ onOpenChange?.(next);
25510
+ if (controlledOpen === void 0) setUncontrolledOpen(next);
25511
+ }, [controlledOpen, onOpenChange]);
25512
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DialogContext.Provider, {
25513
+ value: {
25514
+ open,
25515
+ setOpen,
25516
+ contentId
25517
+ },
25518
+ children
25519
+ });
25520
+ }
25521
+ function DialogTrigger({ children, ...props }) {
25522
+ const { setOpen } = useDialogContext();
25523
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
25524
+ type: "button",
25525
+ onClick: () => setOpen(true),
25526
+ ...props,
25527
+ children
25528
+ });
25529
+ }
25530
+ /**
25531
+ * A native <dialog> opened with showModal() is promoted to the top layer, so
25532
+ * ancestor transform/overflow can't clip it — but it relies on the UA
25533
+ * stylesheet's `dialog { margin: auto }` for modal centering. Tailwind's
25534
+ * preflight resets `margin: 0` on every element, which defeats that centering
25535
+ * and pins the modal to the top-left. We therefore center deterministically:
25536
+ * a top-layer dialog with `position: fixed` is viewport-relative, and a
25537
+ * self-transform is fine, so `fixed left-1/2 top-1/2 -translate-x-1/2
25538
+ * -translate-y-1/2 m-0` always centers regardless of any margin reset. Width
25539
+ * is capped to the viewport (`w-[calc(100vw-2rem)]`) rather than a bare
25540
+ * `w-full` (which would overflow/clip a centered dialog); the per-variant
25541
+ * `max-w-*` keeps small dialogs small while the cap prevents overflow.
25542
+ *
25543
+ * Height is capped against the SAFE viewport, not the raw one. A top-layer
25544
+ * `fixed` dialog is viewport-relative, and under `viewport-fit=cover` the
25545
+ * viewport extends behind the iOS notch/Dynamic Island and home indicator —
25546
+ * so a dialog tall enough to hit its `max-h` put its header under the clock.
25547
+ * Because the box is centred on the viewport (not on the safe area), the cap
25548
+ * has to subtract TWICE the LARGER of the two insets for the box to clear
25549
+ * both edges; using each inset once would still overflow the taller side
25550
+ * whenever they are asymmetric (they are: ~59px top vs ~34px bottom). Every
25551
+ * term collapses to the previous `100dvh - 2rem` where the insets are 0.
25552
+ */
25553
+ 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", {
25554
+ variants: {
25555
+ width: {
25556
+ sm: "max-w-sm",
25557
+ md: "max-w-md",
25558
+ lg: "max-w-lg"
25559
+ },
25560
+ /**
25561
+ * WHICH box scrolls when the content is taller than the height cap.
25562
+ *
25563
+ * `content` (default) scrolls the whole dialog: the title, any tab strip
25564
+ * and the Save/Cancel row travel with the fields. That is fine for a
25565
+ * short form and wrong for a long one — the operator scrolls to the
25566
+ * bottom of a rule editor and the buttons are somewhere above him, the
25567
+ * tab strip is gone, and the only way back to either is to scroll the
25568
+ * form he was reading.
25569
+ *
25570
+ * `body` makes the dialog a flex column that does not scroll at all and
25571
+ * hands the scrolling to `<DialogBody>`. The chrome around the body —
25572
+ * header, tab strip, footer — stays put at every height. The dialog
25573
+ * keeps its own padding either way, so `sheet-on-mobile`'s
25574
+ * safe-area bottom padding still applies to the footer.
25575
+ *
25576
+ * `body` also takes a DEFINITE height below `md` — see the
25577
+ * `scroll: 'body'` compound variants. That is not a style choice; the
25578
+ * flex chain does not resolve without it on iOS Safari.
25579
+ */
25580
+ scroll: {
25581
+ content: "overflow-y-auto",
25582
+ body: "flex flex-col overflow-hidden"
25583
+ },
25584
+ placement: {
25585
+ center: "",
25586
+ "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)))]"
25587
+ }
25588
+ },
25589
+ compoundVariants: [
25590
+ {
25591
+ placement: "sheet-on-mobile",
25592
+ width: "sm",
25593
+ class: "md:w-[calc(100vw-2rem)] md:max-w-sm"
25594
+ },
25595
+ {
25596
+ placement: "sheet-on-mobile",
25597
+ width: "md",
25598
+ class: "md:w-[calc(100vw-2rem)] md:max-w-md"
25599
+ },
25600
+ {
25601
+ placement: "sheet-on-mobile",
25602
+ width: "lg",
25603
+ class: "md:w-[calc(100vw-2rem)] md:max-w-lg"
25604
+ },
25605
+ {
25606
+ scroll: "body",
25607
+ placement: "sheet-on-mobile",
25608
+ class: "h-[92dvh] md:h-auto"
25609
+ },
25610
+ {
25611
+ scroll: "body",
25612
+ placement: "center",
25613
+ class: "h-[calc(100dvh-2rem-2*max(env(safe-area-inset-top),env(safe-area-inset-bottom)))] md:h-auto"
25614
+ }
25615
+ ],
25616
+ defaultVariants: {
25617
+ width: "md",
25618
+ placement: "center",
25619
+ scroll: "content"
25620
+ }
25621
+ });
25622
+ var DialogContent = (0, react$1.forwardRef)(({ className, width, placement, scroll, children, ...props }, ref) => {
25623
+ const { open, setOpen, contentId } = useDialogContext();
25624
+ const innerRef = (0, react$1.useRef)(null);
25625
+ const dialogRef = ref ?? innerRef;
25626
+ (0, react$1.useEffect)(() => {
25627
+ const el = dialogRef.current;
25628
+ if (!el) return;
25629
+ if (open && !el.open) el.showModal();
25630
+ if (!open && el.open) el.close();
25631
+ }, [open, dialogRef]);
25632
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dialog", {
25633
+ ref: dialogRef,
25634
+ id: contentId,
25635
+ className: cn(contentVariants({
25636
+ width,
25637
+ placement,
25638
+ scroll
25639
+ }), className),
25640
+ onClose: () => setOpen(false),
25641
+ ...props,
25642
+ children
25643
+ });
25644
+ });
25645
+ DialogContent.displayName = "DialogContent";
25646
+ /** `shrink-0` is inert outside a flex column and load-bearing inside one:
25647
+ * under `scroll="body"` the header must keep its height while the body gives
25648
+ * ground, or a long form squeezes its own title to nothing. */
25649
+ function DialogHeader({ className, ...props }) {
25650
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
25651
+ className: cn("flex flex-col gap-1 mb-3 shrink-0", className),
25652
+ ...props
25653
+ });
25654
+ }
25655
+ /**
25656
+ * The scrolling middle of a `scroll="body"` dialog.
25657
+ *
25658
+ * `min-h-0` is what makes it work: a flex item's default `min-height: auto`
25659
+ * refuses to shrink below its content, so without it the body pushes the
25660
+ * footer out of the dialog instead of scrolling — the exact failure this
25661
+ * variant exists to remove. Anything sticky INSIDE a dialog body pins against
25662
+ * this element, since it is the scroll container.
25663
+ *
25664
+ * It only bounds a scroll area if every ancestor up to the dialog has a
25665
+ * resolved height. `DialogContent` supplies the top of that chain (see the
25666
+ * `scroll: 'body'` compound variants); an intermediate wrapper between them —
25667
+ * a `<Tabs>` that owns the tab strip, say — must carry `flex-1 min-h-0` too,
25668
+ * or it collapses and takes the body with it.
25669
+ */
25670
+ function DialogBody({ className, ...props }) {
25671
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
25672
+ className: cn("flex-1 min-h-0 overflow-y-auto", className),
25673
+ ...props
25674
+ });
25675
+ }
25676
+ function DialogFooter({ className, ...props }) {
25677
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
25678
+ className: cn("flex justify-end gap-2 mt-4 shrink-0", className),
25679
+ ...props
25680
+ });
25681
+ }
25682
+ function DialogTitle({ className, ...props }) {
25683
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
25684
+ className: cn("text-sm font-semibold text-foreground", className),
25685
+ ...props
25686
+ });
25687
+ }
25688
+ function DialogDescription({ className, ...props }) {
25689
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
25690
+ className: cn("text-xs text-foreground-muted", className),
25691
+ ...props
25692
+ });
25693
+ }
25694
+ //#endregion
25695
+ //#region src/primitives/input.tsx
25696
+ /**
25697
+ * `disabled:opacity-50 disabled:cursor-not-allowed` for the same reason as
25698
+ * `Select` — an explicit `bg-surface` / `text-foreground` overrides the greying
25699
+ * a browser would otherwise apply, leaving an inert field indistinguishable
25700
+ * from a live one. See `disabled-affordance.test.tsx`.
25701
+ */
25702
+ 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", {
25703
+ variants: { state: {
25704
+ default: "border-border",
25705
+ error: "border-danger"
25706
+ } },
25707
+ defaultVariants: { state: "default" }
25708
+ });
25709
+ var Input = (0, react$1.forwardRef)(({ className, state, leftSlot, rightSlot, ...props }, ref) => {
25710
+ if (leftSlot || rightSlot) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
25711
+ className: "relative flex items-center w-full",
25712
+ children: [
25713
+ leftSlot && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
25714
+ className: "absolute left-2.5 flex items-center pointer-events-none",
25715
+ children: leftSlot
25716
+ }),
25717
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
25718
+ ref,
25719
+ className: cn(inputVariants({ state }), leftSlot ? "pl-7" : "", rightSlot ? "pr-7" : "", className),
25720
+ ...props
25721
+ }),
25722
+ rightSlot && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
25723
+ className: "absolute right-2.5 flex items-center pointer-events-none",
25724
+ children: rightSlot
25725
+ })
25726
+ ]
25727
+ });
25728
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
25729
+ ref,
25730
+ className: cn(inputVariants({ state }), className),
25731
+ ...props
25732
+ });
25733
+ });
25734
+ Input.displayName = "Input";
25735
+ //#endregion
25736
+ //#region src/composites/training/training-collection-picker.tsx
25737
+ /**
25738
+ * <TrainingCollectionPicker> — choose a named training collection, or create
25739
+ * one in place.
25740
+ *
25741
+ * A collection is a named set over the retrain corpus ("packages porch
25742
+ * night"). The picker lists them (newest first, with their frame counts) and
25743
+ * offers a name field for a new one; the hub refuses an empty or duplicate
25744
+ * name, and the refusal is shown here rather than swallowed.
25745
+ */
25746
+ var CREATE_REFUSAL = {
25747
+ "empty-name": "Give the collection a name.",
25748
+ "duplicate-name": "A collection with that name already exists."
25749
+ };
25750
+ function TrainingCollectionPicker({ value, onChange }) {
25751
+ const collections = usePipelineAnalyticsListRetrainCollections({});
25752
+ const create = usePipelineAnalyticsCreateRetrainCollection();
25753
+ const [name, setName] = (0, react$1.useState)("");
25754
+ const [error, setError] = (0, react$1.useState)(null);
25755
+ const list = collections.data ?? [];
25756
+ const onCreate = async () => {
25757
+ setError(null);
25758
+ const result = await create.mutateAsync({ name });
25759
+ if (result.kind === "refused") {
25760
+ setError(CREATE_REFUSAL[result.reason]);
25761
+ return;
25762
+ }
25763
+ setName("");
25764
+ await collections.refetch();
25765
+ onChange(result.collection.id);
25766
+ };
25767
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
25768
+ className: "space-y-2",
25769
+ "data-testid": "training-collection-picker",
25770
+ children: [
25771
+ list.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Select, {
25772
+ "aria-label": "Collection",
25773
+ value: value ?? "",
25774
+ options: [{
25775
+ value: "",
25776
+ label: "Choose a collection…"
25777
+ }, ...list.map((c) => ({
25778
+ value: c.id,
25779
+ label: `${c.name} (${String(c.frameCount)})`
25780
+ }))],
25781
+ onChange: (event) => {
25782
+ if (event.target.value !== "") onChange(event.target.value);
25783
+ }
25784
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
25785
+ className: "text-xs text-foreground-subtle",
25786
+ children: collections.isLoading ? "Reading the collections…" : "No collection yet — create one."
25787
+ }),
25788
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
25789
+ className: "flex items-center gap-2",
25790
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Input, {
25791
+ className: "flex-1",
25792
+ "aria-label": "New collection name",
25793
+ placeholder: "New collection (e.g. missed at night)",
25794
+ value: name,
25795
+ onChange: (event) => {
25796
+ setName(event.target.value);
25797
+ }
25798
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Button, {
25799
+ type: "button",
25800
+ variant: "secondary",
25801
+ size: "sm",
25802
+ disabled: create.isPending || name.trim() === "",
25803
+ onClick: () => void onCreate(),
25804
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Plus, { className: "h-3 w-3" }), "Create"]
25805
+ })]
25806
+ }),
25807
+ error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
25808
+ className: "text-xs text-danger",
25809
+ children: error
25810
+ })
25811
+ ]
25812
+ });
25813
+ }
25814
+ //#endregion
25815
+ //#region src/composites/training/training-refusal-text.ts
25816
+ var REFUSAL_TEXT = {
25817
+ "unknown-collection": "That collection no longer exists — pick another one.",
25818
+ "still-unavailable": "No frame could be taken from the recording at that moment.",
25819
+ "still-busy": "The recorder is busy decoding other frames. Try again in a moment.",
25820
+ "unreadable-image": "The recorder returned something that is not a picture.",
25821
+ "write-failed": "The frame could not be stored. Check the artifacts storage."
25822
+ };
25823
+ /** One sentence for a refusal, with the hub's own detail appended. */
25824
+ function trainingRefusalText(reason, detail) {
25825
+ const base = REFUSAL_TEXT[reason];
25826
+ return detail !== void 0 && detail !== "" ? `${base} (${detail})` : base;
25827
+ }
25828
+ //#endregion
25829
+ //#region src/composites/training/send-frame-to-training.tsx
25830
+ /**
25831
+ * <SendFrameToTrainingButton> — "Send frame to training" from a recording
25832
+ * playhead.
25833
+ *
25834
+ * The frame a detector most needs to learn from is often one where it saw
25835
+ * NOTHING — no event, no track, nothing to mark. From the recording, the
25836
+ * operator stops on that moment and sends it: the hub re-decodes the native
25837
+ * frame at the playhead instant and adds it to a named training collection,
25838
+ * where the Retrain page annotates it like any other frame.
25839
+ *
25840
+ * Draws NOTHING for a session that cannot curate training data: the
25841
+ * collection list is admin-only, and a button that 403s is worse than no
25842
+ * button. It is disabled, with the reason, while there is no playhead.
25843
+ */
25844
+ function SendFrameToTrainingButton({ deviceId, epochMs }) {
25845
+ const collections = usePipelineAnalyticsListRetrainCollections({}, { retry: false });
25846
+ const send = usePipelineAnalyticsAddRetrainFrameFromRecording();
25847
+ const [open, setOpen] = (0, react$1.useState)(false);
25848
+ const [collectionId, setCollectionId] = (0, react$1.useState)(null);
25849
+ const [instant, setInstant] = (0, react$1.useState)(null);
25850
+ const [outcome, setOutcome] = (0, react$1.useState)(null);
25851
+ if (collections.isError) return null;
25852
+ const onSend = async () => {
25853
+ if (collectionId === null || instant === null) return;
25854
+ const result = await send.mutateAsync({
25855
+ collectionId,
25856
+ deviceId,
25857
+ epochMs: instant
25858
+ });
25859
+ const name = collections.data?.find((c) => c.id === collectionId)?.name ?? "the collection";
25860
+ setOutcome(result.kind === "added" ? {
25861
+ kind: "added",
25862
+ reused: result.reused,
25863
+ collection: name
25864
+ } : {
25865
+ kind: "refused",
25866
+ text: trainingRefusalText(result.reason, result.detail)
25867
+ });
25868
+ if (result.kind === "added") await collections.refetch();
25869
+ };
25870
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Button, {
25871
+ type: "button",
25872
+ variant: "secondary",
25873
+ size: "sm",
25874
+ "data-testid": "send-frame-to-training",
25875
+ disabled: epochMs === null,
25876
+ 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",
25877
+ onClick: () => {
25878
+ setInstant(epochMs);
25879
+ setOutcome(null);
25880
+ setOpen(true);
25881
+ },
25882
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(GraduationCap, { className: "h-3.5 w-3.5" }), "Send frame to training"]
25883
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dialog, {
25884
+ open,
25885
+ onOpenChange: (next) => !send.isPending && setOpen(next),
25886
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(DialogContent, { children: [
25887
+ /* @__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.` : "" })] }),
25888
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrainingCollectionPicker, {
25889
+ value: collectionId,
25890
+ onChange: setCollectionId
25891
+ }),
25892
+ outcome !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
25893
+ className: `mt-2 text-xs ${outcome.kind === "added" ? "text-success" : "text-danger"}`,
25894
+ role: "status",
25895
+ 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
25896
+ }),
25897
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(DialogFooter, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
25898
+ type: "button",
25899
+ variant: "ghost",
25900
+ size: "sm",
25901
+ disabled: send.isPending,
25902
+ onClick: () => {
25903
+ setOpen(false);
25904
+ },
25905
+ children: outcome?.kind === "added" ? "Done" : "Cancel"
25906
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Button, {
25907
+ type: "button",
25908
+ size: "sm",
25909
+ disabled: collectionId === null || send.isPending || outcome?.kind === "added",
25910
+ onClick: () => void onSend(),
25911
+ children: [send.isPending && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LoaderCircle, { className: "h-3.5 w-3.5 animate-spin" }), "Send"]
25912
+ })] })
25913
+ ] })
25914
+ })] });
25915
+ }
25916
+ //#endregion
25236
25917
  //#region src/composites/cap-settings/CoverageTrack.tsx
25237
25918
  function CoverageTrack({ windowFrom, windowTo, spans, playheadMs, onSeek, onScrubStart, onScrubMove, onScrubEnd }) {
25238
25919
  const [hoverInfo, setHoverInfo] = (0, react$1.useState)(null);
@@ -25811,6 +26492,13 @@ function RecordingTimeline({ deviceId }) {
25811
26492
  dayBounds: computedDayBounds,
25812
26493
  onViewChange: handleViewChange
25813
26494
  }),
26495
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
26496
+ className: "flex justify-end",
26497
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SendFrameToTrainingButton, {
26498
+ deviceId,
26499
+ epochMs: displayPlayheadMs
26500
+ })
26501
+ }),
25814
26502
  recorded.channelOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
25815
26503
  "data-testid": "frame-push-status-row",
25816
26504
  className: "flex flex-wrap items-center gap-2 text-[10px]",
@@ -27408,6 +28096,32 @@ function FieldWrapper({ label, description, required, span, children, translatio
27408
28096
  ]
27409
28097
  });
27410
28098
  }
28099
+ /**
28100
+ * A keychain-stored secret (D787) arrives as its VIEW — `{ $secret, set }` —
28101
+ * or `null`, never as a value; it renders as "set · Change · Clear · Reveal".
28102
+ * Decided ONCE, at mount, from what the form was hydrated with: once the
28103
+ * operator types, the value is a plain string and the field must stay the
28104
+ * same control. A form that was not hydrated from a keychain-aware store (a
28105
+ * create dialog seeding `''`) keeps the plain input.
28106
+ */
28107
+ function KeychainOr({ field, value, onChange, disabled, translationFn, multiline, children }) {
28108
+ const [keychain] = (0, react$1.useState)(() => (0, _camstack_types.isKeychainStoredField)(field) && isKeychainFieldValue(value));
28109
+ if (!keychain) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children });
28110
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldWrapper, {
28111
+ label: "label" in field ? field.label : void 0,
28112
+ description: "description" in field ? field.description : void 0,
28113
+ required: "required" in field ? field.required : void 0,
28114
+ span: "span" in field ? field.span : void 0,
28115
+ translationFn,
28116
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SecretFieldControl, {
28117
+ field,
28118
+ value,
28119
+ onChange,
28120
+ disabled,
28121
+ multiline
28122
+ })
28123
+ });
28124
+ }
27411
28125
  function TextField({ field, value, onChange, disabled, translationFn }) {
27412
28126
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldWrapper, {
27413
28127
  label: field.label,
@@ -28480,7 +29194,7 @@ function resolveActionParams(field, values) {
28480
29194
  const params = { ...field.paramsStatic };
28481
29195
  if (field.paramsFromForm) for (const [paramKey, formKey] of Object.entries(field.paramsFromForm)) {
28482
29196
  const v = values[formKey];
28483
- if (v !== void 0 && v !== null && v !== "") params[paramKey] = v;
29197
+ if (v !== void 0 && v !== null && v !== "" && !(0, _camstack_types.isSecretClear)(v)) params[paramKey] = v;
28484
29198
  }
28485
29199
  return params;
28486
29200
  }
@@ -28976,12 +29690,19 @@ function FormField({ field, values, onChange, disabled, translationFn, onTestFie
28976
29690
  const handleChange = (v) => onChange(field.key, v);
28977
29691
  const customRenderer = useCustomFieldRenderer(field.type);
28978
29692
  switch (field.type) {
28979
- case "text": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
29693
+ case "text": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KeychainOr, {
28980
29694
  field,
28981
29695
  value,
28982
29696
  onChange: handleChange,
28983
29697
  disabled,
28984
- translationFn
29698
+ translationFn,
29699
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
29700
+ field,
29701
+ value,
29702
+ onChange: handleChange,
29703
+ disabled,
29704
+ translationFn
29705
+ })
28985
29706
  });
28986
29707
  case "number": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NumberField, {
28987
29708
  field,
@@ -29025,19 +29746,34 @@ function FormField({ field, values, onChange, disabled, translationFn, onTestFie
29025
29746
  disabled,
29026
29747
  translationFn
29027
29748
  });
29028
- case "password": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PasswordField, {
29749
+ case "password": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KeychainOr, {
29029
29750
  field,
29030
29751
  value,
29031
29752
  onChange: handleChange,
29032
29753
  disabled,
29033
- translationFn
29754
+ translationFn,
29755
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PasswordField, {
29756
+ field,
29757
+ value,
29758
+ onChange: handleChange,
29759
+ disabled,
29760
+ translationFn
29761
+ })
29034
29762
  });
29035
- case "textarea": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextAreaField, {
29763
+ case "textarea": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KeychainOr, {
29036
29764
  field,
29037
29765
  value,
29038
29766
  onChange: handleChange,
29039
29767
  disabled,
29040
- translationFn
29768
+ translationFn,
29769
+ multiline: true,
29770
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextAreaField, {
29771
+ field,
29772
+ value,
29773
+ onChange: handleChange,
29774
+ disabled,
29775
+ translationFn
29776
+ })
29041
29777
  });
29042
29778
  case "slider": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SliderField, {
29043
29779
  field,
@@ -30839,47 +31575,6 @@ var Separator = (0, react$1.forwardRef)(({ className, orientation, ...props }, r
30839
31575
  });
30840
31576
  Separator.displayName = "Separator";
30841
31577
  //#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
31578
  //#region src/primitives/checkbox.tsx
30884
31579
  var Checkbox = (0, react$1.forwardRef)(({ className, ...props }, ref) => {
30885
31580
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -30912,204 +31607,6 @@ var Switch = (0, react$1.forwardRef)(({ className, checked, onCheckedChange, lab
30912
31607
  });
30913
31608
  Switch.displayName = "Switch";
30914
31609
  //#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
31610
  //#region src/primitives/tooltip.tsx
31114
31611
  var TooltipContext = (0, react$1.createContext)(null);
31115
31612
  function useTooltipContext() {
@@ -61463,6 +61960,7 @@ exports.RotateCcw = RotateCcw;
61463
61960
  exports.RunReport = RunReport;
61464
61961
  exports.SCENE_CAPTURE_VARIANTS = SCENE_CAPTURE_VARIANTS;
61465
61962
  exports.SCENE_CAPTURE_VARIANTS$1 = SCENE_CAPTURE_VARIANTS;
61963
+ exports.SECRET_REVEAL_MS = SECRET_REVEAL_MS;
61466
61964
  exports.SECTION_BODY = SECTION_BODY;
61467
61965
  exports.SECTION_CARD = SECTION_CARD;
61468
61966
  exports.SECTION_HEADER = SECTION_HEADER;
@@ -61482,11 +61980,14 @@ exports.ScopePicker = ScopePicker;
61482
61980
  exports.ScriptHeroCard = ScriptHeroCard;
61483
61981
  exports.ScriptInlineControl = ScriptInlineControl;
61484
61982
  exports.ScrollArea = ScrollArea;
61983
+ exports.SecretFieldControl = SecretFieldControl;
61984
+ exports.SecretRevealProvider = SecretRevealProvider;
61485
61985
  exports.SectionCard = SectionCard;
61486
61986
  exports.SegmentedChoice = SegmentedChoice;
61487
61987
  exports.Select = Select;
61488
61988
  exports.SelectedChip = SelectedChip;
61489
61989
  exports.SemanticBadge = SemanticBadge;
61990
+ exports.SendFrameToTrainingButton = SendFrameToTrainingButton;
61490
61991
  exports.SensorHeroCard = SensorHeroCard;
61491
61992
  exports.SensorInlineControl = SensorInlineControl;
61492
61993
  exports.SensorValueAtom = SensorValueAtom;
@@ -61534,6 +62035,7 @@ exports.TimezoneSelector = TimezoneSelector;
61534
62035
  exports.Tooltip = Tooltip;
61535
62036
  exports.TooltipContent = TooltipContent;
61536
62037
  exports.TooltipTrigger = TooltipTrigger;
62038
+ exports.TrainingCollectionPicker = TrainingCollectionPicker;
61537
62039
  exports.Trash2 = Trash2;
61538
62040
  exports.UnitPicker = UnitPicker;
61539
62041
  exports.VacuumHeroCard = VacuumHeroCard;
@@ -61644,6 +62146,7 @@ exports.isAbsentProvider$1 = isAbsentProvider;
61644
62146
  exports.isDataTableFilterActive = isDataTableFilterActive;
61645
62147
  exports.isFieldVisible = isFieldVisible;
61646
62148
  exports.isGroupExpanded = isGroupExpanded;
62149
+ exports.isKeychainFieldValue = isKeychainFieldValue;
61647
62150
  exports.isValueField = isValueField;
61648
62151
  exports.lawnMowerActivityMeta = lawnMowerActivityMeta;
61649
62152
  exports.lightColors = require_theme_index.lightColors$1;
@@ -61740,6 +62243,7 @@ exports.toStationaryOverlayBox = toStationaryOverlayBox;
61740
62243
  exports.toggleDataTableFacet = toggleDataTableFacet;
61741
62244
  exports.togglePickerDevice = togglePickerDevice;
61742
62245
  exports.togglePickerKey = togglePickerKey;
62246
+ exports.trainingRefusalText = trainingRefusalText;
61743
62247
  exports.trpc = trpc;
61744
62248
  exports.typeLabel = typeLabel;
61745
62249
  exports.useAccessoriesGetStatus = useAccessoriesGetStatus;
@@ -62172,6 +62676,15 @@ exports.useIntercomStartTalkSession = useIntercomStartTalkSession;
62172
62676
  exports.useIntercomStopSession = useIntercomStopSession;
62173
62677
  exports.useIsMidWidth = useIsMidWidth;
62174
62678
  exports.useIsMobile = useIsMobile;
62679
+ exports.useKeychainAdminDeleteOrphans = useKeychainAdminDeleteOrphans;
62680
+ exports.useKeychainAdminDownloadRecoveryKey = useKeychainAdminDownloadRecoveryKey;
62681
+ exports.useKeychainAdminListAudit = useKeychainAdminListAudit;
62682
+ exports.useKeychainAdminListSecrets = useKeychainAdminListSecrets;
62683
+ exports.useKeychainAdminPurgeRetiredKeys = useKeychainAdminPurgeRetiredKeys;
62684
+ exports.useKeychainAdminResetKeychain = useKeychainAdminResetKeychain;
62685
+ exports.useKeychainAdminReveal = useKeychainAdminReveal;
62686
+ exports.useKeychainAdminRotateMasterKey = useKeychainAdminRotateMasterKey;
62687
+ exports.useKeychainAdminStatus = useKeychainAdminStatus;
62175
62688
  exports.useLawnMowerControlDock = useLawnMowerControlDock;
62176
62689
  exports.useLawnMowerControlGetStatus = useLawnMowerControlGetStatus;
62177
62690
  exports.useLawnMowerControlPause = useLawnMowerControlPause;
@@ -62390,6 +62903,8 @@ exports.usePetFeederSetFeedSound = usePetFeederSetFeedSound;
62390
62903
  exports.usePetFeederSetIndicatorLight = usePetFeederSetIndicatorLight;
62391
62904
  exports.usePetFeederSetVolume = usePetFeederSetVolume;
62392
62905
  exports.usePickerSiteZones = usePickerSiteZones;
62906
+ exports.usePipelineAnalyticsAddRetrainFrameFromRecording = usePipelineAnalyticsAddRetrainFrameFromRecording;
62907
+ exports.usePipelineAnalyticsAddRetrainFramesToCollection = usePipelineAnalyticsAddRetrainFramesToCollection;
62393
62908
  exports.usePipelineAnalyticsApplyDeviceSettingsPatch = usePipelineAnalyticsApplyDeviceSettingsPatch;
62394
62909
  exports.usePipelineAnalyticsCancelRelocateMedia = usePipelineAnalyticsCancelRelocateMedia;
62395
62910
  exports.usePipelineAnalyticsCancelStorageMigrationMove = usePipelineAnalyticsCancelStorageMigrationMove;
@@ -62398,7 +62913,11 @@ exports.usePipelineAnalyticsClearTracks = usePipelineAnalyticsClearTracks;
62398
62913
  exports.usePipelineAnalyticsCompleteRetrainTrack = usePipelineAnalyticsCompleteRetrainTrack;
62399
62914
  exports.usePipelineAnalyticsCountRelocatableMedia = usePipelineAnalyticsCountRelocatableMedia;
62400
62915
  exports.usePipelineAnalyticsCountUnstampedEventMedia = usePipelineAnalyticsCountUnstampedEventMedia;
62916
+ exports.usePipelineAnalyticsCreateRetrainCollection = usePipelineAnalyticsCreateRetrainCollection;
62917
+ exports.usePipelineAnalyticsCreateRetrainDatasetVersion = usePipelineAnalyticsCreateRetrainDatasetVersion;
62401
62918
  exports.usePipelineAnalyticsDeleteDeviceEvents = usePipelineAnalyticsDeleteDeviceEvents;
62919
+ exports.usePipelineAnalyticsDeleteRetrainCollection = usePipelineAnalyticsDeleteRetrainCollection;
62920
+ exports.usePipelineAnalyticsDeleteRetrainDatasetVersion = usePipelineAnalyticsDeleteRetrainDatasetVersion;
62402
62921
  exports.usePipelineAnalyticsDeleteTracks = usePipelineAnalyticsDeleteTracks;
62403
62922
  exports.usePipelineAnalyticsDeselectRetrainFrame = usePipelineAnalyticsDeselectRetrainFrame;
62404
62923
  exports.usePipelineAnalyticsGetActiveTracks = usePipelineAnalyticsGetActiveTracks;
@@ -62433,6 +62952,10 @@ exports.usePipelineAnalyticsListOpsLog = usePipelineAnalyticsListOpsLog;
62433
62952
  exports.usePipelineAnalyticsListRecentTracks = usePipelineAnalyticsListRecentTracks;
62434
62953
  exports.usePipelineAnalyticsListRelocateMediaJobs = usePipelineAnalyticsListRelocateMediaJobs;
62435
62954
  exports.usePipelineAnalyticsListRetrainAnnotations = usePipelineAnalyticsListRetrainAnnotations;
62955
+ exports.usePipelineAnalyticsListRetrainAssistProfiles = usePipelineAnalyticsListRetrainAssistProfiles;
62956
+ exports.usePipelineAnalyticsListRetrainCollectionFrames = usePipelineAnalyticsListRetrainCollectionFrames;
62957
+ exports.usePipelineAnalyticsListRetrainCollections = usePipelineAnalyticsListRetrainCollections;
62958
+ exports.usePipelineAnalyticsListRetrainDatasetVersions = usePipelineAnalyticsListRetrainDatasetVersions;
62436
62959
  exports.usePipelineAnalyticsListRetrainFrames = usePipelineAnalyticsListRetrainFrames;
62437
62960
  exports.usePipelineAnalyticsListRetrainStaging = usePipelineAnalyticsListRetrainStaging;
62438
62961
  exports.usePipelineAnalyticsListTrackMedia = usePipelineAnalyticsListTrackMedia;
@@ -62440,7 +62963,9 @@ exports.usePipelineAnalyticsListTrackRelations = usePipelineAnalyticsListTrackRe
62440
62963
  exports.usePipelineAnalyticsListTracks = usePipelineAnalyticsListTracks;
62441
62964
  exports.usePipelineAnalyticsOwnersWithMedia = usePipelineAnalyticsOwnersWithMedia;
62442
62965
  exports.usePipelineAnalyticsPauseForStorageMigration = usePipelineAnalyticsPauseForStorageMigration;
62966
+ exports.usePipelineAnalyticsPreviewRetrainDataset = usePipelineAnalyticsPreviewRetrainDataset;
62443
62967
  exports.usePipelineAnalyticsProposeRetrainAnnotations = usePipelineAnalyticsProposeRetrainAnnotations;
62968
+ exports.usePipelineAnalyticsProposeRetrainAnnotationsWithLlm = usePipelineAnalyticsProposeRetrainAnnotationsWithLlm;
62444
62969
  exports.usePipelineAnalyticsPruneEvents = usePipelineAnalyticsPruneEvents;
62445
62970
  exports.usePipelineAnalyticsPruneEventsBefore = usePipelineAnalyticsPruneEventsBefore;
62446
62971
  exports.usePipelineAnalyticsPruneTracksBefore = usePipelineAnalyticsPruneTracksBefore;
@@ -62450,6 +62975,8 @@ exports.usePipelineAnalyticsReclaimDebugMedia = usePipelineAnalyticsReclaimDebug
62450
62975
  exports.usePipelineAnalyticsReconcileFromDisk = usePipelineAnalyticsReconcileFromDisk;
62451
62976
  exports.usePipelineAnalyticsRefreshStorageLocationsForMigration = usePipelineAnalyticsRefreshStorageLocationsForMigration;
62452
62977
  exports.usePipelineAnalyticsRelocateMedia = usePipelineAnalyticsRelocateMedia;
62978
+ exports.usePipelineAnalyticsRemoveRetrainFrameFromCollection = usePipelineAnalyticsRemoveRetrainFrameFromCollection;
62979
+ exports.usePipelineAnalyticsRenameRetrainCollection = usePipelineAnalyticsRenameRetrainCollection;
62453
62980
  exports.usePipelineAnalyticsRestageRetrainTrack = usePipelineAnalyticsRestageRetrainTrack;
62454
62981
  exports.usePipelineAnalyticsResumeForStorageMigration = usePipelineAnalyticsResumeForStorageMigration;
62455
62982
  exports.usePipelineAnalyticsSaveRetrainAnnotations = usePipelineAnalyticsSaveRetrainAnnotations;
@@ -62460,6 +62987,7 @@ exports.usePipelineAnalyticsSetTrackFlags = usePipelineAnalyticsSetTrackFlags;
62460
62987
  exports.usePipelineAnalyticsSetTrackPurity = usePipelineAnalyticsSetTrackPurity;
62461
62988
  exports.usePipelineAnalyticsSetTrackRelation = usePipelineAnalyticsSetTrackRelation;
62462
62989
  exports.usePipelineAnalyticsStartStorageMigrationMove = usePipelineAnalyticsStartStorageMigrationMove;
62990
+ exports.usePipelineAnalyticsVerifyRetrainDatasetVersion = usePipelineAnalyticsVerifyRetrainDatasetVersion;
62463
62991
  exports.usePipelineAnalyticsWipeAllAnalytics = usePipelineAnalyticsWipeAllAnalytics;
62464
62992
  exports.usePipelineAnalyticsWipeObjectEmbeddings = usePipelineAnalyticsWipeObjectEmbeddings;
62465
62993
  exports.usePipelineAnalyticsWriteRetrainArchive = usePipelineAnalyticsWriteRetrainArchive;
@@ -62498,10 +63026,12 @@ exports.usePipelineExecutorSetVideoPipelineSteps = usePipelineExecutorSetVideoPi
62498
63026
  exports.usePipelineExecutorSpinEngine = usePipelineExecutorSpinEngine;
62499
63027
  exports.usePipelineExecutorUncacheFrame = usePipelineExecutorUncacheFrame;
62500
63028
  exports.usePipelineExecutorValidatePipeline = usePipelineExecutorValidatePipeline;
63029
+ exports.usePipelineOrchestratorAbortNodeBenchmark = usePipelineOrchestratorAbortNodeBenchmark;
62501
63030
  exports.usePipelineOrchestratorApplyAutoTune = usePipelineOrchestratorApplyAutoTune;
62502
63031
  exports.usePipelineOrchestratorApplyDeviceSettingsPatch = usePipelineOrchestratorApplyDeviceSettingsPatch;
62503
63032
  exports.usePipelineOrchestratorAssignAudio = usePipelineOrchestratorAssignAudio;
62504
63033
  exports.usePipelineOrchestratorAssignPipeline = usePipelineOrchestratorAssignPipeline;
63034
+ exports.usePipelineOrchestratorDeleteNodeBenchmarkResult = usePipelineOrchestratorDeleteNodeBenchmarkResult;
62505
63035
  exports.usePipelineOrchestratorGetAgentLoad = usePipelineOrchestratorGetAgentLoad;
62506
63036
  exports.usePipelineOrchestratorGetAgentSettings = usePipelineOrchestratorGetAgentSettings;
62507
63037
  exports.usePipelineOrchestratorGetAudioAssignment = usePipelineOrchestratorGetAudioAssignment;
@@ -62520,6 +63050,9 @@ exports.usePipelineOrchestratorGetDeviceSettingsContribution = usePipelineOrches
62520
63050
  exports.usePipelineOrchestratorGetEffectiveShares = usePipelineOrchestratorGetEffectiveShares;
62521
63051
  exports.usePipelineOrchestratorGetGlobalMetrics = usePipelineOrchestratorGetGlobalMetrics;
62522
63052
  exports.usePipelineOrchestratorGetIngestOwner = usePipelineOrchestratorGetIngestOwner;
63053
+ exports.usePipelineOrchestratorGetNodeBenchmarkCandidates = usePipelineOrchestratorGetNodeBenchmarkCandidates;
63054
+ exports.usePipelineOrchestratorGetNodeBenchmarkPreflight = usePipelineOrchestratorGetNodeBenchmarkPreflight;
63055
+ exports.usePipelineOrchestratorGetNodeBenchmarkStatus = usePipelineOrchestratorGetNodeBenchmarkStatus;
62523
63056
  exports.usePipelineOrchestratorGetNodeInferenceDevices = usePipelineOrchestratorGetNodeInferenceDevices;
62524
63057
  exports.usePipelineOrchestratorGetPipelineAssignment = usePipelineOrchestratorGetPipelineAssignment;
62525
63058
  exports.usePipelineOrchestratorGetPipelineAssignments = usePipelineOrchestratorGetPipelineAssignments;
@@ -62527,6 +63060,7 @@ exports.usePipelineOrchestratorGetPipelineDevicePin = usePipelineOrchestratorGet
62527
63060
  exports.usePipelineOrchestratorGetPlacementStats = usePipelineOrchestratorGetPlacementStats;
62528
63061
  exports.usePipelineOrchestratorGetReconcileFromDiskStatus = usePipelineOrchestratorGetReconcileFromDiskStatus;
62529
63062
  exports.usePipelineOrchestratorListAgentSettings = usePipelineOrchestratorListAgentSettings;
63063
+ exports.usePipelineOrchestratorListNodeBenchmarkResults = usePipelineOrchestratorListNodeBenchmarkResults;
62530
63064
  exports.usePipelineOrchestratorPauseForStorageMigration = usePipelineOrchestratorPauseForStorageMigration;
62531
63065
  exports.usePipelineOrchestratorPlanAutoTune = usePipelineOrchestratorPlanAutoTune;
62532
63066
  exports.usePipelineOrchestratorRebalance = usePipelineOrchestratorRebalance;
@@ -62551,9 +63085,11 @@ exports.usePipelineOrchestratorSetCapabilityBinding = usePipelineOrchestratorSet
62551
63085
  exports.usePipelineOrchestratorSetLoadBalancingShares = usePipelineOrchestratorSetLoadBalancingShares;
62552
63086
  exports.usePipelineOrchestratorSetPipelineDevicePin = usePipelineOrchestratorSetPipelineDevicePin;
62553
63087
  exports.usePipelineOrchestratorSetShareSource = usePipelineOrchestratorSetShareSource;
63088
+ exports.usePipelineOrchestratorStartNodeBenchmark = usePipelineOrchestratorStartNodeBenchmark;
62554
63089
  exports.usePipelineOrchestratorSuggestShares = usePipelineOrchestratorSuggestShares;
62555
63090
  exports.usePipelineOrchestratorUnassignAudio = usePipelineOrchestratorUnassignAudio;
62556
63091
  exports.usePipelineOrchestratorUnassignPipeline = usePipelineOrchestratorUnassignPipeline;
63092
+ exports.usePipelineRunnerAbortNodeBench = usePipelineRunnerAbortNodeBench;
62557
63093
  exports.usePipelineRunnerAttachCamera = usePipelineRunnerAttachCamera;
62558
63094
  exports.usePipelineRunnerDetachCamera = usePipelineRunnerDetachCamera;
62559
63095
  exports.usePipelineRunnerGetAllCameraMetrics = usePipelineRunnerGetAllCameraMetrics;
@@ -62562,6 +63098,7 @@ exports.usePipelineRunnerGetLocalCameras = usePipelineRunnerGetLocalCameras;
62562
63098
  exports.usePipelineRunnerGetLocalLoad = usePipelineRunnerGetLocalLoad;
62563
63099
  exports.usePipelineRunnerGetLocalMetrics = usePipelineRunnerGetLocalMetrics;
62564
63100
  exports.usePipelineRunnerGetNativeCrop = usePipelineRunnerGetNativeCrop;
63101
+ exports.usePipelineRunnerGetNodeBenchStatus = usePipelineRunnerGetNodeBenchStatus;
62565
63102
  exports.usePipelineRunnerGetParkedTrackFrame = usePipelineRunnerGetParkedTrackFrame;
62566
63103
  exports.usePipelineRunnerParkTrackFrame = usePipelineRunnerParkTrackFrame;
62567
63104
  exports.usePipelineRunnerReleaseParkedTrackFrames = usePipelineRunnerReleaseParkedTrackFrames;
@@ -62569,6 +63106,7 @@ exports.usePipelineRunnerReportMotion = usePipelineRunnerReportMotion;
62569
63106
  exports.usePipelineRunnerRequestOccupancyBurst = usePipelineRunnerRequestOccupancyBurst;
62570
63107
  exports.usePipelineRunnerRunDetailSubtree = usePipelineRunnerRunDetailSubtree;
62571
63108
  exports.usePipelineRunnerRunStatelessStep = usePipelineRunnerRunStatelessStep;
63109
+ exports.usePipelineRunnerStartNodeBench = usePipelineRunnerStartNodeBench;
62572
63110
  exports.usePlateGalleryAssignPlate = usePlateGalleryAssignPlate;
62573
63111
  exports.usePlateGalleryAssignPlates = usePlateGalleryAssignPlates;
62574
63112
  exports.usePlateGalleryCorrectPlateText = usePlateGalleryCorrectPlateText;