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,399 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from "vitest";
2
- import { createElicitationClient, ElicitationType } from "./index.js";
3
- import type { Logger } from "../logger.js";
4
- import type { ClientCapabilities } from "../types/capabilities.js";
5
- import type { ElicitationRequest, ElicitationResponse } from "./types.js";
6
-
7
- describe("elicitation", () => {
8
- let mockLogger: Logger;
9
-
10
- beforeEach(() => {
11
- mockLogger = {
12
- debug: vi.fn(),
13
- info: vi.fn(),
14
- warn: vi.fn(),
15
- error: vi.fn(),
16
- setLevel: vi.fn(),
17
- withCorrelation: vi.fn().mockReturnThis(),
18
- } as unknown as Logger;
19
- });
20
-
21
- const capabilitiesWithElicitation: ClientCapabilities = {
22
- sampling: true,
23
- elicitation: true,
24
- logging: false,
25
- progress: true,
26
- resourcesListChanged: false,
27
- resourcesSubscribe: false,
28
- protocolVersion: "2025-06-18",
29
- };
30
-
31
- const capabilitiesWithoutElicitation: ClientCapabilities = {
32
- sampling: true,
33
- elicitation: false,
34
- logging: false,
35
- progress: true,
36
- resourcesListChanged: false,
37
- resourcesSubscribe: false,
38
- protocolVersion: "2025-06-18",
39
- };
40
-
41
- describe("createElicitationClient", () => {
42
- it("reports elicitation availability correctly", () => {
43
- const clientWith = createElicitationClient(
44
- vi.fn(),
45
- capabilitiesWithElicitation,
46
- mockLogger
47
- );
48
-
49
- const clientWithout = createElicitationClient(
50
- vi.fn(),
51
- capabilitiesWithoutElicitation,
52
- mockLogger
53
- );
54
-
55
- expect(clientWith.hasElicitation()).toBe(true);
56
- expect(clientWithout.hasElicitation()).toBe(false);
57
- });
58
- });
59
-
60
- describe("elicit", () => {
61
- it("returns fallback when elicitation unavailable", async () => {
62
- const requestElicitation = vi.fn();
63
- const client = createElicitationClient(
64
- requestElicitation,
65
- capabilitiesWithoutElicitation,
66
- mockLogger
67
- );
68
-
69
- const request: ElicitationRequest = {
70
- type: ElicitationType.CookieConsent,
71
- title: "Cookie Banner",
72
- message: "A cookie banner was detected",
73
- options: [{ value: "accept", label: "Accept all" }],
74
- };
75
-
76
- const result = await client.elicit(request);
77
-
78
- expect(result.success).toBe(false);
79
- expect(result.error).toBe("Elicitation not available");
80
- expect(result.fallbackQuestions).toBeDefined();
81
- expect(requestElicitation).not.toHaveBeenCalled();
82
- });
83
-
84
- it("blocks credential elicitation requests", async () => {
85
- const requestElicitation = vi.fn();
86
- const client = createElicitationClient(
87
- requestElicitation,
88
- capabilitiesWithElicitation,
89
- mockLogger
90
- );
91
-
92
- const request: ElicitationRequest = {
93
- type: ElicitationType.AuthRequired,
94
- title: "Auth Required",
95
- message: "Please authenticate",
96
- options: [
97
- { value: "enter_password", label: "Enter your password" },
98
- { value: "skip", label: "Skip" },
99
- ],
100
- };
101
-
102
- const result = await client.elicit(request);
103
-
104
- expect(result.success).toBe(false);
105
- expect(result.error).toBe("Security policy prevents credential elicitation");
106
- expect(requestElicitation).not.toHaveBeenCalled();
107
- expect(mockLogger.error).toHaveBeenCalledWith(
108
- "Attempted to elicit credentials - blocked",
109
- expect.any(Object)
110
- );
111
- });
112
-
113
- it("handles user cancel action", async () => {
114
- const mockResponse: ElicitationResponse = {
115
- action: "cancel",
116
- };
117
-
118
- const requestElicitation = vi.fn().mockResolvedValue(mockResponse);
119
- const client = createElicitationClient(
120
- requestElicitation,
121
- capabilitiesWithElicitation,
122
- mockLogger
123
- );
124
-
125
- const request: ElicitationRequest = {
126
- type: ElicitationType.CookieConsent,
127
- title: "Cookie Banner",
128
- message: "A cookie banner was detected",
129
- options: [{ value: "accept", label: "Accept all" }],
130
- };
131
-
132
- const result = await client.elicit(request);
133
-
134
- expect(result.success).toBe(true);
135
- expect(result.cancelled).toBe(true);
136
- });
137
-
138
- it("handles user dismiss action", async () => {
139
- const mockResponse: ElicitationResponse = {
140
- action: "dismiss",
141
- };
142
-
143
- const requestElicitation = vi.fn().mockResolvedValue(mockResponse);
144
- const client = createElicitationClient(
145
- requestElicitation,
146
- capabilitiesWithElicitation,
147
- mockLogger
148
- );
149
-
150
- const request: ElicitationRequest = {
151
- type: ElicitationType.ModalBlocking,
152
- title: "Modal",
153
- message: "A modal is blocking",
154
- options: [{ value: "close", label: "Close" }],
155
- };
156
-
157
- const result = await client.elicit(request);
158
-
159
- expect(result.success).toBe(true);
160
- expect(result.selectedValue).toBe("dismiss");
161
- });
162
-
163
- it("extracts selected value from response", async () => {
164
- const mockResponse: ElicitationResponse = {
165
- action: "submit",
166
- content: { selected: "accept_all" },
167
- };
168
-
169
- const requestElicitation = vi.fn().mockResolvedValue(mockResponse);
170
- const client = createElicitationClient(
171
- requestElicitation,
172
- capabilitiesWithElicitation,
173
- mockLogger
174
- );
175
-
176
- const request: ElicitationRequest = {
177
- type: ElicitationType.CookieConsent,
178
- title: "Cookie Banner",
179
- message: "A cookie banner was detected",
180
- options: [{ value: "accept_all", label: "Accept all" }],
181
- };
182
-
183
- const result = await client.elicit(request);
184
-
185
- expect(result.success).toBe(true);
186
- expect(result.selectedValue).toBe("accept_all");
187
- });
188
-
189
- it("extracts custom value from response", async () => {
190
- const mockResponse: ElicitationResponse = {
191
- action: "submit",
192
- content: { custom: "/custom/path" },
193
- };
194
-
195
- const requestElicitation = vi.fn().mockResolvedValue(mockResponse);
196
- const client = createElicitationClient(
197
- requestElicitation,
198
- capabilitiesWithElicitation,
199
- mockLogger
200
- );
201
-
202
- const request: ElicitationRequest = {
203
- type: ElicitationType.AmbiguousNavigation,
204
- title: "Multiple options",
205
- message: "Which path?",
206
- options: [],
207
- allowCustom: true,
208
- };
209
-
210
- const result = await client.elicit(request);
211
-
212
- expect(result.success).toBe(true);
213
- expect(result.customValue).toBe("/custom/path");
214
- });
215
-
216
- it("handles request errors gracefully", async () => {
217
- const requestElicitation = vi
218
- .fn()
219
- .mockRejectedValue(new Error("Connection failed"));
220
-
221
- const client = createElicitationClient(
222
- requestElicitation,
223
- capabilitiesWithElicitation,
224
- mockLogger
225
- );
226
-
227
- const request: ElicitationRequest = {
228
- type: ElicitationType.CookieConsent,
229
- title: "Cookie Banner",
230
- message: "A cookie banner was detected",
231
- options: [{ value: "accept", label: "Accept" }],
232
- };
233
-
234
- const result = await client.elicit(request);
235
-
236
- expect(result.success).toBe(false);
237
- expect(result.error).toBe("Connection failed");
238
- expect(result.fallbackQuestions).toBeDefined();
239
- });
240
- });
241
-
242
- describe("createCookieConsentRequest", () => {
243
- it("creates properly structured request", () => {
244
- const client = createElicitationClient(
245
- vi.fn(),
246
- capabilitiesWithElicitation,
247
- mockLogger
248
- );
249
-
250
- const request = client.createCookieConsentRequest(
251
- "GDPR banner with accept/reject buttons"
252
- );
253
-
254
- expect(request.type).toBe(ElicitationType.CookieConsent);
255
- expect(request.title).toBe("Cookie Consent Banner Detected");
256
- expect(request.message).toContain("GDPR banner");
257
- expect(request.options.length).toBeGreaterThan(0);
258
- });
259
- });
260
-
261
- describe("createModalBlockingRequest", () => {
262
- it("creates properly structured request", () => {
263
- const client = createElicitationClient(
264
- vi.fn(),
265
- capabilitiesWithElicitation,
266
- mockLogger
267
- );
268
-
269
- const request = client.createModalBlockingRequest(
270
- "Sign up for our newsletter to get 10% off!"
271
- );
272
-
273
- expect(request.type).toBe(ElicitationType.ModalBlocking);
274
- expect(request.title).toBe("Modal Dialog Blocking Page");
275
- expect(request.message).toContain("Sign up");
276
- expect(request.options.length).toBeGreaterThan(0);
277
- });
278
-
279
- it("truncates long modal content", () => {
280
- const client = createElicitationClient(
281
- vi.fn(),
282
- capabilitiesWithElicitation,
283
- mockLogger
284
- );
285
-
286
- const longContent = "A".repeat(500);
287
- const request = client.createModalBlockingRequest(longContent);
288
-
289
- expect(request.message.length).toBeLessThan(500);
290
- expect(request.message).toContain("...");
291
- });
292
- });
293
-
294
- describe("createAmbiguousNavigationRequest", () => {
295
- it("creates properly structured request", () => {
296
- const client = createElicitationClient(
297
- vi.fn(),
298
- capabilitiesWithElicitation,
299
- mockLogger
300
- );
301
-
302
- const options = [
303
- { url: "/products", label: "Products" },
304
- { url: "/services", label: "Services" },
305
- { url: "/about", label: "About Us" },
306
- ];
307
-
308
- const request = client.createAmbiguousNavigationRequest(options);
309
-
310
- expect(request.type).toBe(ElicitationType.AmbiguousNavigation);
311
- expect(request.title).toBe("Multiple Navigation Options");
312
- expect(request.options.length).toBe(3);
313
- expect(request.options[0].value).toBe("/products");
314
- expect(request.options[0].label).toBe("Products");
315
- expect(request.allowCustom).toBe(true);
316
- });
317
-
318
- it("limits options to 5 maximum", () => {
319
- const client = createElicitationClient(
320
- vi.fn(),
321
- capabilitiesWithElicitation,
322
- mockLogger
323
- );
324
-
325
- const options = Array.from({ length: 10 }, (_, i) => ({
326
- url: `/path${i}`,
327
- label: `Option ${i}`,
328
- }));
329
-
330
- const request = client.createAmbiguousNavigationRequest(options);
331
-
332
- expect(request.options.length).toBe(5);
333
- });
334
-
335
- it("uses default labels when not provided", () => {
336
- const client = createElicitationClient(
337
- vi.fn(),
338
- capabilitiesWithElicitation,
339
- mockLogger
340
- );
341
-
342
- const options = [
343
- { url: "/path1", label: "" },
344
- { url: "/path2", label: "" },
345
- ];
346
-
347
- const request = client.createAmbiguousNavigationRequest(options);
348
-
349
- expect(request.options[0].label).toBe("Option 1");
350
- expect(request.options[1].label).toBe("Option 2");
351
- });
352
- });
353
-
354
- describe("createAuthRequiredRequest", () => {
355
- it("creates properly structured request", () => {
356
- const client = createElicitationClient(
357
- vi.fn(),
358
- capabilitiesWithElicitation,
359
- mockLogger
360
- );
361
-
362
- const request = client.createAuthRequiredRequest();
363
-
364
- expect(request.type).toBe(ElicitationType.AuthRequired);
365
- expect(request.title).toBe("Authentication Required");
366
- expect(request.message).toContain("security reasons");
367
- expect(request.message).toContain("cannot handle login automatically");
368
- expect(request.options.length).toBeGreaterThan(0);
369
- });
370
-
371
- it("does not include credential entry options", () => {
372
- const client = createElicitationClient(
373
- vi.fn(),
374
- capabilitiesWithElicitation,
375
- mockLogger
376
- );
377
-
378
- const request = client.createAuthRequiredRequest();
379
-
380
- const hasCredentialOption = request.options.some(
381
- (opt) =>
382
- opt.value.includes("password") ||
383
- opt.value.includes("credential") ||
384
- opt.value.includes("login")
385
- );
386
-
387
- expect(hasCredentialOption).toBe(false);
388
- });
389
- });
390
-
391
- describe("ElicitationType enum", () => {
392
- it("has expected values", () => {
393
- expect(ElicitationType.CookieConsent).toBe("cookie_consent");
394
- expect(ElicitationType.ModalBlocking).toBe("modal_blocking");
395
- expect(ElicitationType.AmbiguousNavigation).toBe("ambiguous_navigation");
396
- expect(ElicitationType.AuthRequired).toBe("auth_required");
397
- });
398
- });
399
- });
@@ -1,171 +0,0 @@
1
- import type { Logger } from "../logger.js";
2
- import type { ClientCapabilities } from "../types/capabilities.js";
3
- import { isElicitationSupported } from "../types/capabilities.js";
4
- import {
5
- type ElicitationRequest,
6
- type ElicitationResponse,
7
- type ElicitationResult,
8
- ElicitationType,
9
- COOKIE_CONSENT_OPTIONS,
10
- MODAL_BLOCKING_OPTIONS,
11
- AUTH_REQUIRED_OPTIONS,
12
- } from "./types.js";
13
-
14
- export * from "./types.js";
15
-
16
- export interface ElicitationClient {
17
- elicit(request: ElicitationRequest): Promise<ElicitationResult>;
18
- hasElicitation(): boolean;
19
- createCookieConsentRequest(context: string): ElicitationRequest;
20
- createModalBlockingRequest(modalContent: string): ElicitationRequest;
21
- createAmbiguousNavigationRequest(
22
- options: Array<{ url: string; label: string }>
23
- ): ElicitationRequest;
24
- createAuthRequiredRequest(): ElicitationRequest;
25
- }
26
-
27
- export function createElicitationClient(
28
- requestElicitation: (
29
- request: ElicitationRequest
30
- ) => Promise<ElicitationResponse>,
31
- capabilities: ClientCapabilities,
32
- logger: Logger
33
- ): ElicitationClient {
34
- const hasElicitationCapability = isElicitationSupported(capabilities);
35
-
36
- async function elicit(
37
- request: ElicitationRequest
38
- ): Promise<ElicitationResult> {
39
- // Validate that we never request credentials
40
- if (request.type === ElicitationType.AuthRequired) {
41
- // Ensure options don't include credential entry
42
- const hasCredentialOption = request.options.some(
43
- (opt) =>
44
- opt.value.includes("password") ||
45
- opt.value.includes("credential") ||
46
- opt.value.includes("login")
47
- );
48
-
49
- if (hasCredentialOption) {
50
- logger.error("Attempted to elicit credentials - blocked", {
51
- type: request.type,
52
- });
53
- return {
54
- success: false,
55
- error: "Security policy prevents credential elicitation",
56
- };
57
- }
58
- }
59
-
60
- // If elicitation not available, return fallback
61
- if (!hasElicitationCapability) {
62
- logger.info("Elicitation unavailable, returning fallback questions");
63
-
64
- return {
65
- success: false,
66
- error: "Elicitation not available",
67
- fallbackQuestions: request,
68
- };
69
- }
70
-
71
- logger.debug("Sending elicitation request", {
72
- type: request.type,
73
- title: request.title,
74
- optionCount: request.options.length,
75
- });
76
-
77
- try {
78
- const response = await requestElicitation(request);
79
-
80
- if (response.action === "cancel") {
81
- logger.info("User cancelled elicitation", { type: request.type });
82
- return {
83
- success: true,
84
- cancelled: true,
85
- };
86
- }
87
-
88
- if (response.action === "dismiss") {
89
- logger.info("User dismissed elicitation", { type: request.type });
90
- return {
91
- success: true,
92
- selectedValue: "dismiss",
93
- };
94
- }
95
-
96
- // Extract selected value from content
97
- const selectedValue = response.content?.selected || response.content?.value;
98
-
99
- logger.info("Elicitation response received", {
100
- type: request.type,
101
- action: response.action,
102
- selectedValue,
103
- });
104
-
105
- return {
106
- success: true,
107
- selectedValue,
108
- customValue: response.content?.custom,
109
- };
110
- } catch (error) {
111
- const message = error instanceof Error ? error.message : "Unknown error";
112
- logger.error("Elicitation request failed", { error: message });
113
-
114
- return {
115
- success: false,
116
- error: message,
117
- fallbackQuestions: request,
118
- };
119
- }
120
- }
121
-
122
- return {
123
- elicit,
124
- hasElicitation: () => hasElicitationCapability,
125
-
126
- createCookieConsentRequest(context: string): ElicitationRequest {
127
- return {
128
- type: ElicitationType.CookieConsent,
129
- title: "Cookie Consent Banner Detected",
130
- message: `A cookie consent banner was detected on the page. How should we handle it?\n\nContext: ${context}`,
131
- options: COOKIE_CONSENT_OPTIONS,
132
- };
133
- },
134
-
135
- createModalBlockingRequest(modalContent: string): ElicitationRequest {
136
- return {
137
- type: ElicitationType.ModalBlocking,
138
- title: "Modal Dialog Blocking Page",
139
- message: `A modal dialog is blocking page interaction.\n\nModal content: ${modalContent.slice(0, 200)}...`,
140
- options: MODAL_BLOCKING_OPTIONS,
141
- };
142
- },
143
-
144
- createAmbiguousNavigationRequest(
145
- options: Array<{ url: string; label: string }>
146
- ): ElicitationRequest {
147
- return {
148
- type: ElicitationType.AmbiguousNavigation,
149
- title: "Multiple Navigation Options",
150
- message:
151
- "Multiple similar navigation options were found. Which path should we explore?",
152
- options: options.slice(0, 5).map((opt, i) => ({
153
- value: opt.url,
154
- label: opt.label || `Option ${i + 1}`,
155
- description: opt.url,
156
- })),
157
- allowCustom: true,
158
- };
159
- },
160
-
161
- createAuthRequiredRequest(): ElicitationRequest {
162
- return {
163
- type: ElicitationType.AuthRequired,
164
- title: "Authentication Required",
165
- message:
166
- "This page requires authentication. For security reasons, we cannot handle login automatically. How would you like to proceed?",
167
- options: AUTH_REQUIRED_OPTIONS,
168
- };
169
- },
170
- };
171
- }
@@ -1,68 +0,0 @@
1
- export enum ElicitationType {
2
- CookieConsent = "cookie_consent",
3
- ModalBlocking = "modal_blocking",
4
- AmbiguousNavigation = "ambiguous_navigation",
5
- AuthRequired = "auth_required",
6
- ConfirmAction = "confirm_action",
7
- }
8
-
9
- export interface ElicitationOption {
10
- value: string;
11
- label: string;
12
- description?: string;
13
- }
14
-
15
- export interface ElicitationRequest {
16
- type: ElicitationType;
17
- title: string;
18
- message: string;
19
- options: ElicitationOption[];
20
- allowCustom?: boolean;
21
- }
22
-
23
- export interface ElicitationResponse {
24
- action: "confirm" | "dismiss" | "cancel";
25
- content?: Record<string, string>;
26
- }
27
-
28
- export interface ElicitationResult {
29
- success: boolean;
30
- selectedValue?: string;
31
- customValue?: string;
32
- cancelled?: boolean;
33
- error?: string;
34
- fallbackQuestions?: ElicitationRequest;
35
- }
36
-
37
- // Predefined option sets for common scenarios
38
- export const COOKIE_CONSENT_OPTIONS: ElicitationOption[] = [
39
- { value: "accept", label: "Accept All", description: "Accept all cookies" },
40
- {
41
- value: "reject",
42
- label: "Reject All",
43
- description: "Reject non-essential cookies",
44
- },
45
- {
46
- value: "dismiss",
47
- label: "Dismiss",
48
- description: "Close the banner without choosing",
49
- },
50
- ];
51
-
52
- export const MODAL_BLOCKING_OPTIONS: ElicitationOption[] = [
53
- { value: "close", label: "Close Modal", description: "Close and continue" },
54
- {
55
- value: "interact",
56
- label: "Interact",
57
- description: "Interact with modal content",
58
- },
59
- ];
60
-
61
- export const AUTH_REQUIRED_OPTIONS: ElicitationOption[] = [
62
- { value: "stop", label: "Stop Analysis", description: "End the analysis" },
63
- {
64
- value: "continue",
65
- label: "Continue Unauthenticated",
66
- description: "Continue without logging in",
67
- },
68
- ];