@stigmer/react 3.11.1-dev.20260812192248 → 3.12.1

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 (273) hide show
  1. package/activity/useRecentActivity.d.ts +3 -2
  2. package/activity/useRecentActivity.d.ts.map +1 -1
  3. package/activity/useRecentActivity.js +3 -2
  4. package/activity/useRecentActivity.js.map +1 -1
  5. package/agent/AgentDetailView.d.ts +2 -12
  6. package/agent/AgentDetailView.d.ts.map +1 -1
  7. package/agent/AgentDetailView.js +10 -42
  8. package/agent/AgentDetailView.js.map +1 -1
  9. package/agent/internal/agentToInput.d.ts.map +1 -1
  10. package/agent/internal/agentToInput.js +0 -8
  11. package/agent/internal/agentToInput.js.map +1 -1
  12. package/dependency-graph/DependencyTreeNode.d.ts.map +1 -1
  13. package/dependency-graph/DependencyTreeNode.js +1 -7
  14. package/dependency-graph/DependencyTreeNode.js.map +1 -1
  15. package/dependency-graph/types.d.ts +8 -20
  16. package/dependency-graph/types.d.ts.map +1 -1
  17. package/dependency-graph/useDependencyGraph.d.ts.map +1 -1
  18. package/dependency-graph/useDependencyGraph.js +2 -20
  19. package/dependency-graph/useDependencyGraph.js.map +1 -1
  20. package/execution/useCreateAgentExecution.d.ts +3 -2
  21. package/execution/useCreateAgentExecution.d.ts.map +1 -1
  22. package/execution/useCreateAgentExecution.js.map +1 -1
  23. package/index.d.ts +0 -2
  24. package/index.d.ts.map +1 -1
  25. package/index.js +0 -6
  26. package/index.js.map +1 -1
  27. package/internal/isUnimplemented.d.ts +17 -0
  28. package/internal/isUnimplemented.d.ts.map +1 -0
  29. package/internal/isUnimplemented.js +26 -0
  30. package/internal/isUnimplemented.js.map +1 -0
  31. package/library/useExportResource.d.ts +3 -4
  32. package/library/useExportResource.d.ts.map +1 -1
  33. package/library/useExportResource.js +1 -1
  34. package/library/useExportResource.js.map +1 -1
  35. package/manifest/EditResourceYamlDialog.d.ts.map +1 -1
  36. package/manifest/EditResourceYamlDialog.js.map +1 -1
  37. package/mcp-server/McpServerConnectDialog.js +7 -3
  38. package/mcp-server/McpServerConnectDialog.js.map +1 -1
  39. package/mcp-server/useMcpServerCredentials.d.ts +38 -10
  40. package/mcp-server/useMcpServerCredentials.d.ts.map +1 -1
  41. package/mcp-server/useMcpServerCredentials.js +50 -7
  42. package/mcp-server/useMcpServerCredentials.js.map +1 -1
  43. package/mcp-server/useOrgOAuthApp.d.ts +22 -0
  44. package/mcp-server/useOrgOAuthApp.d.ts.map +1 -1
  45. package/mcp-server/useOrgOAuthApp.js +39 -7
  46. package/mcp-server/useOrgOAuthApp.js.map +1 -1
  47. package/package.json +4 -4
  48. package/session/useSessionConversation.d.ts +4 -2
  49. package/session/useSessionConversation.d.ts.map +1 -1
  50. package/session/useSessionConversation.js.map +1 -1
  51. package/skill/useSkillVersions.d.ts.map +1 -1
  52. package/skill/useSkillVersions.js +1 -9
  53. package/skill/useSkillVersions.js.map +1 -1
  54. package/src/activity/useRecentActivity.ts +3 -2
  55. package/src/agent/AgentDetailView.tsx +6 -130
  56. package/src/agent/internal/__tests__/agentToInput.test.ts +2 -11
  57. package/src/agent/internal/agentToInput.ts +0 -11
  58. package/src/dependency-graph/DependencyTreeNode.tsx +1 -7
  59. package/src/dependency-graph/__tests__/useDependencyGraph.test.ts +18 -34
  60. package/src/dependency-graph/types.ts +8 -20
  61. package/src/dependency-graph/useDependencyGraph.ts +2 -22
  62. package/src/execution/useCreateAgentExecution.ts +3 -2
  63. package/src/index.ts +0 -82
  64. package/src/internal/isUnimplemented.ts +26 -0
  65. package/src/library/useExportResource.ts +3 -4
  66. package/src/manifest/EditResourceYamlDialog.tsx +1 -2
  67. package/src/manifest/__tests__/ApplyManifestDialog.test.tsx +2 -2
  68. package/src/manifest/__tests__/EditResourceYamlDialog.test.tsx +9 -9
  69. package/src/mcp-server/McpServerConnectDialog.tsx +29 -11
  70. package/src/mcp-server/__tests__/VendorApprovalBlocked.surfaces.test.tsx +103 -5
  71. package/src/mcp-server/__tests__/byoaEditionDegradation.test.tsx +323 -0
  72. package/src/mcp-server/__tests__/useMcpServerCredentials.test.tsx +306 -0
  73. package/src/mcp-server/useMcpServerCredentials.ts +87 -19
  74. package/src/mcp-server/useOrgOAuthApp.ts +54 -8
  75. package/src/session/useSessionConversation.ts +4 -2
  76. package/src/skill/useSkillVersions.ts +1 -11
  77. package/src/workflow/WorkflowCanvasEditor.tsx +37 -7
  78. package/src/workflow/WorkflowExecutionGraph.tsx +26 -1
  79. package/src/workflow/WorkflowExecutionViewer.tsx +27 -13
  80. package/src/workflow/WorkflowNode.tsx +5 -2
  81. package/src/workflow/WorkflowRunDialog.tsx +28 -1
  82. package/src/workflow/__tests__/WorkflowExecutionViewer.reconciliation.test.tsx +48 -1
  83. package/src/workflow/__tests__/WorkflowNode.test.tsx +93 -0
  84. package/src/workflow/__tests__/WorkflowRunDialog.test.tsx +127 -0
  85. package/src/workflow/__tests__/graph-history.test.ts +103 -0
  86. package/src/workflow/__tests__/overview-graph.test.ts +17 -0
  87. package/src/workflow/__tests__/useCanvasKeyboardShortcuts.undo.test.ts +115 -0
  88. package/src/workflow/__tests__/useWorkflowCanvas.undo.test.tsx +133 -0
  89. package/src/workflow/instance/CreateWorkflowInstanceDialog.tsx +16 -7
  90. package/src/workflow/instance/useDeleteWorkflowInstance.ts +9 -4
  91. package/src/workflow/layout/registry-dimensions.ts +2 -5
  92. package/src/workflow/node-shell/NodeShell.tsx +4 -0
  93. package/src/workflow/task-type-visual-registry.ts +5 -3
  94. package/src/workflow/useCanvasKeyboardShortcuts.ts +33 -3
  95. package/src/workflow/useGraphHistory.ts +22 -41
  96. package/src/workflow/useWorkflowCanvas.ts +12 -10
  97. package/src/workflow/useWorkflowSave.ts +2 -15
  98. package/src/workflow/workflow-graph-conversions.ts +25 -3
  99. package/styles.css +1 -1
  100. package/workflow/CanvasTransitionEdge.d.ts +1 -1
  101. package/workflow/WorkflowCanvasEditor.d.ts.map +1 -1
  102. package/workflow/WorkflowCanvasEditor.js +31 -6
  103. package/workflow/WorkflowCanvasEditor.js.map +1 -1
  104. package/workflow/WorkflowExecutionGraph.d.ts.map +1 -1
  105. package/workflow/WorkflowExecutionGraph.js +27 -1
  106. package/workflow/WorkflowExecutionGraph.js.map +1 -1
  107. package/workflow/WorkflowExecutionViewer.d.ts.map +1 -1
  108. package/workflow/WorkflowExecutionViewer.js +26 -12
  109. package/workflow/WorkflowExecutionViewer.js.map +1 -1
  110. package/workflow/WorkflowNode.d.ts.map +1 -1
  111. package/workflow/WorkflowNode.js +2 -2
  112. package/workflow/WorkflowNode.js.map +1 -1
  113. package/workflow/WorkflowRunDialog.d.ts +11 -1
  114. package/workflow/WorkflowRunDialog.d.ts.map +1 -1
  115. package/workflow/WorkflowRunDialog.js +16 -2
  116. package/workflow/WorkflowRunDialog.js.map +1 -1
  117. package/workflow/instance/CreateWorkflowInstanceDialog.d.ts.map +1 -1
  118. package/workflow/instance/CreateWorkflowInstanceDialog.js +10 -2
  119. package/workflow/instance/CreateWorkflowInstanceDialog.js.map +1 -1
  120. package/workflow/instance/useDeleteWorkflowInstance.d.ts +9 -4
  121. package/workflow/instance/useDeleteWorkflowInstance.d.ts.map +1 -1
  122. package/workflow/instance/useDeleteWorkflowInstance.js +4 -2
  123. package/workflow/instance/useDeleteWorkflowInstance.js.map +1 -1
  124. package/workflow/layout/registry-dimensions.d.ts.map +1 -1
  125. package/workflow/layout/registry-dimensions.js +2 -5
  126. package/workflow/layout/registry-dimensions.js.map +1 -1
  127. package/workflow/node-shell/NodeShell.js +1 -1
  128. package/workflow/node-shell/NodeShell.js.map +1 -1
  129. package/workflow/task-type-visual-registry.d.ts.map +1 -1
  130. package/workflow/task-type-visual-registry.js +5 -3
  131. package/workflow/task-type-visual-registry.js.map +1 -1
  132. package/workflow/useCanvasKeyboardShortcuts.d.ts +15 -4
  133. package/workflow/useCanvasKeyboardShortcuts.d.ts.map +1 -1
  134. package/workflow/useCanvasKeyboardShortcuts.js +25 -4
  135. package/workflow/useCanvasKeyboardShortcuts.js.map +1 -1
  136. package/workflow/useGraphHistory.d.ts +16 -9
  137. package/workflow/useGraphHistory.d.ts.map +1 -1
  138. package/workflow/useGraphHistory.js +19 -33
  139. package/workflow/useGraphHistory.js.map +1 -1
  140. package/workflow/useWorkflowCanvas.d.ts +1 -3
  141. package/workflow/useWorkflowCanvas.d.ts.map +1 -1
  142. package/workflow/useWorkflowCanvas.js +15 -9
  143. package/workflow/useWorkflowCanvas.js.map +1 -1
  144. package/workflow/useWorkflowSave.d.ts.map +1 -1
  145. package/workflow/useWorkflowSave.js +2 -15
  146. package/workflow/useWorkflowSave.js.map +1 -1
  147. package/workflow/workflow-graph-conversions.d.ts +19 -1
  148. package/workflow/workflow-graph-conversions.d.ts.map +1 -1
  149. package/workflow/workflow-graph-conversions.js +17 -3
  150. package/workflow/workflow-graph-conversions.js.map +1 -1
  151. package/datastore/CollectionRecordsBrowser.d.ts +0 -34
  152. package/datastore/CollectionRecordsBrowser.d.ts.map +0 -1
  153. package/datastore/CollectionRecordsBrowser.js +0 -226
  154. package/datastore/CollectionRecordsBrowser.js.map +0 -1
  155. package/datastore/CollectionSchemaView.d.ts +0 -29
  156. package/datastore/CollectionSchemaView.d.ts.map +0 -1
  157. package/datastore/CollectionSchemaView.js +0 -93
  158. package/datastore/CollectionSchemaView.js.map +0 -1
  159. package/datastore/DatastoreDetailView.d.ts +0 -44
  160. package/datastore/DatastoreDetailView.d.ts.map +0 -1
  161. package/datastore/DatastoreDetailView.js +0 -76
  162. package/datastore/DatastoreDetailView.js.map +0 -1
  163. package/datastore/DatastoreSyncReport.d.ts +0 -19
  164. package/datastore/DatastoreSyncReport.d.ts.map +0 -1
  165. package/datastore/DatastoreSyncReport.js +0 -45
  166. package/datastore/DatastoreSyncReport.js.map +0 -1
  167. package/datastore/DeleteDatastoreDialog.d.ts +0 -35
  168. package/datastore/DeleteDatastoreDialog.d.ts.map +0 -1
  169. package/datastore/DeleteDatastoreDialog.js +0 -90
  170. package/datastore/DeleteDatastoreDialog.js.map +0 -1
  171. package/datastore/FieldValueControl.d.ts +0 -55
  172. package/datastore/FieldValueControl.d.ts.map +0 -1
  173. package/datastore/FieldValueControl.js +0 -138
  174. package/datastore/FieldValueControl.js.map +0 -1
  175. package/datastore/RecordFilterBuilder.d.ts +0 -37
  176. package/datastore/RecordFilterBuilder.d.ts.map +0 -1
  177. package/datastore/RecordFilterBuilder.js +0 -122
  178. package/datastore/RecordFilterBuilder.js.map +0 -1
  179. package/datastore/RecordFormPanel.d.ts +0 -45
  180. package/datastore/RecordFormPanel.d.ts.map +0 -1
  181. package/datastore/RecordFormPanel.js +0 -215
  182. package/datastore/RecordFormPanel.js.map +0 -1
  183. package/datastore/index.d.ts +0 -43
  184. package/datastore/index.d.ts.map +0 -1
  185. package/datastore/index.js +0 -22
  186. package/datastore/index.js.map +0 -1
  187. package/datastore/recordFilter.d.ts +0 -62
  188. package/datastore/recordFilter.d.ts.map +0 -1
  189. package/datastore/recordFilter.js +0 -104
  190. package/datastore/recordFilter.js.map +0 -1
  191. package/datastore/recordValues.d.ts +0 -85
  192. package/datastore/recordValues.d.ts.map +0 -1
  193. package/datastore/recordValues.js +0 -282
  194. package/datastore/recordValues.js.map +0 -1
  195. package/datastore/useDatastore.d.ts +0 -39
  196. package/datastore/useDatastore.d.ts.map +0 -1
  197. package/datastore/useDatastore.js +0 -44
  198. package/datastore/useDatastore.js.map +0 -1
  199. package/datastore/useDatastoreCount.d.ts +0 -50
  200. package/datastore/useDatastoreCount.d.ts.map +0 -1
  201. package/datastore/useDatastoreCount.js +0 -27
  202. package/datastore/useDatastoreCount.js.map +0 -1
  203. package/datastore/useDatastoreDescription.d.ts +0 -54
  204. package/datastore/useDatastoreDescription.d.ts.map +0 -1
  205. package/datastore/useDatastoreDescription.js +0 -50
  206. package/datastore/useDatastoreDescription.js.map +0 -1
  207. package/datastore/useDatastoreList.d.ts +0 -57
  208. package/datastore/useDatastoreList.d.ts.map +0 -1
  209. package/datastore/useDatastoreList.js +0 -29
  210. package/datastore/useDatastoreList.js.map +0 -1
  211. package/datastore/useDatastoreSearch.d.ts +0 -19
  212. package/datastore/useDatastoreSearch.d.ts.map +0 -1
  213. package/datastore/useDatastoreSearch.js +0 -22
  214. package/datastore/useDatastoreSearch.js.map +0 -1
  215. package/datastore/useDeleteDatastore.d.ts +0 -53
  216. package/datastore/useDeleteDatastore.d.ts.map +0 -1
  217. package/datastore/useDeleteDatastore.js +0 -40
  218. package/datastore/useDeleteDatastore.js.map +0 -1
  219. package/datastore/useDeleteRecord.d.ts +0 -34
  220. package/datastore/useDeleteRecord.d.ts.map +0 -1
  221. package/datastore/useDeleteRecord.js +0 -43
  222. package/datastore/useDeleteRecord.js.map +0 -1
  223. package/datastore/useInsertRecord.d.ts +0 -50
  224. package/datastore/useInsertRecord.d.ts.map +0 -1
  225. package/datastore/useInsertRecord.js +0 -55
  226. package/datastore/useInsertRecord.js.map +0 -1
  227. package/datastore/useRecordCollection.d.ts +0 -104
  228. package/datastore/useRecordCollection.d.ts.map +0 -1
  229. package/datastore/useRecordCollection.js +0 -136
  230. package/datastore/useRecordCollection.js.map +0 -1
  231. package/datastore/useRecordList.d.ts +0 -66
  232. package/datastore/useRecordList.d.ts.map +0 -1
  233. package/datastore/useRecordList.js +0 -58
  234. package/datastore/useRecordList.js.map +0 -1
  235. package/datastore/useUpdateRecord.d.ts +0 -52
  236. package/datastore/useUpdateRecord.d.ts.map +0 -1
  237. package/datastore/useUpdateRecord.js +0 -55
  238. package/datastore/useUpdateRecord.js.map +0 -1
  239. package/src/agent/__tests__/AgentDetailView.datastores.test.tsx +0 -166
  240. package/src/datastore/CollectionRecordsBrowser.tsx +0 -571
  241. package/src/datastore/CollectionSchemaView.tsx +0 -247
  242. package/src/datastore/DatastoreDetailView.tsx +0 -201
  243. package/src/datastore/DatastoreSyncReport.tsx +0 -105
  244. package/src/datastore/DeleteDatastoreDialog.tsx +0 -202
  245. package/src/datastore/FieldValueControl.tsx +0 -289
  246. package/src/datastore/RecordFilterBuilder.tsx +0 -422
  247. package/src/datastore/RecordFormPanel.tsx +0 -432
  248. package/src/datastore/__tests__/CollectionRecordsBrowser.test.tsx +0 -245
  249. package/src/datastore/__tests__/DeleteDatastoreDialog.test.tsx +0 -133
  250. package/src/datastore/__tests__/FieldValueControl.test.tsx +0 -160
  251. package/src/datastore/__tests__/RecordFilterBuilder.test.tsx +0 -155
  252. package/src/datastore/__tests__/RecordFormPanel.test.tsx +0 -227
  253. package/src/datastore/__tests__/recordFilter.test.ts +0 -169
  254. package/src/datastore/__tests__/recordMutations.test.tsx +0 -195
  255. package/src/datastore/__tests__/recordValues.test.ts +0 -359
  256. package/src/datastore/__tests__/schemaAndSyncViews.test.tsx +0 -142
  257. package/src/datastore/__tests__/useDatastoreDescription.test.tsx +0 -143
  258. package/src/datastore/__tests__/useRecordCollection.test.tsx +0 -250
  259. package/src/datastore/__tests__/useRecordList.test.tsx +0 -85
  260. package/src/datastore/index.ts +0 -111
  261. package/src/datastore/recordFilter.ts +0 -154
  262. package/src/datastore/recordValues.ts +0 -327
  263. package/src/datastore/useDatastore.ts +0 -67
  264. package/src/datastore/useDatastoreCount.ts +0 -69
  265. package/src/datastore/useDatastoreDescription.ts +0 -90
  266. package/src/datastore/useDatastoreList.ts +0 -79
  267. package/src/datastore/useDatastoreSearch.ts +0 -39
  268. package/src/datastore/useDeleteDatastore.ts +0 -87
  269. package/src/datastore/useDeleteRecord.ts +0 -77
  270. package/src/datastore/useInsertRecord.ts +0 -92
  271. package/src/datastore/useRecordCollection.ts +0 -256
  272. package/src/datastore/useRecordList.ts +0 -131
  273. package/src/datastore/useUpdateRecord.ts +0 -95
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Detect gRPC/Connect UNIMPLEMENTED (code 12) from any error the SDK
3
+ * client can throw.
4
+ *
5
+ * UNIMPLEMENTED is how the shared SDK discovers edition capabilities:
6
+ * the OSS server deliberately leaves hosted-only RPCs unimplemented
7
+ * (e.g. the org-OAuth-app override surface, stigmer/stigmer#558), and
8
+ * hooks probe for it to degrade gracefully instead of surfacing an
9
+ * error. The SDK's generated CODE_MAP does not include Unimplemented —
10
+ * a `StigmerError` wrapping one reports `code: "unknown"` — so
11
+ * detection must go through `connectCode` (or the message shapes used
12
+ * by transports that never produce a structured error).
13
+ *
14
+ * @internal
15
+ */
16
+ export function isUnimplemented(err: unknown): boolean {
17
+ if (!err || typeof err !== "object") return false;
18
+ if (
19
+ "connectCode" in err &&
20
+ (err as { connectCode: unknown }).connectCode === 12
21
+ ) {
22
+ return true;
23
+ }
24
+ const msg = (err as { message?: string }).message ?? "";
25
+ return msg.includes("[unimplemented]") || msg.includes("UNIMPLEMENTED");
26
+ }
@@ -3,7 +3,6 @@
3
3
  import { useCallback, useMemo } from "react";
4
4
  import { parse as parseYaml } from "yaml";
5
5
  import type { Agent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
6
- import type { Datastore } from "@stigmer/protos/ai/stigmer/agentic/datastore/v1/api_pb";
7
6
  import type { McpServer } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
8
7
  import type { Schedule } from "@stigmer/protos/ai/stigmer/agentic/schedule/v1/api_pb";
9
8
  import type { Workflow } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/api_pb";
@@ -18,9 +17,9 @@ import { serializeWorkflowYaml } from "../workflow/serialize-workflow-yaml.js";
18
17
  /** Options for {@link useExportResource}. */
19
18
  export interface UseExportResourceOptions {
20
19
  /** The resource kind — determines which serializer is used. */
21
- readonly kind: "Agent" | "McpServer" | "Workflow" | "Datastore" | "Schedule";
20
+ readonly kind: "Agent" | "McpServer" | "Workflow" | "Schedule";
22
21
  /** The proto resource to export, or `null` when not yet loaded. */
23
- readonly resource: Agent | McpServer | Workflow | Datastore | Schedule | null;
22
+ readonly resource: Agent | McpServer | Workflow | Schedule | null;
24
23
  }
25
24
 
26
25
  /** Return value of {@link useExportResource}. */
@@ -45,7 +44,7 @@ export interface UseExportResourceReturn {
45
44
 
46
45
  /**
47
46
  * Headless export hook for Stigmer resources (Agent, McpServer,
48
- * Workflow, Datastore, Schedule).
47
+ * Workflow, Schedule).
49
48
  *
50
49
  * Serializes the resource into YAML and JSON formats and provides
51
50
  * stable callbacks for copying to clipboard or triggering a file
@@ -155,8 +155,7 @@ export function EditResourceYamlDialog({
155
155
  </div>
156
156
  )}
157
157
 
158
- {/* Apply error — the server's refusal (e.g. a datastore
159
- collection-removal rejection) rendered verbatim, with an
158
+ {/* Apply error — the server's refusal rendered verbatim, with an
160
159
  acknowledge-and-retry affordance: the operator reads the
161
160
  guard, edits or decides, and re-applies without reopening
162
161
  the dialog. */}
@@ -36,7 +36,7 @@ function entry(
36
36
  ): ManifestPreviewEntry {
37
37
  return {
38
38
  document: {
39
- handler: { yamlKind: "datastore", displayName: "Datastore" },
39
+ handler: { yamlKind: "mcpserver", displayName: "McpServer" },
40
40
  name: slug,
41
41
  slug,
42
42
  org: "acme",
@@ -55,7 +55,7 @@ const applyAllMock = vi.fn(async () => applyAllResult);
55
55
  vi.mock("../useApplyManifest", () => ({
56
56
  useApplyManifest: (): UseApplyManifestReturn =>
57
57
  ({
58
- content: "kind: Datastore",
58
+ content: "kind: McpServer",
59
59
  setContent: vi.fn(),
60
60
  readFile: vi.fn(),
61
61
  entries: mockEntries,
@@ -1,13 +1,13 @@
1
1
  // Tests for the shared Edit-YAML dialog's apply-error affordance
2
2
  // (DD-008 SD-6): the server's refusal renders verbatim with
3
- // Try-again/Dismiss — shared by every kind (McpServer, Agent, Skill,
4
- // Datastore), so the datastore collection-removal rejection and any
5
- // other apply-time guard get the same acknowledge-and-retry treatment.
3
+ // Try-again/Dismiss — shared by every kind (McpServer, Agent, Skill),
4
+ // so any apply-time guard gets the same acknowledge-and-retry
5
+ // treatment.
6
6
 
7
7
  import { describe, it, expect, vi, beforeAll, afterEach } from "vitest";
8
8
  import { render, screen, cleanup, fireEvent } from "@testing-library/react";
9
9
  import { create } from "@bufbuild/protobuf";
10
- import { DatastoreSchema } from "@stigmer/protos/ai/stigmer/agentic/datastore/v1/api_pb";
10
+ import { McpServerSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
11
11
  import { EditResourceYamlDialog } from "../EditResourceYamlDialog";
12
12
  import type { useEditResourceYaml } from "../useEditResourceYaml";
13
13
 
@@ -34,7 +34,7 @@ let editState: Partial<EditState>;
34
34
 
35
35
  vi.mock("../useEditResourceYaml", () => ({
36
36
  useEditResourceYaml: () => ({
37
- yaml: "kind: Datastore",
37
+ yaml: "kind: McpServer",
38
38
  setYaml: vi.fn(),
39
39
  validation: { status: "valid" as const },
40
40
  target: { action: "update" as const, slug: "clinic" },
@@ -54,8 +54,8 @@ vi.mock("../YamlEditor", () => ({
54
54
  YamlEditor: () => <div data-testid="yaml-editor" />,
55
55
  }));
56
56
 
57
- const RESOURCE = create(DatastoreSchema, {
58
- metadata: { id: "dst_1", slug: "clinic", org: "acme", name: "Clinic" },
57
+ const RESOURCE = create(McpServerSchema, {
58
+ metadata: { id: "mcp_1", slug: "clinic", org: "acme", name: "Clinic" },
59
59
  });
60
60
 
61
61
  function renderDialog() {
@@ -73,14 +73,14 @@ describe("EditResourceYamlDialog — apply-error affordance", () => {
73
73
  it("renders the server's refusal verbatim with Try again and Dismiss", () => {
74
74
  editState = {
75
75
  error: new Error(
76
- 'collection "old_notes" was removed from the spec; re-apply with the removal acknowledged',
76
+ 'spec change refused by an apply-time guard; re-apply with the change acknowledged',
77
77
  ),
78
78
  };
79
79
  renderDialog();
80
80
 
81
81
  const alert = screen.getByRole("alert");
82
82
  expect(alert.textContent).toContain(
83
- 'collection "old_notes" was removed from the spec',
83
+ "spec change refused by an apply-time guard",
84
84
  );
85
85
  expect(screen.getByRole("button", { name: "Try again" })).toBeTruthy();
86
86
  expect(screen.getByRole("button", { name: "Dismiss error" })).toBeTruthy();
@@ -344,6 +344,7 @@ function ConnectDialogContent({
344
344
  onSignIn={handleOAuthSignIn}
345
345
  isVendorApprovalBlocked={creds.isVendorApprovalBlocked}
346
346
  isVendorApprovalPending={creds.isVendorApprovalPending}
347
+ isOrgOAuthApp={creds.isOrgOAuthApp}
347
348
  manualEntrySupported={creds.manualEntrySupported}
348
349
  canBringOwnApp={creds.canBringOwnApp}
349
350
  vendorApprovalDocsUrl={creds.vendorApprovalDocsUrl}
@@ -459,6 +460,7 @@ function OAuthSection({
459
460
  onSignIn,
460
461
  isVendorApprovalBlocked,
461
462
  isVendorApprovalPending,
463
+ isOrgOAuthApp,
462
464
  manualEntrySupported,
463
465
  canBringOwnApp,
464
466
  vendorApprovalDocsUrl,
@@ -471,6 +473,14 @@ function OAuthSection({
471
473
  readonly onSignIn: () => void;
472
474
  readonly isVendorApprovalBlocked: boolean;
473
475
  readonly isVendorApprovalPending: boolean;
476
+ /**
477
+ * `true` when the org's own BYOA OAuth app is the effective one. The
478
+ * vendor-approval block describes the PLATFORM app, so it neither
479
+ * disables sign-in nor warrants the blocked notice when the org's own
480
+ * app is what sign-in will use (the caller-side org-override gate the
481
+ * notice's contract expects).
482
+ */
483
+ readonly isOrgOAuthApp: boolean;
474
484
  readonly manualEntrySupported: boolean;
475
485
  readonly canBringOwnApp: boolean;
476
486
  readonly vendorApprovalDocsUrl: string | null;
@@ -502,7 +512,9 @@ function OAuthSection({
502
512
  <button
503
513
  type="button"
504
514
  onClick={onSignIn}
505
- disabled={disabled || isInProgress || isVendorApprovalBlocked}
515
+ disabled={
516
+ disabled || isInProgress || (isVendorApprovalBlocked && !isOrgOAuthApp)
517
+ }
506
518
  className={cn(
507
519
  "stg:inline-flex stg:w-full stg:items-center stg:justify-center stg:gap-2 stg:rounded-md stg:px-4 stg:py-2 stg:text-sm stg:font-medium",
508
520
  "stg:bg-primary stg:text-primary-foreground",
@@ -512,17 +524,23 @@ function OAuthSection({
512
524
  )}
513
525
  >
514
526
  {isInProgress && <LoadingSpinner size="sm" />}
515
- {isInProgress ? (phaseLabel[phase] ?? "Connecting...") : "Sign in with OAuth"}
527
+ {isInProgress
528
+ ? (phaseLabel[phase] ?? "Connecting...")
529
+ : isOrgOAuthApp
530
+ ? "Sign in with your app"
531
+ : "Sign in with OAuth"}
516
532
  </button>
517
- <VendorApprovalBlockedNotice
518
- blocked={isVendorApprovalBlocked}
519
- pending={isVendorApprovalPending}
520
- manualEntrySupported={manualEntrySupported}
521
- canBringOwnApp={canBringOwnApp}
522
- docsUrl={vendorApprovalDocsUrl}
523
- onBringOwnApp={onOpenDetails}
524
- className="stg:rounded-md stg:border stg:border-amber-500/20"
525
- />
533
+ {!isOrgOAuthApp && (
534
+ <VendorApprovalBlockedNotice
535
+ blocked={isVendorApprovalBlocked}
536
+ pending={isVendorApprovalPending}
537
+ manualEntrySupported={manualEntrySupported}
538
+ canBringOwnApp={canBringOwnApp}
539
+ docsUrl={vendorApprovalDocsUrl}
540
+ onBringOwnApp={onOpenDetails}
541
+ className="stg:rounded-md stg:border stg:border-amber-500/20"
542
+ />
543
+ )}
526
544
  {onSwitchToManual && (
527
545
  <button
528
546
  type="button"
@@ -5,7 +5,10 @@ import { create } from "@bufbuild/protobuf";
5
5
  import { createRouterTransport } from "@connectrpc/connect";
6
6
  import { Stigmer } from "@stigmer/sdk";
7
7
  import { McpServerQueryController } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/query_pb";
8
- import { GetOAuthGrantStatusOutputSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/io_pb";
8
+ import {
9
+ GetOAuthGrantStatusOutputSchema,
10
+ GetOrgOAuthAppOutputSchema,
11
+ } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/io_pb";
9
12
  import {
10
13
  McpServerSpecSchema,
11
14
  McpServerAuthSchema,
@@ -14,7 +17,6 @@ import {
14
17
  import {
15
18
  McpServerStatusSchema,
16
19
  OAuthStatusSchema,
17
- OAuthAppSource,
18
20
  ValidationState,
19
21
  } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/status_pb";
20
22
  import { VendorApprovalStatus } from "@stigmer/protos/ai/stigmer/iam/oauthapp/v1/spec_pb";
@@ -53,8 +55,11 @@ const DOCS_URL = "https://vendor.example.com/oauth-docs";
53
55
 
54
56
  /**
55
57
  * An oauth_only vendor-OAuth server whose platform OAuth app is blocked.
56
- * `withAppRef` controls the BYOA arm: with a ref and a platform-sourced
57
- * effective app, `canBringOwnApp` is true.
58
+ * `withAppRef` controls the BYOA arm: with a ref and no org override,
59
+ * `canBringOwnApp` is true. The org-override state itself comes from the
60
+ * `getOrgOAuthApp` transport handler (client-side derivation,
61
+ * stigmer-cloud#401) — status.oauth_status carries only the
62
+ * vendor-approval fields, matching what backends actually populate.
58
63
  */
59
64
  function buildBlockedOAuthOnlyServer(options: {
60
65
  status: VendorApprovalStatus;
@@ -86,7 +91,6 @@ function buildBlockedOAuthOnlyServer(options: {
86
91
  oauthStatus: create(OAuthStatusSchema, {
87
92
  vendorApprovalStatus: options.status,
88
93
  vendorApprovalDocsUrl: DOCS_URL,
89
- effectiveOauthSource: OAuthAppSource.OAUTH_APP_SOURCE_PLATFORM,
90
94
  }),
91
95
  });
92
96
  return server;
@@ -96,6 +100,15 @@ function noGrant() {
96
100
  return create(GetOAuthGrantStatusOutputSchema, { connected: false });
97
101
  }
98
102
 
103
+ // BYOA affordances render only where the org-override surface exists —
104
+ // canBringOwnApp is gated on a getOrgOAuthApp capability probe
105
+ // (stigmer/stigmer#558), so the BYOA arms of these tests must register the
106
+ // RPC to simulate the hosted edition. The OSS arm (probe UNIMPLEMENTED →
107
+ // affordances hidden) is pinned in byoaEditionDegradation.test.tsx.
108
+ function noOverride() {
109
+ return create(GetOrgOAuthAppOutputSchema, { hasOverride: false });
110
+ }
111
+
99
112
  function renderWithTransport(
100
113
  ui: ReactNode,
101
114
  register: Parameters<typeof createRouterTransport>[0] = () => {},
@@ -128,6 +141,7 @@ describe("McpServerConnectDialog — oauth_only + vendor-blocked", () => {
128
141
  router.service(McpServerQueryController, {
129
142
  getByReference: () => server,
130
143
  getOAuthGrantStatus: noGrant,
144
+ getOrgOAuthApp: noOverride,
131
145
  });
132
146
  },
133
147
  );
@@ -199,6 +213,48 @@ describe("McpServerConnectDialog — oauth_only + vendor-blocked", () => {
199
213
  });
200
214
  expect(docs.getAttribute("href")).toBe(DOCS_URL);
201
215
  });
216
+
217
+ it("enables sign-in with the org's own app when a BYOA override is active", async () => {
218
+ // The platform app is still vendor-blocked, but the org brought its
219
+ // own approved app — the block describes an app sign-in won't use
220
+ // (stigmer-cloud#401). Before the client-side derivation this state
221
+ // was a dead end: disabled button AND no way forward.
222
+ renderWithTransport(
223
+ <McpServerConnectDialog
224
+ org={ORG}
225
+ slug={SLUG}
226
+ open
227
+ onClose={() => {}}
228
+ />,
229
+ (router) => {
230
+ router.service(McpServerQueryController, {
231
+ getByReference: () =>
232
+ buildBlockedOAuthOnlyServer({
233
+ status: VendorApprovalStatus.PENDING,
234
+ withAppRef: true,
235
+ }),
236
+ getOAuthGrantStatus: noGrant,
237
+ getOrgOAuthApp: () =>
238
+ create(GetOrgOAuthAppOutputSchema, {
239
+ hasOverride: true,
240
+ oauthAppId: "oauthapp_01acme",
241
+ clientId: "acme-client-id",
242
+ }),
243
+ });
244
+ },
245
+ );
246
+
247
+ const signIn = await screen.findByRole("button", {
248
+ name: "Sign in with your app",
249
+ });
250
+ expect((signIn as HTMLButtonElement).disabled).toBe(false);
251
+ // The blocked notice describes the platform app — suppressed while
252
+ // the org's own app is the effective one.
253
+ expect(screen.queryByText(/awaiting vendor approval/)).toBeNull();
254
+ expect(
255
+ screen.queryByRole("button", { name: "Use your own OAuth app" }),
256
+ ).toBeNull();
257
+ });
202
258
  });
203
259
 
204
260
  // ---------------------------------------------------------------------------
@@ -231,6 +287,7 @@ describe("McpServerDetailView — oauth_only + vendor-blocked", () => {
231
287
  (router) => {
232
288
  router.service(McpServerQueryController, {
233
289
  getOAuthGrantStatus: noGrant,
290
+ getOrgOAuthApp: noOverride,
234
291
  });
235
292
  },
236
293
  );
@@ -252,6 +309,47 @@ describe("McpServerDetailView — oauth_only + vendor-blocked", () => {
252
309
  // extraction into the shared notice.
253
310
  expect(cta.getAttribute("data-cursor-target")).toBe("byoa-cta-button");
254
311
  });
312
+
313
+ it("enables 'Sign in with your app' when the org's BYOA override is active", async () => {
314
+ // The vendor block gates the PLATFORM app; with the org's own app
315
+ // effective, sign-in must be enabled and the BYOA CTA retired
316
+ // (stigmer-cloud#401 — the signal these gates key on never fired).
317
+ renderWithTransport(
318
+ <McpServerDetailView
319
+ org={ORG}
320
+ slug={SLUG}
321
+ mcpServerState={loadedState(
322
+ buildBlockedOAuthOnlyServer({
323
+ status: VendorApprovalStatus.PENDING,
324
+ withAppRef: true,
325
+ }),
326
+ )}
327
+ />,
328
+ (router) => {
329
+ router.service(McpServerQueryController, {
330
+ getOAuthGrantStatus: noGrant,
331
+ getOrgOAuthApp: () =>
332
+ create(GetOrgOAuthAppOutputSchema, {
333
+ hasOverride: true,
334
+ oauthAppId: "oauthapp_01acme",
335
+ clientId: "acme-client-id",
336
+ }),
337
+ });
338
+ },
339
+ );
340
+
341
+ const signIn = await screen.findByRole("button", {
342
+ name: "Sign in with your app",
343
+ });
344
+ expect((signIn as HTMLButtonElement).disabled).toBe(false);
345
+ expect(screen.getByText("Using your OAuth app")).toBeTruthy();
346
+ // The blocked banner and BYOA offer describe the platform app —
347
+ // both retire while the override is active.
348
+ expect(screen.queryByText(/awaiting vendor approval/)).toBeNull();
349
+ expect(
350
+ screen.queryByRole("button", { name: "Use your own OAuth app" }),
351
+ ).toBeNull();
352
+ });
255
353
  });
256
354
 
257
355
  // ---------------------------------------------------------------------------