@tangle-network/sandbox-ui 0.10.3 → 0.10.5

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/pages.js CHANGED
@@ -24,7 +24,7 @@ import {
24
24
  BillingDashboard,
25
25
  PricingPage,
26
26
  UsageChart
27
- } from "./chunk-OHPW55EV.js";
27
+ } from "./chunk-QMU2PWOU.js";
28
28
  import {
29
29
  Skeleton,
30
30
  SkeletonCard
@@ -298,20 +298,65 @@ function BillingPage({
298
298
 
299
299
  // src/pages/provisioning-wizard.tsx
300
300
  import * as React2 from "react";
301
- import { ArrowLeft, Layers, Cpu, Bot, Info, Loader2, Settings, Plus, Trash2, Check } from "lucide-react";
301
+ import {
302
+ ArrowLeft,
303
+ Layers,
304
+ Cpu,
305
+ Bot,
306
+ Info,
307
+ Loader2,
308
+ Settings,
309
+ Plus,
310
+ Trash2,
311
+ Check
312
+ } from "lucide-react";
302
313
  import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
303
- var VALID_DRIVERS = /* @__PURE__ */ new Set(["docker", "firecracker", "tangle"]);
314
+ var VALID_DRIVERS = /* @__PURE__ */ new Set([
315
+ "docker",
316
+ "firecracker",
317
+ "tangle"
318
+ ]);
304
319
  var DEFAULT_MODEL_OPTIONS = [
305
320
  { value: "claude-sonnet", label: "Claude Sonnet 4.6 (Highly Capable)" }
306
321
  ];
307
322
  var DEFAULT_MODEL_TIER = DEFAULT_MODEL_OPTIONS[0]?.value ?? "claude-sonnet";
308
323
  var STACK_DISPLAY = {
309
- universal: { name: "Default", abbr: "D", color: "violet", textClass: "text-[var(--surface-violet-text)]" },
310
- ethereum: { name: "Ethereum", abbr: "\u039E", color: "blue", textClass: "text-[var(--surface-info-text)]" },
311
- solana: { name: "Solana", abbr: "S", color: "green", textClass: "text-[var(--surface-success-text)]" },
312
- tangle: { name: "Tangle", abbr: "T", color: "purple", textClass: "text-[var(--surface-violet-text)]" },
313
- "ai-sdk": { name: "AI SDK", abbr: "AI", color: "teal", textClass: "text-[var(--surface-teal-text)]" },
314
- rust: { name: "Rust", abbr: "Rs", color: "orange", textClass: "text-[var(--surface-orange-text)]" }
324
+ universal: {
325
+ name: "Default",
326
+ abbr: "D",
327
+ color: "violet",
328
+ textClass: "text-[var(--surface-violet-text)]"
329
+ },
330
+ ethereum: {
331
+ name: "Ethereum",
332
+ abbr: "\u039E",
333
+ color: "blue",
334
+ textClass: "text-[var(--surface-info-text)]"
335
+ },
336
+ solana: {
337
+ name: "Solana",
338
+ abbr: "S",
339
+ color: "green",
340
+ textClass: "text-[var(--surface-success-text)]"
341
+ },
342
+ tangle: {
343
+ name: "Tangle",
344
+ abbr: "T",
345
+ color: "purple",
346
+ textClass: "text-[var(--surface-violet-text)]"
347
+ },
348
+ "ai-sdk": {
349
+ name: "AI SDK",
350
+ abbr: "AI",
351
+ color: "teal",
352
+ textClass: "text-[var(--surface-teal-text)]"
353
+ },
354
+ rust: {
355
+ name: "Rust",
356
+ abbr: "Rs",
357
+ color: "orange",
358
+ textClass: "text-[var(--surface-orange-text)]"
359
+ }
315
360
  };
316
361
  function resolveEnvironment(env) {
317
362
  if (env.id.startsWith("template:")) {
@@ -338,9 +383,27 @@ function resolveEnvironment(env) {
338
383
  };
339
384
  }
340
385
  var defaultEnvironments = [
341
- { id: "node", name: "Node.js", description: "v20.x LTS with optimized runtime for asynchronous event-driven agents.", icon: /* @__PURE__ */ jsx2("span", { className: "text-[var(--code-success)] text-2xl font-bold", children: "N" }), color: "green" },
342
- { id: "python", name: "Python", description: "v3.11 pre-installed with PyTorch and common data science libraries.", icon: /* @__PURE__ */ jsx2("span", { className: "text-sky-400 text-2xl font-bold", children: "Py" }), color: "blue" },
343
- { id: "ubuntu", name: "Ubuntu", description: "Full 22.04 LTS terminal access for custom containerized workloads.", icon: /* @__PURE__ */ jsx2("span", { className: "text-orange-400 text-2xl font-bold", children: "U" }), color: "orange" }
386
+ {
387
+ id: "node",
388
+ name: "Node.js",
389
+ description: "v20.x LTS with optimized runtime for asynchronous event-driven agents.",
390
+ icon: /* @__PURE__ */ jsx2("span", { className: "text-[var(--code-success)] text-2xl font-bold", children: "N" }),
391
+ color: "green"
392
+ },
393
+ {
394
+ id: "python",
395
+ name: "Python",
396
+ description: "v3.11 pre-installed with PyTorch and common data science libraries.",
397
+ icon: /* @__PURE__ */ jsx2("span", { className: "text-sky-400 text-2xl font-bold", children: "Py" }),
398
+ color: "blue"
399
+ },
400
+ {
401
+ id: "ubuntu",
402
+ name: "Ubuntu",
403
+ description: "Full 22.04 LTS terminal access for custom containerized workloads.",
404
+ icon: /* @__PURE__ */ jsx2("span", { className: "text-orange-400 text-2xl font-bold", children: "U" }),
405
+ color: "orange"
406
+ }
344
407
  ];
345
408
  var CPU_MIN = 0.5;
346
409
  var CPU_MAX = 8;
@@ -354,17 +417,29 @@ var DEFAULT_PRICING_RATES = {
354
417
  diskPerGbHr: 11e-4,
355
418
  minChargePerHr: void 0
356
419
  };
420
+ function formatPerSecondValue(hourlyValue) {
421
+ return (hourlyValue / 3600).toFixed(8);
422
+ }
357
423
  var RAW_PRESETS = [
358
424
  { name: "Lightweight", cpu: 2, ram: 4, storage: 50 },
359
425
  { name: "Standard", cpu: 4, ram: 16, storage: 128 },
360
426
  { name: "Performance", cpu: 8, ram: 32, storage: 256 }
361
427
  ];
362
- function calcCost(cpu, ram, storage, rates) {
363
- const cost = Math.max(
364
- rates.minChargePerHr ?? 0,
365
- cpu * rates.cpuPerHr + ram * rates.ramPerGbHr + storage * rates.diskPerGbHr
366
- );
367
- return cost.toFixed(2);
428
+ function computeHourlyCost(cpu, ram, storage, rates) {
429
+ const compute = cpu * rates.cpuPerHr;
430
+ const memory = ram * rates.ramPerGbHr;
431
+ const storageCost = storage * rates.diskPerGbHr;
432
+ const lineSum = compute + memory + storageCost;
433
+ const floor = rates.minChargePerHr ?? 0;
434
+ return {
435
+ compute,
436
+ memory,
437
+ storage: storageCost,
438
+ lineSum,
439
+ floor,
440
+ floorApplies: floor > lineSum,
441
+ total: Math.max(floor, lineSum)
442
+ };
368
443
  }
369
444
  function ProvisioningWizard({
370
445
  environments: environmentsProp,
@@ -382,11 +457,22 @@ function ProvisioningWizard({
382
457
  pricingRates,
383
458
  planTiers
384
459
  }) {
385
- const cpuMax = Math.max(CPU_MIN, Math.min(resourceLimits?.cpuMax ?? CPU_MAX, CPU_MAX));
386
- const ramMax = Math.max(RAM_MIN, Math.min(resourceLimits?.ramMaxGB ?? RAM_MAX, RAM_MAX));
387
- const storageMax = Math.max(STORAGE_MIN, Math.min(resourceLimits?.storageMaxGB ?? STORAGE_MAX, STORAGE_MAX));
460
+ const cpuMax = Math.max(
461
+ CPU_MIN,
462
+ Math.min(resourceLimits?.cpuMax ?? CPU_MAX, CPU_MAX)
463
+ );
464
+ const ramMax = Math.max(
465
+ RAM_MIN,
466
+ Math.min(resourceLimits?.ramMaxGB ?? RAM_MAX, RAM_MAX)
467
+ );
468
+ const storageMax = Math.max(
469
+ STORAGE_MIN,
470
+ Math.min(resourceLimits?.storageMaxGB ?? STORAGE_MAX, STORAGE_MAX)
471
+ );
388
472
  const dc = defaultConfig;
389
- const [envList, setEnvList] = React2.useState(environmentsProp ?? defaultEnvironments);
473
+ const [envList, setEnvList] = React2.useState(
474
+ environmentsProp ?? defaultEnvironments
475
+ );
390
476
  const onLoadEnvironmentsRef = React2.useRef(onLoadEnvironments);
391
477
  onLoadEnvironmentsRef.current = onLoadEnvironments;
392
478
  React2.useEffect(() => {
@@ -395,7 +481,10 @@ function ProvisioningWizard({
395
481
  onLoadEnvironmentsRef.current().then((entries) => {
396
482
  if (!cancelled) setEnvList(entries.map(resolveEnvironment));
397
483
  }).catch((err) => {
398
- if (!cancelled) setLoadError(err instanceof Error ? err.message : "Failed to load environments");
484
+ if (!cancelled)
485
+ setLoadError(
486
+ err instanceof Error ? err.message : "Failed to load environments"
487
+ );
399
488
  });
400
489
  } else if (environmentsProp) {
401
490
  setEnvList(environmentsProp);
@@ -406,22 +495,32 @@ function ProvisioningWizard({
406
495
  }, [environmentsProp]);
407
496
  const environments = envList;
408
497
  const effectiveDefault = dc?.environment ?? defaultEnvironment;
409
- const [selectedEnv, setSelectedEnv] = React2.useState(effectiveDefault ?? environments[0]?.id ?? "");
498
+ const [selectedEnv, setSelectedEnv] = React2.useState(
499
+ effectiveDefault ?? environments[0]?.id ?? ""
500
+ );
410
501
  React2.useEffect(() => {
411
502
  if (effectiveDefault && envList.some((e) => e.id === effectiveDefault)) {
412
503
  setSelectedEnv(effectiveDefault);
413
504
  }
414
505
  }, [envList, effectiveDefault]);
415
- const [cpuCores, setCpuCores] = React2.useState(Math.min(dc?.cpuCores ?? 4, cpuMax));
506
+ const [cpuCores, setCpuCores] = React2.useState(
507
+ Math.min(dc?.cpuCores ?? 4, cpuMax)
508
+ );
416
509
  const [ramGB, setRamGB] = React2.useState(Math.min(dc?.ramGB ?? 16, ramMax));
417
- const [storageGB, setStorageGB] = React2.useState(Math.min(dc?.storageGB ?? 128, storageMax));
510
+ const [storageGB, setStorageGB] = React2.useState(
511
+ Math.min(dc?.storageGB ?? 128, storageMax)
512
+ );
418
513
  React2.useEffect(() => {
419
514
  setCpuCores((prev) => Math.min(prev, cpuMax));
420
515
  setRamGB((prev) => Math.min(prev, ramMax));
421
516
  setStorageGB((prev) => Math.min(prev, storageMax));
422
517
  }, [cpuMax, ramMax, storageMax]);
423
- const [modelTier, setModelTier] = React2.useState(dc?.modelTier ?? DEFAULT_MODEL_TIER);
424
- const [systemPrompt, setSystemPrompt] = React2.useState(dc?.systemPrompt ?? "");
518
+ const [modelTier, setModelTier] = React2.useState(
519
+ dc?.modelTier ?? DEFAULT_MODEL_TIER
520
+ );
521
+ const [systemPrompt, setSystemPrompt] = React2.useState(
522
+ dc?.systemPrompt ?? ""
523
+ );
425
524
  React2.useEffect(() => {
426
525
  const options = modelOptions ?? DEFAULT_MODEL_OPTIONS;
427
526
  if (options.length === 0) return;
@@ -438,9 +537,12 @@ function ProvisioningWizard({
438
537
  const [envVars, setEnvVars] = React2.useState(dc?.envVars ?? [{ key: "", value: "" }]);
439
538
  const [driver, setDriver] = React2.useState(dc?.driver ?? "docker");
440
539
  const [bare, setBare] = React2.useState(dc?.bare ?? false);
441
- const [startupScriptIds, setStartupScriptIds] = React2.useState(dc?.startupScriptIds ?? []);
540
+ const [startupScriptIds, setStartupScriptIds] = React2.useState(
541
+ dc?.startupScriptIds ?? []
542
+ );
442
543
  const [availableScripts, setAvailableScripts] = React2.useState([]);
443
544
  const [activePreset, setActivePreset] = React2.useState(null);
545
+ const [pricingView, setPricingView] = React2.useState("hourly");
444
546
  const [showAdvanced, setShowAdvanced] = React2.useState(false);
445
547
  const [loadError, setLoadError] = React2.useState(null);
446
548
  const onLoadStartupScriptsRef = React2.useRef(onLoadStartupScripts);
@@ -451,7 +553,10 @@ function ProvisioningWizard({
451
553
  onLoadStartupScriptsRef.current().then((scripts) => {
452
554
  if (!cancelled) setAvailableScripts(scripts);
453
555
  }).catch((err) => {
454
- if (!cancelled) setLoadError(err instanceof Error ? err.message : "Failed to load startup scripts");
556
+ if (!cancelled)
557
+ setLoadError(
558
+ err instanceof Error ? err.message : "Failed to load startup scripts"
559
+ );
455
560
  });
456
561
  }
457
562
  return () => {
@@ -459,7 +564,9 @@ function ProvisioningWizard({
459
564
  };
460
565
  }, []);
461
566
  const isMultistep = variant === "multistep";
462
- const [currentStep, setCurrentStep] = React2.useState(skipToReview && dc && isMultistep ? 3 : 1);
567
+ const [currentStep, setCurrentStep] = React2.useState(
568
+ skipToReview && dc && isMultistep ? 3 : 1
569
+ );
463
570
  const [isDeploying, setIsDeploying] = React2.useState(false);
464
571
  const [deployError, setDeployError] = React2.useState(null);
465
572
  const handleDeploy = async () => {
@@ -467,8 +574,25 @@ function ProvisioningWizard({
467
574
  setIsDeploying(true);
468
575
  setDeployError(null);
469
576
  try {
470
- const validScriptIds = new Set(availableScripts.filter((s) => s.enabled).map((s) => s.id));
471
- await onSubmit({ environment: selectedEnv, cpuCores, ramGB, storageGB, modelTier, systemPrompt, name, gitUrl, envVars: envVars.filter((e) => e.key.trim() !== ""), driver, bare, startupScriptIds: startupScriptIds.filter((id) => validScriptIds.has(id)) });
577
+ const validScriptIds = new Set(
578
+ availableScripts.filter((s) => s.enabled).map((s) => s.id)
579
+ );
580
+ await onSubmit({
581
+ environment: selectedEnv,
582
+ cpuCores,
583
+ ramGB,
584
+ storageGB,
585
+ modelTier,
586
+ systemPrompt,
587
+ name,
588
+ gitUrl,
589
+ envVars: envVars.filter((e) => e.key.trim() !== ""),
590
+ driver,
591
+ bare,
592
+ startupScriptIds: startupScriptIds.filter(
593
+ (id) => validScriptIds.has(id)
594
+ )
595
+ });
472
596
  } catch (err) {
473
597
  setDeployError(err instanceof Error ? err.message : "Deployment failed");
474
598
  } finally {
@@ -511,18 +635,43 @@ function ProvisioningWizard({
511
635
  if (matching) setActivePreset(matching.name);
512
636
  return;
513
637
  }
514
- const largestFitting = [...RAW_PRESETS].reverse().find((p) => p.cpu <= cpuMax && p.ram <= ramMax && p.storage <= storageMax);
638
+ const largestFitting = [...RAW_PRESETS].reverse().find(
639
+ (p) => p.cpu <= cpuMax && p.ram <= ramMax && p.storage <= storageMax
640
+ );
515
641
  if (largestFitting) {
516
- applyPreset(largestFitting.name, largestFitting.cpu, largestFitting.ram, largestFitting.storage);
642
+ applyPreset(
643
+ largestFitting.name,
644
+ largestFitting.cpu,
645
+ largestFitting.ram,
646
+ largestFitting.storage
647
+ );
517
648
  } else {
518
649
  setActivePreset(null);
519
650
  }
520
651
  }, [cpuMax, ramMax, storageMax, dc]);
521
652
  const effectivePricingRates = pricingRates ?? DEFAULT_PRICING_RATES;
522
- const hourCost = calcCost(cpuCores, ramGB, storageGB, effectivePricingRates);
653
+ const hourlyCostBreakdown = computeHourlyCost(
654
+ cpuCores,
655
+ ramGB,
656
+ storageGB,
657
+ effectivePricingRates
658
+ );
659
+ const hourCost = hourlyCostBreakdown.total.toFixed(2);
660
+ const displayValue = pricingView === "hourly" ? hourCost : formatPerSecondValue(hourlyCostBreakdown.total);
661
+ const pricingSuffix = pricingView === "hourly" ? "/ hour" : "/ sec";
662
+ const rateSuffix = pricingView === "hourly" ? "/h" : "/s";
663
+ const fmtRate = (v) => pricingView === "hourly" ? v.toFixed(2) : formatPerSecondValue(v);
523
664
  return /* @__PURE__ */ jsxs2("div", { className: cn("max-w-6xl mx-auto flex flex-col", className), children: [
524
665
  /* @__PURE__ */ jsxs2("div", { className: "mb-6 flex items-center gap-4 shrink-0", children: [
525
- onBack && /* @__PURE__ */ jsx2("button", { type: "button", onClick: onBack, className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border border-border hover:bg-muted/50 transition-colors text-foreground", children: /* @__PURE__ */ jsx2(ArrowLeft, { className: "h-5 w-5" }) }),
666
+ onBack && /* @__PURE__ */ jsx2(
667
+ "button",
668
+ {
669
+ type: "button",
670
+ onClick: onBack,
671
+ className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border border-border hover:bg-muted/50 transition-colors text-foreground",
672
+ children: /* @__PURE__ */ jsx2(ArrowLeft, { className: "h-5 w-5" })
673
+ }
674
+ ),
526
675
  /* @__PURE__ */ jsxs2("div", { children: [
527
676
  /* @__PURE__ */ jsx2("h1", { className: "text-3xl font-extrabold tracking-tight text-foreground mb-1", children: "Sandbox Provisioning" }),
528
677
  /* @__PURE__ */ jsx2("p", { className: "text-muted-foreground text-sm", children: "Select your stack, allocate resources, and configure your agent." })
@@ -531,16 +680,39 @@ function ProvisioningWizard({
531
680
  /* @__PURE__ */ jsxs2("div", { className: "grid grid-cols-12 gap-6 flex-1 min-h-0", children: [
532
681
  /* @__PURE__ */ jsxs2("div", { className: "col-span-12 xl:col-span-8 flex flex-col min-h-0", children: [
533
682
  isMultistep && /* @__PURE__ */ jsx2("div", { className: "flex items-center gap-2 mb-4 bg-card border border-border p-3 rounded-2xl mx-auto max-w-2xl justify-between shrink-0", children: [1, 2, 3].map((s) => /* @__PURE__ */ jsxs2("div", { className: "flex items-center", children: [
534
- /* @__PURE__ */ jsx2("div", { className: cn(
535
- "w-7 h-7 rounded-full flex items-center justify-center font-bold text-xs shrink-0 transition-all duration-200",
536
- currentStep === s ? "bg-primary text-primary-foreground ring-2 ring-primary/30 ring-offset-2 ring-offset-card shadow-sm" : currentStep > s ? "bg-primary text-primary-foreground" : "bg-muted border border-border text-muted-foreground"
537
- ), children: currentStep > s ? /* @__PURE__ */ jsx2(Check, { className: "h-3.5 w-3.5" }) : s }),
538
- /* @__PURE__ */ jsxs2("span", { className: cn("ml-2 sm:ml-3 font-bold text-sm tracking-tight hidden sm:inline transition-colors duration-200", currentStep === s ? "text-foreground" : currentStep > s ? "text-primary" : "text-muted-foreground"), children: [
539
- s === 1 && "Environment",
540
- s === 2 && "Resources",
541
- s === 3 && "AI Agent"
542
- ] }),
543
- s < 3 && /* @__PURE__ */ jsx2("div", { className: cn("w-4 sm:w-8 h-0.5 mx-2 sm:mx-4 rounded-full transition-colors duration-300", currentStep > s ? "bg-primary" : "bg-border") })
683
+ /* @__PURE__ */ jsx2(
684
+ "div",
685
+ {
686
+ className: cn(
687
+ "w-7 h-7 rounded-full flex items-center justify-center font-bold text-xs shrink-0 transition-all duration-200",
688
+ currentStep === s ? "bg-primary text-primary-foreground ring-2 ring-primary/30 ring-offset-2 ring-offset-card shadow-sm" : currentStep > s ? "bg-primary text-primary-foreground" : "bg-muted border border-border text-muted-foreground"
689
+ ),
690
+ children: currentStep > s ? /* @__PURE__ */ jsx2(Check, { className: "h-3.5 w-3.5" }) : s
691
+ }
692
+ ),
693
+ /* @__PURE__ */ jsxs2(
694
+ "span",
695
+ {
696
+ className: cn(
697
+ "ml-2 sm:ml-3 font-bold text-sm tracking-tight hidden sm:inline transition-colors duration-200",
698
+ currentStep === s ? "text-foreground" : currentStep > s ? "text-primary" : "text-muted-foreground"
699
+ ),
700
+ children: [
701
+ s === 1 && "Environment",
702
+ s === 2 && "Resources",
703
+ s === 3 && "AI Agent"
704
+ ]
705
+ }
706
+ ),
707
+ s < 3 && /* @__PURE__ */ jsx2(
708
+ "div",
709
+ {
710
+ className: cn(
711
+ "w-4 sm:w-8 h-0.5 mx-2 sm:mx-4 rounded-full transition-colors duration-300",
712
+ currentStep > s ? "bg-primary" : "bg-border"
713
+ )
714
+ }
715
+ )
544
716
  ] }, s)) }),
545
717
  dc && isMultistep && /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between bg-card border border-border rounded-2xl px-4 py-3 shrink-0", children: [
546
718
  /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 text-sm", children: [
@@ -557,11 +729,11 @@ function ProvisioningWizard({
557
729
  setCpuCores(Math.min(4, cpuMax));
558
730
  setRamGB(Math.min(16, ramMax));
559
731
  setStorageGB(Math.min(128, storageMax));
560
- {
561
- const resetOptions = modelOptions ?? DEFAULT_MODEL_OPTIONS;
562
- const firstAvailable = resetOptions.find((o) => !o.disabled);
563
- setModelTier(firstAvailable?.value ?? DEFAULT_MODEL_TIER);
564
- }
732
+ const resetOptions = modelOptions ?? DEFAULT_MODEL_OPTIONS;
733
+ const firstAvailable = resetOptions.find(
734
+ (o) => !o.disabled
735
+ );
736
+ setModelTier(firstAvailable?.value ?? DEFAULT_MODEL_TIER);
565
737
  setSystemPrompt("");
566
738
  setName("");
567
739
  setGitUrl("");
@@ -570,6 +742,7 @@ function ProvisioningWizard({
570
742
  setBare(false);
571
743
  setStartupScriptIds([]);
572
744
  setActivePreset(null);
745
+ setPricingView("hourly");
573
746
  },
574
747
  className: "text-xs font-bold text-primary hover:text-primary/70 transition-colors",
575
748
  children: "Start from scratch"
@@ -599,10 +772,16 @@ function ProvisioningWizard({
599
772
  selectedEnv === env.id && /* @__PURE__ */ jsx2("div", { className: "absolute inset-0 bg-gradient-to-br from-primary/8 to-transparent pointer-events-none" }),
600
773
  /* @__PURE__ */ jsxs2("div", { className: "flex justify-between items-start mb-3 relative z-10", children: [
601
774
  /* @__PURE__ */ jsx2("div", { className: "w-10 h-10 rounded-full flex items-center justify-center bg-muted/50 border border-border shadow-inner", children: env.icon }),
602
- /* @__PURE__ */ jsx2("div", { className: cn(
603
- "w-5 h-5 rounded-full border-2 flex items-center justify-center transition-all duration-200",
604
- selectedEnv === env.id ? "border-primary bg-primary" : "border-border group-hover:border-primary/40"
605
- ), children: selectedEnv === env.id && /* @__PURE__ */ jsx2(Check, { className: "h-3 w-3 text-primary-foreground animate-in zoom-in duration-200" }) })
775
+ /* @__PURE__ */ jsx2(
776
+ "div",
777
+ {
778
+ className: cn(
779
+ "w-5 h-5 rounded-full border-2 flex items-center justify-center transition-all duration-200",
780
+ selectedEnv === env.id ? "border-primary bg-primary" : "border-border group-hover:border-primary/40"
781
+ ),
782
+ children: selectedEnv === env.id && /* @__PURE__ */ jsx2(Check, { className: "h-3 w-3 text-primary-foreground animate-in zoom-in duration-200" })
783
+ }
784
+ )
606
785
  ] }),
607
786
  /* @__PURE__ */ jsx2("h3", { className: "font-bold text-sm mb-0.5 text-foreground relative z-10", children: env.name }),
608
787
  /* @__PURE__ */ jsx2("p", { className: "text-xs text-muted-foreground leading-relaxed relative z-10", children: env.description })
@@ -632,14 +811,24 @@ function ProvisioningWizard({
632
811
  ),
633
812
  children: [
634
813
  p.locked && /* @__PURE__ */ jsx2("div", { className: "absolute -top-1.5 -right-1.5 bg-primary text-primary-foreground text-[9px] font-bold px-1.5 py-0.5 rounded-full uppercase tracking-wider", children: p.unlockLabel }),
635
- /* @__PURE__ */ jsx2("div", { className: cn("font-bold text-sm transition-colors duration-200", active ? "text-primary" : p.locked ? "text-muted-foreground" : "text-foreground"), children: p.name }),
814
+ /* @__PURE__ */ jsx2(
815
+ "div",
816
+ {
817
+ className: cn(
818
+ "font-bold text-sm transition-colors duration-200",
819
+ active ? "text-primary" : p.locked ? "text-muted-foreground" : "text-foreground"
820
+ ),
821
+ children: p.name
822
+ }
823
+ ),
636
824
  /* @__PURE__ */ jsxs2("div", { className: "text-xs text-muted-foreground mt-0.5 font-mono", children: [
637
825
  p.cpu,
638
826
  " vCPU",
639
827
  p.cpu === 1 ? "" : "s",
640
828
  " / ",
641
829
  p.ram,
642
- "GB / ",
830
+ "GB /",
831
+ " ",
643
832
  p.storage,
644
833
  "GB"
645
834
  ] })
@@ -650,43 +839,69 @@ function ProvisioningWizard({
650
839
  }) })
651
840
  ] }),
652
841
  /* @__PURE__ */ jsx2("div", { className: "space-y-6", children: [
653
- { label: "Compute Cores (CPU)", value: cpuCores, setter: setCpuCores, min: CPU_MIN, max: cpuMax, step: 0.5, unit: "vCPU" },
654
- { label: "Memory (RAM)", value: ramGB, setter: setRamGB, min: RAM_MIN, max: ramMax, step: 1, unit: "GB" },
655
- { label: "Ephemeral Storage", value: storageGB, setter: setStorageGB, min: STORAGE_MIN, max: storageMax, step: 8, unit: "GB" }
656
- ].map(({ label, value, setter, min, max, step: s, unit }) => {
657
- const displayUnit = unit === "vCPU" ? `${value} vCPU${value === 1 ? "" : "s"}` : `${value}${unit}`;
658
- return /* @__PURE__ */ jsxs2("div", { children: [
659
- /* @__PURE__ */ jsxs2("div", { className: "flex justify-between items-end border-b border-border pb-1.5 mb-2", children: [
660
- /* @__PURE__ */ jsx2("label", { className: "font-label text-xs font-bold uppercase tracking-widest text-muted-foreground", children: label }),
661
- /* @__PURE__ */ jsx2("span", { className: "text-xl font-bold text-foreground tracking-tight", children: displayUnit })
662
- ] }),
663
- /* @__PURE__ */ jsx2(
664
- "input",
665
- {
666
- type: "range",
667
- min,
668
- max,
669
- step: s,
670
- value,
671
- onChange: (e) => {
672
- setter(+e.target.value);
673
- setActivePreset(null);
674
- },
675
- className: "w-full h-2 rounded-full appearance-none cursor-pointer accent-primary [&::-webkit-slider-runnable-track]:bg-border [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:h-2 [&::-moz-range-track]:bg-border [&::-moz-range-track]:rounded-full [&::-moz-range-track]:h-2 [&::-webkit-slider-thumb]:bg-primary [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:h-5 [&::-webkit-slider-thumb]:w-5 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:-mt-[6px] [&::-webkit-slider-thumb]:shadow-md [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-primary-foreground [&::-webkit-slider-thumb]:transition-transform [&::-webkit-slider-thumb]:hover:scale-110"
676
- }
677
- ),
678
- /* @__PURE__ */ jsxs2("div", { className: "flex justify-between text-[10px] font-mono text-muted-foreground/60 mt-1", children: [
679
- /* @__PURE__ */ jsxs2("span", { children: [
680
- min,
681
- unit === "vCPU" ? min === 1 ? " vCPU" : " vCPUs" : unit
842
+ {
843
+ label: "Compute Cores (CPU)",
844
+ value: cpuCores,
845
+ setter: setCpuCores,
846
+ min: CPU_MIN,
847
+ max: cpuMax,
848
+ step: 0.5,
849
+ unit: "vCPU"
850
+ },
851
+ {
852
+ label: "Memory (RAM)",
853
+ value: ramGB,
854
+ setter: setRamGB,
855
+ min: RAM_MIN,
856
+ max: ramMax,
857
+ step: 1,
858
+ unit: "GB"
859
+ },
860
+ {
861
+ label: "Ephemeral Storage",
862
+ value: storageGB,
863
+ setter: setStorageGB,
864
+ min: STORAGE_MIN,
865
+ max: storageMax,
866
+ step: 8,
867
+ unit: "GB"
868
+ }
869
+ ].map(
870
+ ({ label, value, setter, min, max, step: s, unit }) => {
871
+ const displayUnit = unit === "vCPU" ? `${value} vCPU${value === 1 ? "" : "s"}` : `${value}${unit}`;
872
+ return /* @__PURE__ */ jsxs2("div", { children: [
873
+ /* @__PURE__ */ jsxs2("div", { className: "flex justify-between items-end border-b border-border pb-1.5 mb-2", children: [
874
+ /* @__PURE__ */ jsx2("label", { className: "font-label text-xs font-bold uppercase tracking-widest text-muted-foreground", children: label }),
875
+ /* @__PURE__ */ jsx2("span", { className: "text-xl font-bold text-foreground tracking-tight", children: displayUnit })
682
876
  ] }),
683
- /* @__PURE__ */ jsxs2("span", { children: [
684
- max,
685
- unit === "vCPU" ? max === 1 ? " vCPU" : " vCPUs" : unit
877
+ /* @__PURE__ */ jsx2(
878
+ "input",
879
+ {
880
+ type: "range",
881
+ min,
882
+ max,
883
+ step: s,
884
+ value,
885
+ onChange: (e) => {
886
+ setter(+e.target.value);
887
+ setActivePreset(null);
888
+ },
889
+ className: "w-full h-2 rounded-full appearance-none cursor-pointer accent-primary [&::-webkit-slider-runnable-track]:bg-border [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:h-2 [&::-moz-range-track]:bg-border [&::-moz-range-track]:rounded-full [&::-moz-range-track]:h-2 [&::-webkit-slider-thumb]:bg-primary [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:h-5 [&::-webkit-slider-thumb]:w-5 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:-mt-[6px] [&::-webkit-slider-thumb]:shadow-md [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-primary-foreground [&::-webkit-slider-thumb]:transition-transform [&::-webkit-slider-thumb]:hover:scale-110"
890
+ }
891
+ ),
892
+ /* @__PURE__ */ jsxs2("div", { className: "flex justify-between text-[10px] font-mono text-muted-foreground/60 mt-1", children: [
893
+ /* @__PURE__ */ jsxs2("span", { children: [
894
+ min,
895
+ unit === "vCPU" ? min === 1 ? " vCPU" : " vCPUs" : unit
896
+ ] }),
897
+ /* @__PURE__ */ jsxs2("span", { children: [
898
+ max,
899
+ unit === "vCPU" ? max === 1 ? " vCPU" : " vCPUs" : unit
900
+ ] })
686
901
  ] })
687
- ] })
688
- ] }, label);
689
- }) })
902
+ ] }, label);
903
+ }
904
+ ) })
690
905
  ] }) }),
691
906
  (!isMultistep || currentStep === 3) && /* @__PURE__ */ jsx2(React2.Fragment, { children: /* @__PURE__ */ jsxs2("section", { className: "bg-card border border-border rounded-[24px] p-6 shadow-2xl relative overflow-hidden animate-in fade-in slide-in-from-bottom-4 duration-300", children: [
692
907
  /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-3 mb-5", children: [
@@ -703,16 +918,18 @@ function ProvisioningWizard({
703
918
  onChange: (e) => setModelTier(e.target.value),
704
919
  disabled: modelOptions && modelOptions.filter((o) => !o.disabled).length === 0,
705
920
  className: "w-full bg-card border border-border rounded-xl h-12 px-4 font-bold text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent appearance-none disabled:opacity-50 disabled:cursor-not-allowed",
706
- children: (modelOptions ?? DEFAULT_MODEL_OPTIONS).map((option) => /* @__PURE__ */ jsx2(
707
- "option",
708
- {
709
- value: option.value,
710
- disabled: option.disabled,
711
- className: "bg-gray-900",
712
- children: option.label
713
- },
714
- option.value
715
- ))
921
+ children: (modelOptions ?? DEFAULT_MODEL_OPTIONS).map(
922
+ (option) => /* @__PURE__ */ jsx2(
923
+ "option",
924
+ {
925
+ value: option.value,
926
+ disabled: option.disabled,
927
+ className: "bg-gray-900",
928
+ children: option.label
929
+ },
930
+ option.value
931
+ )
932
+ )
716
933
  }
717
934
  ),
718
935
  modelOptions && modelOptions.length > 0 && modelOptions.every((o) => o.disabled) && /* @__PURE__ */ jsx2("p", { className: "text-xs text-muted-foreground mt-2", children: "All model options are currently disabled. Please upgrade your plan or contact support." })
@@ -766,12 +983,22 @@ function ProvisioningWizard({
766
983
  {
767
984
  value: driver,
768
985
  onChange: (e) => {
769
- if (VALID_DRIVERS.has(e.target.value)) setDriver(e.target.value);
986
+ if (VALID_DRIVERS.has(e.target.value))
987
+ setDriver(
988
+ e.target.value
989
+ );
770
990
  },
771
991
  className: "w-full bg-card border border-border rounded-xl h-12 px-4 font-bold text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent appearance-none",
772
992
  children: [
773
993
  /* @__PURE__ */ jsx2("option", { value: "docker", className: "bg-gray-900", children: "Docker container (Default)" }),
774
- /* @__PURE__ */ jsx2("option", { value: "firecracker", className: "bg-gray-900", children: "Firecracker microVM (Secure)" }),
994
+ /* @__PURE__ */ jsx2(
995
+ "option",
996
+ {
997
+ value: "firecracker",
998
+ className: "bg-gray-900",
999
+ children: "Firecracker microVM (Secure)"
1000
+ }
1001
+ ),
775
1002
  /* @__PURE__ */ jsx2("option", { value: "tangle", className: "bg-gray-900", children: "Tangle Distributed Node" })
776
1003
  ]
777
1004
  }
@@ -794,10 +1021,21 @@ function ProvisioningWizard({
794
1021
  /* @__PURE__ */ jsxs2("div", { children: [
795
1022
  /* @__PURE__ */ jsxs2("div", { className: "flex justify-between items-center mb-2", children: [
796
1023
  /* @__PURE__ */ jsx2("label", { className: "block font-label text-xs font-bold uppercase tracking-widest text-muted-foreground", children: "Environment Variables" }),
797
- /* @__PURE__ */ jsxs2("button", { type: "button", onClick: () => setEnvVars([...envVars, { key: "", value: "" }]), className: "flex items-center gap-1 text-xs text-primary hover:text-primary/70 transition-colors font-bold", children: [
798
- /* @__PURE__ */ jsx2(Plus, { className: "h-3 w-3" }),
799
- " Add Var"
800
- ] })
1024
+ /* @__PURE__ */ jsxs2(
1025
+ "button",
1026
+ {
1027
+ type: "button",
1028
+ onClick: () => setEnvVars([
1029
+ ...envVars,
1030
+ { key: "", value: "" }
1031
+ ]),
1032
+ className: "flex items-center gap-1 text-xs text-primary hover:text-primary/70 transition-colors font-bold",
1033
+ children: [
1034
+ /* @__PURE__ */ jsx2(Plus, { className: "h-3 w-3" }),
1035
+ " Add Var"
1036
+ ]
1037
+ }
1038
+ )
801
1039
  ] }),
802
1040
  /* @__PURE__ */ jsxs2("div", { className: "space-y-2", children: [
803
1041
  envVars.map((env, i) => /* @__PURE__ */ jsxs2("div", { className: "flex gap-2", children: [
@@ -806,7 +1044,11 @@ function ProvisioningWizard({
806
1044
  {
807
1045
  type: "text",
808
1046
  value: env.key,
809
- onChange: (e) => setEnvVars(envVars.map((v, idx) => idx === i ? { ...v, key: e.target.value } : v)),
1047
+ onChange: (e) => setEnvVars(
1048
+ envVars.map(
1049
+ (v, idx) => idx === i ? { ...v, key: e.target.value } : v
1050
+ )
1051
+ ),
810
1052
  className: "flex-1 bg-card border border-border rounded-xl h-10 px-3 font-mono text-sm text-foreground focus:outline-none focus:ring-1 focus:ring-primary placeholder:text-muted-foreground",
811
1053
  placeholder: "API_KEY"
812
1054
  }
@@ -816,12 +1058,26 @@ function ProvisioningWizard({
816
1058
  {
817
1059
  type: "password",
818
1060
  value: env.value,
819
- onChange: (e) => setEnvVars(envVars.map((v, idx) => idx === i ? { ...v, value: e.target.value } : v)),
1061
+ onChange: (e) => setEnvVars(
1062
+ envVars.map(
1063
+ (v, idx) => idx === i ? { ...v, value: e.target.value } : v
1064
+ )
1065
+ ),
820
1066
  className: "flex-[2] bg-card border border-border rounded-xl h-10 px-3 font-mono text-sm text-foreground focus:outline-none focus:ring-1 focus:ring-primary placeholder:text-muted-foreground",
821
1067
  placeholder: "sk-xxxxxxxxxxx"
822
1068
  }
823
1069
  ),
824
- /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => setEnvVars(envVars.filter((_, idx) => idx !== i)), className: "h-10 w-10 flex items-center justify-center shrink-0 rounded-xl bg-card border border-border text-red-400 hover:bg-red-500/10 hover:border-red-500/30 transition-colors", children: /* @__PURE__ */ jsx2(Trash2, { className: "h-4 w-4" }) })
1070
+ /* @__PURE__ */ jsx2(
1071
+ "button",
1072
+ {
1073
+ type: "button",
1074
+ onClick: () => setEnvVars(
1075
+ envVars.filter((_, idx) => idx !== i)
1076
+ ),
1077
+ className: "h-10 w-10 flex items-center justify-center shrink-0 rounded-xl bg-card border border-border text-red-400 hover:bg-red-500/10 hover:border-red-500/30 transition-colors",
1078
+ children: /* @__PURE__ */ jsx2(Trash2, { className: "h-4 w-4" })
1079
+ }
1080
+ )
825
1081
  ] }, i)),
826
1082
  envVars.length === 0 && /* @__PURE__ */ jsx2("div", { className: "text-center p-3 bg-card border border-border rounded-xl text-muted-foreground/60 text-sm italic", children: "No environment variables set" })
827
1083
  ] })
@@ -829,36 +1085,82 @@ function ProvisioningWizard({
829
1085
  availableScripts.length > 0 && /* @__PURE__ */ jsxs2("div", { children: [
830
1086
  /* @__PURE__ */ jsx2("div", { className: "text-xs font-bold uppercase tracking-widest text-muted-foreground mb-2", children: "Startup Scripts" }),
831
1087
  /* @__PURE__ */ jsx2("div", { className: "space-y-2", children: availableScripts.filter((s) => s.enabled).map((script) => {
832
- const selected = startupScriptIds.includes(script.id);
833
- return /* @__PURE__ */ jsxs2("label", { className: "flex items-start gap-3 cursor-pointer group rounded-lg border border-border p-3 transition-colors hover:border-primary/30", children: [
834
- /* @__PURE__ */ jsx2(
835
- "input",
836
- {
837
- type: "checkbox",
838
- checked: selected,
839
- onChange: () => setStartupScriptIds(
840
- (prev) => selected ? prev.filter((id) => id !== script.id) : [...prev, script.id]
1088
+ const selected = startupScriptIds.includes(
1089
+ script.id
1090
+ );
1091
+ return /* @__PURE__ */ jsxs2(
1092
+ "label",
1093
+ {
1094
+ className: "flex items-start gap-3 cursor-pointer group rounded-lg border border-border p-3 transition-colors hover:border-primary/30",
1095
+ children: [
1096
+ /* @__PURE__ */ jsx2(
1097
+ "input",
1098
+ {
1099
+ type: "checkbox",
1100
+ checked: selected,
1101
+ onChange: () => setStartupScriptIds(
1102
+ (prev) => selected ? prev.filter(
1103
+ (id) => id !== script.id
1104
+ ) : [...prev, script.id]
1105
+ ),
1106
+ className: "mt-0.5 h-4 w-4 rounded border-border text-primary focus:ring-primary/30"
1107
+ }
841
1108
  ),
842
- className: "mt-0.5 h-4 w-4 rounded border-border text-primary focus:ring-primary/30"
843
- }
844
- ),
845
- /* @__PURE__ */ jsxs2("div", { className: "flex-1 min-w-0", children: [
846
- /* @__PURE__ */ jsx2("div", { className: "text-sm font-medium text-foreground group-hover:text-primary transition-colors", children: script.name }),
847
- script.description && /* @__PURE__ */ jsx2("div", { className: "text-xs text-muted-foreground mt-0.5", children: script.description }),
848
- script.injectSecrets.length > 0 && /* @__PURE__ */ jsx2("div", { className: "flex flex-wrap gap-1 mt-1.5", children: script.injectSecrets.map((s) => /* @__PURE__ */ jsxs2("span", { className: "inline-flex items-center gap-0.5 rounded-full bg-muted px-2 py-0.5 text-[10px] text-muted-foreground", children: [
849
- /* @__PURE__ */ jsxs2("svg", { className: "h-2.5 w-2.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
850
- /* @__PURE__ */ jsx2("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }),
851
- /* @__PURE__ */ jsx2("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })
852
- ] }),
853
- s
854
- ] }, s)) })
855
- ] })
856
- ] }, script.id);
1109
+ /* @__PURE__ */ jsxs2("div", { className: "flex-1 min-w-0", children: [
1110
+ /* @__PURE__ */ jsx2("div", { className: "text-sm font-medium text-foreground group-hover:text-primary transition-colors", children: script.name }),
1111
+ script.description && /* @__PURE__ */ jsx2("div", { className: "text-xs text-muted-foreground mt-0.5", children: script.description }),
1112
+ script.injectSecrets.length > 0 && /* @__PURE__ */ jsx2("div", { className: "flex flex-wrap gap-1 mt-1.5", children: script.injectSecrets.map((s) => /* @__PURE__ */ jsxs2(
1113
+ "span",
1114
+ {
1115
+ className: "inline-flex items-center gap-0.5 rounded-full bg-muted px-2 py-0.5 text-[10px] text-muted-foreground",
1116
+ children: [
1117
+ /* @__PURE__ */ jsxs2(
1118
+ "svg",
1119
+ {
1120
+ className: "h-2.5 w-2.5",
1121
+ viewBox: "0 0 24 24",
1122
+ fill: "none",
1123
+ stroke: "currentColor",
1124
+ strokeWidth: "2",
1125
+ children: [
1126
+ /* @__PURE__ */ jsx2(
1127
+ "rect",
1128
+ {
1129
+ x: "3",
1130
+ y: "11",
1131
+ width: "18",
1132
+ height: "11",
1133
+ rx: "2",
1134
+ ry: "2"
1135
+ }
1136
+ ),
1137
+ /* @__PURE__ */ jsx2("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })
1138
+ ]
1139
+ }
1140
+ ),
1141
+ s
1142
+ ]
1143
+ },
1144
+ s
1145
+ )) })
1146
+ ] })
1147
+ ]
1148
+ },
1149
+ script.id
1150
+ );
857
1151
  }) })
858
1152
  ] }),
859
1153
  /* @__PURE__ */ jsx2("div", { className: "pt-2 border-t border-border", children: /* @__PURE__ */ jsxs2("label", { className: "flex items-center gap-3 cursor-pointer group", children: [
860
1154
  /* @__PURE__ */ jsxs2("div", { className: "relative flex items-center justify-center shrink-0", children: [
861
- /* @__PURE__ */ jsx2("input", { type: "checkbox", className: "sr-only peer", checked: bare, onChange: (e) => setBare(e.target.checked) }),
1155
+ /* @__PURE__ */ jsx2(
1156
+ "input",
1157
+ {
1158
+ type: "checkbox",
1159
+ className: "sr-only peer",
1160
+ checked: bare,
1161
+ onChange: (e) => setBare(e.target.checked)
1162
+ }
1163
+ ),
862
1164
  /* @__PURE__ */ jsx2("div", { className: "w-10 h-6 bg-muted peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-primary hover:bg-muted/80 transition-colors" })
863
1165
  ] }),
864
1166
  /* @__PURE__ */ jsxs2("div", { children: [
@@ -877,57 +1179,96 @@ function ProvisioningWizard({
877
1179
  /* @__PURE__ */ jsx2("div", { className: "hidden" }),
878
1180
  /* @__PURE__ */ jsxs2("div", { className: "flex justify-between items-center mb-4 relative z-10", children: [
879
1181
  /* @__PURE__ */ jsx2("span", { className: "font-label text-xs font-bold uppercase tracking-widest text-muted-foreground", children: "Run Cost" }),
880
- /* @__PURE__ */ jsx2("div", { className: "h-7 w-7 rounded-full bg-muted/30 flex items-center justify-center border border-border", children: /* @__PURE__ */ jsx2(Info, { className: "h-3.5 w-3.5 text-primary" }) })
1182
+ /* @__PURE__ */ jsxs2(
1183
+ "div",
1184
+ {
1185
+ role: "group",
1186
+ "aria-label": "Pricing view",
1187
+ className: "inline-flex items-center rounded-full border border-border bg-muted/50 p-0.5",
1188
+ children: [
1189
+ /* @__PURE__ */ jsx2(
1190
+ "button",
1191
+ {
1192
+ type: "button",
1193
+ "aria-pressed": pricingView === "hourly",
1194
+ onClick: () => setPricingView("hourly"),
1195
+ className: cn(
1196
+ "rounded-full px-2.5 py-0.5 text-[10px] font-bold transition-all",
1197
+ pricingView === "hourly" ? "bg-card text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
1198
+ ),
1199
+ children: "Per Hour"
1200
+ }
1201
+ ),
1202
+ /* @__PURE__ */ jsx2(
1203
+ "button",
1204
+ {
1205
+ type: "button",
1206
+ "aria-pressed": pricingView === "perSecond",
1207
+ onClick: () => setPricingView("perSecond"),
1208
+ className: cn(
1209
+ "rounded-full px-2.5 py-0.5 text-[10px] font-bold transition-all",
1210
+ pricingView === "perSecond" ? "bg-card text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
1211
+ ),
1212
+ children: "Per Second"
1213
+ }
1214
+ )
1215
+ ]
1216
+ }
1217
+ )
881
1218
  ] }),
882
1219
  /* @__PURE__ */ jsxs2("div", { className: "flex items-baseline gap-2 mb-5 relative z-10", children: [
883
- /* @__PURE__ */ jsxs2("span", { className: "text-4xl font-black text-foreground tracking-tighter animate-in fade-in duration-200", children: [
884
- "$",
885
- hourCost
886
- ] }, hourCost),
887
- /* @__PURE__ */ jsx2("span", { className: "text-muted-foreground text-sm font-bold", children: "/ hour" })
888
- ] }),
889
- (() => {
890
- const computeCost = cpuCores * effectivePricingRates.cpuPerHr;
891
- const memoryCost = ramGB * effectivePricingRates.ramPerGbHr;
892
- const storageCost = storageGB * effectivePricingRates.diskPerGbHr;
893
- const lineSum = computeCost + memoryCost + storageCost;
894
- const floor = effectivePricingRates.minChargePerHr ?? 0;
895
- const floorApplies = floor > lineSum;
896
- return /* @__PURE__ */ jsxs2("div", { className: "space-y-2 relative z-10 bg-card border border-border rounded-xl p-3", children: [
897
- /* @__PURE__ */ jsxs2("div", { className: "flex justify-between text-xs font-mono tracking-widest text-muted-foreground", children: [
898
- /* @__PURE__ */ jsx2("span", { children: "COMPUTE" }),
899
- /* @__PURE__ */ jsxs2("span", { className: "text-foreground", children: [
900
- "$",
901
- computeCost.toFixed(2),
902
- "/h"
903
- ] })
904
- ] }),
905
- /* @__PURE__ */ jsxs2("div", { className: "flex justify-between text-xs font-mono tracking-widest text-muted-foreground", children: [
906
- /* @__PURE__ */ jsx2("span", { children: "MEMORY" }),
907
- /* @__PURE__ */ jsxs2("span", { className: "text-foreground/80", children: [
908
- "$",
909
- memoryCost.toFixed(2),
910
- "/h"
911
- ] })
912
- ] }),
913
- /* @__PURE__ */ jsxs2("div", { className: "flex justify-between text-xs font-mono tracking-widest text-muted-foreground", children: [
914
- /* @__PURE__ */ jsx2("span", { children: "STORAGE" }),
915
- /* @__PURE__ */ jsxs2("span", { className: "text-foreground/80", children: [
916
- "$",
917
- storageCost.toFixed(2),
918
- "/h"
919
- ] })
920
- ] }),
921
- floorApplies && /* @__PURE__ */ jsxs2("div", { className: "flex justify-between text-xs font-mono tracking-widest text-primary border-t border-border pt-2", children: [
922
- /* @__PURE__ */ jsx2("span", { children: "MIN CHARGE" }),
923
- /* @__PURE__ */ jsxs2("span", { children: [
1220
+ /* @__PURE__ */ jsxs2(
1221
+ "span",
1222
+ {
1223
+ className: cn(
1224
+ "font-black text-foreground tracking-tighter animate-in fade-in duration-200",
1225
+ pricingView === "hourly" ? "text-4xl" : "text-2xl"
1226
+ ),
1227
+ children: [
924
1228
  "$",
925
- (floor - lineSum).toFixed(2),
926
- "/h"
927
- ] })
1229
+ displayValue
1230
+ ]
1231
+ },
1232
+ pricingView
1233
+ ),
1234
+ /* @__PURE__ */ jsx2("span", { className: "text-muted-foreground text-sm font-bold", children: pricingSuffix })
1235
+ ] }),
1236
+ /* @__PURE__ */ jsxs2("div", { className: "space-y-2 relative z-10 bg-card border border-border rounded-xl p-3", children: [
1237
+ /* @__PURE__ */ jsxs2("div", { className: "flex justify-between text-xs font-mono tracking-widest text-muted-foreground", children: [
1238
+ /* @__PURE__ */ jsx2("span", { children: "COMPUTE" }),
1239
+ /* @__PURE__ */ jsxs2("span", { className: "text-foreground", children: [
1240
+ "$",
1241
+ fmtRate(hourlyCostBreakdown.compute),
1242
+ rateSuffix
1243
+ ] })
1244
+ ] }),
1245
+ /* @__PURE__ */ jsxs2("div", { className: "flex justify-between text-xs font-mono tracking-widest text-muted-foreground", children: [
1246
+ /* @__PURE__ */ jsx2("span", { children: "MEMORY" }),
1247
+ /* @__PURE__ */ jsxs2("span", { className: "text-foreground/80", children: [
1248
+ "$",
1249
+ fmtRate(hourlyCostBreakdown.memory),
1250
+ rateSuffix
1251
+ ] })
1252
+ ] }),
1253
+ /* @__PURE__ */ jsxs2("div", { className: "flex justify-between text-xs font-mono tracking-widest text-muted-foreground", children: [
1254
+ /* @__PURE__ */ jsx2("span", { children: "STORAGE" }),
1255
+ /* @__PURE__ */ jsxs2("span", { className: "text-foreground/80", children: [
1256
+ "$",
1257
+ fmtRate(hourlyCostBreakdown.storage),
1258
+ rateSuffix
928
1259
  ] })
929
- ] });
930
- })()
1260
+ ] }),
1261
+ hourlyCostBreakdown.floorApplies && /* @__PURE__ */ jsxs2("div", { className: "flex justify-between text-xs font-mono tracking-widest text-primary border-t border-border pt-2", children: [
1262
+ /* @__PURE__ */ jsx2("span", { children: "MIN CHARGE" }),
1263
+ /* @__PURE__ */ jsxs2("span", { children: [
1264
+ "$",
1265
+ fmtRate(
1266
+ hourlyCostBreakdown.floor - hourlyCostBreakdown.lineSum
1267
+ ),
1268
+ rateSuffix
1269
+ ] })
1270
+ ] })
1271
+ ] })
931
1272
  ] }),
932
1273
  deployError && /* @__PURE__ */ jsxs2("div", { className: "rounded-xl border border-destructive/30 bg-destructive/10 p-3 flex items-center gap-2", children: [
933
1274
  /* @__PURE__ */ jsx2(Info, { className: "h-4 w-4 text-destructive shrink-0" }),
@@ -941,7 +1282,8 @@ function ProvisioningWizard({
941
1282
  onClick: () => setCurrentStep((s) => s + 1),
942
1283
  className: "w-full relative overflow-hidden h-12 bg-primary text-primary-foreground font-extrabold text-sm rounded-2xl hover:brightness-110 transition-all active:scale-[0.98] shadow-md",
943
1284
  children: [
944
- "Continue to ",
1285
+ "Continue to",
1286
+ " ",
945
1287
  currentStep === 1 ? "Resources" : "Agent Config"
946
1288
  ]
947
1289
  }
@@ -1763,9 +2105,9 @@ function ProfileDetailDialog({
1763
2105
 
1764
2106
  // src/pages/secrets-page.tsx
1765
2107
  import * as React5 from "react";
1766
- import { Lock, Plus as Plus3, Trash2 as Trash23, Eye, EyeOff, AlertCircle as AlertCircle2, Key, Shield, CheckCircle } from "lucide-react";
2108
+ import { Lock, Plus as Plus3, Trash2 as Trash23, Eye, EyeOff, AlertCircle as AlertCircle2, Key, Shield, CheckCircle, Users, ArrowRight } from "lucide-react";
1767
2109
  import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1768
- function SecretsPage({ apiClient, className }) {
2110
+ function SecretsPage({ apiClient, className, teamSecretsHint }) {
1769
2111
  const [secrets, setSecrets] = React5.useState([]);
1770
2112
  const [loading, setLoading] = React5.useState(true);
1771
2113
  const [error, setError] = React5.useState(null);
@@ -1856,6 +2198,29 @@ function SecretsPage({ apiClient, className }) {
1856
2198
  }
1857
2199
  )
1858
2200
  ] }),
2201
+ teamSecretsHint && /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-3 rounded-lg border border-border bg-[var(--accent-surface-soft)]/40 px-4 py-3", children: [
2202
+ /* @__PURE__ */ jsx5(Users, { className: "h-5 w-5 shrink-0 text-[var(--accent-text)]", "aria-hidden": "true" }),
2203
+ /* @__PURE__ */ jsxs5("div", { className: "flex-1 text-sm", children: [
2204
+ /* @__PURE__ */ jsx5("p", { className: "font-semibold text-foreground", children: "Setting up secrets for a team?" }),
2205
+ /* @__PURE__ */ jsxs5("p", { className: "mt-0.5 text-muted-foreground text-xs", children: [
2206
+ "Secrets here are ",
2207
+ /* @__PURE__ */ jsx5("strong", { children: "personal" }),
2208
+ " \u2014 only available in sandboxes you create. To share credentials with teammates, configure them on the team page instead."
2209
+ ] })
2210
+ ] }),
2211
+ /* @__PURE__ */ jsxs5(
2212
+ "button",
2213
+ {
2214
+ type: "button",
2215
+ onClick: teamSecretsHint.onNavigate,
2216
+ className: "inline-flex shrink-0 items-center gap-1 rounded-md border border-border bg-card px-3 py-1.5 text-xs font-semibold text-foreground hover:bg-muted transition-colors",
2217
+ children: [
2218
+ teamSecretsHint.label ?? "Manage team secrets",
2219
+ /* @__PURE__ */ jsx5(ArrowRight, { className: "h-3 w-3", "aria-hidden": "true" })
2220
+ ]
2221
+ }
2222
+ )
2223
+ ] }),
1859
2224
  /* @__PURE__ */ jsxs5("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-4", children: [
1860
2225
  /* @__PURE__ */ jsxs5("div", { className: "rounded-lg border border-border bg-card p-5 shadow-[var(--shadow-card)]", children: [
1861
2226
  /* @__PURE__ */ jsx5("p", { className: "text-[10px] font-bold uppercase tracking-widest text-muted-foreground", children: "Total Active Secrets" }),