@sentientui/mcp 0.7.0 → 0.8.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.
package/dist/lib.cjs CHANGED
@@ -36,7 +36,7 @@ var import_node_module = require("module");
36
36
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
37
37
 
38
38
  // src/tools/projects.ts
39
- var import_zod = require("zod");
39
+ var import_zod2 = require("zod");
40
40
 
41
41
  // src/api-client.ts
42
42
  var ApiError = class extends Error {
@@ -45,16 +45,15 @@ var ApiError = class extends Error {
45
45
  this.status = status;
46
46
  this.name = "ApiError";
47
47
  }
48
- status;
49
48
  };
50
49
  var ApiClient = class {
51
- baseUrl;
52
- apiKey;
53
50
  constructor(opts) {
51
+ var _a;
54
52
  this.apiKey = opts.apiKey;
55
- this.baseUrl = (opts.baseUrl ?? "https://api.sentient-ui.com").replace(/\/$/, "");
53
+ this.baseUrl = ((_a = opts.baseUrl) != null ? _a : "https://api.sentient-ui.com").replace(/\/$/, "");
56
54
  }
57
55
  async get(path) {
56
+ var _a;
58
57
  const res = await fetch(`${this.baseUrl}/v1/mgmt${path}`, {
59
58
  headers: {
60
59
  authorization: `Bearer ${this.apiKey}`,
@@ -63,11 +62,12 @@ var ApiClient = class {
63
62
  });
64
63
  if (!res.ok) {
65
64
  const body = await res.json().catch(() => ({}));
66
- throw new ApiError(res.status, String(body.error ?? res.statusText));
65
+ throw new ApiError(res.status, String((_a = body.error) != null ? _a : res.statusText));
67
66
  }
68
67
  return res.json();
69
68
  }
70
69
  async post(path, body) {
70
+ var _a;
71
71
  const res = await fetch(`${this.baseUrl}/v1/mgmt${path}`, {
72
72
  method: "POST",
73
73
  headers: {
@@ -78,14 +78,51 @@ var ApiClient = class {
78
78
  });
79
79
  if (!res.ok) {
80
80
  const errBody = await res.json().catch(() => ({}));
81
- throw new ApiError(res.status, String(errBody.error ?? res.statusText));
81
+ throw new ApiError(res.status, String((_a = errBody.error) != null ? _a : res.statusText));
82
82
  }
83
83
  return res.json();
84
84
  }
85
85
  };
86
86
 
87
- // src/tools/projects.ts
87
+ // src/tools/common.ts
88
+ var import_zod = require("zod");
88
89
  var projectIdSchema = import_zod.z.string().uuid().describe("The project UUID");
90
+ function apiErrorGuidance(err) {
91
+ switch (err.message) {
92
+ case "insufficient_scope":
93
+ return "This action needs an account login. Connect via the hosted MCP URL (https://api.sentient-ui.com/mcp) and sign in \u2014 a project-scoped server key (sk_\u2026) or anonymous demo token cannot do this.";
94
+ case "demo_read_only":
95
+ return "Demo mode is read-only. Create a SentientUI account and sign in (or use a project server key) to make changes.";
96
+ case "insufficient_role":
97
+ return "Your account role does not permit this action \u2014 it needs the account owner or an admin.";
98
+ default:
99
+ break;
100
+ }
101
+ if (err.status === 402) {
102
+ return `This feature requires a higher plan (${err.message}). Upgrade your SentientUI plan, then try again.`;
103
+ }
104
+ if (err.status === 403) {
105
+ return `Access denied (${err.message}). Check that your key or login has access to this project.`;
106
+ }
107
+ return null;
108
+ }
109
+ function withApiErrorGuidance(fn) {
110
+ return async (args) => {
111
+ try {
112
+ return await fn(args);
113
+ } catch (err) {
114
+ if (err instanceof ApiError) {
115
+ const guidance = apiErrorGuidance(err);
116
+ if (guidance) {
117
+ return { content: [{ type: "text", text: guidance }], isError: true };
118
+ }
119
+ }
120
+ throw err;
121
+ }
122
+ };
123
+ }
124
+
125
+ // src/tools/projects.ts
89
126
  function createProjectGuidance(err) {
90
127
  switch (err.message) {
91
128
  case "insufficient_scope":
@@ -109,16 +146,16 @@ function registerProjectTools(server, client) {
109
146
  title: "Create project",
110
147
  description: "Create a NEW SentientUI project (onboarding). Returns the project id and its pk_ public key for the SDK. Requires an account login: this works when connected via OAuth (the hosted MCP URL) but NOT with a project-scoped sk_ server key or an anonymous demo token. After it succeeds, call get_integration_guide and help the user install @sentientui/react with the returned key.",
111
148
  inputSchema: {
112
- name: import_zod.z.string().min(1).describe("Human-readable project name"),
113
- contextType: import_zod.z.enum(["saas", "ecommerce", "marketing", "internal"]).optional().describe("What kind of product this is; defaults to saas"),
114
- framework: import_zod.z.enum(["next", "react", "core"]).optional().describe("How the site is built \u2014 next, react, or core (website builder/CMS); defaults to next"),
115
- websiteUrl: import_zod.z.string().optional().describe("Production site origin to allow-list so the SDK's events aren't origin-blocked on day one")
149
+ name: import_zod2.z.string().min(1).describe("Human-readable project name"),
150
+ contextType: import_zod2.z.enum(["saas", "ecommerce", "marketing", "landing", "internal"]).optional().describe("What kind of product this is; defaults to saas"),
151
+ framework: import_zod2.z.enum(["next", "react", "core"]).optional().describe("How the site is built \u2014 next, react, or core (website builder/CMS); defaults to next"),
152
+ websiteUrl: import_zod2.z.string().optional().describe("Production site origin to allow-list so the SDK's events aren't origin-blocked on day one")
116
153
  },
117
154
  outputSchema: {
118
- projectId: import_zod.z.string().describe("The new project UUID"),
119
- publicKey: import_zod.z.string().describe("The pk_ public key to configure the SDK with"),
120
- name: import_zod.z.string().describe("The project name"),
121
- contextType: import_zod.z.string().describe("The resolved context type")
155
+ projectId: import_zod2.z.string().describe("The new project UUID"),
156
+ publicKey: import_zod2.z.string().describe("The pk_ public key to configure the SDK with"),
157
+ name: import_zod2.z.string().describe("The project name"),
158
+ contextType: import_zod2.z.string().describe("The resolved context type")
122
159
  },
123
160
  annotations: {
124
161
  readOnlyHint: false,
@@ -135,7 +172,7 @@ function registerProjectTools(server, client) {
135
172
  framework,
136
173
  origin: websiteUrl
137
174
  });
138
- const resolvedContextType = contextType ?? "saas";
175
+ const resolvedContextType = contextType != null ? contextType : "saas";
139
176
  return {
140
177
  content: [{
141
178
  type: "text",
@@ -170,12 +207,12 @@ function registerProjectTools(server, client) {
170
207
  description: "List all SentientUI projects for the authenticated account.",
171
208
  inputSchema: {},
172
209
  outputSchema: {
173
- projects: import_zod.z.array(
174
- import_zod.z.object({
175
- id: import_zod.z.string().describe("Project UUID"),
176
- name: import_zod.z.string(),
177
- contextType: import_zod.z.string(),
178
- createdAt: import_zod.z.string().describe("ISO date (YYYY-MM-DD)")
210
+ projects: import_zod2.z.array(
211
+ import_zod2.z.object({
212
+ id: import_zod2.z.string().describe("Project UUID"),
213
+ name: import_zod2.z.string(),
214
+ contextType: import_zod2.z.string(),
215
+ createdAt: import_zod2.z.string().describe("ISO date (YYYY-MM-DD)")
179
216
  })
180
217
  ).describe("All projects for the account (empty if none)")
181
218
  },
@@ -185,7 +222,7 @@ function registerProjectTools(server, client) {
185
222
  openWorldHint: false
186
223
  }
187
224
  },
188
- async () => {
225
+ withApiErrorGuidance(async () => {
189
226
  const projects = await client.get("/projects");
190
227
  const text = projects.length === 0 ? "No projects found." : projects.map(
191
228
  (p) => `- ${p.name} (id: ${p.id}, type: ${p.context_type}, created: ${p.created_at.slice(0, 10)})`
@@ -201,7 +238,7 @@ function registerProjectTools(server, client) {
201
238
  }))
202
239
  }
203
240
  };
204
- }
241
+ })
205
242
  );
206
243
  server.registerTool(
207
244
  "get_project_stats",
@@ -210,11 +247,11 @@ function registerProjectTools(server, client) {
210
247
  description: "Get health stats for a project: event volume, session count, agent calls, and status.",
211
248
  inputSchema: { projectId: projectIdSchema },
212
249
  outputSchema: {
213
- status: import_zod.z.string().describe("Overall project health status"),
214
- events24h: import_zod.z.number().describe("Events in the last 24 hours"),
215
- sessions24h: import_zod.z.number().describe("Sessions in the last 24 hours"),
216
- agentCalls: import_zod.z.number().describe("Total agent (MCP/API) calls"),
217
- lastEventAt: import_zod.z.string().nullable().describe("ISO timestamp of the last event, or null")
250
+ status: import_zod2.z.string().describe("Overall project health status"),
251
+ events24h: import_zod2.z.number().describe("Events in the last 24 hours"),
252
+ sessions24h: import_zod2.z.number().describe("Sessions in the last 24 hours"),
253
+ agentCalls: import_zod2.z.number().describe("Total agent (MCP/API) calls"),
254
+ lastEventAt: import_zod2.z.string().nullable().describe("ISO timestamp of the last event, or null")
218
255
  },
219
256
  annotations: {
220
257
  readOnlyHint: true,
@@ -222,7 +259,8 @@ function registerProjectTools(server, client) {
222
259
  openWorldHint: false
223
260
  }
224
261
  },
225
- async ({ projectId }) => {
262
+ withApiErrorGuidance(async ({ projectId }) => {
263
+ var _a;
226
264
  const id = encodeURIComponent(projectId);
227
265
  const stats = await client.get(`/projects/${id}/health`);
228
266
  const text = [
@@ -230,7 +268,7 @@ function registerProjectTools(server, client) {
230
268
  `Events (24h): ${stats.events24h}`,
231
269
  `Sessions (24h): ${stats.sessions24h}`,
232
270
  `Agent calls (total): ${stats.agentCalls}`,
233
- `Last event: ${stats.lastEventAt ?? "never"}`
271
+ `Last event: ${(_a = stats.lastEventAt) != null ? _a : "never"}`
234
272
  ].join("\n");
235
273
  return {
236
274
  content: [{ type: "text", text }],
@@ -242,12 +280,12 @@ function registerProjectTools(server, client) {
242
280
  lastEventAt: stats.lastEventAt
243
281
  }
244
282
  };
245
- }
283
+ })
246
284
  );
247
285
  }
248
286
 
249
287
  // src/tools/components.ts
250
- var import_zod2 = require("zod");
288
+ var import_zod3 = require("zod");
251
289
 
252
290
  // src/ui/templates.ts
253
291
  var VIZ_TITLES = {
@@ -506,21 +544,20 @@ function registerUiResources(server) {
506
544
  }
507
545
 
508
546
  // src/tools/components.ts
509
- var projectIdSchema2 = import_zod2.z.string().uuid().describe("The project UUID");
510
547
  function registerComponentTools(server, client) {
511
548
  server.registerTool(
512
549
  "list_components",
513
550
  {
514
551
  title: "List components",
515
552
  description: "List all adaptive components in a project with variant counts and impression totals.",
516
- inputSchema: { projectId: projectIdSchema2 },
553
+ inputSchema: { projectId: projectIdSchema },
517
554
  outputSchema: {
518
- components: import_zod2.z.array(
519
- import_zod2.z.object({
520
- componentId: import_zod2.z.string(),
521
- variantCount: import_zod2.z.number(),
522
- impressions: import_zod2.z.number(),
523
- conversions: import_zod2.z.number()
555
+ components: import_zod3.z.array(
556
+ import_zod3.z.object({
557
+ componentId: import_zod3.z.string(),
558
+ variantCount: import_zod3.z.number(),
559
+ impressions: import_zod3.z.number(),
560
+ conversions: import_zod3.z.number()
524
561
  })
525
562
  ).describe("Adaptive components in the project (empty if none)")
526
563
  },
@@ -530,7 +567,7 @@ function registerComponentTools(server, client) {
530
567
  openWorldHint: false
531
568
  }
532
569
  },
533
- async ({ projectId }) => {
570
+ withApiErrorGuidance(async ({ projectId }) => {
534
571
  const id = encodeURIComponent(projectId);
535
572
  const { components } = await client.get(`/projects/${id}/components`);
536
573
  const structuredContent = {
@@ -551,23 +588,23 @@ function registerComponentTools(server, client) {
551
588
  (c) => `- ${c.component_id}: ${c.variants.length} variants, ${c.total_impressions} impressions, ${c.total_conversions} conversions`
552
589
  ).join("\n");
553
590
  return { content: [{ type: "text", text }], structuredContent };
554
- }
591
+ })
555
592
  );
556
593
  server.registerTool(
557
594
  "get_variant_performance",
558
595
  {
559
596
  title: "Variant performance",
560
597
  description: "Get CVR and momentum for all variants in a project over the last 7 days vs prior 7 days.",
561
- inputSchema: { projectId: projectIdSchema2 },
598
+ inputSchema: { projectId: projectIdSchema },
562
599
  _meta: uiMeta("variant-performance"),
563
600
  outputSchema: {
564
- variants: import_zod2.z.array(
565
- import_zod2.z.object({
566
- variantId: import_zod2.z.string(),
567
- currentCvr: import_zod2.z.number().describe("Conversion rate over the last 7 days (0-1)"),
568
- priorCvr: import_zod2.z.number().describe("Conversion rate over the prior 7 days (0-1)"),
569
- deltaPp: import_zod2.z.number().describe("Change in percentage points"),
570
- momentum: import_zod2.z.string().describe("Momentum direction: gaining, losing, or stable")
601
+ variants: import_zod3.z.array(
602
+ import_zod3.z.object({
603
+ variantId: import_zod3.z.string(),
604
+ currentCvr: import_zod3.z.number().describe("Conversion rate over the last 7 days (0-1)"),
605
+ priorCvr: import_zod3.z.number().describe("Conversion rate over the prior 7 days (0-1)"),
606
+ deltaPp: import_zod3.z.number().describe("Change in percentage points"),
607
+ momentum: import_zod3.z.string().describe("Momentum direction: gaining, losing, or stable")
571
608
  })
572
609
  ).describe("Per-variant performance (empty if no data yet)")
573
610
  },
@@ -577,20 +614,24 @@ function registerComponentTools(server, client) {
577
614
  openWorldHint: false
578
615
  }
579
616
  },
580
- async ({ projectId }) => {
617
+ withApiErrorGuidance(async ({ projectId }) => {
618
+ var _a, _b, _c;
581
619
  const id = encodeURIComponent(projectId);
582
620
  const data = await client.get(`/projects/${id}/trends`);
583
- const momentumMap = new Map((data.momentum ?? []).map((m) => [m.variantId, m.direction]));
621
+ const momentumMap = new Map(((_a = data.momentum) != null ? _a : []).map((m) => [m.variantId, m.direction]));
584
622
  const structuredContent = {
585
- variants: (data.cvr ?? []).map((v) => ({
586
- variantId: v.variantId,
587
- currentCvr: v.currentCvr,
588
- priorCvr: v.priorCvr,
589
- deltaPp: v.deltaPp,
590
- momentum: momentumMap.get(v.variantId) ?? "stable"
591
- }))
623
+ variants: ((_b = data.cvr) != null ? _b : []).map((v) => {
624
+ var _a2;
625
+ return {
626
+ variantId: v.variantId,
627
+ currentCvr: v.currentCvr,
628
+ priorCvr: v.priorCvr,
629
+ deltaPp: v.deltaPp,
630
+ momentum: (_a2 = momentumMap.get(v.variantId)) != null ? _a2 : "stable"
631
+ };
632
+ })
592
633
  };
593
- if (!data.cvr?.length) {
634
+ if (!((_c = data.cvr) == null ? void 0 : _c.length)) {
594
635
  return {
595
636
  content: [{ type: "text", text: "No variant data available yet." }],
596
637
  structuredContent,
@@ -598,29 +639,31 @@ function registerComponentTools(server, client) {
598
639
  };
599
640
  }
600
641
  const text = data.cvr.map(
601
- (v) => `- ${v.variantId}: CVR ${(v.currentCvr * 100).toFixed(2)}% (prior ${(v.priorCvr * 100).toFixed(2)}%, ${v.deltaPp > 0 ? "+" : ""}${v.deltaPp.toFixed(1)} pp, ${momentumMap.get(v.variantId) ?? "stable"})`
642
+ (v) => {
643
+ var _a2;
644
+ return `- ${v.variantId}: CVR ${(v.currentCvr * 100).toFixed(2)}% (prior ${(v.priorCvr * 100).toFixed(2)}%, ${v.deltaPp > 0 ? "+" : ""}${v.deltaPp.toFixed(1)} pp, ${(_a2 = momentumMap.get(v.variantId)) != null ? _a2 : "stable"})`;
645
+ }
602
646
  ).join("\n");
603
647
  return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("variant-performance") };
604
- }
648
+ })
605
649
  );
606
650
  }
607
651
 
608
652
  // src/tools/insights.ts
609
- var import_zod3 = require("zod");
610
- var projectIdSchema3 = import_zod3.z.string().uuid().describe("The project UUID");
653
+ var import_zod4 = require("zod");
611
654
  function registerInsightTools(server, client) {
612
655
  server.registerTool(
613
656
  "get_insights",
614
657
  {
615
658
  title: "Get insights",
616
659
  description: "Get the latest AI-generated insights: narrator observations and (Growth tier) advisor recommendations.",
617
- inputSchema: { projectId: projectIdSchema3 },
660
+ inputSchema: { projectId: projectIdSchema },
618
661
  outputSchema: {
619
- status: import_zod3.z.enum(["ok", "empty"]).describe("Whether insights exist yet"),
620
- observations: import_zod3.z.array(import_zod3.z.string()).describe("Narrator observations"),
621
- recommendations: import_zod3.z.array(import_zod3.z.string()).describe("Advisor recommendations (Growth tier)"),
622
- isStale: import_zod3.z.boolean().describe("True when the insights are older than ~6h"),
623
- generatedAt: import_zod3.z.string().nullable().describe("ISO timestamp the insights were generated, or null")
662
+ status: import_zod4.z.enum(["ok", "empty"]).describe("Whether insights exist yet"),
663
+ observations: import_zod4.z.array(import_zod4.z.string()).describe("Narrator observations"),
664
+ recommendations: import_zod4.z.array(import_zod4.z.string()).describe("Advisor recommendations (Growth tier)"),
665
+ isStale: import_zod4.z.boolean().describe("True when the insights are older than ~6h"),
666
+ generatedAt: import_zod4.z.string().nullable().describe("ISO timestamp the insights were generated, or null")
624
667
  },
625
668
  annotations: {
626
669
  readOnlyHint: true,
@@ -628,7 +671,8 @@ function registerInsightTools(server, client) {
628
671
  openWorldHint: false
629
672
  }
630
673
  },
631
- async ({ projectId }) => {
674
+ withApiErrorGuidance(async ({ projectId }) => {
675
+ var _a, _b, _c, _d;
632
676
  const id = encodeURIComponent(projectId);
633
677
  const data = await client.get(`/projects/${id}/insights`);
634
678
  if (data.status === "empty") {
@@ -643,8 +687,8 @@ function registerInsightTools(server, client) {
643
687
  }
644
688
  };
645
689
  }
646
- const observations = data.narratorBullets ?? [];
647
- const recommendations = data.advisorBullets ?? [];
690
+ const observations = (_a = data.narratorBullets) != null ? _a : [];
691
+ const recommendations = (_b = data.advisorBullets) != null ? _b : [];
648
692
  const lines = [];
649
693
  if (data.isStale) lines.push("\u26A0 Insights are stale (>6h old). Consider calling refresh_insights.");
650
694
  if (data.generatedAt) lines.push(`Generated: ${new Date(data.generatedAt).toUTCString()}`);
@@ -662,33 +706,32 @@ function registerInsightTools(server, client) {
662
706
  status: "ok",
663
707
  observations,
664
708
  recommendations,
665
- isStale: data.isStale ?? false,
666
- generatedAt: data.generatedAt ?? null
709
+ isStale: (_c = data.isStale) != null ? _c : false,
710
+ generatedAt: (_d = data.generatedAt) != null ? _d : null
667
711
  }
668
712
  };
669
- }
713
+ })
670
714
  );
671
715
  }
672
716
 
673
717
  // src/tools/personas.ts
674
- var import_zod4 = require("zod");
675
- var projectIdSchema4 = import_zod4.z.string().uuid().describe("The project UUID");
718
+ var import_zod5 = require("zod");
676
719
  function registerPersonaTools(server, client) {
677
720
  server.registerTool(
678
721
  "get_persona_breakdown",
679
722
  {
680
723
  title: "Persona breakdown",
681
724
  description: "Get the distribution of visitor persona clusters with session counts and reliability scores.",
682
- inputSchema: { projectId: projectIdSchema4 },
725
+ inputSchema: { projectId: projectIdSchema },
683
726
  _meta: uiMeta("persona-breakdown"),
684
727
  outputSchema: {
685
- totalSessions: import_zod4.z.number().describe("Total sessions across all clusters"),
686
- clusters: import_zod4.z.array(
687
- import_zod4.z.object({
688
- label: import_zod4.z.string(),
689
- sessionCount: import_zod4.z.number(),
690
- sharePct: import_zod4.z.number().describe("Share of total traffic (0-100)"),
691
- reliability: import_zod4.z.number().describe("Average cluster reliability (0-1)")
728
+ totalSessions: import_zod5.z.number().describe("Total sessions across all clusters"),
729
+ clusters: import_zod5.z.array(
730
+ import_zod5.z.object({
731
+ label: import_zod5.z.string(),
732
+ sessionCount: import_zod5.z.number(),
733
+ sharePct: import_zod5.z.number().describe("Share of total traffic (0-100)"),
734
+ reliability: import_zod5.z.number().describe("Average cluster reliability (0-1)")
692
735
  })
693
736
  ).describe("Persona clusters (empty until enough visitor data)")
694
737
  },
@@ -698,7 +741,7 @@ function registerPersonaTools(server, client) {
698
741
  openWorldHint: false
699
742
  }
700
743
  },
701
- async ({ projectId }) => {
744
+ withApiErrorGuidance(async ({ projectId }) => {
702
745
  const id = encodeURIComponent(projectId);
703
746
  const data = await client.get(`/projects/${id}/portraits`);
704
747
  const structuredContent = {
@@ -727,33 +770,32 @@ function registerPersonaTools(server, client) {
727
770
  })
728
771
  ];
729
772
  return { content: [{ type: "text", text: lines.join("\n") }], structuredContent, _meta: uiMeta("persona-breakdown") };
730
- }
773
+ })
731
774
  );
732
775
  }
733
776
 
734
777
  // src/tools/goals.ts
735
- var import_zod5 = require("zod");
736
- var projectIdSchema5 = import_zod5.z.string().uuid().describe("The project UUID");
778
+ var import_zod6 = require("zod");
737
779
  function registerGoalTools(server, client) {
738
780
  server.registerTool(
739
781
  "get_goal_funnel",
740
782
  {
741
783
  title: "Goal funnel",
742
784
  description: "Get goal hit counts, unique-session conversion rates, and per-variant breakdown.",
743
- inputSchema: { projectId: projectIdSchema5 },
785
+ inputSchema: { projectId: projectIdSchema },
744
786
  _meta: uiMeta("goal-funnel"),
745
787
  outputSchema: {
746
- goals: import_zod5.z.array(
747
- import_zod5.z.object({
748
- goalName: import_zod5.z.string(),
749
- hits: import_zod5.z.number(),
750
- uniqueSessions: import_zod5.z.number(),
751
- conversionRate: import_zod5.z.number().describe("Unique-session conversion rate (0-1)"),
752
- variants: import_zod5.z.array(
753
- import_zod5.z.object({
754
- componentId: import_zod5.z.string(),
755
- variantId: import_zod5.z.string(),
756
- completionRate: import_zod5.z.number().describe("Completion rate per assigned session (0-1)")
788
+ goals: import_zod6.z.array(
789
+ import_zod6.z.object({
790
+ goalName: import_zod6.z.string(),
791
+ hits: import_zod6.z.number(),
792
+ uniqueSessions: import_zod6.z.number(),
793
+ conversionRate: import_zod6.z.number().describe("Unique-session conversion rate (0-1)"),
794
+ variants: import_zod6.z.array(
795
+ import_zod6.z.object({
796
+ componentId: import_zod6.z.string(),
797
+ variantId: import_zod6.z.string(),
798
+ completionRate: import_zod6.z.number().describe("Completion rate per assigned session (0-1)")
757
799
  })
758
800
  ).describe("Per-variant breakdown")
759
801
  })
@@ -765,7 +807,7 @@ function registerGoalTools(server, client) {
765
807
  openWorldHint: false
766
808
  }
767
809
  },
768
- async ({ projectId }) => {
810
+ withApiErrorGuidance(async ({ projectId }) => {
769
811
  const id = encodeURIComponent(projectId);
770
812
  const data = await client.get(`/projects/${id}/goals`);
771
813
  const structuredContent = {
@@ -794,26 +836,25 @@ function registerGoalTools(server, client) {
794
836
  ""
795
837
  ]);
796
838
  return { content: [{ type: "text", text: lines.join("\n").trim() }], structuredContent, _meta: uiMeta("goal-funnel") };
797
- }
839
+ })
798
840
  );
799
841
  }
800
842
 
801
843
  // src/tools/guardrails.ts
802
- var import_zod6 = require("zod");
803
- var projectIdSchema6 = import_zod6.z.string().uuid().describe("The project UUID");
844
+ var import_zod7 = require("zod");
804
845
  function registerGuardrailTools(server, client) {
805
846
  server.registerTool(
806
847
  "list_guardrail_events",
807
848
  {
808
849
  title: "List guardrail events",
809
850
  description: "List variants currently paused by the guardrail in the last 24 hours.",
810
- inputSchema: { projectId: projectIdSchema6 },
851
+ inputSchema: { projectId: projectIdSchema },
811
852
  outputSchema: {
812
- events: import_zod6.z.array(
813
- import_zod6.z.object({
814
- componentId: import_zod6.z.string(),
815
- variantIds: import_zod6.z.array(import_zod6.z.string()).describe("Variants paused by the guardrail"),
816
- pausedAt: import_zod6.z.string().nullable().describe("ISO timestamp the pause fired, or null")
853
+ events: import_zod7.z.array(
854
+ import_zod7.z.object({
855
+ componentId: import_zod7.z.string(),
856
+ variantIds: import_zod7.z.array(import_zod7.z.string()).describe("Variants paused by the guardrail"),
857
+ pausedAt: import_zod7.z.string().nullable().describe("ISO timestamp the pause fired, or null")
817
858
  })
818
859
  ).describe("Guardrail events in the last 24h (empty if none)")
819
860
  },
@@ -823,7 +864,7 @@ function registerGuardrailTools(server, client) {
823
864
  openWorldHint: false
824
865
  }
825
866
  },
826
- async ({ projectId }) => {
867
+ withApiErrorGuidance(async ({ projectId }) => {
827
868
  const id = encodeURIComponent(projectId);
828
869
  const data = await client.get(`/projects/${id}/guardrail-events`);
829
870
  const structuredContent = {
@@ -843,28 +884,27 @@ function registerGuardrailTools(server, client) {
843
884
  (e) => `- ${e.componentId}: variants [${e.variantIds.join(", ")}] paused${e.pausedAt ? ` at ${e.pausedAt}` : ""}`
844
885
  );
845
886
  return { content: [{ type: "text", text: lines.join("\n") }], structuredContent };
846
- }
887
+ })
847
888
  );
848
889
  }
849
890
 
850
891
  // src/tools/layout.ts
851
- var import_zod7 = require("zod");
852
- var projectIdSchema7 = import_zod7.z.string().uuid().describe("The project UUID");
892
+ var import_zod8 = require("zod");
853
893
  function registerLayoutTools(server, client) {
854
894
  server.registerTool(
855
895
  "get_layout_stats",
856
896
  {
857
897
  title: "Layout stats",
858
898
  description: "Get per-persona section layout rankings and bandit reward weights.",
859
- inputSchema: { projectId: projectIdSchema7 },
899
+ inputSchema: { projectId: projectIdSchema },
860
900
  _meta: uiMeta("layout-stats"),
861
901
  outputSchema: {
862
- layouts: import_zod7.z.array(
863
- import_zod7.z.object({
864
- persona: import_zod7.z.string(),
865
- layoutOrder: import_zod7.z.array(import_zod7.z.string()).describe("Ranked section order for this persona"),
866
- pulls: import_zod7.z.number().describe("Number of times this arm was served"),
867
- avgReward: import_zod7.z.number().describe("Average bandit reward weight")
902
+ layouts: import_zod8.z.array(
903
+ import_zod8.z.object({
904
+ persona: import_zod8.z.string(),
905
+ layoutOrder: import_zod8.z.array(import_zod8.z.string()).describe("Ranked section order for this persona"),
906
+ pulls: import_zod8.z.number().describe("Number of times this arm was served"),
907
+ avgReward: import_zod8.z.number().describe("Average bandit reward weight")
868
908
  })
869
909
  ).describe("Per-persona layout rankings (empty until enough sessions)")
870
910
  },
@@ -874,7 +914,7 @@ function registerLayoutTools(server, client) {
874
914
  openWorldHint: false
875
915
  }
876
916
  },
877
- async ({ projectId }) => {
917
+ withApiErrorGuidance(async ({ projectId }) => {
878
918
  const id = encodeURIComponent(projectId);
879
919
  const stats = await client.get(`/projects/${id}/layout-stats`);
880
920
  const structuredContent = {
@@ -896,13 +936,12 @@ function registerLayoutTools(server, client) {
896
936
  (s) => `- ${s.persona}: [${s.layoutOrder.join(" \u2192 ")}] (avg reward: ${s.avgReward.toFixed(2)}, ${s.pulls} pulls)`
897
937
  ).join("\n");
898
938
  return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("layout-stats") };
899
- }
939
+ })
900
940
  );
901
941
  }
902
942
 
903
943
  // src/tools/variants.ts
904
- var import_zod8 = require("zod");
905
- var projectIdSchema8 = import_zod8.z.string().uuid().describe("The project UUID");
944
+ var import_zod9 = require("zod");
906
945
  function registerVariantWriteTools(server, client) {
907
946
  server.registerTool(
908
947
  "create_variant",
@@ -910,17 +949,17 @@ function registerVariantWriteTools(server, client) {
910
949
  title: "Create managed variant",
911
950
  description: "Create a NO-CODE managed text variant for a component (content stored in SentientUI, rendered by <AdaptiveText>). Use this ONLY for text-only variants the user wants without a code change. For variants that will live in the codebase (full components \u2014 copy, markup, styling), use get_variant_brief and write the variant in code instead; those auto-register on deploy and do not need create_variant. Requires a paid plan (server keys are Starter+; anonymous demo tokens are read-only).",
912
951
  inputSchema: {
913
- projectId: projectIdSchema8,
914
- componentId: import_zod8.z.string().describe("The component ID to add a variant to"),
915
- displayName: import_zod8.z.string().describe("Human-readable name for the new variant"),
916
- content: import_zod8.z.string().optional().describe("The text content for this managed variant (rendered by <AdaptiveText>). Generate it from get_variant_brief context; omit only to create an empty placeholder to fill in from the dashboard.")
952
+ projectId: projectIdSchema,
953
+ componentId: import_zod9.z.string().describe("The component ID to add a variant to"),
954
+ displayName: import_zod9.z.string().describe("Human-readable name for the new variant"),
955
+ content: import_zod9.z.string().optional().describe("The text content for this managed variant (rendered by <AdaptiveText>). Generate it from get_variant_brief context; omit only to create an empty placeholder to fill in from the dashboard.")
917
956
  },
918
957
  outputSchema: {
919
- variantId: import_zod8.z.string().describe("The new variant ID"),
920
- displayName: import_zod8.z.string(),
921
- componentId: import_zod8.z.string(),
922
- state: import_zod8.z.literal("draft").describe("New managed variants start in draft state"),
923
- hasContent: import_zod8.z.boolean().describe("Whether text content was provided at creation")
958
+ variantId: import_zod9.z.string().describe("The new variant ID"),
959
+ displayName: import_zod9.z.string(),
960
+ componentId: import_zod9.z.string(),
961
+ state: import_zod9.z.literal("draft").describe("New managed variants start in draft state"),
962
+ hasContent: import_zod9.z.boolean().describe("Whether text content was provided at creation")
924
963
  },
925
964
  annotations: {
926
965
  readOnlyHint: false,
@@ -929,7 +968,7 @@ function registerVariantWriteTools(server, client) {
929
968
  openWorldHint: false
930
969
  }
931
970
  },
932
- async ({ projectId, componentId, displayName, content }) => {
971
+ withApiErrorGuidance(async ({ projectId, componentId, displayName, content }) => {
933
972
  const id = encodeURIComponent(projectId);
934
973
  const result = await client.post(
935
974
  `/projects/${id}/variants`,
@@ -949,7 +988,7 @@ function registerVariantWriteTools(server, client) {
949
988
  hasContent: Boolean(content)
950
989
  }
951
990
  };
952
- }
991
+ })
953
992
  );
954
993
  server.registerTool(
955
994
  "pause_variant",
@@ -957,14 +996,14 @@ function registerVariantWriteTools(server, client) {
957
996
  title: "Pause variant",
958
997
  description: "Pause a variant, stopping traffic from being assigned to it.",
959
998
  inputSchema: {
960
- projectId: projectIdSchema8,
961
- componentId: import_zod8.z.string().describe("The component ID"),
962
- variantId: import_zod8.z.string().describe("The variant ID to pause")
999
+ projectId: projectIdSchema,
1000
+ componentId: import_zod9.z.string().describe("The component ID"),
1001
+ variantId: import_zod9.z.string().describe("The variant ID to pause")
963
1002
  },
964
1003
  outputSchema: {
965
- variantId: import_zod8.z.string(),
966
- componentId: import_zod8.z.string(),
967
- paused: import_zod8.z.literal(true).describe("The variant is now paused")
1004
+ variantId: import_zod9.z.string(),
1005
+ componentId: import_zod9.z.string(),
1006
+ paused: import_zod9.z.literal(true).describe("The variant is now paused")
968
1007
  },
969
1008
  annotations: {
970
1009
  readOnlyHint: false,
@@ -973,7 +1012,7 @@ function registerVariantWriteTools(server, client) {
973
1012
  openWorldHint: false
974
1013
  }
975
1014
  },
976
- async ({ projectId, componentId, variantId }) => {
1015
+ withApiErrorGuidance(async ({ projectId, componentId, variantId }) => {
977
1016
  const id = encodeURIComponent(projectId);
978
1017
  await client.post(`/projects/${id}/variants/pause`, { componentId, variantId });
979
1018
  return {
@@ -983,17 +1022,17 @@ function registerVariantWriteTools(server, client) {
983
1022
  }],
984
1023
  structuredContent: { variantId, componentId, paused: true }
985
1024
  };
986
- }
1025
+ })
987
1026
  );
988
1027
  server.registerTool(
989
1028
  "refresh_insights",
990
1029
  {
991
1030
  title: "Refresh insights",
992
1031
  description: "Trigger fresh AI insight generation for a project. Returns immediately; use get_insights in ~15 seconds to see results.",
993
- inputSchema: { projectId: projectIdSchema8 },
1032
+ inputSchema: { projectId: projectIdSchema },
994
1033
  outputSchema: {
995
- projectId: import_zod8.z.string(),
996
- status: import_zod8.z.literal("generating").describe("Generation has been triggered")
1034
+ projectId: import_zod9.z.string(),
1035
+ status: import_zod9.z.literal("generating").describe("Generation has been triggered")
997
1036
  },
998
1037
  annotations: {
999
1038
  readOnlyHint: false,
@@ -1002,7 +1041,7 @@ function registerVariantWriteTools(server, client) {
1002
1041
  openWorldHint: false
1003
1042
  }
1004
1043
  },
1005
- async ({ projectId }) => {
1044
+ withApiErrorGuidance(async ({ projectId }) => {
1006
1045
  const id = encodeURIComponent(projectId);
1007
1046
  await client.post(`/projects/${id}/insights/refresh`);
1008
1047
  return {
@@ -1012,13 +1051,12 @@ function registerVariantWriteTools(server, client) {
1012
1051
  }],
1013
1052
  structuredContent: { projectId, status: "generating" }
1014
1053
  };
1015
- }
1054
+ })
1016
1055
  );
1017
1056
  }
1018
1057
 
1019
1058
  // src/tools/variant-brief.ts
1020
- var import_zod9 = require("zod");
1021
- var projectIdSchema9 = import_zod9.z.string().uuid().describe("The project UUID");
1059
+ var import_zod10 = require("zod");
1022
1060
  var GOAL_TARGET = 500;
1023
1061
  var BEST_PRACTICE_PRIORS = {
1024
1062
  ecommerce: [
@@ -1056,11 +1094,12 @@ var GENERIC_PRIORS = [
1056
1094
  "Add one credible proof point near the action."
1057
1095
  ];
1058
1096
  function priorsFor(contextType) {
1059
- return BEST_PRACTICE_PRIORS[contextType] ?? GENERIC_PRIORS;
1097
+ var _a;
1098
+ return (_a = BEST_PRACTICE_PRIORS[contextType]) != null ? _a : GENERIC_PRIORS;
1060
1099
  }
1061
1100
  function computeDataState(impressions, insights, avgReliability) {
1062
1101
  if (impressions === 0) return "empty";
1063
- const insightsReady = insights?.status === "ok" && !insights.isStale;
1102
+ const insightsReady = (insights == null ? void 0 : insights.status) === "ok" && !insights.isStale;
1064
1103
  const reliable = avgReliability === null || avgReliability >= 0.3;
1065
1104
  if (impressions < GOAL_TARGET || !insightsReady || !reliable) return "collecting";
1066
1105
  return "sufficient";
@@ -1078,7 +1117,7 @@ function guidanceFor(dataState, contextType) {
1078
1117
  async function settled(p) {
1079
1118
  try {
1080
1119
  return await p;
1081
- } catch {
1120
+ } catch (e) {
1082
1121
  return null;
1083
1122
  }
1084
1123
  }
@@ -1089,16 +1128,16 @@ function registerVariantBriefTools(server, client) {
1089
1128
  title: "Variant brief",
1090
1129
  description: "Get an insight-driven brief for creating a new CODE-NATIVE variant of a component. Returns current variant performance, audience, insights, a data-sufficiency assessment (with a best-practice fallback when there is no data yet), and step-by-step instructions for writing the variant in the customer's code. Use this instead of create_variant when the variant will live in the codebase.",
1091
1130
  inputSchema: {
1092
- projectId: projectIdSchema9,
1093
- componentId: import_zod9.z.string().describe('The component ID to write a new variant for (matches <Adaptive id="...">).')
1131
+ projectId: projectIdSchema,
1132
+ componentId: import_zod10.z.string().describe('The component ID to write a new variant for (matches <Adaptive id="...">).')
1094
1133
  },
1095
1134
  outputSchema: {
1096
- componentId: import_zod9.z.string(),
1097
- contextType: import_zod9.z.string().describe("The project's context type (or 'unknown')"),
1098
- dataState: import_zod9.z.enum(["sufficient", "collecting", "empty"]).describe("Data-sufficiency assessment"),
1099
- existingVariantIds: import_zod9.z.array(import_zod9.z.string()).describe("Variant IDs already in use (do not reuse)"),
1100
- priors: import_zod9.z.array(import_zod9.z.string()).describe("Best-practice priors applied for this context type"),
1101
- markdown: import_zod9.z.string().describe("The full variant brief in Markdown")
1135
+ componentId: import_zod10.z.string(),
1136
+ contextType: import_zod10.z.string().describe("The project's context type (or 'unknown')"),
1137
+ dataState: import_zod10.z.enum(["sufficient", "collecting", "empty"]).describe("Data-sufficiency assessment"),
1138
+ existingVariantIds: import_zod10.z.array(import_zod10.z.string()).describe("Variant IDs already in use (do not reuse)"),
1139
+ priors: import_zod10.z.array(import_zod10.z.string()).describe("Best-practice priors applied for this context type"),
1140
+ markdown: import_zod10.z.string().describe("The full variant brief in Markdown")
1102
1141
  },
1103
1142
  annotations: {
1104
1143
  readOnlyHint: true,
@@ -1106,7 +1145,8 @@ function registerVariantBriefTools(server, client) {
1106
1145
  openWorldHint: false
1107
1146
  }
1108
1147
  },
1109
- async ({ projectId, componentId }) => {
1148
+ withApiErrorGuidance(async ({ projectId, componentId }) => {
1149
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
1110
1150
  const id = encodeURIComponent(projectId);
1111
1151
  const [projects, componentsEnvelope, trends, portraits, insights] = await Promise.all([
1112
1152
  settled(client.get("/projects")),
@@ -1116,19 +1156,19 @@ function registerVariantBriefTools(server, client) {
1116
1156
  settled(client.get(`/projects/${id}/portraits`)),
1117
1157
  settled(client.get(`/projects/${id}/insights`))
1118
1158
  ]);
1119
- const project = projects?.find((p) => p.id === projectId) ?? null;
1120
- const contextType = project?.context_type ?? "unknown";
1121
- const components = componentsEnvelope?.components ?? [];
1122
- const component = components.find((c) => c.component_id === componentId) ?? null;
1123
- const impressions = component?.total_impressions ?? 0;
1124
- const conversions = component?.total_conversions ?? 0;
1159
+ const project = (_a = projects == null ? void 0 : projects.find((p) => p.id === projectId)) != null ? _a : null;
1160
+ const contextType = (_b = project == null ? void 0 : project.context_type) != null ? _b : "unknown";
1161
+ const components = (_c = componentsEnvelope == null ? void 0 : componentsEnvelope.components) != null ? _c : [];
1162
+ const component = (_d = components.find((c) => c.component_id === componentId)) != null ? _d : null;
1163
+ const impressions = (_e = component == null ? void 0 : component.total_impressions) != null ? _e : 0;
1164
+ const conversions = (_f = component == null ? void 0 : component.total_conversions) != null ? _f : 0;
1125
1165
  const componentCvr = impressions > 0 ? conversions / impressions * 100 : 0;
1126
- const existingVariantIds = component?.variants.map((v) => v.variant_id) ?? [];
1166
+ const existingVariantIds = (_g = component == null ? void 0 : component.variants.map((v) => v.variant_id)) != null ? _g : [];
1127
1167
  const variantIdSet = new Set(existingVariantIds);
1128
- const momentumMap = new Map((trends?.momentum ?? []).map((m) => [m.variantId, m.direction]));
1129
- const variantPerf = (trends?.cvr ?? []).filter((v) => variantIdSet.has(v.variantId));
1130
- const clusters = portraits?.clusters ?? [];
1131
- const totalSessions = portraits?.totalSessions ?? 0;
1168
+ const momentumMap = new Map(((_h = trends == null ? void 0 : trends.momentum) != null ? _h : []).map((m) => [m.variantId, m.direction]));
1169
+ const variantPerf = ((_i = trends == null ? void 0 : trends.cvr) != null ? _i : []).filter((v) => variantIdSet.has(v.variantId));
1170
+ const clusters = (_j = portraits == null ? void 0 : portraits.clusters) != null ? _j : [];
1171
+ const totalSessions = (_k = portraits == null ? void 0 : portraits.totalSessions) != null ? _k : 0;
1132
1172
  const avgReliability = clusters.length ? clusters.reduce((s, c) => s + c.avgReliability, 0) / clusters.length : null;
1133
1173
  const dataState = computeDataState(impressions, insights, avgReliability);
1134
1174
  const lines = [];
@@ -1153,7 +1193,7 @@ function registerVariantBriefTools(server, client) {
1153
1193
  lines.push("Current variant performance (7d vs prior 7d):");
1154
1194
  for (const v of variantPerf) {
1155
1195
  lines.push(
1156
- `- ${v.variantId}: ${(v.currentCvr * 100).toFixed(2)}% CVR (${v.deltaPp > 0 ? "+" : ""}${v.deltaPp.toFixed(1)} pp, ${momentumMap.get(v.variantId) ?? "stable"})`
1196
+ `- ${v.variantId}: ${(v.currentCvr * 100).toFixed(2)}% CVR (${v.deltaPp > 0 ? "+" : ""}${v.deltaPp.toFixed(1)} pp, ${(_l = momentumMap.get(v.variantId)) != null ? _l : "stable"})`
1157
1197
  );
1158
1198
  }
1159
1199
  lines.push("");
@@ -1168,8 +1208,8 @@ function registerVariantBriefTools(server, client) {
1168
1208
  }
1169
1209
  if (insights && insights.status === "ok") {
1170
1210
  if (insights.isStale) lines.push("\u26A0 Insights are stale (>6h). Consider refresh_insights for a fresher read.");
1171
- const narrator = insights.narratorBullets ?? [];
1172
- const advisor = insights.advisorBullets ?? [];
1211
+ const narrator = (_m = insights.narratorBullets) != null ? _m : [];
1212
+ const advisor = (_n = insights.advisorBullets) != null ? _n : [];
1173
1213
  if (narrator.length) {
1174
1214
  lines.push("Insights \u2014 observations:");
1175
1215
  narrator.forEach((b) => lines.push(`- ${b}`));
@@ -1209,17 +1249,16 @@ function registerVariantBriefTools(server, client) {
1209
1249
  markdown
1210
1250
  }
1211
1251
  };
1212
- }
1252
+ })
1213
1253
  );
1214
1254
  }
1215
1255
 
1216
1256
  // src/tools/test-brief.ts
1217
- var import_zod10 = require("zod");
1218
- var projectIdSchema10 = import_zod10.z.string().uuid().describe("The project UUID");
1257
+ var import_zod11 = require("zod");
1219
1258
  async function settled2(p) {
1220
1259
  try {
1221
1260
  return await p;
1222
- } catch {
1261
+ } catch (e) {
1223
1262
  return null;
1224
1263
  }
1225
1264
  }
@@ -1230,14 +1269,14 @@ function registerTestBriefTools(server, client) {
1230
1269
  title: "Test brief",
1231
1270
  description: "Get a ready-to-paste test for a SentientUI-wrapped component, populated with the component's real variants and goals. This project uses @sentientui/react/testing. Use this so your tests force a specific variant/layout deterministically and never break when the optimizer serves a different version. Returns a React Testing Library example plus the URL-param recipe for E2E (Playwright/Cypress).",
1232
1271
  inputSchema: {
1233
- projectId: projectIdSchema10,
1234
- componentId: import_zod10.z.string().describe('The component ID to write a test for (matches <Adaptive id="...">).')
1272
+ projectId: projectIdSchema,
1273
+ componentId: import_zod11.z.string().describe('The component ID to write a test for (matches <Adaptive id="...">).')
1235
1274
  },
1236
1275
  outputSchema: {
1237
- componentId: import_zod10.z.string(),
1238
- forcedVariantId: import_zod10.z.string().describe("The non-control variant the example forces"),
1239
- goalName: import_zod10.z.string().describe("The goal the example asserts fires"),
1240
- markdown: import_zod10.z.string().describe("The full test brief in Markdown")
1276
+ componentId: import_zod11.z.string(),
1277
+ forcedVariantId: import_zod11.z.string().describe("The non-control variant the example forces"),
1278
+ goalName: import_zod11.z.string().describe("The goal the example asserts fires"),
1279
+ markdown: import_zod11.z.string().describe("The full test brief in Markdown")
1241
1280
  },
1242
1281
  annotations: {
1243
1282
  readOnlyHint: true,
@@ -1245,20 +1284,21 @@ function registerTestBriefTools(server, client) {
1245
1284
  openWorldHint: false
1246
1285
  }
1247
1286
  },
1248
- async ({ projectId, componentId }) => {
1287
+ withApiErrorGuidance(async ({ projectId, componentId }) => {
1288
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1249
1289
  const id = encodeURIComponent(projectId);
1250
1290
  const [componentsEnvelope, goalsRes] = await Promise.all([
1251
1291
  // mgmt API returns a paginated envelope: { components, total, page, limit }.
1252
1292
  settled2(client.get(`/projects/${id}/components`)),
1253
1293
  settled2(client.get(`/projects/${id}/goals`))
1254
1294
  ]);
1255
- const components = componentsEnvelope?.components ?? [];
1256
- const component = components.find((c) => c.component_id === componentId) ?? null;
1257
- const variantIds = component?.variants.map((v) => v.variant_id) ?? [];
1258
- const goals = Array.isArray(goalsRes) ? goalsRes : goalsRes?.goals ?? [];
1259
- const goalName = goals[0]?.goalName ?? "signup";
1260
- const controlId = variantIds[0] ?? "control";
1261
- const forcedId = variantIds.find((v) => v !== controlId) ?? "variant_b";
1295
+ const components = (_a = componentsEnvelope == null ? void 0 : componentsEnvelope.components) != null ? _a : [];
1296
+ const component = (_b = components.find((c) => c.component_id === componentId)) != null ? _b : null;
1297
+ const variantIds = (_c = component == null ? void 0 : component.variants.map((v) => v.variant_id)) != null ? _c : [];
1298
+ const goals = Array.isArray(goalsRes) ? goalsRes : (_d = goalsRes == null ? void 0 : goalsRes.goals) != null ? _d : [];
1299
+ const goalName = (_f = (_e = goals[0]) == null ? void 0 : _e.goalName) != null ? _f : "signup";
1300
+ const controlId = (_g = variantIds[0]) != null ? _g : "control";
1301
+ const forcedId = (_h = variantIds.find((v) => v !== controlId)) != null ? _h : "variant_b";
1262
1302
  const lines = [];
1263
1303
  lines.push(`# Test brief \u2014 ${componentId}`);
1264
1304
  lines.push("");
@@ -1314,12 +1354,12 @@ function registerTestBriefTools(server, client) {
1314
1354
  content: [{ type: "text", text: markdown }],
1315
1355
  structuredContent: { componentId, forcedVariantId: forcedId, goalName, markdown }
1316
1356
  };
1317
- }
1357
+ })
1318
1358
  );
1319
1359
  }
1320
1360
 
1321
1361
  // src/tools/integration-guide.ts
1322
- var import_zod11 = require("zod");
1362
+ var import_zod12 = require("zod");
1323
1363
  var GUIDE = `# SentientUI integration guide \u2014 the adaptive ladder
1324
1364
 
1325
1365
  SentientUI adapts a site per visitor type (personas: buyer, researcher, deal_seeker, browser,
@@ -1394,7 +1434,7 @@ function registerIntegrationGuideTools(server) {
1394
1434
  description: "Get the SentientUI adaptive-ladder integration guide: setup (keyless and keyed) plus copy-pasteable examples for every rung (Style, Swap, Reorder). Use this to integrate SentientUI into a codebase.",
1395
1435
  inputSchema: {},
1396
1436
  outputSchema: {
1397
- guide: import_zod11.z.string().describe("The full integration guide in Markdown")
1437
+ guide: import_zod12.z.string().describe("The full integration guide in Markdown")
1398
1438
  },
1399
1439
  annotations: {
1400
1440
  readOnlyHint: true,