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