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.
- package/README.md +59 -40
- package/dist/config.js +8 -8
- package/dist/config.js.map +1 -1
- package/dist/logger.js +1 -1
- package/dist/logger.js.map +1 -1
- package/dist/prompts/index.d.ts +1 -1
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +21 -21
- package/dist/prompts/index.js.map +1 -1
- package/dist/prompts/templates/mcp/retest-crawl.md +7 -0
- package/{src/prompts/templates/mcp/webtest-discover-flows.md → dist/prompts/templates/mcp/retest-discover-flows.md} +1 -1
- package/{src/prompts/templates/mcp/webtest-discover.md → dist/prompts/templates/mcp/retest-discover.md} +2 -2
- package/dist/prompts/templates/mcp/retest-full-workflow.md +12 -0
- package/{src/prompts/templates/mcp/webtest-generate-tests.md → dist/prompts/templates/mcp/retest-generate-tests.md} +1 -1
- package/{src/prompts/templates/mcp/webtest-run-test.md → dist/prompts/templates/mcp/retest-run-test.md} +1 -1
- package/{src/prompts/templates/mcp/webtest-start.md → dist/prompts/templates/mcp/retest-start.md} +1 -1
- package/{src → dist}/prompts/templates/sampling/system-prefix.md +1 -1
- package/dist/resources/index.js +7 -7
- package/dist/resources/index.js.map +1 -1
- package/dist/schemas/config.js +2 -2
- package/dist/schemas/config.js.map +1 -1
- package/dist/security/index.js +1 -1
- package/dist/security/index.js.map +1 -1
- package/dist/server.js +3 -3
- package/dist/server.js.map +1 -1
- package/dist/test-utils/mock-context.js +22 -22
- package/dist/test-utils/mock-context.js.map +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +5 -5
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/retest/crawl.d.ts.map +1 -0
- package/dist/tools/{webtest → retest}/crawl.js +7 -7
- package/dist/tools/retest/crawl.js.map +1 -0
- package/dist/tools/retest/discover-features.d.ts.map +1 -0
- package/dist/tools/{webtest → retest}/discover-features.js +6 -6
- package/dist/tools/retest/discover-features.js.map +1 -0
- package/dist/tools/retest/discover-flows.d.ts.map +1 -0
- package/dist/tools/{webtest → retest}/discover-flows.js +6 -6
- package/dist/tools/retest/discover-flows.js.map +1 -0
- package/dist/tools/retest/generate-tests.d.ts.map +1 -0
- package/dist/tools/{webtest → retest}/generate-tests.js +5 -5
- package/dist/tools/retest/generate-tests.js.map +1 -0
- package/dist/tools/retest/index.d.ts.map +1 -0
- package/dist/tools/retest/index.js.map +1 -0
- package/dist/tools/retest/run-test-case.d.ts.map +1 -0
- package/dist/tools/{webtest → retest}/run-test-case.js +3 -3
- package/dist/tools/retest/run-test-case.js.map +1 -0
- package/dist/tools/retest/schemas.d.ts.map +1 -0
- package/dist/tools/retest/schemas.js.map +1 -0
- package/dist/tools/retest/start-analysis.d.ts.map +1 -0
- package/dist/tools/{webtest → retest}/start-analysis.js +5 -5
- package/dist/tools/retest/start-analysis.js.map +1 -0
- package/dist/workspace/index.js +8 -8
- package/dist/workspace/index.js.map +1 -1
- package/dist/workspace/types.d.ts +2 -2
- package/dist/workspace/types.d.ts.map +1 -1
- package/package.json +6 -2
- package/.claude/commands/openspec/apply.md +0 -23
- package/.claude/commands/openspec/archive.md +0 -27
- package/.claude/commands/openspec/proposal.md +0 -28
- package/.gemini/commands/openspec/apply.toml +0 -21
- package/.gemini/commands/openspec/archive.toml +0 -25
- package/.gemini/commands/openspec/proposal.toml +0 -26
- package/.github/prompts/openspec-apply.prompt.md +0 -22
- package/.github/prompts/openspec-archive.prompt.md +0 -26
- package/.github/prompts/openspec-proposal.prompt.md +0 -27
- package/.github/workflows/release.yml +0 -33
- package/.kilocode/workflows/openspec-apply.md +0 -17
- package/.kilocode/workflows/openspec-archive.md +0 -21
- package/.kilocode/workflows/openspec-proposal.md +0 -22
- package/.mcp.json +0 -23
- package/.opencode/command/openspec-apply.md +0 -25
- package/.opencode/command/openspec-archive.md +0 -28
- package/.opencode/command/openspec-proposal.md +0 -30
- package/.roo/commands/openspec-apply.md +0 -20
- package/.roo/commands/openspec-archive.md +0 -24
- package/.roo/commands/openspec-proposal.md +0 -25
- package/.vscode/mcp.json +0 -23
- package/AGENTS.md +0 -18
- package/CLAUDE.md +0 -18
- package/dist/tools/webtest/crawl.d.ts.map +0 -1
- package/dist/tools/webtest/crawl.js.map +0 -1
- package/dist/tools/webtest/discover-features.d.ts.map +0 -1
- package/dist/tools/webtest/discover-features.js.map +0 -1
- package/dist/tools/webtest/discover-flows.d.ts.map +0 -1
- package/dist/tools/webtest/discover-flows.js.map +0 -1
- package/dist/tools/webtest/generate-tests.d.ts.map +0 -1
- package/dist/tools/webtest/generate-tests.js.map +0 -1
- package/dist/tools/webtest/index.d.ts.map +0 -1
- package/dist/tools/webtest/index.js.map +0 -1
- package/dist/tools/webtest/run-test-case.d.ts.map +0 -1
- package/dist/tools/webtest/run-test-case.js.map +0 -1
- package/dist/tools/webtest/schemas.d.ts.map +0 -1
- package/dist/tools/webtest/schemas.js.map +0 -1
- package/dist/tools/webtest/start-analysis.d.ts.map +0 -1
- package/dist/tools/webtest/start-analysis.js.map +0 -1
- package/openspec/AGENTS.md +0 -456
- package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/proposal.md +0 -33
- package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/specs/webtest-resources/spec.md +0 -27
- package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/specs/webtest-tools/spec.md +0 -304
- package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/tasks.md +0 -43
- package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/design.md +0 -209
- package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/proposal.md +0 -41
- package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/specs/mcp-server-core/spec.md +0 -183
- package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/tasks.md +0 -112
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/design.md +0 -333
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/proposal.md +0 -66
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/mcp-server-core/spec.md +0 -129
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-lifecycle/spec.md +0 -138
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-logging/spec.md +0 -211
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-prompts/spec.md +0 -157
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-resources/spec.md +0 -213
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-sampling/spec.md +0 -257
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-tools/spec.md +0 -501
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/tasks.md +0 -264
- package/openspec/changes/archive/2025-12-18-allow-analysis-of-incomplete-crawls/proposal.md +0 -24
- package/openspec/changes/archive/2025-12-18-allow-analysis-of-incomplete-crawls/specs/webtest-tools/spec.md +0 -80
- package/openspec/changes/archive/2025-12-18-allow-analysis-of-incomplete-crawls/tasks.md +0 -8
- package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/design.md +0 -90
- package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/proposal.md +0 -28
- package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/specs/webtest-sampling/spec.md +0 -90
- package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/tasks.md +0 -33
- package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/design.md +0 -558
- package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/proposal.md +0 -119
- package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/specs/webtest-resources/spec.md +0 -109
- package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/specs/webtest-tools/spec.md +0 -121
- package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/tasks.md +0 -133
- package/openspec/changes/extract-prompts-to-markdown/design.md +0 -86
- package/openspec/changes/extract-prompts-to-markdown/proposal.md +0 -50
- package/openspec/changes/extract-prompts-to-markdown/specs/webtest-prompts/spec.md +0 -74
- package/openspec/changes/extract-prompts-to-markdown/tasks.md +0 -40
- package/openspec/changes/refactor-webtest-naming/design.md +0 -95
- package/openspec/changes/refactor-webtest-naming/proposal.md +0 -66
- package/openspec/changes/refactor-webtest-naming/specs/webtest-prompts/spec.md +0 -79
- package/openspec/changes/refactor-webtest-naming/specs/webtest-resources/spec.md +0 -80
- package/openspec/changes/refactor-webtest-naming/specs/webtest-sampling/spec.md +0 -122
- package/openspec/changes/refactor-webtest-naming/specs/webtest-tools/spec.md +0 -113
- package/openspec/changes/refactor-webtest-naming/tasks.md +0 -119
- package/openspec/changes/rename-package-to-retest/proposal.md +0 -52
- package/openspec/changes/rename-package-to-retest/specs/mcp-server-core/spec.md +0 -53
- package/openspec/changes/rename-package-to-retest/specs/retest-lifecycle/spec.md +0 -68
- package/openspec/changes/rename-package-to-retest/specs/retest-logging/spec.md +0 -35
- package/openspec/changes/rename-package-to-retest/specs/retest-prompts/spec.md +0 -159
- package/openspec/changes/rename-package-to-retest/specs/retest-resources/spec.md +0 -251
- package/openspec/changes/rename-package-to-retest/specs/retest-sampling/spec.md +0 -99
- package/openspec/changes/rename-package-to-retest/specs/retest-tools/spec.md +0 -295
- package/openspec/changes/rename-package-to-retest/tasks.md +0 -71
- package/openspec/project.md +0 -31
- package/openspec/specs/mcp-server-core/spec.md +0 -178
- package/openspec/specs/webtest-lifecycle/spec.md +0 -136
- package/openspec/specs/webtest-logging/spec.md +0 -209
- package/openspec/specs/webtest-prompts/spec.md +0 -155
- package/openspec/specs/webtest-resources/spec.md +0 -248
- package/openspec/specs/webtest-sampling/spec.md +0 -344
- package/openspec/specs/webtest-tools/spec.md +0 -282
- package/release.config.js +0 -9
- package/src/config.test.ts +0 -96
- package/src/config.ts +0 -32
- package/src/elicitation/index.test.ts +0 -399
- package/src/elicitation/index.ts +0 -171
- package/src/elicitation/types.ts +0 -68
- package/src/index.ts +0 -83
- package/src/lifecycle/index.test.ts +0 -260
- package/src/lifecycle/index.ts +0 -101
- package/src/logger.redaction.test.ts +0 -322
- package/src/logger.test.ts +0 -123
- package/src/logger.ts +0 -229
- package/src/playwright-client/index.ts +0 -392
- package/src/playwright-client/types.ts +0 -99
- package/src/progress/index.test.ts +0 -327
- package/src/progress/index.ts +0 -170
- package/src/progress/types.ts +0 -25
- package/src/prompts/index.test.ts +0 -451
- package/src/prompts/index.ts +0 -246
- package/src/prompts/loader.test.ts +0 -100
- package/src/prompts/loader.ts +0 -59
- package/src/prompts/templates/mcp/webtest-crawl.md +0 -7
- package/src/prompts/templates/mcp/webtest-full-workflow.md +0 -12
- package/src/resources/index.ts +0 -250
- package/src/resources/subscriptions.ts +0 -37
- package/src/sampling/index.test.ts +0 -414
- package/src/sampling/index.ts +0 -286
- package/src/sampling/prompts.ts +0 -194
- package/src/sampling/types.ts +0 -60
- package/src/schemas/config.ts +0 -39
- package/src/security/index.test.ts +0 -441
- package/src/security/index.ts +0 -361
- package/src/security/security-scenarios.test.ts +0 -468
- package/src/server.ts +0 -211
- package/src/test-utils/index.ts +0 -6
- package/src/test-utils/mock-context.ts +0 -426
- package/src/test-utils/mock-playwright-client.ts +0 -422
- package/src/tools/index.ts +0 -11
- package/src/tools/webtest/crawl.test.ts +0 -834
- package/src/tools/webtest/crawl.ts +0 -901
- package/src/tools/webtest/discover-features.ts +0 -412
- package/src/tools/webtest/discover-flows.ts +0 -408
- package/src/tools/webtest/generate-tests.test.ts +0 -532
- package/src/tools/webtest/generate-tests.ts +0 -425
- package/src/tools/webtest/index.ts +0 -7
- package/src/tools/webtest/integration.test.ts +0 -536
- package/src/tools/webtest/run-test-case.test.ts +0 -659
- package/src/tools/webtest/run-test-case.ts +0 -508
- package/src/tools/webtest/schemas.ts +0 -201
- package/src/tools/webtest/start-analysis.test.ts +0 -151
- package/src/tools/webtest/start-analysis.ts +0 -158
- package/src/transports/http.ts +0 -19
- package/src/transports/index.ts +0 -30
- package/src/transports/stdio.ts +0 -7
- package/src/types/capabilities.test.ts +0 -193
- package/src/types/capabilities.ts +0 -50
- package/src/types/context.ts +0 -21
- package/src/types/tool.ts +0 -11
- package/src/workspace/index.ts +0 -945
- package/src/workspace/markdown.ts +0 -272
- package/src/workspace/types.ts +0 -186
- package/tests/integration/server.test.ts +0 -89
- package/tests/integration/tools.test.ts +0 -99
- package/tsconfig.json +0 -20
- package/vitest.config.ts +0 -9
- package/vitest.integration.config.ts +0 -10
- /package/{src → dist}/prompts/templates/sampling/crawl-action.md +0 -0
- /package/{src → dist}/prompts/templates/sampling/feature-discovery.md +0 -0
- /package/{src → dist}/prompts/templates/sampling/flow-discovery.md +0 -0
- /package/{src → dist}/prompts/templates/sampling/page-content-wrapper.md +0 -0
- /package/{src → dist}/prompts/templates/sampling/test-evaluation.md +0 -0
- /package/{src → dist}/prompts/templates/sampling/test-generation.md +0 -0
- /package/dist/tools/{webtest → retest}/crawl.d.ts +0 -0
- /package/dist/tools/{webtest → retest}/discover-features.d.ts +0 -0
- /package/dist/tools/{webtest → retest}/discover-flows.d.ts +0 -0
- /package/dist/tools/{webtest → retest}/generate-tests.d.ts +0 -0
- /package/dist/tools/{webtest → retest}/index.d.ts +0 -0
- /package/dist/tools/{webtest → retest}/index.js +0 -0
- /package/dist/tools/{webtest → retest}/run-test-case.d.ts +0 -0
- /package/dist/tools/{webtest → retest}/schemas.d.ts +0 -0
- /package/dist/tools/{webtest → retest}/schemas.js +0 -0
- /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
|
-
});
|
package/src/elicitation/index.ts
DELETED
|
@@ -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
|
-
}
|
package/src/elicitation/types.ts
DELETED
|
@@ -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
|
-
];
|