@stigmer/react 0.2.2 → 0.3.0

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 (178) hide show
  1. package/composer/ComposerToolbar.d.ts +5 -1
  2. package/composer/ComposerToolbar.d.ts.map +1 -1
  3. package/composer/ComposerToolbar.js +6 -3
  4. package/composer/ComposerToolbar.js.map +1 -1
  5. package/composer/SessionComposer.d.ts +17 -1
  6. package/composer/SessionComposer.d.ts.map +1 -1
  7. package/composer/SessionComposer.js +32 -35
  8. package/composer/SessionComposer.js.map +1 -1
  9. package/execution/MessageEntry.d.ts +3 -1
  10. package/execution/MessageEntry.d.ts.map +1 -1
  11. package/execution/MessageEntry.js +30 -1
  12. package/execution/MessageEntry.js.map +1 -1
  13. package/github/index.d.ts +1 -1
  14. package/github/index.d.ts.map +1 -1
  15. package/github/index.js.map +1 -1
  16. package/github/useGitHubConnection.d.ts +70 -1
  17. package/github/useGitHubConnection.d.ts.map +1 -1
  18. package/github/useGitHubConnection.js +99 -20
  19. package/github/useGitHubConnection.js.map +1 -1
  20. package/identity-provider/IdentityProviderWizard.d.ts.map +1 -1
  21. package/identity-provider/IdentityProviderWizard.js +19 -3
  22. package/identity-provider/IdentityProviderWizard.js.map +1 -1
  23. package/index.d.ts +4 -4
  24. package/index.d.ts.map +1 -1
  25. package/index.js +2 -2
  26. package/index.js.map +1 -1
  27. package/models/HarnessSelector.d.ts +41 -0
  28. package/models/HarnessSelector.d.ts.map +1 -0
  29. package/models/HarnessSelector.js +74 -0
  30. package/models/HarnessSelector.js.map +1 -0
  31. package/models/ModelSelector.d.ts +26 -16
  32. package/models/ModelSelector.d.ts.map +1 -1
  33. package/models/ModelSelector.js +128 -48
  34. package/models/ModelSelector.js.map +1 -1
  35. package/models/__tests__/HarnessSelector.test.d.ts +2 -0
  36. package/models/__tests__/HarnessSelector.test.d.ts.map +1 -0
  37. package/models/__tests__/HarnessSelector.test.js +160 -0
  38. package/models/__tests__/HarnessSelector.test.js.map +1 -0
  39. package/models/__tests__/harness.test.d.ts +2 -0
  40. package/models/__tests__/harness.test.d.ts.map +1 -0
  41. package/models/__tests__/harness.test.js +50 -0
  42. package/models/__tests__/harness.test.js.map +1 -0
  43. package/models/__tests__/useModelRegistry.test.d.ts +2 -0
  44. package/models/__tests__/useModelRegistry.test.d.ts.map +1 -0
  45. package/models/__tests__/useModelRegistry.test.js +148 -0
  46. package/models/__tests__/useModelRegistry.test.js.map +1 -0
  47. package/models/harness.d.ts +21 -0
  48. package/models/harness.d.ts.map +1 -0
  49. package/models/harness.js +34 -0
  50. package/models/harness.js.map +1 -0
  51. package/models/index.d.ts +7 -2
  52. package/models/index.d.ts.map +1 -1
  53. package/models/index.js +3 -1
  54. package/models/index.js.map +1 -1
  55. package/models/registry.d.ts +53 -13
  56. package/models/registry.d.ts.map +1 -1
  57. package/models/registry.js +51 -40
  58. package/models/registry.js.map +1 -1
  59. package/models/useModelRegistry.d.ts +39 -19
  60. package/models/useModelRegistry.d.ts.map +1 -1
  61. package/models/useModelRegistry.js +45 -23
  62. package/models/useModelRegistry.js.map +1 -1
  63. package/organization/OrgProfilePanel.d.ts.map +1 -1
  64. package/organization/OrgProfilePanel.js +23 -2
  65. package/organization/OrgProfilePanel.js.map +1 -1
  66. package/package.json +4 -4
  67. package/runner/RunnerFileBrowser.d.ts +11 -1
  68. package/runner/RunnerFileBrowser.d.ts.map +1 -1
  69. package/runner/RunnerFileBrowser.js +70 -7
  70. package/runner/RunnerFileBrowser.js.map +1 -1
  71. package/runner/RunnerListPanel.js +2 -1
  72. package/runner/RunnerListPanel.js.map +1 -1
  73. package/runner/WorkspaceRunnerSelector.d.ts +36 -0
  74. package/runner/WorkspaceRunnerSelector.d.ts.map +1 -0
  75. package/runner/WorkspaceRunnerSelector.js +63 -0
  76. package/runner/WorkspaceRunnerSelector.js.map +1 -0
  77. package/runner/__tests__/phase.test.js +6 -2
  78. package/runner/__tests__/phase.test.js.map +1 -1
  79. package/runner/index.d.ts +2 -0
  80. package/runner/index.d.ts.map +1 -1
  81. package/runner/index.js +1 -0
  82. package/runner/index.js.map +1 -1
  83. package/runner/phase.d.ts +9 -7
  84. package/runner/phase.d.ts.map +1 -1
  85. package/runner/phase.js +18 -12
  86. package/runner/phase.js.map +1 -1
  87. package/runner/useRunnerFileBrowser.d.ts.map +1 -1
  88. package/runner/useRunnerFileBrowser.js +26 -2
  89. package/runner/useRunnerFileBrowser.js.map +1 -1
  90. package/session/__tests__/useCreateSession.test.d.ts +2 -0
  91. package/session/__tests__/useCreateSession.test.d.ts.map +1 -0
  92. package/session/__tests__/useCreateSession.test.js +232 -0
  93. package/session/__tests__/useCreateSession.test.js.map +1 -0
  94. package/session/__tests__/useNewSessionFlow.test.d.ts +2 -0
  95. package/session/__tests__/useNewSessionFlow.test.d.ts.map +1 -0
  96. package/session/__tests__/useNewSessionFlow.test.js +199 -0
  97. package/session/__tests__/useNewSessionFlow.test.js.map +1 -0
  98. package/session/__tests__/useSessionConversation.test.js +37 -0
  99. package/session/__tests__/useSessionConversation.test.js.map +1 -1
  100. package/session/index.d.ts +1 -1
  101. package/session/index.d.ts.map +1 -1
  102. package/session/useCreateSession.d.ts +8 -0
  103. package/session/useCreateSession.d.ts.map +1 -1
  104. package/session/useCreateSession.js +2 -0
  105. package/session/useCreateSession.js.map +1 -1
  106. package/session/useNewSessionFlow.d.ts +6 -1
  107. package/session/useNewSessionFlow.d.ts.map +1 -1
  108. package/session/useNewSessionFlow.js +34 -8
  109. package/session/useNewSessionFlow.js.map +1 -1
  110. package/session/usePersistedModel.d.ts +16 -1
  111. package/session/usePersistedModel.d.ts.map +1 -1
  112. package/session/usePersistedModel.js +15 -6
  113. package/session/usePersistedModel.js.map +1 -1
  114. package/session/useSessionConversation.d.ts.map +1 -1
  115. package/session/useSessionConversation.js +6 -1
  116. package/session/useSessionConversation.js.map +1 -1
  117. package/session/useSessionPageFlow.d.ts +11 -0
  118. package/session/useSessionPageFlow.d.ts.map +1 -1
  119. package/session/useSessionPageFlow.js +11 -2
  120. package/session/useSessionPageFlow.js.map +1 -1
  121. package/settings/MembersSection.d.ts.map +1 -1
  122. package/settings/MembersSection.js +7 -2
  123. package/settings/MembersSection.js.map +1 -1
  124. package/src/composer/ComposerToolbar.tsx +24 -1
  125. package/src/composer/SessionComposer.tsx +81 -44
  126. package/src/execution/MessageEntry.tsx +134 -1
  127. package/src/github/index.ts +1 -0
  128. package/src/github/useGitHubConnection.ts +162 -22
  129. package/src/identity-provider/IdentityProviderWizard.tsx +112 -3
  130. package/src/index.ts +16 -1
  131. package/src/models/HarnessSelector.tsx +130 -0
  132. package/src/models/ModelSelector.tsx +285 -81
  133. package/src/models/__tests__/HarnessSelector.test.tsx +190 -0
  134. package/src/models/__tests__/harness.test.ts +66 -0
  135. package/src/models/__tests__/useModelRegistry.test.tsx +209 -0
  136. package/src/models/harness.ts +45 -0
  137. package/src/models/index.ts +7 -2
  138. package/src/models/registry.ts +122 -50
  139. package/src/models/useModelRegistry.ts +74 -24
  140. package/src/organization/OrgProfilePanel.tsx +98 -0
  141. package/src/runner/RunnerFileBrowser.tsx +227 -8
  142. package/src/runner/RunnerListPanel.tsx +13 -5
  143. package/src/runner/WorkspaceRunnerSelector.tsx +180 -0
  144. package/src/runner/__tests__/phase.test.ts +6 -2
  145. package/src/runner/index.ts +3 -0
  146. package/src/runner/phase.ts +18 -12
  147. package/src/runner/useRunnerFileBrowser.ts +39 -3
  148. package/src/session/__tests__/useCreateSession.test.tsx +296 -0
  149. package/src/session/__tests__/useNewSessionFlow.test.tsx +258 -0
  150. package/src/session/__tests__/useSessionConversation.test.tsx +53 -0
  151. package/src/session/index.ts +1 -1
  152. package/src/session/useCreateSession.ts +9 -0
  153. package/src/session/useNewSessionFlow.ts +46 -9
  154. package/src/session/usePersistedModel.ts +30 -6
  155. package/src/session/useSessionConversation.ts +6 -1
  156. package/src/session/useSessionPageFlow.ts +26 -2
  157. package/src/settings/MembersSection.tsx +23 -1
  158. package/src/workspace/WorkspaceEditor.tsx +176 -126
  159. package/src/workspace/index.ts +5 -0
  160. package/src/workspace/useRecentWorkspaces.ts +162 -0
  161. package/src/workspace/useWorkspaceEntries.ts +13 -0
  162. package/styles.css +1 -1
  163. package/workspace/WorkspaceEditor.d.ts +25 -22
  164. package/workspace/WorkspaceEditor.d.ts.map +1 -1
  165. package/workspace/WorkspaceEditor.js +64 -43
  166. package/workspace/WorkspaceEditor.js.map +1 -1
  167. package/workspace/index.d.ts +2 -0
  168. package/workspace/index.d.ts.map +1 -1
  169. package/workspace/index.js +1 -0
  170. package/workspace/index.js.map +1 -1
  171. package/workspace/useRecentWorkspaces.d.ts +31 -0
  172. package/workspace/useRecentWorkspaces.d.ts.map +1 -0
  173. package/workspace/useRecentWorkspaces.js +117 -0
  174. package/workspace/useRecentWorkspaces.js.map +1 -0
  175. package/workspace/useWorkspaceEntries.d.ts +8 -0
  176. package/workspace/useWorkspaceEntries.d.ts.map +1 -1
  177. package/workspace/useWorkspaceEntries.js +4 -0
  178. package/workspace/useWorkspaceEntries.js.map +1 -1
@@ -26,7 +26,7 @@ export interface IdentityProviderWizardProps {
26
26
  readonly className?: string;
27
27
  }
28
28
 
29
- type WizardStep = "pick" | "configure" | "review";
29
+ type WizardStep = "pick" | "configure" | "review" | "success";
30
30
 
31
31
  /**
32
32
  * Multi-step wizard for creating a new identity provider.
@@ -88,6 +88,9 @@ export function IdentityProviderWizard({
88
88
  const [autoGrantRole, setAutoGrantRole] = useState<IamRole>(IamRole.iam_role_unspecified);
89
89
  const [tenantOrgClaim, setTenantOrgClaim] = useState("");
90
90
 
91
+ // Success step
92
+ const [createdIdp, setCreatedIdp] = useState<IdentityProvider | null>(null);
93
+
91
94
  // -- Step transitions ------------------------------------------------
92
95
 
93
96
  const handlePickProvider = useCallback((selected: ProviderPreset) => {
@@ -186,7 +189,8 @@ export function IdentityProviderWizard({
186
189
  }),
187
190
  }),
188
191
  });
189
- onCreated?.(idp);
192
+ setCreatedIdp(idp);
193
+ setStep("success");
190
194
  } catch {
191
195
  // error state is managed by useCreateIdentityProvider
192
196
  }
@@ -194,7 +198,7 @@ export function IdentityProviderWizard({
194
198
  [
195
199
  name, org, jwksUri, issuers, audience, userinfoEndpoint,
196
200
  isSso, oidcClientId, autoProvision, autoGrant, autoGrantRole,
197
- tenantOrgClaim, create, clearError, onCreated,
201
+ tenantOrgClaim, create, clearError,
198
202
  ],
199
203
  );
200
204
 
@@ -267,6 +271,18 @@ export function IdentityProviderWizard({
267
271
  onCancel={onCancel}
268
272
  />
269
273
  )}
274
+
275
+ {step === "success" && createdIdp && (
276
+ <SuccessStep
277
+ identityProvider={createdIdp}
278
+ org={org}
279
+ isSso={isSso}
280
+ autoProvision={autoProvision}
281
+ autoGrant={autoGrant}
282
+ autoGrantRole={autoGrantRole}
283
+ onDone={() => onCreated?.(createdIdp)}
284
+ />
285
+ )}
270
286
  </div>
271
287
  );
272
288
  }
@@ -279,6 +295,7 @@ const STEPS: { key: WizardStep; label: string }[] = [
279
295
  { key: "pick", label: "Provider" },
280
296
  { key: "configure", label: "Configure" },
281
297
  { key: "review", label: "Review" },
298
+ { key: "success", label: "Done" },
282
299
  ];
283
300
 
284
301
  function StepIndicator({ current }: { current: WizardStep }) {
@@ -608,6 +625,98 @@ function ReviewStep({
608
625
  );
609
626
  }
610
627
 
628
+ // ---------------------------------------------------------------------------
629
+ // Success step (step 4)
630
+ // ---------------------------------------------------------------------------
631
+
632
+ function SuccessStep({
633
+ identityProvider,
634
+ org,
635
+ isSso,
636
+ autoProvision,
637
+ autoGrant,
638
+ autoGrantRole,
639
+ onDone,
640
+ }: {
641
+ identityProvider: IdentityProvider;
642
+ org: string;
643
+ isSso: boolean;
644
+ autoProvision: boolean;
645
+ autoGrant: boolean;
646
+ autoGrantRole: IamRole;
647
+ onDone: () => void;
648
+ }) {
649
+ const displayName =
650
+ identityProvider.spec?.displayName ||
651
+ identityProvider.metadata?.name ||
652
+ "Identity provider";
653
+
654
+ const roleName =
655
+ autoGrantRole !== IamRole.iam_role_unspecified
656
+ ? IamRole[autoGrantRole]
657
+ : "viewer";
658
+
659
+ return (
660
+ <div className="space-y-4">
661
+ <div className="rounded-md border border-primary/30 bg-primary-subtle px-3 py-2.5">
662
+ <p className="text-xs font-medium text-foreground">
663
+ {displayName} created successfully
664
+ </p>
665
+ </div>
666
+
667
+ <div className="space-y-2">
668
+ <p className="text-xs font-medium text-foreground">What happens next</p>
669
+
670
+ {isSso ? (
671
+ <p className="text-[0.65rem] text-muted-foreground">
672
+ Users can sign in via SSO at{" "}
673
+ <span className="font-mono text-foreground">
674
+ /login?org={org}
675
+ </span>
676
+ . Accounts are auto-provisioned and granted the{" "}
677
+ <span className="font-medium text-foreground">viewer</span> role on
678
+ this organization.
679
+ </p>
680
+ ) : autoProvision && autoGrant ? (
681
+ <p className="text-[0.65rem] text-muted-foreground">
682
+ Users authenticating with JWTs from this provider will be
683
+ automatically provisioned and granted the{" "}
684
+ <span className="font-medium text-foreground">{roleName}</span> role
685
+ on this organization. No additional setup is required.
686
+ </p>
687
+ ) : autoProvision ? (
688
+ <p className="text-[0.65rem] text-muted-foreground">
689
+ Accounts are auto-provisioned on first authentication, but no
690
+ organization role is granted automatically. Use the Members page to
691
+ grant access.
692
+ </p>
693
+ ) : (
694
+ <p className="text-[0.65rem] text-muted-foreground">
695
+ The trust relationship is configured. Accounts must be created
696
+ manually before users can authenticate.
697
+ </p>
698
+ )}
699
+
700
+ <p className="text-[0.65rem] text-muted-foreground">
701
+ To verify the setup, have a user authenticate with a JWT from this
702
+ provider and confirm they can access the organization&apos;s resources.
703
+ </p>
704
+ </div>
705
+
706
+ <button
707
+ type="button"
708
+ onClick={onDone}
709
+ className={cn(
710
+ "inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium",
711
+ "bg-primary text-primary-foreground hover:bg-primary-hover",
712
+ )}
713
+ >
714
+ Done
715
+ </button>
716
+ </div>
717
+ );
718
+ }
719
+
611
720
  // ---------------------------------------------------------------------------
612
721
  // Shared primitives
613
722
  // ---------------------------------------------------------------------------
package/src/index.ts CHANGED
@@ -18,19 +18,32 @@ export {
18
18
  export { type DeploymentMode, isResourceAvailable, ApiResourceKind } from "@stigmer/sdk";
19
19
  export { CloudFeatureNotice, type CloudFeatureNoticeProps } from "./internal/CloudFeatureNotice";
20
20
 
21
- // Models — data hook, styled component, and registry data
21
+ // Models — data hook, styled components, and registry data
22
22
  export {
23
23
  MODEL_REGISTRY,
24
24
  DEFAULT_MODEL_ID,
25
+ DEFAULT_CURSOR_MODEL_ID,
26
+ DISABLED_PROVIDERS,
27
+ modelKey,
28
+ parseModelKey,
25
29
  useModelRegistry,
26
30
  ModelSelector,
31
+ HarnessSelector,
32
+ DEFAULT_HARNESS,
33
+ HARNESS_LABELS,
34
+ toProtoHarness,
35
+ fromProtoHarness,
27
36
  } from "./models";
28
37
  export type {
29
38
  ModelInfo,
39
+ ParsedModelKey,
30
40
  Provider,
31
41
  CostTier,
32
42
  UseModelRegistryReturn,
43
+ UseModelRegistryOptions,
33
44
  ModelSelectorProps,
45
+ HarnessSelectorProps,
46
+ HarnessOption,
34
47
  } from "./models";
35
48
 
36
49
  // Workspace — behavior hooks and styled components
@@ -92,6 +105,7 @@ export type {
92
105
  UseNewSessionFlowReturn,
93
106
  UseSessionPageFlowOptions,
94
107
  UseSessionPageFlowReturn,
108
+ UsePersistedModelOptions,
95
109
  UsePersistedModelReturn,
96
110
  UseEditSessionPrepReturn,
97
111
  DraftResourceType,
@@ -315,6 +329,7 @@ export {
315
329
  export type {
316
330
  GitHubUser,
317
331
  GitHubConnectOptions,
332
+ UseGitHubConnectionConfig,
318
333
  UseGitHubConnectionReturn,
319
334
  GitHubRepo,
320
335
  GitHubBranch,
@@ -0,0 +1,130 @@
1
+ "use client";
2
+
3
+ import { useCallback, useRef, type KeyboardEvent } from "react";
4
+ import { HARNESS_LABELS, type HarnessOption } from "./harness";
5
+
6
+ const OPTIONS: readonly HarnessOption[] = ["native", "cursor"];
7
+
8
+ /** Props for {@link HarnessSelector}. */
9
+ export interface HarnessSelectorProps {
10
+ /** Currently selected harness. */
11
+ readonly value: HarnessOption;
12
+ /** Called when the user picks a different harness. */
13
+ readonly onValueChange: (harness: HarnessOption) => void;
14
+ /** Additional CSS class names for the root container. */
15
+ readonly className?: string;
16
+ /** When true, disables the selector. */
17
+ readonly disabled?: boolean;
18
+ }
19
+
20
+ /**
21
+ * Compact segmented control for choosing the session execution engine.
22
+ *
23
+ * Renders two mutually exclusive options — "Stigmer" (native) and
24
+ * "Cursor" (premium) — as adjacent pill segments. The Cursor segment
25
+ * carries a subtle premium tier indicator.
26
+ *
27
+ * Built as a `radiogroup` with full arrow-key navigation and ARIA
28
+ * semantics. All visual properties flow through `--stgm-*` tokens.
29
+ *
30
+ * Platform builders who need different rendering use
31
+ * {@link HarnessOption} and {@link HARNESS_LABELS} directly.
32
+ *
33
+ * @deprecated Use {@link ModelSelector} in unified mode (without the
34
+ * `harness` prop) instead. The unified model picker embeds an engine
35
+ * tag on each model row, eliminating the need for a separate harness
36
+ * control. This component is kept for backward compatibility.
37
+ *
38
+ * @example
39
+ * ```tsx
40
+ * function LauncherToolbar() {
41
+ * const [harness, setHarness] = useState<HarnessOption>("native");
42
+ *
43
+ * return <HarnessSelector value={harness} onValueChange={setHarness} />;
44
+ * }
45
+ * ```
46
+ */
47
+ export function HarnessSelector({
48
+ value,
49
+ onValueChange,
50
+ className,
51
+ disabled,
52
+ }: HarnessSelectorProps) {
53
+ const groupRef = useRef<HTMLDivElement>(null);
54
+
55
+ const handleKeyDown = useCallback(
56
+ (e: KeyboardEvent<HTMLDivElement>) => {
57
+ if (disabled) return;
58
+
59
+ const idx = OPTIONS.indexOf(value);
60
+ let next: number | undefined;
61
+
62
+ if (e.key === "ArrowRight" || e.key === "ArrowDown") {
63
+ next = (idx + 1) % OPTIONS.length;
64
+ } else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
65
+ next = (idx - 1 + OPTIONS.length) % OPTIONS.length;
66
+ }
67
+
68
+ if (next !== undefined) {
69
+ e.preventDefault();
70
+ onValueChange(OPTIONS[next]);
71
+ const buttons = groupRef.current?.querySelectorAll<HTMLButtonElement>("[role=radio]");
72
+ buttons?.[next]?.focus();
73
+ }
74
+ },
75
+ [value, onValueChange, disabled],
76
+ );
77
+
78
+ return (
79
+ <div
80
+ ref={groupRef}
81
+ role="radiogroup"
82
+ aria-label="Execution engine"
83
+ onKeyDown={handleKeyDown}
84
+ className={[
85
+ "inline-flex items-center rounded-md border border-border bg-background p-0.5",
86
+ disabled ? "pointer-events-none opacity-50" : undefined,
87
+ className,
88
+ ]
89
+ .filter(Boolean)
90
+ .join(" ")}
91
+ >
92
+ {OPTIONS.map((option) => {
93
+ const isActive = value === option;
94
+
95
+ return (
96
+ <button
97
+ key={option}
98
+ type="button"
99
+ role="radio"
100
+ aria-checked={isActive}
101
+ aria-label={HARNESS_LABELS[option]}
102
+ tabIndex={isActive ? 0 : -1}
103
+ disabled={disabled}
104
+ onClick={() => {
105
+ if (!isActive) onValueChange(option);
106
+ }}
107
+ className={[
108
+ "inline-flex items-center gap-1 rounded-[5px] px-2 py-1 text-xs transition-colors",
109
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
110
+ "disabled:pointer-events-none",
111
+ isActive
112
+ ? "bg-accent font-medium text-foreground shadow-sm"
113
+ : "text-muted-foreground hover:text-foreground",
114
+ ].join(" ")}
115
+ >
116
+ {HARNESS_LABELS[option]}
117
+ {option === "cursor" && (
118
+ <span
119
+ aria-label="premium"
120
+ className="text-[0.6rem] text-muted-foreground"
121
+ >
122
+ $$$
123
+ </span>
124
+ )}
125
+ </button>
126
+ );
127
+ })}
128
+ </div>
129
+ );
130
+ }