@skyramp/mcp 0.4.2-rc.1 → 0.4.2-rc.3

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 (110) hide show
  1. package/build/commands/localDevTestChangesCommand.js +1 -1
  2. package/build/commands/recommendTestsAndExecuteCommand.js +10 -1
  3. package/build/commands/testThisEndpointCommand.js +19 -2
  4. package/build/execution/wrapperConfig.d.ts +56 -0
  5. package/build/execution/wrapperConfig.js +155 -0
  6. package/build/index.js +6 -6
  7. package/build/playwright/registerPlaywrightTools.js +14 -0
  8. package/build/playwright/traceExportStore.d.ts +22 -0
  9. package/build/playwright/traceExportStore.js +81 -0
  10. package/build/playwright/traceRecordingPrompt.js +2 -1
  11. package/build/prompts/code-reuse.js +24 -21
  12. package/build/prompts/local-dev/local-dev-plan.js +6 -23
  13. package/build/prompts/local-dev/local-dev-prompts.js +1 -1
  14. package/build/prompts/shared-helper-policy.d.ts +36 -0
  15. package/build/prompts/shared-helper-policy.js +33 -1
  16. package/build/prompts/startTraceCollectionPrompts.js +1 -1
  17. package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.js +6 -7
  18. package/build/prompts/sut-setup/shared.d.ts +1 -1
  19. package/build/prompts/sut-setup/shared.js +5 -3
  20. package/build/prompts/test-maintenance/drift-analysis-prompt.d.ts +16 -8
  21. package/build/prompts/test-maintenance/drift-analysis-prompt.js +90 -36
  22. package/build/prompts/test-maintenance/uiDriftAnalysisSections.js +1 -1
  23. package/build/prompts/test-recommendation/recommendationShared.d.ts +1 -1
  24. package/build/prompts/test-recommendation/recommendationShared.js +0 -1
  25. package/build/prompts/testbot/testbot-prompts.js +11 -9
  26. package/build/services/TestDiscoveryService.js +32 -4
  27. package/build/skills/runTestSkill.d.ts +6 -0
  28. package/build/skills/runTestSkill.js +17 -0
  29. package/build/tool-phases.js +0 -1
  30. package/build/tools/budgetExcuse.d.ts +15 -0
  31. package/build/tools/budgetExcuse.js +113 -0
  32. package/build/tools/code-refactor/utils-verify-gates.js +17 -3
  33. package/build/tools/executeSkyrampTestTool.d.ts +97 -48
  34. package/build/tools/executeSkyrampTestTool.js +775 -449
  35. package/build/tools/generate-tests/generateE2ERestTool.d.ts +0 -1
  36. package/build/tools/generate-tests/generateE2ERestTool.js +1 -9
  37. package/build/tools/generate-tests/generateUIRestTool.d.ts +0 -2
  38. package/build/tools/generate-tests/generateUIRestTool.js +1 -9
  39. package/build/tools/submitReportTool.js +128 -0
  40. package/build/tools/test-management/actionsTool.js +31 -0
  41. package/build/tools/test-management/analyzeChangesTool.d.ts +4 -4
  42. package/build/tools/test-management/analyzeTestHealthTool.d.ts +0 -11
  43. package/build/tools/test-management/analyzeTestHealthTool.js +7 -63
  44. package/build/tools/test-management/testsOwedBeforeRun.d.ts +28 -0
  45. package/build/tools/test-management/testsOwedBeforeRun.js +53 -0
  46. package/build/tools/trace/stopTraceCollectionTool.js +1 -1
  47. package/build/types/RepositoryAnalysis.d.ts +32 -32
  48. package/build/types/ReuseOutcome.d.ts +4 -3
  49. package/build/types/TestExecution.d.ts +2 -2
  50. package/build/types/TestTypes.d.ts +3 -7
  51. package/build/types/TestTypes.js +6 -20
  52. package/build/utils/AnalysisStateManager.d.ts +0 -7
  53. package/build/utils/AnalysisStateManager.js +1 -1
  54. package/build/utils/connectionErrors.d.ts +10 -0
  55. package/build/utils/connectionErrors.js +10 -0
  56. package/build/utils/language-helper.js +24 -3
  57. package/build/utils/progress.d.ts +1 -1
  58. package/build/utils/progress.js +1 -1
  59. package/build/utils/rebaselineSnapshots.d.ts +1 -1
  60. package/build/utils/rebaselineSnapshots.js +6 -16
  61. package/build/utils/reuseRouting.d.ts +10 -0
  62. package/build/utils/reuseRouting.js +15 -0
  63. package/build/utils/runContextGauge.d.ts +27 -0
  64. package/build/utils/runContextGauge.js +181 -0
  65. package/build/utils/skyrampMdContent.d.ts +1 -1
  66. package/build/utils/skyrampMdContent.js +1 -1
  67. package/build/utils/skyrampSdkVersion.d.ts +9 -0
  68. package/build/utils/skyrampSdkVersion.js +16 -0
  69. package/build/utils/testDependencyPolicy.js +21 -0
  70. package/build/utils/testExecutionRecord.d.ts +5 -1
  71. package/build/utils/testExecutionRecord.js +3 -1
  72. package/build/utils/testFileClassification.d.ts +8 -0
  73. package/build/utils/testFileClassification.js +36 -3
  74. package/build/utils/utils-verify/action-key.d.ts +42 -0
  75. package/build/utils/utils-verify/action-key.js +118 -36
  76. package/build/utils/utils-verify/action-sites.d.ts +32 -0
  77. package/build/utils/utils-verify/action-sites.js +202 -0
  78. package/build/utils/utils-verify/body-reach.js +2 -4
  79. package/build/utils/utils-verify/call-sites.d.ts +25 -6
  80. package/build/utils/utils-verify/call-sites.js +8 -5
  81. package/build/utils/utils-verify/index.d.ts +1 -0
  82. package/build/utils/utils-verify/index.js +1 -0
  83. package/build/utils/utils-verify/language-spec.d.ts +25 -0
  84. package/build/utils/utils-verify/language-spec.js +16 -2
  85. package/build/utils/utils-verify/parse.d.ts +10 -1
  86. package/build/utils/utils-verify/parse.js +19 -2
  87. package/build/utils/utils-verify/verify.d.ts +3 -2
  88. package/build/utils/utils-verify/verify.js +16 -18
  89. package/build/workspace/workspace.d.ts +72 -52
  90. package/build/workspace/workspace.js +12 -8
  91. package/package.json +1 -1
  92. package/plugin/prompts/testbot-task1.md +0 -2
  93. package/plugin/skills/enhance-assertions/reference/shared-rules.md +1 -1
  94. package/plugin/skills/enhance-assertions/reference/ui.md +1 -1
  95. package/plugin/skills/fix-test-import-errors/SKILL.md +2 -1
  96. package/plugin/skills/run-test/SKILL.md +16 -0
  97. package/build/adapters/jestAdapter.d.ts +0 -14
  98. package/build/adapters/jestAdapter.js +0 -131
  99. package/build/adapters/mochaAdapter.d.ts +0 -13
  100. package/build/adapters/mochaAdapter.js +0 -93
  101. package/build/adapters/playwrightAdapter.d.ts +0 -17
  102. package/build/adapters/playwrightAdapter.js +0 -184
  103. package/build/adapters/pytestAdapter.d.ts +0 -15
  104. package/build/adapters/pytestAdapter.js +0 -119
  105. package/build/tools/runExistingTestsTool.d.ts +0 -138
  106. package/build/tools/runExistingTestsTool.js +0 -666
  107. package/build/types/ExternalTestExecution.d.ts +0 -67
  108. package/build/types/ExternalTestExecution.js +0 -8
  109. package/build/workspace/testSuites.d.ts +0 -20
  110. package/build/workspace/testSuites.js +0 -17
@@ -10,7 +10,7 @@
10
10
  * SKYR-4196 Part B runs 5 and 11 leaked a scenario-literal body assertion into a shared
11
11
  * helper despite both rules being in the prompt.
12
12
  */
13
- import { HELPER_ASSERTION_POLICIES, CONTENT_ROLES, } from "../../prompts/shared-helper-policy.js";
13
+ import { API_HELPERS, BROWSER_HELPERS, HELPER_ASSERTION_POLICIES, CONTENT_ROLES, } from "../../prompts/shared-helper-policy.js";
14
14
  import { escapeRegExp } from "../regex.js";
15
15
  /**
16
16
  * A Playwright name as the language SPELLS it: camelCase unchanged, Python
@@ -228,7 +228,7 @@ const ROLE_WITH_NAME_RE = /\b(?:getByRole|get_by_role)\s*\(\s*["'`]([A-Za-z]+)["
228
228
  * wrong. The split walks bracket depth on a copy whose strings are blanked, so a comma
229
229
  * inside a selector or a message does not end the argument.
230
230
  */
231
- function expectArgs(expr) {
231
+ export function expectArgs(expr) {
232
232
  const open = expr.indexOf("(", expr.indexOf("expect"));
233
233
  // `.not.to…` in TypeScript, `.not_to_…` in Python. Reading only the first left a
234
234
  // negated Python assertion with no end, so the whole source line — a trailing
@@ -325,6 +325,14 @@ export const HELPER_FAMILIES = {
325
325
  isAllowed: (spec, expr) => spec.allowedAssertion.test(expr),
326
326
  assertionRule: HELPER_ASSERTION_POLICIES.api.boundary,
327
327
  fixRule: "a helper that wraps an SDK request asserts only the status code — one helper per method+path, extended with defaulted parameters (the expected status excepted: it has no default and every call passes it), named method + resource",
328
+ inlineSite: {
329
+ // The prompt's word for the same thing, read from the policy so the advisory
330
+ // and the rule the agent followed name the site alike.
331
+ noun: API_HELPERS.inlineSite.noun,
332
+ already: "wraps",
333
+ instruction: "Each is a candidate: the request's method, path and call shape match the helper's. Replace the block with a call to the helper only if the remaining differences are literals (they become the arguments; keep the block's response variable; import the helper into that file; change nothing else there).",
334
+ localCopy: "that request",
335
+ },
328
336
  },
329
337
  browser: {
330
338
  family: "browser",
@@ -336,6 +344,12 @@ export const HELPER_FAMILIES = {
336
344
  !selectsByRenderedText(expectArgs(expr)),
337
345
  assertionRule: `${HELPER_ASSERTION_POLICIES.browser.boundary}. Move this value assertion to the test body immediately after the helper call, selector verbatim`,
338
346
  fixRule: "every other helper holds actions and structural waits only, named for the user intent",
347
+ inlineSite: {
348
+ noun: BROWSER_HELPERS.inlineSite.noun,
349
+ already: "performs",
350
+ instruction: "Each is a candidate: the sequence's actions and locators equal the helper's, in order. Replace the sequence with a call to the helper only if the remaining differences are literals — fill values, option labels, literal arguments — which become the arguments (import the helper into that file; every assertion and the page-error guard stay in the test body where they are; change nothing else there).",
351
+ localCopy: "the sequence",
352
+ },
339
353
  },
340
354
  };
341
355
  /** The helper family a test type's shared helpers follow. Unlike `isBrowserTestType`,
@@ -44,8 +44,10 @@ export interface UtilsHelper {
44
44
  /** The helper's Playwright action sequence — the duplicate key of a browser
45
45
  * helper, where an API helper has method+path. See actionKeyOf. Read for
46
46
  * TypeScript, JavaScript and Python (through the JavaScript spelling); absent
47
- * for a helper with no readable action. */
47
+ * for a helper with no readable action. `actionSteps` is the same sequence one
48
+ * step per entry, for the sibling scan that matches step by step. */
48
49
  actionKey?: string;
50
+ actionSteps?: string[];
49
51
  }
50
52
  /** The declared parameters of a signature, raw text trimmed, empty entries dropped
51
53
  * (a trailing comma). Reads the signature from the definition line to its body
@@ -91,6 +93,13 @@ export declare function unusableParamTypesOf(sigLines: string[]): string[];
91
93
  * next non-blank column-0 line; TS/JS bodies end when the brace depth opened by
92
94
  * the definition returns to zero.
93
95
  */
96
+ /** A generated TEST's own module-level helpers: what parseUtilsFile reads from it,
97
+ * less the test functions themselves (`test_…` / `testUi`), which are not helpers a
98
+ * call can sit "inside" in the sense the sibling scans and the body-reach check
99
+ * report. */
100
+ export declare function localHelpersOf(content: string, spec: UtilsLanguageSpec): UtilsHelper[];
101
+ /** The helper whose body holds `line` (1-based), if any. */
102
+ export declare function localHelperAt(helpers: UtilsHelper[], line: number): UtilsHelper | undefined;
94
103
  export declare function parseUtilsFile(content: string, spec: UtilsLanguageSpec): UtilsHelper[];
95
104
  /** True when the `path` value is a single string literal ending the argument — a
96
105
  * concatenation (`"/api/orders/" + str(id) + "/items"`) has no route this can name. */
@@ -1,5 +1,11 @@
1
1
  import { normalizePath } from "./language-spec.js";
2
- import { actionKeyOf } from "./action-key.js";
2
+ import { actionStepKeys, actionStepsOf, } from "./action-key.js";
3
+ /** A helper's action steps and their joined key, read once from its body. */
4
+ function actionSequence(body, language) {
5
+ const steps = actionStepsOf(body, language);
6
+ const keys = actionStepKeys(steps);
7
+ return keys ? { actionKey: keys.join("; "), actionSteps: keys } : {};
8
+ }
3
9
  import { fixedSleepsIn, pythonSleepBindings, } from "./fixed-sleep.js";
4
10
  import { stripComments, stripCommentsAndStrings, stripStrings, } from "../pom-scope/strip.js";
5
11
  /** Whether the `<` at `i` opens a generic (`Record<string, …>`, `Array<{…}>`) rather
@@ -204,6 +210,17 @@ export function unusableParamTypesOf(sigLines) {
204
210
  * next non-blank column-0 line; TS/JS bodies end when the brace depth opened by
205
211
  * the definition returns to zero.
206
212
  */
213
+ /** A generated TEST's own module-level helpers: what parseUtilsFile reads from it,
214
+ * less the test functions themselves (`test_…` / `testUi`), which are not helpers a
215
+ * call can sit "inside" in the sense the sibling scans and the body-reach check
216
+ * report. */
217
+ export function localHelpersOf(content, spec) {
218
+ return parseUtilsFile(content, spec).filter((h) => !/^test/i.test(h.name));
219
+ }
220
+ /** The helper whose body holds `line` (1-based), if any. */
221
+ export function localHelperAt(helpers, line) {
222
+ return helpers.find((h) => line >= h.line && line <= h.endLine);
223
+ }
207
224
  export function parseUtilsFile(content, spec) {
208
225
  const lines = content.split("\n");
209
226
  // Structure — where a body ends — is read on a copy with comments and string
@@ -263,7 +280,7 @@ export function parseUtilsFile(content, spec) {
263
280
  fixedSleeps: fixedSleepsIn(body, scan, spec.language, params ?? [], start + 1, sleepBindings),
264
281
  // Comments blanked, strings kept: a commented-out click is not a step, and
265
282
  // the selector literals are the key.
266
- actionKey: actionKeyOf(blankComments(body.join("\n"), spec), spec.language),
283
+ ...actionSequence(blankComments(body.join("\n"), spec), spec.language),
267
284
  };
268
285
  let requests = 0;
269
286
  for (let k = 0; k < body.length; k++) {
@@ -50,8 +50,9 @@ export interface UtilsVerifyResult {
50
50
  * a helper that issues an SDK request is judged by the api rules regardless. See
51
51
  * helperFamilyOf. */
52
52
  fallbackFamily: HelperFamilySpec;
53
- /** Advisory (does not affect `ok`): inline request calls in sibling generated tests
54
- * that a utils helper already wraps — see findSiblingInlineCallSites. API family only. */
53
+ /** Advisory (does not affect `ok`): inline request calls (integration) or inline
54
+ * action sequences (seeded UI) in sibling generated tests that a utils helper
55
+ * already wraps — see findSiblingInlineCallSites. */
55
56
  inlineCallSites: InlineCallSite[];
56
57
  /** Advisory (does not affect `ok`): operations written in two or more sibling
57
58
  * generated tests (this one included) that NO utils helper wraps — the extraction
@@ -7,10 +7,12 @@ import { typecheckDelivered } from "./typecheck.js";
7
7
  import { blankComments, blankCommentsAndStrings, countAssertions, hasPageErrorGuard, parseUtilsFile, } from "./parse.js";
8
8
  import { escapeRegExp } from "../regex.js";
9
9
  import { detectGitRoot } from "../gitStaging.js";
10
- import { isModularizeFirstTarget } from "../reuseRouting.js";
10
+ import { inlineCallSiteFamily, isModularizeFirstTarget, } from "../reuseRouting.js";
11
+ import { describeActionKey } from "./action-key.js";
11
12
  import { findDuplicateBodyReach, findUnreachableBodies } from "./body-reach.js";
12
13
  import { misnamedNewModules } from "./module-name.js";
13
14
  import { additiveChanges, locateInHouseModules, resolveInHouseCalls, } from "./in-house.js";
15
+ import { findSiblingInlineActionSites } from "./action-sites.js";
14
16
  import { findSiblingInlineCallSites, findUnextractedDuplicates, generatedSiblings, } from "./call-sites.js";
15
17
  import { parseUtilsAllows, } from "./allow.js";
16
18
  import { describeFixedSleeps, fixedSleepReplacement } from "./fixed-sleep.js";
@@ -633,17 +635,24 @@ export async function verifyUtils(params) {
633
635
  });
634
636
  result.ok =
635
637
  result.violations.length === 0 && result.malformedAllows.length === 0;
636
- // Integration only — the same gate as the prompt rule. `contract`, `load` and an
637
- // absent type also resolve to the API family, but the reuse flow never targets them,
638
- // so an advisory (and a report count) there would describe reuse the feature could
639
- // not have taken.
640
- if ((params.testType ?? "").toLowerCase() === "integration") {
638
+ // The gate the prompt renders the rule on: one predicate, so the advisory can
639
+ // never describe a rewiring the prompt did not ask for.
640
+ const scanFamily = inlineCallSiteFamily(params.testType, spec.language);
641
+ if (scanFamily) {
641
642
  try {
642
- result.inlineCallSites = await findSiblingInlineCallSites(params.testFile, utilsFiles, allHelpers, spec, siblings);
643
+ result.inlineCallSites =
644
+ scanFamily === "api"
645
+ ? await findSiblingInlineCallSites(params.testFile, utilsFiles, allHelpers, spec, siblings)
646
+ : await findSiblingInlineActionSites(params.testFile, helpersByFile, spec, siblings);
643
647
  }
644
648
  catch {
645
649
  /* advisory only — never fails a verify */
646
650
  }
651
+ }
652
+ // Integration only — `contract`, `load` and an absent type also resolve to the API
653
+ // family, but the reuse flow never targets them.
654
+ const integration = (params.testType ?? "").toLowerCase() === "integration";
655
+ if (integration) {
647
656
  try {
648
657
  result.unextractedDuplicates = await findUnextractedDuplicates(params.testFile, utilsFiles, spec, siblings);
649
658
  }
@@ -953,14 +962,3 @@ incumbents = new Set()) {
953
962
  }
954
963
  return out;
955
964
  }
956
- /** `click empty-cart-btn; fill qty` → `click \`empty-cart-btn\`; fill \`qty\`` — the
957
- * key as the agent reads it, selectors quoted so a `#id` never reads as prose. */
958
- function describeActionKey(key) {
959
- return key
960
- .split("; ")
961
- .map((step) => {
962
- const at = step.indexOf(" ");
963
- return `${step.slice(0, at)} \`${step.slice(at + 1)}\``;
964
- })
965
- .join("; ");
966
- }