@stigmer/react 3.1.7 → 3.1.9

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 (206) hide show
  1. package/agent/AgentDetailView.d.ts +9 -1
  2. package/agent/AgentDetailView.d.ts.map +1 -1
  3. package/agent/AgentDetailView.js +15 -4
  4. package/agent/AgentDetailView.js.map +1 -1
  5. package/environment/EnvironmentListPanel.d.ts.map +1 -1
  6. package/environment/EnvironmentListPanel.js +11 -3
  7. package/environment/EnvironmentListPanel.js.map +1 -1
  8. package/environment/EnvironmentPicker.d.ts +17 -1
  9. package/environment/EnvironmentPicker.d.ts.map +1 -1
  10. package/environment/EnvironmentPicker.js +3 -2
  11. package/environment/EnvironmentPicker.js.map +1 -1
  12. package/environment/EnvironmentVariableEditor.d.ts.map +1 -1
  13. package/environment/EnvironmentVariableEditor.js +9 -3
  14. package/environment/EnvironmentVariableEditor.js.map +1 -1
  15. package/environment/index.d.ts +1 -0
  16. package/environment/index.d.ts.map +1 -1
  17. package/environment/index.js +1 -0
  18. package/environment/index.js.map +1 -1
  19. package/environment/shareRestriction.d.ts +13 -0
  20. package/environment/shareRestriction.d.ts.map +1 -0
  21. package/environment/shareRestriction.js +15 -0
  22. package/environment/shareRestriction.js.map +1 -0
  23. package/execution/ToolCallItem.d.ts.map +1 -1
  24. package/execution/ToolCallItem.js +12 -0
  25. package/execution/ToolCallItem.js.map +1 -1
  26. package/execution/ToolRunGroup.js +4 -0
  27. package/execution/ToolRunGroup.js.map +1 -1
  28. package/execution/WriteBackCard.d.ts +14 -5
  29. package/execution/WriteBackCard.d.ts.map +1 -1
  30. package/execution/WriteBackCard.js +103 -32
  31. package/execution/WriteBackCard.js.map +1 -1
  32. package/execution/WriteBacksWidget.d.ts +1 -1
  33. package/execution/WriteBacksWidget.js +2 -2
  34. package/execution/WriteBacksWidget.js.map +1 -1
  35. package/execution/index.d.ts +2 -0
  36. package/execution/index.d.ts.map +1 -1
  37. package/execution/index.js +1 -0
  38. package/execution/index.js.map +1 -1
  39. package/execution/write-back-utils.d.ts +57 -0
  40. package/execution/write-back-utils.d.ts.map +1 -0
  41. package/execution/write-back-utils.js +81 -0
  42. package/execution/write-back-utils.js.map +1 -0
  43. package/index.d.ts +6 -2
  44. package/index.d.ts.map +1 -1
  45. package/index.js +6 -1
  46. package/index.js.map +1 -1
  47. package/internal/dev/dom-counter.d.ts.map +1 -1
  48. package/internal/dev/dom-counter.js +2 -2
  49. package/internal/dev/dom-counter.js.map +1 -1
  50. package/internal/dev/enabled.d.ts +7 -0
  51. package/internal/dev/enabled.d.ts.map +1 -0
  52. package/internal/dev/enabled.js +38 -0
  53. package/internal/dev/enabled.js.map +1 -0
  54. package/internal/dev/profiler-wrapper.d.ts +3 -3
  55. package/internal/dev/profiler-wrapper.d.ts.map +1 -1
  56. package/internal/dev/profiler-wrapper.js +5 -5
  57. package/internal/dev/profiler-wrapper.js.map +1 -1
  58. package/internal/dev/use-key-stability.d.ts.map +1 -1
  59. package/internal/dev/use-key-stability.js +2 -2
  60. package/internal/dev/use-key-stability.js.map +1 -1
  61. package/internal/dev/use-render-tracer.d.ts +2 -2
  62. package/internal/dev/use-render-tracer.d.ts.map +1 -1
  63. package/internal/dev/use-render-tracer.js +4 -4
  64. package/internal/dev/use-render-tracer.js.map +1 -1
  65. package/internal/dev/use-stream-rate.d.ts +2 -1
  66. package/internal/dev/use-stream-rate.d.ts.map +1 -1
  67. package/internal/dev/use-stream-rate.js +4 -3
  68. package/internal/dev/use-stream-rate.js.map +1 -1
  69. package/library/ResourceVisibilityControl.d.ts +3 -0
  70. package/library/ResourceVisibilityControl.d.ts.map +1 -1
  71. package/library/ResourceVisibilityControl.js +22 -8
  72. package/library/ResourceVisibilityControl.js.map +1 -1
  73. package/library/useUpdateVisibility.d.ts +5 -3
  74. package/library/useUpdateVisibility.d.ts.map +1 -1
  75. package/library/useUpdateVisibility.js +7 -2
  76. package/library/useUpdateVisibility.js.map +1 -1
  77. package/library/visibilityLevels.d.ts +17 -0
  78. package/library/visibilityLevels.d.ts.map +1 -1
  79. package/library/visibilityLevels.js +32 -0
  80. package/library/visibilityLevels.js.map +1 -1
  81. package/package.json +4 -4
  82. package/session/NewSessionViewer.d.ts +11 -1
  83. package/session/NewSessionViewer.d.ts.map +1 -1
  84. package/session/NewSessionViewer.js +28 -8
  85. package/session/NewSessionViewer.js.map +1 -1
  86. package/session/SessionViewer.d.ts +9 -2
  87. package/session/SessionViewer.d.ts.map +1 -1
  88. package/session/SessionViewer.js +26 -12
  89. package/session/SessionViewer.js.map +1 -1
  90. package/session/audience.d.ts +12 -4
  91. package/session/audience.d.ts.map +1 -1
  92. package/session/facets/ChangesTab.d.ts.map +1 -1
  93. package/session/facets/ChangesTab.js +3 -1
  94. package/session/facets/ChangesTab.js.map +1 -1
  95. package/session/useNewSessionFlow.d.ts +12 -0
  96. package/session/useNewSessionFlow.d.ts.map +1 -1
  97. package/session/useNewSessionFlow.js +13 -1
  98. package/session/useNewSessionFlow.js.map +1 -1
  99. package/session/useSessionPageFlow.d.ts +13 -0
  100. package/session/useSessionPageFlow.d.ts.map +1 -1
  101. package/session/useSessionPageFlow.js +7 -2
  102. package/session/useSessionPageFlow.js.map +1 -1
  103. package/sharing/ShareAgentDialog.d.ts +57 -0
  104. package/sharing/ShareAgentDialog.d.ts.map +1 -0
  105. package/sharing/ShareAgentDialog.js +478 -0
  106. package/sharing/ShareAgentDialog.js.map +1 -0
  107. package/sharing/SharedAgentChat.d.ts +84 -0
  108. package/sharing/SharedAgentChat.d.ts.map +1 -0
  109. package/sharing/SharedAgentChat.js +80 -0
  110. package/sharing/SharedAgentChat.js.map +1 -0
  111. package/sharing/index.d.ts +18 -0
  112. package/sharing/index.d.ts.map +1 -0
  113. package/sharing/index.js +12 -0
  114. package/sharing/index.js.map +1 -0
  115. package/sharing/useAgentShare.d.ts +43 -0
  116. package/sharing/useAgentShare.d.ts.map +1 -0
  117. package/sharing/useAgentShare.js +54 -0
  118. package/sharing/useAgentShare.js.map +1 -0
  119. package/sharing/useRotateShareLink.d.ts +45 -0
  120. package/sharing/useRotateShareLink.d.ts.map +1 -0
  121. package/sharing/useRotateShareLink.js +58 -0
  122. package/sharing/useRotateShareLink.js.map +1 -0
  123. package/sharing/useSaveAgentShare.d.ts +105 -0
  124. package/sharing/useSaveAgentShare.d.ts.map +1 -0
  125. package/sharing/useSaveAgentShare.js +97 -0
  126. package/sharing/useSaveAgentShare.js.map +1 -0
  127. package/sharing/useShareAgent.d.ts +69 -0
  128. package/sharing/useShareAgent.d.ts.map +1 -0
  129. package/sharing/useShareAgent.js +42 -0
  130. package/sharing/useShareAgent.js.map +1 -0
  131. package/sharing/useShareToolReadiness.d.ts +52 -0
  132. package/sharing/useShareToolReadiness.d.ts.map +1 -0
  133. package/sharing/useShareToolReadiness.js +89 -0
  134. package/sharing/useShareToolReadiness.js.map +1 -0
  135. package/sharing/useSharedAgentProfile.d.ts +85 -0
  136. package/sharing/useSharedAgentProfile.d.ts.map +1 -0
  137. package/sharing/useSharedAgentProfile.js +73 -0
  138. package/sharing/useSharedAgentProfile.js.map +1 -0
  139. package/src/agent/AgentDetailView.tsx +28 -3
  140. package/src/environment/EnvironmentListPanel.tsx +47 -18
  141. package/src/environment/EnvironmentPicker.tsx +23 -2
  142. package/src/environment/EnvironmentVariableEditor.tsx +27 -17
  143. package/src/environment/__tests__/shareRestriction.test.ts +35 -0
  144. package/src/environment/index.ts +5 -0
  145. package/src/environment/shareRestriction.ts +22 -0
  146. package/src/execution/ToolCallItem.tsx +19 -1
  147. package/src/execution/ToolRunGroup.tsx +4 -0
  148. package/src/execution/WriteBackCard.tsx +285 -88
  149. package/src/execution/WriteBacksWidget.tsx +5 -5
  150. package/src/execution/__tests__/ToolCallItem.test.tsx +51 -0
  151. package/src/execution/__tests__/ToolRunGroup.test.tsx +22 -0
  152. package/src/execution/__tests__/WriteBackCard.test.tsx +64 -10
  153. package/src/execution/__tests__/write-back-utils.test.ts +135 -0
  154. package/src/execution/index.ts +7 -0
  155. package/src/execution/write-back-utils.ts +107 -0
  156. package/src/index.ts +38 -0
  157. package/src/internal/dev/__tests__/use-key-stability.test.ts +4 -0
  158. package/src/internal/dev/__tests__/use-render-tracer.test.ts +4 -0
  159. package/src/internal/dev/dom-counter.ts +2 -3
  160. package/src/internal/dev/enabled.ts +39 -0
  161. package/src/internal/dev/profiler-wrapper.tsx +5 -6
  162. package/src/internal/dev/use-key-stability.ts +2 -3
  163. package/src/internal/dev/use-render-tracer.ts +4 -5
  164. package/src/internal/dev/use-stream-rate.ts +4 -4
  165. package/src/library/ResourceVisibilityControl.tsx +23 -7
  166. package/src/library/__tests__/visibilityLevels.test.ts +33 -0
  167. package/src/library/useUpdateVisibility.ts +9 -3
  168. package/src/library/visibilityLevels.ts +36 -0
  169. package/src/session/NewSessionViewer.tsx +67 -31
  170. package/src/session/SessionViewer.tsx +67 -36
  171. package/src/session/__tests__/audienceWiring.test.tsx +99 -0
  172. package/src/session/__tests__/useNewSessionFlow.test.tsx +75 -1
  173. package/src/session/__tests__/useSessionPageFlow.guest.test.tsx +112 -0
  174. package/src/session/audience.ts +12 -4
  175. package/src/session/facets/ChangesTab.tsx +6 -4
  176. package/src/session/useNewSessionFlow.ts +26 -1
  177. package/src/session/useSessionPageFlow.ts +24 -2
  178. package/src/sharing/ShareAgentDialog.tsx +1489 -0
  179. package/src/sharing/SharedAgentChat.tsx +283 -0
  180. package/src/sharing/__tests__/ShareAgentDialog.test.tsx +926 -0
  181. package/src/sharing/__tests__/SharedAgentChat.test.tsx +222 -0
  182. package/src/sharing/__tests__/useAgentShare.test.tsx +149 -0
  183. package/src/sharing/__tests__/useRotateShareLink.test.tsx +96 -0
  184. package/src/sharing/__tests__/useSaveAgentShare.test.tsx +241 -0
  185. package/src/sharing/__tests__/useShareAgent.test.tsx +131 -0
  186. package/src/sharing/__tests__/useShareToolReadiness.test.tsx +219 -0
  187. package/src/sharing/__tests__/useSharedAgentProfile.test.tsx +201 -0
  188. package/src/sharing/index.ts +32 -0
  189. package/src/sharing/useAgentShare.ts +91 -0
  190. package/src/sharing/useRotateShareLink.ts +81 -0
  191. package/src/sharing/useSaveAgentShare.ts +186 -0
  192. package/src/sharing/useShareAgent.tsx +107 -0
  193. package/src/sharing/useShareToolReadiness.ts +131 -0
  194. package/src/sharing/useSharedAgentProfile.ts +132 -0
  195. package/src/switch/Switch.tsx +97 -0
  196. package/src/switch/__tests__/Switch.test.tsx +107 -0
  197. package/src/switch/index.ts +2 -0
  198. package/styles.css +1 -1
  199. package/switch/Switch.d.ts +47 -0
  200. package/switch/Switch.d.ts.map +1 -0
  201. package/switch/Switch.js +41 -0
  202. package/switch/Switch.js.map +1 -0
  203. package/switch/index.d.ts +3 -0
  204. package/switch/index.d.ts.map +1 -0
  205. package/switch/index.js +2 -0
  206. package/switch/index.js.map +1 -0
@@ -0,0 +1,69 @@
1
+ import { type ReactNode } from "react";
2
+ import type { Agent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
3
+ import type { DetailAction } from "../resource-detail/types.js";
4
+ /** Arguments for {@link useShareAgent}. */
5
+ export interface UseShareAgentArgs {
6
+ /**
7
+ * The agent whose sharing is managed, or `null` while it is still
8
+ * loading. When `null`, {@link UseShareAgentReturn.action} is `null`
9
+ * and the dialog renders nothing — safe to call before the resource
10
+ * is ready.
11
+ */
12
+ readonly agent: Agent | null;
13
+ /**
14
+ * Builds the absolute public chat URL for the shared agent. The host
15
+ * application owns URL construction (its configured public origin may
16
+ * differ from the rendering origin — e.g. the desktop app). When
17
+ * omitted, the dialog falls back to the relative `/chat/<org>/<slug>`.
18
+ */
19
+ readonly buildShareUrl?: (org: string, slug: string) => string;
20
+ /**
21
+ * Called after any sharing change is persisted. Hosts typically pass
22
+ * the agent data hook's `refetch`.
23
+ */
24
+ readonly onSharingChanged?: () => void;
25
+ /** Menu-item label. @default "Share" */
26
+ readonly label?: string;
27
+ }
28
+ /** Return value of {@link useShareAgent}. */
29
+ export interface UseShareAgentReturn {
30
+ /**
31
+ * A ready-to-spread {@link DetailAction} for a kebab/overflow menu, or
32
+ * `null` when the agent is unavailable or the user lacks `can_edit`.
33
+ * Lives in the `"sharing"` group, beside "Manage access".
34
+ */
35
+ readonly action: DetailAction | null;
36
+ /** The {@link ShareAgentDialog} node — render it once in the host tree. */
37
+ readonly dialog: ReactNode;
38
+ /** Imperatively open the dialog. */
39
+ readonly open: () => void;
40
+ /** Whether the dialog is currently open. */
41
+ readonly isOpen: boolean;
42
+ }
43
+ /**
44
+ * Wires the Share dialog to a kebab/overflow menu — the same trigger
45
+ * shape as {@link useManageAccess}, its conceptual sibling: Manage access
46
+ * governs who can *read* the blueprint; Share governs who can *chat* with
47
+ * the running agent (billed to the owning org).
48
+ *
49
+ * Owns the open-state and the `can_edit` gate — the same permission the
50
+ * AgentShare create/apply handlers enforce on the referenced agent, so
51
+ * the action never appears to a user whose changes would be rejected.
52
+ * Returns a `null` action while the agent is loading or the user cannot
53
+ * edit, so the host can unconditionally fold `action` into its actions
54
+ * array.
55
+ *
56
+ * @example
57
+ * ```tsx
58
+ * const share = useShareAgent({
59
+ * agent,
60
+ * buildShareUrl: (org, slug) => `${appOrigin}/chat/${org}/${slug}`,
61
+ * onSharingChanged: refetch,
62
+ * });
63
+ * // ...
64
+ * <ResourceDetailShell actions={share.action ? [...actions, share.action] : actions} ... />
65
+ * {share.dialog}
66
+ * ```
67
+ */
68
+ export declare function useShareAgent({ agent, buildShareUrl, onSharingChanged, label, }: UseShareAgentArgs): UseShareAgentReturn;
69
+ //# sourceMappingURL=useShareAgent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useShareAgent.d.ts","sourceRoot":"","sources":["../../src/sharing/useShareAgent.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAyB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAC9D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oDAAoD,CAAC;AAEhF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAGhE,2CAA2C;AAC3C,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/D;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IACvC,wCAAwC;IACxC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,6CAA6C;AAC7C,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IACrC,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,oCAAoC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC;IAC1B,4CAA4C;IAC5C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,aAAa,EACb,gBAAgB,EAChB,KAAe,GAChB,EAAE,iBAAiB,GAAG,mBAAmB,CA2BzC"}
@@ -0,0 +1,42 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { useCallback, useState } from "react";
4
+ import { useCheckPermission } from "../iam-policy/useCheckPermission.js";
5
+ import { ShareAgentDialog } from "./ShareAgentDialog.js";
6
+ /**
7
+ * Wires the Share dialog to a kebab/overflow menu — the same trigger
8
+ * shape as {@link useManageAccess}, its conceptual sibling: Manage access
9
+ * governs who can *read* the blueprint; Share governs who can *chat* with
10
+ * the running agent (billed to the owning org).
11
+ *
12
+ * Owns the open-state and the `can_edit` gate — the same permission the
13
+ * AgentShare create/apply handlers enforce on the referenced agent, so
14
+ * the action never appears to a user whose changes would be rejected.
15
+ * Returns a `null` action while the agent is loading or the user cannot
16
+ * edit, so the host can unconditionally fold `action` into its actions
17
+ * array.
18
+ *
19
+ * @example
20
+ * ```tsx
21
+ * const share = useShareAgent({
22
+ * agent,
23
+ * buildShareUrl: (org, slug) => `${appOrigin}/chat/${org}/${slug}`,
24
+ * onSharingChanged: refetch,
25
+ * });
26
+ * // ...
27
+ * <ResourceDetailShell actions={share.action ? [...actions, share.action] : actions} ... />
28
+ * {share.dialog}
29
+ * ```
30
+ */
31
+ export function useShareAgent({ agent, buildShareUrl, onSharingChanged, label = "Share", }) {
32
+ const [isOpen, setIsOpen] = useState(false);
33
+ const agentId = agent?.metadata?.id ?? null;
34
+ const { allowed: canEdit } = useCheckPermission(agentId ? { kind: "agent", id: agentId } : null, "can_edit");
35
+ const open = useCallback(() => setIsOpen(true), []);
36
+ const action = agent && canEdit
37
+ ? { id: "share", label, group: "sharing", onAction: open }
38
+ : null;
39
+ const dialog = agent ? (_jsx(ShareAgentDialog, { open: isOpen, onOpenChange: setIsOpen, agent: agent, buildShareUrl: buildShareUrl, onSharingChanged: onSharingChanged })) : null;
40
+ return { action, dialog, open, isOpen };
41
+ }
42
+ //# sourceMappingURL=useShareAgent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useShareAgent.js","sourceRoot":"","sources":["../../src/sharing/useShareAgent.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAkB,MAAM,OAAO,CAAC;AAE9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAEzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AA2CzD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,aAAa,CAAC,EAC5B,KAAK,EACL,aAAa,EACb,gBAAgB,EAChB,KAAK,GAAG,OAAO,GACG;IAClB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE5C,MAAM,OAAO,GAAG,KAAK,EAAE,QAAQ,EAAE,EAAE,IAAI,IAAI,CAAC;IAC5C,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,kBAAkB,CAC7C,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,EAC/C,UAAU,CACX,CAAC;IAEF,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IAEpD,MAAM,MAAM,GACV,KAAK,IAAI,OAAO;QACd,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE;QAC1D,CAAC,CAAC,IAAI,CAAC;IAEX,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CACrB,KAAC,gBAAgB,IACf,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,SAAS,EACvB,KAAK,EAAE,KAAK,EACZ,aAAa,EAAE,aAAa,EAC5B,gBAAgB,EAAE,gBAAgB,GAClC,CACH,CAAC,CAAC,CAAC,IAAI,CAAC;IAET,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,52 @@
1
+ import type { Agent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
2
+ import type { AgentShareDraft } from "./useSaveAgentShare.js";
3
+ /**
4
+ * Readiness of a share's tool credentials for visitor executions.
5
+ *
6
+ * - `na` — nothing to check: the agent uses no MCP tools, sharing is
7
+ * off, the audience is org (bindings are public-audience only), or
8
+ * the deployment cannot serve guest chat (local mode).
9
+ * - `needs-credentials` — the agent uses MCP tools but the share has no
10
+ * environments bound: visitors' tool calls will fail until the owner
11
+ * binds credentials.
12
+ * - `checking` — lookups in flight.
13
+ * - `ready` — every environment bound to the share is shared with the
14
+ * organization.
15
+ * - `blocked` — one or more bound environments are private; their
16
+ * `org/slug` references are listed for the hint copy.
17
+ */
18
+ export type ShareToolReadiness = {
19
+ readonly status: "na";
20
+ } | {
21
+ readonly status: "needs-credentials";
22
+ } | {
23
+ readonly status: "checking";
24
+ } | {
25
+ readonly status: "ready";
26
+ } | {
27
+ readonly status: "blocked";
28
+ readonly privateEnvironments: readonly string[];
29
+ };
30
+ /**
31
+ * Data hook that checks whether a tool-using shared agent's credentials
32
+ * will work for visitors — i.e. whether the share binds environments
33
+ * (`environment_refs`) and each one is shared with the organization
34
+ * (`visibility_org`).
35
+ *
36
+ * Guest executions receive credentials exclusively from the share's own
37
+ * `environment_refs`, resolved through the org-shared environment seam
38
+ * (decision 011 — the agent's default instance stays pristine and is
39
+ * never consulted). So a tool-using agent with an empty binding list is
40
+ * *guaranteed* broken for visitors, and this hook says so explicitly
41
+ * (`needs-credentials`) instead of staying silent — the gap that made
42
+ * session 12's misconfiguration invisible until a visitor's first
43
+ * message failed.
44
+ *
45
+ * The check runs only when the share is enabled with a public audience
46
+ * (org-audience shares reject bindings at the proto boundary), the
47
+ * deployment is cloud (local mode has no guest runtime or secret
48
+ * gating), and the agent declares MCP server usages. All lookups run as
49
+ * the owner viewing the dialog, who can read the bound environments.
50
+ */
51
+ export declare function useShareToolReadiness(agent: Agent, draft: AgentShareDraft): ShareToolReadiness;
52
+ //# sourceMappingURL=useShareToolReadiness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useShareToolReadiness.d.ts","sourceRoot":"","sources":["../../src/sharing/useShareToolReadiness.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oDAAoD,CAAC;AAIhF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAA;CAAE,GACzB;IAAE,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,GACxC;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAC/B;IAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GAC5B;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,mBAAmB,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAKpF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,eAAe,GACrB,kBAAkB,CAwEpB"}
@@ -0,0 +1,89 @@
1
+ "use client";
2
+ import { useEffect, useMemo, useState } from "react";
3
+ import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
4
+ import { useStigmer } from "../hooks.js";
5
+ import { useDeploymentMode } from "../deployment-mode.js";
6
+ const NA = { status: "na" };
7
+ const NEEDS_CREDENTIALS = { status: "needs-credentials" };
8
+ /**
9
+ * Data hook that checks whether a tool-using shared agent's credentials
10
+ * will work for visitors — i.e. whether the share binds environments
11
+ * (`environment_refs`) and each one is shared with the organization
12
+ * (`visibility_org`).
13
+ *
14
+ * Guest executions receive credentials exclusively from the share's own
15
+ * `environment_refs`, resolved through the org-shared environment seam
16
+ * (decision 011 — the agent's default instance stays pristine and is
17
+ * never consulted). So a tool-using agent with an empty binding list is
18
+ * *guaranteed* broken for visitors, and this hook says so explicitly
19
+ * (`needs-credentials`) instead of staying silent — the gap that made
20
+ * session 12's misconfiguration invisible until a visitor's first
21
+ * message failed.
22
+ *
23
+ * The check runs only when the share is enabled with a public audience
24
+ * (org-audience shares reject bindings at the proto boundary), the
25
+ * deployment is cloud (local mode has no guest runtime or secret
26
+ * gating), and the agent declares MCP server usages. All lookups run as
27
+ * the owner viewing the dialog, who can read the bound environments.
28
+ */
29
+ export function useShareToolReadiness(agent, draft) {
30
+ const stigmer = useStigmer();
31
+ const deploymentMode = useDeploymentMode();
32
+ const [checked, setChecked] = useState(NA);
33
+ const hasMcpTools = (agent.spec?.mcpServerUsages?.length ?? 0) > 0;
34
+ const applicable = draft.enabled &&
35
+ draft.audience === "public" &&
36
+ deploymentMode === "cloud" &&
37
+ hasMcpTools;
38
+ // Stable key for the effect: the visibility lookups depend only on
39
+ // which environments are bound, not on the array's identity.
40
+ const refsKey = useMemo(() => draft.environmentRefs.map((ref) => `${ref.org}/${ref.slug}`).join(","), [draft.environmentRefs]);
41
+ const shouldFetch = applicable && refsKey !== "";
42
+ useEffect(() => {
43
+ if (!shouldFetch) {
44
+ setChecked(NA);
45
+ return;
46
+ }
47
+ let cancelled = false;
48
+ setChecked({ status: "checking" });
49
+ (async () => {
50
+ const privateRefs = [];
51
+ for (const ref of refsKey.split(",")) {
52
+ const [org, slug] = ref.split("/");
53
+ try {
54
+ const env = await stigmer.environment.getByReference({ org, slug });
55
+ if (env.metadata?.visibility !== ApiResourceVisibility.visibility_org) {
56
+ privateRefs.push(ref);
57
+ }
58
+ }
59
+ catch {
60
+ // Unreadable ref (deleted, foreign): the runtime's merge will
61
+ // skip it for visitors too — surface it as blocking.
62
+ privateRefs.push(ref);
63
+ }
64
+ }
65
+ return privateRefs.length === 0
66
+ ? { status: "ready" }
67
+ : { status: "blocked", privateEnvironments: privateRefs };
68
+ })().then((result) => {
69
+ if (!cancelled)
70
+ setChecked(result);
71
+ }, () => {
72
+ // The hint is best-effort pre-flight advice — a failed check must
73
+ // never block the dialog. The runtime error path still diagnoses.
74
+ if (!cancelled)
75
+ setChecked(NA);
76
+ });
77
+ return () => {
78
+ cancelled = true;
79
+ };
80
+ }, [shouldFetch, refsKey, stigmer]);
81
+ if (!applicable)
82
+ return NA;
83
+ // Zero bindings needs no lookup: a tool-using agent without bound
84
+ // credentials is broken for visitors by construction.
85
+ if (refsKey === "")
86
+ return NEEDS_CREDENTIALS;
87
+ return checked;
88
+ }
89
+ //# sourceMappingURL=useShareToolReadiness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useShareToolReadiness.js","sourceRoot":"","sources":["../../src/sharing/useShareToolReadiness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ import { type SharedAgentProfile } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v1/io_pb";
2
+ import type { SharingAudience } from "./useSaveAgentShare.js";
3
+ /** Options for {@link useSharedAgentProfile}. */
4
+ export interface UseSharedAgentProfileOptions {
5
+ /**
6
+ * Which resolution path to use.
7
+ *
8
+ * - `"public"` (default) — the anonymous `getSharedProfile` RPC. An
9
+ * org-audience share answers NOT_FOUND here by design.
10
+ * - `"org"` — the authenticated `getSharedProfileForMember` RPC, which
11
+ * resolves org-audience shares for signed-in members of the owning
12
+ * organization (and public shares too). Requires a `StigmerProvider`
13
+ * whose client carries the member's token.
14
+ */
15
+ readonly audience?: SharingAudience;
16
+ /**
17
+ * Share-link token from the URL's `?k=` parameter (public path only).
18
+ *
19
+ * Required when the share link has been locked with a rotatable token;
20
+ * harmless on plain links. On a locked link a missing or rotated-away
21
+ * token resolves to `profile === null`, indistinguishable from an
22
+ * agent that does not exist.
23
+ */
24
+ readonly linkToken?: string;
25
+ }
26
+ /** Return value of {@link useSharedAgentProfile}. */
27
+ export interface UseSharedAgentProfileReturn {
28
+ /**
29
+ * The shared agent's public profile, or `null` while loading, on
30
+ * error, or when the agent is not shared.
31
+ */
32
+ readonly profile: SharedAgentProfile | null;
33
+ /** `true` while the initial fetch or a refetch is in flight. */
34
+ readonly isLoading: boolean;
35
+ /** `true` while a background refetch is in flight and stale data is shown. */
36
+ readonly isRefetching: boolean;
37
+ /** Error from the last failed request, or `null` when healthy. */
38
+ readonly error: Error | null;
39
+ /** Discard cached data and re-fetch the profile from the server. */
40
+ readonly refetch: () => void;
41
+ }
42
+ /**
43
+ * Data hook that fetches a shared agent's public profile by the org and
44
+ * slug from the share URL (the share's slug — it defaults to the
45
+ * agent's, so existing links resolve unchanged).
46
+ *
47
+ * By default this hook calls the `getSharedProfile` endpoint, which is
48
+ * **public** — it requires no authentication. The server returns a
49
+ * trimmed projection safe for anonymous visitors: name, description,
50
+ * icon, and the default instance id needed to start a session
51
+ * (an identifier, not a capability — session creation still requires
52
+ * an authorized token, e.g. a guest token from `createGuestAuth`).
53
+ * With `{ audience: "org" }` it calls the authenticated
54
+ * `getSharedProfileForMember` endpoint instead, which resolves
55
+ * org-members-only shares for a signed-in member.
56
+ *
57
+ * **Not-shared handling:** the server answers NOT_FOUND for "this
58
+ * agent does not exist", "this agent is not shared", and (on the
59
+ * member path) "you are not a member of this organization" — all
60
+ * indistinguishable by design so a share URL leaks nothing. The hook
61
+ * maps that to `profile === null` without raising an error, matching
62
+ * `useAgent`'s not-found convention:
63
+ * `profile === null && !isLoading && !error` means unavailable.
64
+ *
65
+ * Pass `null` for either `org` or `slug` to skip fetching (stable
66
+ * no-op) — useful while route params are still resolving.
67
+ *
68
+ * **Note**: Although authentication is not required by the server,
69
+ * the hook still requires a `StigmerProvider` ancestor because it
70
+ * needs the transport configuration (API base URL) to make the
71
+ * request.
72
+ *
73
+ * @example
74
+ * ```tsx
75
+ * const { profile, isLoading, error } = useSharedAgentProfile(org, slug);
76
+ *
77
+ * if (isLoading) return <Spinner />;
78
+ * if (error) return <ErrorCard error={error} />;
79
+ * if (!profile) return <AgentUnavailable />;
80
+ *
81
+ * return <h1>{profile.name}</h1>;
82
+ * ```
83
+ */
84
+ export declare function useSharedAgentProfile(org: string | null, slug: string | null, options?: UseSharedAgentProfileOptions): UseSharedAgentProfileReturn;
85
+ //# sourceMappingURL=useSharedAgentProfile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSharedAgentProfile.d.ts","sourceRoot":"","sources":["../../src/sharing/useSharedAgentProfile.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,wDAAwD,CAAC;AAIhE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,iDAAiD;AACjD,MAAM,WAAW,4BAA4B;IAC3C;;;;;;;;;OASG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,eAAe,CAAC;IAEpC;;;;;;;OAOG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,qDAAqD;AACrD,MAAM,WAAW,2BAA2B;IAC1C;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC5C,gEAAgE;IAChE,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,8EAA8E;IAC9E,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,kEAAkE;IAClE,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC7B,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,OAAO,CAAC,EAAE,4BAA4B,GACrC,2BAA2B,CA+B7B"}
@@ -0,0 +1,73 @@
1
+ "use client";
2
+ import { create } from "@bufbuild/protobuf";
3
+ import { GetSharedProfileRequestSchema, } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v1/io_pb";
4
+ import { isNotFound } from "@stigmer/sdk";
5
+ import { useStigmer } from "../hooks.js";
6
+ import { useFetch } from "../internal/useFetch.js";
7
+ /**
8
+ * Data hook that fetches a shared agent's public profile by the org and
9
+ * slug from the share URL (the share's slug — it defaults to the
10
+ * agent's, so existing links resolve unchanged).
11
+ *
12
+ * By default this hook calls the `getSharedProfile` endpoint, which is
13
+ * **public** — it requires no authentication. The server returns a
14
+ * trimmed projection safe for anonymous visitors: name, description,
15
+ * icon, and the default instance id needed to start a session
16
+ * (an identifier, not a capability — session creation still requires
17
+ * an authorized token, e.g. a guest token from `createGuestAuth`).
18
+ * With `{ audience: "org" }` it calls the authenticated
19
+ * `getSharedProfileForMember` endpoint instead, which resolves
20
+ * org-members-only shares for a signed-in member.
21
+ *
22
+ * **Not-shared handling:** the server answers NOT_FOUND for "this
23
+ * agent does not exist", "this agent is not shared", and (on the
24
+ * member path) "you are not a member of this organization" — all
25
+ * indistinguishable by design so a share URL leaks nothing. The hook
26
+ * maps that to `profile === null` without raising an error, matching
27
+ * `useAgent`'s not-found convention:
28
+ * `profile === null && !isLoading && !error` means unavailable.
29
+ *
30
+ * Pass `null` for either `org` or `slug` to skip fetching (stable
31
+ * no-op) — useful while route params are still resolving.
32
+ *
33
+ * **Note**: Although authentication is not required by the server,
34
+ * the hook still requires a `StigmerProvider` ancestor because it
35
+ * needs the transport configuration (API base URL) to make the
36
+ * request.
37
+ *
38
+ * @example
39
+ * ```tsx
40
+ * const { profile, isLoading, error } = useSharedAgentProfile(org, slug);
41
+ *
42
+ * if (isLoading) return <Spinner />;
43
+ * if (error) return <ErrorCard error={error} />;
44
+ * if (!profile) return <AgentUnavailable />;
45
+ *
46
+ * return <h1>{profile.name}</h1>;
47
+ * ```
48
+ */
49
+ export function useSharedAgentProfile(org, slug, options) {
50
+ const stigmer = useStigmer();
51
+ const audience = options?.audience ?? "public";
52
+ const linkToken = options?.linkToken ?? "";
53
+ const fetchFn = org && slug
54
+ ? async () => {
55
+ try {
56
+ // The member path is tokenless by contract: org-audience access
57
+ // is gated by live membership, and token-locked public shares
58
+ // deliberately refuse there (see getSharedProfileForMember).
59
+ return audience === "org"
60
+ ? await stigmer.agentShare.getSharedProfileForMember({ org, slug })
61
+ : await stigmer.agentShare.getSharedProfile(create(GetSharedProfileRequestSchema, { org, slug, linkToken }));
62
+ }
63
+ catch (err) {
64
+ if (isNotFound(err))
65
+ return null;
66
+ throw err;
67
+ }
68
+ }
69
+ : null;
70
+ const { data: profile, isLoading, isRefetching, error, refetch } = useFetch(fetchFn, [org, slug, audience, linkToken, stigmer], null);
71
+ return { profile, isLoading, isRefetching, error, refetch };
72
+ }
73
+ //# sourceMappingURL=useSharedAgentProfile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSharedAgentProfile.js","sourceRoot":"","sources":["../../src/sharing/useSharedAgentProfile.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EACL,6BAA6B,GAE9B,MAAM,wDAAwD,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AA6CnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,MAAM,UAAU,qBAAqB,CACnC,GAAkB,EAClB,IAAmB,EACnB,OAAsC;IAEtC,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,QAAQ,CAAC;IAC/C,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,EAAE,CAAC;IAE3C,MAAM,OAAO,GACX,GAAG,IAAI,IAAI;QACT,CAAC,CAAC,KAAK,IAAI,EAAE;YACT,IAAI,CAAC;gBACH,gEAAgE;gBAChE,8DAA8D;gBAC9D,6DAA6D;gBAC7D,OAAO,QAAQ,KAAK,KAAK;oBACvB,CAAC,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,yBAAyB,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;oBACnE,CAAC,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,gBAAgB,CACvC,MAAM,CAAC,6BAA6B,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAChE,CAAC;YACR,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,UAAU,CAAC,GAAG,CAAC;oBAAE,OAAO,IAAI,CAAC;gBACjC,MAAM,GAAG,CAAC;YACZ,CAAC;QACH,CAAC;QACH,CAAC,CAAC,IAAI,CAAC;IAEX,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,QAAQ,CACzE,OAAO,EACP,CAAC,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,EACzC,IAAiC,CAClC,CAAC;IAEF,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC9D,CAAC"}
@@ -17,6 +17,7 @@ import { agentToInput } from "./internal/agentToInput.js";
17
17
  import { ErrorMessage } from "../error/ErrorMessage.js";
18
18
  import { VisibilityBadge } from "../library/VisibilitySelector.js";
19
19
  import { useManageAccess } from "../access/useManageAccess.js";
20
+ import { useShareAgent } from "../sharing/useShareAgent.js";
20
21
  import { ResourceDetailShell } from "../resource-detail/ResourceDetailShell.js";
21
22
  import { Section } from "../resource-detail/Section.js";
22
23
  import { useDetailTabs } from "../resource-detail/useDetailTabs.js";
@@ -127,6 +128,14 @@ export interface AgentDetailViewProps {
127
128
  * Opens the create instance dialog.
128
129
  */
129
130
  readonly onCreateInstanceClick?: () => void;
131
+ /**
132
+ * Builds the absolute public chat URL shown in the Share dialog.
133
+ * The host application owns URL construction — its configured public
134
+ * origin may differ from the rendering origin (e.g. the desktop app).
135
+ * When omitted, the dialog falls back to the relative
136
+ * `/chat/<org>/<slug>` path.
137
+ */
138
+ readonly buildShareUrl?: (org: string, slug: string) => string;
130
139
  /**
131
140
  * Called when the user clicks an instance row in the Instances tab.
132
141
  * Typically opens an instance detail panel.
@@ -204,6 +213,7 @@ export function AgentDetailView({
204
213
  defaultTab,
205
214
  editable = false,
206
215
  onResourceUpdated,
216
+ buildShareUrl,
207
217
  onCreateInstanceClick,
208
218
  onInstanceClick,
209
219
  onInstanceStartSessionClick,
@@ -306,6 +316,15 @@ export function AgentDetailView({
306
316
  : undefined,
307
317
  });
308
318
 
319
+ // Share — the sibling consent to Manage access: visibility governs who
320
+ // can read the blueprint; sharing governs who can chat with the running
321
+ // agent (billed to the owning org). Same null-until-ready contract.
322
+ const share = useShareAgent({
323
+ agent,
324
+ buildShareUrl,
325
+ onSharingChanged: refetch,
326
+ });
327
+
309
328
  if (isLoading) return <LoadingSkeleton className={className} />;
310
329
  if (error)
311
330
  return <ErrorMessage error={error} retry={refetch} className={className} />;
@@ -344,9 +363,14 @@ export function AgentDetailView({
344
363
  <VisibilityBadge visibility={meta.visibility} />
345
364
  ) : undefined;
346
365
 
347
- const mergedActions = access.action
348
- ? [...(actions ?? []), access.action]
349
- : actions;
366
+ // Share precedes Manage access within the "sharing" group.
367
+ const injectedActions = [share.action, access.action].filter(
368
+ (a): a is NonNullable<typeof a> => a != null,
369
+ );
370
+ const mergedActions =
371
+ injectedActions.length > 0
372
+ ? [...(actions ?? []), ...injectedActions]
373
+ : actions;
350
374
 
351
375
  let tabContent: React.ReactNode;
352
376
  if (activeAdditionalTab) {
@@ -402,6 +426,7 @@ export function AgentDetailView({
402
426
  {tabContent}
403
427
  </ResourceDetailShell>
404
428
  {access.dialog}
429
+ {share.dialog}
405
430
  </>
406
431
  );
407
432
  }
@@ -4,8 +4,11 @@ import { useCallback, useMemo, useState } from "react";
4
4
  import { cn } from "@stigmer/theme";
5
5
  import { getUserMessage } from "@stigmer/sdk";
6
6
  import type { Environment } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/api_pb";
7
+ import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
8
+ import { ResourceVisibilityControl } from "../library/ResourceVisibilityControl.js";
7
9
  import { useEnvironmentList } from "./useEnvironmentList.js";
8
10
  import { EnvironmentVariableEditor } from "./EnvironmentVariableEditor.js";
11
+ import { isShareRestrictedEnvironment } from "./shareRestriction.js";
9
12
 
10
13
  // ---------------------------------------------------------------------------
11
14
  // Public API
@@ -175,6 +178,7 @@ export function EnvironmentListPanel({
175
178
  isExpanded={isExpanded}
176
179
  onToggle={() => handleToggle(env)}
177
180
  readOnly={readOnly}
181
+ onVisibilityChanged={refetch}
178
182
  />
179
183
  );
180
184
  })}
@@ -191,11 +195,13 @@ function EnvironmentCard({
191
195
  isExpanded,
192
196
  onToggle,
193
197
  readOnly,
198
+ onVisibilityChanged,
194
199
  }: {
195
200
  environment: Environment;
196
201
  isExpanded: boolean;
197
202
  onToggle: () => void;
198
203
  readOnly: boolean;
204
+ onVisibilityChanged: () => void;
199
205
  }) {
200
206
  const name =
201
207
  environment.metadata?.name || environment.metadata?.slug || "Unnamed";
@@ -203,6 +209,12 @@ function EnvironmentCard({
203
209
  const variableCount = Object.keys(environment.spec?.data ?? {}).length;
204
210
  const environmentId = environment.metadata?.id ?? "";
205
211
 
212
+ // Personal and OAuth-managed environments are never org-shareable
213
+ // (the backend rejects the transition) — offering the control would
214
+ // be an error trap, so it is structurally absent for them.
215
+ const showVisibilityControl =
216
+ !readOnly && environmentId !== "" && !isShareRestrictedEnvironment(environment);
217
+
206
218
  return (
207
219
  <div
208
220
  role="listitem"
@@ -213,30 +225,47 @@ function EnvironmentCard({
213
225
  : "border-border-muted hover:border-border",
214
226
  )}
215
227
  >
216
- {/* Header — always visible */}
217
- <button
218
- type="button"
219
- onClick={onToggle}
220
- aria-expanded={isExpanded}
221
- className="flex w-full items-center gap-3 px-3 py-2.5 text-left"
222
- >
223
- <ChevronIcon expanded={isExpanded} />
228
+ {/* Header — always visible. The expand toggle and the visibility
229
+ control are sibling interactive elements (nesting the selector
230
+ inside the toggle button would be invalid markup). */}
231
+ <div className="flex w-full items-center gap-3 px-3 py-2.5">
232
+ <button
233
+ type="button"
234
+ onClick={onToggle}
235
+ aria-expanded={isExpanded}
236
+ className="flex min-w-0 flex-1 items-center gap-3 text-left"
237
+ >
238
+ <ChevronIcon expanded={isExpanded} />
224
239
 
225
- <div className="min-w-0 flex-1">
226
- <span className="block truncate text-sm font-medium text-foreground">
227
- {name}
228
- </span>
229
- {description && (
230
- <span className="block truncate text-xs text-muted-foreground">
231
- {description}
240
+ <div className="min-w-0 flex-1">
241
+ <span className="block truncate text-sm font-medium text-foreground">
242
+ {name}
232
243
  </span>
233
- )}
234
- </div>
244
+ {description && (
245
+ <span className="block truncate text-xs text-muted-foreground">
246
+ {description}
247
+ </span>
248
+ )}
249
+ </div>
250
+ </button>
251
+
252
+ {showVisibilityControl && (
253
+ <ResourceVisibilityControl
254
+ kind="environment"
255
+ resourceId={environmentId}
256
+ visibility={
257
+ environment.metadata?.visibility ??
258
+ ApiResourceVisibility.visibility_private
259
+ }
260
+ onChanged={onVisibilityChanged}
261
+ className="shrink-0"
262
+ />
263
+ )}
235
264
 
236
265
  <span className="shrink-0 text-xs text-muted-foreground">
237
266
  {variableCount} {variableCount === 1 ? "variable" : "variables"}
238
267
  </span>
239
- </button>
268
+ </div>
240
269
 
241
270
  {/* Expanded content — variable editor */}
242
271
  {isExpanded && environmentId && (