@stigmer/react 0.0.79 → 0.0.80

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 (85) hide show
  1. package/agent/AgentDetailView.js +2 -2
  2. package/agent/AgentDetailView.js.map +1 -1
  3. package/agent/agentSetupReducer.d.ts +3 -3
  4. package/agent/agentSetupReducer.d.ts.map +1 -1
  5. package/agent/index.d.ts +1 -1
  6. package/agent/index.d.ts.map +1 -1
  7. package/agent/index.js +1 -1
  8. package/agent/index.js.map +1 -1
  9. package/agent/useAgentSetup.d.ts +4 -4
  10. package/agent/useAgentSetup.js +9 -9
  11. package/agent/useAgentSetup.js.map +1 -1
  12. package/environment/EnvVarForm.d.ts +9 -3
  13. package/environment/EnvVarForm.d.ts.map +1 -1
  14. package/environment/EnvVarForm.js +1 -1
  15. package/environment/EnvVarForm.js.map +1 -1
  16. package/environment/EnvironmentListPanel.d.ts +19 -4
  17. package/environment/EnvironmentListPanel.d.ts.map +1 -1
  18. package/environment/EnvironmentListPanel.js +7 -3
  19. package/environment/EnvironmentListPanel.js.map +1 -1
  20. package/environment/{diffEnvSpec.d.ts → diffEnv.d.ts} +9 -8
  21. package/environment/diffEnv.d.ts.map +1 -0
  22. package/environment/{diffEnvSpec.js → diffEnv.js} +10 -9
  23. package/environment/diffEnv.js.map +1 -0
  24. package/environment/index.d.ts +1 -1
  25. package/environment/index.d.ts.map +1 -1
  26. package/environment/index.js +1 -1
  27. package/environment/index.js.map +1 -1
  28. package/execution/SessionVariablesInput.d.ts +1 -1
  29. package/index.d.ts +3 -3
  30. package/index.d.ts.map +1 -1
  31. package/index.js +3 -3
  32. package/index.js.map +1 -1
  33. package/library/parse-resource-yaml.d.ts +1 -1
  34. package/library/parse-resource-yaml.d.ts.map +1 -1
  35. package/library/parse-resource-yaml.js +26 -16
  36. package/library/parse-resource-yaml.js.map +1 -1
  37. package/library/serialize-resource-yaml.js +17 -21
  38. package/library/serialize-resource-yaml.js.map +1 -1
  39. package/mcp-server/McpServerDetailView.d.ts +8 -1
  40. package/mcp-server/McpServerDetailView.d.ts.map +1 -1
  41. package/mcp-server/McpServerDetailView.js +27 -6
  42. package/mcp-server/McpServerDetailView.js.map +1 -1
  43. package/mcp-server/McpServerPicker.d.ts +8 -1
  44. package/mcp-server/McpServerPicker.d.ts.map +1 -1
  45. package/mcp-server/McpServerPicker.js +2 -2
  46. package/mcp-server/McpServerPicker.js.map +1 -1
  47. package/mcp-server/index.d.ts +2 -0
  48. package/mcp-server/index.d.ts.map +1 -1
  49. package/mcp-server/index.js +1 -0
  50. package/mcp-server/index.js.map +1 -1
  51. package/mcp-server/mcpServerSetupReducer.d.ts +4 -4
  52. package/mcp-server/useMcpServerCredentials.d.ts +32 -17
  53. package/mcp-server/useMcpServerCredentials.d.ts.map +1 -1
  54. package/mcp-server/useMcpServerCredentials.js +30 -19
  55. package/mcp-server/useMcpServerCredentials.js.map +1 -1
  56. package/mcp-server/useMcpServerSetup.d.ts +5 -5
  57. package/mcp-server/useMcpServerSetup.d.ts.map +1 -1
  58. package/mcp-server/useMcpServerSetup.js +33 -13
  59. package/mcp-server/useMcpServerSetup.js.map +1 -1
  60. package/mcp-server/useOAuthGrantStatus.d.ts +41 -0
  61. package/mcp-server/useOAuthGrantStatus.d.ts.map +1 -0
  62. package/mcp-server/useOAuthGrantStatus.js +91 -0
  63. package/mcp-server/useOAuthGrantStatus.js.map +1 -0
  64. package/package.json +4 -4
  65. package/src/agent/AgentDetailView.tsx +5 -5
  66. package/src/agent/agentSetupReducer.ts +3 -3
  67. package/src/agent/index.ts +1 -1
  68. package/src/agent/useAgentSetup.ts +11 -11
  69. package/src/environment/EnvVarForm.tsx +9 -3
  70. package/src/environment/EnvironmentListPanel.tsx +27 -9
  71. package/src/environment/{diffEnvSpec.ts → diffEnv.ts} +10 -9
  72. package/src/environment/index.ts +1 -1
  73. package/src/execution/SessionVariablesInput.tsx +1 -1
  74. package/src/index.ts +4 -2
  75. package/src/library/parse-resource-yaml.ts +27 -18
  76. package/src/library/serialize-resource-yaml.ts +20 -27
  77. package/src/mcp-server/McpServerDetailView.tsx +39 -7
  78. package/src/mcp-server/McpServerPicker.tsx +9 -1
  79. package/src/mcp-server/index.ts +3 -0
  80. package/src/mcp-server/mcpServerSetupReducer.ts +4 -4
  81. package/src/mcp-server/useMcpServerCredentials.ts +65 -32
  82. package/src/mcp-server/useMcpServerSetup.ts +38 -15
  83. package/src/mcp-server/useOAuthGrantStatus.ts +125 -0
  84. package/environment/diffEnvSpec.d.ts.map +0 -1
  85. package/environment/diffEnvSpec.js.map +0 -1
@@ -2,12 +2,14 @@
2
2
 
3
3
  import { useCallback, useEffect, useMemo, useReducer, useRef } from "react";
4
4
  import type { EnvVarInput, McpServerUsageInput, ResourceRef } from "@stigmer/sdk";
5
+ import { create } from "@bufbuild/protobuf";
5
6
  import type { McpServer } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
7
+ import { GetOAuthGrantStatusInputSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/io_pb";
6
8
  import type { DiscoveredTool } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/status_pb";
7
9
  import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
8
10
  import { useStigmer } from "../hooks";
9
11
  import { usePersonalEnvironment } from "../environment/usePersonalEnvironment";
10
- import { diffEnvSpec } from "../environment/diffEnvSpec";
12
+ import { diffEnv } from "../environment/diffEnv";
11
13
  import { toError } from "../internal/toError";
12
14
  import {
13
15
  mcpServerSetupReducer,
@@ -57,8 +59,8 @@ export interface UseMcpServerSetupReturn {
57
59
  /**
58
60
  * Add an MCP server to the setup flow.
59
61
  *
60
- * Fetches the full server resource, checks `env_spec` against the
61
- * personal environment, and resolves the entry to either `ready`
62
+ * Fetches the full server resource, checks `env` declarations against
63
+ * the personal environment, and resolves the entry to either `ready`
62
64
  * (no credentials needed or all present) or `needsSetup` (missing
63
65
  * variables). Also extracts discovered tools and approval policies
64
66
  * for the tool selector.
@@ -171,8 +173,8 @@ function computeDefaultEnabledTools(
171
173
  * MCP servers selected in the {@link McpServerPicker}.
172
174
  *
173
175
  * When a user toggles an MCP server ON, this hook fetches the server's
174
- * full resource, checks its `env_spec` against the personal environment
175
- * (via {@link diffEnvSpec}), and determines whether credentials are
176
+ * full resource, checks its `env` declarations against the personal
177
+ * environment (via {@link diffEnv}), and determines whether credentials are
176
178
  * needed. It also extracts discovered tools and approval policies for
177
179
  * the tool selector UI.
178
180
  *
@@ -198,7 +200,7 @@ function computeDefaultEnabledTools(
198
200
  * @param org - Organization slug. Pass `null` to disable.
199
201
  * @param poolKeys - Optional set of env-var keys already available
200
202
  * from the session env pool (manual secrets, one-time env vars from
201
- * other components). When provided, servers whose `env_spec` keys
203
+ * other components). When provided, servers whose `env` keys
202
204
  * are fully covered by `poolKeys` + personal env auto-resolve to
203
205
  * `ready` without prompting. Reactive — when `poolKeys` changes,
204
206
  * `needsSetup` entries are re-evaluated.
@@ -264,9 +266,9 @@ export function useMcpServerSetup(
264
266
  const discoveredTools =
265
267
  mcpServer.status?.discoveredCapabilities?.tools ?? [];
266
268
  const toolApprovals = mcpServer.spec?.pinnedToolApprovals ?? [];
267
- const envSpecData = mcpServer.spec?.envSpec?.data;
269
+ const envDeclarations = mcpServer.spec?.env;
268
270
 
269
- if (!envSpecData || Object.keys(envSpecData).length === 0) {
271
+ if (!envDeclarations || Object.keys(envDeclarations).length === 0) {
270
272
  dispatch({
271
273
  type: "RESOLVE_READY",
272
274
  key,
@@ -284,9 +286,29 @@ export function useMcpServerSetup(
284
286
  const existingKeys = new Set(
285
287
  Object.keys(personalEnv.environment?.spec?.data ?? {}),
286
288
  );
287
- const missingVariables = diffEnvSpec(envSpecData, existingKeys, poolKeys);
288
289
 
289
- if (missingVariables.length === 0) {
290
+ const auth = mcpServer.spec?.auth;
291
+ if (auth?.targetEnvVar && mcpServer.metadata?.id) {
292
+ try {
293
+ const grantStatus = await stigmer.mcpServer.getOAuthGrantStatus(
294
+ create(GetOAuthGrantStatusInputSchema, {
295
+ resourceId: mcpServer.metadata.id,
296
+ org,
297
+ }),
298
+ );
299
+ if (grantStatus.connected) {
300
+ existingKeys.add(auth.targetEnvVar);
301
+ }
302
+ } catch {
303
+ // Non-fatal: if grant status lookup fails, the OAuth var stays
304
+ // in missingVariables and the UI shows the sign-in button.
305
+ }
306
+ }
307
+
308
+ const allMissing = diffEnv(envDeclarations, existingKeys, poolKeys);
309
+ const requiredMissing = allMissing.filter((v) => !v.optional);
310
+
311
+ if (requiredMissing.length === 0) {
290
312
  dispatch({
291
313
  type: "RESOLVE_READY",
292
314
  key,
@@ -305,7 +327,7 @@ export function useMcpServerSetup(
305
327
  type: "RESOLVE_NEEDS_SETUP",
306
328
  key,
307
329
  mcpServer,
308
- missingVariables,
330
+ missingVariables: requiredMissing,
309
331
  discoveredTools,
310
332
  toolApprovals,
311
333
  });
@@ -420,15 +442,16 @@ export function useMcpServerSetup(
420
442
  for (const [key, entry] of Object.entries(entriesRef.current)) {
421
443
  if (entry.status !== "needsSetup") continue;
422
444
 
423
- const envSpecData = entry.mcpServer.spec?.envSpec?.data;
424
- if (!envSpecData) continue;
445
+ const envDeclarations = entry.mcpServer.spec?.env;
446
+ if (!envDeclarations) continue;
425
447
 
426
- const missingVariables = diffEnvSpec(envSpecData, personalKeys, poolKeys);
448
+ const allMissing = diffEnv(envDeclarations, personalKeys, poolKeys);
449
+ const requiredMissing = allMissing.filter((v) => !v.optional);
427
450
  const enabledTools = computeDefaultEnabledTools(
428
451
  entry.mcpServer,
429
452
  entry.discoveredTools,
430
453
  );
431
- dispatch({ type: "POOL_RESOLVE", key, missingVariables, enabledTools });
454
+ dispatch({ type: "POOL_RESOLVE", key, missingVariables: requiredMissing, enabledTools });
432
455
  }
433
456
  }, [poolKeys, personalEnv.environment]);
434
457
 
@@ -0,0 +1,125 @@
1
+ "use client";
2
+
3
+ import { useCallback, useEffect, useState } from "react";
4
+ import { create } from "@bufbuild/protobuf";
5
+ import { GetOAuthGrantStatusInputSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/io_pb";
6
+ import { useStigmer } from "../hooks";
7
+ import { toError } from "../internal/toError";
8
+
9
+ /** Return value of {@link useOAuthGrantStatus}. */
10
+ export interface UseOAuthGrantStatusReturn {
11
+ /** Whether the user has an active OAuth grant for this resource + org. */
12
+ readonly connected: boolean;
13
+ /**
14
+ * When the access token expires (Unix timestamp seconds).
15
+ * `BigInt(0)` when no grant exists or the token does not expire.
16
+ */
17
+ readonly accessTokenExpiresAt: bigint;
18
+ /** The env var name managed by OAuth, or empty string when no grant exists. */
19
+ readonly targetEnvVar: string;
20
+ /** Auth method used (`"mcp_oauth"` or `"vendor_oauth"`), or empty string. */
21
+ readonly authMethod: string;
22
+ /** `true` while the grant status is being fetched. */
23
+ readonly isLoading: boolean;
24
+ /** Error from the last failed request, or `null` when healthy. */
25
+ readonly error: Error | null;
26
+ /** Discard cached data and re-fetch the grant status. */
27
+ readonly refetch: () => void;
28
+ }
29
+
30
+ const BIGINT_ZERO = BigInt(0);
31
+
32
+ const IDLE: UseOAuthGrantStatusReturn = {
33
+ connected: false,
34
+ accessTokenExpiresAt: BIGINT_ZERO,
35
+ targetEnvVar: "",
36
+ authMethod: "",
37
+ isLoading: false,
38
+ error: null,
39
+ refetch: () => {},
40
+ };
41
+
42
+ /**
43
+ * Data hook that fetches the OAuth grant status for a single MCP server.
44
+ *
45
+ * Wraps `stigmer.mcpServer.getOAuthGrantStatus()` with loading, error,
46
+ * and idle state management. When `resourceId` or `org` changes, the
47
+ * previous in-flight request is discarded and a fresh fetch begins.
48
+ *
49
+ * Pass `null` for either parameter to skip fetching (stable no-op).
50
+ * This is useful when the MCP server resource has not loaded yet.
51
+ *
52
+ * @example
53
+ * ```tsx
54
+ * const grantStatus = useOAuthGrantStatus(mcpServer?.metadata?.id ?? null, org);
55
+ *
56
+ * if (grantStatus.isLoading) return <Spinner />;
57
+ * if (grantStatus.connected) return <span>Connected via OAuth</span>;
58
+ * return <button onClick={startOAuth}>Sign in</button>;
59
+ * ```
60
+ */
61
+ export function useOAuthGrantStatus(
62
+ resourceId: string | null,
63
+ org: string | null,
64
+ ): UseOAuthGrantStatusReturn {
65
+ const stigmer = useStigmer();
66
+ const [connected, setConnected] = useState(false);
67
+ const [accessTokenExpiresAt, setAccessTokenExpiresAt] = useState(BIGINT_ZERO);
68
+ const [targetEnvVar, setTargetEnvVar] = useState("");
69
+ const [authMethod, setAuthMethod] = useState("");
70
+ const [isLoading, setIsLoading] = useState(false);
71
+ const [error, setError] = useState<Error | null>(null);
72
+ const [fetchKey, setFetchKey] = useState(0);
73
+
74
+ const refetch = useCallback(() => setFetchKey((k) => k + 1), []);
75
+
76
+ useEffect(() => {
77
+ if (!resourceId || !org) {
78
+ setConnected(false);
79
+ setAccessTokenExpiresAt(BIGINT_ZERO);
80
+ setTargetEnvVar("");
81
+ setAuthMethod("");
82
+ setIsLoading(false);
83
+ setError(null);
84
+ return;
85
+ }
86
+
87
+ const cancelled = { current: false };
88
+ setIsLoading(true);
89
+ setError(null);
90
+
91
+ stigmer.mcpServer
92
+ .getOAuthGrantStatus(create(GetOAuthGrantStatusInputSchema, { resourceId, org }))
93
+ .then(
94
+ (result) => {
95
+ if (cancelled.current) return;
96
+ setConnected(result.connected);
97
+ setAccessTokenExpiresAt(result.accessTokenExpiresAt);
98
+ setTargetEnvVar(result.targetEnvVar);
99
+ setAuthMethod(result.authMethod);
100
+ setIsLoading(false);
101
+ },
102
+ (err) => {
103
+ if (cancelled.current) return;
104
+ setError(toError(err));
105
+ setIsLoading(false);
106
+ },
107
+ );
108
+
109
+ return () => {
110
+ cancelled.current = true;
111
+ };
112
+ }, [resourceId, org, stigmer, fetchKey]);
113
+
114
+ if (!resourceId || !org) return { ...IDLE, refetch };
115
+
116
+ return {
117
+ connected,
118
+ accessTokenExpiresAt,
119
+ targetEnvVar,
120
+ authMethod,
121
+ isLoading,
122
+ error,
123
+ refetch,
124
+ };
125
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"diffEnvSpec.d.ts","sourceRoot":"","sources":["../../src/environment/diffEnvSpec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,WAAW,CACzB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EACxE,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,EACzB,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GACrB,kBAAkB,EAAE,CAetB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"diffEnvSpec.js","sourceRoot":"","sources":["../../src/environment/diffEnvSpec.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,WAAW,CACzB,WAAwE,EACxE,YAAyB,EACzB,QAAsB;IAEtB,MAAM,OAAO,GAAyB,EAAE,CAAC;IAEzC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QACvD,IAAI,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QACpC,IAAI,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAEjC,OAAO,CAAC,IAAI,CAAC;YACX,GAAG;YACH,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,GAAG,CAAC,KAAK,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;SAC7D,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}