@sentientui/mcp 0.8.0 → 0.8.2

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.
@@ -7,16 +7,15 @@ var ApiError = class extends Error {
7
7
  this.status = status;
8
8
  this.name = "ApiError";
9
9
  }
10
- status;
11
10
  };
12
11
  var ApiClient = class {
13
- baseUrl;
14
- apiKey;
15
12
  constructor(opts) {
13
+ var _a;
16
14
  this.apiKey = opts.apiKey;
17
- this.baseUrl = (opts.baseUrl ?? "https://api.sentient-ui.com").replace(/\/$/, "");
15
+ this.baseUrl = ((_a = opts.baseUrl) != null ? _a : "https://api.sentient-ui.com").replace(/\/$/, "");
18
16
  }
19
17
  async get(path) {
18
+ var _a;
20
19
  const res = await fetch(`${this.baseUrl}/v1/mgmt${path}`, {
21
20
  headers: {
22
21
  authorization: `Bearer ${this.apiKey}`,
@@ -25,11 +24,12 @@ var ApiClient = class {
25
24
  });
26
25
  if (!res.ok) {
27
26
  const body = await res.json().catch(() => ({}));
28
- throw new ApiError(res.status, String(body.error ?? res.statusText));
27
+ throw new ApiError(res.status, String((_a = body.error) != null ? _a : res.statusText));
29
28
  }
30
29
  return res.json();
31
30
  }
32
31
  async post(path, body) {
32
+ var _a;
33
33
  const res = await fetch(`${this.baseUrl}/v1/mgmt${path}`, {
34
34
  method: "POST",
35
35
  headers: {
@@ -40,35 +40,64 @@ var ApiClient = class {
40
40
  });
41
41
  if (!res.ok) {
42
42
  const errBody = await res.json().catch(() => ({}));
43
- throw new ApiError(res.status, String(errBody.error ?? res.statusText));
43
+ throw new ApiError(res.status, String((_a = errBody.error) != null ? _a : res.statusText));
44
44
  }
45
45
  return res.json();
46
46
  }
47
47
  };
48
48
 
49
49
  // src/server.ts
50
- import { createRequire } from "module";
51
50
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
52
51
 
53
52
  // src/tools/projects.ts
53
+ import { z as z2 } from "zod";
54
+
55
+ // src/tools/common.ts
54
56
  import { z } from "zod";
55
57
  var projectIdSchema = z.string().uuid().describe("The project UUID");
56
- function createProjectGuidance(err) {
58
+ function apiErrorGuidance(err, extra) {
59
+ if (extra && Object.prototype.hasOwnProperty.call(extra, err.message)) {
60
+ return extra[err.message];
61
+ }
57
62
  switch (err.message) {
58
63
  case "insufficient_scope":
59
- return "Creating a project 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) cannot create projects.";
64
+ 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.";
60
65
  case "demo_read_only":
61
- return "Demo mode is read-only. Create a SentientUI account and sign in to make projects.";
66
+ return "Demo mode is read-only. Create a SentientUI account and sign in (or use a project server key) to make changes.";
62
67
  case "insufficient_role":
63
- return "Your account role cannot create projects \u2014 this needs the account owner or an admin.";
64
- case "project_limit_reached":
65
- return "You've reached your plan's project limit. Upgrade your plan or remove an existing project, then try again.";
66
- case "name_required":
67
- return "A project name is required to create a project.";
68
+ return "Your account role does not permit this action \u2014 it needs the account owner or an admin.";
68
69
  default:
69
- return null;
70
+ break;
71
+ }
72
+ if (err.status === 402) {
73
+ return `This feature requires a higher plan (${err.message}). Upgrade your SentientUI plan, then try again.`;
70
74
  }
75
+ if (err.status === 403) {
76
+ return `Access denied (${err.message}). Check that your key or login has access to this project.`;
77
+ }
78
+ return null;
71
79
  }
80
+ function withApiErrorGuidance(fn, extra) {
81
+ return async (args) => {
82
+ try {
83
+ return await fn(args);
84
+ } catch (err) {
85
+ if (err instanceof ApiError) {
86
+ const guidance = apiErrorGuidance(err, extra);
87
+ if (guidance) {
88
+ return { content: [{ type: "text", text: guidance }], isError: true };
89
+ }
90
+ }
91
+ throw err;
92
+ }
93
+ };
94
+ }
95
+
96
+ // src/tools/projects.ts
97
+ var CREATE_PROJECT_GUIDANCE = {
98
+ project_limit_reached: "You've reached your plan's project limit. Upgrade your plan or remove an existing project, then try again.",
99
+ name_required: "A project name is required to create a project."
100
+ };
72
101
  function registerProjectTools(server, client) {
73
102
  server.registerTool(
74
103
  "create_project",
@@ -76,16 +105,16 @@ function registerProjectTools(server, client) {
76
105
  title: "Create project",
77
106
  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.",
78
107
  inputSchema: {
79
- name: z.string().min(1).describe("Human-readable project name"),
80
- contextType: z.enum(["saas", "ecommerce", "marketing", "landing", "internal"]).optional().describe("What kind of product this is; defaults to saas"),
81
- framework: z.enum(["next", "react", "core"]).optional().describe("How the site is built \u2014 next, react, or core (website builder/CMS); defaults to next"),
82
- websiteUrl: z.string().optional().describe("Production site origin to allow-list so the SDK's events aren't origin-blocked on day one")
108
+ name: z2.string().min(1).describe("Human-readable project name"),
109
+ contextType: z2.enum(["saas", "ecommerce", "marketing", "landing", "internal"]).optional().describe("What kind of product this is; defaults to saas"),
110
+ framework: z2.enum(["next", "react", "core"]).optional().describe("How the site is built \u2014 next, react, or core (website builder/CMS); defaults to next"),
111
+ websiteUrl: z2.string().optional().describe("Production site origin to allow-list so the SDK's events aren't origin-blocked on day one")
83
112
  },
84
113
  outputSchema: {
85
- projectId: z.string().describe("The new project UUID"),
86
- publicKey: z.string().describe("The pk_ public key to configure the SDK with"),
87
- name: z.string().describe("The project name"),
88
- contextType: z.string().describe("The resolved context type")
114
+ projectId: z2.string().describe("The new project UUID"),
115
+ publicKey: z2.string().describe("The pk_ public key to configure the SDK with"),
116
+ name: z2.string().describe("The project name"),
117
+ contextType: z2.string().describe("The resolved context type")
89
118
  },
90
119
  annotations: {
91
120
  readOnlyHint: false,
@@ -94,41 +123,31 @@ function registerProjectTools(server, client) {
94
123
  openWorldHint: false
95
124
  }
96
125
  },
97
- async ({ name, contextType, framework, websiteUrl }) => {
98
- try {
99
- const created = await client.post("/projects", {
126
+ withApiErrorGuidance(async ({ name, contextType, framework, websiteUrl }) => {
127
+ const created = await client.post("/projects", {
128
+ name,
129
+ contextType,
130
+ framework,
131
+ origin: websiteUrl
132
+ });
133
+ const resolvedContextType = contextType != null ? contextType : "saas";
134
+ return {
135
+ content: [{
136
+ type: "text",
137
+ text: [
138
+ `Created project "${name}" (id: ${created.id}, type: ${resolvedContextType}).`,
139
+ `Public key: ${created.apiKey}`,
140
+ `Next: install @sentientui/react with this key. Ask me to pull the setup guide (get_integration_guide) and I'll wrap your first component.`
141
+ ].join("\n")
142
+ }],
143
+ structuredContent: {
144
+ projectId: created.id,
145
+ publicKey: created.apiKey,
100
146
  name,
101
- contextType,
102
- framework,
103
- origin: websiteUrl
104
- });
105
- const resolvedContextType = contextType ?? "saas";
106
- return {
107
- content: [{
108
- type: "text",
109
- text: [
110
- `Created project "${name}" (id: ${created.id}, type: ${resolvedContextType}).`,
111
- `Public key: ${created.apiKey}`,
112
- `Next: install @sentientui/react with this key. Ask me to pull the setup guide (get_integration_guide) and I'll wrap your first component.`
113
- ].join("\n")
114
- }],
115
- structuredContent: {
116
- projectId: created.id,
117
- publicKey: created.apiKey,
118
- name,
119
- contextType: resolvedContextType
120
- }
121
- };
122
- } catch (err) {
123
- if (err instanceof ApiError) {
124
- const guidance = createProjectGuidance(err);
125
- if (guidance) {
126
- return { content: [{ type: "text", text: guidance }], isError: true };
127
- }
147
+ contextType: resolvedContextType
128
148
  }
129
- throw err;
130
- }
131
- }
149
+ };
150
+ }, CREATE_PROJECT_GUIDANCE)
132
151
  );
133
152
  server.registerTool(
134
153
  "list_projects",
@@ -137,12 +156,12 @@ function registerProjectTools(server, client) {
137
156
  description: "List all SentientUI projects for the authenticated account.",
138
157
  inputSchema: {},
139
158
  outputSchema: {
140
- projects: z.array(
141
- z.object({
142
- id: z.string().describe("Project UUID"),
143
- name: z.string(),
144
- contextType: z.string(),
145
- createdAt: z.string().describe("ISO date (YYYY-MM-DD)")
159
+ projects: z2.array(
160
+ z2.object({
161
+ id: z2.string().describe("Project UUID"),
162
+ name: z2.string(),
163
+ contextType: z2.string(),
164
+ createdAt: z2.string().describe("ISO date (YYYY-MM-DD)")
146
165
  })
147
166
  ).describe("All projects for the account (empty if none)")
148
167
  },
@@ -152,7 +171,7 @@ function registerProjectTools(server, client) {
152
171
  openWorldHint: false
153
172
  }
154
173
  },
155
- async () => {
174
+ withApiErrorGuidance(async () => {
156
175
  const projects = await client.get("/projects");
157
176
  const text = projects.length === 0 ? "No projects found." : projects.map(
158
177
  (p) => `- ${p.name} (id: ${p.id}, type: ${p.context_type}, created: ${p.created_at.slice(0, 10)})`
@@ -168,7 +187,7 @@ function registerProjectTools(server, client) {
168
187
  }))
169
188
  }
170
189
  };
171
- }
190
+ })
172
191
  );
173
192
  server.registerTool(
174
193
  "get_project_stats",
@@ -177,11 +196,11 @@ function registerProjectTools(server, client) {
177
196
  description: "Get health stats for a project: event volume, session count, agent calls, and status.",
178
197
  inputSchema: { projectId: projectIdSchema },
179
198
  outputSchema: {
180
- status: z.string().describe("Overall project health status"),
181
- events24h: z.number().describe("Events in the last 24 hours"),
182
- sessions24h: z.number().describe("Sessions in the last 24 hours"),
183
- agentCalls: z.number().describe("Total agent (MCP/API) calls"),
184
- lastEventAt: z.string().nullable().describe("ISO timestamp of the last event, or null")
199
+ status: z2.string().describe("Overall project health status"),
200
+ events24h: z2.number().describe("Events in the last 24 hours"),
201
+ sessions24h: z2.number().describe("Sessions in the last 24 hours"),
202
+ agentCalls: z2.number().describe("Total agent (MCP/API) calls"),
203
+ lastEventAt: z2.string().nullable().describe("ISO timestamp of the last event, or null")
185
204
  },
186
205
  annotations: {
187
206
  readOnlyHint: true,
@@ -189,7 +208,8 @@ function registerProjectTools(server, client) {
189
208
  openWorldHint: false
190
209
  }
191
210
  },
192
- async ({ projectId }) => {
211
+ withApiErrorGuidance(async ({ projectId }) => {
212
+ var _a;
193
213
  const id = encodeURIComponent(projectId);
194
214
  const stats = await client.get(`/projects/${id}/health`);
195
215
  const text = [
@@ -197,7 +217,7 @@ function registerProjectTools(server, client) {
197
217
  `Events (24h): ${stats.events24h}`,
198
218
  `Sessions (24h): ${stats.sessions24h}`,
199
219
  `Agent calls (total): ${stats.agentCalls}`,
200
- `Last event: ${stats.lastEventAt ?? "never"}`
220
+ `Last event: ${(_a = stats.lastEventAt) != null ? _a : "never"}`
201
221
  ].join("\n");
202
222
  return {
203
223
  content: [{ type: "text", text }],
@@ -209,12 +229,12 @@ function registerProjectTools(server, client) {
209
229
  lastEventAt: stats.lastEventAt
210
230
  }
211
231
  };
212
- }
232
+ })
213
233
  );
214
234
  }
215
235
 
216
236
  // src/tools/components.ts
217
- import { z as z2 } from "zod";
237
+ import { z as z3 } from "zod";
218
238
 
219
239
  // src/ui/templates.ts
220
240
  var VIZ_TITLES = {
@@ -473,21 +493,20 @@ function registerUiResources(server) {
473
493
  }
474
494
 
475
495
  // src/tools/components.ts
476
- var projectIdSchema2 = z2.string().uuid().describe("The project UUID");
477
496
  function registerComponentTools(server, client) {
478
497
  server.registerTool(
479
498
  "list_components",
480
499
  {
481
500
  title: "List components",
482
501
  description: "List all adaptive components in a project with variant counts and impression totals.",
483
- inputSchema: { projectId: projectIdSchema2 },
502
+ inputSchema: { projectId: projectIdSchema },
484
503
  outputSchema: {
485
- components: z2.array(
486
- z2.object({
487
- componentId: z2.string(),
488
- variantCount: z2.number(),
489
- impressions: z2.number(),
490
- conversions: z2.number()
504
+ components: z3.array(
505
+ z3.object({
506
+ componentId: z3.string(),
507
+ variantCount: z3.number(),
508
+ impressions: z3.number(),
509
+ conversions: z3.number()
491
510
  })
492
511
  ).describe("Adaptive components in the project (empty if none)")
493
512
  },
@@ -497,7 +516,7 @@ function registerComponentTools(server, client) {
497
516
  openWorldHint: false
498
517
  }
499
518
  },
500
- async ({ projectId }) => {
519
+ withApiErrorGuidance(async ({ projectId }) => {
501
520
  const id = encodeURIComponent(projectId);
502
521
  const { components } = await client.get(`/projects/${id}/components`);
503
522
  const structuredContent = {
@@ -518,23 +537,23 @@ function registerComponentTools(server, client) {
518
537
  (c) => `- ${c.component_id}: ${c.variants.length} variants, ${c.total_impressions} impressions, ${c.total_conversions} conversions`
519
538
  ).join("\n");
520
539
  return { content: [{ type: "text", text }], structuredContent };
521
- }
540
+ })
522
541
  );
523
542
  server.registerTool(
524
543
  "get_variant_performance",
525
544
  {
526
545
  title: "Variant performance",
527
546
  description: "Get CVR and momentum for all variants in a project over the last 7 days vs prior 7 days.",
528
- inputSchema: { projectId: projectIdSchema2 },
547
+ inputSchema: { projectId: projectIdSchema },
529
548
  _meta: uiMeta("variant-performance"),
530
549
  outputSchema: {
531
- variants: z2.array(
532
- z2.object({
533
- variantId: z2.string(),
534
- currentCvr: z2.number().describe("Conversion rate over the last 7 days (0-1)"),
535
- priorCvr: z2.number().describe("Conversion rate over the prior 7 days (0-1)"),
536
- deltaPp: z2.number().describe("Change in percentage points"),
537
- momentum: z2.string().describe("Momentum direction: gaining, losing, or stable")
550
+ variants: z3.array(
551
+ z3.object({
552
+ variantId: z3.string(),
553
+ currentCvr: z3.number().describe("Conversion rate over the last 7 days (0-1)"),
554
+ priorCvr: z3.number().describe("Conversion rate over the prior 7 days (0-1)"),
555
+ deltaPp: z3.number().describe("Change in percentage points"),
556
+ momentum: z3.string().describe("Momentum direction: gaining, losing, or stable")
538
557
  })
539
558
  ).describe("Per-variant performance (empty if no data yet)")
540
559
  },
@@ -544,20 +563,24 @@ function registerComponentTools(server, client) {
544
563
  openWorldHint: false
545
564
  }
546
565
  },
547
- async ({ projectId }) => {
566
+ withApiErrorGuidance(async ({ projectId }) => {
567
+ var _a, _b, _c;
548
568
  const id = encodeURIComponent(projectId);
549
569
  const data = await client.get(`/projects/${id}/trends`);
550
- const momentumMap = new Map((data.momentum ?? []).map((m) => [m.variantId, m.direction]));
570
+ const momentumMap = new Map(((_a = data.momentum) != null ? _a : []).map((m) => [m.variantId, m.direction]));
551
571
  const structuredContent = {
552
- variants: (data.cvr ?? []).map((v) => ({
553
- variantId: v.variantId,
554
- currentCvr: v.currentCvr,
555
- priorCvr: v.priorCvr,
556
- deltaPp: v.deltaPp,
557
- momentum: momentumMap.get(v.variantId) ?? "stable"
558
- }))
572
+ variants: ((_b = data.cvr) != null ? _b : []).map((v) => {
573
+ var _a2;
574
+ return {
575
+ variantId: v.variantId,
576
+ currentCvr: v.currentCvr,
577
+ priorCvr: v.priorCvr,
578
+ deltaPp: v.deltaPp,
579
+ momentum: (_a2 = momentumMap.get(v.variantId)) != null ? _a2 : "stable"
580
+ };
581
+ })
559
582
  };
560
- if (!data.cvr?.length) {
583
+ if (!((_c = data.cvr) == null ? void 0 : _c.length)) {
561
584
  return {
562
585
  content: [{ type: "text", text: "No variant data available yet." }],
563
586
  structuredContent,
@@ -565,29 +588,31 @@ function registerComponentTools(server, client) {
565
588
  };
566
589
  }
567
590
  const text = data.cvr.map(
568
- (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"})`
591
+ (v) => {
592
+ var _a2;
593
+ 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"})`;
594
+ }
569
595
  ).join("\n");
570
596
  return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("variant-performance") };
571
- }
597
+ })
572
598
  );
573
599
  }
574
600
 
575
601
  // src/tools/insights.ts
576
- import { z as z3 } from "zod";
577
- var projectIdSchema3 = z3.string().uuid().describe("The project UUID");
602
+ import { z as z4 } from "zod";
578
603
  function registerInsightTools(server, client) {
579
604
  server.registerTool(
580
605
  "get_insights",
581
606
  {
582
607
  title: "Get insights",
583
608
  description: "Get the latest AI-generated insights: narrator observations and (Growth tier) advisor recommendations.",
584
- inputSchema: { projectId: projectIdSchema3 },
609
+ inputSchema: { projectId: projectIdSchema },
585
610
  outputSchema: {
586
- status: z3.enum(["ok", "empty"]).describe("Whether insights exist yet"),
587
- observations: z3.array(z3.string()).describe("Narrator observations"),
588
- recommendations: z3.array(z3.string()).describe("Advisor recommendations (Growth tier)"),
589
- isStale: z3.boolean().describe("True when the insights are older than ~6h"),
590
- generatedAt: z3.string().nullable().describe("ISO timestamp the insights were generated, or null")
611
+ status: z4.enum(["ok", "empty"]).describe("Whether insights exist yet"),
612
+ observations: z4.array(z4.string()).describe("Narrator observations"),
613
+ recommendations: z4.array(z4.string()).describe("Advisor recommendations (Growth tier)"),
614
+ isStale: z4.boolean().describe("True when the insights are older than ~6h"),
615
+ generatedAt: z4.string().nullable().describe("ISO timestamp the insights were generated, or null")
591
616
  },
592
617
  annotations: {
593
618
  readOnlyHint: true,
@@ -595,7 +620,8 @@ function registerInsightTools(server, client) {
595
620
  openWorldHint: false
596
621
  }
597
622
  },
598
- async ({ projectId }) => {
623
+ withApiErrorGuidance(async ({ projectId }) => {
624
+ var _a, _b, _c, _d;
599
625
  const id = encodeURIComponent(projectId);
600
626
  const data = await client.get(`/projects/${id}/insights`);
601
627
  if (data.status === "empty") {
@@ -610,8 +636,8 @@ function registerInsightTools(server, client) {
610
636
  }
611
637
  };
612
638
  }
613
- const observations = data.narratorBullets ?? [];
614
- const recommendations = data.advisorBullets ?? [];
639
+ const observations = (_a = data.narratorBullets) != null ? _a : [];
640
+ const recommendations = (_b = data.advisorBullets) != null ? _b : [];
615
641
  const lines = [];
616
642
  if (data.isStale) lines.push("\u26A0 Insights are stale (>6h old). Consider calling refresh_insights.");
617
643
  if (data.generatedAt) lines.push(`Generated: ${new Date(data.generatedAt).toUTCString()}`);
@@ -629,33 +655,32 @@ function registerInsightTools(server, client) {
629
655
  status: "ok",
630
656
  observations,
631
657
  recommendations,
632
- isStale: data.isStale ?? false,
633
- generatedAt: data.generatedAt ?? null
658
+ isStale: (_c = data.isStale) != null ? _c : false,
659
+ generatedAt: (_d = data.generatedAt) != null ? _d : null
634
660
  }
635
661
  };
636
- }
662
+ })
637
663
  );
638
664
  }
639
665
 
640
666
  // src/tools/personas.ts
641
- import { z as z4 } from "zod";
642
- var projectIdSchema4 = z4.string().uuid().describe("The project UUID");
667
+ import { z as z5 } from "zod";
643
668
  function registerPersonaTools(server, client) {
644
669
  server.registerTool(
645
670
  "get_persona_breakdown",
646
671
  {
647
672
  title: "Persona breakdown",
648
673
  description: "Get the distribution of visitor persona clusters with session counts and reliability scores.",
649
- inputSchema: { projectId: projectIdSchema4 },
674
+ inputSchema: { projectId: projectIdSchema },
650
675
  _meta: uiMeta("persona-breakdown"),
651
676
  outputSchema: {
652
- totalSessions: z4.number().describe("Total sessions across all clusters"),
653
- clusters: z4.array(
654
- z4.object({
655
- label: z4.string(),
656
- sessionCount: z4.number(),
657
- sharePct: z4.number().describe("Share of total traffic (0-100)"),
658
- reliability: z4.number().describe("Average cluster reliability (0-1)")
677
+ totalSessions: z5.number().describe("Total sessions across all clusters"),
678
+ clusters: z5.array(
679
+ z5.object({
680
+ label: z5.string(),
681
+ sessionCount: z5.number(),
682
+ sharePct: z5.number().describe("Share of total traffic (0-100)"),
683
+ reliability: z5.number().describe("Average cluster reliability (0-1)")
659
684
  })
660
685
  ).describe("Persona clusters (empty until enough visitor data)")
661
686
  },
@@ -665,7 +690,7 @@ function registerPersonaTools(server, client) {
665
690
  openWorldHint: false
666
691
  }
667
692
  },
668
- async ({ projectId }) => {
693
+ withApiErrorGuidance(async ({ projectId }) => {
669
694
  const id = encodeURIComponent(projectId);
670
695
  const data = await client.get(`/projects/${id}/portraits`);
671
696
  const structuredContent = {
@@ -694,33 +719,32 @@ function registerPersonaTools(server, client) {
694
719
  })
695
720
  ];
696
721
  return { content: [{ type: "text", text: lines.join("\n") }], structuredContent, _meta: uiMeta("persona-breakdown") };
697
- }
722
+ })
698
723
  );
699
724
  }
700
725
 
701
726
  // src/tools/goals.ts
702
- import { z as z5 } from "zod";
703
- var projectIdSchema5 = z5.string().uuid().describe("The project UUID");
727
+ import { z as z6 } from "zod";
704
728
  function registerGoalTools(server, client) {
705
729
  server.registerTool(
706
730
  "get_goal_funnel",
707
731
  {
708
732
  title: "Goal funnel",
709
733
  description: "Get goal hit counts, unique-session conversion rates, and per-variant breakdown.",
710
- inputSchema: { projectId: projectIdSchema5 },
734
+ inputSchema: { projectId: projectIdSchema },
711
735
  _meta: uiMeta("goal-funnel"),
712
736
  outputSchema: {
713
- goals: z5.array(
714
- z5.object({
715
- goalName: z5.string(),
716
- hits: z5.number(),
717
- uniqueSessions: z5.number(),
718
- conversionRate: z5.number().describe("Unique-session conversion rate (0-1)"),
719
- variants: z5.array(
720
- z5.object({
721
- componentId: z5.string(),
722
- variantId: z5.string(),
723
- completionRate: z5.number().describe("Completion rate per assigned session (0-1)")
737
+ goals: z6.array(
738
+ z6.object({
739
+ goalName: z6.string(),
740
+ hits: z6.number(),
741
+ uniqueSessions: z6.number(),
742
+ conversionRate: z6.number().describe("Unique-session conversion rate (0-1)"),
743
+ variants: z6.array(
744
+ z6.object({
745
+ componentId: z6.string(),
746
+ variantId: z6.string(),
747
+ completionRate: z6.number().describe("Completion rate per assigned session (0-1)")
724
748
  })
725
749
  ).describe("Per-variant breakdown")
726
750
  })
@@ -732,7 +756,7 @@ function registerGoalTools(server, client) {
732
756
  openWorldHint: false
733
757
  }
734
758
  },
735
- async ({ projectId }) => {
759
+ withApiErrorGuidance(async ({ projectId }) => {
736
760
  const id = encodeURIComponent(projectId);
737
761
  const data = await client.get(`/projects/${id}/goals`);
738
762
  const structuredContent = {
@@ -761,26 +785,25 @@ function registerGoalTools(server, client) {
761
785
  ""
762
786
  ]);
763
787
  return { content: [{ type: "text", text: lines.join("\n").trim() }], structuredContent, _meta: uiMeta("goal-funnel") };
764
- }
788
+ })
765
789
  );
766
790
  }
767
791
 
768
792
  // src/tools/guardrails.ts
769
- import { z as z6 } from "zod";
770
- var projectIdSchema6 = z6.string().uuid().describe("The project UUID");
793
+ import { z as z7 } from "zod";
771
794
  function registerGuardrailTools(server, client) {
772
795
  server.registerTool(
773
796
  "list_guardrail_events",
774
797
  {
775
798
  title: "List guardrail events",
776
799
  description: "List variants currently paused by the guardrail in the last 24 hours.",
777
- inputSchema: { projectId: projectIdSchema6 },
800
+ inputSchema: { projectId: projectIdSchema },
778
801
  outputSchema: {
779
- events: z6.array(
780
- z6.object({
781
- componentId: z6.string(),
782
- variantIds: z6.array(z6.string()).describe("Variants paused by the guardrail"),
783
- pausedAt: z6.string().nullable().describe("ISO timestamp the pause fired, or null")
802
+ events: z7.array(
803
+ z7.object({
804
+ componentId: z7.string(),
805
+ variantIds: z7.array(z7.string()).describe("Variants paused by the guardrail"),
806
+ pausedAt: z7.string().nullable().describe("ISO timestamp the pause fired, or null")
784
807
  })
785
808
  ).describe("Guardrail events in the last 24h (empty if none)")
786
809
  },
@@ -790,7 +813,7 @@ function registerGuardrailTools(server, client) {
790
813
  openWorldHint: false
791
814
  }
792
815
  },
793
- async ({ projectId }) => {
816
+ withApiErrorGuidance(async ({ projectId }) => {
794
817
  const id = encodeURIComponent(projectId);
795
818
  const data = await client.get(`/projects/${id}/guardrail-events`);
796
819
  const structuredContent = {
@@ -810,28 +833,27 @@ function registerGuardrailTools(server, client) {
810
833
  (e) => `- ${e.componentId}: variants [${e.variantIds.join(", ")}] paused${e.pausedAt ? ` at ${e.pausedAt}` : ""}`
811
834
  );
812
835
  return { content: [{ type: "text", text: lines.join("\n") }], structuredContent };
813
- }
836
+ })
814
837
  );
815
838
  }
816
839
 
817
840
  // src/tools/layout.ts
818
- import { z as z7 } from "zod";
819
- var projectIdSchema7 = z7.string().uuid().describe("The project UUID");
841
+ import { z as z8 } from "zod";
820
842
  function registerLayoutTools(server, client) {
821
843
  server.registerTool(
822
844
  "get_layout_stats",
823
845
  {
824
846
  title: "Layout stats",
825
847
  description: "Get per-persona section layout rankings and bandit reward weights.",
826
- inputSchema: { projectId: projectIdSchema7 },
848
+ inputSchema: { projectId: projectIdSchema },
827
849
  _meta: uiMeta("layout-stats"),
828
850
  outputSchema: {
829
- layouts: z7.array(
830
- z7.object({
831
- persona: z7.string(),
832
- layoutOrder: z7.array(z7.string()).describe("Ranked section order for this persona"),
833
- pulls: z7.number().describe("Number of times this arm was served"),
834
- avgReward: z7.number().describe("Average bandit reward weight")
851
+ layouts: z8.array(
852
+ z8.object({
853
+ persona: z8.string(),
854
+ layoutOrder: z8.array(z8.string()).describe("Ranked section order for this persona"),
855
+ pulls: z8.number().describe("Number of times this arm was served"),
856
+ avgReward: z8.number().describe("Average bandit reward weight")
835
857
  })
836
858
  ).describe("Per-persona layout rankings (empty until enough sessions)")
837
859
  },
@@ -841,7 +863,7 @@ function registerLayoutTools(server, client) {
841
863
  openWorldHint: false
842
864
  }
843
865
  },
844
- async ({ projectId }) => {
866
+ withApiErrorGuidance(async ({ projectId }) => {
845
867
  const id = encodeURIComponent(projectId);
846
868
  const stats = await client.get(`/projects/${id}/layout-stats`);
847
869
  const structuredContent = {
@@ -863,13 +885,12 @@ function registerLayoutTools(server, client) {
863
885
  (s) => `- ${s.persona}: [${s.layoutOrder.join(" \u2192 ")}] (avg reward: ${s.avgReward.toFixed(2)}, ${s.pulls} pulls)`
864
886
  ).join("\n");
865
887
  return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("layout-stats") };
866
- }
888
+ })
867
889
  );
868
890
  }
869
891
 
870
892
  // src/tools/variants.ts
871
- import { z as z8 } from "zod";
872
- var projectIdSchema8 = z8.string().uuid().describe("The project UUID");
893
+ import { z as z9 } from "zod";
873
894
  function registerVariantWriteTools(server, client) {
874
895
  server.registerTool(
875
896
  "create_variant",
@@ -877,17 +898,20 @@ function registerVariantWriteTools(server, client) {
877
898
  title: "Create managed variant",
878
899
  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).",
879
900
  inputSchema: {
880
- projectId: projectIdSchema8,
881
- componentId: z8.string().describe("The component ID to add a variant to"),
882
- displayName: z8.string().describe("Human-readable name for the new variant"),
883
- content: z8.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.")
901
+ projectId: projectIdSchema,
902
+ componentId: z9.string().min(1).max(200).describe("The component ID to add a variant to"),
903
+ displayName: z9.string().min(1).max(200).describe("Human-readable name for the new variant"),
904
+ content: z9.string().max(1e4).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.")
884
905
  },
885
906
  outputSchema: {
886
- variantId: z8.string().describe("The new variant ID"),
887
- displayName: z8.string(),
888
- componentId: z8.string(),
889
- state: z8.literal("draft").describe("New managed variants start in draft state"),
890
- hasContent: z8.boolean().describe("Whether text content was provided at creation")
907
+ variantId: z9.string().describe("The new variant ID"),
908
+ // API returns `body.displayName ?? null`, so a successful create can
909
+ // carry a null name — match that contract or outputSchema validation
910
+ // would reject an otherwise-successful response.
911
+ displayName: z9.string().nullable(),
912
+ componentId: z9.string(),
913
+ state: z9.literal("draft").describe("New managed variants start in draft state"),
914
+ hasContent: z9.boolean().describe("Whether text content was provided at creation")
891
915
  },
892
916
  annotations: {
893
917
  readOnlyHint: false,
@@ -896,7 +920,7 @@ function registerVariantWriteTools(server, client) {
896
920
  openWorldHint: false
897
921
  }
898
922
  },
899
- async ({ projectId, componentId, displayName, content }) => {
923
+ withApiErrorGuidance(async ({ projectId, componentId, displayName, content }) => {
900
924
  const id = encodeURIComponent(projectId);
901
925
  const result = await client.post(
902
926
  `/projects/${id}/variants`,
@@ -916,7 +940,7 @@ function registerVariantWriteTools(server, client) {
916
940
  hasContent: Boolean(content)
917
941
  }
918
942
  };
919
- }
943
+ })
920
944
  );
921
945
  server.registerTool(
922
946
  "pause_variant",
@@ -924,14 +948,14 @@ function registerVariantWriteTools(server, client) {
924
948
  title: "Pause variant",
925
949
  description: "Pause a variant, stopping traffic from being assigned to it.",
926
950
  inputSchema: {
927
- projectId: projectIdSchema8,
928
- componentId: z8.string().describe("The component ID"),
929
- variantId: z8.string().describe("The variant ID to pause")
951
+ projectId: projectIdSchema,
952
+ componentId: z9.string().describe("The component ID"),
953
+ variantId: z9.string().describe("The variant ID to pause")
930
954
  },
931
955
  outputSchema: {
932
- variantId: z8.string(),
933
- componentId: z8.string(),
934
- paused: z8.literal(true).describe("The variant is now paused")
956
+ variantId: z9.string(),
957
+ componentId: z9.string(),
958
+ paused: z9.literal(true).describe("The variant is now paused")
935
959
  },
936
960
  annotations: {
937
961
  readOnlyHint: false,
@@ -940,7 +964,7 @@ function registerVariantWriteTools(server, client) {
940
964
  openWorldHint: false
941
965
  }
942
966
  },
943
- async ({ projectId, componentId, variantId }) => {
967
+ withApiErrorGuidance(async ({ projectId, componentId, variantId }) => {
944
968
  const id = encodeURIComponent(projectId);
945
969
  await client.post(`/projects/${id}/variants/pause`, { componentId, variantId });
946
970
  return {
@@ -950,17 +974,17 @@ function registerVariantWriteTools(server, client) {
950
974
  }],
951
975
  structuredContent: { variantId, componentId, paused: true }
952
976
  };
953
- }
977
+ })
954
978
  );
955
979
  server.registerTool(
956
980
  "refresh_insights",
957
981
  {
958
982
  title: "Refresh insights",
959
983
  description: "Trigger fresh AI insight generation for a project. Returns immediately; use get_insights in ~15 seconds to see results.",
960
- inputSchema: { projectId: projectIdSchema8 },
984
+ inputSchema: { projectId: projectIdSchema },
961
985
  outputSchema: {
962
- projectId: z8.string(),
963
- status: z8.literal("generating").describe("Generation has been triggered")
986
+ projectId: z9.string(),
987
+ status: z9.literal("generating").describe("Generation has been triggered")
964
988
  },
965
989
  annotations: {
966
990
  readOnlyHint: false,
@@ -969,7 +993,7 @@ function registerVariantWriteTools(server, client) {
969
993
  openWorldHint: false
970
994
  }
971
995
  },
972
- async ({ projectId }) => {
996
+ withApiErrorGuidance(async ({ projectId }) => {
973
997
  const id = encodeURIComponent(projectId);
974
998
  await client.post(`/projects/${id}/insights/refresh`);
975
999
  return {
@@ -979,13 +1003,12 @@ function registerVariantWriteTools(server, client) {
979
1003
  }],
980
1004
  structuredContent: { projectId, status: "generating" }
981
1005
  };
982
- }
1006
+ })
983
1007
  );
984
1008
  }
985
1009
 
986
1010
  // src/tools/variant-brief.ts
987
- import { z as z9 } from "zod";
988
- var projectIdSchema9 = z9.string().uuid().describe("The project UUID");
1011
+ import { z as z10 } from "zod";
989
1012
  var GOAL_TARGET = 500;
990
1013
  var BEST_PRACTICE_PRIORS = {
991
1014
  ecommerce: [
@@ -1023,11 +1046,12 @@ var GENERIC_PRIORS = [
1023
1046
  "Add one credible proof point near the action."
1024
1047
  ];
1025
1048
  function priorsFor(contextType) {
1026
- return BEST_PRACTICE_PRIORS[contextType] ?? GENERIC_PRIORS;
1049
+ var _a;
1050
+ return (_a = BEST_PRACTICE_PRIORS[contextType]) != null ? _a : GENERIC_PRIORS;
1027
1051
  }
1028
1052
  function computeDataState(impressions, insights, avgReliability) {
1029
1053
  if (impressions === 0) return "empty";
1030
- const insightsReady = insights?.status === "ok" && !insights.isStale;
1054
+ const insightsReady = (insights == null ? void 0 : insights.status) === "ok" && !insights.isStale;
1031
1055
  const reliable = avgReliability === null || avgReliability >= 0.3;
1032
1056
  if (impressions < GOAL_TARGET || !insightsReady || !reliable) return "collecting";
1033
1057
  return "sufficient";
@@ -1045,7 +1069,7 @@ function guidanceFor(dataState, contextType) {
1045
1069
  async function settled(p) {
1046
1070
  try {
1047
1071
  return await p;
1048
- } catch {
1072
+ } catch (e) {
1049
1073
  return null;
1050
1074
  }
1051
1075
  }
@@ -1056,16 +1080,16 @@ function registerVariantBriefTools(server, client) {
1056
1080
  title: "Variant brief",
1057
1081
  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.",
1058
1082
  inputSchema: {
1059
- projectId: projectIdSchema9,
1060
- componentId: z9.string().describe('The component ID to write a new variant for (matches <Adaptive id="...">).')
1083
+ projectId: projectIdSchema,
1084
+ componentId: z10.string().describe('The component ID to write a new variant for (matches <Adaptive id="...">).')
1061
1085
  },
1062
1086
  outputSchema: {
1063
- componentId: z9.string(),
1064
- contextType: z9.string().describe("The project's context type (or 'unknown')"),
1065
- dataState: z9.enum(["sufficient", "collecting", "empty"]).describe("Data-sufficiency assessment"),
1066
- existingVariantIds: z9.array(z9.string()).describe("Variant IDs already in use (do not reuse)"),
1067
- priors: z9.array(z9.string()).describe("Best-practice priors applied for this context type"),
1068
- markdown: z9.string().describe("The full variant brief in Markdown")
1087
+ componentId: z10.string(),
1088
+ contextType: z10.string().describe("The project's context type (or 'unknown')"),
1089
+ dataState: z10.enum(["sufficient", "collecting", "empty"]).describe("Data-sufficiency assessment"),
1090
+ existingVariantIds: z10.array(z10.string()).describe("Variant IDs already in use (do not reuse)"),
1091
+ priors: z10.array(z10.string()).describe("Best-practice priors applied for this context type"),
1092
+ markdown: z10.string().describe("The full variant brief in Markdown")
1069
1093
  },
1070
1094
  annotations: {
1071
1095
  readOnlyHint: true,
@@ -1073,7 +1097,8 @@ function registerVariantBriefTools(server, client) {
1073
1097
  openWorldHint: false
1074
1098
  }
1075
1099
  },
1076
- async ({ projectId, componentId }) => {
1100
+ withApiErrorGuidance(async ({ projectId, componentId }) => {
1101
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
1077
1102
  const id = encodeURIComponent(projectId);
1078
1103
  const [projects, componentsEnvelope, trends, portraits, insights] = await Promise.all([
1079
1104
  settled(client.get("/projects")),
@@ -1083,19 +1108,19 @@ function registerVariantBriefTools(server, client) {
1083
1108
  settled(client.get(`/projects/${id}/portraits`)),
1084
1109
  settled(client.get(`/projects/${id}/insights`))
1085
1110
  ]);
1086
- const project = projects?.find((p) => p.id === projectId) ?? null;
1087
- const contextType = project?.context_type ?? "unknown";
1088
- const components = componentsEnvelope?.components ?? [];
1089
- const component = components.find((c) => c.component_id === componentId) ?? null;
1090
- const impressions = component?.total_impressions ?? 0;
1091
- const conversions = component?.total_conversions ?? 0;
1111
+ const project = (_a = projects == null ? void 0 : projects.find((p) => p.id === projectId)) != null ? _a : null;
1112
+ const contextType = (_b = project == null ? void 0 : project.context_type) != null ? _b : "unknown";
1113
+ const components = (_c = componentsEnvelope == null ? void 0 : componentsEnvelope.components) != null ? _c : [];
1114
+ const component = (_d = components.find((c) => c.component_id === componentId)) != null ? _d : null;
1115
+ const impressions = (_e = component == null ? void 0 : component.total_impressions) != null ? _e : 0;
1116
+ const conversions = (_f = component == null ? void 0 : component.total_conversions) != null ? _f : 0;
1092
1117
  const componentCvr = impressions > 0 ? conversions / impressions * 100 : 0;
1093
- const existingVariantIds = component?.variants.map((v) => v.variant_id) ?? [];
1118
+ const existingVariantIds = (_g = component == null ? void 0 : component.variants.map((v) => v.variant_id)) != null ? _g : [];
1094
1119
  const variantIdSet = new Set(existingVariantIds);
1095
- const momentumMap = new Map((trends?.momentum ?? []).map((m) => [m.variantId, m.direction]));
1096
- const variantPerf = (trends?.cvr ?? []).filter((v) => variantIdSet.has(v.variantId));
1097
- const clusters = portraits?.clusters ?? [];
1098
- const totalSessions = portraits?.totalSessions ?? 0;
1120
+ const momentumMap = new Map(((_h = trends == null ? void 0 : trends.momentum) != null ? _h : []).map((m) => [m.variantId, m.direction]));
1121
+ const variantPerf = ((_i = trends == null ? void 0 : trends.cvr) != null ? _i : []).filter((v) => variantIdSet.has(v.variantId));
1122
+ const clusters = (_j = portraits == null ? void 0 : portraits.clusters) != null ? _j : [];
1123
+ const totalSessions = (_k = portraits == null ? void 0 : portraits.totalSessions) != null ? _k : 0;
1099
1124
  const avgReliability = clusters.length ? clusters.reduce((s, c) => s + c.avgReliability, 0) / clusters.length : null;
1100
1125
  const dataState = computeDataState(impressions, insights, avgReliability);
1101
1126
  const lines = [];
@@ -1120,7 +1145,7 @@ function registerVariantBriefTools(server, client) {
1120
1145
  lines.push("Current variant performance (7d vs prior 7d):");
1121
1146
  for (const v of variantPerf) {
1122
1147
  lines.push(
1123
- `- ${v.variantId}: ${(v.currentCvr * 100).toFixed(2)}% CVR (${v.deltaPp > 0 ? "+" : ""}${v.deltaPp.toFixed(1)} pp, ${momentumMap.get(v.variantId) ?? "stable"})`
1148
+ `- ${v.variantId}: ${(v.currentCvr * 100).toFixed(2)}% CVR (${v.deltaPp > 0 ? "+" : ""}${v.deltaPp.toFixed(1)} pp, ${(_l = momentumMap.get(v.variantId)) != null ? _l : "stable"})`
1124
1149
  );
1125
1150
  }
1126
1151
  lines.push("");
@@ -1135,8 +1160,8 @@ function registerVariantBriefTools(server, client) {
1135
1160
  }
1136
1161
  if (insights && insights.status === "ok") {
1137
1162
  if (insights.isStale) lines.push("\u26A0 Insights are stale (>6h). Consider refresh_insights for a fresher read.");
1138
- const narrator = insights.narratorBullets ?? [];
1139
- const advisor = insights.advisorBullets ?? [];
1163
+ const narrator = (_m = insights.narratorBullets) != null ? _m : [];
1164
+ const advisor = (_n = insights.advisorBullets) != null ? _n : [];
1140
1165
  if (narrator.length) {
1141
1166
  lines.push("Insights \u2014 observations:");
1142
1167
  narrator.forEach((b) => lines.push(`- ${b}`));
@@ -1176,17 +1201,16 @@ function registerVariantBriefTools(server, client) {
1176
1201
  markdown
1177
1202
  }
1178
1203
  };
1179
- }
1204
+ })
1180
1205
  );
1181
1206
  }
1182
1207
 
1183
1208
  // src/tools/test-brief.ts
1184
- import { z as z10 } from "zod";
1185
- var projectIdSchema10 = z10.string().uuid().describe("The project UUID");
1209
+ import { z as z11 } from "zod";
1186
1210
  async function settled2(p) {
1187
1211
  try {
1188
1212
  return await p;
1189
- } catch {
1213
+ } catch (e) {
1190
1214
  return null;
1191
1215
  }
1192
1216
  }
@@ -1197,14 +1221,14 @@ function registerTestBriefTools(server, client) {
1197
1221
  title: "Test brief",
1198
1222
  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).",
1199
1223
  inputSchema: {
1200
- projectId: projectIdSchema10,
1201
- componentId: z10.string().describe('The component ID to write a test for (matches <Adaptive id="...">).')
1224
+ projectId: projectIdSchema,
1225
+ componentId: z11.string().describe('The component ID to write a test for (matches <Adaptive id="...">).')
1202
1226
  },
1203
1227
  outputSchema: {
1204
- componentId: z10.string(),
1205
- forcedVariantId: z10.string().describe("The non-control variant the example forces"),
1206
- goalName: z10.string().describe("The goal the example asserts fires"),
1207
- markdown: z10.string().describe("The full test brief in Markdown")
1228
+ componentId: z11.string(),
1229
+ forcedVariantId: z11.string().describe("The non-control variant the example forces"),
1230
+ goalName: z11.string().describe("The goal the example asserts fires"),
1231
+ markdown: z11.string().describe("The full test brief in Markdown")
1208
1232
  },
1209
1233
  annotations: {
1210
1234
  readOnlyHint: true,
@@ -1212,20 +1236,21 @@ function registerTestBriefTools(server, client) {
1212
1236
  openWorldHint: false
1213
1237
  }
1214
1238
  },
1215
- async ({ projectId, componentId }) => {
1239
+ withApiErrorGuidance(async ({ projectId, componentId }) => {
1240
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1216
1241
  const id = encodeURIComponent(projectId);
1217
1242
  const [componentsEnvelope, goalsRes] = await Promise.all([
1218
1243
  // mgmt API returns a paginated envelope: { components, total, page, limit }.
1219
1244
  settled2(client.get(`/projects/${id}/components`)),
1220
1245
  settled2(client.get(`/projects/${id}/goals`))
1221
1246
  ]);
1222
- const components = componentsEnvelope?.components ?? [];
1223
- const component = components.find((c) => c.component_id === componentId) ?? null;
1224
- const variantIds = component?.variants.map((v) => v.variant_id) ?? [];
1225
- const goals = Array.isArray(goalsRes) ? goalsRes : goalsRes?.goals ?? [];
1226
- const goalName = goals[0]?.goalName ?? "signup";
1227
- const controlId = variantIds[0] ?? "control";
1228
- const forcedId = variantIds.find((v) => v !== controlId) ?? "variant_b";
1247
+ const components = (_a = componentsEnvelope == null ? void 0 : componentsEnvelope.components) != null ? _a : [];
1248
+ const component = (_b = components.find((c) => c.component_id === componentId)) != null ? _b : null;
1249
+ const variantIds = (_c = component == null ? void 0 : component.variants.map((v) => v.variant_id)) != null ? _c : [];
1250
+ const goals = Array.isArray(goalsRes) ? goalsRes : (_d = goalsRes == null ? void 0 : goalsRes.goals) != null ? _d : [];
1251
+ const goalName = (_f = (_e = goals[0]) == null ? void 0 : _e.goalName) != null ? _f : "signup";
1252
+ const controlId = (_g = variantIds[0]) != null ? _g : "control";
1253
+ const forcedId = (_h = variantIds.find((v) => v !== controlId)) != null ? _h : "variant_b";
1229
1254
  const lines = [];
1230
1255
  lines.push(`# Test brief \u2014 ${componentId}`);
1231
1256
  lines.push("");
@@ -1281,12 +1306,12 @@ function registerTestBriefTools(server, client) {
1281
1306
  content: [{ type: "text", text: markdown }],
1282
1307
  structuredContent: { componentId, forcedVariantId: forcedId, goalName, markdown }
1283
1308
  };
1284
- }
1309
+ })
1285
1310
  );
1286
1311
  }
1287
1312
 
1288
1313
  // src/tools/integration-guide.ts
1289
- import { z as z11 } from "zod";
1314
+ import { z as z12 } from "zod";
1290
1315
  var GUIDE = `# SentientUI integration guide \u2014 the adaptive ladder
1291
1316
 
1292
1317
  SentientUI adapts a site per visitor type (personas: buyer, researcher, deal_seeker, browser,
@@ -1361,7 +1386,7 @@ function registerIntegrationGuideTools(server) {
1361
1386
  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.",
1362
1387
  inputSchema: {},
1363
1388
  outputSchema: {
1364
- guide: z11.string().describe("The full integration guide in Markdown")
1389
+ guide: z12.string().describe("The full integration guide in Markdown")
1365
1390
  },
1366
1391
  annotations: {
1367
1392
  readOnlyHint: true,
@@ -1377,7 +1402,7 @@ function registerIntegrationGuideTools(server) {
1377
1402
  }
1378
1403
 
1379
1404
  // src/server.ts
1380
- var { version: PKG_VERSION } = createRequire(import.meta.url)("../package.json");
1405
+ var PKG_VERSION = true ? "0.8.2" : "0.0.0-dev";
1381
1406
  function createMcpServer(client) {
1382
1407
  const server = new McpServer(
1383
1408
  {