@camstack/addon-training 0.1.22 → 0.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/MaskShapeCanvas-Kfg9dl6B.mjs +686 -0
  2. package/dist/MotionZonesSettings-0RO2vXPR.mjs +292 -0
  3. package/dist/{PrivacyMaskSettings-DDaIx7j5.mjs → PrivacyMaskSettings-DQUoMnuu.mjs} +45 -70
  4. package/dist/ReactKonva-DGuYUN0L.mjs +5416 -0
  5. package/dist/{SceneMonitorEditor-CuJ7xjyd.mjs → SceneMonitorEditor-C3FOjEom.mjs} +311 -311
  6. package/dist/_stub.js +16625 -7160
  7. package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-DJDgoXBt.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-BxPcEUyP.mjs} +2 -2
  8. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-OmGE1nuE.mjs +26 -0
  9. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-DpjirGmB.mjs +89 -0
  10. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_trpc_mf_1_client__loadShare__.js-CFCVuRAs.mjs +58 -0
  11. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_trpc_mf_1_react_mf_2_query__loadShare__.js-BkvDudqY.mjs +62 -0
  12. package/dist/{_virtual_mf___mfe_internal__addon_training_page__loadShare__react__loadShare__.js-BT_wL8s3.mjs → _virtual_mf___mfe_internal__addon_training_page__loadShare__react__loadShare__.js-DeDbF7NI.mjs} +1 -1
  13. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-DnrbBvrw.mjs +34 -0
  14. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare__react_mf_2_dom__loadShare__.js-DAZkHxxU.mjs +45 -0
  15. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-CHqN9NLt.mjs +34 -0
  16. package/dist/{dist-DhCvklZW.mjs → dist-CoNkmm69.mjs} +24 -12
  17. package/dist/{dist-Dd6EAdVX.js → dist-e1vfYY_l.js} +59 -11
  18. package/dist/grid-2x2-Dip9973H.mjs +21 -0
  19. package/dist/{hostInit-DR-St7pA.mjs → hostInit-DESLun4m.mjs} +1 -1
  20. package/dist/index.js +1 -1
  21. package/dist/lib-CVGFTwe0.mjs +7770 -0
  22. package/dist/orchestrator/training.addon.js +8 -1
  23. package/dist/orchestrator/training.addon.mjs +8 -1
  24. package/dist/{player-overlays-DUZMtmvk.mjs → player-overlays-ChonJUSb.mjs} +32 -10
  25. package/dist/providers/modal/training-modal.addon.js +233 -53
  26. package/dist/providers/modal/training-modal.addon.mjs +233 -53
  27. package/dist/remoteEntry.js +1 -1
  28. package/dist/{responsive-C7QsFtTb.mjs → responsive-vGH-n9E5.mjs} +42 -38
  29. package/dist/{scene-monitor-copy-BtffdnnW.mjs → scene-monitor-copy-Bv7SdZp4.mjs} +4 -4
  30. package/dist/{square-e5Ytjod_.mjs → square-CT7zu_EB.mjs} +29 -4
  31. package/dist/{trash-2-Clte6zIF.mjs → trash-2-JjHVW2_2.mjs} +1 -1
  32. package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-dy7yMOdw.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-BZV1gmqf.mjs} +399 -390
  33. package/package.json +1 -1
  34. package/dist/MaskShapeCanvas-BokARvOj.mjs +0 -13806
  35. package/dist/MotionZonesSettings-DshSNzpp.mjs +0 -310
  36. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D7T4QEtw.mjs +0 -26
  37. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-BSOdwqcC.mjs +0 -26
  38. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_trpc_mf_1_client__loadShare__.js-B3rryujf.mjs +0 -25
  39. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_trpc_mf_1_react_mf_2_query__loadShare__.js-nL4MGFRP.mjs +0 -26
  40. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-DDBEvLdo.mjs +0 -26
  41. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare__react_mf_2_dom__loadShare__.js-CK-LlgOt.mjs +0 -26
  42. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-gTIQrhKs.mjs +0 -25
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_dist = require("../dist-Dd6EAdVX.js");
2
+ const require_dist = require("../dist-e1vfYY_l.js");
3
3
  let node_path = require("node:path");
4
4
  node_path = require_dist.__toESM(node_path);
5
5
  let node_crypto = require("node:crypto");
@@ -32,6 +32,13 @@ function providerPort(api) {
32
32
  addonId
33
33
  });
34
34
  },
35
+ updateEntry: async (i) => {
36
+ const addonId = await addonForEntry(i.entryId);
37
+ return p.updateEntry.mutate({
38
+ ...i,
39
+ addonId
40
+ });
41
+ },
35
42
  deleteEntry: async (i) => {
36
43
  const addonId = await addonForEntry(i.entryId);
37
44
  return p.deleteEntry.mutate({
@@ -1,4 +1,4 @@
1
- import { a as addonPagesSourceCapability, i as TrainingResultSchema, l as BaseAddon, n as TrainingJobSchema, o as parseTrainingEventLine, r as TrainingJobSpecSchema, s as trainingCapability, t as TRAINING_JOB_SCHEMA } from "../dist-DhCvklZW.mjs";
1
+ import { a as addonPagesSourceCapability, i as TrainingResultSchema, l as BaseAddon, n as TrainingJobSchema, o as parseTrainingEventLine, r as TrainingJobSpecSchema, s as trainingCapability, t as TRAINING_JOB_SCHEMA } from "../dist-CoNkmm69.mjs";
2
2
  import path from "node:path";
3
3
  import { createHash } from "node:crypto";
4
4
  import { createReadStream } from "node:fs";
@@ -30,6 +30,13 @@ function providerPort(api) {
30
30
  addonId
31
31
  });
32
32
  },
33
+ updateEntry: async (i) => {
34
+ const addonId = await addonForEntry(i.entryId);
35
+ return p.updateEntry.mutate({
36
+ ...i,
37
+ addonId
38
+ });
39
+ },
33
40
  deleteEntry: async (i) => {
34
41
  const addonId = await addonForEntry(i.entryId);
35
42
  return p.deleteEntry.mutate({
@@ -1,10 +1,10 @@
1
- import { b as e, g as t, l as n, u as r } from "./_virtual_mf___mfe_internal__addon_training_page__loadShare__react__loadShare__.js-BT_wL8s3.mjs";
2
- import { v as i, y as a } from "./responsive-C7QsFtTb.mjs";
3
- import { n as o, r as s, t as c } from "./_virtual_mf___mfe_internal__addon_training_page__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-DDBEvLdo.mjs";
4
- var l = a("chevron-down", [["path", {
1
+ import { S as e, _ as t, l as n, u as r } from "./_virtual_mf___mfe_internal__addon_training_page__loadShare__react__loadShare__.js-DeDbF7NI.mjs";
2
+ import { b as i, y as a } from "./responsive-vGH-n9E5.mjs";
3
+ import { n as o, r as s, t as c } from "./_virtual_mf___mfe_internal__addon_training_page__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-DnrbBvrw.mjs";
4
+ var l = i("chevron-down", [["path", {
5
5
  d: "m6 9 6 6 6-6",
6
6
  key: "qrunsl"
7
- }]]), u = a("chevron-right", [["path", {
7
+ }]]), u = i("chevron-right", [["path", {
8
8
  d: "m9 18 6-6-6-6",
9
9
  key: "mthhwq"
10
10
  }]]);
@@ -32,13 +32,35 @@ function d({ title: e, icon: n, headerRight: r, collapsible: i = !1, defaultOpen
32
32
  }) : null]
33
33
  });
34
34
  }
35
- e(), i("camstack:player-overlays-state", null);
36
- var f = i("camstack:player-overlays-actions", null);
37
- function p(e) {
38
- let t = n(f);
35
+ function f({ label: e, icon: t, children: n, footer: r }) {
36
+ return /* @__PURE__ */ s("div", {
37
+ className: "min-w-0 rounded-lg border border-border bg-surface p-2 sm:p-2.5",
38
+ children: [
39
+ /* @__PURE__ */ s("div", {
40
+ className: "mb-0.5 flex min-w-0 items-center gap-1.5 text-[10px] uppercase tracking-wider text-foreground-subtle",
41
+ children: [t, /* @__PURE__ */ o("span", {
42
+ className: "min-w-0 truncate",
43
+ children: e
44
+ })]
45
+ }),
46
+ /* @__PURE__ */ o("div", {
47
+ className: "truncate text-lg font-semibold leading-tight text-foreground",
48
+ children: n
49
+ }),
50
+ r == null ? null : /* @__PURE__ */ o("div", {
51
+ className: "mt-0.5 truncate text-[10px] text-foreground-subtle",
52
+ children: r
53
+ })
54
+ ]
55
+ });
56
+ }
57
+ e(), a("camstack:player-overlays-state", null);
58
+ var p = a("camstack:player-overlays-actions", null);
59
+ function m(e) {
60
+ let t = n(p);
39
61
  r(() => {
40
62
  if (!(!t || !e)) return t.setLayer(e), () => t.removeLayer(e.id);
41
63
  }, [t, e]);
42
64
  }
43
65
  //#endregion
44
- export { l as i, d as n, u as r, p as t };
66
+ export { l as a, u as i, f as n, d as r, m as t };
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_dist = require("../../dist-Dd6EAdVX.js");
2
+ const require_dist = require("../../dist-e1vfYY_l.js");
3
3
  let node_path = require("node:path");
4
4
  node_path = require_dist.__toESM(node_path, 1);
5
5
  let node_crypto = require("node:crypto");
@@ -11,14 +11,43 @@ let timers_promises = require("timers/promises");
11
11
  let node_console = require("node:console");
12
12
  let node_os = require("node:os");
13
13
  let node_stream = require("node:stream");
14
- //#region src/providers/modal/modal-entries.ts
14
+ //#region src/providers/modal/entry-secret-view.ts
15
15
  /**
16
- * Modal provider entries — one credentials + defaults row per operator
17
- * account. Pure helpers so the store is unit-tested without BaseAddon.
16
+ * Build the {@link SecretFieldView} the Providers edit form needs for an
17
+ * entry's token secret.
18
18
  *
19
- * A pre-multi-entry config (flat tokenId/tokenSecret on the addon) migrates
20
- * to a single entry named {@link DEFAULT_MODAL_ENTRY_NAME}.
19
+ * `readStoredGlobalKey` / `this.config` answer VALUES (D798), never markers —
20
+ * so `toSecretFieldView(plaintext)` alone yields an inline view (`$secret:
21
+ * null`) and `SecretFieldControl` cannot reveal. When the secret is set we
22
+ * prefer the deterministic keychain ref (`ctx.secrets.ref`) so the eye can
23
+ * call `keychain-admin.reveal` (D789).
21
24
  */
25
+ /** View for one entry row, or `null` when nothing is stored. */
26
+ function entryTokenSecretView(tokenSecret, secrets, entryId) {
27
+ if (require_dist.isSecretMarker(tokenSecret)) return require_dist.toSecretFieldView(tokenSecret);
28
+ const plain = typeof tokenSecret === "string" ? tokenSecret.trim() : "";
29
+ if (plain === "") return null;
30
+ if (secrets === void 0) return require_dist.toSecretFieldView(plain);
31
+ return {
32
+ $secret: secrets.ref(require_dist.globalSecretScope(), require_dist.arrayItemFieldPath("entries", entryId, "tokenSecret")),
33
+ v: 1,
34
+ set: true
35
+ };
36
+ }
37
+ /** View for the legacy flat `tokenSecret` (pre-multi-entry Default). */
38
+ function flatTokenSecretView(tokenSecret, secrets) {
39
+ if (require_dist.isSecretMarker(tokenSecret)) return require_dist.toSecretFieldView(tokenSecret);
40
+ const plain = typeof tokenSecret === "string" ? tokenSecret.trim() : "";
41
+ if (plain === "") return null;
42
+ if (secrets === void 0) return require_dist.toSecretFieldView(plain);
43
+ return {
44
+ $secret: secrets.ref(require_dist.globalSecretScope(), "tokenSecret"),
45
+ v: 1,
46
+ set: true
47
+ };
48
+ }
49
+ //#endregion
50
+ //#region src/providers/modal/modal-entries.ts
22
51
  var MODAL_TYPE_ID = "modal";
23
52
  var DEFAULT_MODAL_ENTRY_NAME = "Default";
24
53
  var MODAL_ICON_ASSET = "assets/training-modal/icon.svg";
@@ -29,22 +58,44 @@ var DEFAULT_GRACE = 24;
29
58
  function legacyConfigured(config) {
30
59
  return (config.tokenId ?? "").trim() !== "" || (config.tokenSecret ?? "").trim() !== "";
31
60
  }
61
+ /**
62
+ * Keychain / secretStatePaths may omit an empty `tokenSecret` from a stored
63
+ * row (writing `''` is KEEP, not "store empty"). Readers must never see
64
+ * `undefined` and then call `.trim()`.
65
+ */
66
+ function secretAsString(value) {
67
+ return typeof value === "string" ? value : "";
68
+ }
69
+ function normalizeModalEntry(entry) {
70
+ return {
71
+ id: entry.id,
72
+ name: entry.name ?? "Default",
73
+ tokenId: entry.tokenId ?? "",
74
+ tokenSecret: secretAsString(entry.tokenSecret),
75
+ environment: entry.environment ?? "",
76
+ gpuType: entry.gpuType ?? DEFAULT_GPU,
77
+ region: entry.region ?? "",
78
+ costCapUsd: entry.costCapUsd ?? DEFAULT_COST,
79
+ maxRuntimeHours: entry.maxRuntimeHours ?? DEFAULT_HOURS,
80
+ failedDatasetGraceHours: entry.failedDatasetGraceHours ?? DEFAULT_GRACE
81
+ };
82
+ }
32
83
  /** Entries the operator sees — synthesises Default from legacy flat fields. */
33
84
  function effectiveModalEntries(config) {
34
- if (config.entries.length > 0) return config.entries;
85
+ if (config.entries.length > 0) return config.entries.map((e) => normalizeModalEntry(e));
35
86
  if (!legacyConfigured(config)) return [];
36
- return [{
87
+ return [normalizeModalEntry({
37
88
  id: "legacy-default",
38
89
  name: DEFAULT_MODAL_ENTRY_NAME,
39
- tokenId: config.tokenId ?? "",
40
- tokenSecret: config.tokenSecret ?? "",
41
- environment: config.environment ?? "",
42
- gpuType: config.gpuType ?? DEFAULT_GPU,
43
- region: config.region ?? "",
44
- costCapUsd: config.costCapUsd ?? DEFAULT_COST,
45
- maxRuntimeHours: config.maxRuntimeHours ?? DEFAULT_HOURS,
46
- failedDatasetGraceHours: config.failedDatasetGraceHours ?? DEFAULT_GRACE
47
- }];
90
+ tokenId: config.tokenId,
91
+ tokenSecret: config.tokenSecret,
92
+ environment: config.environment,
93
+ gpuType: config.gpuType,
94
+ region: config.region,
95
+ costCapUsd: config.costCapUsd,
96
+ maxRuntimeHours: config.maxRuntimeHours,
97
+ failedDatasetGraceHours: config.failedDatasetGraceHours
98
+ })];
48
99
  }
49
100
  function findModalEntry(config, entryId) {
50
101
  return effectiveModalEntries(config).find((e) => e.id === entryId) ?? null;
@@ -249,20 +300,6 @@ function trainerDockerfileUrl(repo, revision) {
249
300
  return `https://huggingface.co/${repo}/resolve/${revision}/Dockerfile`;
250
301
  }
251
302
  //#endregion
252
- //#region src/providers/modal/modal-gateway.ts
253
- var MODAL_APP_NAME = "camstack-training";
254
- var MODAL_CACHE_VOLUME = "camstack-training-cache";
255
- /** A small public image with `sh` and `cat`, for the staging / collector sandboxes. */
256
- var MODAL_TOOLS_IMAGE = "alpine:3.20";
257
- var ModalAuthError = class extends Error {
258
- reason;
259
- constructor(reason, message) {
260
- super(message);
261
- this.reason = reason;
262
- this.name = "ModalAuthError";
263
- }
264
- };
265
- //#endregion
266
303
  //#region src/providers/modal/modal-pricing.ts
267
304
  var MODAL_GPUS = [
268
305
  {
@@ -340,6 +377,96 @@ function modalPricePerSecond(gpuType, region) {
340
377
  return gpu === void 0 ? 0 : gpu.usdPerHour * multiplier / 3600;
341
378
  }
342
379
  //#endregion
380
+ //#region src/providers/modal/modal-entry-schema.ts
381
+ var MODAL_ENTRY_CONFIG_SCHEMA = { sections: [{
382
+ id: "credentials",
383
+ title: "Credentials",
384
+ fields: [
385
+ {
386
+ type: "text",
387
+ key: "tokenId",
388
+ label: "Token id",
389
+ placeholder: "ak-…"
390
+ },
391
+ {
392
+ type: "password",
393
+ key: "tokenSecret",
394
+ label: "Token secret",
395
+ placeholder: "as-…",
396
+ showToggle: true
397
+ },
398
+ {
399
+ type: "text",
400
+ key: "environment",
401
+ label: "Environment",
402
+ placeholder: "Optional workspace environment"
403
+ }
404
+ ]
405
+ }, {
406
+ id: "defaults",
407
+ title: "Defaults",
408
+ fields: [
409
+ {
410
+ type: "select",
411
+ key: "gpuType",
412
+ label: "GPU",
413
+ default: "L4",
414
+ options: MODAL_GPUS.map((g) => ({
415
+ value: g.id,
416
+ label: g.label
417
+ }))
418
+ },
419
+ {
420
+ type: "select",
421
+ key: "region",
422
+ label: "Region",
423
+ default: "",
424
+ options: MODAL_REGIONS.map((r) => ({
425
+ value: r.id,
426
+ label: r.label
427
+ }))
428
+ },
429
+ {
430
+ type: "number",
431
+ key: "costCapUsd",
432
+ label: "Cost cap (USD)",
433
+ default: 5,
434
+ min: 0,
435
+ step: .5
436
+ },
437
+ {
438
+ type: "number",
439
+ key: "maxRuntimeHours",
440
+ label: "Max runtime (hours)",
441
+ default: 4,
442
+ min: .1,
443
+ step: .5
444
+ },
445
+ {
446
+ type: "number",
447
+ key: "failedDatasetGraceHours",
448
+ label: "Failed-job dataset grace (hours)",
449
+ default: 24,
450
+ min: 0,
451
+ step: 1
452
+ }
453
+ ]
454
+ }] };
455
+ //#endregion
456
+ //#region src/providers/modal/modal-gateway.ts
457
+ var MODAL_APP_NAME = "camstack-training";
458
+ var MODAL_CACHE_VOLUME = "camstack-training-cache";
459
+ /** A small public image with `sh` and `cat`, for the staging / collector sandboxes. */
460
+ var MODAL_TOOLS_IMAGE = "alpine:3.20";
461
+ var ModalAuthError = class extends Error {
462
+ reason;
463
+ constructor(reason, message) {
464
+ super(message);
465
+ this.reason = reason;
466
+ this.name = "ModalAuthError";
467
+ }
468
+ };
469
+ //#endregion
343
470
  //#region src/providers/modal/modal-provider.ts
344
471
  /**
345
472
  * The Modal `training-provider` (D807), over {@link ModalGateway}.
@@ -381,12 +508,16 @@ var ModalTrainingProvider = class {
381
508
  constructor(deps) {
382
509
  this.deps = deps;
383
510
  }
384
- describe = async () => this.deps.listEntries().map((entry) => this.descriptorOf(entry));
511
+ describe = async () => {
512
+ const views = await this.deps.secretViews();
513
+ return this.deps.listEntries().map((entry) => this.descriptorOf(entry, views.get(entry.id) ?? null));
514
+ };
385
515
  describeTypes = async () => [{
386
516
  typeId: MODAL_TYPE_ID,
387
517
  label: "Modal",
388
518
  iconAsset: MODAL_ICON_ASSET,
389
- addonId: this.deps.addonId
519
+ addonId: this.deps.addonId,
520
+ configSchema: MODAL_ENTRY_CONFIG_SCHEMA
390
521
  }];
391
522
  listEntries = async () => this.deps.listEntries().map((entry) => ({
392
523
  entryId: entry.id,
@@ -397,10 +528,11 @@ var ModalTrainingProvider = class {
397
528
  }));
398
529
  createEntry = async (input) => this.deps.createEntry(input);
399
530
  updateEntry = async (input) => {
531
+ const secret = input.tokenSecret === void 0 ? {} : require_dist.isSecretClear(input.tokenSecret) ? { clearTokenSecret: true } : input.tokenSecret === "" ? {} : { tokenSecret: input.tokenSecret };
400
532
  await this.deps.updateEntry(input.entryId, {
401
533
  name: input.name,
402
534
  ...input.tokenId !== void 0 ? { tokenId: input.tokenId } : {},
403
- ...input.tokenSecret !== void 0 ? { tokenSecret: input.tokenSecret } : {},
535
+ ...secret,
404
536
  ...input.environment !== void 0 ? { environment: input.environment } : {},
405
537
  ...input.gpuType !== void 0 ? { gpuType: input.gpuType } : {},
406
538
  ...input.region !== void 0 ? { region: input.region } : {},
@@ -687,9 +819,15 @@ var ModalTrainingProvider = class {
687
819
  }))];
688
820
  };
689
821
  entryConfigured(entry) {
690
- return entry.tokenId.trim() !== "" && entry.tokenSecret.trim() !== "";
822
+ const secret = typeof entry.tokenSecret === "string" ? entry.tokenSecret : "";
823
+ return (entry.tokenId ?? "").trim() !== "" && secret.trim() !== "";
691
824
  }
692
- descriptorOf(entry) {
825
+ descriptorOf(entry, tokenSecretView) {
826
+ const gpuType = entry.gpuType ?? "L4";
827
+ const region = entry.region ?? "";
828
+ const costCapUsd = entry.costCapUsd ?? 5;
829
+ const maxRuntimeHours = entry.maxRuntimeHours ?? 4;
830
+ const failedDatasetGraceHours = entry.failedDatasetGraceHours ?? 24;
693
831
  return {
694
832
  addonId: this.deps.addonId,
695
833
  entryId: entry.id,
@@ -706,15 +844,22 @@ var ModalTrainingProvider = class {
706
844
  dataResidencyNote: "Modal keeps the frames on a Volume of your workspace for the length of the job; the training container sees them only while it runs.",
707
845
  configured: this.entryConfigured(entry),
708
846
  defaults: {
709
- gpuType: entry.gpuType,
710
- region: entry.region,
711
- costCapUsd: entry.costCapUsd,
712
- maxRuntimeSec: Math.round(entry.maxRuntimeHours * 3600),
713
- failedDatasetGraceHours: entry.failedDatasetGraceHours
847
+ gpuType,
848
+ region,
849
+ costCapUsd,
850
+ maxRuntimeSec: Math.round(maxRuntimeHours * 3600),
851
+ failedDatasetGraceHours
714
852
  },
715
- tokenId: entry.tokenId,
716
- environment: entry.environment,
717
- hasTokenSecret: entry.tokenSecret.trim() !== ""
853
+ formValues: {
854
+ tokenId: entry.tokenId ?? "",
855
+ tokenSecret: tokenSecretView ?? "",
856
+ environment: entry.environment ?? "",
857
+ gpuType,
858
+ region,
859
+ costCapUsd,
860
+ maxRuntimeHours,
861
+ failedDatasetGraceHours
862
+ }
718
863
  };
719
864
  }
720
865
  requireGateway(entryId) {
@@ -88588,9 +88733,15 @@ var TrainingModalAddon = class extends require_dist.BaseAddon {
88588
88733
  }
88589
88734
  async onInitialize() {
88590
88735
  let next = this.config;
88591
- if (next.entries.length === 0) next = migrateLegacyModalConfig(next, () => (0, node_crypto.randomUUID)());
88736
+ let migratedLegacy = false;
88737
+ if (next.entries.length === 0) {
88738
+ const migrated = migrateLegacyModalConfig(next, () => (0, node_crypto.randomUUID)());
88739
+ migratedLegacy = migrated !== next;
88740
+ next = migrated;
88741
+ }
88592
88742
  next = ensureModalEntryIds(next, () => (0, node_crypto.randomUUID)());
88593
88743
  if (next !== this.config) await this.updateGlobalSettings(next);
88744
+ if (migratedLegacy) await this.clearSecrets(["tokenSecret"]);
88594
88745
  this.ledgerState = this.state(LEDGER_KEY, LedgerSchema, {});
88595
88746
  const peer = this.ctx.peerBytes;
88596
88747
  if (peer === void 0) throw new Error("training-modal needs the peer-bytes facility");
@@ -88606,17 +88757,27 @@ var TrainingModalAddon = class extends require_dist.BaseAddon {
88606
88757
  return { entryId: result.entryId };
88607
88758
  },
88608
88759
  updateEntry: async (entryId, patch) => {
88609
- const result = updateModalEntry(this.config, entryId, patch);
88760
+ const { clearTokenSecret, ...rest } = patch;
88761
+ const result = updateModalEntry(this.config, entryId, rest);
88610
88762
  if (!result.ok) throw new Error(`cannot update entry: ${result.reason}`);
88611
- await this.updateGlobalSettings(result.config);
88763
+ if (clearTokenSecret === true) await this.updateGlobalSettings({
88764
+ ...result.config,
88765
+ entries: result.config.entries.map((entry) => entry.id === entryId ? {
88766
+ ...entry,
88767
+ tokenSecret: require_dist.SECRET_CLEAR
88768
+ } : entry)
88769
+ });
88770
+ else await this.updateGlobalSettings(result.config);
88612
88771
  this.closeGateway(entryId);
88613
88772
  },
88614
88773
  deleteEntry: async (entryId) => {
88615
88774
  const result = deleteModalEntry(this.config, entryId);
88616
88775
  if (!result.ok) throw new Error(`cannot delete entry: ${result.reason}`);
88617
88776
  await this.updateGlobalSettings(result.config);
88777
+ await this.clearSecrets(["tokenSecret"]);
88618
88778
  this.closeGateway(entryId);
88619
88779
  },
88780
+ secretViews: () => this.readEntrySecretViews(),
88620
88781
  ledger: this.ledger(),
88621
88782
  peer,
88622
88783
  fetchText,
@@ -88625,7 +88786,10 @@ var TrainingModalAddon = class extends require_dist.BaseAddon {
88625
88786
  });
88626
88787
  this.ctx.logger.info("Modal training provider ready", { meta: {
88627
88788
  entries: effectiveModalEntries(this.config).length,
88628
- configured: effectiveModalEntries(this.config).some((e) => e.tokenId.trim() !== "" && e.tokenSecret.trim() !== "")
88789
+ configured: effectiveModalEntries(this.config).some((e) => {
88790
+ const secret = typeof e.tokenSecret === "string" ? e.tokenSecret : "";
88791
+ return (e.tokenId ?? "").trim() !== "" && secret.trim() !== "";
88792
+ })
88629
88793
  } });
88630
88794
  return { providers: [{
88631
88795
  capability: require_dist.trainingProviderCapability,
@@ -88643,15 +88807,18 @@ var TrainingModalAddon = class extends require_dist.BaseAddon {
88643
88807
  gatewayFor(entryId) {
88644
88808
  const entry = findModalEntry(this.config, entryId);
88645
88809
  if (entry === null) return null;
88646
- if (entry.tokenId.trim() === "" || entry.tokenSecret.trim() === "") return null;
88647
- const key = `${entry.tokenId}\u0000${entry.environment}`;
88810
+ const tokenId = (entry.tokenId ?? "").trim();
88811
+ const tokenSecret = (typeof entry.tokenSecret === "string" ? entry.tokenSecret : "").trim();
88812
+ if (tokenId === "" || tokenSecret === "") return null;
88813
+ const environment = (entry.environment ?? "").trim();
88814
+ const key = `${tokenId}\u0000${environment}`;
88648
88815
  const cached = this.gateways.get(entryId);
88649
88816
  if (cached !== void 0 && cached.key === key) return cached.gateway;
88650
88817
  cached?.gateway.close();
88651
88818
  const gateway = new ModalSdkGateway({
88652
- tokenId: entry.tokenId.trim(),
88653
- tokenSecret: entry.tokenSecret.trim(),
88654
- environment: entry.environment.trim()
88819
+ tokenId,
88820
+ tokenSecret,
88821
+ environment
88655
88822
  });
88656
88823
  this.gateways.set(entryId, {
88657
88824
  key,
@@ -88665,6 +88832,19 @@ var TrainingModalAddon = class extends require_dist.BaseAddon {
88665
88832
  cached.gateway.close();
88666
88833
  this.gateways.delete(entryId);
88667
88834
  }
88835
+ /**
88836
+ * Keychain views for the Providers edit form. Addon-facing reads answer
88837
+ * VALUES (D798), so we cannot recover markers from `readStoredGlobalKey`.
88838
+ * When a secret is present on the resolved entry we emit the deterministic
88839
+ * keychain ref (`ctx.secrets.ref`) so `SecretFieldControl` can reveal.
88840
+ */
88841
+ async readEntrySecretViews() {
88842
+ const map = /* @__PURE__ */ new Map();
88843
+ const secrets = this.ctx.secrets;
88844
+ for (const entry of effectiveModalEntries(this.config)) map.set(entry.id, entryTokenSecretView(entry.tokenSecret, secrets, entry.id));
88845
+ map.set("legacy-default", flatTokenSecretView(this.config.tokenSecret, secrets));
88846
+ return map;
88847
+ }
88668
88848
  ledger() {
88669
88849
  const state = () => {
88670
88850
  if (this.ledgerState === null) throw new Error("training-modal ledger not initialised");