@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,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Search Tools — Semantic and keyword search over the tool catalog.
|
|
3
|
-
*
|
|
4
|
-
* Allows the agent to discover specialized tools by describing what
|
|
5
|
-
* it needs in natural language. Uses pre-computed embeddings for
|
|
6
|
-
* fast, accurate matching with fallback to keyword search.
|
|
7
|
-
*/
|
|
8
|
-
export interface ToolEntry {
|
|
9
|
-
name: string;
|
|
10
|
-
description: string;
|
|
11
|
-
category: string;
|
|
12
|
-
parameters: Record<string, {
|
|
13
|
-
type: string;
|
|
14
|
-
required?: boolean;
|
|
15
|
-
description?: string;
|
|
16
|
-
}>;
|
|
17
|
-
embedding: number[];
|
|
18
|
-
}
|
|
19
|
-
export declare function searchTools(query: string, limit?: number, queryEmbedding?: number[]): Promise<ToolEntry[]>;
|
|
20
|
-
export declare function getToolByName(name: string): ToolEntry | undefined;
|
|
21
|
-
export declare function getAllTools(): ToolEntry[];
|
|
22
|
-
export declare function registerSearchTools(server: any): void;
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Search Tools — Semantic and keyword search over the tool catalog.
|
|
3
|
-
*
|
|
4
|
-
* Allows the agent to discover specialized tools by describing what
|
|
5
|
-
* it needs in natural language. Uses pre-computed embeddings for
|
|
6
|
-
* fast, accurate matching with fallback to keyword search.
|
|
7
|
-
*/
|
|
8
|
-
import { z } from "zod";
|
|
9
|
-
import { readFileSync } from "node:fs";
|
|
10
|
-
import { fileURLToPath } from "node:url";
|
|
11
|
-
import { dirname, join } from "node:path";
|
|
12
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
-
const __dirname = dirname(__filename);
|
|
14
|
-
let _catalog = null;
|
|
15
|
-
function loadCatalog() {
|
|
16
|
-
if (_catalog)
|
|
17
|
-
return _catalog;
|
|
18
|
-
try {
|
|
19
|
-
const catalogPath = join(__dirname, "toolCatalog.json");
|
|
20
|
-
const raw = readFileSync(catalogPath, "utf-8");
|
|
21
|
-
_catalog = JSON.parse(raw);
|
|
22
|
-
return _catalog;
|
|
23
|
-
}
|
|
24
|
-
catch {
|
|
25
|
-
console.warn("[searchTools] Failed to load toolCatalog.json, using empty catalog");
|
|
26
|
-
_catalog = [];
|
|
27
|
-
return _catalog;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
function cosineSimilarity(a, b) {
|
|
31
|
-
if (a.length === 0 || b.length === 0 || a.length !== b.length)
|
|
32
|
-
return 0;
|
|
33
|
-
let dot = 0;
|
|
34
|
-
for (let i = 0; i < a.length; i++) {
|
|
35
|
-
dot += a[i] * b[i];
|
|
36
|
-
}
|
|
37
|
-
return dot;
|
|
38
|
-
}
|
|
39
|
-
function searchByKeyword(query, limit) {
|
|
40
|
-
const catalog = loadCatalog();
|
|
41
|
-
const normalizedQuery = query.toLowerCase();
|
|
42
|
-
// Extract words, keeping short ones that might be meaningful (e.g., "ux", "js")
|
|
43
|
-
const queryWords = normalizedQuery
|
|
44
|
-
.split(/[\s_-]+/)
|
|
45
|
-
.filter((w) => w.length >= 2);
|
|
46
|
-
// Also check for the full query as a phrase
|
|
47
|
-
const queryPhrases = [normalizedQuery];
|
|
48
|
-
// Common synonyms and related terms
|
|
49
|
-
const synonyms = {
|
|
50
|
-
error: ["console", "js", "javascript", "bug", "crash", "exception"],
|
|
51
|
-
page: ["pages", "route", "url", "path"],
|
|
52
|
-
user: ["users", "session", "visitor"],
|
|
53
|
-
click: ["clicks", "tap", "press", "rage"],
|
|
54
|
-
form: ["forms", "input", "field", "submit"],
|
|
55
|
-
flow: ["flows", "journey", "funnel", "navigation", "path"],
|
|
56
|
-
issue: ["issues", "problem", "bug", "friction"],
|
|
57
|
-
fix: ["fixes", "remediation", "repair", "resolve"],
|
|
58
|
-
compare: ["comparison", "diff", "versus", "cohort"],
|
|
59
|
-
health: ["score", "metrics", "ux"],
|
|
60
|
-
dead: ["unresponsive", "broken", "stuck"],
|
|
61
|
-
rage: ["angry", "frustrated", "frustration"],
|
|
62
|
-
};
|
|
63
|
-
// Expand query words with synonyms
|
|
64
|
-
const expandedWords = new Set(queryWords);
|
|
65
|
-
for (const word of queryWords) {
|
|
66
|
-
if (synonyms[word]) {
|
|
67
|
-
synonyms[word].forEach((syn) => expandedWords.add(syn));
|
|
68
|
-
}
|
|
69
|
-
// Also check if query word is a synonym value
|
|
70
|
-
for (const [key, values] of Object.entries(synonyms)) {
|
|
71
|
-
if (values.includes(word)) {
|
|
72
|
-
expandedWords.add(key);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return catalog
|
|
77
|
-
.map((tool) => {
|
|
78
|
-
const toolName = tool.name.toLowerCase().replace(/_/g, " ");
|
|
79
|
-
const toolNameParts = tool.name.toLowerCase().split("_");
|
|
80
|
-
const text = `${toolName} ${tool.description} ${tool.category}`.toLowerCase();
|
|
81
|
-
let score = 0;
|
|
82
|
-
// Phrase match in description (highest value)
|
|
83
|
-
for (const phrase of queryPhrases) {
|
|
84
|
-
if (phrase.length > 3 && text.includes(phrase))
|
|
85
|
-
score += 5;
|
|
86
|
-
}
|
|
87
|
-
// Word matches
|
|
88
|
-
for (const word of expandedWords) {
|
|
89
|
-
// Exact word in tool name parts (e.g., "page" matches "get_page_metrics")
|
|
90
|
-
if (toolNameParts.includes(word))
|
|
91
|
-
score += 4;
|
|
92
|
-
// Word appears in tool name
|
|
93
|
-
if (toolName.includes(word))
|
|
94
|
-
score += 3;
|
|
95
|
-
// Category match
|
|
96
|
-
if (tool.category.toLowerCase() === word)
|
|
97
|
-
score += 2;
|
|
98
|
-
// Word in description
|
|
99
|
-
if (text.includes(word))
|
|
100
|
-
score += 1;
|
|
101
|
-
}
|
|
102
|
-
return { tool, score };
|
|
103
|
-
})
|
|
104
|
-
.filter((s) => s.score > 0)
|
|
105
|
-
.sort((a, b) => b.score - a.score)
|
|
106
|
-
.slice(0, limit)
|
|
107
|
-
.map((s) => s.tool);
|
|
108
|
-
}
|
|
109
|
-
async function searchBySemantic(query, limit, queryEmbedding) {
|
|
110
|
-
const catalog = loadCatalog();
|
|
111
|
-
return catalog
|
|
112
|
-
.filter((t) => t.embedding && t.embedding.length > 0)
|
|
113
|
-
.map((tool) => ({
|
|
114
|
-
tool,
|
|
115
|
-
score: cosineSimilarity(queryEmbedding, tool.embedding),
|
|
116
|
-
}))
|
|
117
|
-
.sort((a, b) => b.score - a.score)
|
|
118
|
-
.slice(0, limit)
|
|
119
|
-
.map((s) => s.tool);
|
|
120
|
-
}
|
|
121
|
-
export async function searchTools(query, limit = 5, queryEmbedding) {
|
|
122
|
-
if (queryEmbedding && queryEmbedding.length > 0) {
|
|
123
|
-
return searchBySemantic(query, limit, queryEmbedding);
|
|
124
|
-
}
|
|
125
|
-
return searchByKeyword(query, limit);
|
|
126
|
-
}
|
|
127
|
-
export function getToolByName(name) {
|
|
128
|
-
return loadCatalog().find((t) => t.name === name);
|
|
129
|
-
}
|
|
130
|
-
export function getAllTools() {
|
|
131
|
-
return loadCatalog();
|
|
132
|
-
}
|
|
133
|
-
const DEFAULT_TOOL_LIMIT = 5;
|
|
134
|
-
const searchToolsSchema = z.object({
|
|
135
|
-
query: z
|
|
136
|
-
.string()
|
|
137
|
-
.describe("Natural language description of what data or analysis capability you need. " +
|
|
138
|
-
"Describe what you want to learn or investigate."),
|
|
139
|
-
limit: z
|
|
140
|
-
.number()
|
|
141
|
-
.optional()
|
|
142
|
-
.describe("Maximum number of tools to return (default 5)"),
|
|
143
|
-
});
|
|
144
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
145
|
-
export function registerSearchTools(server) {
|
|
146
|
-
server.registerTool("search_tools", {
|
|
147
|
-
description: "Discover analysis tools by describing what data or capability you need. " +
|
|
148
|
-
"You have access to 40+ specialized tools covering sessions, pages, behaviors, journeys, " +
|
|
149
|
-
"forms, errors, performance, cohorts, issues, and remediation. Keyword search matches your intent to " +
|
|
150
|
-
"relevant tools. Returns tool names, descriptions, categories, and parameters. " +
|
|
151
|
-
"Use call_tool to execute discovered tools.",
|
|
152
|
-
inputSchema: searchToolsSchema,
|
|
153
|
-
}, async ({ query, limit }) => {
|
|
154
|
-
const searchLimit = limit ?? DEFAULT_TOOL_LIMIT;
|
|
155
|
-
const matches = await searchTools(query, searchLimit);
|
|
156
|
-
if (matches.length === 0) {
|
|
157
|
-
return {
|
|
158
|
-
content: [
|
|
159
|
-
{
|
|
160
|
-
type: "text",
|
|
161
|
-
text: JSON.stringify({
|
|
162
|
-
tools: [],
|
|
163
|
-
message: "No matching tools found. Try rephrasing your query or use broader terms like 'page', 'session', 'issue', 'flow', or 'form'.",
|
|
164
|
-
}),
|
|
165
|
-
},
|
|
166
|
-
],
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
const tools = matches.map((tool) => ({
|
|
170
|
-
name: tool.name,
|
|
171
|
-
description: tool.description.length > 250
|
|
172
|
-
? tool.description.slice(0, 250) + "..."
|
|
173
|
-
: tool.description,
|
|
174
|
-
category: tool.category,
|
|
175
|
-
parameters: Object.entries(tool.parameters).map(([name, prop]) => ({
|
|
176
|
-
name,
|
|
177
|
-
type: prop.type,
|
|
178
|
-
required: prop.required ?? false,
|
|
179
|
-
description: prop.description,
|
|
180
|
-
})),
|
|
181
|
-
}));
|
|
182
|
-
return {
|
|
183
|
-
content: [
|
|
184
|
-
{
|
|
185
|
-
type: "text",
|
|
186
|
-
text: JSON.stringify({
|
|
187
|
-
tools,
|
|
188
|
-
usage: "Use call_tool with the tool name and arguments to execute. Example: call_tool({ tool_name: 'get_page_metrics', arguments: { page_path: '/checkout' } })",
|
|
189
|
-
}),
|
|
190
|
-
},
|
|
191
|
-
],
|
|
192
|
-
};
|
|
193
|
-
});
|
|
194
|
-
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* compare_cohorts tool
|
|
3
|
-
*
|
|
4
|
-
* Compare two user cohorts side by side.
|
|
5
|
-
*/
|
|
6
|
-
import { z } from "zod";
|
|
7
|
-
import { apiPost, isApiConfigured } from "../api/client.js";
|
|
8
|
-
const cohortFilterSchema = z.object({
|
|
9
|
-
device: z
|
|
10
|
-
.enum(["desktop", "tablet", "mobile"])
|
|
11
|
-
.optional()
|
|
12
|
-
.describe("Filter by device type"),
|
|
13
|
-
outcome: z
|
|
14
|
-
.enum(["COMPLETED", "STRUGGLED", "BLOCKED", "DISENGAGED"])
|
|
15
|
-
.optional()
|
|
16
|
-
.describe("Filter by session outcome"),
|
|
17
|
-
pattern: z.string().optional().describe("Filter by behavioral pattern"),
|
|
18
|
-
page_path: z.string().optional().describe("Filter by page path"),
|
|
19
|
-
has_friction: z
|
|
20
|
-
.boolean()
|
|
21
|
-
.optional()
|
|
22
|
-
.describe("Filter for sessions with friction"),
|
|
23
|
-
has_rage_clicks: z
|
|
24
|
-
.boolean()
|
|
25
|
-
.optional()
|
|
26
|
-
.describe("Filter for sessions with rage clicks"),
|
|
27
|
-
});
|
|
28
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
29
|
-
export function registerCompareCohorts(server) {
|
|
30
|
-
server.registerTool("compare_cohorts", {
|
|
31
|
-
description: "Compare two user cohorts side by side. Each cohort is defined by filter criteria: " +
|
|
32
|
-
"device (desktop/tablet/mobile), outcome (COMPLETED/STRUGGLED/BLOCKED/DISENGAGED), " +
|
|
33
|
-
"pattern, has_friction, has_rage_clicks, or page_path. " +
|
|
34
|
-
"Returns behavioral metrics for each cohort and statistically significant differences. " +
|
|
35
|
-
'Use this to answer "how do mobile users differ from desktop?", "what distinguishes ' +
|
|
36
|
-
'users who complete vs abandon?", or "do form users struggle more than non-form users?"',
|
|
37
|
-
inputSchema: z.object({
|
|
38
|
-
cohort_a: cohortFilterSchema.describe('Filters for cohort A, e.g. {"device": "mobile"} or {"outcome": "COMPLETED"}'),
|
|
39
|
-
cohort_b: cohortFilterSchema.describe('Filters for cohort B, e.g. {"device": "desktop"} or {"outcome": "BLOCKED"}'),
|
|
40
|
-
cohort_a_label: z
|
|
41
|
-
.string()
|
|
42
|
-
.optional()
|
|
43
|
-
.describe("Human label for cohort A"),
|
|
44
|
-
cohort_b_label: z
|
|
45
|
-
.string()
|
|
46
|
-
.optional()
|
|
47
|
-
.describe("Human label for cohort B"),
|
|
48
|
-
page_path: z
|
|
49
|
-
.string()
|
|
50
|
-
.optional()
|
|
51
|
-
.describe("Scope comparison to a specific page"),
|
|
52
|
-
date_from: z.string().optional().describe("Start date (ISO format)"),
|
|
53
|
-
date_to: z.string().optional().describe("End date (ISO format)"),
|
|
54
|
-
}),
|
|
55
|
-
}, async ({ cohort_a, cohort_b, cohort_a_label, cohort_b_label, page_path, date_from, date_to, }) => {
|
|
56
|
-
if (!isApiConfigured()) {
|
|
57
|
-
return {
|
|
58
|
-
content: [
|
|
59
|
-
{
|
|
60
|
-
type: "text",
|
|
61
|
-
text: JSON.stringify({ error: "API not configured" }),
|
|
62
|
-
},
|
|
63
|
-
],
|
|
64
|
-
isError: true,
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
const { data, error } = await apiPost("/cohorts/compare", {
|
|
68
|
-
cohort_a,
|
|
69
|
-
cohort_b,
|
|
70
|
-
cohort_a_label,
|
|
71
|
-
cohort_b_label,
|
|
72
|
-
page_path,
|
|
73
|
-
date_from,
|
|
74
|
-
date_to,
|
|
75
|
-
});
|
|
76
|
-
if (error) {
|
|
77
|
-
return {
|
|
78
|
-
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
79
|
-
isError: true,
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
83
|
-
});
|
|
84
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* compare_periods tool
|
|
3
|
-
*
|
|
4
|
-
* Compare metrics between two time periods for a page.
|
|
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 registerComparePeriods(server) {
|
|
10
|
-
server.registerTool("compare_periods", {
|
|
11
|
-
description: "Compare behavioral metrics between two time periods for a specific page. " +
|
|
12
|
-
"Returns metrics for each period and the deltas between them. " +
|
|
13
|
-
"Use this to measure the impact of changes or compare week-over-week performance.",
|
|
14
|
-
inputSchema: z.object({
|
|
15
|
-
page_path: z.string().describe("Page path to compare"),
|
|
16
|
-
period_a: z
|
|
17
|
-
.object({
|
|
18
|
-
from: z.string().describe("Start date for period A (ISO format)"),
|
|
19
|
-
to: z.string().describe("End date for period A (ISO format)"),
|
|
20
|
-
})
|
|
21
|
-
.describe("First time period"),
|
|
22
|
-
period_b: z
|
|
23
|
-
.object({
|
|
24
|
-
from: z.string().describe("Start date for period B (ISO format)"),
|
|
25
|
-
to: z.string().describe("End date for period B (ISO format)"),
|
|
26
|
-
})
|
|
27
|
-
.describe("Second time period"),
|
|
28
|
-
}),
|
|
29
|
-
}, async ({ page_path, period_a, period_b, }) => {
|
|
30
|
-
if (!isApiConfigured()) {
|
|
31
|
-
return {
|
|
32
|
-
content: [
|
|
33
|
-
{
|
|
34
|
-
type: "text",
|
|
35
|
-
text: JSON.stringify({ error: "API not configured" }),
|
|
36
|
-
},
|
|
37
|
-
],
|
|
38
|
-
isError: true,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
const { data, error } = await apiPost("/pages/compare-periods", {
|
|
42
|
-
page_path,
|
|
43
|
-
period_a,
|
|
44
|
-
period_b,
|
|
45
|
-
});
|
|
46
|
-
if (error) {
|
|
47
|
-
return {
|
|
48
|
-
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
49
|
-
isError: true,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
53
|
-
});
|
|
54
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* detect_drift tool
|
|
3
|
-
*
|
|
4
|
-
* Detect behavioral drift over time.
|
|
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 registerDetectDrift(server) {
|
|
10
|
-
server.registerTool("detect_drift", {
|
|
11
|
-
description: "Detect behavioral drift over time by analyzing how user behavior patterns change. " +
|
|
12
|
-
"Splits data into time windows and measures centroid shift between consecutive periods. " +
|
|
13
|
-
"Use this for long-term monitoring to detect gradual UX degradation.",
|
|
14
|
-
inputSchema: z.object({
|
|
15
|
-
page_path: z
|
|
16
|
-
.string()
|
|
17
|
-
.optional()
|
|
18
|
-
.describe("Scope drift detection to a specific page"),
|
|
19
|
-
days: z
|
|
20
|
-
.number()
|
|
21
|
-
.optional()
|
|
22
|
-
.default(30)
|
|
23
|
-
.describe("Number of days to analyze (default 30)"),
|
|
24
|
-
window_size: z
|
|
25
|
-
.number()
|
|
26
|
-
.optional()
|
|
27
|
-
.default(7)
|
|
28
|
-
.describe("Size of each time window in days (default 7)"),
|
|
29
|
-
}),
|
|
30
|
-
}, async ({ page_path, days, window_size, }) => {
|
|
31
|
-
if (!isApiConfigured()) {
|
|
32
|
-
return {
|
|
33
|
-
content: [
|
|
34
|
-
{
|
|
35
|
-
type: "text",
|
|
36
|
-
text: JSON.stringify({ error: "API not configured" }),
|
|
37
|
-
},
|
|
38
|
-
],
|
|
39
|
-
isError: true,
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
const { data, error } = await apiGet("/drift", {
|
|
43
|
-
page_path,
|
|
44
|
-
days: days ?? 30,
|
|
45
|
-
window_size: window_size ?? 7,
|
|
46
|
-
});
|
|
47
|
-
if (error) {
|
|
48
|
-
return {
|
|
49
|
-
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
50
|
-
isError: true,
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
54
|
-
});
|
|
55
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* detect_regressions tool
|
|
3
|
-
*
|
|
4
|
-
* Detect behavioral regressions by comparing recent data against baselines.
|
|
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 registerDetectRegressions(server) {
|
|
10
|
-
server.registerTool("detect_regressions", {
|
|
11
|
-
description: "Detect behavioral regressions by comparing recent data against rolling 7-day baselines. " +
|
|
12
|
-
"By default analyzes top 50 pages by traffic. Use sort_by='low_traffic' to check low-traffic " +
|
|
13
|
-
"pages that might otherwise be missed. Use offset/limit to paginate through all pages. " +
|
|
14
|
-
"Returns pages where frustration, confusion, or rage click rate have deviated significantly.",
|
|
15
|
-
inputSchema: z.object({
|
|
16
|
-
window_hours: z
|
|
17
|
-
.number()
|
|
18
|
-
.optional()
|
|
19
|
-
.default(24)
|
|
20
|
-
.describe("How many recent hours to compare against baseline (default 24)"),
|
|
21
|
-
limit: z
|
|
22
|
-
.number()
|
|
23
|
-
.optional()
|
|
24
|
-
.default(50)
|
|
25
|
-
.describe("Number of pages to check per request (default 50, max 100)"),
|
|
26
|
-
offset: z
|
|
27
|
-
.number()
|
|
28
|
-
.optional()
|
|
29
|
-
.default(0)
|
|
30
|
-
.describe("Skip this many pages for pagination (default 0)"),
|
|
31
|
-
sort_by: z
|
|
32
|
-
.enum(["traffic", "low_traffic"])
|
|
33
|
-
.optional()
|
|
34
|
-
.default("traffic")
|
|
35
|
-
.describe("Sort order: 'traffic' (default) or 'low_traffic' to check overlooked pages"),
|
|
36
|
-
}),
|
|
37
|
-
}, async ({ window_hours, limit, offset, sort_by, }) => {
|
|
38
|
-
if (!isApiConfigured()) {
|
|
39
|
-
return {
|
|
40
|
-
content: [
|
|
41
|
-
{
|
|
42
|
-
type: "text",
|
|
43
|
-
text: JSON.stringify({ error: "API not configured" }),
|
|
44
|
-
},
|
|
45
|
-
],
|
|
46
|
-
isError: true,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
const { data, error } = await apiGet("/regressions", {
|
|
50
|
-
window_hours: window_hours ?? 24,
|
|
51
|
-
limit: limit ?? 50,
|
|
52
|
-
offset: offset ?? 0,
|
|
53
|
-
sort_by: sort_by ?? "traffic",
|
|
54
|
-
});
|
|
55
|
-
if (error) {
|
|
56
|
-
return {
|
|
57
|
-
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
58
|
-
isError: true,
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
62
|
-
});
|
|
63
|
-
}
|
package/dist/tools/diagnostic.js
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Diagnostic tools for self-improvement workflow.
|
|
3
|
-
*
|
|
4
|
-
* Provides comprehensive site diagnostics, issue investigation, and validation.
|
|
5
|
-
*/
|
|
6
|
-
import { z } from "zod";
|
|
7
|
-
import { apiGet, apiPost, isApiConfigured } from "../api/client.js";
|
|
8
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
|
-
export function registerDiagnosticTools(server) {
|
|
10
|
-
server.registerTool("run_full_diagnostic", {
|
|
11
|
-
description: "Get a quick site health overview with prioritized issues and problem pages. " +
|
|
12
|
-
"This is a lightweight entry point — it does NOT include regression detection. " +
|
|
13
|
-
"For a complete analysis, call detect_regressions separately after this. " +
|
|
14
|
-
"Returns: health score, top issues, pages needing attention, and investigation order.",
|
|
15
|
-
inputSchema: z.object({
|
|
16
|
-
days: z
|
|
17
|
-
.number()
|
|
18
|
-
.optional()
|
|
19
|
-
.default(7)
|
|
20
|
-
.describe("Number of days to analyze (default: 7)"),
|
|
21
|
-
}),
|
|
22
|
-
}, async ({ days }) => {
|
|
23
|
-
if (!isApiConfigured()) {
|
|
24
|
-
return {
|
|
25
|
-
content: [
|
|
26
|
-
{
|
|
27
|
-
type: "text",
|
|
28
|
-
text: JSON.stringify({ error: "API not configured" }),
|
|
29
|
-
},
|
|
30
|
-
],
|
|
31
|
-
isError: true,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
const { data, error } = await apiGet("/diagnostic/full", { days: days ?? 7 });
|
|
35
|
-
if (error) {
|
|
36
|
-
return {
|
|
37
|
-
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
38
|
-
isError: true,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
42
|
-
});
|
|
43
|
-
server.registerTool("investigate_issue", {
|
|
44
|
-
description: "Deep-dive into a specific issue. Returns affected sessions, element friction data, " +
|
|
45
|
-
"related console errors, similar issues, and page context. Use after identifying an " +
|
|
46
|
-
"issue to understand root cause. NOTE: Free tier users get issue summary and page " +
|
|
47
|
-
"context only. Detailed investigation data (affected sessions, element friction, " +
|
|
48
|
-
"related errors) requires a paid plan (Starter+).",
|
|
49
|
-
inputSchema: z.object({
|
|
50
|
-
issue_id: z.string().describe("The ID of the issue to investigate"),
|
|
51
|
-
days: z
|
|
52
|
-
.number()
|
|
53
|
-
.optional()
|
|
54
|
-
.default(7)
|
|
55
|
-
.describe("Number of days to look back (default: 7)"),
|
|
56
|
-
}),
|
|
57
|
-
}, async ({ issue_id, days }) => {
|
|
58
|
-
if (!isApiConfigured()) {
|
|
59
|
-
return {
|
|
60
|
-
content: [
|
|
61
|
-
{
|
|
62
|
-
type: "text",
|
|
63
|
-
text: JSON.stringify({ error: "API not configured" }),
|
|
64
|
-
},
|
|
65
|
-
],
|
|
66
|
-
isError: true,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
const { data, error } = await apiGet(`/issues/${issue_id}/investigate`, { days: days ?? 7 });
|
|
70
|
-
if (error) {
|
|
71
|
-
return {
|
|
72
|
-
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
73
|
-
isError: true,
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
77
|
-
});
|
|
78
|
-
server.registerTool("validate_issue", {
|
|
79
|
-
description: "Check if an issue is still actively occurring. Returns staleness info and recommendation (investigate, dismiss_stale, or monitor). Use to filter out stale issues before proposing fixes.",
|
|
80
|
-
inputSchema: z.object({
|
|
81
|
-
issue_id: z.string().describe("The ID of the issue to validate"),
|
|
82
|
-
lookback_days: z
|
|
83
|
-
.number()
|
|
84
|
-
.optional()
|
|
85
|
-
.default(3)
|
|
86
|
-
.describe("Number of days to look back for recent occurrences (default: 3)"),
|
|
87
|
-
}),
|
|
88
|
-
}, async ({ issue_id, lookback_days, }) => {
|
|
89
|
-
if (!isApiConfigured()) {
|
|
90
|
-
return {
|
|
91
|
-
content: [
|
|
92
|
-
{
|
|
93
|
-
type: "text",
|
|
94
|
-
text: JSON.stringify({ error: "API not configured" }),
|
|
95
|
-
},
|
|
96
|
-
],
|
|
97
|
-
isError: true,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
const { data, error } = await apiPost(`/issues/${issue_id}/validate`, { lookback_days: lookback_days ?? 3 });
|
|
101
|
-
if (error) {
|
|
102
|
-
return {
|
|
103
|
-
content: [{ type: "text", text: JSON.stringify({ error }) }],
|
|
104
|
-
isError: true,
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
108
|
-
});
|
|
109
|
-
}
|