@skyramp/mcp 0.4.3-rc.2 → 0.4.4-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 (69) hide show
  1. package/build/playwright/traceRecordingPrompt.js +2 -1
  2. package/build/prompts/orderAssertionRule.d.ts +9 -0
  3. package/build/prompts/orderAssertionRule.js +9 -0
  4. package/build/prompts/test-maintenance/driftAnalysisShared.js +2 -0
  5. package/build/prompts/testbot/testbot-prompts.js +10 -7
  6. package/build/recommendation/answers.d.ts +54 -19
  7. package/build/recommendation/answers.js +102 -31
  8. package/build/recommendation/blockerProbes.d.ts +13 -0
  9. package/build/recommendation/blockerProbes.js +91 -0
  10. package/build/recommendation/blockers.d.ts +65 -0
  11. package/build/recommendation/blockers.js +135 -0
  12. package/build/recommendation/pullRequestText.d.ts +2 -0
  13. package/build/recommendation/pullRequestText.js +16 -0
  14. package/build/recommendation/registerPlan.d.ts +7 -4
  15. package/build/recommendation/registerPlan.js +37 -11
  16. package/build/recommendation/types.d.ts +21 -4
  17. package/build/recommendation/verifierContracts.d.ts +6 -6
  18. package/build/recommendation/verifierContracts.js +8 -7
  19. package/build/recommendation/verifiers/citedPath.d.ts +2 -2
  20. package/build/recommendation/verifiers/citedPath.js +2 -2
  21. package/build/recommendation/verifiers/coverage.js +25 -25
  22. package/build/recommendation/verifiers/deliveredMatchesPlan.js +3 -3
  23. package/build/recommendation/verifiers/issueTraceability.d.ts +1 -5
  24. package/build/recommendation/verifiers/issueTraceability.js +4 -35
  25. package/build/tools/executeSkyrampTestTool.js +8 -0
  26. package/build/tools/generate-tests/generateE2ERestTool.d.ts +1 -0
  27. package/build/tools/generate-tests/generateE2ERestTool.js +9 -1
  28. package/build/tools/generate-tests/generateUIRestTool.d.ts +2 -0
  29. package/build/tools/generate-tests/generateUIRestTool.js +9 -1
  30. package/build/tools/submitReportTool.d.ts +9 -9
  31. package/build/tools/submitReportTool.js +178 -26
  32. package/build/tools/test-management/registerTestPlanTool.d.ts +20 -14
  33. package/build/tools/test-management/registerTestPlanTool.js +30 -14
  34. package/build/types/TestTypes.d.ts +7 -0
  35. package/build/types/TestTypes.js +22 -0
  36. package/build/types/TestbotReport.d.ts +4 -1
  37. package/build/utils/assertion-verify/metrics.js +12 -0
  38. package/build/utils/findUp.d.ts +20 -0
  39. package/build/utils/findUp.js +59 -0
  40. package/build/utils/language-helper.js +1 -1
  41. package/build/utils/repoSdkVersion.d.ts +16 -0
  42. package/build/utils/repoSdkVersion.js +88 -0
  43. package/build/utils/testDependencyPolicy.d.ts +20 -0
  44. package/build/utils/testDependencyPolicy.js +64 -4
  45. package/build/utils/utils-verify/typecheck.js +3 -18
  46. package/node_modules/playwright/lib/mcp/skyramp/assertOrder.js +66 -0
  47. package/node_modules/playwright/lib/mcp/skyramp/assertTool.js +12 -3
  48. package/node_modules/playwright/lib/mcp/skyramp/common/liveReadError.js +40 -0
  49. package/node_modules/playwright/lib/mcp/skyramp/loadTraceTool.js +21 -0
  50. package/node_modules/playwright/lib/mcp/skyramp/skyRampImport.js +2 -1
  51. package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +96 -16
  52. package/node_modules/playwright/lib/mcp/test/skyRampExport.js +10 -0
  53. package/node_modules/playwright/node_modules/playwright-core/lib/server/codegen/skyramp/jsonlReader.js +1 -0
  54. package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/recorderRunner.js +22 -0
  55. package/node_modules/playwright/node_modules/playwright-core/lib/utils/isomorphic/elementOrder.js +57 -0
  56. package/node_modules/playwright/node_modules/playwright-core/lib/utils.js +2 -0
  57. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{index.uiPTFncY.js → index.0MJW0uG7.js} +1 -1
  58. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.html +1 -1
  59. package/node_modules/playwright/node_modules/playwright-core/package.json +1 -1
  60. package/node_modules/playwright/node_modules/playwright-core/src/server/codegen/skyramp/jsonlReader.ts +1 -1
  61. package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/recorderRunner.ts +26 -1
  62. package/node_modules/playwright/node_modules/playwright-core/src/utils/isomorphic/elementOrder.ts +83 -0
  63. package/node_modules/playwright/node_modules/playwright-core/src/utils.ts +1 -0
  64. package/node_modules/playwright/package.json +1 -1
  65. package/package.json +4 -2
  66. package/plugin/prompts/plan-tests.md +9 -17
  67. package/plugin/skills/enhance-assertions/reference/shared-rules.md +1 -1
  68. package/plugin/skills/enhance-assertions/reference/ui.md +2 -2
  69. package/plugin/skills/fix-test-import-errors/SKILL.md +1 -1
@@ -31,30 +31,6 @@ function quote(description) {
31
31
  .replace(/\s+/g, " ");
32
32
  return text.length > QUOTE_LENGTH ? `${text.slice(0, QUOTE_LENGTH)}…` : text;
33
33
  }
34
- /** The plan-time `defects:untested:<id>` objection, as the plan-time verifier ids it. */
35
- const UNTESTED_PREFIX = "defects:untested:";
36
- /** Defect ids whose `defects:untested:<id>` objection the agent closed when it
37
- * registered the plan, by an answer or by a blocker. Both buckets: a blocker
38
- * close is stored apart from an answer and is a close all the same. Read
39
- * defensively: the plan comes off disk. */
40
- function answeredUntested(plan) {
41
- const closed = [
42
- ...(Array.isArray(plan?.answeredObjections) ? plan.answeredObjections : []),
43
- ...(Array.isArray(plan?.unverifiedCloses) ? plan.unverifiedCloses : []),
44
- ];
45
- const ids = new Set();
46
- for (const entry of closed) {
47
- const objectionId = idKey(entry?.objection?.objectionId);
48
- if (!objectionId.startsWith(UNTESTED_PREFIX))
49
- continue;
50
- if (idKey(entry?.answer).length === 0)
51
- continue;
52
- const id = idKey(objectionId.slice(UNTESTED_PREFIX.length));
53
- if (id)
54
- ids.add(id);
55
- }
56
- return ids;
57
- }
58
34
  /** The declared defect ids a `maintains` entry proves, as plan time judged them.
59
35
  * Report time has no VerifyContext, so it reads plan time's own verdict on the
60
36
  * entry's file, `existingCoverage:maintains:<file>`, rather than resolving the path
@@ -122,11 +98,7 @@ function locate(defect) {
122
98
  * accepted that entry — the same claim a planned test makes. See
123
99
  * {@link maintainedDefects} for how that acceptance is read.
124
100
  * `deliveredMatchesPlan:maintains:` checks separately that the edit landed.
125
- *
126
- * A declared `defectId` also counts when the agent answered `defects:untested:<id>`
127
- * at plan time (or closed it with a blocker). The plan-time verifier asked why no
128
- * test proves that defect and the agent said; asking again here is the same
129
- * question twice, and the answer is already published with the plan. */
101
+ */
130
102
  export function checkIssueTraceability(plan, delivered, issues, lane = NORMAL_LANE) {
131
103
  const shipped = new Set(delivered.map((test) => idKey(test?.plannedTestId)).filter(Boolean));
132
104
  const plannedTests = Array.isArray(plan?.plannedTests)
@@ -173,7 +145,6 @@ export function checkIssueTraceability(plan, delivered, issues, lane = NORMAL_LA
173
145
  bucket.set(defectId, [...(bucket.get(defectId) ?? []), id]);
174
146
  }
175
147
  }
176
- const answered = answeredUntested(plan);
177
148
  const maintained = maintainedDefects(plan);
178
149
  const objections = [];
179
150
  issues.forEach((issue, index) => {
@@ -187,9 +158,7 @@ export function checkIssueTraceability(plan, delivered, issues, lane = NORMAL_LA
187
158
  const defectId = idKey(issue?.defectId);
188
159
  const declaredDefect = defectId.length > 0 && known.has(defectId);
189
160
  if (declaredDefect &&
190
- ((provenBy.get(defectId) ?? []).length > 0 ||
191
- maintained.has(defectId) ||
192
- answered.has(defectId))) {
161
+ ((provenBy.get(defectId) ?? []).length > 0 || maintained.has(defectId))) {
193
162
  return;
194
163
  }
195
164
  const named = [];
@@ -204,7 +173,7 @@ export function checkIssueTraceability(plan, delivered, issues, lane = NORMAL_LA
204
173
  named.push(`defectId "${defectId}" is cited by no ${word} test that expects to fail: ${(citedWeakly.get(defectId) ?? []).join(", ")} cite it and the plan declares each as expecting to pass`);
205
174
  }
206
175
  else {
207
- named.push(`defectId "${defectId}" is cited by no ${word} test that expects to fail, no accepted \`maintains\` entry proves it — an entry naming a file that is not in the checkout is refused — and no plan-time answer closed ${UNTESTED_PREFIX}${defectId}`);
176
+ named.push(`defectId "${defectId}" is cited by no ${word} test that expects to fail, no accepted \`maintains\` entry proves it — an entry naming a file that is not in the checkout is refused`);
208
177
  }
209
178
  }
210
179
  const where = String(issue?.sourceFile ?? "").trim() || "no sourceFile";
@@ -217,7 +186,7 @@ export function checkIssueTraceability(plan, delivered, issues, lane = NORMAL_LA
217
186
  verifier: "issueTraceability",
218
187
  message: `No test proves this bug: "${quote(issue?.description)}" (${where}).`,
219
188
  evidence: `issuesFound[${index}]: ${named.length > 0 ? named.join("; ") : "no plannedTestId and no defectId"}.`,
220
- suggestion: "Set `plannedTestId` to the delivered test that proves this bug — one the plan declares with `expected.outcome: fail`, so it stays red until the bug is fixed — or set `defectId` to a declared plan defect such a test cites. If no test proves it, answer in one line why.",
189
+ suggestion: "Set `plannedTestId` to the delivered test that proves this bug — one the plan declares with `expected.outcome: fail`, so it stays red until the bug is fixed — or set `defectId` to a declared plan defect such a test cites. If something stopped the test — a service that is not running, the one credential the run holds — answer and set `blocker` to it. A reason the bug is not worth testing is not a blocker.",
221
190
  });
222
191
  });
223
192
  return objections;
@@ -17,6 +17,7 @@ import { StateManager, currentRunStateFile, getPrimaryRepository, getTestsRepoDi
17
17
  import { DriftAction, } from "../types/TestAnalysis.js";
18
18
  import { logger } from "../utils/logger.js";
19
19
  import { toolError } from "../utils/utils.js";
20
+ import { staleSdkRefusal } from "../utils/repoSdkVersion.js";
20
21
  import { recordExecutionVideo } from "./execution-video-state.js";
21
22
  import { stageGeneratedPaths } from "../utils/gitStaging.js";
22
23
  import { walkDir } from "../utils/fileWalk.js";
@@ -1142,6 +1143,13 @@ export function registerExecuteSkyrampTestTool(server) {
1142
1143
  errorResult = toolError(`commandOverride does not contain ${testFileNames(params.testFile).join(" or ")}, the name of testFile. The command was not run.`);
1143
1144
  return errorResult;
1144
1145
  }
1146
+ // SKYR-4548: only a host run loads the repository's own SDK; the
1147
+ // executor container supplies its own whatever the repository pins.
1148
+ const staleSdk = staleSdkRefusal(params.testFile, params.language);
1149
+ if (staleSdk) {
1150
+ errorResult = toolError(staleSdk);
1151
+ return errorResult;
1152
+ }
1145
1153
  }
1146
1154
  // Hashed once, before any state write: recorded with the reservation
1147
1155
  // so the NEXT run can tell an unchanged re-run from a fixed file.
@@ -7,6 +7,7 @@ export declare class E2ETestService extends TestGenerationService {
7
7
  protected buildGenerationOptions(params: BaseTestParams & {
8
8
  responseData?: string;
9
9
  playwrightInput?: string;
10
+ testName?: string;
10
11
  }): any;
11
12
  protected handleApiAnalysis(_params: BaseTestParams): Promise<CallToolResult | null>;
12
13
  }
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { baseSchema, baseTraceSchema, TestType, codeRefactoringSchema, } from "../../types/TestTypes.js";
2
+ import { baseSchema, baseTraceSchema, TestType, codeRefactoringSchema, testNameField, } from "../../types/TestTypes.js";
3
3
  import { TestGenerationService, } from "../../services/TestGenerationService.js";
4
4
  import { AnalyticsService } from "../../services/AnalyticsService.js";
5
5
  import { toolError } from "../../utils/utils.js";
@@ -16,6 +16,7 @@ const e2eTestSchema = {
16
16
  "from a Playwright zip that already produced one is rejected — one recording covers one scenario, and reusing " +
17
17
  "it manufactures identical tests under names the recording never covered. Set true only when the same " +
18
18
  "recording genuinely covers the new scenario end-to-end."),
19
+ testName: testNameField("testE2e"),
19
20
  ...codeRefactoringSchema.shape,
20
21
  ...baseSchema.shape,
21
22
  };
@@ -28,6 +29,11 @@ export class E2ETestService extends TestGenerationService {
28
29
  ...super.buildBaseGenerationOptions(params),
29
30
  responseData: params.responseData,
30
31
  playwrightInput: params.playwrightInput,
32
+ // SKYR-4468: free-form title for the generated test, so the spec names the
33
+ // behaviour it verifies instead of the generic `testE2e`. The option is
34
+ // inert until the pinned @skyramp/skyramp release carries it — the client
35
+ // ignores options it does not know, so passing it early is safe.
36
+ testName: params.testName,
31
37
  };
32
38
  }
33
39
  async handleApiAnalysis(_params) {
@@ -44,6 +50,8 @@ End-to-End tests validate complete user journeys by testing the entire applicati
44
50
  TRACE & UI INTEGRATION:
45
51
  E2E tests require both trace files (capturing backend API interactions) and Playwright recordings (capturing UI interactions captured using start_trace_collection tool) to generate comprehensive tests that validate the complete user experience.
46
52
 
53
+ **Test title:** Pass \`testName\` with the behaviour this recording verifies (e.g. "Add to cart from search results"), taken from the recommendation the recording came from. Omit it and the spec is titled \`testE2e\`, which claims nothing.
54
+
47
55
  **CRITICAL - When using trace parameter:**
48
56
  If \`trace\` parameter is provided (path to a trace file), DO NOT pass \`apiSchema\` or \`endpointURL\` parameters. The trace file already contains all necessary endpoint and schema information. Passing both will cause test generation to fail.`,
49
57
  inputSchema: e2eTestSchema,
@@ -8,6 +8,7 @@ export declare class UITestService extends TestGenerationService {
8
8
  protected buildGenerationOptions(params: BaseTestParams & {
9
9
  playwrightInput?: string;
10
10
  uniqueUIFormInputs?: string[];
11
+ testName?: string;
11
12
  }): any;
12
13
  protected handleApiAnalysis(_params: BaseTestParams): Promise<CallToolResult | null>;
13
14
  generateTest(params: BaseTestParams & Record<string, any>): Promise<CallToolResult>;
@@ -19,6 +20,7 @@ export declare const uiTestSchema: {
19
20
  include: z.ZodOptional<z.ZodDefault<z.ZodArray<z.ZodString, "many">>>;
20
21
  exclude: z.ZodOptional<z.ZodDefault<z.ZodArray<z.ZodString, "many">>>;
21
22
  uniqueUIFormInputs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
23
+ testName: z.ZodOptional<z.ZodString>;
22
24
  output: z.ZodEffects<z.ZodOptional<z.ZodString>, string | undefined, string | undefined>;
23
25
  outputDir: z.ZodString;
24
26
  force: z.ZodDefault<z.ZodBoolean>;
@@ -1,4 +1,4 @@
1
- import { baseSchema, languageSchema, TestType, codeRefactoringSchema, baseTraceSchema, } from "../../types/TestTypes.js";
1
+ import { baseSchema, languageSchema, TestType, codeRefactoringSchema, baseTraceSchema, testNameField, } from "../../types/TestTypes.js";
2
2
  import { z } from "zod";
3
3
  import { AnalyticsService } from "../../services/AnalyticsService.js";
4
4
  import { TestGenerationService, } from "../../services/TestGenerationService.js";
@@ -21,6 +21,11 @@ export class UITestService extends TestGenerationService {
21
21
  // SKYR-4012: create-form inputs the agent flagged as unique-constrained,
22
22
  // so Skyramp codegen types a per-run-unique value into them.
23
23
  uniqueUIFormInputs: params.uniqueUIFormInputs,
24
+ // SKYR-4468: free-form title for the generated test, so the spec names the
25
+ // behaviour it verifies instead of the generic `testUi`. The option is
26
+ // inert until the pinned @skyramp/skyramp release carries it — the client
27
+ // ignores options it does not know, so passing it early is safe.
28
+ testName: params.testName,
24
29
  };
25
30
  }
26
31
  async handleApiAnalysis(_params) {
@@ -86,6 +91,7 @@ export const uiTestSchema = {
86
91
  .array(z.string().min(1))
87
92
  .optional()
88
93
  .describe("Create-form inputs whose value is UNIQUE-constrained (e.g. a name/slug that the backend rejects as a duplicate). Identify each by the accessible label or selector you typed into during recording (the same value passed to getByLabel/getByPlaceholder/getByRole, or a raw selector). Skyramp types a per-run-unique value into these inputs — and reuses it in later assertions — so the generated UI test can be re-run without hitting a duplicate/conflict error. Inspect the app's data model for unique constraints; omit when no create-form field is unique-constrained."),
94
+ testName: testNameField("testUi"),
89
95
  output: baseSchema.shape.output,
90
96
  outputDir: baseSchema.shape.outputDir,
91
97
  force: baseSchema.shape.force,
@@ -123,6 +129,8 @@ This tells you exactly which frontend files changed so you record traces for the
123
129
 
124
130
  **Idempotency (re-runnable create flows):** If the recorded flow creates a resource by typing into a UNIQUE-constrained field (a name/slug the backend rejects as a duplicate on a second run), pass those inputs in \`uniqueUIFormInputs\`. Skyramp then types a per-run-unique value into them (and reuses it in later assertions) so the generated test can be re-run without a duplicate/conflict failure.
125
131
 
132
+ **Test title:** Pass \`testName\` with the behaviour this recording verifies (e.g. "Add to cart from search results"), taken from the recommendation the recording came from. Omit it and the spec is titled \`testUi\`, which claims nothing.
133
+
126
134
  **DOM Analyzer tools for blueprint-aware recording:** alongside the basic \`browser_*\` interaction tools, the Skyramp MCP exposes \`browser_blueprint\` (canonical PageBlueprint capture). This enables semantic target selection and delta-derived assertions: capture a blueprint before each meaningful action, perform the action, then capture again — the delta between the two grounds your assertions in observable state changes rather than author guesses about what "success" looks like.
127
135
 
128
136
  **CRITICAL: Do NOT use skyramp_start_trace_collection/skyramp_stop_trace_collection for UI test recording — use browser_* tools + skyramp_export_zip instead.**`,
@@ -25,9 +25,9 @@ export declare const targetElementSchema: z.ZodObject<{
25
25
  widgetType: z.ZodOptional<z.ZodEnum<["native", "custom", "unknown"]>>;
26
26
  }, "strip", z.ZodTypeAny, {
27
27
  role: string;
28
- accessibleName: string;
29
28
  testId: string | null;
30
29
  stableId: string | null;
30
+ accessibleName: string;
31
31
  contextText: string[] | null;
32
32
  mutability?: "unknown" | "mutable" | "immutable" | undefined;
33
33
  widgetType?: "unknown" | "custom" | "native" | undefined;
@@ -73,9 +73,9 @@ export declare const newTestSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
73
73
  widgetType: z.ZodOptional<z.ZodEnum<["native", "custom", "unknown"]>>;
74
74
  }, "strip", z.ZodTypeAny, {
75
75
  role: string;
76
- accessibleName: string;
77
76
  testId: string | null;
78
77
  stableId: string | null;
78
+ accessibleName: string;
79
79
  contextText: string[] | null;
80
80
  mutability?: "unknown" | "mutable" | "immutable" | undefined;
81
81
  widgetType?: "unknown" | "custom" | "native" | undefined;
@@ -112,9 +112,9 @@ export declare const newTestSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
112
112
  scenarioFile?: string | undefined;
113
113
  targetElements?: {
114
114
  role: string;
115
- accessibleName: string;
116
115
  testId: string | null;
117
116
  stableId: string | null;
117
+ accessibleName: string;
118
118
  contextText: string[] | null;
119
119
  mutability?: "unknown" | "mutable" | "immutable" | undefined;
120
120
  widgetType?: "unknown" | "custom" | "native" | undefined;
@@ -164,9 +164,9 @@ export declare const newTestSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
164
164
  scenarioFile?: string | undefined;
165
165
  targetElements?: {
166
166
  role: string;
167
- accessibleName: string;
168
167
  testId: string | null;
169
168
  stableId: string | null;
169
+ accessibleName: string;
170
170
  contextText: string[] | null;
171
171
  mutability?: "unknown" | "mutable" | "immutable" | undefined;
172
172
  widgetType?: "unknown" | "custom" | "native" | undefined;
@@ -216,9 +216,9 @@ export declare const newTestSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
216
216
  scenarioFile?: string | undefined;
217
217
  targetElements?: {
218
218
  role: string;
219
- accessibleName: string;
220
219
  testId: string | null;
221
220
  stableId: string | null;
221
+ accessibleName: string;
222
222
  contextText: string[] | null;
223
223
  mutability?: "unknown" | "mutable" | "immutable" | undefined;
224
224
  widgetType?: "unknown" | "custom" | "native" | undefined;
@@ -274,9 +274,9 @@ export declare const additionalRecommendationSchema: z.ZodEffects<z.ZodEffects<z
274
274
  widgetType: z.ZodOptional<z.ZodEnum<["native", "custom", "unknown"]>>;
275
275
  }, "strip", z.ZodTypeAny, {
276
276
  role: string;
277
- accessibleName: string;
278
277
  testId: string | null;
279
278
  stableId: string | null;
279
+ accessibleName: string;
280
280
  contextText: string[] | null;
281
281
  mutability?: "unknown" | "mutable" | "immutable" | undefined;
282
282
  widgetType?: "unknown" | "custom" | "native" | undefined;
@@ -318,9 +318,9 @@ export declare const additionalRecommendationSchema: z.ZodEffects<z.ZodEffects<z
318
318
  scenarioName?: string | undefined;
319
319
  targetElements?: {
320
320
  role: string;
321
- accessibleName: string;
322
321
  testId: string | null;
323
322
  stableId: string | null;
323
+ accessibleName: string;
324
324
  contextText: string[] | null;
325
325
  mutability?: "unknown" | "mutable" | "immutable" | undefined;
326
326
  widgetType?: "unknown" | "custom" | "native" | undefined;
@@ -386,9 +386,9 @@ export declare const additionalRecommendationSchema: z.ZodEffects<z.ZodEffects<z
386
386
  scenarioName?: string | undefined;
387
387
  targetElements?: {
388
388
  role: string;
389
- accessibleName: string;
390
389
  testId: string | null;
391
390
  stableId: string | null;
391
+ accessibleName: string;
392
392
  contextText: string[] | null;
393
393
  mutability?: "unknown" | "mutable" | "immutable" | undefined;
394
394
  widgetType?: "unknown" | "custom" | "native" | undefined;
@@ -454,9 +454,9 @@ export declare const additionalRecommendationSchema: z.ZodEffects<z.ZodEffects<z
454
454
  scenarioName?: string | undefined;
455
455
  targetElements?: {
456
456
  role: string;
457
- accessibleName: string;
458
457
  testId: string | null;
459
458
  stableId: string | null;
459
+ accessibleName: string;
460
460
  contextText: string[] | null;
461
461
  mutability?: "unknown" | "mutable" | "immutable" | undefined;
462
462
  widgetType?: "unknown" | "custom" | "native" | undefined;