@skyramp/mcp 0.3.5 → 0.3.6-rc.1

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 (157) hide show
  1. package/build/playwright/registerPlaywrightTools.js +92 -30
  2. package/build/playwright/traceRecordingPrompt.d.ts +6 -0
  3. package/build/playwright/traceRecordingPrompt.js +6 -2
  4. package/build/prompts/code-reuse.d.ts +1 -2
  5. package/build/prompts/code-reuse.js +182 -77
  6. package/build/prompts/modularization/integration-test-modularization.d.ts +2 -0
  7. package/build/prompts/modularization/integration-test-modularization.js +83 -41
  8. package/build/prompts/modularization/render.d.ts +18 -0
  9. package/build/prompts/modularization/render.js +12 -0
  10. package/build/prompts/modularization/ui-test-modularization.d.ts +3 -1
  11. package/build/prompts/modularization/ui-test-modularization.js +89 -47
  12. package/build/prompts/pom-aware-code-reuse.js +3 -1
  13. package/build/prompts/shared-helper-policy.d.ts +57 -0
  14. package/build/prompts/shared-helper-policy.js +135 -0
  15. package/build/prompts/test-recommendation/diffExecutionPlan.js +62 -56
  16. package/build/prompts/test-recommendation/fullRepoCatalog.js +19 -8
  17. package/build/prompts/test-recommendation/recommendationShared.d.ts +28 -6
  18. package/build/prompts/test-recommendation/recommendationShared.js +90 -16
  19. package/build/prompts/test-recommendation/registerRecommendTestsPrompt.js +22 -0
  20. package/build/prompts/test-recommendation/test-recommendation-prompt.d.ts +2 -2
  21. package/build/prompts/test-recommendation/test-recommendation-prompt.js +3 -3
  22. package/build/prompts/testbot/testbot-prompts.js +80 -34
  23. package/build/recommendation/budgeters/shared.js +105 -27
  24. package/build/recommendation/discriminators.js +13 -2
  25. package/build/recommendation/planRanker.d.ts +6 -6
  26. package/build/recommendation/planRanker.js +6 -61
  27. package/build/services/AnalyticsService.d.ts +7 -0
  28. package/build/services/AnalyticsService.js +7 -1
  29. package/build/services/ModularizationService.js +1 -3
  30. package/build/services/TestDiscoveryService.d.ts +0 -2
  31. package/build/services/TestDiscoveryService.js +2 -37
  32. package/build/services/TestGenerationService.d.ts +16 -0
  33. package/build/services/TestGenerationService.js +86 -10
  34. package/build/services/containerEnv.js +13 -12
  35. package/build/tools/code-refactor/codeReuseTool.js +279 -93
  36. package/build/tools/code-refactor/enhance-state.d.ts +49 -0
  37. package/build/tools/code-refactor/enhance-state.js +109 -0
  38. package/build/tools/code-refactor/enhanceAssertionsTool.js +34 -1
  39. package/build/tools/code-refactor/modularizationTool.js +9 -2
  40. package/build/tools/code-refactor/reuse-outcome.d.ts +23 -1
  41. package/build/tools/code-refactor/reuse-outcome.js +14 -4
  42. package/build/tools/code-refactor/reuse-state.d.ts +127 -5
  43. package/build/tools/code-refactor/reuse-state.js +628 -16
  44. package/build/tools/code-refactor/utils-verify-gates.d.ts +26 -0
  45. package/build/tools/code-refactor/utils-verify-gates.js +100 -0
  46. package/build/tools/code-refactor/verify-gates.d.ts +2 -1
  47. package/build/tools/code-refactor/verify-gates.js +90 -25
  48. package/build/tools/executeSkyrampTestTool.d.ts +19 -0
  49. package/build/tools/executeSkyrampTestTool.js +158 -8
  50. package/build/tools/generate-tests/generateBatchScenarioRestTool.js +2 -2
  51. package/build/tools/generate-tests/generateE2ERestTool.js +16 -0
  52. package/build/tools/generate-tests/generateUIRestTool.d.ts +1 -0
  53. package/build/tools/generate-tests/generateUIRestTool.js +22 -0
  54. package/build/tools/generate-tests/scenarioLint.d.ts +2 -0
  55. package/build/tools/generate-tests/scenarioLint.js +127 -19
  56. package/build/tools/generate-tests/trace-reuse-guard.d.ts +20 -0
  57. package/build/tools/generate-tests/trace-reuse-guard.js +93 -0
  58. package/build/tools/submitReportTool.d.ts +38 -38
  59. package/build/tools/submitReportTool.js +411 -114
  60. package/build/tools/test-management/analyzeChangesTool.d.ts +24 -1
  61. package/build/tools/test-management/analyzeChangesTool.js +71 -10
  62. package/build/tools/test-management/analyzeTestHealthTool.js +7 -7
  63. package/build/tools/test-management/registerTestPlanTool.d.ts +203 -0
  64. package/build/tools/test-management/registerTestPlanTool.js +70 -12
  65. package/build/types/Recommendation.d.ts +34 -5
  66. package/build/types/RepositoryAnalysis.d.ts +133 -114
  67. package/build/types/RepositoryAnalysis.js +1 -1
  68. package/build/types/ReuseOutcome.d.ts +102 -6
  69. package/build/types/ReuseOutcome.js +16 -2
  70. package/build/types/TestRecommendation.js +21 -3
  71. package/build/types/TestTypes.js +14 -8
  72. package/build/types/TestbotReport.d.ts +10 -1
  73. package/build/types/index.d.ts +2 -2
  74. package/build/types/index.js +1 -1
  75. package/build/utils/AnalysisStateManager.d.ts +57 -1
  76. package/build/utils/AnalysisStateManager.js +54 -5
  77. package/build/utils/branchDiff.d.ts +10 -0
  78. package/build/utils/branchDiff.js +28 -0
  79. package/build/utils/changedRoutes.d.ts +29 -0
  80. package/build/utils/changedRoutes.js +87 -0
  81. package/build/utils/featureFlags.d.ts +21 -0
  82. package/build/utils/featureFlags.js +23 -0
  83. package/build/utils/frontendIntegration.js +34 -4
  84. package/build/utils/importerHop.d.ts +2 -8
  85. package/build/utils/importerHop.js +15 -53
  86. package/build/utils/pathMatching.d.ts +38 -0
  87. package/build/utils/pathMatching.js +71 -0
  88. package/build/utils/pathSignatures.d.ts +22 -0
  89. package/build/utils/pathSignatures.js +57 -0
  90. package/build/utils/planMatchKeys.d.ts +16 -3
  91. package/build/utils/planMatchKeys.js +26 -10
  92. package/build/utils/pluralization.d.ts +10 -0
  93. package/build/utils/pluralization.js +18 -0
  94. package/build/utils/pom-catalog-parse.d.ts +52 -0
  95. package/build/utils/pom-catalog-parse.js +141 -0
  96. package/build/utils/pom-scope/selector-extractor.d.ts +12 -0
  97. package/build/utils/pom-scope/selector-extractor.js +34 -8
  98. package/build/utils/pom-verify/verify.d.ts +6 -5
  99. package/build/utils/pom-verify/verify.js +8 -6
  100. package/build/utils/reportVerification.d.ts +64 -4
  101. package/build/utils/reportVerification.js +228 -3
  102. package/build/utils/reuseRouting.d.ts +3 -0
  103. package/build/utils/reuseRouting.js +50 -0
  104. package/build/utils/routeParsers.d.ts +2 -0
  105. package/build/utils/routeParsers.js +65 -8
  106. package/build/utils/scenarioDrafting.d.ts +1 -1
  107. package/build/utils/scenarioDrafting.js +57 -45
  108. package/build/utils/subjectEndpoints.d.ts +19 -0
  109. package/build/utils/subjectEndpoints.js +98 -0
  110. package/build/utils/testFileClassification.d.ts +11 -0
  111. package/build/utils/testFileClassification.js +47 -0
  112. package/build/utils/uiPageEnumerator.d.ts +45 -19
  113. package/build/utils/uiPageEnumerator.js +95 -51
  114. package/build/utils/utils-verify/allow.d.ts +16 -0
  115. package/build/utils/utils-verify/allow.js +68 -0
  116. package/build/utils/utils-verify/call-sites.d.ts +34 -0
  117. package/build/utils/utils-verify/call-sites.js +154 -0
  118. package/build/utils/utils-verify/index.d.ts +7 -0
  119. package/build/utils/utils-verify/index.js +7 -0
  120. package/build/utils/utils-verify/language-spec.d.ts +91 -0
  121. package/build/utils/utils-verify/language-spec.js +210 -0
  122. package/build/utils/utils-verify/locate.d.ts +39 -0
  123. package/build/utils/utils-verify/locate.js +199 -0
  124. package/build/utils/utils-verify/parse.d.ts +34 -0
  125. package/build/utils/utils-verify/parse.js +177 -0
  126. package/build/utils/utils-verify/stage.d.ts +24 -0
  127. package/build/utils/utils-verify/stage.js +107 -0
  128. package/build/utils/utils-verify/verify.d.ts +63 -0
  129. package/build/utils/utils-verify/verify.js +168 -0
  130. package/build/utils/utils.d.ts +3 -1
  131. package/build/utils/utils.js +3 -1
  132. package/build/workspace/workspace.d.ts +32 -32
  133. package/node_modules/playwright/lib/mcp/skyramp/assertTool.js +9 -5
  134. package/node_modules/playwright/lib/mcp/skyramp/loadTraceTool.js +16 -0
  135. package/node_modules/playwright/lib/mcp/skyramp/skyRampImport.js +2 -0
  136. package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +115 -14
  137. package/node_modules/playwright/lib/mcp/test/skyRampExport.js +13 -1
  138. package/node_modules/playwright/node_modules/playwright-core/.DS_Store +0 -0
  139. package/node_modules/playwright/node_modules/playwright-core/lib/server/codegen/skyramp/jsonlReader.js +2 -0
  140. package/node_modules/playwright/node_modules/playwright-core/lib/vite/htmlReport/index.html +27 -253
  141. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/{codeMirrorModule-DtudTj_v.js → codeMirrorModule-DJMC4zNo.js} +1 -1
  142. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/index-BW82eAUI.js +196 -0
  143. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/index.html +1 -1
  144. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/{codeMirrorModule-FNMuBzX1.js → codeMirrorModule-CZfp96qZ.js} +1 -1
  145. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-gpLo02E0.js +809 -0
  146. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.Bq1r1URj.js +2 -0
  147. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.html +2 -2
  148. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.VEfqi1qN.js +5 -0
  149. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.html +2 -2
  150. package/node_modules/playwright/node_modules/playwright-core/package.json +1 -1
  151. package/node_modules/playwright/node_modules/playwright-core/src/server/codegen/skyramp/jsonlReader.ts +1 -1
  152. package/node_modules/playwright/package.json +1 -1
  153. package/package.json +2 -2
  154. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/index-BpDwp16L.js +0 -422
  155. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-Co9upU5h.js +0 -1035
  156. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.DXNIQ_dx.js +0 -2
  157. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.CIKB3XSv.js +0 -5
@@ -0,0 +1,168 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import { logger } from "../logger.js";
4
+ import { locateUtilsFiles } from "./locate.js";
5
+ import { parseUtilsFile } from "./parse.js";
6
+ import { findSiblingInlineCallSites, } from "./call-sites.js";
7
+ import { parseUtilsAllows } from "./allow.js";
8
+ import { helperFamilyFor, scenarioNameViolation, utilsSpecFor, utilsSpecForFile, } from "./language-spec.js";
9
+ /**
10
+ * Deterministic post-reuse check of the shared utils file(s) a spec depends on.
11
+ *
12
+ * Three invariants, each a class of drift measured in the SKYR-4196 Part B evals:
13
+ * - `duplicate-helper`: two helpers for one method+path (run 4 — `create_product`
14
+ * beside `create_list_reflect_product`); the shared file must hold one canonical
15
+ * helper per step, extended with defaulted parameters rather than duplicated.
16
+ * - `body-assertion`: any assertion other than a status-code comparison inside a
17
+ * helper (runs 5 and 11 — `assert total_amount == 16.0` in `update_order`); a
18
+ * body assertion carries one scenario's values into a function every scenario calls.
19
+ * - `scenario-name` (ADVISORY only): a helper named for its scenario rather than its step.
20
+ *
21
+ * Analyses the utils files' INTERNAL invariants — unlike the POM verifier, which
22
+ * checks a spec's cross-file references — so it reads the utils files, not the spec,
23
+ * except to count what the spec imports.
24
+ */
25
+ export async function verifyUtils(params) {
26
+ const spec = utilsSpecFor(params.language) ?? utilsSpecForFile(params.testFile);
27
+ const family = helperFamilyFor(params.testType);
28
+ const utilsFiles = spec
29
+ ? await locateUtilsFiles({
30
+ testFile: params.testFile,
31
+ language: spec.language,
32
+ cwd: params.cwd,
33
+ })
34
+ : [];
35
+ const result = {
36
+ ok: true,
37
+ utilsFiles,
38
+ helpers: 0,
39
+ imported: 0,
40
+ violations: [],
41
+ allowed: [],
42
+ advisories: [],
43
+ malformedAllows: [],
44
+ spec,
45
+ family,
46
+ inlineCallSites: [],
47
+ };
48
+ if (!spec || utilsFiles.length === 0)
49
+ return result;
50
+ let specContent = "";
51
+ try {
52
+ specContent = await fs.promises.readFile(params.testFile, "utf8");
53
+ }
54
+ catch {
55
+ /* the spec may be absent outside a run; import counting then reports 0 */
56
+ }
57
+ const allHelpers = [];
58
+ const importedNames = new Set();
59
+ // Route map spans every utils file: the reuse prompt allows the helpers to split
60
+ // across files, and the same method+path in two of them is still one duplicate.
61
+ const byRoute = new Map();
62
+ for (const file of utilsFiles) {
63
+ let content;
64
+ try {
65
+ content = await fs.promises.readFile(file, "utf8");
66
+ }
67
+ catch (err) {
68
+ if (err?.code === "ENOENT")
69
+ continue; // removed since locate
70
+ logger.warning("Could not read a located utils file", {
71
+ file,
72
+ error: String(err),
73
+ });
74
+ throw err; // the caller records a verify error, which fails OPEN — never a silent PASS
75
+ }
76
+ const helpers = parseUtilsFile(content, spec, (expr) => family.isAllowed(spec, expr));
77
+ allHelpers.push(...helpers);
78
+ const { allows, malformed } = parseUtilsAllows(content, spec);
79
+ result.helpers += helpers.length;
80
+ result.malformedAllows.push(...malformed.map((line) => ({ file, line })));
81
+ const stem = path.basename(file).replace(/\.[^.]+$/, "");
82
+ const defined = new Set(helpers.map((h) => h.name));
83
+ for (const n of spec.importedNames(specContent, stem))
84
+ if (defined.has(n))
85
+ importedNames.add(n);
86
+ // One marker documents ONE violation of that kind in that helper: a second,
87
+ // undocumented scenario claim in the same helper is not covered by the first
88
+ // decline. Markers are consumed in order.
89
+ const budget = new Map();
90
+ for (const a of allows) {
91
+ const k = `${a.kind}\0${a.helper}`;
92
+ budget.set(k, (budget.get(k) ?? 0) + 1);
93
+ }
94
+ for (const v of violationsIn(helpers, file, family, byRoute)) {
95
+ const k = `${v.kind}\0${v.helper}`;
96
+ const left = budget.get(k) ?? 0;
97
+ if (left > 0) {
98
+ budget.set(k, left - 1);
99
+ result.allowed.push(v);
100
+ }
101
+ else if (v.kind === "scenario-name") {
102
+ result.advisories.push(v);
103
+ }
104
+ else {
105
+ result.violations.push(v);
106
+ }
107
+ }
108
+ }
109
+ result.imported = importedNames.size;
110
+ result.ok =
111
+ result.violations.length === 0 && result.malformedAllows.length === 0;
112
+ // Integration only — the same gate as the prompt rule. `contract`, `load` and an
113
+ // absent type also resolve to the API family, but the reuse flow never targets them,
114
+ // so an advisory (and a report count) there would describe reuse the feature could
115
+ // not have taken.
116
+ if ((params.testType ?? "").toLowerCase() === "integration") {
117
+ try {
118
+ result.inlineCallSites = await findSiblingInlineCallSites(params.testFile, utilsFiles, allHelpers, spec);
119
+ }
120
+ catch {
121
+ /* advisory only — never fails a verify */
122
+ }
123
+ }
124
+ return result;
125
+ }
126
+ function violationsIn(helpers, file, family, byRoute) {
127
+ const out = [];
128
+ for (const h of helpers) {
129
+ if (family.routeDuplicates && h.method && h.normalizedPath) {
130
+ const key = `${h.method} ${h.normalizedPath}`;
131
+ const first = byRoute.get(key);
132
+ if (first) {
133
+ out.push({
134
+ kind: "duplicate-helper",
135
+ file,
136
+ helper: h.name,
137
+ line: h.line,
138
+ detail: `${h.name} and ${first.name} (${path.basename(first.file)}:${first.line}) both wrap ${key}; keep one helper per method+path and lift the differing literals into defaulted parameters`,
139
+ });
140
+ }
141
+ else {
142
+ byRoute.set(key, { ...h, file });
143
+ }
144
+ }
145
+ for (const a of h.assertions) {
146
+ if (!a.allowed) {
147
+ out.push({
148
+ kind: "body-assertion",
149
+ file,
150
+ helper: h.name,
151
+ line: a.line,
152
+ detail: `\`${a.text}\` — ${family.assertionRule}`,
153
+ });
154
+ }
155
+ }
156
+ const naming = scenarioNameViolation(h.name);
157
+ if (naming) {
158
+ out.push({
159
+ kind: "scenario-name",
160
+ file,
161
+ helper: h.name,
162
+ line: h.line,
163
+ detail: naming,
164
+ });
165
+ }
166
+ }
167
+ return out;
168
+ }
@@ -32,7 +32,9 @@ export declare function toolError(message: string): CallToolResult;
32
32
  *
33
33
  * 2. Each agent CLI testbot supports reads a different channel and none falls
34
34
  * back to the other: Claude Code takes `structuredContent` and drops
35
- * `content[]`; Cursor takes `content[]` and ignores `structuredContent`;
35
+ * `content[]` WHEN BOTH ARE PRESENT — a content-only result still reaches it,
36
+ * which is what SKYR-4267 relies on for `browser_blueprint`; Cursor takes
37
+ * `content[]` and ignores `structuredContent`;
36
38
  * GitHub Copilot CLI surfaces both and de-duplicates them only when the text
37
39
  * is the literal JSON serialization of `structuredContent` (MCP spec 5.2.6),
38
40
  * otherwise it concatenates. Hence `JSON.stringify` rather than the raw text,
@@ -49,7 +49,9 @@ export function toolError(message) {
49
49
  *
50
50
  * 2. Each agent CLI testbot supports reads a different channel and none falls
51
51
  * back to the other: Claude Code takes `structuredContent` and drops
52
- * `content[]`; Cursor takes `content[]` and ignores `structuredContent`;
52
+ * `content[]` WHEN BOTH ARE PRESENT — a content-only result still reaches it,
53
+ * which is what SKYR-4267 relies on for `browser_blueprint`; Cursor takes
54
+ * `content[]` and ignores `structuredContent`;
53
55
  * GitHub Copilot CLI surfaces both and de-duplicates them only when the text
54
56
  * is the literal JSON serialization of `structuredContent` (MCP spec 5.2.6),
55
57
  * otherwise it concatenates. Hence `JSON.stringify` rather than the raw text,
@@ -55,26 +55,26 @@ export declare const serviceSchema: z.ZodObject<{
55
55
  }, "strict", z.ZodTypeAny, {
56
56
  authHeader?: string | undefined;
57
57
  authScheme?: string | undefined;
58
+ authType?: "none" | "cookie" | "bearer" | "basic" | "oauth" | "apiKey" | "session" | "token" | undefined;
59
+ baseUrl?: string | undefined;
58
60
  schemaPath?: string | undefined;
59
- authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
60
61
  defaultQueryParams?: Record<string, string> | undefined;
61
62
  queryParamOverrides?: {
62
63
  values: Record<string, string>;
63
64
  pathPattern: string;
64
65
  }[] | undefined;
65
- baseUrl?: string | undefined;
66
66
  skipTLSVerify?: boolean | undefined;
67
67
  }, {
68
68
  authHeader?: string | undefined;
69
69
  authScheme?: string | undefined;
70
+ authType?: "none" | "cookie" | "bearer" | "basic" | "oauth" | "apiKey" | "session" | "token" | undefined;
71
+ baseUrl?: string | undefined;
70
72
  schemaPath?: string | undefined;
71
- authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
72
73
  defaultQueryParams?: Record<string, string> | undefined;
73
74
  queryParamOverrides?: {
74
75
  values: Record<string, string>;
75
76
  pathPattern: string;
76
77
  }[] | undefined;
77
- baseUrl?: string | undefined;
78
78
  skipTLSVerify?: boolean | undefined;
79
79
  }>>;
80
80
  runtimeDetails: z.ZodOptional<z.ZodObject<{
@@ -143,20 +143,20 @@ export declare const serviceSchema: z.ZodObject<{
143
143
  language?: "python" | "typescript" | "javascript" | "java" | undefined;
144
144
  framework?: "playwright" | "pytest" | "robot" | "junit" | "vitest" | "jest" | "mocha" | "go" | "rspec" | "jasmine" | undefined;
145
145
  repository?: string | undefined;
146
- testDirectory?: string | undefined;
147
146
  api?: {
148
147
  authHeader?: string | undefined;
149
148
  authScheme?: string | undefined;
149
+ authType?: "none" | "cookie" | "bearer" | "basic" | "oauth" | "apiKey" | "session" | "token" | undefined;
150
+ baseUrl?: string | undefined;
150
151
  schemaPath?: string | undefined;
151
- authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
152
152
  defaultQueryParams?: Record<string, string> | undefined;
153
153
  queryParamOverrides?: {
154
154
  values: Record<string, string>;
155
155
  pathPattern: string;
156
156
  }[] | undefined;
157
- baseUrl?: string | undefined;
158
157
  skipTLSVerify?: boolean | undefined;
159
158
  } | undefined;
159
+ testDirectory?: string | undefined;
160
160
  runtimeDetails?: {
161
161
  runtime: import("../types/TestTypes.js").RuntimeEnvironment;
162
162
  dockerNetwork?: string | undefined;
@@ -178,20 +178,20 @@ export declare const serviceSchema: z.ZodObject<{
178
178
  language?: "python" | "typescript" | "javascript" | "java" | undefined;
179
179
  framework?: "playwright" | "pytest" | "robot" | "junit" | "vitest" | "jest" | "mocha" | "go" | "rspec" | "jasmine" | undefined;
180
180
  repository?: string | undefined;
181
- testDirectory?: string | undefined;
182
181
  api?: {
183
182
  authHeader?: string | undefined;
184
183
  authScheme?: string | undefined;
184
+ authType?: "none" | "cookie" | "bearer" | "basic" | "oauth" | "apiKey" | "session" | "token" | undefined;
185
+ baseUrl?: string | undefined;
185
186
  schemaPath?: string | undefined;
186
- authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
187
187
  defaultQueryParams?: Record<string, string> | undefined;
188
188
  queryParamOverrides?: {
189
189
  values: Record<string, string>;
190
190
  pathPattern: string;
191
191
  }[] | undefined;
192
- baseUrl?: string | undefined;
193
192
  skipTLSVerify?: boolean | undefined;
194
193
  } | undefined;
194
+ testDirectory?: string | undefined;
195
195
  runtimeDetails?: {
196
196
  runtime?: unknown;
197
197
  dockerNetwork?: string | undefined;
@@ -292,26 +292,26 @@ export declare const workspaceConfigSchema: z.ZodObject<{
292
292
  }, "strict", z.ZodTypeAny, {
293
293
  authHeader?: string | undefined;
294
294
  authScheme?: string | undefined;
295
+ authType?: "none" | "cookie" | "bearer" | "basic" | "oauth" | "apiKey" | "session" | "token" | undefined;
296
+ baseUrl?: string | undefined;
295
297
  schemaPath?: string | undefined;
296
- authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
297
298
  defaultQueryParams?: Record<string, string> | undefined;
298
299
  queryParamOverrides?: {
299
300
  values: Record<string, string>;
300
301
  pathPattern: string;
301
302
  }[] | undefined;
302
- baseUrl?: string | undefined;
303
303
  skipTLSVerify?: boolean | undefined;
304
304
  }, {
305
305
  authHeader?: string | undefined;
306
306
  authScheme?: string | undefined;
307
+ authType?: "none" | "cookie" | "bearer" | "basic" | "oauth" | "apiKey" | "session" | "token" | undefined;
308
+ baseUrl?: string | undefined;
307
309
  schemaPath?: string | undefined;
308
- authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
309
310
  defaultQueryParams?: Record<string, string> | undefined;
310
311
  queryParamOverrides?: {
311
312
  values: Record<string, string>;
312
313
  pathPattern: string;
313
314
  }[] | undefined;
314
- baseUrl?: string | undefined;
315
315
  skipTLSVerify?: boolean | undefined;
316
316
  }>>;
317
317
  runtimeDetails: z.ZodOptional<z.ZodObject<{
@@ -380,20 +380,20 @@ export declare const workspaceConfigSchema: z.ZodObject<{
380
380
  language?: "python" | "typescript" | "javascript" | "java" | undefined;
381
381
  framework?: "playwright" | "pytest" | "robot" | "junit" | "vitest" | "jest" | "mocha" | "go" | "rspec" | "jasmine" | undefined;
382
382
  repository?: string | undefined;
383
- testDirectory?: string | undefined;
384
383
  api?: {
385
384
  authHeader?: string | undefined;
386
385
  authScheme?: string | undefined;
386
+ authType?: "none" | "cookie" | "bearer" | "basic" | "oauth" | "apiKey" | "session" | "token" | undefined;
387
+ baseUrl?: string | undefined;
387
388
  schemaPath?: string | undefined;
388
- authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
389
389
  defaultQueryParams?: Record<string, string> | undefined;
390
390
  queryParamOverrides?: {
391
391
  values: Record<string, string>;
392
392
  pathPattern: string;
393
393
  }[] | undefined;
394
- baseUrl?: string | undefined;
395
394
  skipTLSVerify?: boolean | undefined;
396
395
  } | undefined;
396
+ testDirectory?: string | undefined;
397
397
  runtimeDetails?: {
398
398
  runtime: import("../types/TestTypes.js").RuntimeEnvironment;
399
399
  dockerNetwork?: string | undefined;
@@ -415,20 +415,20 @@ export declare const workspaceConfigSchema: z.ZodObject<{
415
415
  language?: "python" | "typescript" | "javascript" | "java" | undefined;
416
416
  framework?: "playwright" | "pytest" | "robot" | "junit" | "vitest" | "jest" | "mocha" | "go" | "rspec" | "jasmine" | undefined;
417
417
  repository?: string | undefined;
418
- testDirectory?: string | undefined;
419
418
  api?: {
420
419
  authHeader?: string | undefined;
421
420
  authScheme?: string | undefined;
421
+ authType?: "none" | "cookie" | "bearer" | "basic" | "oauth" | "apiKey" | "session" | "token" | undefined;
422
+ baseUrl?: string | undefined;
422
423
  schemaPath?: string | undefined;
423
- authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
424
424
  defaultQueryParams?: Record<string, string> | undefined;
425
425
  queryParamOverrides?: {
426
426
  values: Record<string, string>;
427
427
  pathPattern: string;
428
428
  }[] | undefined;
429
- baseUrl?: string | undefined;
430
429
  skipTLSVerify?: boolean | undefined;
431
430
  } | undefined;
431
+ testDirectory?: string | undefined;
432
432
  runtimeDetails?: {
433
433
  runtime?: unknown;
434
434
  dockerNetwork?: string | undefined;
@@ -463,20 +463,20 @@ export declare const workspaceConfigSchema: z.ZodObject<{
463
463
  language?: "python" | "typescript" | "javascript" | "java" | undefined;
464
464
  framework?: "playwright" | "pytest" | "robot" | "junit" | "vitest" | "jest" | "mocha" | "go" | "rspec" | "jasmine" | undefined;
465
465
  repository?: string | undefined;
466
- testDirectory?: string | undefined;
467
466
  api?: {
468
467
  authHeader?: string | undefined;
469
468
  authScheme?: string | undefined;
469
+ authType?: "none" | "cookie" | "bearer" | "basic" | "oauth" | "apiKey" | "session" | "token" | undefined;
470
+ baseUrl?: string | undefined;
470
471
  schemaPath?: string | undefined;
471
- authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
472
472
  defaultQueryParams?: Record<string, string> | undefined;
473
473
  queryParamOverrides?: {
474
474
  values: Record<string, string>;
475
475
  pathPattern: string;
476
476
  }[] | undefined;
477
- baseUrl?: string | undefined;
478
477
  skipTLSVerify?: boolean | undefined;
479
478
  } | undefined;
479
+ testDirectory?: string | undefined;
480
480
  runtimeDetails?: {
481
481
  runtime: import("../types/TestTypes.js").RuntimeEnvironment;
482
482
  dockerNetwork?: string | undefined;
@@ -511,20 +511,20 @@ export declare const workspaceConfigSchema: z.ZodObject<{
511
511
  language?: "python" | "typescript" | "javascript" | "java" | undefined;
512
512
  framework?: "playwright" | "pytest" | "robot" | "junit" | "vitest" | "jest" | "mocha" | "go" | "rspec" | "jasmine" | undefined;
513
513
  repository?: string | undefined;
514
- testDirectory?: string | undefined;
515
514
  api?: {
516
515
  authHeader?: string | undefined;
517
516
  authScheme?: string | undefined;
517
+ authType?: "none" | "cookie" | "bearer" | "basic" | "oauth" | "apiKey" | "session" | "token" | undefined;
518
+ baseUrl?: string | undefined;
518
519
  schemaPath?: string | undefined;
519
- authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
520
520
  defaultQueryParams?: Record<string, string> | undefined;
521
521
  queryParamOverrides?: {
522
522
  values: Record<string, string>;
523
523
  pathPattern: string;
524
524
  }[] | undefined;
525
- baseUrl?: string | undefined;
526
525
  skipTLSVerify?: boolean | undefined;
527
526
  } | undefined;
527
+ testDirectory?: string | undefined;
528
528
  runtimeDetails?: {
529
529
  runtime?: unknown;
530
530
  dockerNetwork?: string | undefined;
@@ -568,20 +568,20 @@ export declare function validateWorkspaceConfig(config: unknown): z.SafeParseRet
568
568
  language?: "python" | "typescript" | "javascript" | "java" | undefined;
569
569
  framework?: "playwright" | "pytest" | "robot" | "junit" | "vitest" | "jest" | "mocha" | "go" | "rspec" | "jasmine" | undefined;
570
570
  repository?: string | undefined;
571
- testDirectory?: string | undefined;
572
571
  api?: {
573
572
  authHeader?: string | undefined;
574
573
  authScheme?: string | undefined;
574
+ authType?: "none" | "cookie" | "bearer" | "basic" | "oauth" | "apiKey" | "session" | "token" | undefined;
575
+ baseUrl?: string | undefined;
575
576
  schemaPath?: string | undefined;
576
- authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
577
577
  defaultQueryParams?: Record<string, string> | undefined;
578
578
  queryParamOverrides?: {
579
579
  values: Record<string, string>;
580
580
  pathPattern: string;
581
581
  }[] | undefined;
582
- baseUrl?: string | undefined;
583
582
  skipTLSVerify?: boolean | undefined;
584
583
  } | undefined;
584
+ testDirectory?: string | undefined;
585
585
  runtimeDetails?: {
586
586
  runtime?: unknown;
587
587
  dockerNetwork?: string | undefined;
@@ -616,20 +616,20 @@ export declare function validateWorkspaceConfig(config: unknown): z.SafeParseRet
616
616
  language?: "python" | "typescript" | "javascript" | "java" | undefined;
617
617
  framework?: "playwright" | "pytest" | "robot" | "junit" | "vitest" | "jest" | "mocha" | "go" | "rspec" | "jasmine" | undefined;
618
618
  repository?: string | undefined;
619
- testDirectory?: string | undefined;
620
619
  api?: {
621
620
  authHeader?: string | undefined;
622
621
  authScheme?: string | undefined;
622
+ authType?: "none" | "cookie" | "bearer" | "basic" | "oauth" | "apiKey" | "session" | "token" | undefined;
623
+ baseUrl?: string | undefined;
623
624
  schemaPath?: string | undefined;
624
- authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
625
625
  defaultQueryParams?: Record<string, string> | undefined;
626
626
  queryParamOverrides?: {
627
627
  values: Record<string, string>;
628
628
  pathPattern: string;
629
629
  }[] | undefined;
630
- baseUrl?: string | undefined;
631
630
  skipTLSVerify?: boolean | undefined;
632
631
  } | undefined;
632
+ testDirectory?: string | undefined;
633
633
  runtimeDetails?: {
634
634
  runtime: import("../types/TestTypes.js").RuntimeEnvironment;
635
635
  dockerNetwork?: string | undefined;
@@ -28,16 +28,20 @@ const assertToolSchema = {
28
28
  name: "browser_assert",
29
29
  title: "Assert element state",
30
30
  description: [
31
- "Assert that an element has expected text, value, or is visible.",
31
+ "Assert that an element has expected text, value, or state.",
32
32
  "Use this after key actions to verify the page state is correct.",
33
33
  "The assertion is recorded in the trace for test generation.",
34
- 'Types: "text" checks element text content, "value" checks input field value.'
34
+ 'Types: "text" checks element text content, "value" checks input field value,',
35
+ '"checked" checks checkbox/radio state, "disabled" checks disabled/enabled state,',
36
+ '"visible" checks the element is visible,',
37
+ `"count" counts elements sharing the referenced element's role (or exact text)`,
38
+ "across the page, e.g. ref one option of an open dropdown to assert the number of options."
35
39
  ].join(" "),
36
40
  inputSchema: import_mcpBundle.z.object({
37
- type: import_mcpBundle.z.enum(["text", "value"]).describe('Type of assertion: "text" for text content, "value" for input field value'),
38
- ref: import_mcpBundle.z.string().describe("Element reference from the latest snapshot"),
41
+ type: import_mcpBundle.z.enum(["text", "value", "checked", "disabled", "visible", "count"]).describe(`Type of assertion: "text" for text content, "value" for input field value, "checked" for checkbox/radio state, "disabled" for disabled/enabled state ("false" asserts the element is enabled), "visible" for element visibility, "count" for the number of elements with the referenced element's role`),
42
+ ref: import_mcpBundle.z.string().describe('Element reference from the latest snapshot. For "count", reference one exemplar element (e.g. one option in an open dropdown).'),
39
43
  element: import_mcpBundle.z.string().describe("Human-readable description of the element being asserted"),
40
- expected: import_mcpBundle.z.string().describe("Expected text or value to assert"),
44
+ expected: import_mcpBundle.z.string().optional().describe('Expected text or value ("text"/"value"), "true"/"false" ("checked"/"disabled", default "true"; "disabled" with "false" asserts enabled), the expected element count ("count"). Not used for "visible".'),
41
45
  substring: import_mcpBundle.z.boolean().optional().default(true).describe("For text assertions: match as substring (true) or exact match (false)")
42
46
  }),
43
47
  type: "readOnly"
@@ -370,6 +370,22 @@ async function performClientAction(page, actionInContext) {
370
370
  throw new Error(`assertVisible failed: element is not visible`);
371
371
  return;
372
372
  }
373
+ case "assertDisabled": {
374
+ if (typeof action.disabled !== "boolean")
375
+ throw new Error(`assertDisabled failed: trace line has no boolean "disabled" field`);
376
+ const disabled = await locator.isDisabled(opts);
377
+ if (disabled !== action.disabled)
378
+ throw new Error(`assertDisabled failed: expected disabled=${action.disabled}, got ${disabled}`);
379
+ return;
380
+ }
381
+ case "assertCount": {
382
+ await locator.first().waitFor(opts).catch(() => {
383
+ });
384
+ const count = await locator.count();
385
+ if (count !== action.count)
386
+ throw new Error(`assertCount failed: expected ${action.count} element(s), got ${count}`);
387
+ return;
388
+ }
373
389
  default:
374
390
  return;
375
391
  }
@@ -61,6 +61,8 @@ const ACTION_NAMES = /* @__PURE__ */ new Set([
61
61
  "assertValue",
62
62
  "assertChecked",
63
63
  "assertVisible",
64
+ "assertDisabled",
65
+ "assertCount",
64
66
  "assertSnapshot",
65
67
  "visualSnapshot",
66
68
  "assertTableCell",