@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.
package/dist/lib.cjs CHANGED
@@ -27,15 +27,13 @@ __export(lib_exports, {
27
27
  });
28
28
  module.exports = __toCommonJS(lib_exports);
29
29
 
30
- // ../../node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.14_tsx@4.22.1_typescript@5.9.3_yaml@2.9.0/node_modules/tsup/assets/cjs_shims.js
31
- var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
32
- var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
33
-
34
30
  // src/server.ts
35
- var import_node_module = require("module");
36
31
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
37
32
 
38
33
  // src/tools/projects.ts
34
+ var import_zod2 = require("zod");
35
+
36
+ // src/tools/common.ts
39
37
  var import_zod = require("zod");
40
38
 
41
39
  // src/api-client.ts
@@ -45,16 +43,15 @@ var ApiError = class extends Error {
45
43
  this.status = status;
46
44
  this.name = "ApiError";
47
45
  }
48
- status;
49
46
  };
50
47
  var ApiClient = class {
51
- baseUrl;
52
- apiKey;
53
48
  constructor(opts) {
49
+ var _a;
54
50
  this.apiKey = opts.apiKey;
55
- this.baseUrl = (opts.baseUrl ?? "https://api.sentient-ui.com").replace(/\/$/, "");
51
+ this.baseUrl = ((_a = opts.baseUrl) != null ? _a : "https://api.sentient-ui.com").replace(/\/$/, "");
56
52
  }
57
53
  async get(path) {
54
+ var _a;
58
55
  const res = await fetch(`${this.baseUrl}/v1/mgmt${path}`, {
59
56
  headers: {
60
57
  authorization: `Bearer ${this.apiKey}`,
@@ -63,11 +60,12 @@ var ApiClient = class {
63
60
  });
64
61
  if (!res.ok) {
65
62
  const body = await res.json().catch(() => ({}));
66
- throw new ApiError(res.status, String(body.error ?? res.statusText));
63
+ throw new ApiError(res.status, String((_a = body.error) != null ? _a : res.statusText));
67
64
  }
68
65
  return res.json();
69
66
  }
70
67
  async post(path, body) {
68
+ var _a;
71
69
  const res = await fetch(`${this.baseUrl}/v1/mgmt${path}`, {
72
70
  method: "POST",
73
71
  headers: {
@@ -78,30 +76,57 @@ var ApiClient = class {
78
76
  });
79
77
  if (!res.ok) {
80
78
  const errBody = await res.json().catch(() => ({}));
81
- throw new ApiError(res.status, String(errBody.error ?? res.statusText));
79
+ throw new ApiError(res.status, String((_a = errBody.error) != null ? _a : res.statusText));
82
80
  }
83
81
  return res.json();
84
82
  }
85
83
  };
86
84
 
87
- // src/tools/projects.ts
85
+ // src/tools/common.ts
88
86
  var projectIdSchema = import_zod.z.string().uuid().describe("The project UUID");
89
- function createProjectGuidance(err) {
87
+ function apiErrorGuidance(err, extra) {
88
+ if (extra && Object.prototype.hasOwnProperty.call(extra, err.message)) {
89
+ return extra[err.message];
90
+ }
90
91
  switch (err.message) {
91
92
  case "insufficient_scope":
92
- 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.";
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.";
93
94
  case "demo_read_only":
94
- return "Demo mode is read-only. Create a SentientUI account and sign in to make projects.";
95
+ return "Demo mode is read-only. Create a SentientUI account and sign in (or use a project server key) to make changes.";
95
96
  case "insufficient_role":
96
- return "Your account role cannot create projects \u2014 this needs the account owner or an admin.";
97
- case "project_limit_reached":
98
- return "You've reached your plan's project limit. Upgrade your plan or remove an existing project, then try again.";
99
- case "name_required":
100
- return "A project name is required to create a project.";
97
+ return "Your account role does not permit this action \u2014 it needs the account owner or an admin.";
101
98
  default:
102
- return null;
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.`;
103
106
  }
107
+ return null;
108
+ }
109
+ function withApiErrorGuidance(fn, extra) {
110
+ return async (args) => {
111
+ try {
112
+ return await fn(args);
113
+ } catch (err) {
114
+ if (err instanceof ApiError) {
115
+ const guidance = apiErrorGuidance(err, extra);
116
+ if (guidance) {
117
+ return { content: [{ type: "text", text: guidance }], isError: true };
118
+ }
119
+ }
120
+ throw err;
121
+ }
122
+ };
104
123
  }
124
+
125
+ // src/tools/projects.ts
126
+ var CREATE_PROJECT_GUIDANCE = {
127
+ project_limit_reached: "You've reached your plan's project limit. Upgrade your plan or remove an existing project, then try again.",
128
+ name_required: "A project name is required to create a project."
129
+ };
105
130
  function registerProjectTools(server, client) {
106
131
  server.registerTool(
107
132
  "create_project",
@@ -109,16 +134,16 @@ function registerProjectTools(server, client) {
109
134
  title: "Create project",
110
135
  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
136
  inputSchema: {
112
- name: import_zod.z.string().min(1).describe("Human-readable project name"),
113
- contextType: import_zod.z.enum(["saas", "ecommerce", "marketing", "landing", "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")
137
+ name: import_zod2.z.string().min(1).describe("Human-readable project name"),
138
+ contextType: import_zod2.z.enum(["saas", "ecommerce", "marketing", "landing", "internal"]).optional().describe("What kind of product this is; defaults to saas"),
139
+ 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"),
140
+ 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
141
  },
117
142
  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")
143
+ projectId: import_zod2.z.string().describe("The new project UUID"),
144
+ publicKey: import_zod2.z.string().describe("The pk_ public key to configure the SDK with"),
145
+ name: import_zod2.z.string().describe("The project name"),
146
+ contextType: import_zod2.z.string().describe("The resolved context type")
122
147
  },
123
148
  annotations: {
124
149
  readOnlyHint: false,
@@ -127,41 +152,31 @@ function registerProjectTools(server, client) {
127
152
  openWorldHint: false
128
153
  }
129
154
  },
130
- async ({ name, contextType, framework, websiteUrl }) => {
131
- try {
132
- const created = await client.post("/projects", {
155
+ withApiErrorGuidance(async ({ name, contextType, framework, websiteUrl }) => {
156
+ const created = await client.post("/projects", {
157
+ name,
158
+ contextType,
159
+ framework,
160
+ origin: websiteUrl
161
+ });
162
+ const resolvedContextType = contextType != null ? contextType : "saas";
163
+ return {
164
+ content: [{
165
+ type: "text",
166
+ text: [
167
+ `Created project "${name}" (id: ${created.id}, type: ${resolvedContextType}).`,
168
+ `Public key: ${created.apiKey}`,
169
+ `Next: install @sentientui/react with this key. Ask me to pull the setup guide (get_integration_guide) and I'll wrap your first component.`
170
+ ].join("\n")
171
+ }],
172
+ structuredContent: {
173
+ projectId: created.id,
174
+ publicKey: created.apiKey,
133
175
  name,
134
- contextType,
135
- framework,
136
- origin: websiteUrl
137
- });
138
- const resolvedContextType = contextType ?? "saas";
139
- return {
140
- content: [{
141
- type: "text",
142
- text: [
143
- `Created project "${name}" (id: ${created.id}, type: ${resolvedContextType}).`,
144
- `Public key: ${created.apiKey}`,
145
- `Next: install @sentientui/react with this key. Ask me to pull the setup guide (get_integration_guide) and I'll wrap your first component.`
146
- ].join("\n")
147
- }],
148
- structuredContent: {
149
- projectId: created.id,
150
- publicKey: created.apiKey,
151
- name,
152
- contextType: resolvedContextType
153
- }
154
- };
155
- } catch (err) {
156
- if (err instanceof ApiError) {
157
- const guidance = createProjectGuidance(err);
158
- if (guidance) {
159
- return { content: [{ type: "text", text: guidance }], isError: true };
160
- }
176
+ contextType: resolvedContextType
161
177
  }
162
- throw err;
163
- }
164
- }
178
+ };
179
+ }, CREATE_PROJECT_GUIDANCE)
165
180
  );
166
181
  server.registerTool(
167
182
  "list_projects",
@@ -170,12 +185,12 @@ function registerProjectTools(server, client) {
170
185
  description: "List all SentientUI projects for the authenticated account.",
171
186
  inputSchema: {},
172
187
  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)")
188
+ projects: import_zod2.z.array(
189
+ import_zod2.z.object({
190
+ id: import_zod2.z.string().describe("Project UUID"),
191
+ name: import_zod2.z.string(),
192
+ contextType: import_zod2.z.string(),
193
+ createdAt: import_zod2.z.string().describe("ISO date (YYYY-MM-DD)")
179
194
  })
180
195
  ).describe("All projects for the account (empty if none)")
181
196
  },
@@ -185,7 +200,7 @@ function registerProjectTools(server, client) {
185
200
  openWorldHint: false
186
201
  }
187
202
  },
188
- async () => {
203
+ withApiErrorGuidance(async () => {
189
204
  const projects = await client.get("/projects");
190
205
  const text = projects.length === 0 ? "No projects found." : projects.map(
191
206
  (p) => `- ${p.name} (id: ${p.id}, type: ${p.context_type}, created: ${p.created_at.slice(0, 10)})`
@@ -201,7 +216,7 @@ function registerProjectTools(server, client) {
201
216
  }))
202
217
  }
203
218
  };
204
- }
219
+ })
205
220
  );
206
221
  server.registerTool(
207
222
  "get_project_stats",
@@ -210,11 +225,11 @@ function registerProjectTools(server, client) {
210
225
  description: "Get health stats for a project: event volume, session count, agent calls, and status.",
211
226
  inputSchema: { projectId: projectIdSchema },
212
227
  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")
228
+ status: import_zod2.z.string().describe("Overall project health status"),
229
+ events24h: import_zod2.z.number().describe("Events in the last 24 hours"),
230
+ sessions24h: import_zod2.z.number().describe("Sessions in the last 24 hours"),
231
+ agentCalls: import_zod2.z.number().describe("Total agent (MCP/API) calls"),
232
+ lastEventAt: import_zod2.z.string().nullable().describe("ISO timestamp of the last event, or null")
218
233
  },
219
234
  annotations: {
220
235
  readOnlyHint: true,
@@ -222,7 +237,8 @@ function registerProjectTools(server, client) {
222
237
  openWorldHint: false
223
238
  }
224
239
  },
225
- async ({ projectId }) => {
240
+ withApiErrorGuidance(async ({ projectId }) => {
241
+ var _a;
226
242
  const id = encodeURIComponent(projectId);
227
243
  const stats = await client.get(`/projects/${id}/health`);
228
244
  const text = [
@@ -230,7 +246,7 @@ function registerProjectTools(server, client) {
230
246
  `Events (24h): ${stats.events24h}`,
231
247
  `Sessions (24h): ${stats.sessions24h}`,
232
248
  `Agent calls (total): ${stats.agentCalls}`,
233
- `Last event: ${stats.lastEventAt ?? "never"}`
249
+ `Last event: ${(_a = stats.lastEventAt) != null ? _a : "never"}`
234
250
  ].join("\n");
235
251
  return {
236
252
  content: [{ type: "text", text }],
@@ -242,12 +258,12 @@ function registerProjectTools(server, client) {
242
258
  lastEventAt: stats.lastEventAt
243
259
  }
244
260
  };
245
- }
261
+ })
246
262
  );
247
263
  }
248
264
 
249
265
  // src/tools/components.ts
250
- var import_zod2 = require("zod");
266
+ var import_zod3 = require("zod");
251
267
 
252
268
  // src/ui/templates.ts
253
269
  var VIZ_TITLES = {
@@ -506,21 +522,20 @@ function registerUiResources(server) {
506
522
  }
507
523
 
508
524
  // src/tools/components.ts
509
- var projectIdSchema2 = import_zod2.z.string().uuid().describe("The project UUID");
510
525
  function registerComponentTools(server, client) {
511
526
  server.registerTool(
512
527
  "list_components",
513
528
  {
514
529
  title: "List components",
515
530
  description: "List all adaptive components in a project with variant counts and impression totals.",
516
- inputSchema: { projectId: projectIdSchema2 },
531
+ inputSchema: { projectId: projectIdSchema },
517
532
  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()
533
+ components: import_zod3.z.array(
534
+ import_zod3.z.object({
535
+ componentId: import_zod3.z.string(),
536
+ variantCount: import_zod3.z.number(),
537
+ impressions: import_zod3.z.number(),
538
+ conversions: import_zod3.z.number()
524
539
  })
525
540
  ).describe("Adaptive components in the project (empty if none)")
526
541
  },
@@ -530,7 +545,7 @@ function registerComponentTools(server, client) {
530
545
  openWorldHint: false
531
546
  }
532
547
  },
533
- async ({ projectId }) => {
548
+ withApiErrorGuidance(async ({ projectId }) => {
534
549
  const id = encodeURIComponent(projectId);
535
550
  const { components } = await client.get(`/projects/${id}/components`);
536
551
  const structuredContent = {
@@ -551,23 +566,23 @@ function registerComponentTools(server, client) {
551
566
  (c) => `- ${c.component_id}: ${c.variants.length} variants, ${c.total_impressions} impressions, ${c.total_conversions} conversions`
552
567
  ).join("\n");
553
568
  return { content: [{ type: "text", text }], structuredContent };
554
- }
569
+ })
555
570
  );
556
571
  server.registerTool(
557
572
  "get_variant_performance",
558
573
  {
559
574
  title: "Variant performance",
560
575
  description: "Get CVR and momentum for all variants in a project over the last 7 days vs prior 7 days.",
561
- inputSchema: { projectId: projectIdSchema2 },
576
+ inputSchema: { projectId: projectIdSchema },
562
577
  _meta: uiMeta("variant-performance"),
563
578
  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")
579
+ variants: import_zod3.z.array(
580
+ import_zod3.z.object({
581
+ variantId: import_zod3.z.string(),
582
+ currentCvr: import_zod3.z.number().describe("Conversion rate over the last 7 days (0-1)"),
583
+ priorCvr: import_zod3.z.number().describe("Conversion rate over the prior 7 days (0-1)"),
584
+ deltaPp: import_zod3.z.number().describe("Change in percentage points"),
585
+ momentum: import_zod3.z.string().describe("Momentum direction: gaining, losing, or stable")
571
586
  })
572
587
  ).describe("Per-variant performance (empty if no data yet)")
573
588
  },
@@ -577,20 +592,24 @@ function registerComponentTools(server, client) {
577
592
  openWorldHint: false
578
593
  }
579
594
  },
580
- async ({ projectId }) => {
595
+ withApiErrorGuidance(async ({ projectId }) => {
596
+ var _a, _b, _c;
581
597
  const id = encodeURIComponent(projectId);
582
598
  const data = await client.get(`/projects/${id}/trends`);
583
- const momentumMap = new Map((data.momentum ?? []).map((m) => [m.variantId, m.direction]));
599
+ const momentumMap = new Map(((_a = data.momentum) != null ? _a : []).map((m) => [m.variantId, m.direction]));
584
600
  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
- }))
601
+ variants: ((_b = data.cvr) != null ? _b : []).map((v) => {
602
+ var _a2;
603
+ return {
604
+ variantId: v.variantId,
605
+ currentCvr: v.currentCvr,
606
+ priorCvr: v.priorCvr,
607
+ deltaPp: v.deltaPp,
608
+ momentum: (_a2 = momentumMap.get(v.variantId)) != null ? _a2 : "stable"
609
+ };
610
+ })
592
611
  };
593
- if (!data.cvr?.length) {
612
+ if (!((_c = data.cvr) == null ? void 0 : _c.length)) {
594
613
  return {
595
614
  content: [{ type: "text", text: "No variant data available yet." }],
596
615
  structuredContent,
@@ -598,29 +617,31 @@ function registerComponentTools(server, client) {
598
617
  };
599
618
  }
600
619
  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"})`
620
+ (v) => {
621
+ var _a2;
622
+ 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"})`;
623
+ }
602
624
  ).join("\n");
603
625
  return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("variant-performance") };
604
- }
626
+ })
605
627
  );
606
628
  }
607
629
 
608
630
  // src/tools/insights.ts
609
- var import_zod3 = require("zod");
610
- var projectIdSchema3 = import_zod3.z.string().uuid().describe("The project UUID");
631
+ var import_zod4 = require("zod");
611
632
  function registerInsightTools(server, client) {
612
633
  server.registerTool(
613
634
  "get_insights",
614
635
  {
615
636
  title: "Get insights",
616
637
  description: "Get the latest AI-generated insights: narrator observations and (Growth tier) advisor recommendations.",
617
- inputSchema: { projectId: projectIdSchema3 },
638
+ inputSchema: { projectId: projectIdSchema },
618
639
  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")
640
+ status: import_zod4.z.enum(["ok", "empty"]).describe("Whether insights exist yet"),
641
+ observations: import_zod4.z.array(import_zod4.z.string()).describe("Narrator observations"),
642
+ recommendations: import_zod4.z.array(import_zod4.z.string()).describe("Advisor recommendations (Growth tier)"),
643
+ isStale: import_zod4.z.boolean().describe("True when the insights are older than ~6h"),
644
+ generatedAt: import_zod4.z.string().nullable().describe("ISO timestamp the insights were generated, or null")
624
645
  },
625
646
  annotations: {
626
647
  readOnlyHint: true,
@@ -628,7 +649,8 @@ function registerInsightTools(server, client) {
628
649
  openWorldHint: false
629
650
  }
630
651
  },
631
- async ({ projectId }) => {
652
+ withApiErrorGuidance(async ({ projectId }) => {
653
+ var _a, _b, _c, _d;
632
654
  const id = encodeURIComponent(projectId);
633
655
  const data = await client.get(`/projects/${id}/insights`);
634
656
  if (data.status === "empty") {
@@ -643,8 +665,8 @@ function registerInsightTools(server, client) {
643
665
  }
644
666
  };
645
667
  }
646
- const observations = data.narratorBullets ?? [];
647
- const recommendations = data.advisorBullets ?? [];
668
+ const observations = (_a = data.narratorBullets) != null ? _a : [];
669
+ const recommendations = (_b = data.advisorBullets) != null ? _b : [];
648
670
  const lines = [];
649
671
  if (data.isStale) lines.push("\u26A0 Insights are stale (>6h old). Consider calling refresh_insights.");
650
672
  if (data.generatedAt) lines.push(`Generated: ${new Date(data.generatedAt).toUTCString()}`);
@@ -662,33 +684,32 @@ function registerInsightTools(server, client) {
662
684
  status: "ok",
663
685
  observations,
664
686
  recommendations,
665
- isStale: data.isStale ?? false,
666
- generatedAt: data.generatedAt ?? null
687
+ isStale: (_c = data.isStale) != null ? _c : false,
688
+ generatedAt: (_d = data.generatedAt) != null ? _d : null
667
689
  }
668
690
  };
669
- }
691
+ })
670
692
  );
671
693
  }
672
694
 
673
695
  // src/tools/personas.ts
674
- var import_zod4 = require("zod");
675
- var projectIdSchema4 = import_zod4.z.string().uuid().describe("The project UUID");
696
+ var import_zod5 = require("zod");
676
697
  function registerPersonaTools(server, client) {
677
698
  server.registerTool(
678
699
  "get_persona_breakdown",
679
700
  {
680
701
  title: "Persona breakdown",
681
702
  description: "Get the distribution of visitor persona clusters with session counts and reliability scores.",
682
- inputSchema: { projectId: projectIdSchema4 },
703
+ inputSchema: { projectId: projectIdSchema },
683
704
  _meta: uiMeta("persona-breakdown"),
684
705
  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)")
706
+ totalSessions: import_zod5.z.number().describe("Total sessions across all clusters"),
707
+ clusters: import_zod5.z.array(
708
+ import_zod5.z.object({
709
+ label: import_zod5.z.string(),
710
+ sessionCount: import_zod5.z.number(),
711
+ sharePct: import_zod5.z.number().describe("Share of total traffic (0-100)"),
712
+ reliability: import_zod5.z.number().describe("Average cluster reliability (0-1)")
692
713
  })
693
714
  ).describe("Persona clusters (empty until enough visitor data)")
694
715
  },
@@ -698,7 +719,7 @@ function registerPersonaTools(server, client) {
698
719
  openWorldHint: false
699
720
  }
700
721
  },
701
- async ({ projectId }) => {
722
+ withApiErrorGuidance(async ({ projectId }) => {
702
723
  const id = encodeURIComponent(projectId);
703
724
  const data = await client.get(`/projects/${id}/portraits`);
704
725
  const structuredContent = {
@@ -727,33 +748,32 @@ function registerPersonaTools(server, client) {
727
748
  })
728
749
  ];
729
750
  return { content: [{ type: "text", text: lines.join("\n") }], structuredContent, _meta: uiMeta("persona-breakdown") };
730
- }
751
+ })
731
752
  );
732
753
  }
733
754
 
734
755
  // src/tools/goals.ts
735
- var import_zod5 = require("zod");
736
- var projectIdSchema5 = import_zod5.z.string().uuid().describe("The project UUID");
756
+ var import_zod6 = require("zod");
737
757
  function registerGoalTools(server, client) {
738
758
  server.registerTool(
739
759
  "get_goal_funnel",
740
760
  {
741
761
  title: "Goal funnel",
742
762
  description: "Get goal hit counts, unique-session conversion rates, and per-variant breakdown.",
743
- inputSchema: { projectId: projectIdSchema5 },
763
+ inputSchema: { projectId: projectIdSchema },
744
764
  _meta: uiMeta("goal-funnel"),
745
765
  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)")
766
+ goals: import_zod6.z.array(
767
+ import_zod6.z.object({
768
+ goalName: import_zod6.z.string(),
769
+ hits: import_zod6.z.number(),
770
+ uniqueSessions: import_zod6.z.number(),
771
+ conversionRate: import_zod6.z.number().describe("Unique-session conversion rate (0-1)"),
772
+ variants: import_zod6.z.array(
773
+ import_zod6.z.object({
774
+ componentId: import_zod6.z.string(),
775
+ variantId: import_zod6.z.string(),
776
+ completionRate: import_zod6.z.number().describe("Completion rate per assigned session (0-1)")
757
777
  })
758
778
  ).describe("Per-variant breakdown")
759
779
  })
@@ -765,7 +785,7 @@ function registerGoalTools(server, client) {
765
785
  openWorldHint: false
766
786
  }
767
787
  },
768
- async ({ projectId }) => {
788
+ withApiErrorGuidance(async ({ projectId }) => {
769
789
  const id = encodeURIComponent(projectId);
770
790
  const data = await client.get(`/projects/${id}/goals`);
771
791
  const structuredContent = {
@@ -794,26 +814,25 @@ function registerGoalTools(server, client) {
794
814
  ""
795
815
  ]);
796
816
  return { content: [{ type: "text", text: lines.join("\n").trim() }], structuredContent, _meta: uiMeta("goal-funnel") };
797
- }
817
+ })
798
818
  );
799
819
  }
800
820
 
801
821
  // src/tools/guardrails.ts
802
- var import_zod6 = require("zod");
803
- var projectIdSchema6 = import_zod6.z.string().uuid().describe("The project UUID");
822
+ var import_zod7 = require("zod");
804
823
  function registerGuardrailTools(server, client) {
805
824
  server.registerTool(
806
825
  "list_guardrail_events",
807
826
  {
808
827
  title: "List guardrail events",
809
828
  description: "List variants currently paused by the guardrail in the last 24 hours.",
810
- inputSchema: { projectId: projectIdSchema6 },
829
+ inputSchema: { projectId: projectIdSchema },
811
830
  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")
831
+ events: import_zod7.z.array(
832
+ import_zod7.z.object({
833
+ componentId: import_zod7.z.string(),
834
+ variantIds: import_zod7.z.array(import_zod7.z.string()).describe("Variants paused by the guardrail"),
835
+ pausedAt: import_zod7.z.string().nullable().describe("ISO timestamp the pause fired, or null")
817
836
  })
818
837
  ).describe("Guardrail events in the last 24h (empty if none)")
819
838
  },
@@ -823,7 +842,7 @@ function registerGuardrailTools(server, client) {
823
842
  openWorldHint: false
824
843
  }
825
844
  },
826
- async ({ projectId }) => {
845
+ withApiErrorGuidance(async ({ projectId }) => {
827
846
  const id = encodeURIComponent(projectId);
828
847
  const data = await client.get(`/projects/${id}/guardrail-events`);
829
848
  const structuredContent = {
@@ -843,28 +862,27 @@ function registerGuardrailTools(server, client) {
843
862
  (e) => `- ${e.componentId}: variants [${e.variantIds.join(", ")}] paused${e.pausedAt ? ` at ${e.pausedAt}` : ""}`
844
863
  );
845
864
  return { content: [{ type: "text", text: lines.join("\n") }], structuredContent };
846
- }
865
+ })
847
866
  );
848
867
  }
849
868
 
850
869
  // src/tools/layout.ts
851
- var import_zod7 = require("zod");
852
- var projectIdSchema7 = import_zod7.z.string().uuid().describe("The project UUID");
870
+ var import_zod8 = require("zod");
853
871
  function registerLayoutTools(server, client) {
854
872
  server.registerTool(
855
873
  "get_layout_stats",
856
874
  {
857
875
  title: "Layout stats",
858
876
  description: "Get per-persona section layout rankings and bandit reward weights.",
859
- inputSchema: { projectId: projectIdSchema7 },
877
+ inputSchema: { projectId: projectIdSchema },
860
878
  _meta: uiMeta("layout-stats"),
861
879
  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")
880
+ layouts: import_zod8.z.array(
881
+ import_zod8.z.object({
882
+ persona: import_zod8.z.string(),
883
+ layoutOrder: import_zod8.z.array(import_zod8.z.string()).describe("Ranked section order for this persona"),
884
+ pulls: import_zod8.z.number().describe("Number of times this arm was served"),
885
+ avgReward: import_zod8.z.number().describe("Average bandit reward weight")
868
886
  })
869
887
  ).describe("Per-persona layout rankings (empty until enough sessions)")
870
888
  },
@@ -874,7 +892,7 @@ function registerLayoutTools(server, client) {
874
892
  openWorldHint: false
875
893
  }
876
894
  },
877
- async ({ projectId }) => {
895
+ withApiErrorGuidance(async ({ projectId }) => {
878
896
  const id = encodeURIComponent(projectId);
879
897
  const stats = await client.get(`/projects/${id}/layout-stats`);
880
898
  const structuredContent = {
@@ -896,13 +914,12 @@ function registerLayoutTools(server, client) {
896
914
  (s) => `- ${s.persona}: [${s.layoutOrder.join(" \u2192 ")}] (avg reward: ${s.avgReward.toFixed(2)}, ${s.pulls} pulls)`
897
915
  ).join("\n");
898
916
  return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("layout-stats") };
899
- }
917
+ })
900
918
  );
901
919
  }
902
920
 
903
921
  // src/tools/variants.ts
904
- var import_zod8 = require("zod");
905
- var projectIdSchema8 = import_zod8.z.string().uuid().describe("The project UUID");
922
+ var import_zod9 = require("zod");
906
923
  function registerVariantWriteTools(server, client) {
907
924
  server.registerTool(
908
925
  "create_variant",
@@ -910,17 +927,20 @@ function registerVariantWriteTools(server, client) {
910
927
  title: "Create managed variant",
911
928
  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
929
  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.")
930
+ projectId: projectIdSchema,
931
+ componentId: import_zod9.z.string().min(1).max(200).describe("The component ID to add a variant to"),
932
+ displayName: import_zod9.z.string().min(1).max(200).describe("Human-readable name for the new variant"),
933
+ content: import_zod9.z.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.")
917
934
  },
918
935
  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")
936
+ variantId: import_zod9.z.string().describe("The new variant ID"),
937
+ // API returns `body.displayName ?? null`, so a successful create can
938
+ // carry a null name — match that contract or outputSchema validation
939
+ // would reject an otherwise-successful response.
940
+ displayName: import_zod9.z.string().nullable(),
941
+ componentId: import_zod9.z.string(),
942
+ state: import_zod9.z.literal("draft").describe("New managed variants start in draft state"),
943
+ hasContent: import_zod9.z.boolean().describe("Whether text content was provided at creation")
924
944
  },
925
945
  annotations: {
926
946
  readOnlyHint: false,
@@ -929,7 +949,7 @@ function registerVariantWriteTools(server, client) {
929
949
  openWorldHint: false
930
950
  }
931
951
  },
932
- async ({ projectId, componentId, displayName, content }) => {
952
+ withApiErrorGuidance(async ({ projectId, componentId, displayName, content }) => {
933
953
  const id = encodeURIComponent(projectId);
934
954
  const result = await client.post(
935
955
  `/projects/${id}/variants`,
@@ -949,7 +969,7 @@ function registerVariantWriteTools(server, client) {
949
969
  hasContent: Boolean(content)
950
970
  }
951
971
  };
952
- }
972
+ })
953
973
  );
954
974
  server.registerTool(
955
975
  "pause_variant",
@@ -957,14 +977,14 @@ function registerVariantWriteTools(server, client) {
957
977
  title: "Pause variant",
958
978
  description: "Pause a variant, stopping traffic from being assigned to it.",
959
979
  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")
980
+ projectId: projectIdSchema,
981
+ componentId: import_zod9.z.string().describe("The component ID"),
982
+ variantId: import_zod9.z.string().describe("The variant ID to pause")
963
983
  },
964
984
  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")
985
+ variantId: import_zod9.z.string(),
986
+ componentId: import_zod9.z.string(),
987
+ paused: import_zod9.z.literal(true).describe("The variant is now paused")
968
988
  },
969
989
  annotations: {
970
990
  readOnlyHint: false,
@@ -973,7 +993,7 @@ function registerVariantWriteTools(server, client) {
973
993
  openWorldHint: false
974
994
  }
975
995
  },
976
- async ({ projectId, componentId, variantId }) => {
996
+ withApiErrorGuidance(async ({ projectId, componentId, variantId }) => {
977
997
  const id = encodeURIComponent(projectId);
978
998
  await client.post(`/projects/${id}/variants/pause`, { componentId, variantId });
979
999
  return {
@@ -983,17 +1003,17 @@ function registerVariantWriteTools(server, client) {
983
1003
  }],
984
1004
  structuredContent: { variantId, componentId, paused: true }
985
1005
  };
986
- }
1006
+ })
987
1007
  );
988
1008
  server.registerTool(
989
1009
  "refresh_insights",
990
1010
  {
991
1011
  title: "Refresh insights",
992
1012
  description: "Trigger fresh AI insight generation for a project. Returns immediately; use get_insights in ~15 seconds to see results.",
993
- inputSchema: { projectId: projectIdSchema8 },
1013
+ inputSchema: { projectId: projectIdSchema },
994
1014
  outputSchema: {
995
- projectId: import_zod8.z.string(),
996
- status: import_zod8.z.literal("generating").describe("Generation has been triggered")
1015
+ projectId: import_zod9.z.string(),
1016
+ status: import_zod9.z.literal("generating").describe("Generation has been triggered")
997
1017
  },
998
1018
  annotations: {
999
1019
  readOnlyHint: false,
@@ -1002,7 +1022,7 @@ function registerVariantWriteTools(server, client) {
1002
1022
  openWorldHint: false
1003
1023
  }
1004
1024
  },
1005
- async ({ projectId }) => {
1025
+ withApiErrorGuidance(async ({ projectId }) => {
1006
1026
  const id = encodeURIComponent(projectId);
1007
1027
  await client.post(`/projects/${id}/insights/refresh`);
1008
1028
  return {
@@ -1012,13 +1032,12 @@ function registerVariantWriteTools(server, client) {
1012
1032
  }],
1013
1033
  structuredContent: { projectId, status: "generating" }
1014
1034
  };
1015
- }
1035
+ })
1016
1036
  );
1017
1037
  }
1018
1038
 
1019
1039
  // src/tools/variant-brief.ts
1020
- var import_zod9 = require("zod");
1021
- var projectIdSchema9 = import_zod9.z.string().uuid().describe("The project UUID");
1040
+ var import_zod10 = require("zod");
1022
1041
  var GOAL_TARGET = 500;
1023
1042
  var BEST_PRACTICE_PRIORS = {
1024
1043
  ecommerce: [
@@ -1056,11 +1075,12 @@ var GENERIC_PRIORS = [
1056
1075
  "Add one credible proof point near the action."
1057
1076
  ];
1058
1077
  function priorsFor(contextType) {
1059
- return BEST_PRACTICE_PRIORS[contextType] ?? GENERIC_PRIORS;
1078
+ var _a;
1079
+ return (_a = BEST_PRACTICE_PRIORS[contextType]) != null ? _a : GENERIC_PRIORS;
1060
1080
  }
1061
1081
  function computeDataState(impressions, insights, avgReliability) {
1062
1082
  if (impressions === 0) return "empty";
1063
- const insightsReady = insights?.status === "ok" && !insights.isStale;
1083
+ const insightsReady = (insights == null ? void 0 : insights.status) === "ok" && !insights.isStale;
1064
1084
  const reliable = avgReliability === null || avgReliability >= 0.3;
1065
1085
  if (impressions < GOAL_TARGET || !insightsReady || !reliable) return "collecting";
1066
1086
  return "sufficient";
@@ -1078,7 +1098,7 @@ function guidanceFor(dataState, contextType) {
1078
1098
  async function settled(p) {
1079
1099
  try {
1080
1100
  return await p;
1081
- } catch {
1101
+ } catch (e) {
1082
1102
  return null;
1083
1103
  }
1084
1104
  }
@@ -1089,16 +1109,16 @@ function registerVariantBriefTools(server, client) {
1089
1109
  title: "Variant brief",
1090
1110
  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
1111
  inputSchema: {
1092
- projectId: projectIdSchema9,
1093
- componentId: import_zod9.z.string().describe('The component ID to write a new variant for (matches <Adaptive id="...">).')
1112
+ projectId: projectIdSchema,
1113
+ componentId: import_zod10.z.string().describe('The component ID to write a new variant for (matches <Adaptive id="...">).')
1094
1114
  },
1095
1115
  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")
1116
+ componentId: import_zod10.z.string(),
1117
+ contextType: import_zod10.z.string().describe("The project's context type (or 'unknown')"),
1118
+ dataState: import_zod10.z.enum(["sufficient", "collecting", "empty"]).describe("Data-sufficiency assessment"),
1119
+ existingVariantIds: import_zod10.z.array(import_zod10.z.string()).describe("Variant IDs already in use (do not reuse)"),
1120
+ priors: import_zod10.z.array(import_zod10.z.string()).describe("Best-practice priors applied for this context type"),
1121
+ markdown: import_zod10.z.string().describe("The full variant brief in Markdown")
1102
1122
  },
1103
1123
  annotations: {
1104
1124
  readOnlyHint: true,
@@ -1106,7 +1126,8 @@ function registerVariantBriefTools(server, client) {
1106
1126
  openWorldHint: false
1107
1127
  }
1108
1128
  },
1109
- async ({ projectId, componentId }) => {
1129
+ withApiErrorGuidance(async ({ projectId, componentId }) => {
1130
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
1110
1131
  const id = encodeURIComponent(projectId);
1111
1132
  const [projects, componentsEnvelope, trends, portraits, insights] = await Promise.all([
1112
1133
  settled(client.get("/projects")),
@@ -1116,19 +1137,19 @@ function registerVariantBriefTools(server, client) {
1116
1137
  settled(client.get(`/projects/${id}/portraits`)),
1117
1138
  settled(client.get(`/projects/${id}/insights`))
1118
1139
  ]);
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;
1140
+ const project = (_a = projects == null ? void 0 : projects.find((p) => p.id === projectId)) != null ? _a : null;
1141
+ const contextType = (_b = project == null ? void 0 : project.context_type) != null ? _b : "unknown";
1142
+ const components = (_c = componentsEnvelope == null ? void 0 : componentsEnvelope.components) != null ? _c : [];
1143
+ const component = (_d = components.find((c) => c.component_id === componentId)) != null ? _d : null;
1144
+ const impressions = (_e = component == null ? void 0 : component.total_impressions) != null ? _e : 0;
1145
+ const conversions = (_f = component == null ? void 0 : component.total_conversions) != null ? _f : 0;
1125
1146
  const componentCvr = impressions > 0 ? conversions / impressions * 100 : 0;
1126
- const existingVariantIds = component?.variants.map((v) => v.variant_id) ?? [];
1147
+ const existingVariantIds = (_g = component == null ? void 0 : component.variants.map((v) => v.variant_id)) != null ? _g : [];
1127
1148
  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;
1149
+ const momentumMap = new Map(((_h = trends == null ? void 0 : trends.momentum) != null ? _h : []).map((m) => [m.variantId, m.direction]));
1150
+ const variantPerf = ((_i = trends == null ? void 0 : trends.cvr) != null ? _i : []).filter((v) => variantIdSet.has(v.variantId));
1151
+ const clusters = (_j = portraits == null ? void 0 : portraits.clusters) != null ? _j : [];
1152
+ const totalSessions = (_k = portraits == null ? void 0 : portraits.totalSessions) != null ? _k : 0;
1132
1153
  const avgReliability = clusters.length ? clusters.reduce((s, c) => s + c.avgReliability, 0) / clusters.length : null;
1133
1154
  const dataState = computeDataState(impressions, insights, avgReliability);
1134
1155
  const lines = [];
@@ -1153,7 +1174,7 @@ function registerVariantBriefTools(server, client) {
1153
1174
  lines.push("Current variant performance (7d vs prior 7d):");
1154
1175
  for (const v of variantPerf) {
1155
1176
  lines.push(
1156
- `- ${v.variantId}: ${(v.currentCvr * 100).toFixed(2)}% CVR (${v.deltaPp > 0 ? "+" : ""}${v.deltaPp.toFixed(1)} pp, ${momentumMap.get(v.variantId) ?? "stable"})`
1177
+ `- ${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
1178
  );
1158
1179
  }
1159
1180
  lines.push("");
@@ -1168,8 +1189,8 @@ function registerVariantBriefTools(server, client) {
1168
1189
  }
1169
1190
  if (insights && insights.status === "ok") {
1170
1191
  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 ?? [];
1192
+ const narrator = (_m = insights.narratorBullets) != null ? _m : [];
1193
+ const advisor = (_n = insights.advisorBullets) != null ? _n : [];
1173
1194
  if (narrator.length) {
1174
1195
  lines.push("Insights \u2014 observations:");
1175
1196
  narrator.forEach((b) => lines.push(`- ${b}`));
@@ -1209,17 +1230,16 @@ function registerVariantBriefTools(server, client) {
1209
1230
  markdown
1210
1231
  }
1211
1232
  };
1212
- }
1233
+ })
1213
1234
  );
1214
1235
  }
1215
1236
 
1216
1237
  // src/tools/test-brief.ts
1217
- var import_zod10 = require("zod");
1218
- var projectIdSchema10 = import_zod10.z.string().uuid().describe("The project UUID");
1238
+ var import_zod11 = require("zod");
1219
1239
  async function settled2(p) {
1220
1240
  try {
1221
1241
  return await p;
1222
- } catch {
1242
+ } catch (e) {
1223
1243
  return null;
1224
1244
  }
1225
1245
  }
@@ -1230,14 +1250,14 @@ function registerTestBriefTools(server, client) {
1230
1250
  title: "Test brief",
1231
1251
  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
1252
  inputSchema: {
1233
- projectId: projectIdSchema10,
1234
- componentId: import_zod10.z.string().describe('The component ID to write a test for (matches <Adaptive id="...">).')
1253
+ projectId: projectIdSchema,
1254
+ componentId: import_zod11.z.string().describe('The component ID to write a test for (matches <Adaptive id="...">).')
1235
1255
  },
1236
1256
  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")
1257
+ componentId: import_zod11.z.string(),
1258
+ forcedVariantId: import_zod11.z.string().describe("The non-control variant the example forces"),
1259
+ goalName: import_zod11.z.string().describe("The goal the example asserts fires"),
1260
+ markdown: import_zod11.z.string().describe("The full test brief in Markdown")
1241
1261
  },
1242
1262
  annotations: {
1243
1263
  readOnlyHint: true,
@@ -1245,20 +1265,21 @@ function registerTestBriefTools(server, client) {
1245
1265
  openWorldHint: false
1246
1266
  }
1247
1267
  },
1248
- async ({ projectId, componentId }) => {
1268
+ withApiErrorGuidance(async ({ projectId, componentId }) => {
1269
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1249
1270
  const id = encodeURIComponent(projectId);
1250
1271
  const [componentsEnvelope, goalsRes] = await Promise.all([
1251
1272
  // mgmt API returns a paginated envelope: { components, total, page, limit }.
1252
1273
  settled2(client.get(`/projects/${id}/components`)),
1253
1274
  settled2(client.get(`/projects/${id}/goals`))
1254
1275
  ]);
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";
1276
+ const components = (_a = componentsEnvelope == null ? void 0 : componentsEnvelope.components) != null ? _a : [];
1277
+ const component = (_b = components.find((c) => c.component_id === componentId)) != null ? _b : null;
1278
+ const variantIds = (_c = component == null ? void 0 : component.variants.map((v) => v.variant_id)) != null ? _c : [];
1279
+ const goals = Array.isArray(goalsRes) ? goalsRes : (_d = goalsRes == null ? void 0 : goalsRes.goals) != null ? _d : [];
1280
+ const goalName = (_f = (_e = goals[0]) == null ? void 0 : _e.goalName) != null ? _f : "signup";
1281
+ const controlId = (_g = variantIds[0]) != null ? _g : "control";
1282
+ const forcedId = (_h = variantIds.find((v) => v !== controlId)) != null ? _h : "variant_b";
1262
1283
  const lines = [];
1263
1284
  lines.push(`# Test brief \u2014 ${componentId}`);
1264
1285
  lines.push("");
@@ -1314,12 +1335,12 @@ function registerTestBriefTools(server, client) {
1314
1335
  content: [{ type: "text", text: markdown }],
1315
1336
  structuredContent: { componentId, forcedVariantId: forcedId, goalName, markdown }
1316
1337
  };
1317
- }
1338
+ })
1318
1339
  );
1319
1340
  }
1320
1341
 
1321
1342
  // src/tools/integration-guide.ts
1322
- var import_zod11 = require("zod");
1343
+ var import_zod12 = require("zod");
1323
1344
  var GUIDE = `# SentientUI integration guide \u2014 the adaptive ladder
1324
1345
 
1325
1346
  SentientUI adapts a site per visitor type (personas: buyer, researcher, deal_seeker, browser,
@@ -1394,7 +1415,7 @@ function registerIntegrationGuideTools(server) {
1394
1415
  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
1416
  inputSchema: {},
1396
1417
  outputSchema: {
1397
- guide: import_zod11.z.string().describe("The full integration guide in Markdown")
1418
+ guide: import_zod12.z.string().describe("The full integration guide in Markdown")
1398
1419
  },
1399
1420
  annotations: {
1400
1421
  readOnlyHint: true,
@@ -1410,7 +1431,7 @@ function registerIntegrationGuideTools(server) {
1410
1431
  }
1411
1432
 
1412
1433
  // src/server.ts
1413
- var { version: PKG_VERSION } = (0, import_node_module.createRequire)(importMetaUrl)("../package.json");
1434
+ var PKG_VERSION = true ? "0.8.2" : "0.0.0-dev";
1414
1435
  function createMcpServer(client) {
1415
1436
  const server = new import_mcp.McpServer(
1416
1437
  {