@soba-so/react 0.0.17 → 0.0.18
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/ModelPicker.d.ts +31 -0
- package/dist/index.d.ts +10 -2
- package/dist/index.mjs +360 -9
- package/dist/styles.css +352 -1
- package/dist/tier.d.ts +35 -0
- package/dist/types.d.ts +106 -0
- package/dist/useCheckout.d.ts +41 -0
- package/dist/useCompute.d.ts +91 -0
- package/dist/useConnectButton.d.ts +75 -0
- package/dist/useConnectNudge.d.ts +204 -0
- package/dist/useModel.d.ts +93 -0
- package/dist/useOpenSobaConnect.d.ts +1 -1
- package/package.json +9 -8
package/dist/styles.css
CHANGED
|
@@ -197,6 +197,10 @@ a.sc-btn {
|
|
|
197
197
|
color: var(--sc-muted, #6b6b73);
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
+
.sc-tone-absent {
|
|
201
|
+
color: var(--sc-faint, #a1a1aa);
|
|
202
|
+
}
|
|
203
|
+
|
|
200
204
|
.sc-error {
|
|
201
205
|
color: var(--sc-warn, #b06f14);
|
|
202
206
|
font-size: var(--sc-fs-body);
|
|
@@ -263,6 +267,13 @@ a.sc-btn {
|
|
|
263
267
|
padding: 0 2px 3px 12px;
|
|
264
268
|
}
|
|
265
269
|
|
|
270
|
+
.sc-cap-acts {
|
|
271
|
+
flex: none;
|
|
272
|
+
display: flex;
|
|
273
|
+
align-items: center;
|
|
274
|
+
gap: 4px;
|
|
275
|
+
}
|
|
276
|
+
|
|
266
277
|
.sc-group-title {
|
|
267
278
|
flex: 1;
|
|
268
279
|
min-width: 0;
|
|
@@ -402,6 +413,71 @@ a.sc-btn {
|
|
|
402
413
|
color: var(--sc-line-2, #dcdce0);
|
|
403
414
|
}
|
|
404
415
|
|
|
416
|
+
.sc-mrow-btn {
|
|
417
|
+
width: calc(100% + 4px);
|
|
418
|
+
margin-left: -4px;
|
|
419
|
+
padding-left: 4px;
|
|
420
|
+
border: 0;
|
|
421
|
+
border-radius: 10px;
|
|
422
|
+
background: transparent;
|
|
423
|
+
color: inherit;
|
|
424
|
+
font: inherit;
|
|
425
|
+
text-align: left;
|
|
426
|
+
cursor: pointer;
|
|
427
|
+
transition: background-color 120ms ease;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
.sc-mrow-btn:hover {
|
|
431
|
+
background: var(--sc-tray-sunk, #f6f6f7);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.sc-mrow-btn:hover .sc-mbadge {
|
|
435
|
+
box-shadow: 0 0 0 2.5px var(--sc-tray-sunk, #f6f6f7);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
.sc-chev {
|
|
439
|
+
flex: none;
|
|
440
|
+
width: 14px;
|
|
441
|
+
height: 14px;
|
|
442
|
+
color: var(--sc-muted, #6b6b73);
|
|
443
|
+
transition: transform 120ms ease;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
.sc-chev-open {
|
|
447
|
+
transform: rotate(90deg);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.sc-rrow {
|
|
451
|
+
display: flex;
|
|
452
|
+
align-items: flex-start;
|
|
453
|
+
gap: 10px;
|
|
454
|
+
padding: 6px 12px 6px 0;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
.sc-rrow .sc-runtime-tile {
|
|
458
|
+
margin-top: 1px;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
.sc-rtop {
|
|
462
|
+
display: flex;
|
|
463
|
+
align-items: baseline;
|
|
464
|
+
gap: 8px;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
.sc-rtop .sc-averdict {
|
|
468
|
+
font-variant-numeric: tabular-nums;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
.sc-rstep {
|
|
472
|
+
display: -webkit-box;
|
|
473
|
+
overflow: hidden;
|
|
474
|
+
-webkit-box-orient: vertical;
|
|
475
|
+
-webkit-line-clamp: 2;
|
|
476
|
+
font-size: var(--sc-fs-label);
|
|
477
|
+
line-height: 1.4;
|
|
478
|
+
color: var(--sc-muted, #6b6b73);
|
|
479
|
+
}
|
|
480
|
+
|
|
405
481
|
.sc-arow {
|
|
406
482
|
display: flex;
|
|
407
483
|
align-items: center;
|
|
@@ -436,6 +512,10 @@ a.sc-btn {
|
|
|
436
512
|
font-size: var(--sc-fs-small);
|
|
437
513
|
}
|
|
438
514
|
|
|
515
|
+
.sc-aname-absent {
|
|
516
|
+
color: var(--sc-muted, #6b6b73);
|
|
517
|
+
}
|
|
518
|
+
|
|
439
519
|
.sc-aversion {
|
|
440
520
|
color: var(--sc-muted, #6b6b73);
|
|
441
521
|
}
|
|
@@ -449,6 +529,18 @@ a.sc-btn {
|
|
|
449
529
|
color: var(--sc-muted, #6b6b73);
|
|
450
530
|
}
|
|
451
531
|
|
|
532
|
+
.sc-sglyph {
|
|
533
|
+
flex: none;
|
|
534
|
+
width: 11px;
|
|
535
|
+
height: 11px;
|
|
536
|
+
color: var(--sc-ok, #22a06b);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
.sc-aserving {
|
|
540
|
+
margin-left: 5px;
|
|
541
|
+
font-variant-numeric: tabular-nums;
|
|
542
|
+
}
|
|
543
|
+
|
|
452
544
|
.sc-orow {
|
|
453
545
|
display: flex;
|
|
454
546
|
align-items: center;
|
|
@@ -517,6 +609,11 @@ a.sc-btn {
|
|
|
517
609
|
background: var(--sc-tray-sunk, #f6f6f7);
|
|
518
610
|
}
|
|
519
611
|
|
|
612
|
+
.sc-open-app {
|
|
613
|
+
color: inherit;
|
|
614
|
+
text-decoration: none;
|
|
615
|
+
}
|
|
616
|
+
|
|
520
617
|
.sc-hrow {
|
|
521
618
|
padding-bottom: 2px;
|
|
522
619
|
}
|
|
@@ -529,6 +626,246 @@ a.sc-btn {
|
|
|
529
626
|
color: var(--sc-muted, #6b6b73);
|
|
530
627
|
}
|
|
531
628
|
|
|
629
|
+
.sc-runs-to {
|
|
630
|
+
display: inline-flex;
|
|
631
|
+
flex: none;
|
|
632
|
+
align-items: center;
|
|
633
|
+
gap: 2px;
|
|
634
|
+
min-width: 0;
|
|
635
|
+
max-width: 62%;
|
|
636
|
+
font-size: var(--sc-fs-label);
|
|
637
|
+
color: var(--sc-muted, #6b6b73);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
.sc-runs-cap {
|
|
641
|
+
flex: none;
|
|
642
|
+
white-space: nowrap;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
.sc-runs-fixed,
|
|
646
|
+
.sc-runs-btn {
|
|
647
|
+
display: inline-flex;
|
|
648
|
+
align-items: center;
|
|
649
|
+
gap: 5px;
|
|
650
|
+
min-width: 0;
|
|
651
|
+
height: 24px;
|
|
652
|
+
padding: 0 6px;
|
|
653
|
+
font-size: var(--sc-fs-label);
|
|
654
|
+
font-weight: 500;
|
|
655
|
+
color: var(--sc-text-2, #3f3f46);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
.sc-runs-btn {
|
|
659
|
+
padding-right: 4px;
|
|
660
|
+
border: 0;
|
|
661
|
+
border-radius: var(--sc-r-pill, 999px);
|
|
662
|
+
background: transparent;
|
|
663
|
+
font-family: inherit;
|
|
664
|
+
cursor: pointer;
|
|
665
|
+
transition: background-color 120ms ease, color 120ms ease;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
.sc-runs-btn:hover:not(:disabled),
|
|
669
|
+
.sc-runs-btn[aria-expanded="true"] {
|
|
670
|
+
background: var(--sc-tray-card, #ffffff);
|
|
671
|
+
color: var(--sc-text, #1a1a1c);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
.sc-runs-btn:disabled {
|
|
675
|
+
opacity: 0.5;
|
|
676
|
+
cursor: default;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
.sc-runs-glyph {
|
|
680
|
+
flex: none;
|
|
681
|
+
width: 12px;
|
|
682
|
+
height: 12px;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
.sc-runs-mark {
|
|
686
|
+
display: inline-grid;
|
|
687
|
+
flex: none;
|
|
688
|
+
place-items: center;
|
|
689
|
+
width: 14px;
|
|
690
|
+
height: 14px;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
.sc-runs-mark > * {
|
|
694
|
+
max-width: 14px;
|
|
695
|
+
max-height: 14px;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
.sc-runs-label {
|
|
699
|
+
min-width: 0;
|
|
700
|
+
overflow: hidden;
|
|
701
|
+
text-overflow: ellipsis;
|
|
702
|
+
white-space: nowrap;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
.sc-runs-btn .sc-chev {
|
|
706
|
+
width: 11px;
|
|
707
|
+
height: 11px;
|
|
708
|
+
color: var(--sc-faint, #a1a1aa);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
.sc-menu {
|
|
712
|
+
position: fixed;
|
|
713
|
+
inset: auto;
|
|
714
|
+
z-index: 2147483647;
|
|
715
|
+
width: 248px;
|
|
716
|
+
margin: 0;
|
|
717
|
+
padding: 4px;
|
|
718
|
+
border: 1px solid var(--sc-line, #e9e9eb);
|
|
719
|
+
border-radius: 12px;
|
|
720
|
+
background: var(--sc-tray-card, #ffffff);
|
|
721
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.06);
|
|
722
|
+
color: var(--sc-text, #1a1a1c);
|
|
723
|
+
|
|
724
|
+
max-height: 60vh;
|
|
725
|
+
overflow-y: auto;
|
|
726
|
+
overscroll-behavior: contain;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
.sc-menu-item {
|
|
730
|
+
display: flex;
|
|
731
|
+
align-items: center;
|
|
732
|
+
gap: 10px;
|
|
733
|
+
width: 100%;
|
|
734
|
+
min-height: 34px;
|
|
735
|
+
padding: 5px 8px;
|
|
736
|
+
border: 0;
|
|
737
|
+
border-radius: 8px;
|
|
738
|
+
background: transparent;
|
|
739
|
+
font: inherit;
|
|
740
|
+
font-size: var(--sc-fs-small);
|
|
741
|
+
color: inherit;
|
|
742
|
+
text-align: left;
|
|
743
|
+
cursor: pointer;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
.sc-menu-item:hover,
|
|
747
|
+
.sc-menu-item:focus-visible {
|
|
748
|
+
background: var(--sc-tray-sunk, #f6f6f7);
|
|
749
|
+
outline: none;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
.sc-menu-text {
|
|
753
|
+
display: flex;
|
|
754
|
+
flex: 1;
|
|
755
|
+
min-width: 0;
|
|
756
|
+
flex-direction: column;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
.sc-menu-label {
|
|
760
|
+
overflow: hidden;
|
|
761
|
+
text-overflow: ellipsis;
|
|
762
|
+
white-space: nowrap;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
.sc-menu-note {
|
|
766
|
+
font-size: var(--sc-fs-label);
|
|
767
|
+
line-height: 1.4;
|
|
768
|
+
color: var(--sc-muted, #6b6b73);
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
.sc-menu-check {
|
|
772
|
+
flex: none;
|
|
773
|
+
width: 15px;
|
|
774
|
+
height: 15px;
|
|
775
|
+
color: var(--sc-text-2, #3f3f46);
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
.sc-menu-sep {
|
|
779
|
+
height: 1px;
|
|
780
|
+
margin: 4px 6px;
|
|
781
|
+
background: var(--sc-line, #e9e9eb);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
.sc-menu-head {
|
|
785
|
+
margin: 6px 6px 2px;
|
|
786
|
+
padding-top: 7px;
|
|
787
|
+
border-top: 1px solid var(--sc-line, #e9e9eb);
|
|
788
|
+
font-size: var(--sc-fs-label);
|
|
789
|
+
font-weight: 500;
|
|
790
|
+
color: var(--sc-muted, #6b6b73);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
.sc-menu > .sc-menu-head:first-child {
|
|
794
|
+
margin-top: 2px;
|
|
795
|
+
padding-top: 0;
|
|
796
|
+
border-top: 0;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
.sc-mp {
|
|
800
|
+
display: inline-flex;
|
|
801
|
+
align-items: center;
|
|
802
|
+
gap: 2px;
|
|
803
|
+
max-width: 100%;
|
|
804
|
+
min-width: 0;
|
|
805
|
+
font-size: var(--sc-fs-label);
|
|
806
|
+
color: var(--sc-muted, #6b6b73);
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
.sc-mp-cap {
|
|
810
|
+
flex: none;
|
|
811
|
+
white-space: nowrap;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
.sc-mp-btn {
|
|
815
|
+
display: inline-flex;
|
|
816
|
+
align-items: center;
|
|
817
|
+
gap: 5px;
|
|
818
|
+
min-width: 0;
|
|
819
|
+
height: 26px;
|
|
820
|
+
padding: 0 5px 0 7px;
|
|
821
|
+
border: 0;
|
|
822
|
+
border-radius: var(--sc-r-pill, 999px);
|
|
823
|
+
background: transparent;
|
|
824
|
+
font: inherit;
|
|
825
|
+
font-size: var(--sc-fs-label);
|
|
826
|
+
font-weight: 500;
|
|
827
|
+
color: var(--sc-text-2, #3f3f46);
|
|
828
|
+
cursor: pointer;
|
|
829
|
+
transition: background-color 120ms ease, color 120ms ease;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
.sc-mp-btn:hover:not(:disabled),
|
|
833
|
+
.sc-mp-btn[aria-expanded="true"] {
|
|
834
|
+
background: var(--sc-raised, #f6f6f7);
|
|
835
|
+
color: var(--sc-text, #1a1a1c);
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
.sc-mp-btn:disabled {
|
|
839
|
+
opacity: 0.5;
|
|
840
|
+
cursor: default;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
.sc-mp-mark {
|
|
844
|
+
display: inline-grid;
|
|
845
|
+
flex: none;
|
|
846
|
+
place-items: center;
|
|
847
|
+
width: 13px;
|
|
848
|
+
height: 13px;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
.sc-mp-glyph {
|
|
852
|
+
max-width: 13px;
|
|
853
|
+
max-height: 13px;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
.sc-mp-label {
|
|
857
|
+
min-width: 0;
|
|
858
|
+
overflow: hidden;
|
|
859
|
+
text-overflow: ellipsis;
|
|
860
|
+
white-space: nowrap;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
.sc-mp-btn .sc-chev {
|
|
864
|
+
width: 11px;
|
|
865
|
+
height: 11px;
|
|
866
|
+
color: var(--sc-faint, #a1a1aa);
|
|
867
|
+
}
|
|
868
|
+
|
|
532
869
|
.sc-row-act {
|
|
533
870
|
flex: none;
|
|
534
871
|
padding: 3px 9px;
|
|
@@ -605,7 +942,9 @@ a.sc-btn {
|
|
|
605
942
|
.sc-spin {
|
|
606
943
|
animation: none;
|
|
607
944
|
}
|
|
608
|
-
.sc-pair
|
|
945
|
+
.sc-pair,
|
|
946
|
+
.sc-mrow-btn,
|
|
947
|
+
.sc-chev {
|
|
609
948
|
transition: none;
|
|
610
949
|
}
|
|
611
950
|
}
|
|
@@ -680,6 +1019,15 @@ a.sc-btn {
|
|
|
680
1019
|
--sc-shadow-2: 0 1px 2px rgb(0 0 0 / 40%), 0 8px 24px -12px rgb(0 0 0 / 64%);
|
|
681
1020
|
}
|
|
682
1021
|
|
|
1022
|
+
.soba-connect.sc-inline {
|
|
1023
|
+
display: inline-flex;
|
|
1024
|
+
width: auto;
|
|
1025
|
+
max-width: 100%;
|
|
1026
|
+
margin-inline: 0;
|
|
1027
|
+
|
|
1028
|
+
line-height: 1;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
683
1031
|
.soba-connect.sc-fill {
|
|
684
1032
|
max-width: none;
|
|
685
1033
|
|
|
@@ -1520,9 +1868,12 @@ a.sc-btn {
|
|
|
1520
1868
|
.sc-step-lead:focus-visible,
|
|
1521
1869
|
.sc-step-links a:focus-visible,
|
|
1522
1870
|
.sc-alt-link:focus-visible,
|
|
1871
|
+
.sc-runs-btn:focus-visible,
|
|
1872
|
+
.sc-mp-btn:focus-visible,
|
|
1523
1873
|
.sc-row-act:focus-visible,
|
|
1524
1874
|
.sc-disc:focus-visible,
|
|
1525
1875
|
.sc-pair:focus-visible,
|
|
1876
|
+
.sc-mrow-btn:focus-visible,
|
|
1526
1877
|
.sc-input:focus-visible,
|
|
1527
1878
|
.sc-modal-close:focus-visible {
|
|
1528
1879
|
outline: 2px solid var(--sc-accent, #18181b);
|
package/dist/tier.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { CostClass } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* WHERE THE ANSWER CAME FROM, IN WORDS — a pure function, because there is no
|
|
4
|
+
* state in it.
|
|
5
|
+
*
|
|
6
|
+
* `status` carries the cost class BEFORE any output, which is the whole reason
|
|
7
|
+
* an app renders it: a run that quietly fell back from somebody's laptop to a
|
|
8
|
+
* metered API says so on the screen rather than in a bill. So every surface
|
|
9
|
+
* that shows a run shows this, and every one of them wrote the map itself.
|
|
10
|
+
*
|
|
11
|
+
* THIS SHIPPED BECAUSE THE COPIES DISAGREED. Four of them, across our own
|
|
12
|
+
* examples and the `create-soba` template: `user-hardware` was "your own
|
|
13
|
+
* hardware", "your own computer" and "your own machine" depending on which page
|
|
14
|
+
* you were on. That is a glossary problem, not a styling one — the names of the
|
|
15
|
+
* five economics this product is about should not depend on the file.
|
|
16
|
+
*
|
|
17
|
+
* And three of the copies had the same bug, which is the part worth having a
|
|
18
|
+
* test for: they were written as an if-chain ending in `return "a frontier
|
|
19
|
+
* model we paid for"`, so `user-api-key` — somebody's OWN key, costing the app
|
|
20
|
+
* nothing — was reported to them as the app's most expensive supply.
|
|
21
|
+
*
|
|
22
|
+
* A BARE NOUN PHRASE, so the sentence stays the app's. "running on …" while it
|
|
23
|
+
* is, "ran on …" afterwards, or the words on their own beside an icon; a
|
|
24
|
+
* function that returned a whole sentence would have to pick a tense, and the
|
|
25
|
+
* one surface that shows this both during and after a run needs both.
|
|
26
|
+
*
|
|
27
|
+
* `null` for a run that has not said yet — the value every page holds before
|
|
28
|
+
* the first `status` — so `{tierLabel(tier)}` is a complete integration.
|
|
29
|
+
*
|
|
30
|
+
* Not the same words as a PLAN's compute line, deliberately: `usePlans()`
|
|
31
|
+
* describes supply a plan is allowed to reach ("your own AI subscription", a
|
|
32
|
+
* thing you might go and connect), and this describes where one run actually
|
|
33
|
+
* landed. Same five classes, two different claims.
|
|
34
|
+
*/
|
|
35
|
+
export declare function tierLabel(tier: CostClass | string | null | undefined): string | null;
|
package/dist/types.d.ts
CHANGED
|
@@ -51,6 +51,85 @@ export interface Machine {
|
|
|
51
51
|
always_on: boolean;
|
|
52
52
|
last_seen_at: string | null;
|
|
53
53
|
runtimes: Runtime[];
|
|
54
|
+
/**
|
|
55
|
+
* WHICH AGENT GETS THIS APP'S RUNS, and whose decision that is.
|
|
56
|
+
*
|
|
57
|
+
* `requested_runtime` is what the app named on its latest run here: set, the
|
|
58
|
+
* app has chosen and the person's pick does not apply. Null, the app does not
|
|
59
|
+
* mind, and `preferred_runtime` is the person's pick — or null for the
|
|
60
|
+
* machine's own first-found default. Both optional: a server older than the
|
|
61
|
+
* fields sends neither, which reads as "nothing picked".
|
|
62
|
+
*
|
|
63
|
+
* MISSING FROM THIS COPY UNTIL `useModel()` NEEDED THEM, and the parity guard
|
|
64
|
+
* could not catch it. `test/types-parity.ts` compares this interface against
|
|
65
|
+
* the panel's both ways, and an interface WITHOUT an optional property still
|
|
66
|
+
* extends one that has it — in both directions. So the two shapes drifted by
|
|
67
|
+
* exactly the amount the guard is blind to, and the fields arrived at the
|
|
68
|
+
* browser on every poll with nothing here to read them. The same note is on
|
|
69
|
+
* `Runtime.quarantined`, which drifted the same way first.
|
|
70
|
+
*/
|
|
71
|
+
preferred_runtime?: string | null;
|
|
72
|
+
requested_runtime?: string | null;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* WHAT PRESSING "OPEN SOBA" LOOKED LIKE — mirrored from the panel for the
|
|
76
|
+
* reason the shapes above it are, and it is the one that was caught by the
|
|
77
|
+
* published artefact rather than by a review: `useOpenSobaConnect.d.ts` shipped
|
|
78
|
+
* importing this type out of the private panel package, which no customer can
|
|
79
|
+
* install. The build has a check for exactly that, and the name in it was
|
|
80
|
+
* spelled `@soba` rather than `@soba-so`, so it had never once fired.
|
|
81
|
+
*
|
|
82
|
+
* (Written without the specifier spelled out, because the check greps the
|
|
83
|
+
* emitted declarations and prose in them is still text it has to read.)
|
|
84
|
+
*
|
|
85
|
+
* No browser will tell a page whether a scheme handler exists. The only
|
|
86
|
+
* observable consequence of one is that something else takes the foreground.
|
|
87
|
+
*/
|
|
88
|
+
export type Launch =
|
|
89
|
+
/** Something took the foreground. Almost certainly the app. */
|
|
90
|
+
"opened"
|
|
91
|
+
/** Nothing did, within the window. Probably not installed. */
|
|
92
|
+
| "absent"
|
|
93
|
+
/** The tab was already in the background, so the signal means nothing. */
|
|
94
|
+
| "unknown";
|
|
95
|
+
/**
|
|
96
|
+
* A MODEL THIS PERSON COULD BE ANSWERED BY — mirrored from the panel, like
|
|
97
|
+
* `Machine` above it, so no published declaration names a private package.
|
|
98
|
+
*
|
|
99
|
+
* Derived from what they have connected rather than configured anywhere: see
|
|
100
|
+
* `useModel()`, and `models.ts` in the panel for the three facts it reconciles.
|
|
101
|
+
*/
|
|
102
|
+
export type ModelOptionKind = "auto" | "size" | "named";
|
|
103
|
+
export interface ModelOption {
|
|
104
|
+
/** `auto`, `small`, `large`, or `<runtime>/<model>`. */
|
|
105
|
+
id: string;
|
|
106
|
+
kind: ModelOptionKind;
|
|
107
|
+
/** `Automatic`, `Fast`, `Opus`, `llama3.2:3b`. */
|
|
108
|
+
label: string;
|
|
109
|
+
note?: string;
|
|
110
|
+
/** What goes on the run as `model`. */
|
|
111
|
+
model: string;
|
|
112
|
+
/**
|
|
113
|
+
* What goes on the run as `runtime`, on a named model only.
|
|
114
|
+
*
|
|
115
|
+
* THE TWO TRAVEL TOGETHER OR NOT AT ALL. The broker applies the person's
|
|
116
|
+
* preferred agent only to a run whose model is blank or a size, so `opus`
|
|
117
|
+
* sent on its own is handed to whichever agent the broker finds first — and
|
|
118
|
+
* on somebody running Codex that is a run that dies on a model name Codex
|
|
119
|
+
* has never heard of. `ModelView.run` is the pair; spread it.
|
|
120
|
+
*/
|
|
121
|
+
runtime?: string;
|
|
122
|
+
/** The agent's own name, which is the heading this model sits under. */
|
|
123
|
+
runtimeName?: string;
|
|
124
|
+
/** Who pays for a run served here. */
|
|
125
|
+
costClass?: string;
|
|
126
|
+
/** The machine advertising it, when exactly one of theirs does. */
|
|
127
|
+
machine?: string;
|
|
128
|
+
}
|
|
129
|
+
export interface ModelGroup {
|
|
130
|
+
/** Null for the first group — Automatic and the sizes head nothing. */
|
|
131
|
+
heading: string | null;
|
|
132
|
+
options: ModelOption[];
|
|
54
133
|
}
|
|
55
134
|
/** A device code someone is being asked to approve. */
|
|
56
135
|
export interface PendingCode {
|
|
@@ -201,6 +280,33 @@ export interface AgentEvent {
|
|
|
201
280
|
usage?: RunUsage;
|
|
202
281
|
/** Which economics is serving this run, announced before any output. */
|
|
203
282
|
tier?: CostClass;
|
|
283
|
+
/** On a `status` from a terminal run: what the agent said at the end of a turn. */
|
|
284
|
+
turn?: {
|
|
285
|
+
text: string;
|
|
286
|
+
};
|
|
287
|
+
/** On `done` / `error`: the runtime's conversation id, for a follow-up run. */
|
|
288
|
+
session?: string;
|
|
289
|
+
/** On a tool `status`: what the tool was pointed at — a path, a command. */
|
|
290
|
+
toolInput?: string;
|
|
291
|
+
/** On a `status` from a run in a git checkout: where its branch stands. */
|
|
292
|
+
git?: {
|
|
293
|
+
branch: string;
|
|
294
|
+
base: string;
|
|
295
|
+
head: string;
|
|
296
|
+
ahead: number;
|
|
297
|
+
behind: number;
|
|
298
|
+
files: {
|
|
299
|
+
path: string;
|
|
300
|
+
status: "A" | "M" | "D" | "R";
|
|
301
|
+
added: number;
|
|
302
|
+
removed: number;
|
|
303
|
+
}[];
|
|
304
|
+
commits: {
|
|
305
|
+
sha: string;
|
|
306
|
+
subject: string;
|
|
307
|
+
}[];
|
|
308
|
+
dirty: boolean;
|
|
309
|
+
};
|
|
204
310
|
/** On an `error`: a stable code to branch on, e.g. `run_too_long`. */
|
|
205
311
|
reason?: string;
|
|
206
312
|
/** On an `error`: false when starting the same run again will end the same way. */
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Plan } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* THE BUY BUTTON'S BEHAVIOUR — the headless half of `<SobaCheckout />`.
|
|
4
|
+
*
|
|
5
|
+
* It creates a Checkout Session and navigates. It does not take a card number,
|
|
6
|
+
* it never sees one, and **it grants nothing**: the entitlement is written by
|
|
7
|
+
* Stripe's webhook when the money actually moves. That split is the whole
|
|
8
|
+
* security model, and it is the reason this is worth a hook rather than a
|
|
9
|
+
* snippet — an app that wrote its own and granted the plan on redirect would
|
|
10
|
+
* hand one to anybody who could reach the URL and close the tab.
|
|
11
|
+
*
|
|
12
|
+
* The payment lands on the APP's own Stripe account with Soba's fee taken off
|
|
13
|
+
* the top, so their user sees their name on the statement. Soba is the rail
|
|
14
|
+
* underneath.
|
|
15
|
+
*/
|
|
16
|
+
export interface CheckoutView {
|
|
17
|
+
/** "Subscribe for $20/month", or "Opening…" while it is. The default label,
|
|
18
|
+
* because a button that says "Subscribe" makes the reader look back up. */
|
|
19
|
+
label: string;
|
|
20
|
+
/** A session is being created, or the navigation is already under way. */
|
|
21
|
+
busy: boolean;
|
|
22
|
+
/** Why it did not open, or null. Cleared on the next attempt. */
|
|
23
|
+
error: string | null;
|
|
24
|
+
/** Create the session and go. Resolves only when it did NOT navigate. */
|
|
25
|
+
buy: () => Promise<void>;
|
|
26
|
+
/** The URL, for an app that would rather navigate itself — a native wrapper,
|
|
27
|
+
* or a flow that wants to open it in a new tab. `buy()` is the usual one. */
|
|
28
|
+
session: () => Promise<string>;
|
|
29
|
+
}
|
|
30
|
+
export interface UseCheckoutOptions {
|
|
31
|
+
/** The plan to buy. A free one is refused by the endpoint — `usePlans()`
|
|
32
|
+
* routes free and priced plans to the right place on its own. */
|
|
33
|
+
plan: Plan;
|
|
34
|
+
/** Where Stripe returns on success. Defaults to the page they are on, which
|
|
35
|
+
* is right for a settings page and wrong for a landing page. */
|
|
36
|
+
successUrl?: string;
|
|
37
|
+
cancelUrl?: string;
|
|
38
|
+
/** Override the words. */
|
|
39
|
+
label?: string;
|
|
40
|
+
}
|
|
41
|
+
export declare function useCheckout({ plan, successUrl, cancelUrl, label, }: UseCheckoutOptions): CheckoutView;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { Machine, Runtime } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* WHAT THIS PERSON HAS CONNECTED, IN WORDS — the headless half of
|
|
4
|
+
* `<ComputeStatus />` and `<ConnectCompute />`.
|
|
5
|
+
*
|
|
6
|
+
* `useSoba().compute` is already the raw list, and it is not enough to draw
|
|
7
|
+
* from. Every surface that tried re-derived the same five judgements, and the
|
|
8
|
+
* two below are ones this repo has got wrong in production:
|
|
9
|
+
*
|
|
10
|
+
* **"Nothing connected yet" is a claim about somebody's ACCOUNT**, and it is
|
|
11
|
+
* only true once the account has been read. While the first poll is in flight,
|
|
12
|
+
* or after it has failed, the honest answer is that we do not know — and saying
|
|
13
|
+
* the empty thing instead tells a person with a paired laptop that it has
|
|
14
|
+
* vanished, during an outage they cannot see and did not cause. `view` is that
|
|
15
|
+
* decision, made once. Two of our own components drew this list and only one of
|
|
16
|
+
* them knew the rule.
|
|
17
|
+
*
|
|
18
|
+
* **Machines in hand beat both flags.** The provider polls, so `loading` and
|
|
19
|
+
* `error` come back around; a poll that fails on its fourth round must not
|
|
20
|
+
* blank a list somebody is already reading.
|
|
21
|
+
*
|
|
22
|
+
* The rest is naming: a hostname is not what anybody calls the laptop on their
|
|
23
|
+
* desk, `darwin · arm64` is what a kernel calls itself, and a runtime's
|
|
24
|
+
* `authenticated` is tri-state all the way to the screen — "could not tell" is
|
|
25
|
+
* not "signed out", and rendering it as one tells somebody their working setup
|
|
26
|
+
* is broken.
|
|
27
|
+
*/
|
|
28
|
+
export interface ComputeRuntime {
|
|
29
|
+
runtime: Runtime;
|
|
30
|
+
/** "Claude Code". */
|
|
31
|
+
name: string;
|
|
32
|
+
/** Signed in, signed out, or we could not tell — with the tone to draw it
|
|
33
|
+
* in. Never collapse `unknown` into `warn`. */
|
|
34
|
+
auth: {
|
|
35
|
+
tone: "ok" | "warn" | "unknown";
|
|
36
|
+
text: string;
|
|
37
|
+
};
|
|
38
|
+
/** It arrived on a machine that was already paired, so it waits to be let in
|
|
39
|
+
* and serves nothing until somebody says so. */
|
|
40
|
+
quarantined: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface ComputeMachine {
|
|
43
|
+
machine: Machine;
|
|
44
|
+
/** What to call it: the name they gave it, else a tidied hostname. */
|
|
45
|
+
name: string;
|
|
46
|
+
/** One word plus a tone, for a dot. Agrees with the panel's own badge. */
|
|
47
|
+
state: {
|
|
48
|
+
tone: "ok" | "busy" | "off";
|
|
49
|
+
word: string;
|
|
50
|
+
};
|
|
51
|
+
/** The sentence version — "serving 2 of 4" — for where there is room. */
|
|
52
|
+
status: {
|
|
53
|
+
tone: "ok" | "busy" | "off";
|
|
54
|
+
text: string;
|
|
55
|
+
};
|
|
56
|
+
/** "MacBook · Apple silicon", or null when the worker reported nothing. */
|
|
57
|
+
hardware: string | null;
|
|
58
|
+
/** "3 days ago", or null while it is here. */
|
|
59
|
+
lastSeen: string | null;
|
|
60
|
+
/** The agents a person may send runs to: let in, and never the shell. */
|
|
61
|
+
runtimes: ComputeRuntime[];
|
|
62
|
+
/** Which agent this app's next run on it goes to, and whose decision that
|
|
63
|
+
* was — the app's, the person's, or the machine's own first-found default. */
|
|
64
|
+
runsOn: {
|
|
65
|
+
by: "app" | "you" | "default";
|
|
66
|
+
name: string | null;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
export interface ComputeView {
|
|
70
|
+
/**
|
|
71
|
+
* WHAT TO DRAW, decided once instead of by each surface. `empty` is a claim
|
|
72
|
+
* about the account and is only reached once one has actually been read.
|
|
73
|
+
*/
|
|
74
|
+
view: "loading" | "error" | "empty" | "machines";
|
|
75
|
+
/** Every machine, named and worded, best-present first. */
|
|
76
|
+
machines: ComputeMachine[];
|
|
77
|
+
/** The one the panel is about: serving beats awake beats asleep, and within a
|
|
78
|
+
* state the one heard from most recently. Null with nothing connected. */
|
|
79
|
+
primary: ComputeMachine | null;
|
|
80
|
+
/** Something paired. It may still be asleep — see `online`. */
|
|
81
|
+
connected: boolean;
|
|
82
|
+
/** Something of theirs could serve a run right now. */
|
|
83
|
+
online: boolean;
|
|
84
|
+
/** Paired and not reachable: the state an app goes silent in unless it says
|
|
85
|
+
* something. `<ConnectNudge />`'s `stalled` reason is this one. */
|
|
86
|
+
stalled: ComputeMachine | null;
|
|
87
|
+
loading: boolean;
|
|
88
|
+
error: Error | null;
|
|
89
|
+
refresh: () => Promise<void>;
|
|
90
|
+
}
|
|
91
|
+
export declare function useCompute(): ComputeView;
|