@stigmer/react 3.1.13 → 3.1.14

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 (69) hide show
  1. package/agent/AgentDetailView.d.ts +7 -9
  2. package/agent/AgentDetailView.d.ts.map +1 -1
  3. package/agent/AgentDetailView.js +22 -30
  4. package/agent/AgentDetailView.js.map +1 -1
  5. package/index.d.ts +2 -2
  6. package/index.d.ts.map +1 -1
  7. package/index.js +2 -2
  8. package/index.js.map +1 -1
  9. package/package.json +4 -4
  10. package/sharing/AgentShareList.d.ts +44 -0
  11. package/sharing/AgentShareList.d.ts.map +1 -0
  12. package/sharing/AgentShareList.js +149 -0
  13. package/sharing/AgentShareList.js.map +1 -0
  14. package/sharing/ShareAgentDialog.d.ts +38 -25
  15. package/sharing/ShareAgentDialog.d.ts.map +1 -1
  16. package/sharing/ShareAgentDialog.js +131 -62
  17. package/sharing/ShareAgentDialog.js.map +1 -1
  18. package/sharing/index.d.ts +10 -8
  19. package/sharing/index.d.ts.map +1 -1
  20. package/sharing/index.js +5 -4
  21. package/sharing/index.js.map +1 -1
  22. package/sharing/useAgentShares.d.ts +42 -0
  23. package/sharing/useAgentShares.d.ts.map +1 -0
  24. package/sharing/useAgentShares.js +38 -0
  25. package/sharing/useAgentShares.js.map +1 -0
  26. package/sharing/useCanCreateAgentShare.d.ts +43 -0
  27. package/sharing/useCanCreateAgentShare.d.ts.map +1 -0
  28. package/sharing/useCanCreateAgentShare.js +44 -0
  29. package/sharing/useCanCreateAgentShare.js.map +1 -0
  30. package/sharing/useDeleteAgentShare.d.ts +42 -0
  31. package/sharing/useDeleteAgentShare.d.ts.map +1 -0
  32. package/sharing/useDeleteAgentShare.js +45 -0
  33. package/sharing/useDeleteAgentShare.js.map +1 -0
  34. package/sharing/useSaveAgentShare.d.ts +43 -18
  35. package/sharing/useSaveAgentShare.d.ts.map +1 -1
  36. package/sharing/useSaveAgentShare.js +55 -22
  37. package/sharing/useSaveAgentShare.js.map +1 -1
  38. package/src/agent/AgentDetailView.tsx +34 -43
  39. package/src/index.ts +11 -9
  40. package/src/sharing/AgentShareList.tsx +507 -0
  41. package/src/sharing/ShareAgentDialog.tsx +310 -112
  42. package/src/sharing/__tests__/AgentShareList.test.tsx +388 -0
  43. package/src/sharing/__tests__/ShareAgentDialog.test.tsx +311 -312
  44. package/src/sharing/__tests__/useAgentShares.test.tsx +145 -0
  45. package/src/sharing/__tests__/useCanCreateAgentShare.test.tsx +190 -0
  46. package/src/sharing/index.ts +10 -12
  47. package/src/sharing/useAgentShares.ts +68 -0
  48. package/src/sharing/useCanCreateAgentShare.ts +74 -0
  49. package/src/sharing/useDeleteAgentShare.ts +73 -0
  50. package/src/sharing/useSaveAgentShare.ts +73 -23
  51. package/styles.css +1 -1
  52. package/sharing/useAgentShare.d.ts +0 -49
  53. package/sharing/useAgentShare.d.ts.map +0 -1
  54. package/sharing/useAgentShare.js +0 -64
  55. package/sharing/useAgentShare.js.map +0 -1
  56. package/sharing/useCreateExternalShareLink.d.ts +0 -90
  57. package/sharing/useCreateExternalShareLink.d.ts.map +0 -1
  58. package/sharing/useCreateExternalShareLink.js +0 -65
  59. package/sharing/useCreateExternalShareLink.js.map +0 -1
  60. package/sharing/useShareAgent.d.ts +0 -69
  61. package/sharing/useShareAgent.d.ts.map +0 -1
  62. package/sharing/useShareAgent.js +0 -42
  63. package/sharing/useShareAgent.js.map +0 -1
  64. package/src/sharing/__tests__/useAgentShare.test.tsx +0 -210
  65. package/src/sharing/__tests__/useCreateExternalShareLink.test.tsx +0 -194
  66. package/src/sharing/__tests__/useShareAgent.test.tsx +0 -131
  67. package/src/sharing/useAgentShare.ts +0 -105
  68. package/src/sharing/useCreateExternalShareLink.tsx +0 -141
  69. package/src/sharing/useShareAgent.tsx +0 -107
@@ -1,9 +1,10 @@
1
1
  import { describe, it, expect, vi, beforeAll, afterEach } from "vitest";
2
2
  import { render, screen, fireEvent, waitFor, cleanup } from "@testing-library/react";
3
3
  import type { ReactNode } from "react";
4
+ import { Code } from "@connectrpc/connect";
4
5
  import { AgentShareAudience } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v1/spec_pb";
5
6
  import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
6
- import type { AgentShareInput } from "@stigmer/sdk";
7
+ import { StigmerError, type AgentShareInput } from "@stigmer/sdk";
7
8
  import { StigmerContext } from "../../context";
8
9
  import { FetchCacheContext } from "../../internal/FetchCacheProvider";
9
10
  import { DeploymentModeContext } from "../../deployment-mode";
@@ -27,7 +28,6 @@ beforeAll(() => {
27
28
  afterEach(cleanup);
28
29
 
29
30
  interface MockOverrides {
30
- getByAgent?: (input: unknown) => Promise<unknown>;
31
31
  apply?: (input: AgentShareInput) => Promise<unknown>;
32
32
  rotateShareLink?: (input: unknown) => Promise<unknown>;
33
33
  getOrCreateBillingAccount?: (orgId: string) => Promise<unknown>;
@@ -37,9 +37,6 @@ interface MockOverrides {
37
37
  function createMockStigmer(overrides: MockOverrides = {}) {
38
38
  return {
39
39
  agentShare: {
40
- getByAgent:
41
- overrides.getByAgent ??
42
- vi.fn().mockResolvedValue({ totalCount: 0, items: [] }),
43
40
  apply: overrides.apply ?? vi.fn().mockResolvedValue({}),
44
41
  rotateShareLink:
45
42
  overrides.rotateShareLink ?? vi.fn().mockResolvedValue({}),
@@ -129,11 +126,7 @@ function makeShare(
129
126
  },
130
127
  spec: { agentRef: { org: "acme", slug: "support-agent" }, ...spec },
131
128
  ...(shareLinkToken !== undefined ? { status: { shareLinkToken } } : {}),
132
- };
133
- }
134
-
135
- function withShare(share: unknown) {
136
- return vi.fn().mockResolvedValue({ totalCount: 1, items: [share] });
129
+ } as never;
137
130
  }
138
131
 
139
132
  function orgSharedEnv(slug: string, name?: string) {
@@ -150,8 +143,8 @@ function orgSharedEnv(slug: string, name?: string) {
150
143
  const buildShareUrl = (org: string, slug: string) =>
151
144
  `https://app.example.com/chat/${org}/${slug}`;
152
145
 
153
- /** Render the open dialog and wait for the share load to settle. */
154
- async function renderOpenDialog(
146
+ /** Render the dialog open. Pass `share` for edit mode; omit for create mode. */
147
+ function renderOpenDialog(
155
148
  client: unknown,
156
149
  props?: Partial<Parameters<typeof ShareAgentDialog>[0]> & { mode?: "cloud" | "local" },
157
150
  ) {
@@ -167,96 +160,31 @@ async function renderOpenDialog(
167
160
  />
168
161
  </Providers>,
169
162
  );
170
- await waitFor(() =>
171
- expect(screen.queryByLabelText("Loading sharing settings")).toBeNull(),
172
- );
173
163
  }
174
164
 
175
165
  describe("ShareAgentDialog", () => {
176
- it("mounts no body while closed (share and billing fetches stay lazy)", () => {
177
- const getByAgent = vi.fn();
166
+ it("mounts no body while closed (billing fetch stays lazy)", () => {
178
167
  const getOrCreateBillingAccount = vi.fn();
179
168
  render(
180
- <Providers
181
- client={createMockStigmer({ getByAgent, getOrCreateBillingAccount })}
182
- >
169
+ <Providers client={createMockStigmer({ getOrCreateBillingAccount })}>
183
170
  <ShareAgentDialog
184
171
  open={false}
185
172
  onOpenChange={() => {}}
186
173
  agent={makeAgent()}
174
+ share={makeShare({ enabled: true })}
187
175
  buildShareUrl={buildShareUrl}
188
176
  />
189
177
  </Providers>,
190
178
  );
191
179
 
192
180
  expect(screen.queryByText("Share")).toBeNull();
193
- expect(getByAgent).not.toHaveBeenCalled();
194
181
  expect(getOrCreateBillingAccount).not.toHaveBeenCalled();
195
182
  });
196
183
 
197
- it("shows a loading state while the share resolves, then the form", async () => {
198
- let resolveLoad: (v: unknown) => void = () => {};
199
- const getByAgent = vi.fn().mockReturnValue(
200
- new Promise((resolve) => {
201
- resolveLoad = resolve;
202
- }),
203
- );
204
- render(
205
- <Providers client={createMockStigmer({ getByAgent })}>
206
- <ShareAgentDialog
207
- open
208
- onOpenChange={() => {}}
209
- agent={makeAgent()}
210
- buildShareUrl={buildShareUrl}
211
- />
212
- </Providers>,
213
- );
214
-
215
- expect(screen.getByLabelText("Loading sharing settings")).toBeTruthy();
216
- resolveLoad({ totalCount: 1, items: [makeShare({ enabled: true })] });
217
- await waitFor(() =>
218
- expect(
219
- screen.getByText("https://app.example.com/chat/acme/support-agent"),
220
- ).toBeTruthy(),
221
- );
222
- });
223
-
224
- it("offers retry when the share load fails", async () => {
225
- const share = makeShare({ enabled: true });
226
- const getByAgent = vi
227
- .fn()
228
- .mockRejectedValueOnce(new Error("backend unavailable"))
229
- .mockResolvedValueOnce({ totalCount: 1, items: [share] });
230
- render(
231
- <Providers client={createMockStigmer({ getByAgent })}>
232
- <ShareAgentDialog
233
- open
234
- onOpenChange={() => {}}
235
- agent={makeAgent()}
236
- buildShareUrl={buildShareUrl}
237
- />
238
- </Providers>,
239
- );
240
-
241
- // A failed load must never render a form that would create a share
242
- // over an existing one the dialog couldn't see.
243
- expect(
244
- await screen.findByText(/couldn't load this agent's sharing settings/i),
245
- ).toBeTruthy();
246
-
247
- fireEvent.click(screen.getByRole("button", { name: "Try again", hidden: true }));
248
- await waitFor(() =>
249
- expect(
250
- screen.getByText("https://app.example.com/chat/acme/support-agent"),
251
- ).toBeTruthy(),
252
- );
253
- });
254
-
255
- it("renders header, toggle, and the share link from buildShareUrl", async () => {
256
- const client = createMockStigmer({
257
- getByAgent: withShare(makeShare({ enabled: true })),
184
+ it("renders header, toggle, and the share link from buildShareUrl", () => {
185
+ renderOpenDialog(createMockStigmer(), {
186
+ share: makeShare({ enabled: true }),
258
187
  });
259
- await renderOpenDialog(client);
260
188
 
261
189
  expect(screen.getByText("Share")).toBeTruthy();
262
190
  expect(screen.getByText("Support Agent")).toBeTruthy();
@@ -266,77 +194,190 @@ describe("ShareAgentDialog", () => {
266
194
  ).toBeTruthy();
267
195
  });
268
196
 
269
- it("builds the link from the SHARE's slug when it differs from the agent's", async () => {
270
- // A manifest-renamed share: the hosted URL lives at the share's slug.
197
+ it("builds the link from the SHARE's slug when it differs from the agent's", () => {
198
+ // A renamed share: the hosted URL lives at the share's slug.
271
199
  const renamed = {
272
- ...makeShare({ enabled: true }),
200
+ ...(makeShare({ enabled: true }) as Record<string, unknown>),
273
201
  metadata: { id: "ash_1", org: "acme", slug: "help-desk", name: "Help Desk" },
274
- };
275
- const client = createMockStigmer({ getByAgent: withShare(renamed) });
276
- await renderOpenDialog(client);
202
+ } as never;
203
+ renderOpenDialog(createMockStigmer(), { share: renamed });
277
204
 
278
205
  expect(
279
206
  screen.getByText("https://app.example.com/chat/acme/help-desk"),
280
207
  ).toBeTruthy();
281
208
  });
282
209
 
283
- it("falls back to the relative /chat path when buildShareUrl is omitted", async () => {
284
- const client = createMockStigmer({
285
- getByAgent: withShare(makeShare({ enabled: true })),
210
+ it("falls back to the relative /chat path when buildShareUrl is omitted", () => {
211
+ renderOpenDialog(createMockStigmer(), {
212
+ share: makeShare({ enabled: true }),
213
+ buildShareUrl: undefined,
286
214
  });
287
- await renderOpenDialog(client, { buildShareUrl: undefined });
288
215
 
289
216
  expect(screen.getByText("/chat/acme/support-agent")).toBeTruthy();
290
217
  });
291
218
 
292
- describe("never-shared agent (no share yet)", () => {
293
- it("renders the off state with disabled copy affordances", async () => {
294
- const client = createMockStigmer();
295
- await renderOpenDialog(client);
219
+ describe("create mode (no share prop)", () => {
220
+ it("renders the create step with identity prefilled from the agent", () => {
221
+ renderOpenDialog(createMockStigmer());
296
222
 
297
223
  expect(
298
- screen.getByRole("switch", { hidden: true }).getAttribute("aria-checked"),
299
- ).toBe("false");
300
- const copy = screen.getByRole("button", {
301
- name: "Copy",
302
- hidden: true,
303
- }) as HTMLButtonElement;
304
- expect(copy.disabled).toBe(true);
305
- expect(
306
- screen.getByText(/sharing is off, so this link doesn't work yet/i),
224
+ screen.getByRole("heading", { name: "Create share", hidden: true }),
307
225
  ).toBeTruthy();
226
+ expect(
227
+ (screen.getByLabelText("Name", { selector: "input" }) as HTMLInputElement).value,
228
+ ).toBe("Support Agent");
229
+ expect(
230
+ (screen.getByLabelText("Slug", { selector: "input" }) as HTMLInputElement).value,
231
+ ).toBe("support-agent");
232
+ // No channel exists yet — no switch, no link, and the footer offers
233
+ // Cancel rather than Done.
234
+ expect(screen.queryByRole("switch", { hidden: true })).toBeNull();
235
+ expect(screen.getByText("Cancel")).toBeTruthy();
236
+ });
237
+
238
+ it("auto-derives the slug from the name until the slug is edited", () => {
239
+ renderOpenDialog(createMockStigmer());
240
+
241
+ const name = screen.getByLabelText("Name", { selector: "input" });
242
+ const slug = screen.getByLabelText("Slug", { selector: "input" }) as HTMLInputElement;
243
+
244
+ fireEvent.change(name, { target: { value: "Docs Site Widget" } });
245
+ expect(slug.value).toBe("docs-site-widget");
246
+
247
+ fireEvent.change(slug, { target: { value: "docs-widget" } });
248
+ fireEvent.change(name, { target: { value: "Renamed Again" } });
249
+ // Touched slug stays put.
250
+ expect(slug.value).toBe("docs-widget");
308
251
  });
309
252
 
310
- it("first enable creates the canonical share via apply", async () => {
253
+ it("creates the share live with the chosen identity, then becomes its editor", async () => {
311
254
  const apply = vi.fn().mockResolvedValue(makeShare({ enabled: true }));
312
- const client = createMockStigmer({ apply });
313
- await renderOpenDialog(client);
255
+ renderOpenDialog(createMockStigmer({ apply }));
314
256
 
315
- fireEvent.click(screen.getByRole("switch", { hidden: true }));
257
+ fireEvent.click(screen.getByRole("button", { name: "Create share", hidden: true }));
316
258
 
317
259
  await waitFor(() => expect(apply).toHaveBeenCalledTimes(1));
318
260
  const input = apply.mock.calls[0][0] as AgentShareInput;
319
- // Create identity: the agent's own org/slug/name (the server's D2
320
- // default made explicit) plus the agent reference.
321
261
  expect(input.org).toBe("acme");
322
262
  expect(input.slug).toBe("support-agent");
263
+ expect(input.name).toBe("Support Agent");
323
264
  expect(input.agentRef).toEqual({ org: "acme", slug: "support-agent" });
265
+ // One intent-click yields a live link: created enabled, public.
324
266
  expect(input.enabled).toBe(true);
267
+ expect(input.audience).toBe(AgentShareAudience.public);
325
268
 
269
+ // The dialog transitions to the editor on the created share.
326
270
  await waitFor(() =>
327
271
  expect(
328
- screen.getByRole("switch", { hidden: true }).getAttribute("aria-checked"),
329
- ).toBe("true"),
272
+ screen.getByText("https://app.example.com/chat/acme/support-agent"),
273
+ ).toBeTruthy(),
330
274
  );
275
+ expect(screen.getByText("Done")).toBeTruthy();
276
+ });
277
+
278
+ it("pins an (org, slug) collision to the slug field with a pick-another-slug remedy", async () => {
279
+ const apply = vi
280
+ .fn()
281
+ .mockRejectedValue(
282
+ new StigmerError("already-exists", "duplicate slug", Code.AlreadyExists),
283
+ );
284
+ renderOpenDialog(createMockStigmer({ apply }));
285
+
286
+ fireEvent.click(screen.getByRole("button", { name: "Create share", hidden: true }));
287
+
288
+ expect(
289
+ await screen.findByText(/pick a different slug/i),
290
+ ).toBeTruthy();
291
+ // Still on the create step — nothing was created.
292
+ expect(screen.queryByRole("switch", { hidden: true })).toBeNull();
293
+
294
+ // Editing the slug clears the collision so the user can retry.
295
+ fireEvent.change(screen.getByLabelText("Slug", { selector: "input" }), {
296
+ target: { value: "support-agent-2" },
297
+ });
298
+ expect(screen.queryByText(/pick a different slug/i)).toBeNull();
299
+ });
300
+
301
+ it("surfaces other server refusals verbatim (e.g. non-public dependencies)", async () => {
302
+ const apply = vi
303
+ .fn()
304
+ .mockRejectedValue(
305
+ new StigmerError(
306
+ "failed-precondition",
307
+ "cannot share acme/support-agent across organizations: it references resources that are not public: skill acme/internal-kb",
308
+ Code.FailedPrecondition,
309
+ ),
310
+ );
311
+ renderOpenDialog(createMockStigmer({ apply }), { shareOrg: "consumer-org" });
312
+
313
+ fireEvent.click(screen.getByRole("button", { name: "Create share", hidden: true }));
314
+
315
+ expect(
316
+ await screen.findByText(/resources that are not public/i),
317
+ ).toBeTruthy();
318
+ });
319
+
320
+ it("cross-org create: qualifies the agent, names the paying org, creates in the viewer's org", async () => {
321
+ const apply = vi.fn().mockResolvedValue({
322
+ metadata: {
323
+ id: "ash_ext",
324
+ org: "consumer-org",
325
+ slug: "support-agent",
326
+ name: "Support Agent",
327
+ },
328
+ spec: {
329
+ agentRef: { org: "acme", slug: "support-agent" },
330
+ enabled: true,
331
+ },
332
+ });
333
+ renderOpenDialog(createMockStigmer({ apply }), { shareOrg: "consumer-org" });
334
+
335
+ // The header names whose blueprint this channel serves.
336
+ expect(screen.getByText("acme/support-agent")).toBeTruthy();
337
+ // The create copy names the org that owns and pays for the channel.
338
+ expect(screen.getByText(/credits/)).toBeTruthy();
339
+
340
+ fireEvent.click(screen.getByRole("button", { name: "Create share", hidden: true }));
341
+
342
+ await waitFor(() => expect(apply).toHaveBeenCalledTimes(1));
343
+ const input = apply.mock.calls[0][0] as AgentShareInput;
344
+ expect(input.org).toBe("consumer-org");
345
+ expect(input.agentRef).toEqual({ org: "acme", slug: "support-agent" });
346
+
347
+ // The editor shows the sharing org's URL; cross-org shares are
348
+ // public-audience only, so no audience selector is offered.
349
+ await waitFor(() =>
350
+ expect(
351
+ screen.getByText("https://app.example.com/chat/consumer-org/support-agent"),
352
+ ).toBeTruthy(),
353
+ );
354
+ expect(screen.queryByRole("radiogroup", { hidden: true })).toBeNull();
331
355
  });
332
356
  });
333
357
 
334
- describe("Sharing-off state", () => {
335
- it("shows the reason on the Embed tab too", async () => {
336
- const client = createMockStigmer({
337
- getByAgent: withShare(makeShare({ enabled: false })),
358
+ describe("paused share (enabled: false)", () => {
359
+ it("renders the off state with disabled copy affordances", () => {
360
+ renderOpenDialog(createMockStigmer(), {
361
+ share: makeShare({ enabled: false }),
362
+ });
363
+
364
+ expect(
365
+ screen.getByRole("switch", { hidden: true }).getAttribute("aria-checked"),
366
+ ).toBe("false");
367
+ const copy = screen.getByRole("button", {
368
+ name: "Copy",
369
+ hidden: true,
370
+ }) as HTMLButtonElement;
371
+ expect(copy.disabled).toBe(true);
372
+ expect(
373
+ screen.getByText(/sharing is off, so this link doesn't work yet/i),
374
+ ).toBeTruthy();
375
+ });
376
+
377
+ it("shows the reason on the Embed tab too", () => {
378
+ renderOpenDialog(createMockStigmer(), {
379
+ share: makeShare({ enabled: false }),
338
380
  });
339
- await renderOpenDialog(client);
340
381
 
341
382
  fireEvent.click(screen.getByRole("tab", { name: /Embed/, hidden: true }));
342
383
  expect(
@@ -344,11 +385,10 @@ describe("ShareAgentDialog", () => {
344
385
  ).toBeTruthy();
345
386
  });
346
387
 
347
- it("drops the hint and enables copy once sharing is on", async () => {
348
- const client = createMockStigmer({
349
- getByAgent: withShare(makeShare({ enabled: true })),
388
+ it("drops the hint and enables copy once sharing is on", () => {
389
+ renderOpenDialog(createMockStigmer(), {
390
+ share: makeShare({ enabled: true }),
350
391
  });
351
- await renderOpenDialog(client);
352
392
 
353
393
  const copy = screen.getByRole("button", {
354
394
  name: "Copy",
@@ -359,11 +399,10 @@ describe("ShareAgentDialog", () => {
359
399
  });
360
400
  });
361
401
 
362
- it("shows the indexability warning", async () => {
363
- const client = createMockStigmer({
364
- getByAgent: withShare(makeShare({ enabled: true })),
402
+ it("shows the indexability warning", () => {
403
+ renderOpenDialog(createMockStigmer(), {
404
+ share: makeShare({ enabled: true }),
365
405
  });
366
- await renderOpenDialog(client);
367
406
 
368
407
  expect(
369
408
  screen.getByText(/forwarded and indexed by search engines/),
@@ -373,17 +412,13 @@ describe("ShareAgentDialog", () => {
373
412
  describe("Audience", () => {
374
413
  it("defaults to Public link and switching to Org members applies the full spec", async () => {
375
414
  const apply = vi.fn().mockResolvedValue({});
376
- const client = createMockStigmer({
377
- apply,
378
- getByAgent: withShare(
379
- makeShare({
380
- enabled: true,
381
- allowedOrigins: ["https://example.com"],
382
- messages: { rateLimited: "Easy there." },
383
- }),
384
- ),
415
+ renderOpenDialog(createMockStigmer({ apply }), {
416
+ share: makeShare({
417
+ enabled: true,
418
+ allowedOrigins: ["https://example.com"],
419
+ messages: { rateLimited: "Easy there." },
420
+ }),
385
421
  });
386
- await renderOpenDialog(client);
387
422
 
388
423
  const publicOption = screen.getByRole("radio", {
389
424
  name: "Public link",
@@ -402,21 +437,25 @@ describe("ShareAgentDialog", () => {
402
437
  expect(input.enabled).toBe(true);
403
438
  expect(input.allowedOrigins).toEqual(["https://example.com"]);
404
439
  expect(input.messages?.rateLimited).toBe("Easy there.");
440
+ // Edit keys on the existing share's identity — never a new row.
441
+ expect(input.org).toBe("acme");
442
+ expect(input.slug).toBe("support-agent");
405
443
  });
406
444
 
407
445
  it("switching to Org members drops credential bindings (public-audience only)", async () => {
408
446
  const apply = vi.fn().mockResolvedValue({});
409
- const client = createMockStigmer({
410
- apply,
411
- getByAgent: withShare(
412
- makeShare({
447
+ renderOpenDialog(
448
+ createMockStigmer({
449
+ apply,
450
+ environments: [orgSharedEnv("github-creds")],
451
+ }),
452
+ {
453
+ share: makeShare({
413
454
  enabled: true,
414
455
  environmentRefs: [{ org: "acme", slug: "github-creds" }],
415
456
  }),
416
- ),
417
- environments: [orgSharedEnv("github-creds")],
418
- });
419
- await renderOpenDialog(client);
457
+ },
458
+ );
420
459
 
421
460
  fireEvent.click(
422
461
  screen.getByRole("radio", { name: "Org members", hidden: true }),
@@ -430,13 +469,10 @@ describe("ShareAgentDialog", () => {
430
469
  expect(input.environmentRefs).toEqual([]);
431
470
  });
432
471
 
433
- it("renders org-audience copy: member link, revocation note, no indexability warning", async () => {
434
- const client = createMockStigmer({
435
- getByAgent: withShare(
436
- makeShare({ enabled: true, audience: AgentShareAudience.org }),
437
- ),
472
+ it("renders org-audience copy: member link, revocation note, no indexability warning", () => {
473
+ renderOpenDialog(createMockStigmer(), {
474
+ share: makeShare({ enabled: true, audience: AgentShareAudience.org }),
438
475
  });
439
- await renderOpenDialog(client);
440
476
 
441
477
  expect(screen.getByText("Organization members can chat")).toBeTruthy();
442
478
  expect(screen.getByText("Member chat link")).toBeTruthy();
@@ -448,13 +484,10 @@ describe("ShareAgentDialog", () => {
448
484
  ).toBeNull();
449
485
  });
450
486
 
451
- it("replaces the Embed tab with a public-only explanation for the org audience", async () => {
452
- const client = createMockStigmer({
453
- getByAgent: withShare(
454
- makeShare({ enabled: true, audience: AgentShareAudience.org }),
455
- ),
487
+ it("replaces the Embed tab with a public-only explanation for the org audience", () => {
488
+ renderOpenDialog(createMockStigmer(), {
489
+ share: makeShare({ enabled: true, audience: AgentShareAudience.org }),
456
490
  });
457
- await renderOpenDialog(client);
458
491
 
459
492
  fireEvent.click(screen.getByRole("tab", { name: /Embed/, hidden: true }));
460
493
  expect(
@@ -464,14 +497,22 @@ describe("ShareAgentDialog", () => {
464
497
  });
465
498
  });
466
499
 
467
- describe("cross-org mode (shareOrg — decision 013)", () => {
468
- it("qualifies the agent in the header and hides the audience selector", async () => {
469
- // No share yet in the consumer org: the owner's share exists but
470
- // belongs to acme, so the consumer's dialog starts never-shared.
471
- const client = createMockStigmer({
472
- getByAgent: withShare(makeShare({ enabled: true })),
473
- });
474
- await renderOpenDialog(client, { shareOrg: "consumer-org" });
500
+ describe("cross-org edit mode (share org differs from the agent's — decision 013)", () => {
501
+ const externalShare = {
502
+ metadata: {
503
+ id: "ash_ext",
504
+ org: "consumer-org",
505
+ slug: "support-agent",
506
+ name: "Support Agent",
507
+ },
508
+ spec: {
509
+ agentRef: { org: "acme", slug: "support-agent" },
510
+ enabled: true,
511
+ },
512
+ } as never;
513
+
514
+ it("qualifies the agent in the header and hides the audience selector", () => {
515
+ renderOpenDialog(createMockStigmer(), { share: externalShare });
475
516
 
476
517
  // The header names whose blueprint this channel serves.
477
518
  expect(screen.getByText("acme/support-agent")).toBeTruthy();
@@ -479,33 +520,20 @@ describe("ShareAgentDialog", () => {
479
520
  expect(screen.queryByRole("radiogroup", { hidden: true })).toBeNull();
480
521
  });
481
522
 
482
- it("builds the link, billing line, and create identity from the sharing org", async () => {
483
- const apply = vi.fn().mockResolvedValue({});
484
- const client = createMockStigmer({ apply });
485
- await renderOpenDialog(client, { shareOrg: "consumer-org" });
523
+ it("builds the link and billing line from the sharing org", () => {
524
+ renderOpenDialog(createMockStigmer(), { share: externalShare });
486
525
 
487
- // The hosted URL lives in the sharing org's namespace even before
488
- // the first save.
489
526
  expect(
490
527
  screen.getByText("https://app.example.com/chat/consumer-org/support-agent"),
491
528
  ).toBeTruthy();
492
529
  // Who-pays names the sharing org, not the agent's.
493
530
  expect(screen.getByText("consumer-org")).toBeTruthy();
494
-
495
- fireEvent.click(screen.getByRole("switch", { hidden: true }));
496
-
497
- await waitFor(() => expect(apply).toHaveBeenCalledTimes(1));
498
- const input = apply.mock.calls[0][0] as AgentShareInput;
499
- expect(input.org).toBe("consumer-org");
500
- expect(input.agentRef).toEqual({ org: "acme", slug: "support-agent" });
501
- expect(input.audience).toBe(AgentShareAudience.public);
502
531
  });
503
532
 
504
- it("same-org dialogs are unchanged when shareOrg equals the agent's org", async () => {
505
- const client = createMockStigmer({
506
- getByAgent: withShare(makeShare({ enabled: true })),
533
+ it("same-org dialogs are unchanged when the share org equals the agent's", () => {
534
+ renderOpenDialog(createMockStigmer(), {
535
+ share: makeShare({ enabled: true }),
507
536
  });
508
- await renderOpenDialog(client, { shareOrg: "acme" });
509
537
 
510
538
  expect(screen.getByText("Support Agent")).toBeTruthy();
511
539
  expect(screen.getByRole("radiogroup", { hidden: true })).toBeTruthy();
@@ -515,17 +543,14 @@ describe("ShareAgentDialog", () => {
515
543
  it("enabling applies the complete spec and notifies the host", async () => {
516
544
  const apply = vi.fn().mockResolvedValue({});
517
545
  const onSharingChanged = vi.fn();
518
- const client = createMockStigmer({
519
- apply,
520
- getByAgent: withShare(
521
- makeShare({
522
- enabled: false,
523
- allowedOrigins: ["https://example.com"],
524
- messages: { rateLimited: "Easy there." },
525
- }),
526
- ),
546
+ renderOpenDialog(createMockStigmer({ apply }), {
547
+ onSharingChanged,
548
+ share: makeShare({
549
+ enabled: false,
550
+ allowedOrigins: ["https://example.com"],
551
+ messages: { rateLimited: "Easy there." },
552
+ }),
527
553
  });
528
- await renderOpenDialog(client, { onSharingChanged });
529
554
 
530
555
  fireEvent.click(screen.getByRole("switch", { hidden: true }));
531
556
 
@@ -547,11 +572,9 @@ describe("ShareAgentDialog", () => {
547
572
  allowedOrigins: ["https://normalized.example.com"],
548
573
  }),
549
574
  );
550
- const client = createMockStigmer({
551
- apply,
552
- getByAgent: withShare(makeShare({ enabled: false })),
575
+ renderOpenDialog(createMockStigmer({ apply }), {
576
+ share: makeShare({ enabled: false }),
553
577
  });
554
- await renderOpenDialog(client);
555
578
 
556
579
  fireEvent.click(screen.getByRole("switch", { hidden: true }));
557
580
  await waitFor(() =>
@@ -565,11 +588,11 @@ describe("ShareAgentDialog", () => {
565
588
  });
566
589
 
567
590
  describe("Tool credentials", () => {
568
- it("warns needs-credentials for a tool-using share without bindings", async () => {
569
- const client = createMockStigmer({
570
- getByAgent: withShare(makeShare({ enabled: true })),
591
+ it("warns needs-credentials for a tool-using share without bindings", () => {
592
+ renderOpenDialog(createMockStigmer(), {
593
+ agent: makeAgent({ mcpUsages: true }),
594
+ share: makeShare({ enabled: true }),
571
595
  });
572
- await renderOpenDialog(client, { agent: makeAgent({ mcpUsages: true }) });
573
596
 
574
597
  expect(
575
598
  screen.getByText(/no credentials are bound to this share/i),
@@ -578,12 +601,16 @@ describe("ShareAgentDialog", () => {
578
601
 
579
602
  it("binds an org-shared environment by applying the appended refs", async () => {
580
603
  const apply = vi.fn().mockResolvedValue({});
581
- const client = createMockStigmer({
582
- apply,
583
- getByAgent: withShare(makeShare({ enabled: true })),
584
- environments: [orgSharedEnv("github-creds", "GitHub Creds")],
585
- });
586
- await renderOpenDialog(client, { agent: makeAgent({ mcpUsages: true }) });
604
+ renderOpenDialog(
605
+ createMockStigmer({
606
+ apply,
607
+ environments: [orgSharedEnv("github-creds", "GitHub Creds")],
608
+ }),
609
+ {
610
+ agent: makeAgent({ mcpUsages: true }),
611
+ share: makeShare({ enabled: true }),
612
+ },
613
+ );
587
614
 
588
615
  // The section is expanded by default for tool-using agents.
589
616
  const picker = await screen.findByLabelText("Add environment", {
@@ -610,11 +637,15 @@ describe("ShareAgentDialog", () => {
610
637
  },
611
638
  spec: { description: "" },
612
639
  };
613
- const client = createMockStigmer({
614
- getByAgent: withShare(makeShare({ enabled: true })),
615
- environments: [orgSharedEnv("github-creds", "GitHub Creds"), privateEnv],
616
- });
617
- await renderOpenDialog(client, { agent: makeAgent({ mcpUsages: true }) });
640
+ renderOpenDialog(
641
+ createMockStigmer({
642
+ environments: [orgSharedEnv("github-creds", "GitHub Creds"), privateEnv],
643
+ }),
644
+ {
645
+ agent: makeAgent({ mcpUsages: true }),
646
+ share: makeShare({ enabled: true }),
647
+ },
648
+ );
618
649
 
619
650
  await screen.findByLabelText("Add environment", { selector: "select" });
620
651
  // Private environments are guest-unusable (the runtime merge skips
@@ -623,24 +654,21 @@ describe("ShareAgentDialog", () => {
623
654
  expect(screen.queryByText("Personal Creds")).toBeNull();
624
655
  });
625
656
 
626
- it("hides the section entirely for org-audience shares", async () => {
627
- const client = createMockStigmer({
628
- getByAgent: withShare(
629
- makeShare({ enabled: true, audience: AgentShareAudience.org }),
630
- ),
657
+ it("hides the section entirely for org-audience shares", () => {
658
+ renderOpenDialog(createMockStigmer(), {
659
+ agent: makeAgent({ mcpUsages: true }),
660
+ share: makeShare({ enabled: true, audience: AgentShareAudience.org }),
631
661
  });
632
- await renderOpenDialog(client, { agent: makeAgent({ mcpUsages: true }) });
633
662
 
634
663
  expect(screen.queryByText("Tool credentials")).toBeNull();
635
664
  });
636
665
  });
637
666
 
638
667
  describe("Embed tab", () => {
639
- it("shows the one-line script snippet: loader from the app origin + <stigmer-agent>", async () => {
640
- const client = createMockStigmer({
641
- getByAgent: withShare(makeShare({ enabled: true })),
668
+ it("shows the one-line script snippet: loader from the app origin + <stigmer-agent>", () => {
669
+ renderOpenDialog(createMockStigmer(), {
670
+ share: makeShare({ enabled: true }),
642
671
  });
643
- await renderOpenDialog(client);
644
672
 
645
673
  fireEvent.click(screen.getByRole("tab", { name: /Embed/, hidden: true }));
646
674
  // The loader must be served from the SAME origin as the share URL —
@@ -657,11 +685,10 @@ describe("ShareAgentDialog", () => {
657
685
  ).toBeTruthy();
658
686
  });
659
687
 
660
- it("keeps the iframe snippet available as the collapsed no-JavaScript alternative", async () => {
661
- const client = createMockStigmer({
662
- getByAgent: withShare(makeShare({ enabled: true })),
688
+ it("keeps the iframe snippet available as the collapsed no-JavaScript alternative", () => {
689
+ renderOpenDialog(createMockStigmer(), {
690
+ share: makeShare({ enabled: true }),
663
691
  });
664
- await renderOpenDialog(client);
665
692
 
666
693
  fireEvent.click(screen.getByRole("tab", { name: /Embed/, hidden: true }));
667
694
  // Collapsed by default — the script snippet is the primary path.
@@ -682,11 +709,9 @@ describe("ShareAgentDialog", () => {
682
709
 
683
710
  it("rejects an invalid origin without calling the RPC", async () => {
684
711
  const apply = vi.fn();
685
- const client = createMockStigmer({
686
- apply,
687
- getByAgent: withShare(makeShare({ enabled: true })),
712
+ renderOpenDialog(createMockStigmer({ apply }), {
713
+ share: makeShare({ enabled: true }),
688
714
  });
689
- await renderOpenDialog(client);
690
715
 
691
716
  fireEvent.click(screen.getByRole("tab", { name: /Embed/, hidden: true }));
692
717
  const input = screen.getByLabelText("Add allowed origin");
@@ -701,16 +726,12 @@ describe("ShareAgentDialog", () => {
701
726
 
702
727
  it("adds a valid origin by applying the appended list", async () => {
703
728
  const apply = vi.fn().mockResolvedValue({});
704
- const client = createMockStigmer({
705
- apply,
706
- getByAgent: withShare(
707
- makeShare({
708
- enabled: true,
709
- allowedOrigins: ["https://existing.example.com"],
710
- }),
711
- ),
729
+ renderOpenDialog(createMockStigmer({ apply }), {
730
+ share: makeShare({
731
+ enabled: true,
732
+ allowedOrigins: ["https://existing.example.com"],
733
+ }),
712
734
  });
713
- await renderOpenDialog(client);
714
735
 
715
736
  fireEvent.click(screen.getByRole("tab", { name: /Embed/, hidden: true }));
716
737
  fireEvent.change(screen.getByLabelText("Add allowed origin"), {
@@ -730,16 +751,12 @@ describe("ShareAgentDialog", () => {
730
751
 
731
752
  it("rejects a duplicate origin", async () => {
732
753
  const apply = vi.fn();
733
- const client = createMockStigmer({
734
- apply,
735
- getByAgent: withShare(
736
- makeShare({
737
- enabled: true,
738
- allowedOrigins: ["https://example.com"],
739
- }),
740
- ),
754
+ renderOpenDialog(createMockStigmer({ apply }), {
755
+ share: makeShare({
756
+ enabled: true,
757
+ allowedOrigins: ["https://example.com"],
758
+ }),
741
759
  });
742
- await renderOpenDialog(client);
743
760
 
744
761
  fireEvent.click(screen.getByRole("tab", { name: /Embed/, hidden: true }));
745
762
  fireEvent.change(screen.getByLabelText("Add allowed origin"), {
@@ -753,16 +770,12 @@ describe("ShareAgentDialog", () => {
753
770
 
754
771
  it("removes an origin by applying the filtered list", async () => {
755
772
  const apply = vi.fn().mockResolvedValue({});
756
- const client = createMockStigmer({
757
- apply,
758
- getByAgent: withShare(
759
- makeShare({
760
- enabled: true,
761
- allowedOrigins: ["https://a.example.com", "https://b.example.com"],
762
- }),
763
- ),
773
+ renderOpenDialog(createMockStigmer({ apply }), {
774
+ share: makeShare({
775
+ enabled: true,
776
+ allowedOrigins: ["https://a.example.com", "https://b.example.com"],
777
+ }),
764
778
  });
765
- await renderOpenDialog(client);
766
779
 
767
780
  fireEvent.click(screen.getByRole("tab", { name: /Embed/, hidden: true }));
768
781
  fireEvent.click(screen.getByLabelText("Remove https://a.example.com"));
@@ -776,16 +789,12 @@ describe("ShareAgentDialog", () => {
776
789
  describe("visitor messages", () => {
777
790
  it("saves edited messages as part of the complete spec", async () => {
778
791
  const apply = vi.fn().mockResolvedValue({});
779
- const client = createMockStigmer({
780
- apply,
781
- getByAgent: withShare(
782
- makeShare({
783
- enabled: true,
784
- allowedOrigins: ["https://example.com"],
785
- }),
786
- ),
792
+ renderOpenDialog(createMockStigmer({ apply }), {
793
+ share: makeShare({
794
+ enabled: true,
795
+ allowedOrigins: ["https://example.com"],
796
+ }),
787
797
  });
788
- await renderOpenDialog(client);
789
798
 
790
799
  fireEvent.click(screen.getByText("Customize visitor messages"));
791
800
  fireEvent.change(screen.getByLabelText(/Rate limited/), {
@@ -800,11 +809,10 @@ describe("ShareAgentDialog", () => {
800
809
  expect(input.allowedOrigins).toEqual(["https://example.com"]);
801
810
  });
802
811
 
803
- it("caps each message at 300 characters", async () => {
804
- const client = createMockStigmer({
805
- getByAgent: withShare(makeShare({ enabled: true })),
812
+ it("caps each message at 300 characters", () => {
813
+ renderOpenDialog(createMockStigmer(), {
814
+ share: makeShare({ enabled: true }),
806
815
  });
807
- await renderOpenDialog(client);
808
816
 
809
817
  fireEvent.click(screen.getByText("Customize visitor messages"));
810
818
  const field = screen.getByLabelText(/Rate limited/) as HTMLTextAreaElement;
@@ -818,11 +826,10 @@ describe("ShareAgentDialog", () => {
818
826
  const getOrCreateBillingAccount = vi.fn().mockResolvedValue({
819
827
  balance: { availableMicros: BigInt(12_500_000) },
820
828
  });
821
- const client = createMockStigmer({
822
- getOrCreateBillingAccount,
823
- getByAgent: withShare(makeShare({ enabled: true })),
829
+ renderOpenDialog(createMockStigmer({ getOrCreateBillingAccount }), {
830
+ mode: "cloud",
831
+ share: makeShare({ enabled: true }),
824
832
  });
825
- await renderOpenDialog(client, { mode: "cloud" });
826
833
 
827
834
  expect(screen.getByText(/Visitors chat on/)).toBeTruthy();
828
835
  await waitFor(() =>
@@ -831,13 +838,12 @@ describe("ShareAgentDialog", () => {
831
838
  expect(getOrCreateBillingAccount).toHaveBeenCalledWith("acme");
832
839
  });
833
840
 
834
- it("degrades to the who-pays line alone in local mode (no billing fetch)", async () => {
841
+ it("degrades to the who-pays line alone in local mode (no billing fetch)", () => {
835
842
  const getOrCreateBillingAccount = vi.fn();
836
- const client = createMockStigmer({
837
- getOrCreateBillingAccount,
838
- getByAgent: withShare(makeShare({ enabled: true })),
843
+ renderOpenDialog(createMockStigmer({ getOrCreateBillingAccount }), {
844
+ mode: "local",
845
+ share: makeShare({ enabled: true }),
839
846
  });
840
- await renderOpenDialog(client, { mode: "local" });
841
847
 
842
848
  expect(screen.getByText(/Visitors chat on/)).toBeTruthy();
843
849
  expect(screen.queryByText(/available/)).toBeNull();
@@ -848,11 +854,10 @@ describe("ShareAgentDialog", () => {
848
854
  const getOrCreateBillingAccount = vi
849
855
  .fn()
850
856
  .mockRejectedValue(new Error("billing unavailable"));
851
- const client = createMockStigmer({
852
- getOrCreateBillingAccount,
853
- getByAgent: withShare(makeShare({ enabled: true })),
857
+ renderOpenDialog(createMockStigmer({ getOrCreateBillingAccount }), {
858
+ mode: "cloud",
859
+ share: makeShare({ enabled: true }),
854
860
  });
855
- await renderOpenDialog(client, { mode: "cloud" });
856
861
 
857
862
  await waitFor(() => expect(getOrCreateBillingAccount).toHaveBeenCalled());
858
863
  expect(screen.getByText(/Visitors chat on/)).toBeTruthy();
@@ -862,11 +867,10 @@ describe("ShareAgentDialog", () => {
862
867
  });
863
868
 
864
869
  describe("Developer tab", () => {
865
- it("shows the platform client snippet and docs link", async () => {
866
- const client = createMockStigmer({
867
- getByAgent: withShare(makeShare({ enabled: true })),
870
+ it("shows the platform client snippet and docs link", () => {
871
+ renderOpenDialog(createMockStigmer(), {
872
+ share: makeShare({ enabled: true }),
868
873
  });
869
- await renderOpenDialog(client);
870
874
 
871
875
  fireEvent.click(screen.getByRole("tab", { name: /Developer/, hidden: true }));
872
876
  expect(screen.getByText(/createPlatformClientAuth/)).toBeTruthy();
@@ -875,24 +879,24 @@ describe("ShareAgentDialog", () => {
875
879
  });
876
880
  });
877
881
 
878
- it("renders in-flow without showModal when modal is false", async () => {
882
+ it("renders in-flow without showModal when modal is false", () => {
879
883
  const showModal = vi.spyOn(HTMLDialogElement.prototype, "showModal");
880
- const client = createMockStigmer({
881
- getByAgent: withShare(makeShare({ enabled: true })),
884
+ renderOpenDialog(createMockStigmer(), {
885
+ modal: false,
886
+ share: makeShare({ enabled: true }),
882
887
  });
883
- await renderOpenDialog(client, { modal: false });
884
888
 
885
889
  expect(screen.getByText("Share")).toBeTruthy();
886
890
  expect(showModal).not.toHaveBeenCalled();
887
891
  showModal.mockRestore();
888
892
  });
889
893
 
890
- it("requests close via Done and the close affordance", async () => {
894
+ it("requests close via Done and the close affordance", () => {
891
895
  const onOpenChange = vi.fn();
892
- const client = createMockStigmer({
893
- getByAgent: withShare(makeShare({ enabled: true })),
896
+ renderOpenDialog(createMockStigmer(), {
897
+ onOpenChange,
898
+ share: makeShare({ enabled: true }),
894
899
  });
895
- await renderOpenDialog(client, { onOpenChange });
896
900
 
897
901
  screen.getByText("Done").click();
898
902
  expect(onOpenChange).toHaveBeenCalledWith(false);
@@ -903,11 +907,10 @@ describe("ShareAgentDialog", () => {
903
907
  });
904
908
 
905
909
  describe("Reset link (rotatable share token)", () => {
906
- it("appends the status token to the shown link and embed snippet", async () => {
907
- const client = createMockStigmer({
908
- getByAgent: withShare(makeShare({ enabled: true }, "tok123")),
910
+ it("appends the status token to the shown link and embed snippet", () => {
911
+ renderOpenDialog(createMockStigmer(), {
912
+ share: makeShare({ enabled: true }, "tok123"),
909
913
  });
910
- await renderOpenDialog(client);
911
914
 
912
915
  expect(
913
916
  screen.getByText("https://app.example.com/chat/acme/support-agent?k=tok123"),
@@ -922,11 +925,10 @@ describe("ShareAgentDialog", () => {
922
925
  .fn()
923
926
  .mockResolvedValue(makeShare({ enabled: true }, "fresh-token"));
924
927
  const onSharingChanged = vi.fn();
925
- const client = createMockStigmer({
926
- rotateShareLink,
927
- getByAgent: withShare(makeShare({ enabled: true })),
928
+ renderOpenDialog(createMockStigmer({ rotateShareLink }), {
929
+ onSharingChanged,
930
+ share: makeShare({ enabled: true }),
928
931
  });
929
- await renderOpenDialog(client, { onSharingChanged });
930
932
 
931
933
  // A plain link shows no token before the reset.
932
934
  expect(
@@ -943,23 +945,20 @@ describe("ShareAgentDialog", () => {
943
945
  ).toBeTruthy(),
944
946
  );
945
947
  expect(rotateShareLink).toHaveBeenCalledTimes(1);
946
- // The rotation targets the loaded share by its own id.
948
+ // The rotation targets the given share by its own id.
947
949
  expect(
948
950
  (rotateShareLink.mock.calls[0][0] as { resourceId: string }).resourceId,
949
951
  ).toBe("ash_1");
950
952
  expect(onSharingChanged).toHaveBeenCalled();
951
953
  });
952
954
 
953
- it("hides the Reset control and the token for org-members-only shares", async () => {
954
- const client = createMockStigmer({
955
- getByAgent: withShare(
956
- makeShare(
957
- { enabled: true, audience: AgentShareAudience.org },
958
- "tok123",
959
- ),
955
+ it("hides the Reset control and the token for org-members-only shares", () => {
956
+ renderOpenDialog(createMockStigmer(), {
957
+ share: makeShare(
958
+ { enabled: true, audience: AgentShareAudience.org },
959
+ "tok123",
960
960
  ),
961
961
  });
962
- await renderOpenDialog(client);
963
962
 
964
963
  // Org access is gated by membership, not the link token: the member
965
964
  // link stays clean and the Reset lever is not offered.