retestkit 1.4.1 → 1.5.0

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.
Files changed (238) hide show
  1. package/README.md +59 -40
  2. package/dist/config.js +8 -8
  3. package/dist/config.js.map +1 -1
  4. package/dist/logger.js +1 -1
  5. package/dist/logger.js.map +1 -1
  6. package/dist/prompts/index.d.ts +1 -1
  7. package/dist/prompts/index.d.ts.map +1 -1
  8. package/dist/prompts/index.js +21 -21
  9. package/dist/prompts/index.js.map +1 -1
  10. package/dist/prompts/templates/mcp/retest-crawl.md +7 -0
  11. package/{src/prompts/templates/mcp/webtest-discover-flows.md → dist/prompts/templates/mcp/retest-discover-flows.md} +1 -1
  12. package/{src/prompts/templates/mcp/webtest-discover.md → dist/prompts/templates/mcp/retest-discover.md} +2 -2
  13. package/dist/prompts/templates/mcp/retest-full-workflow.md +12 -0
  14. package/{src/prompts/templates/mcp/webtest-generate-tests.md → dist/prompts/templates/mcp/retest-generate-tests.md} +1 -1
  15. package/{src/prompts/templates/mcp/webtest-run-test.md → dist/prompts/templates/mcp/retest-run-test.md} +1 -1
  16. package/{src/prompts/templates/mcp/webtest-start.md → dist/prompts/templates/mcp/retest-start.md} +1 -1
  17. package/{src → dist}/prompts/templates/sampling/system-prefix.md +1 -1
  18. package/dist/resources/index.js +7 -7
  19. package/dist/resources/index.js.map +1 -1
  20. package/dist/schemas/config.js +2 -2
  21. package/dist/schemas/config.js.map +1 -1
  22. package/dist/security/index.js +1 -1
  23. package/dist/security/index.js.map +1 -1
  24. package/dist/server.js +3 -3
  25. package/dist/server.js.map +1 -1
  26. package/dist/test-utils/mock-context.js +22 -22
  27. package/dist/test-utils/mock-context.js.map +1 -1
  28. package/dist/tools/index.d.ts +1 -1
  29. package/dist/tools/index.d.ts.map +1 -1
  30. package/dist/tools/index.js +5 -5
  31. package/dist/tools/index.js.map +1 -1
  32. package/dist/tools/retest/crawl.d.ts.map +1 -0
  33. package/dist/tools/{webtest → retest}/crawl.js +7 -7
  34. package/dist/tools/retest/crawl.js.map +1 -0
  35. package/dist/tools/retest/discover-features.d.ts.map +1 -0
  36. package/dist/tools/{webtest → retest}/discover-features.js +6 -6
  37. package/dist/tools/retest/discover-features.js.map +1 -0
  38. package/dist/tools/retest/discover-flows.d.ts.map +1 -0
  39. package/dist/tools/{webtest → retest}/discover-flows.js +6 -6
  40. package/dist/tools/retest/discover-flows.js.map +1 -0
  41. package/dist/tools/retest/generate-tests.d.ts.map +1 -0
  42. package/dist/tools/{webtest → retest}/generate-tests.js +5 -5
  43. package/dist/tools/retest/generate-tests.js.map +1 -0
  44. package/dist/tools/retest/index.d.ts.map +1 -0
  45. package/dist/tools/retest/index.js.map +1 -0
  46. package/dist/tools/retest/run-test-case.d.ts.map +1 -0
  47. package/dist/tools/{webtest → retest}/run-test-case.js +3 -3
  48. package/dist/tools/retest/run-test-case.js.map +1 -0
  49. package/dist/tools/retest/schemas.d.ts.map +1 -0
  50. package/dist/tools/retest/schemas.js.map +1 -0
  51. package/dist/tools/retest/start-analysis.d.ts.map +1 -0
  52. package/dist/tools/{webtest → retest}/start-analysis.js +5 -5
  53. package/dist/tools/retest/start-analysis.js.map +1 -0
  54. package/dist/workspace/index.js +8 -8
  55. package/dist/workspace/index.js.map +1 -1
  56. package/dist/workspace/types.d.ts +2 -2
  57. package/dist/workspace/types.d.ts.map +1 -1
  58. package/package.json +6 -2
  59. package/.claude/commands/openspec/apply.md +0 -23
  60. package/.claude/commands/openspec/archive.md +0 -27
  61. package/.claude/commands/openspec/proposal.md +0 -28
  62. package/.gemini/commands/openspec/apply.toml +0 -21
  63. package/.gemini/commands/openspec/archive.toml +0 -25
  64. package/.gemini/commands/openspec/proposal.toml +0 -26
  65. package/.github/prompts/openspec-apply.prompt.md +0 -22
  66. package/.github/prompts/openspec-archive.prompt.md +0 -26
  67. package/.github/prompts/openspec-proposal.prompt.md +0 -27
  68. package/.github/workflows/release.yml +0 -33
  69. package/.kilocode/workflows/openspec-apply.md +0 -17
  70. package/.kilocode/workflows/openspec-archive.md +0 -21
  71. package/.kilocode/workflows/openspec-proposal.md +0 -22
  72. package/.mcp.json +0 -23
  73. package/.opencode/command/openspec-apply.md +0 -25
  74. package/.opencode/command/openspec-archive.md +0 -28
  75. package/.opencode/command/openspec-proposal.md +0 -30
  76. package/.roo/commands/openspec-apply.md +0 -20
  77. package/.roo/commands/openspec-archive.md +0 -24
  78. package/.roo/commands/openspec-proposal.md +0 -25
  79. package/.vscode/mcp.json +0 -23
  80. package/AGENTS.md +0 -18
  81. package/CLAUDE.md +0 -18
  82. package/dist/tools/webtest/crawl.d.ts.map +0 -1
  83. package/dist/tools/webtest/crawl.js.map +0 -1
  84. package/dist/tools/webtest/discover-features.d.ts.map +0 -1
  85. package/dist/tools/webtest/discover-features.js.map +0 -1
  86. package/dist/tools/webtest/discover-flows.d.ts.map +0 -1
  87. package/dist/tools/webtest/discover-flows.js.map +0 -1
  88. package/dist/tools/webtest/generate-tests.d.ts.map +0 -1
  89. package/dist/tools/webtest/generate-tests.js.map +0 -1
  90. package/dist/tools/webtest/index.d.ts.map +0 -1
  91. package/dist/tools/webtest/index.js.map +0 -1
  92. package/dist/tools/webtest/run-test-case.d.ts.map +0 -1
  93. package/dist/tools/webtest/run-test-case.js.map +0 -1
  94. package/dist/tools/webtest/schemas.d.ts.map +0 -1
  95. package/dist/tools/webtest/schemas.js.map +0 -1
  96. package/dist/tools/webtest/start-analysis.d.ts.map +0 -1
  97. package/dist/tools/webtest/start-analysis.js.map +0 -1
  98. package/openspec/AGENTS.md +0 -456
  99. package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/proposal.md +0 -33
  100. package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/specs/webtest-resources/spec.md +0 -27
  101. package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/specs/webtest-tools/spec.md +0 -304
  102. package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/tasks.md +0 -43
  103. package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/design.md +0 -209
  104. package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/proposal.md +0 -41
  105. package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/specs/mcp-server-core/spec.md +0 -183
  106. package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/tasks.md +0 -112
  107. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/design.md +0 -333
  108. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/proposal.md +0 -66
  109. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/mcp-server-core/spec.md +0 -129
  110. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-lifecycle/spec.md +0 -138
  111. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-logging/spec.md +0 -211
  112. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-prompts/spec.md +0 -157
  113. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-resources/spec.md +0 -213
  114. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-sampling/spec.md +0 -257
  115. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-tools/spec.md +0 -501
  116. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/tasks.md +0 -264
  117. package/openspec/changes/archive/2025-12-18-allow-analysis-of-incomplete-crawls/proposal.md +0 -24
  118. package/openspec/changes/archive/2025-12-18-allow-analysis-of-incomplete-crawls/specs/webtest-tools/spec.md +0 -80
  119. package/openspec/changes/archive/2025-12-18-allow-analysis-of-incomplete-crawls/tasks.md +0 -8
  120. package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/design.md +0 -90
  121. package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/proposal.md +0 -28
  122. package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/specs/webtest-sampling/spec.md +0 -90
  123. package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/tasks.md +0 -33
  124. package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/design.md +0 -558
  125. package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/proposal.md +0 -119
  126. package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/specs/webtest-resources/spec.md +0 -109
  127. package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/specs/webtest-tools/spec.md +0 -121
  128. package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/tasks.md +0 -133
  129. package/openspec/changes/extract-prompts-to-markdown/design.md +0 -86
  130. package/openspec/changes/extract-prompts-to-markdown/proposal.md +0 -50
  131. package/openspec/changes/extract-prompts-to-markdown/specs/webtest-prompts/spec.md +0 -74
  132. package/openspec/changes/extract-prompts-to-markdown/tasks.md +0 -40
  133. package/openspec/changes/refactor-webtest-naming/design.md +0 -95
  134. package/openspec/changes/refactor-webtest-naming/proposal.md +0 -66
  135. package/openspec/changes/refactor-webtest-naming/specs/webtest-prompts/spec.md +0 -79
  136. package/openspec/changes/refactor-webtest-naming/specs/webtest-resources/spec.md +0 -80
  137. package/openspec/changes/refactor-webtest-naming/specs/webtest-sampling/spec.md +0 -122
  138. package/openspec/changes/refactor-webtest-naming/specs/webtest-tools/spec.md +0 -113
  139. package/openspec/changes/refactor-webtest-naming/tasks.md +0 -119
  140. package/openspec/changes/rename-package-to-retest/proposal.md +0 -52
  141. package/openspec/changes/rename-package-to-retest/specs/mcp-server-core/spec.md +0 -53
  142. package/openspec/changes/rename-package-to-retest/specs/retest-lifecycle/spec.md +0 -68
  143. package/openspec/changes/rename-package-to-retest/specs/retest-logging/spec.md +0 -35
  144. package/openspec/changes/rename-package-to-retest/specs/retest-prompts/spec.md +0 -159
  145. package/openspec/changes/rename-package-to-retest/specs/retest-resources/spec.md +0 -251
  146. package/openspec/changes/rename-package-to-retest/specs/retest-sampling/spec.md +0 -99
  147. package/openspec/changes/rename-package-to-retest/specs/retest-tools/spec.md +0 -295
  148. package/openspec/changes/rename-package-to-retest/tasks.md +0 -71
  149. package/openspec/project.md +0 -31
  150. package/openspec/specs/mcp-server-core/spec.md +0 -178
  151. package/openspec/specs/webtest-lifecycle/spec.md +0 -136
  152. package/openspec/specs/webtest-logging/spec.md +0 -209
  153. package/openspec/specs/webtest-prompts/spec.md +0 -155
  154. package/openspec/specs/webtest-resources/spec.md +0 -248
  155. package/openspec/specs/webtest-sampling/spec.md +0 -344
  156. package/openspec/specs/webtest-tools/spec.md +0 -282
  157. package/release.config.js +0 -9
  158. package/src/config.test.ts +0 -96
  159. package/src/config.ts +0 -32
  160. package/src/elicitation/index.test.ts +0 -399
  161. package/src/elicitation/index.ts +0 -171
  162. package/src/elicitation/types.ts +0 -68
  163. package/src/index.ts +0 -83
  164. package/src/lifecycle/index.test.ts +0 -260
  165. package/src/lifecycle/index.ts +0 -101
  166. package/src/logger.redaction.test.ts +0 -322
  167. package/src/logger.test.ts +0 -123
  168. package/src/logger.ts +0 -229
  169. package/src/playwright-client/index.ts +0 -392
  170. package/src/playwright-client/types.ts +0 -99
  171. package/src/progress/index.test.ts +0 -327
  172. package/src/progress/index.ts +0 -170
  173. package/src/progress/types.ts +0 -25
  174. package/src/prompts/index.test.ts +0 -451
  175. package/src/prompts/index.ts +0 -246
  176. package/src/prompts/loader.test.ts +0 -100
  177. package/src/prompts/loader.ts +0 -59
  178. package/src/prompts/templates/mcp/webtest-crawl.md +0 -7
  179. package/src/prompts/templates/mcp/webtest-full-workflow.md +0 -12
  180. package/src/resources/index.ts +0 -250
  181. package/src/resources/subscriptions.ts +0 -37
  182. package/src/sampling/index.test.ts +0 -414
  183. package/src/sampling/index.ts +0 -286
  184. package/src/sampling/prompts.ts +0 -194
  185. package/src/sampling/types.ts +0 -60
  186. package/src/schemas/config.ts +0 -39
  187. package/src/security/index.test.ts +0 -441
  188. package/src/security/index.ts +0 -361
  189. package/src/security/security-scenarios.test.ts +0 -468
  190. package/src/server.ts +0 -211
  191. package/src/test-utils/index.ts +0 -6
  192. package/src/test-utils/mock-context.ts +0 -426
  193. package/src/test-utils/mock-playwright-client.ts +0 -422
  194. package/src/tools/index.ts +0 -11
  195. package/src/tools/webtest/crawl.test.ts +0 -834
  196. package/src/tools/webtest/crawl.ts +0 -901
  197. package/src/tools/webtest/discover-features.ts +0 -412
  198. package/src/tools/webtest/discover-flows.ts +0 -408
  199. package/src/tools/webtest/generate-tests.test.ts +0 -532
  200. package/src/tools/webtest/generate-tests.ts +0 -425
  201. package/src/tools/webtest/index.ts +0 -7
  202. package/src/tools/webtest/integration.test.ts +0 -536
  203. package/src/tools/webtest/run-test-case.test.ts +0 -659
  204. package/src/tools/webtest/run-test-case.ts +0 -508
  205. package/src/tools/webtest/schemas.ts +0 -201
  206. package/src/tools/webtest/start-analysis.test.ts +0 -151
  207. package/src/tools/webtest/start-analysis.ts +0 -158
  208. package/src/transports/http.ts +0 -19
  209. package/src/transports/index.ts +0 -30
  210. package/src/transports/stdio.ts +0 -7
  211. package/src/types/capabilities.test.ts +0 -193
  212. package/src/types/capabilities.ts +0 -50
  213. package/src/types/context.ts +0 -21
  214. package/src/types/tool.ts +0 -11
  215. package/src/workspace/index.ts +0 -945
  216. package/src/workspace/markdown.ts +0 -272
  217. package/src/workspace/types.ts +0 -186
  218. package/tests/integration/server.test.ts +0 -89
  219. package/tests/integration/tools.test.ts +0 -99
  220. package/tsconfig.json +0 -20
  221. package/vitest.config.ts +0 -9
  222. package/vitest.integration.config.ts +0 -10
  223. /package/{src → dist}/prompts/templates/sampling/crawl-action.md +0 -0
  224. /package/{src → dist}/prompts/templates/sampling/feature-discovery.md +0 -0
  225. /package/{src → dist}/prompts/templates/sampling/flow-discovery.md +0 -0
  226. /package/{src → dist}/prompts/templates/sampling/page-content-wrapper.md +0 -0
  227. /package/{src → dist}/prompts/templates/sampling/test-evaluation.md +0 -0
  228. /package/{src → dist}/prompts/templates/sampling/test-generation.md +0 -0
  229. /package/dist/tools/{webtest → retest}/crawl.d.ts +0 -0
  230. /package/dist/tools/{webtest → retest}/discover-features.d.ts +0 -0
  231. /package/dist/tools/{webtest → retest}/discover-flows.d.ts +0 -0
  232. /package/dist/tools/{webtest → retest}/generate-tests.d.ts +0 -0
  233. /package/dist/tools/{webtest → retest}/index.d.ts +0 -0
  234. /package/dist/tools/{webtest → retest}/index.js +0 -0
  235. /package/dist/tools/{webtest → retest}/run-test-case.d.ts +0 -0
  236. /package/dist/tools/{webtest → retest}/schemas.d.ts +0 -0
  237. /package/dist/tools/{webtest → retest}/schemas.js +0 -0
  238. /package/dist/tools/{webtest → retest}/start-analysis.d.ts +0 -0
@@ -1,408 +0,0 @@
1
- import { z } from "zod";
2
- import type { McpTool, ToolResult } from "../../types/tool.js";
3
- import type { ServerContext } from "../../types/context.js";
4
- import type { WorkspaceManager } from "../../workspace/index.js";
5
- import type { SamplingClient } from "../../sampling/index.js";
6
- import type { ResourceManager } from "../../resources/index.js";
7
- import { buildFlowDiscoveryPrompt } from "../../sampling/prompts.js";
8
- import { FlowsDiscoverySchema, AnalysisIdSchema, CrawlIdSchema, FeatureSlugSchema, type FlowsDiscovery } from "./schemas.js";
9
-
10
- export const discoverFlowsInputSchema = z.object({
11
- analysisId: AnalysisIdSchema,
12
- featureSlug: FeatureSlugSchema,
13
- crawlId: CrawlIdSchema
14
- .optional()
15
- .describe("Specific crawl to use. If not provided, uses the most recent crawl with captured pages."),
16
- manualDiscovery: z
17
- .object({
18
- featureSlug: z.string(),
19
- flows: z.array(z.object({
20
- id: z.string(),
21
- name: z.string(),
22
- description: z.string(),
23
- entryPoint: z.string(),
24
- steps: z.array(z.string()),
25
- })),
26
- suggestedAssertions: z.array(z.string()),
27
- })
28
- .optional()
29
- .describe("Manual discovery result when sampling is unavailable. Provide this after executing the returned prompt."),
30
- });
31
-
32
- export type DiscoverFlowsInput = z.infer<typeof discoverFlowsInputSchema>;
33
-
34
- export function createDiscoverFlowsTool(
35
- getContext: () => ServerContext & {
36
- workspaceManager: WorkspaceManager;
37
- samplingClient: SamplingClient;
38
- resourceManager: ResourceManager;
39
- }
40
- ): McpTool<DiscoverFlowsInput> {
41
- return {
42
- name: "webtest_discover_flows",
43
- description: `Discover user flows within a specific feature.
44
-
45
- This tool uses AI to identify user flows within a feature:
46
- - Identifies user journeys that accomplish specific goals
47
- - Maps entry points and step sequences for each flow
48
- - Suggests assertions that should hold for the flows
49
-
50
- Outputs flows.md under features/<feature-slug>/. Run webtest_discover_features first to identify features.
51
-
52
- Requires a crawl with captured pages and a valid feature slug from features.md.`,
53
-
54
- inputSchema: discoverFlowsInputSchema,
55
-
56
- async handler(input: DiscoverFlowsInput): Promise<ToolResult> {
57
- const ctx = getContext();
58
- const { logger, workspaceManager, samplingClient, resourceManager } = ctx;
59
-
60
- const discoveryLogger = logger.withCorrelation({
61
- analysisId: input.analysisId,
62
- featureSlug: input.featureSlug,
63
- });
64
-
65
- discoveryLogger.info("Starting flow discovery", {
66
- featureSlug: input.featureSlug,
67
- crawlId: input.crawlId,
68
- });
69
-
70
- try {
71
- // Validate workspace exists
72
- if (!(await workspaceManager.workspaceExists(input.analysisId))) {
73
- return {
74
- content: [
75
- {
76
- type: "text",
77
- text: `Error: Analysis workspace "${input.analysisId}" not found.`,
78
- },
79
- ],
80
- isError: true,
81
- };
82
- }
83
-
84
- const workspace = await workspaceManager.readWorkspaceIndex(input.analysisId);
85
-
86
- // Check if features have been discovered
87
- if (!workspace.features) {
88
- return {
89
- content: [
90
- {
91
- type: "text",
92
- text: "Error: No features found. Run webtest_discover_features first.",
93
- },
94
- ],
95
- isError: true,
96
- };
97
- }
98
-
99
- // Find the requested feature
100
- const feature = workspace.features.features.find(
101
- (f) => f.slug === input.featureSlug
102
- );
103
-
104
- if (!feature) {
105
- const availableFeatures = workspace.features.features.map((f) => f.slug).join(", ");
106
- return {
107
- content: [
108
- {
109
- type: "text",
110
- text: `Error: Feature "${input.featureSlug}" not found. Available features: ${availableFeatures}`,
111
- },
112
- ],
113
- isError: true,
114
- };
115
- }
116
-
117
- // Find the crawl to use
118
- let targetCrawlId = input.crawlId;
119
- let selectedCrawlRef: (typeof workspace.crawls)[0] | undefined;
120
-
121
- if (!targetCrawlId) {
122
- // Sort crawls by most recent first
123
- const sortedCrawls = [...workspace.crawls].sort(
124
- (a, b) =>
125
- new Date(b.completedAt || b.startedAt).getTime() -
126
- new Date(a.completedAt || a.startedAt).getTime()
127
- );
128
-
129
- const crawlsWithData = sortedCrawls.filter((c) => c.pagesVisited > 0);
130
-
131
- if (crawlsWithData.length > 0) {
132
- selectedCrawlRef = crawlsWithData[0];
133
- targetCrawlId = selectedCrawlRef.crawlId;
134
- } else if (sortedCrawls.length > 0) {
135
- for (const crawlRef of sortedCrawls) {
136
- try {
137
- const crawlIndex = await workspaceManager.readCrawlIndex(
138
- input.analysisId,
139
- crawlRef.crawlId
140
- );
141
- if (crawlIndex.pages.length > 0) {
142
- selectedCrawlRef = crawlRef;
143
- targetCrawlId = crawlRef.crawlId;
144
- break;
145
- }
146
- } catch {
147
- // Crawl index not readable, skip
148
- }
149
- }
150
- }
151
-
152
- if (!targetCrawlId) {
153
- return {
154
- content: [
155
- {
156
- type: "text",
157
- text: "Error: No crawls with captured data found.",
158
- },
159
- ],
160
- isError: true,
161
- };
162
- }
163
- } else {
164
- selectedCrawlRef = workspace.crawls.find((c) => c.crawlId === targetCrawlId);
165
- }
166
-
167
- // Load crawl data
168
- const crawlIndex = await workspaceManager.readCrawlIndex(
169
- input.analysisId,
170
- targetCrawlId
171
- );
172
-
173
- if (crawlIndex.pages.length === 0) {
174
- return {
175
- content: [
176
- {
177
- type: "text",
178
- text: "Error: Crawl has no captured pages.",
179
- },
180
- ],
181
- isError: true,
182
- };
183
- }
184
-
185
- discoveryLogger.info("Discovering flows for feature", {
186
- featureName: feature.name,
187
- crawlId: targetCrawlId,
188
- pageCount: crawlIndex.pages.length,
189
- });
190
-
191
- // Filter page snapshots relevant to the feature (by entry points)
192
- // For now, load all pages and let the AI filter
193
- const pageSnapshots: Array<{ url: string; content: string }> = [];
194
-
195
- for (const page of crawlIndex.pages.slice(0, 10)) {
196
- try {
197
- const snapshotContent = await resourceManager.readResource(
198
- page.snapshotUri
199
- );
200
- if (snapshotContent.text) {
201
- const snapshot = JSON.parse(snapshotContent.text);
202
- pageSnapshots.push({
203
- url: page.url,
204
- content: snapshot.content || "",
205
- });
206
- }
207
- } catch (error) {
208
- discoveryLogger.warn("Failed to load page snapshot", {
209
- pageId: page.pageId,
210
- error: error instanceof Error ? error.message : "Unknown error",
211
- });
212
- }
213
- }
214
-
215
- // Determine discovery source: manual input, sampling, or fallback prompt
216
- let discovery: FlowsDiscovery;
217
-
218
- if (input.manualDiscovery) {
219
- discoveryLogger.info("Using manual discovery input");
220
- discovery = input.manualDiscovery as FlowsDiscovery;
221
- } else if (!samplingClient.hasSampling()) {
222
- const prompt = buildFlowDiscoveryPrompt({
223
- featureSlug: feature.slug,
224
- featureName: feature.name,
225
- featureDescription: feature.description,
226
- featureEntities: feature.entities,
227
- featureEntryPoints: feature.entryPoints,
228
- pageSnapshots,
229
- });
230
-
231
- return {
232
- content: [
233
- {
234
- type: "text",
235
- text: JSON.stringify(
236
- {
237
- needsManualInput: true,
238
- analysisId: input.analysisId,
239
- featureSlug: input.featureSlug,
240
- crawlId: targetCrawlId,
241
- prompt,
242
- expectedResponseSchema: FlowsDiscoverySchema._def,
243
- instructions:
244
- "Execute this prompt with your LLM, then call webtest_discover_flows again with the result in the 'manualDiscovery' parameter",
245
- },
246
- null,
247
- 2
248
- ),
249
- },
250
- ],
251
- };
252
- } else {
253
- const samplingResult = await samplingClient.createMessage({
254
- systemPrompt: `You are identifying user flows within the "${feature.name}" feature of a web application.
255
- A "flow" is a user journey that accomplishes a specific goal within this feature.
256
- Focus only on flows relevant to this specific feature.`,
257
- userPrompt: buildFlowDiscoveryPrompt({
258
- featureSlug: feature.slug,
259
- featureName: feature.name,
260
- featureDescription: feature.description,
261
- featureEntities: feature.entities,
262
- featureEntryPoints: feature.entryPoints,
263
- pageSnapshots,
264
- }),
265
- schema: FlowsDiscoverySchema,
266
- maxTokens: 4096,
267
- });
268
-
269
- if (!samplingResult.success || !samplingResult.data) {
270
- discoveryLogger.error("Flow discovery sampling failed", {
271
- error: samplingResult.error,
272
- });
273
-
274
- return {
275
- content: [
276
- {
277
- type: "text",
278
- text: `Error during flow discovery: ${samplingResult.error}`,
279
- },
280
- ],
281
- isError: true,
282
- };
283
- }
284
-
285
- discovery = samplingResult.data;
286
- }
287
-
288
- // Generate flows markdown
289
- const markdownReport = generateFlowsMarkdown(discovery, feature);
290
-
291
- // Build frontmatter
292
- const frontmatter = {
293
- featureSlug: discovery.featureSlug,
294
- featureName: feature.name,
295
- flows: discovery.flows,
296
- suggestedAssertions: discovery.suggestedAssertions,
297
- };
298
-
299
- // Save flows
300
- const { flowsFilePath, flowsUri, flowCount } =
301
- await workspaceManager.saveFlows(input.analysisId, input.featureSlug, {
302
- markdown: markdownReport,
303
- frontmatter,
304
- });
305
-
306
- await resourceManager.notifyListChanged();
307
-
308
- const result = {
309
- analysisId: input.analysisId,
310
- featureSlug: input.featureSlug,
311
- crawlId: targetCrawlId,
312
- flowsFilePath,
313
- flowsUri,
314
- summary: {
315
- featureName: feature.name,
316
- flowCount,
317
- flows: discovery.flows.map((f) => ({
318
- id: f.id,
319
- name: f.name,
320
- })),
321
- assertionCount: discovery.suggestedAssertions.length,
322
- },
323
- nextSteps: [
324
- `Use webtest_generate_tests with analysisId="${input.analysisId}" to generate test cases`,
325
- `Review discovered flows at ${flowsUri}`,
326
- ],
327
- };
328
-
329
- discoveryLogger.info("Flow discovery completed", {
330
- featureSlug: input.featureSlug,
331
- flowCount,
332
- flows: discovery.flows.map((f) => f.id),
333
- });
334
-
335
- return {
336
- content: [
337
- {
338
- type: "text",
339
- text: JSON.stringify(result, null, 2),
340
- },
341
- ],
342
- };
343
- } catch (error) {
344
- const message = error instanceof Error ? error.message : "Unknown error";
345
- discoveryLogger.error("Flow discovery failed", { error: message });
346
-
347
- return {
348
- content: [
349
- {
350
- type: "text",
351
- text: `Error during flow discovery: ${message}`,
352
- },
353
- ],
354
- isError: true,
355
- };
356
- }
357
- },
358
- };
359
- }
360
-
361
- function generateFlowsMarkdown(
362
- discovery: FlowsDiscovery,
363
- feature: { name: string; slug: string; description: string }
364
- ): string {
365
- let md = `# User Flows: ${feature.name}
366
-
367
- ## Feature Overview
368
-
369
- **Slug**: \`${feature.slug}\`
370
-
371
- ${feature.description}
372
-
373
- ## Flows
374
-
375
- `;
376
-
377
- for (const flow of discovery.flows) {
378
- md += `### ${flow.name}
379
-
380
- **ID**: \`${flow.id}\`
381
- **Entry Point**: ${flow.entryPoint}
382
-
383
- ${flow.description}
384
-
385
- **Steps**:
386
- `;
387
- for (let i = 0; i < flow.steps.length; i++) {
388
- md += `${i + 1}. ${flow.steps[i]}\n`;
389
- }
390
- md += "\n---\n\n";
391
- }
392
-
393
- if (discovery.suggestedAssertions.length > 0) {
394
- md += `## Suggested Assertions
395
-
396
- `;
397
- for (const assertion of discovery.suggestedAssertions) {
398
- md += `- ${assertion}\n`;
399
- }
400
- md += "\n";
401
- }
402
-
403
- md += `---
404
- *Generated by testing-mcp*
405
- `;
406
-
407
- return md;
408
- }