@recapt/mcp 0.0.18-beta → 0.0.20-beta
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/cli/index.d.ts +0 -11
- package/dist/cli/index.js +1059 -21
- package/dist/index.d.ts +0 -18
- package/dist/index.js +3205 -247
- package/dist/tools/catalog/anthropicToolCatalog.json +1306 -0
- package/dist/tools/catalog/toolCatalog.json +4078 -382
- package/package.json +10 -3
- package/skills/self-improvement.md +388 -222
- package/templates/self-improvement-full.md +91 -0
- package/templates/{self-improvement.md → self-improvement-lite.md} +13 -9
- package/dist/api/client.d.ts +0 -14
- package/dist/api/client.js +0 -67
- package/dist/cli/commands/setup-self-improvement-gh.d.ts +0 -7
- package/dist/cli/commands/setup-self-improvement-gh.js +0 -310
- package/dist/cli/commands/setup.d.ts +0 -7
- package/dist/cli/commands/setup.js +0 -173
- package/dist/cli/commands/skill.d.ts +0 -24
- package/dist/cli/commands/skill.js +0 -264
- package/dist/cli/utils/ide-config.d.ts +0 -31
- package/dist/cli/utils/ide-config.js +0 -294
- package/dist/cli/utils/prompts.d.ts +0 -22
- package/dist/cli/utils/prompts.js +0 -71
- package/dist/tools/analyzeFlow.d.ts +0 -7
- package/dist/tools/analyzeFlow.js +0 -68
- package/dist/tools/analyzeFunnel.d.ts +0 -7
- package/dist/tools/analyzeFunnel.js +0 -63
- package/dist/tools/catalog/callTool.d.ts +0 -22
- package/dist/tools/catalog/callTool.js +0 -92
- package/dist/tools/catalog/index.d.ts +0 -11
- package/dist/tools/catalog/index.js +0 -11
- package/dist/tools/catalog/searchTools.d.ts +0 -22
- package/dist/tools/catalog/searchTools.js +0 -194
- package/dist/tools/compareCohorts.d.ts +0 -6
- package/dist/tools/compareCohorts.js +0 -84
- package/dist/tools/comparePeriods.d.ts +0 -6
- package/dist/tools/comparePeriods.js +0 -54
- package/dist/tools/detectDrift.d.ts +0 -6
- package/dist/tools/detectDrift.js +0 -55
- package/dist/tools/detectRegressions.d.ts +0 -6
- package/dist/tools/detectRegressions.js +0 -63
- package/dist/tools/diagnostic.d.ts +0 -6
- package/dist/tools/diagnostic.js +0 -109
- package/dist/tools/discoverPersonas.d.ts +0 -6
- package/dist/tools/discoverPersonas.js +0 -50
- package/dist/tools/getActionableIssues.d.ts +0 -7
- package/dist/tools/getActionableIssues.js +0 -55
- package/dist/tools/getAnomalies.d.ts +0 -6
- package/dist/tools/getAnomalies.js +0 -53
- package/dist/tools/getConsoleErrors.d.ts +0 -6
- package/dist/tools/getConsoleErrors.js +0 -61
- package/dist/tools/getDeadClicks.d.ts +0 -6
- package/dist/tools/getDeadClicks.js +0 -42
- package/dist/tools/getDomains.d.ts +0 -6
- package/dist/tools/getDomains.js +0 -34
- package/dist/tools/getElementFriction.d.ts +0 -6
- package/dist/tools/getElementFriction.js +0 -45
- package/dist/tools/getFlowFriction.d.ts +0 -7
- package/dist/tools/getFlowFriction.js +0 -57
- package/dist/tools/getFormFriction.d.ts +0 -6
- package/dist/tools/getFormFriction.js +0 -42
- package/dist/tools/getIssues.d.ts +0 -6
- package/dist/tools/getIssues.js +0 -82
- package/dist/tools/getJourneyPatterns.d.ts +0 -7
- package/dist/tools/getJourneyPatterns.js +0 -50
- package/dist/tools/getPageMetrics.d.ts +0 -6
- package/dist/tools/getPageMetrics.js +0 -47
- package/dist/tools/getPageTrends.d.ts +0 -6
- package/dist/tools/getPageTrends.js +0 -46
- package/dist/tools/getSessionDetails.d.ts +0 -6
- package/dist/tools/getSessionDetails.js +0 -70
- package/dist/tools/getSessionPages.d.ts +0 -7
- package/dist/tools/getSessionPages.js +0 -74
- package/dist/tools/getUxHealthReport.d.ts +0 -7
- package/dist/tools/getUxHealthReport.js +0 -50
- package/dist/tools/improvementRun.d.ts +0 -6
- package/dist/tools/improvementRun.js +0 -315
- package/dist/tools/knowledge.d.ts +0 -6
- package/dist/tools/knowledge.js +0 -186
- package/dist/tools/listPages.d.ts +0 -6
- package/dist/tools/listPages.js +0 -50
- package/dist/tools/listSessions.d.ts +0 -7
- package/dist/tools/listSessions.js +0 -67
- package/dist/tools/memory.d.ts +0 -7
- package/dist/tools/memory.js +0 -119
- package/dist/tools/predictOutcomes.d.ts +0 -6
- package/dist/tools/predictOutcomes.js +0 -66
- package/dist/tools/remediation.d.ts +0 -6
- package/dist/tools/remediation.js +0 -223
- package/dist/tools/scanSite.d.ts +0 -6
- package/dist/tools/scanSite.js +0 -51
- package/dist/tools/searchSessions.d.ts +0 -6
- package/dist/tools/searchSessions.js +0 -51
- package/dist/tools/triage.d.ts +0 -6
- package/dist/tools/triage.js +0 -114
- package/dist/tools/triageSessions.d.ts +0 -8
- package/dist/tools/triageSessions.js +0 -197
- package/dist/tools/upgradeOptions.d.ts +0 -7
- package/dist/tools/upgradeOptions.js +0 -67
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Remediation tools for self-improvement workflow.
|
|
3
|
-
*
|
|
4
|
-
* Provides fix proposal, deployment confirmation, evaluation, and history tracking.
|
|
5
|
-
*/
|
|
6
|
-
import { z } from "zod";
|
|
7
|
-
import { apiGet, apiPost, apiPatch, isApiConfigured } from "../api/client.js";
|
|
8
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
|
-
export function registerRemediationTools(server) {
|
|
10
|
-
server.registerTool("propose_fix", {
|
|
11
|
-
description: "Propose a fix for an issue. Creates a remediation record with baseline metrics for later evaluation. Include detailed diagnosis and code suggestions when possible.",
|
|
12
|
-
inputSchema: z.object({
|
|
13
|
-
issue_id: z.string().describe("The ID of the issue to fix"),
|
|
14
|
-
diagnosis: z
|
|
15
|
-
.string()
|
|
16
|
-
.describe("Detailed analysis of the root cause of the issue"),
|
|
17
|
-
proposed_fix: z
|
|
18
|
-
.string()
|
|
19
|
-
.describe("Description of the proposed fix and how it addresses the root cause"),
|
|
20
|
-
code_snippet: z
|
|
21
|
-
.string()
|
|
22
|
-
.optional()
|
|
23
|
-
.describe("Suggested code changes (if applicable)"),
|
|
24
|
-
affected_files: z
|
|
25
|
-
.array(z.string())
|
|
26
|
-
.optional()
|
|
27
|
-
.describe("List of files that need to be modified"),
|
|
28
|
-
confidence: z
|
|
29
|
-
.number()
|
|
30
|
-
.min(0)
|
|
31
|
-
.max(1)
|
|
32
|
-
.describe("Confidence level in the fix (0-1). Use <0.7 when uncertain."),
|
|
33
|
-
}),
|
|
34
|
-
}, async ({ issue_id, diagnosis, proposed_fix, code_snippet, affected_files, confidence, }) => {
|
|
35
|
-
if (!isApiConfigured()) {
|
|
36
|
-
return {
|
|
37
|
-
content: [
|
|
38
|
-
{
|
|
39
|
-
type: "text",
|
|
40
|
-
text: JSON.stringify({ error: "API not configured" }),
|
|
41
|
-
},
|
|
42
|
-
],
|
|
43
|
-
isError: true,
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
const { data, error } = await apiPost("/remediations", {
|
|
47
|
-
issue_id,
|
|
48
|
-
diagnosis,
|
|
49
|
-
proposed_fix,
|
|
50
|
-
code_snippet,
|
|
51
|
-
affected_files,
|
|
52
|
-
confidence,
|
|
53
|
-
});
|
|
54
|
-
if (error) {
|
|
55
|
-
return {
|
|
56
|
-
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
57
|
-
isError: true,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
61
|
-
});
|
|
62
|
-
server.registerTool("list_pending_fixes", {
|
|
63
|
-
description: "List all proposed fixes awaiting deployment. Use to show the user what fixes are ready to be deployed.",
|
|
64
|
-
inputSchema: z.object({}),
|
|
65
|
-
}, async () => {
|
|
66
|
-
if (!isApiConfigured()) {
|
|
67
|
-
return {
|
|
68
|
-
content: [
|
|
69
|
-
{
|
|
70
|
-
type: "text",
|
|
71
|
-
text: JSON.stringify({ error: "API not configured" }),
|
|
72
|
-
},
|
|
73
|
-
],
|
|
74
|
-
isError: true,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
const { data, error } = await apiGet("/remediations/pending");
|
|
78
|
-
if (error) {
|
|
79
|
-
return {
|
|
80
|
-
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
81
|
-
isError: true,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
85
|
-
});
|
|
86
|
-
server.registerTool("list_remediations", {
|
|
87
|
-
description: "List remediation records with optional filters. Use to review past and current fix attempts.",
|
|
88
|
-
inputSchema: z.object({
|
|
89
|
-
status: z
|
|
90
|
-
.enum([
|
|
91
|
-
"proposed",
|
|
92
|
-
"deployed",
|
|
93
|
-
"evaluating",
|
|
94
|
-
"succeeded",
|
|
95
|
-
"failed",
|
|
96
|
-
"reverted",
|
|
97
|
-
])
|
|
98
|
-
.optional()
|
|
99
|
-
.describe("Filter by remediation status"),
|
|
100
|
-
issue_id: z.string().optional().describe("Filter by issue ID"),
|
|
101
|
-
page_path: z.string().optional().describe("Filter by page path"),
|
|
102
|
-
limit: z
|
|
103
|
-
.number()
|
|
104
|
-
.optional()
|
|
105
|
-
.default(20)
|
|
106
|
-
.describe("Maximum number of results (default: 20)"),
|
|
107
|
-
}),
|
|
108
|
-
}, async ({ status, issue_id, page_path, limit, }) => {
|
|
109
|
-
if (!isApiConfigured()) {
|
|
110
|
-
return {
|
|
111
|
-
content: [
|
|
112
|
-
{
|
|
113
|
-
type: "text",
|
|
114
|
-
text: JSON.stringify({ error: "API not configured" }),
|
|
115
|
-
},
|
|
116
|
-
],
|
|
117
|
-
isError: true,
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
const { data, error } = await apiGet("/remediations", {
|
|
121
|
-
status,
|
|
122
|
-
issue_id,
|
|
123
|
-
page_path,
|
|
124
|
-
limit: limit ?? 20,
|
|
125
|
-
});
|
|
126
|
-
if (error) {
|
|
127
|
-
return {
|
|
128
|
-
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
129
|
-
isError: true,
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
133
|
-
});
|
|
134
|
-
server.registerTool("confirm_deployment", {
|
|
135
|
-
description: "Confirm that a proposed fix has been deployed to production. This starts the evaluation timer. Call this when the user confirms they have deployed the fix.",
|
|
136
|
-
inputSchema: z.object({
|
|
137
|
-
remediation_id: z
|
|
138
|
-
.string()
|
|
139
|
-
.describe("The ID of the remediation to mark as deployed"),
|
|
140
|
-
}),
|
|
141
|
-
}, async ({ remediation_id }) => {
|
|
142
|
-
if (!isApiConfigured()) {
|
|
143
|
-
return {
|
|
144
|
-
content: [
|
|
145
|
-
{
|
|
146
|
-
type: "text",
|
|
147
|
-
text: JSON.stringify({ error: "API not configured" }),
|
|
148
|
-
},
|
|
149
|
-
],
|
|
150
|
-
isError: true,
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
const { data, error } = await apiPatch(`/remediations/${remediation_id}/deploy`, {});
|
|
154
|
-
if (error) {
|
|
155
|
-
return {
|
|
156
|
-
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
157
|
-
isError: true,
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
161
|
-
});
|
|
162
|
-
server.registerTool("evaluate_fix", {
|
|
163
|
-
description: "Evaluate if a deployed fix improved metrics. Compares post-deployment metrics to baseline. Returns success/partial/failed outcome with detailed verdict. Wait at least 24 hours after deployment for reliable results.",
|
|
164
|
-
inputSchema: z.object({
|
|
165
|
-
remediation_id: z
|
|
166
|
-
.string()
|
|
167
|
-
.describe("The ID of the remediation to evaluate"),
|
|
168
|
-
min_hours: z
|
|
169
|
-
.number()
|
|
170
|
-
.optional()
|
|
171
|
-
.default(24)
|
|
172
|
-
.describe("Minimum hours since deployment required (default: 24)"),
|
|
173
|
-
}),
|
|
174
|
-
}, async ({ remediation_id, min_hours, }) => {
|
|
175
|
-
if (!isApiConfigured()) {
|
|
176
|
-
return {
|
|
177
|
-
content: [
|
|
178
|
-
{
|
|
179
|
-
type: "text",
|
|
180
|
-
text: JSON.stringify({ error: "API not configured" }),
|
|
181
|
-
},
|
|
182
|
-
],
|
|
183
|
-
isError: true,
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
const { data, error } = await apiPost(`/remediations/${remediation_id}/evaluate`, { min_hours: min_hours ?? 24 });
|
|
187
|
-
if (error) {
|
|
188
|
-
return {
|
|
189
|
-
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
190
|
-
isError: true,
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
194
|
-
});
|
|
195
|
-
server.registerTool("get_fix_history", {
|
|
196
|
-
description: "Get the full remediation history for an issue. Shows all fix attempts, their outcomes, and current status. Use before proposing a new fix to learn from past attempts.",
|
|
197
|
-
inputSchema: z.object({
|
|
198
|
-
issue_id: z
|
|
199
|
-
.string()
|
|
200
|
-
.describe("The ID of the issue to get fix history for"),
|
|
201
|
-
}),
|
|
202
|
-
}, async ({ issue_id }) => {
|
|
203
|
-
if (!isApiConfigured()) {
|
|
204
|
-
return {
|
|
205
|
-
content: [
|
|
206
|
-
{
|
|
207
|
-
type: "text",
|
|
208
|
-
text: JSON.stringify({ error: "API not configured" }),
|
|
209
|
-
},
|
|
210
|
-
],
|
|
211
|
-
isError: true,
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
const { data, error } = await apiGet(`/remediations/history/${issue_id}`);
|
|
215
|
-
if (error) {
|
|
216
|
-
return {
|
|
217
|
-
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
218
|
-
isError: true,
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
222
|
-
});
|
|
223
|
-
}
|
package/dist/tools/scanSite.d.ts
DELETED
package/dist/tools/scanSite.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* scan_site tool
|
|
3
|
-
*
|
|
4
|
-
* One-shot site health scan across all pages.
|
|
5
|
-
*/
|
|
6
|
-
import { z } from "zod";
|
|
7
|
-
import { apiGet, isApiConfigured } from "../api/client.js";
|
|
8
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
|
-
export function registerScanSite(server) {
|
|
10
|
-
server.registerTool("scan_site", {
|
|
11
|
-
description: "One-shot site health scan. Lists all pages and computes aggregate metrics " +
|
|
12
|
-
"for the top-N pages (default 10) sorted by session count. Returns a ranked " +
|
|
13
|
-
"table with frustration and health grade per page. " +
|
|
14
|
-
"Use this as the FIRST tool when the user asks a broad question without naming a specific page.",
|
|
15
|
-
inputSchema: z.object({
|
|
16
|
-
top_n: z
|
|
17
|
-
.number()
|
|
18
|
-
.optional()
|
|
19
|
-
.default(10)
|
|
20
|
-
.describe("Number of top pages to analyze (default 10)"),
|
|
21
|
-
offset: z
|
|
22
|
-
.number()
|
|
23
|
-
.optional()
|
|
24
|
-
.default(0)
|
|
25
|
-
.describe("Skip first N pages for pagination (default 0)"),
|
|
26
|
-
}),
|
|
27
|
-
}, async ({ top_n, offset }) => {
|
|
28
|
-
if (!isApiConfigured()) {
|
|
29
|
-
return {
|
|
30
|
-
content: [
|
|
31
|
-
{
|
|
32
|
-
type: "text",
|
|
33
|
-
text: JSON.stringify({ error: "API not configured" }),
|
|
34
|
-
},
|
|
35
|
-
],
|
|
36
|
-
isError: true,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
const { data, error } = await apiGet("/site/overview", {
|
|
40
|
-
top_n: top_n ?? 10,
|
|
41
|
-
offset: offset ?? 0,
|
|
42
|
-
});
|
|
43
|
-
if (error) {
|
|
44
|
-
return {
|
|
45
|
-
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
46
|
-
isError: true,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
50
|
-
});
|
|
51
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* search_sessions tool
|
|
3
|
-
*
|
|
4
|
-
* Search sessions by natural language query using vector search.
|
|
5
|
-
*/
|
|
6
|
-
import { z } from "zod";
|
|
7
|
-
import { apiPost, isApiConfigured } from "../api/client.js";
|
|
8
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
|
-
export function registerSearchSessions(server) {
|
|
10
|
-
server.registerTool("search_sessions", {
|
|
11
|
-
description: 'Search sessions by natural language query. Examples: "frustrated users on checkout", "rage clicks on pricing page", "confused users who abandoned cart".',
|
|
12
|
-
inputSchema: z.object({
|
|
13
|
-
query: z
|
|
14
|
-
.string()
|
|
15
|
-
.describe("Natural language search query describing the sessions you want to find"),
|
|
16
|
-
page_path: z
|
|
17
|
-
.string()
|
|
18
|
-
.optional()
|
|
19
|
-
.describe("Optional: filter to a specific page path"),
|
|
20
|
-
limit: z
|
|
21
|
-
.number()
|
|
22
|
-
.optional()
|
|
23
|
-
.default(10)
|
|
24
|
-
.describe("Maximum number of sessions to return (default: 10)"),
|
|
25
|
-
}),
|
|
26
|
-
}, async ({ query, page_path, limit, }) => {
|
|
27
|
-
if (!isApiConfigured()) {
|
|
28
|
-
return {
|
|
29
|
-
content: [
|
|
30
|
-
{
|
|
31
|
-
type: "text",
|
|
32
|
-
text: JSON.stringify({ error: "API not configured" }),
|
|
33
|
-
},
|
|
34
|
-
],
|
|
35
|
-
isError: true,
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
const { data, error } = await apiPost("/sessions/search", {
|
|
39
|
-
query,
|
|
40
|
-
page_path,
|
|
41
|
-
limit: limit ?? 10,
|
|
42
|
-
});
|
|
43
|
-
if (error) {
|
|
44
|
-
return {
|
|
45
|
-
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
46
|
-
isError: true,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
50
|
-
});
|
|
51
|
-
}
|
package/dist/tools/triage.d.ts
DELETED
package/dist/tools/triage.js
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Triage tools for self-improvement workflow.
|
|
3
|
-
*
|
|
4
|
-
* Provides issue dismissal, marking intended behavior, and issue history.
|
|
5
|
-
*/
|
|
6
|
-
import { z } from "zod";
|
|
7
|
-
import { apiGet, apiPost, isApiConfigured } from "../api/client.js";
|
|
8
|
-
const DISMISS_REASONS = [
|
|
9
|
-
"stale",
|
|
10
|
-
"intended",
|
|
11
|
-
"duplicate",
|
|
12
|
-
"false_positive",
|
|
13
|
-
];
|
|
14
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15
|
-
export function registerTriageTools(server) {
|
|
16
|
-
server.registerTool("dismiss_issue", {
|
|
17
|
-
description: "Dismiss an issue as a false positive. Creates site knowledge to prevent re-flagging. Use when an issue is stale, intended behavior, a duplicate, or a false positive. Always confirm with user before dismissing.",
|
|
18
|
-
inputSchema: z.object({
|
|
19
|
-
issue_id: z.string().describe("The ID of the issue to dismiss"),
|
|
20
|
-
reason: z
|
|
21
|
-
.enum(DISMISS_REASONS)
|
|
22
|
-
.describe("Reason for dismissal: stale, intended, duplicate, or false_positive"),
|
|
23
|
-
explanation: z
|
|
24
|
-
.string()
|
|
25
|
-
.describe("Detailed explanation of why this issue is being dismissed"),
|
|
26
|
-
create_knowledge: z
|
|
27
|
-
.boolean()
|
|
28
|
-
.optional()
|
|
29
|
-
.default(true)
|
|
30
|
-
.describe("Whether to create site knowledge entry (default: true)"),
|
|
31
|
-
}),
|
|
32
|
-
}, async ({ issue_id, reason, explanation, create_knowledge, }) => {
|
|
33
|
-
if (!isApiConfigured()) {
|
|
34
|
-
return {
|
|
35
|
-
content: [
|
|
36
|
-
{
|
|
37
|
-
type: "text",
|
|
38
|
-
text: JSON.stringify({ error: "API not configured" }),
|
|
39
|
-
},
|
|
40
|
-
],
|
|
41
|
-
isError: true,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
const { data, error } = await apiPost(`/issues/${issue_id}/dismiss`, {
|
|
45
|
-
reason,
|
|
46
|
-
explanation,
|
|
47
|
-
create_knowledge: create_knowledge ?? true,
|
|
48
|
-
});
|
|
49
|
-
if (error) {
|
|
50
|
-
return {
|
|
51
|
-
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
52
|
-
isError: true,
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
56
|
-
});
|
|
57
|
-
server.registerTool("mark_intended_behavior", {
|
|
58
|
-
description: "Mark an issue as intended behavior. This is a shortcut for dismissing with reason 'intended' and always creates site knowledge. Use when the detected behavior is by design (e.g., disabled button clicks are expected).",
|
|
59
|
-
inputSchema: z.object({
|
|
60
|
-
issue_id: z
|
|
61
|
-
.string()
|
|
62
|
-
.describe("The ID of the issue to mark as intended"),
|
|
63
|
-
explanation: z
|
|
64
|
-
.string()
|
|
65
|
-
.describe("Explanation of why this behavior is intended"),
|
|
66
|
-
}),
|
|
67
|
-
}, async ({ issue_id, explanation, }) => {
|
|
68
|
-
if (!isApiConfigured()) {
|
|
69
|
-
return {
|
|
70
|
-
content: [
|
|
71
|
-
{
|
|
72
|
-
type: "text",
|
|
73
|
-
text: JSON.stringify({ error: "API not configured" }),
|
|
74
|
-
},
|
|
75
|
-
],
|
|
76
|
-
isError: true,
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
const { data, error } = await apiPost(`/issues/${issue_id}/mark-intended`, { explanation });
|
|
80
|
-
if (error) {
|
|
81
|
-
return {
|
|
82
|
-
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
83
|
-
isError: true,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
87
|
-
});
|
|
88
|
-
server.registerTool("get_issue_history", {
|
|
89
|
-
description: "Get the full history of an issue including status changes, remediation attempts, and outcomes. Use to understand past fix attempts before proposing new ones.",
|
|
90
|
-
inputSchema: z.object({
|
|
91
|
-
issue_id: z.string().describe("The ID of the issue to get history for"),
|
|
92
|
-
}),
|
|
93
|
-
}, async ({ issue_id }) => {
|
|
94
|
-
if (!isApiConfigured()) {
|
|
95
|
-
return {
|
|
96
|
-
content: [
|
|
97
|
-
{
|
|
98
|
-
type: "text",
|
|
99
|
-
text: JSON.stringify({ error: "API not configured" }),
|
|
100
|
-
},
|
|
101
|
-
],
|
|
102
|
-
isError: true,
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
const { data, error } = await apiGet(`/issues/${issue_id}/history`);
|
|
106
|
-
if (error) {
|
|
107
|
-
return {
|
|
108
|
-
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
109
|
-
isError: true,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
113
|
-
});
|
|
114
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* triage_sessions tool
|
|
3
|
-
*
|
|
4
|
-
* Automatically triages sessions to find compromised user experiences.
|
|
5
|
-
* Analyzes user comments, frustration signals, rage clicks, and console errors.
|
|
6
|
-
* Thin proxy to external-api /sessions/triage endpoint.
|
|
7
|
-
*/
|
|
8
|
-
export declare function registerTriageSessions(server: any): void;
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* triage_sessions tool
|
|
3
|
-
*
|
|
4
|
-
* Automatically triages sessions to find compromised user experiences.
|
|
5
|
-
* Analyzes user comments, frustration signals, rage clicks, and console errors.
|
|
6
|
-
* Thin proxy to external-api /sessions/triage endpoint.
|
|
7
|
-
*/
|
|
8
|
-
import { z } from "zod";
|
|
9
|
-
import { apiGet, isApiConfigured } from "../api/client.js";
|
|
10
|
-
function formatDuration(seconds) {
|
|
11
|
-
if (!seconds)
|
|
12
|
-
return "unknown";
|
|
13
|
-
if (seconds < 60)
|
|
14
|
-
return `${seconds}s`;
|
|
15
|
-
if (seconds < 3600)
|
|
16
|
-
return `${Math.floor(seconds / 60)}m ${seconds % 60}s`;
|
|
17
|
-
const hours = Math.floor(seconds / 3600);
|
|
18
|
-
const mins = Math.floor((seconds % 3600) / 60);
|
|
19
|
-
return `${hours}h ${mins}m`;
|
|
20
|
-
}
|
|
21
|
-
function getActionReason(session) {
|
|
22
|
-
const reasons = [];
|
|
23
|
-
if (session.user_comments.length > 0) {
|
|
24
|
-
reasons.push(`USER FEEDBACK: ${session.user_comments.length} comment(s) - "${session.user_comments[0].text.slice(0, 100)}${session.user_comments[0].text.length > 100 ? "..." : ""}"`);
|
|
25
|
-
}
|
|
26
|
-
if (session.behavioral_signals.frustration >= 0.5) {
|
|
27
|
-
reasons.push(`HIGH FRUSTRATION: ${(session.behavioral_signals.frustration * 100).toFixed(0)}%`);
|
|
28
|
-
}
|
|
29
|
-
else if (session.behavioral_signals.frustration >= 0.3) {
|
|
30
|
-
reasons.push(`MODERATE FRUSTRATION: ${(session.behavioral_signals.frustration * 100).toFixed(0)}%`);
|
|
31
|
-
}
|
|
32
|
-
if (session.behavioral_signals.has_rage_clicks) {
|
|
33
|
-
reasons.push("RAGE CLICKS detected");
|
|
34
|
-
}
|
|
35
|
-
if (session.console_errors.length > 0) {
|
|
36
|
-
const errorCount = session.console_errors.reduce((sum, e) => sum + e.count, 0);
|
|
37
|
-
reasons.push(`JS ERRORS: ${errorCount} error(s) - "${session.console_errors[0].message.slice(0, 80)}..."`);
|
|
38
|
-
}
|
|
39
|
-
if (!session.behavioral_signals.has_behavioral_data) {
|
|
40
|
-
reasons.push("NOTE: No behavioral analysis data available for this session");
|
|
41
|
-
}
|
|
42
|
-
if (reasons.length === 0) {
|
|
43
|
-
reasons.push("Low severity - no major issues detected");
|
|
44
|
-
}
|
|
45
|
-
return reasons.join("\n - ");
|
|
46
|
-
}
|
|
47
|
-
function formatTriageOutput(data) {
|
|
48
|
-
const lines = [];
|
|
49
|
-
// Summary
|
|
50
|
-
lines.push("# SESSION TRIAGE RESULTS\n");
|
|
51
|
-
lines.push(`Total sessions analyzed: ${data.summary.total_sessions}`);
|
|
52
|
-
lines.push(`Sessions with issues: ${data.summary.flagged_sessions}`);
|
|
53
|
-
lines.push(`Sessions with user comments: ${data.summary.sessions_with_comments}`);
|
|
54
|
-
if (data.sessions.length === 0) {
|
|
55
|
-
lines.push("\nNo sessions require attention.");
|
|
56
|
-
return lines.join("\n");
|
|
57
|
-
}
|
|
58
|
-
// Group by severity
|
|
59
|
-
const critical = data.sessions.filter((s) => s.severity === "critical");
|
|
60
|
-
const high = data.sessions.filter((s) => s.severity === "high");
|
|
61
|
-
const medium = data.sessions.filter((s) => s.severity === "medium");
|
|
62
|
-
const low = data.sessions.filter((s) => s.severity === "low");
|
|
63
|
-
lines.push("\n## PRIORITY SUMMARY");
|
|
64
|
-
lines.push(`- CRITICAL: ${critical.length} session(s) - investigate immediately`);
|
|
65
|
-
lines.push(`- HIGH: ${high.length} session(s) - investigate soon`);
|
|
66
|
-
lines.push(`- MEDIUM: ${medium.length} session(s) - review when possible`);
|
|
67
|
-
lines.push(`- LOW: ${low.length} session(s) - likely okay`);
|
|
68
|
-
// Action recommendations
|
|
69
|
-
lines.push("\n## RECOMMENDED ACTIONS\n");
|
|
70
|
-
if (critical.length > 0) {
|
|
71
|
-
lines.push("### CRITICAL - Investigate Immediately\n");
|
|
72
|
-
for (const s of critical) {
|
|
73
|
-
lines.push(`**Session ${s.session_id.slice(-8)}** (${formatDuration(s.duration_seconds)}, ${s.device})`);
|
|
74
|
-
lines.push(` Replay: ${s.replay_url}`);
|
|
75
|
-
lines.push(` Score: ${(s.triage_score * 100).toFixed(0)}%`);
|
|
76
|
-
lines.push(` Why: ${getActionReason(s)}`);
|
|
77
|
-
if (s.pages_visited.length > 0) {
|
|
78
|
-
lines.push(` Pages: ${s.pages_visited.slice(0, 3).join(", ")}${s.pages_visited.length > 3 ? ` (+${s.pages_visited.length - 3} more)` : ""}`);
|
|
79
|
-
}
|
|
80
|
-
lines.push("");
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
if (high.length > 0) {
|
|
84
|
-
lines.push("### HIGH - Investigate Soon\n");
|
|
85
|
-
for (const s of high) {
|
|
86
|
-
lines.push(`**Session ${s.session_id.slice(-8)}** (${formatDuration(s.duration_seconds)}, ${s.device})`);
|
|
87
|
-
lines.push(` Replay: ${s.replay_url}`);
|
|
88
|
-
lines.push(` Score: ${(s.triage_score * 100).toFixed(0)}%`);
|
|
89
|
-
lines.push(` Why: ${getActionReason(s)}`);
|
|
90
|
-
if (s.pages_visited.length > 0) {
|
|
91
|
-
lines.push(` Pages: ${s.pages_visited.slice(0, 3).join(", ")}${s.pages_visited.length > 3 ? ` (+${s.pages_visited.length - 3} more)` : ""}`);
|
|
92
|
-
}
|
|
93
|
-
lines.push("");
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
if (medium.length > 0) {
|
|
97
|
-
lines.push("### MEDIUM - Review When Possible\n");
|
|
98
|
-
for (const s of medium) {
|
|
99
|
-
lines.push(`- Session ${s.session_id.slice(-8)} (${formatDuration(s.duration_seconds)}): ${getActionReason(s).split("\n")[0]}`);
|
|
100
|
-
lines.push(` ${s.replay_url}`);
|
|
101
|
-
}
|
|
102
|
-
lines.push("");
|
|
103
|
-
}
|
|
104
|
-
if (low.length > 0) {
|
|
105
|
-
lines.push("### LOW - Likely Okay\n");
|
|
106
|
-
lines.push(`${low.length} session(s) with minor or no issues detected.`);
|
|
107
|
-
if (low.length <= 3) {
|
|
108
|
-
for (const s of low) {
|
|
109
|
-
lines.push(`- Session ${s.session_id.slice(-8)}: ${s.replay_url}`);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
lines.push("");
|
|
113
|
-
}
|
|
114
|
-
// Raw data for reference (compact)
|
|
115
|
-
lines.push("\n## RAW DATA (for detailed analysis)\n");
|
|
116
|
-
lines.push("```json");
|
|
117
|
-
lines.push(JSON.stringify({
|
|
118
|
-
summary: data.summary,
|
|
119
|
-
sessions: data.sessions.map((s) => ({
|
|
120
|
-
id: s.session_id,
|
|
121
|
-
severity: s.severity,
|
|
122
|
-
score: s.triage_score,
|
|
123
|
-
url: s.replay_url,
|
|
124
|
-
comments: s.user_comments.length,
|
|
125
|
-
frustration: s.behavioral_signals.frustration,
|
|
126
|
-
rage_clicks: s.behavioral_signals.has_rage_clicks,
|
|
127
|
-
errors: s.console_errors.length,
|
|
128
|
-
has_data: s.behavioral_signals.has_behavioral_data,
|
|
129
|
-
})),
|
|
130
|
-
}, null, 2));
|
|
131
|
-
lines.push("```");
|
|
132
|
-
return lines.join("\n");
|
|
133
|
-
}
|
|
134
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
135
|
-
export function registerTriageSessions(server) {
|
|
136
|
-
server.registerTool("triage_sessions", {
|
|
137
|
-
description: "Automatically triage sessions to find compromised user experiences. " +
|
|
138
|
-
"Analyzes user comments, frustration signals, rage clicks, and console errors. " +
|
|
139
|
-
"Returns flagged sessions with evidence and replay links. Use this to identify " +
|
|
140
|
-
"sessions that need attention without manually reviewing every recording. " +
|
|
141
|
-
"Can triage specific sessions by ID(s) or scan for problematic sessions. " +
|
|
142
|
-
"NOTE: Session replay URLs require a paid plan (Starter+). Free tier users " +
|
|
143
|
-
"can see session summaries and triage scores but not watch replays.",
|
|
144
|
-
inputSchema: z.object({
|
|
145
|
-
session_ids: z
|
|
146
|
-
.array(z.string())
|
|
147
|
-
.optional()
|
|
148
|
-
.describe("Triage specific sessions by ID. If provided, other filters are ignored."),
|
|
149
|
-
days: z
|
|
150
|
-
.number()
|
|
151
|
-
.optional()
|
|
152
|
-
.default(7)
|
|
153
|
-
.describe("Lookback period in days (default: 7). Ignored if session_ids is provided."),
|
|
154
|
-
page_path: z
|
|
155
|
-
.string()
|
|
156
|
-
.optional()
|
|
157
|
-
.describe("Filter to sessions that visited a specific page"),
|
|
158
|
-
min_severity: z
|
|
159
|
-
.enum(["critical", "high", "medium", "low"])
|
|
160
|
-
.optional()
|
|
161
|
-
.describe("Minimum severity to include in results"),
|
|
162
|
-
limit: z
|
|
163
|
-
.number()
|
|
164
|
-
.optional()
|
|
165
|
-
.default(20)
|
|
166
|
-
.describe("Maximum sessions to return (default: 20, max: 100)"),
|
|
167
|
-
}),
|
|
168
|
-
}, async ({ session_ids, days, page_path, min_severity, limit, }) => {
|
|
169
|
-
if (!isApiConfigured()) {
|
|
170
|
-
return {
|
|
171
|
-
content: [
|
|
172
|
-
{
|
|
173
|
-
type: "text",
|
|
174
|
-
text: JSON.stringify({ error: "API not configured" }),
|
|
175
|
-
},
|
|
176
|
-
],
|
|
177
|
-
isError: true,
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
const { data, error } = await apiGet("/sessions/triage", {
|
|
181
|
-
session_ids: session_ids?.join(","),
|
|
182
|
-
days: session_ids?.length ? undefined : (days ?? 7),
|
|
183
|
-
page_path: session_ids?.length ? undefined : page_path,
|
|
184
|
-
min_severity,
|
|
185
|
-
limit: session_ids?.length ? session_ids.length : (limit ?? 20),
|
|
186
|
-
});
|
|
187
|
-
if (error) {
|
|
188
|
-
return {
|
|
189
|
-
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
190
|
-
isError: true,
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
// Format output for better LLM comprehension
|
|
194
|
-
const formattedOutput = formatTriageOutput(data);
|
|
195
|
-
return { content: [{ type: "text", text: formattedOutput }] };
|
|
196
|
-
});
|
|
197
|
-
}
|