@skyramp/mcp 0.3.5 → 0.3.6-rc.2.ac20

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 (164) hide show
  1. package/build/adapters/jestAdapter.js +3 -0
  2. package/build/adapters/mochaAdapter.js +2 -0
  3. package/build/adapters/playwrightAdapter.js +3 -0
  4. package/build/adapters/pytestAdapter.js +12 -0
  5. package/build/playwright/registerPlaywrightTools.js +92 -30
  6. package/build/playwright/traceRecordingPrompt.d.ts +6 -0
  7. package/build/playwright/traceRecordingPrompt.js +6 -2
  8. package/build/prompts/code-reuse.d.ts +1 -2
  9. package/build/prompts/code-reuse.js +182 -77
  10. package/build/prompts/modularization/integration-test-modularization.d.ts +2 -0
  11. package/build/prompts/modularization/integration-test-modularization.js +83 -41
  12. package/build/prompts/modularization/render.d.ts +18 -0
  13. package/build/prompts/modularization/render.js +12 -0
  14. package/build/prompts/modularization/ui-test-modularization.d.ts +3 -1
  15. package/build/prompts/modularization/ui-test-modularization.js +89 -47
  16. package/build/prompts/pom-aware-code-reuse.js +3 -1
  17. package/build/prompts/shared-helper-policy.d.ts +57 -0
  18. package/build/prompts/shared-helper-policy.js +135 -0
  19. package/build/prompts/test-recommendation/diffExecutionPlan.js +62 -56
  20. package/build/prompts/test-recommendation/fullRepoCatalog.js +19 -8
  21. package/build/prompts/test-recommendation/recommendationShared.d.ts +28 -6
  22. package/build/prompts/test-recommendation/recommendationShared.js +90 -16
  23. package/build/prompts/test-recommendation/registerRecommendTestsPrompt.js +22 -0
  24. package/build/prompts/test-recommendation/test-recommendation-prompt.d.ts +2 -2
  25. package/build/prompts/test-recommendation/test-recommendation-prompt.js +3 -3
  26. package/build/prompts/testbot/testbot-prompts.js +81 -35
  27. package/build/recommendation/budgeters/shared.js +105 -27
  28. package/build/recommendation/discriminators.js +13 -2
  29. package/build/recommendation/planRanker.d.ts +6 -6
  30. package/build/recommendation/planRanker.js +6 -61
  31. package/build/services/AnalyticsService.d.ts +7 -0
  32. package/build/services/AnalyticsService.js +7 -1
  33. package/build/services/ModularizationService.js +1 -3
  34. package/build/services/TestDiscoveryService.d.ts +0 -2
  35. package/build/services/TestDiscoveryService.js +2 -37
  36. package/build/services/TestGenerationService.d.ts +16 -0
  37. package/build/services/TestGenerationService.js +86 -10
  38. package/build/services/containerEnv.js +13 -12
  39. package/build/tools/code-refactor/codeReuseTool.js +279 -93
  40. package/build/tools/code-refactor/enhance-state.d.ts +49 -0
  41. package/build/tools/code-refactor/enhance-state.js +109 -0
  42. package/build/tools/code-refactor/enhanceAssertionsTool.js +34 -1
  43. package/build/tools/code-refactor/modularizationTool.js +9 -2
  44. package/build/tools/code-refactor/reuse-outcome.d.ts +23 -1
  45. package/build/tools/code-refactor/reuse-outcome.js +14 -4
  46. package/build/tools/code-refactor/reuse-state.d.ts +127 -5
  47. package/build/tools/code-refactor/reuse-state.js +628 -16
  48. package/build/tools/code-refactor/utils-verify-gates.d.ts +26 -0
  49. package/build/tools/code-refactor/utils-verify-gates.js +100 -0
  50. package/build/tools/code-refactor/verify-gates.d.ts +2 -1
  51. package/build/tools/code-refactor/verify-gates.js +90 -25
  52. package/build/tools/executeSkyrampTestTool.d.ts +19 -0
  53. package/build/tools/executeSkyrampTestTool.js +158 -8
  54. package/build/tools/generate-tests/generateBatchScenarioRestTool.js +2 -2
  55. package/build/tools/generate-tests/generateE2ERestTool.js +16 -0
  56. package/build/tools/generate-tests/generateUIRestTool.d.ts +1 -0
  57. package/build/tools/generate-tests/generateUIRestTool.js +22 -0
  58. package/build/tools/generate-tests/scenarioLint.d.ts +2 -0
  59. package/build/tools/generate-tests/scenarioLint.js +127 -19
  60. package/build/tools/generate-tests/trace-reuse-guard.d.ts +20 -0
  61. package/build/tools/generate-tests/trace-reuse-guard.js +93 -0
  62. package/build/tools/runExistingTestsTool.d.ts +34 -2
  63. package/build/tools/runExistingTestsTool.js +104 -4
  64. package/build/tools/submitReportTool.d.ts +38 -38
  65. package/build/tools/submitReportTool.js +537 -120
  66. package/build/tools/test-management/analyzeChangesTool.d.ts +24 -1
  67. package/build/tools/test-management/analyzeChangesTool.js +71 -10
  68. package/build/tools/test-management/analyzeTestHealthTool.js +7 -7
  69. package/build/tools/test-management/registerTestPlanTool.d.ts +203 -0
  70. package/build/tools/test-management/registerTestPlanTool.js +70 -12
  71. package/build/types/ExternalTestExecution.d.ts +67 -1
  72. package/build/types/Recommendation.d.ts +34 -5
  73. package/build/types/RepositoryAnalysis.d.ts +133 -114
  74. package/build/types/RepositoryAnalysis.js +1 -1
  75. package/build/types/ReuseOutcome.d.ts +102 -6
  76. package/build/types/ReuseOutcome.js +16 -2
  77. package/build/types/TestRecommendation.js +21 -3
  78. package/build/types/TestTypes.js +14 -8
  79. package/build/types/TestbotReport.d.ts +10 -1
  80. package/build/types/index.d.ts +2 -2
  81. package/build/types/index.js +1 -1
  82. package/build/utils/AnalysisStateManager.d.ts +57 -1
  83. package/build/utils/AnalysisStateManager.js +54 -5
  84. package/build/utils/branchDiff.d.ts +10 -0
  85. package/build/utils/branchDiff.js +28 -0
  86. package/build/utils/changedRoutes.d.ts +29 -0
  87. package/build/utils/changedRoutes.js +87 -0
  88. package/build/utils/featureFlags.d.ts +21 -0
  89. package/build/utils/featureFlags.js +23 -0
  90. package/build/utils/frontendIntegration.js +34 -4
  91. package/build/utils/importerHop.d.ts +2 -8
  92. package/build/utils/importerHop.js +15 -53
  93. package/build/utils/pathMatching.d.ts +38 -0
  94. package/build/utils/pathMatching.js +71 -0
  95. package/build/utils/pathSignatures.d.ts +22 -0
  96. package/build/utils/pathSignatures.js +57 -0
  97. package/build/utils/planMatchKeys.d.ts +16 -3
  98. package/build/utils/planMatchKeys.js +26 -10
  99. package/build/utils/pluralization.d.ts +10 -0
  100. package/build/utils/pluralization.js +18 -0
  101. package/build/utils/pom-catalog-parse.d.ts +52 -0
  102. package/build/utils/pom-catalog-parse.js +141 -0
  103. package/build/utils/pom-scope/selector-extractor.d.ts +12 -0
  104. package/build/utils/pom-scope/selector-extractor.js +34 -8
  105. package/build/utils/pom-verify/verify.d.ts +6 -5
  106. package/build/utils/pom-verify/verify.js +8 -6
  107. package/build/utils/reportVerification.d.ts +64 -4
  108. package/build/utils/reportVerification.js +228 -3
  109. package/build/utils/reuseRouting.d.ts +3 -0
  110. package/build/utils/reuseRouting.js +50 -0
  111. package/build/utils/routeParsers.d.ts +2 -0
  112. package/build/utils/routeParsers.js +65 -8
  113. package/build/utils/scenarioDrafting.d.ts +1 -1
  114. package/build/utils/scenarioDrafting.js +57 -45
  115. package/build/utils/subjectEndpoints.d.ts +19 -0
  116. package/build/utils/subjectEndpoints.js +98 -0
  117. package/build/utils/testFileClassification.d.ts +11 -0
  118. package/build/utils/testFileClassification.js +47 -0
  119. package/build/utils/uiPageEnumerator.d.ts +45 -19
  120. package/build/utils/uiPageEnumerator.js +95 -51
  121. package/build/utils/utils-verify/allow.d.ts +16 -0
  122. package/build/utils/utils-verify/allow.js +68 -0
  123. package/build/utils/utils-verify/call-sites.d.ts +34 -0
  124. package/build/utils/utils-verify/call-sites.js +154 -0
  125. package/build/utils/utils-verify/index.d.ts +7 -0
  126. package/build/utils/utils-verify/index.js +7 -0
  127. package/build/utils/utils-verify/language-spec.d.ts +91 -0
  128. package/build/utils/utils-verify/language-spec.js +210 -0
  129. package/build/utils/utils-verify/locate.d.ts +39 -0
  130. package/build/utils/utils-verify/locate.js +199 -0
  131. package/build/utils/utils-verify/parse.d.ts +34 -0
  132. package/build/utils/utils-verify/parse.js +177 -0
  133. package/build/utils/utils-verify/stage.d.ts +24 -0
  134. package/build/utils/utils-verify/stage.js +107 -0
  135. package/build/utils/utils-verify/verify.d.ts +63 -0
  136. package/build/utils/utils-verify/verify.js +168 -0
  137. package/build/utils/utils.d.ts +3 -1
  138. package/build/utils/utils.js +3 -1
  139. package/build/workspace/workspace.d.ts +32 -32
  140. package/node_modules/playwright/lib/mcp/skyramp/assertTool.js +9 -5
  141. package/node_modules/playwright/lib/mcp/skyramp/loadTraceTool.js +16 -0
  142. package/node_modules/playwright/lib/mcp/skyramp/skyRampImport.js +2 -0
  143. package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +115 -14
  144. package/node_modules/playwright/lib/mcp/test/skyRampExport.js +13 -1
  145. package/node_modules/playwright/node_modules/playwright-core/.DS_Store +0 -0
  146. package/node_modules/playwright/node_modules/playwright-core/lib/server/codegen/skyramp/jsonlReader.js +2 -0
  147. package/node_modules/playwright/node_modules/playwright-core/lib/vite/htmlReport/index.html +27 -253
  148. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/{codeMirrorModule-DtudTj_v.js → codeMirrorModule-DJMC4zNo.js} +1 -1
  149. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/index-BW82eAUI.js +196 -0
  150. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/index.html +1 -1
  151. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/{codeMirrorModule-FNMuBzX1.js → codeMirrorModule-CZfp96qZ.js} +1 -1
  152. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-gpLo02E0.js +809 -0
  153. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.Bq1r1URj.js +2 -0
  154. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.html +2 -2
  155. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.VEfqi1qN.js +5 -0
  156. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.html +2 -2
  157. package/node_modules/playwright/node_modules/playwright-core/package.json +1 -1
  158. package/node_modules/playwright/node_modules/playwright-core/src/server/codegen/skyramp/jsonlReader.ts +1 -1
  159. package/node_modules/playwright/package.json +1 -1
  160. package/package.json +2 -2
  161. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/index-BpDwp16L.js +0 -422
  162. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-Co9upU5h.js +0 -1035
  163. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.DXNIQ_dx.js +0 -2
  164. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.CIKB3XSv.js +0 -5
@@ -1,6 +1,8 @@
1
1
  import { generateSkyrampHeader, SKYRAMP_UTILS_HEADER } from "../utils/utils.js";
2
- import { isPomReuseEnabled } from "../utils/featureFlags.js";
2
+ import { isUtilsReuseEnabled } from "../utils/featureFlags.js";
3
+ import { isModularizeFirstTarget, isPomAwareTarget, } from "../utils/reuseRouting.js";
3
4
  import { getPomAwareCodeReusePrompt } from "./pom-aware-code-reuse.js";
5
+ import { NO_SHADOWING_RULE, selectHelperPolicy, } from "./shared-helper-policy.js";
4
6
  const LANGUAGE_MAP = {
5
7
  python: {
6
8
  extension: "py",
@@ -19,23 +21,159 @@ const LANGUAGE_MAP = {
19
21
  fileName: "skyrampUtils.ts",
20
22
  },
21
23
  };
22
- export function isPomAwareTarget(language, framework) {
23
- if (!isPomReuseEnabled())
24
- return false;
25
- const lang = language.toLowerCase();
26
- return (lang === "typescript" || lang === "javascript") && framework?.toLowerCase() === "playwright";
24
+ function genericNearDupExample(testFile) {
25
+ return `### Worked example
26
+
27
+ \`flow-1.spec.ts\` has:
28
+ \`\`\`ts
29
+ export async function upload_translation_file(page, fileName) {
30
+ await page.waitForTimeout(1500);
31
+ const responsePromise1 = page.waitForResponse("**/api/files/upload**");
32
+ const fileUploadPromise0 = page.waitForEvent("filechooser");
33
+ await page.getByText("Choose a file").first().click();
34
+ const fileChooser0 = await fileUploadPromise0;
35
+ await fileChooser0.setFiles(fileName);
36
+ const response1 = await responsePromise1;
37
+ await page.waitForTimeout(1500);
27
38
  }
28
- export function getCodeReusePrompt(testFile, language, framework, scopedPoms) {
39
+ \`\`\`
40
+
41
+ \`${testFile}\` (current) has:
42
+ \`\`\`ts
43
+ export async function uploadFileToRFI(page, fileName, tabName) {
44
+ await page.waitForTimeout(1500);
45
+ const responsePromise1 = page.waitForResponse("**/api/files/upload**");
46
+ const fileUploadPromise0 = page.waitForEvent("filechooser");
47
+ await page.getByText("Choose a file").click();
48
+ const fileChooser0 = await fileUploadPromise0;
49
+ await fileChooser0.setFiles(fileName);
50
+ const response1 = await responsePromise1;
51
+ await page.waitForTimeout(1500);
52
+ }
53
+ \`\`\`
54
+
55
+ These ARE near-duplicates. Same primitive sequence; the only material difference is the \`.first()\` qualifier on the locator. \`tabName\` is unused in the body — recorder noise, drop it. Correct merge:
56
+
57
+ \`\`\`ts
58
+ export async function uploadFileViaChooser(page, fileName) {
59
+ await page.waitForTimeout(1500);
60
+ const responsePromise = page.waitForResponse("**/api/files/upload**");
61
+ const fileUploadPromise = page.waitForEvent("filechooser");
62
+ await page.getByText("Choose a file").first().click();
63
+ const fileChooser = await fileUploadPromise;
64
+ await fileChooser.setFiles(fileName);
65
+ await responsePromise;
66
+ await page.waitForTimeout(1500);
67
+ }
68
+ \`\`\`
69
+
70
+ Both test files import and call \`uploadFileViaChooser(page, fileName)\`.`;
71
+ }
72
+ export function getCodeReusePrompt(testFile, language, framework, scopedPoms, testType) {
29
73
  const lang = language.toLowerCase();
30
- if (isPomAwareTarget(lang, framework)) {
74
+ if (isPomAwareTarget(lang, framework, testType)) {
31
75
  return getPomAwareCodeReusePrompt(testFile, lang, scopedPoms);
32
76
  }
33
- const ext = LANGUAGE_MAP[language].extension || "py";
34
- const fileName = LANGUAGE_MAP[language].fileName || "SkyrampUtils.py";
77
+ const languageEntry = LANGUAGE_MAP[lang] ?? LANGUAGE_MAP.python;
78
+ const ext = languageEntry.extension;
79
+ const fileName = languageEntry.fileName;
35
80
  const codegenMarker = `${ext === "py" ? "#" : "//"} Generated by Skyramp v`;
81
+ // Modularize-first flows (see isModularizeFirstTarget) reach reuse already
82
+ // modularized, so the trailing hand-off must not send the agent back into
83
+ // modularization a second time — it would re-extract the helpers this pass
84
+ // just consolidated.
85
+ const modularizeFirst = isModularizeFirstTarget(testType, lang);
86
+ const modularizationTail = modularizeFirst
87
+ ? `**MANDATORY**: ${testType} tests are modularized BEFORE code reuse (see the PRECONDITION at the top). This reuse pass is the FINAL step for this file — do NOT call skyramp_modularization after it; a second modularization pass would re-extract the helpers this pass just consolidated.`
88
+ : `**MANDATORY**: After code reuse is complete, proceed to modularization by calling skyramp_modularization tool ONLY for UI, E2E, or INTEGRATION test types generated from traces.`;
89
+ // Modularize-first tests reach reuse freshly modularized: their helpers exist
90
+ // only in the current file, and STEP 5's other-files-only rule would strand
91
+ // them there forever — the FIRST test in a repo could never create the utils
92
+ // file. STEP 5b seeds the utils file from the current test's own helpers so
93
+ // this run's output carries it and later tests import instead of re-defining.
94
+ const seedsUtils = modularizeFirst;
95
+ // Naming, equivalence and assertion rules for helpers headed to the shared
96
+ // file are the helper policy's — selected once by test type, stated once.
97
+ const policy = selectHelperPolicy(testType);
98
+ // The generic worked example treats a locator qualifier (.first()) as a
99
+ // liftable difference; a shared-file browser helper must not, so seeded
100
+ // browser flows show an identical-selector merge instead.
101
+ const workedExample = seedsUtils
102
+ ? policy.nearDupExample(testFile)
103
+ : genericNearDupExample(testFile);
104
+ const skipTarget = seedsUtils ? "STEP 5b" : "STEP 6";
105
+ const noSiblingsRule = seedsUtils
106
+ ? `**IF NO OTHER SKYRAMP-GENERATED TEST FILES ARE FOUND, SKIP DIRECTLY TO STEP 5b — do not process STEP 4b or STEP 5.**`
107
+ : `**STOP HERE IF NO OTHER SKYRAMP-GENERATED TEST FILES FOUND**
108
+ **IF NO OTHER SKYRAMP-GENERATED TEST FILES ARE FOUND, SKIP TO STEP 6 - DO NOT CREATE ANY UTILS FILES.**`;
109
+ const seedStepBlock = seedsUtils
110
+ ? `## STEP 5b: MOVE THIS TEST'S OWN HELPERS INTO \`${fileName}\`
111
+
112
+ skyramp_modularization already ran on ${testFile} and extracted its steps into named helper functions. Those helpers belong in the shared \`${fileName}\` so later tests import them instead of re-defining them.
113
+
114
+ For each helper function still defined locally in ${testFile} (i.e. not already merged by STEP 4b):
115
+ 1. **CREATE** \`${fileName}\` if it does not exist, with the standard header:
116
+ \`\`\`${ext}
117
+ ${generateSkyrampHeader(lang)}
118
+ \`\`\`
119
+ 2. **CHECK ITS ASSERTIONS FIRST**: ${policy.assertionRule} Relocate a trailing excluded assertion to ${policy.relocationTarget} before the move.${policy.moveRule ? ` ${policy.moveRule}` : ""}
120
+ 3. **MOVE** the helper into \`${fileName}\` — no renames, no signature changes, no changes beyond the trailing-assertion relocation above.
121
+ 4. **IMPORT** it from \`${fileName}\` into ${testFile}; keep every call site unchanged.
122
+ 5. If \`${fileName}\` already contains a helper for ${policy.sameStep} (or the same name): identical bodies → delete the local copy and import the utils version; differs only by ${policy.liftableLiterals} → apply the defaulted-parameter merge rule from STEP 4b (extend the utils helper with parameters defaulted to its current literals, import it, pass this test's values); differs structurally → leave the local helper in place and do not overwrite the utils version. ${policy.structuralNoise ? `${policy.structuralNoise}. ` : ""}${NO_SHADOWING_RULE}
123
+
124
+ This step MOVES helpers that skyramp_modularization already created — it does not author new ones. If ${testFile} defines no helper functions, skip this step and do not create an empty \`${fileName}\`.
125
+ `
126
+ : "";
127
+ const nearDupRules = seedsUtils ? policy.nearDupRules(fileName) : "";
128
+ const utilsMergeRule = seedsUtils
129
+ ? `
130
+ **IF \`${fileName}\` ALREADY CONTAINS A HELPER FOR ${policy.sameStep}** that differs from what ${testFile} needs only by ${policy.liftableLiterals}: do NOT define a second helper — EXTEND the utils helper by lifting the differing literals to parameters whose defaults are the utils version's current literals (existing call sites stay valid unchanged), then import and call it with this test's values. ${policy.oneHelperRule(fileName)}${policy.structuralNoise ? ` ${policy.structuralNoise}.` : ""} ${NO_SHADOWING_RULE}
131
+ `
132
+ : "";
133
+ // SKYR-4219: an inline request block is a CALL SITE for an existing helper, not a
134
+ // helper to move. Without this, a direct-mode sibling (plain literals, no
135
+ // \`data_override\`/\`uniqueSuffix\`) never meets the scenario-mode helper for the
136
+ // same request, and a step still inline in the current test never meets the utils
137
+ // helper — reuse degrades to a no-op in any mixed directory. Explicit test-type
138
+ // gate, not \`seedsUtils\`: the rule is stated in API terms.
139
+ const inlineRequestRule = testType === "integration"
140
+ ? `**INLINE REQUEST BLOCKS ARE CALL SITES, NOT HELPERS.** A request step written inline — one \`client.send_request(...)\` / \`client.sendRequest(...)\` call plus its status-code assertion, not wrapped in a function — is never something to move or author a helper from. But when a helper for the SAME method+path already exists, the block is that helper's near-duplicate (judge it by the API near-duplicate criteria in STEP 4b: same method+path and call structure; differences limited to body literals, \`data_override\` values, or expected status): REPLACE the block with a call to the helper, passing the block's own literals as arguments, and lift any literal the helper does not yet take to a parameter DEFAULTED to the helper's current value (existing call sites unchanged). KEEP the block's response variable — \`<same variable> = <helper>(...)\` — so the assertions that read it afterwards are unchanged. A value the block wraps in \`uniqueSuffix(...)\` or routes through \`data_override\` where the helper uses a plain literal (or vice versa) is a LITERAL difference, not a structural one — pass the expression as the argument. A block whose request differs structurally (extra step, different method or path) stays as it is.`
141
+ : "";
142
+ // Its own step, placed after 5b: the agent routinely satisfies ${testFile} in STEP 3
143
+ // and jumps straight to verification, never entering STEP 4 — so a sibling rule parked
144
+ // there is never read (measured: eval run u4219b). This is where the shared helper is
145
+ // guaranteed to exist and the agent is guaranteed to still be running.
146
+ const siblingCallSitesStep = testType === "integration"
147
+ ? `## STEP 5c: REPLACE INLINE REQUEST BLOCKS IN OTHER SKYRAMP-GENERATED TESTS WITH CALLS TO \`${fileName}\`
148
+
149
+ **Run this step EVEN IF STEP 3 already satisfied ${testFile} and STEPS 4–5b did nothing.** ${inlineRequestRule}
150
+
151
+ 1. Grep for the other Skyramp-generated test files exactly as in STEP 4 (codegen marker \`${codegenMarker}\`, excluding ${testFile} and \`${fileName}\`).
152
+ 2. In each, find every inline request block whose method+path matches a helper now defined in \`${fileName}\`.
153
+ 3. For each match: import the helper into that file and replace the block with the call, passing the block's literals (or expressions) as arguments; lift a literal the helper lacks to a defaulted parameter in \`${fileName}\`. Change NOTHING else in that file — its other steps, assertions and order stay verbatim.
154
+ 4. A block with no matching helper, or one that differs structurally, stays as it is. Conservative bias: a wrong replacement breaks a passing test; a missed one leaves a duplicate.
155
+
156
+ `
157
+ : "";
158
+ const finalReminderScope = seedsUtils
159
+ ? `**ONLY MOVE HELPERS THAT ALREADY EXIST IN TEST FILES — NEVER AUTHOR NEW ONES**`
160
+ : `**ONLY MOVE EXISTING HELPERS FROM OTHER TEST FILES**`;
161
+ const decisionTreeTail = seedsUtils
162
+ ? `3. Found other test files with only repetitive patterns? → Step 5b (seed utils from this test's own helpers)
163
+ 4. Found no other test files? → Step 5b
164
+ 5. Other test files identical to current? → Step 5b
165
+ 6. This test file defines no helpers either? → Step 6, NO utils file`
166
+ : `3. Found other test files with only repetitive patterns? → SKIP to Step 6, NO utils file
167
+ 4. Found no other test files? → SKIP to Step 6, NO utils file
168
+ 5. Other test files identical to current? → SKIP to Step 6, NO utils file`;
169
+ const precondition = modularizeFirst
170
+ ? `
171
+ **PRECONDITION — check your own tool-call history, not the file**: this flow moves the helpers skyramp_modularization created into \`${fileName}\` (STEP 5b). If you have NOT called skyramp_modularization on ${testFile} in this run, STOP: call it now with \`testFile\` set to ${testFile}, \`testType: "${testType}"\`, and \`isTraceBased: true\`, apply its instructions, then call skyramp_reuse_code again with the same arguments as this call. If you HAVE called it and the file still defines no helper functions, that is a legitimate outcome — proceed; STEP 5b will simply have nothing to move.
172
+ `
173
+ : "";
36
174
  return `# CODE REUSE - 6 CLEAR STEPS
37
175
  **CRITICAL WARNING: VIOLATION OF THESE RULES WILL RESULT IN ERROR**
38
-
176
+ ${precondition}
39
177
  ## DEFINITIONS (READ FIRST):
40
178
  **What is a "Helper Function"?**
41
179
  - A helper function is a STANDALONE, DISTINCT function that is ALREADY DEFINED in the code
@@ -65,10 +203,14 @@ Use the Grep tool to search for files containing "${SKYRAMP_UTILS_HEADER}":
65
203
  Read the matching non-test files and check if any helpers can be reused in ${testFile}.
66
204
 
67
205
  ## STEP 3: USE EXISTING HELPERS FROM UTILS SOURCE FILES FOUND IN STEP 2
68
- If helpers exist in util file that can be reused in ${testFile} without modifying them:
206
+ If helpers exist in util file that can be reused in ${testFile} without modifying them${inlineRequestRule ? " — or, for API request helpers, by EXTENDING them with defaulted parameters as the rules below allow" : ""}:
69
207
  - Import them into ${testFile}
70
208
  - Remove any duplicate code in ${testFile}
71
- - Test that ${testFile} still works without any errors and logical is same as original test file.
209
+ ${inlineRequestRule
210
+ ? `- ${inlineRequestRule} This applies to every request step still inline in ${testFile} that matches a utils helper.
211
+ `
212
+ : ""}- Test that ${testFile} still works without any errors and logical is same as original test file.
213
+ ${utilsMergeRule}
72
214
 
73
215
  ## STEP 4: FIND LOCAL HELPERS IN OTHER SKYRAMP-GENERATED TEST FILES
74
216
 
@@ -85,8 +227,7 @@ The result will mix two kinds of files:
85
227
  - **Utils file(s)** — already handled by STEP 2/STEP 3.
86
228
  - **Other Skyramp-generated test files** — these are the targets of STEP 4 / 4b / 5. Identify them by the \`${codegenMarker}\` codegen marker on line 1 (NOT the bare utils header).
87
229
 
88
- **STOP HERE IF NO OTHER SKYRAMP-GENERATED TEST FILES FOUND**
89
- **IF NO OTHER SKYRAMP-GENERATED TEST FILES ARE FOUND, SKIP TO STEP 6 - DO NOT CREATE ANY UTILS FILES.**
230
+ ${noSiblingsRule}
90
231
 
91
232
  If other Skyramp-generated test files are found, read those files and look for ALREADY DEFINED helper functions with clear function signatures.
92
233
 
@@ -101,8 +242,12 @@ NOT A HELPER FUNCTION (do not extract):
101
242
  - No function definition/signature
102
243
  - Example: Multiple \`await page.getByTestId("xyz").click()\` directly in test
103
244
 
104
- **IF OTHER TEST FILES ONLY CONTAIN REPETITIVE PATTERNS (NO ACTUAL HELPER FUNCTIONS), SKIP TO STEP 6**
105
- **IF OTHER SKYRAMP-GENERATED TEST FILES ARE BYTE-FOR-BYTE IDENTICAL TO ${testFile}, SKIP TO STEP 6** (note: helpers being NEAR-duplicates does NOT count as identical — proceed to STEP 4b)
245
+ ${inlineRequestRule
246
+ ? `(Inline request blocks in OTHER test files are not helpers to move — STEP 5c replaces them with calls to the shared helpers.)
247
+
248
+ `
249
+ : ""}**IF OTHER TEST FILES ONLY CONTAIN REPETITIVE PATTERNS (NO ACTUAL HELPER FUNCTIONS), SKIP TO ${skipTarget}**
250
+ **IF OTHER SKYRAMP-GENERATED TEST FILES ARE BYTE-FOR-BYTE IDENTICAL TO ${testFile}, SKIP TO ${skipTarget}** (note: helpers being NEAR-duplicates does NOT count as identical — proceed to STEP 4b)
106
251
 
107
252
  ## STEP 4b: PARAMETERIZE NEAR-DUPLICATE HELPERS ACROSS SKYRAMP-GENERATED TEST FILES
108
253
 
@@ -117,53 +262,8 @@ Two helpers (one in ${testFile}, one in another Skyramp-generated test file foun
117
262
  3. **The differing literals are trivially liftable to parameters** — no logic needs to be invented to derive them.
118
263
 
119
264
  If any of the three is false → NOT near-duplicates. Leave them alone.
120
-
121
- ### Worked example
122
-
123
- \`flow-1.spec.ts\` has:
124
- \`\`\`ts
125
- export async function upload_translation_file(page, fileName) {
126
- await page.waitForTimeout(1500);
127
- const responsePromise1 = page.waitForResponse("**/api/files/upload**");
128
- const fileUploadPromise0 = page.waitForEvent("filechooser");
129
- await page.getByText("Choose a file").first().click();
130
- const fileChooser0 = await fileUploadPromise0;
131
- await fileChooser0.setFiles(fileName);
132
- const response1 = await responsePromise1;
133
- await page.waitForTimeout(1500);
134
- }
135
- \`\`\`
136
-
137
- \`${testFile}\` (current) has:
138
- \`\`\`ts
139
- export async function uploadFileToRFI(page, fileName, tabName) {
140
- await page.waitForTimeout(1500);
141
- const responsePromise1 = page.waitForResponse("**/api/files/upload**");
142
- const fileUploadPromise0 = page.waitForEvent("filechooser");
143
- await page.getByText("Choose a file").click();
144
- const fileChooser0 = await fileUploadPromise0;
145
- await fileChooser0.setFiles(fileName);
146
- const response1 = await responsePromise1;
147
- await page.waitForTimeout(1500);
148
- }
149
- \`\`\`
150
-
151
- These ARE near-duplicates. Same primitive sequence; the only material difference is the \`.first()\` qualifier on the locator. \`tabName\` is unused in the body — recorder noise, drop it. Correct merge:
152
-
153
- \`\`\`ts
154
- export async function uploadFileViaChooser(page, fileName) {
155
- await page.waitForTimeout(1500);
156
- const responsePromise = page.waitForResponse("**/api/files/upload**");
157
- const fileUploadPromise = page.waitForEvent("filechooser");
158
- await page.getByText("Choose a file").first().click();
159
- const fileChooser = await fileUploadPromise;
160
- await fileChooser.setFiles(fileName);
161
- await responsePromise;
162
- await page.waitForTimeout(1500);
163
- }
164
- \`\`\`
165
-
166
- Both test files import and call \`uploadFileViaChooser(page, fileName)\`.
265
+ ${nearDupRules}
266
+ ${workedExample}
167
267
 
168
268
  ### Procedure
169
269
 
@@ -172,7 +272,7 @@ For each helper defined locally in ${testFile}:
172
272
  1. **Scan** each OTHER Skyramp-generated test file from STEP 4 for a helper that matches the near-duplicate criteria above.
173
273
  2. **If no match** → skip this helper, move on.
174
274
  3. **If exactly one match** → parameterize and merge:
175
- - **Name**: pick a name describing INTENT, not the originating test. E.g. \`uploadFileViaChooser\`, not \`upload_translation_file\` or \`uploadFileToRFI\`.
275
+ - **Name**: pick a name describing INTENT, not the originating test. ${seedsUtils ? policy.namingExample : "E.g. `uploadFileViaChooser`, not `upload_translation_file` or `uploadFileToRFI`."}
176
276
  - **Parameters**: the literal values that differ across the two call sites. Drop any parameter that is unused in the body (recorder noise).
177
277
  - **Body**: the common primitive sequence with the differing literals replaced by parameters.
178
278
  - **Forbidden**: do NOT add if/else, ternaries, defaults, or any logic to bridge the differences. If a single body can't cover both call sites without new logic, they are NOT near-duplicates — leave them alone.
@@ -201,7 +301,7 @@ For each helper defined locally in ${testFile}:
201
301
  - The helper functions are ALREADY IMPLEMENTED and working in those OTHER test files
202
302
  - The helper in the OTHER test file is byte-for-byte usable in ${testFile} without any modification — if a helper would need parameterizing to fit both call sites, it is a near-duplicate and STEP 4b owns it; do NOT process those helpers here
203
303
 
204
- **IF ANY CONDITION IS NOT MET, SKIP TO STEP 6 - DO NOT CREATE ANY UTILS FILES.**
304
+ **IF ANY CONDITION IS NOT MET, SKIP TO ${skipTarget}${seedsUtils ? "" : " - DO NOT CREATE ANY UTILS FILES"}.**
205
305
 
206
306
  **Examples of when to SKIP STEP 5:**
207
307
  - Other test files have identical repetitive code but no helper functions
@@ -212,10 +312,10 @@ For each helper defined locally in ${testFile}:
212
312
  **CRITICAL:** For helpers found in STEP 4:
213
313
  1. **CREATE** \`${fileName}\` file if it doesn't exist with the following header:
214
314
  \`\`\`${ext}
215
- ${generateSkyrampHeader(language)}
315
+ ${generateSkyrampHeader(lang)}
216
316
  \`\`\`
217
317
  **CRITICAL: IF \`${fileName}\` is already big, create a new file with a different name and add the header to the new file.**
218
- 2. **COPY** those local helper functions from original test source files to \`${fileName}\` without modifying them
318
+ 2. **COPY** those local helper functions from original test source files to \`${fileName}\` without modifying them${seedsUtils ? ` — with ONE exception, checked BEFORE the copy: ${policy.assertionRule} Relocate a trailing excluded assertion into the owning test's body first; the copy that lands in \`${fileName}\` carries none.${policy.moveRule ? ` ${policy.moveRule}` : ""}` : ""}
219
319
  3. **DELETE** those local helper functions from test source files (REMOVE THEM COMPLETELY) WITHOUT ANY OTHER CHANGES.
220
320
  4. **IMPORT** those local helper functions from \`${fileName}\` back into test source files WITHOUT MAKING ANY OTHER CHANGE.
221
321
  5. **IMPORT** those local helper functions from \`${fileName}\` into ${testFile}
@@ -224,7 +324,7 @@ For each helper defined locally in ${testFile}:
224
324
  **CRITICAL: DO NOT CREATE UNNECESSARY HELPER FUNCTIONS**
225
325
  **DO NOT CREATE HELPERS BASED ON PATTERNS IN THE CURRENT FILE**
226
326
 
227
- ## STEP 6: VERIFY AND VALIDATE
327
+ ${seedStepBlock}${siblingCallSitesStep}## STEP 6: VERIFY AND VALIDATE
228
328
  1. **BEFORE** making any changes, read the original test file and identify ALL helper functions
229
329
  2. **AFTER** copying helpers to utils, read the original file again to confirm helpers are GONE
230
330
  3. **VERIFY** that helper functions are NO LONGER in original test files
@@ -234,15 +334,15 @@ For each helper defined locally in ${testFile}:
234
334
  6. **VERIFY** that no unnecessary helper functions were created (functions that duplicate existing functionality)
235
335
  7. **VERIFY** that all helper functions in utils are actually imported and used in the test files
236
336
  8. **REMOVE** any helper functions that are not being used after refactoring
237
- 9. **NEVER** refactor, reorganize, or restructure existing source test files beyond moving helpers
337
+ 9. **NEVER** refactor, reorganize, or restructure existing source test files beyond moving helpers${inlineRequestRule ? " — and, in this flow, replacing an inline request block with a call to the shared helper it duplicates (STEP 3 / STEP 5c)" : ""}
238
338
  10. **RUN TESTS** to ensure functionality is preserved after refactoring
239
339
 
240
- **FINAL REMINDER: DO NOT CREATE HELPER FUNCTIONS FROM SCRATCH**
241
- **ONLY MOVE EXISTING HELPERS FROM OTHER TEST FILES**
340
+ **FINAL REMINDER: DO NOT CREATE HELPER FUNCTIONS FROM SCRATCH**
341
+ ${finalReminderScope}
242
342
 
243
343
  **IMPORTANT NOTES:**
244
344
  - The process is designed to REUSE existing helper functions, not create new ones
245
- - If no existing helpers are found, the test file should remain unchanged
345
+ - ${seedsUtils ? `If no existing helpers are found in utils or sibling tests, STEP 5b still moves this test's own helpers into \`${fileName}\` and imports them back — that is the expected first-run outcome, not a no-op` : "If no existing helpers are found, the test file should remain unchanged"}
246
346
  - Code reuse is about moving existing, working helper functions between files
247
347
  - Never create helper functions based on patterns you see in the current test file
248
348
  - Helper functions must have explicit function signatures/definitions
@@ -251,11 +351,16 @@ For each helper defined locally in ${testFile}:
251
351
  **DECISION TREE:**
252
352
  1. Found existing utils file with helpers? → Import and use them (Step 3)
253
353
  2. Found other test files with ACTUAL helper functions? → Move to utils (Step 5)
254
- 3. Found other test files with only repetitive patterns? → SKIP to Step 6, NO utils file
255
- 4. Found no other test files? → SKIP to Step 6, NO utils file
256
- 5. Other test files identical to current? → SKIP to Step 6, NO utils file
354
+ ${decisionTreeTail}
355
+
356
+ ${modularizationTail}
257
357
 
258
- **MANDATORY**: After code reuse is complete, proceed to modularization by calling skyramp_modularization tool ONLY for UI, E2E, INTEGRATION or LOAD test types generated from traces.
358
+ ${
359
+ // Gated with the debt it describes: with SkyrampUtils reuse off nothing refuses, and
360
+ // this text would send the agent to spend a call being told the feature is disabled.
361
+ isUtilsReuseEnabled()
362
+ ? `**MANDATORY FINAL STEP — VERIFY**: once every edit above is written, call skyramp_reuse_code again with the SAME testFile, language, framework and testType and \`verify: true\`. It stages the shared utils file for the output commit and checks its invariants (for API helpers: one helper per method+path, status-code-only assertions, method+resource names; for browser helpers: actions and structural waits only, intent names). Resolve anything it reports and re-verify; finish only when it reports PASSED. It passes immediately when no utils file was written. skyramp_enhance_assertions and skyramp_execute_test refuse this test until that verify pass has run.\n`
363
+ : ""}
259
364
 
260
365
  SUMMARIZE THE CODE REUSE PROCESS AND THE RESULTS.
261
366
  `;
@@ -1 +1,3 @@
1
1
  export declare function getModularizationPrompt(filePath: string): string;
2
+ /** Structured view of which steps render for the given inputs (for tests). */
3
+ export declare function previewModularizationPlan(filePath: string): import("../test-recommendation/promptPlan.js").PlanPreview;
@@ -1,44 +1,44 @@
1
- export function getModularizationPrompt(filePath) {
2
- return `# INTEGRATION TEST MODULARIZATION - SIMPLE AND SAFE
3
-
4
- **CRITICAL: Use the 'write' tool to save the modularized code to: ${filePath}**
5
- **DO NOT use search_replace - use the 'write' tool to overwrite the entire file with the modularized version**
6
-
7
- **ABSOLUTELY FORBIDDEN:**
8
- - DO NOT CREATE ANY INTERFACES, CLASSES, TYPES, OR NEW DATA STRUCTURES. USE INLINE TYPES ONLY.
9
- - DO NOT CREATE/UPDATE package.json or requirements.txt or pom.xml or build.gradle file
10
- - DO NOT CHANGE TEST LOGIC, DATA VALUES, ASSERTIONS, OR API CALLS
11
- - DO NOT MODIFY EXPECTED RESPONSES OR STATUS CODES
12
-
13
- ## STEP 1: READ AND UNDERSTAND THE ORIGINAL TEST
14
- **CRITICAL: Before making ANY changes:**
15
- 1. Read ${filePath} completely
1
+ import { isModularizeFirstTarget } from "../../utils/reuseRouting.js";
2
+ import { PromptPlan } from "../test-recommendation/promptPlan.js";
3
+ import { API_HELPERS, ASSERTION_BOUNDARY_RULE_EXTRACT, } from "../shared-helper-policy.js";
4
+ import { renderModularizationPrompt, } from "./render.js";
5
+ // On modularize-first flows (see isModularizeFirstTarget), downstream
6
+ // skyramp_reuse_code consolidates this file's helpers into the shared
7
+ // SkyrampUtils file — so EVERY request step must become a named helper, even
8
+ // when nothing repeats in-file (a linear CRUD scenario calls each endpoint once,
9
+ // so repetition-based extraction yields zero helpers and the utils file can
10
+ // never materialize).
11
+ const _plan = new PromptPlan()
12
+ .addPhase("main", "Integration Test Modularization", {
13
+ headerLevel: "hidden",
14
+ stepFormat: "hash",
15
+ })
16
+ .step("READ", "READ AND UNDERSTAND THE ORIGINAL TEST", (p) => `**CRITICAL: Before making ANY changes:**
17
+ 1. Read ${p.filePath} completely
16
18
  2. Identify all API endpoints and their parameters
17
19
  3. Identify all test data (request bodies, expected responses)
18
20
  4. Identify all assertions and expected values
19
21
  5. Document the test flow
20
- 6. **DO NOT PROCEED** until you fully understand what the test does
21
-
22
- ## STEP 2: FIND REPETITIVE CODE
23
- Look for API calls that repeat 2+ times with IDENTICAL structure but different data.
24
-
25
- ## STEP 3: CREATE HELPER FUNCTIONS - EXTRACT ONLY, NO CHANGES
26
-
27
- **GOLDEN RULE: COPY-PASTE THE ORIGINAL CODE INTO HELPERS, JUST ADD PARAMETERS AND REPLACE HARDCODED VALUES WITH PARAMETERS**
22
+ 6. **DO NOT PROCEED** until you fully understand what the test does`)
23
+ .step("IDENTIFY", (p) => (p.utilsReuse ? "IDENTIFY REQUEST STEPS" : "FIND REPETITIVE CODE"), (p) => p.utilsReuse
24
+ ? `A request step = one API call plus the assertions that verify its response.
25
+ This project consolidates test helpers into a shared utils file, so EVERY request step becomes a named helper function — the step does NOT need to repeat.
26
+ List every request step in the test (e.g. create product, create order, update order, get order).`
27
+ : `Look for API calls that repeat 2+ times with IDENTICAL structure but different data.`)
28
+ .step("EXTRACT", "CREATE HELPER FUNCTIONS - EXTRACT ONLY, NO CHANGES", (p) => `**GOLDEN RULE: COPY-PASTE THE ORIGINAL CODE INTO HELPERS, JUST ADD PARAMETERS AND REPLACE HARDCODED VALUES WITH PARAMETERS**
28
29
 
29
30
  **CRITICAL RULES:**
30
31
  1. **EXACT CODE COPY** - Copy the API call code EXACTLY as-is from the original test
31
- 2. **ONLY ADD PARAMETERS** - The ONLY change allowed is converting hardcoded values to parameters
32
+ 2. **ONLY ADD PARAMETERS** - The ONLY change allowed is converting hardcoded values to parameters${p.utilsReuse
33
+ ? " — plus ONE placement exception: a response-body assertion that would land inside a helper is placed in the test body, applied to the response the helper returns (same check, same expected value, same relative order). That relocation is the only assertion move allowed; see HELPER SHAPE below"
34
+ : ""}
32
35
  3. **NEVER GENERALIZE SELECTORS** - Keep all selectors/locators exactly as they are in the original code (do not refactor into dynamic template strings)
33
- 4. **NO LOGIC CHANGES** - Do not modify conditions, validations, or assertions
36
+ 4. **NO LOGIC CHANGES** - Do not modify conditions, validations, or assertions${p.utilsReuse ? " (relocating a body assertion per rule 2 is a placement, not a change)" : ""}
34
37
  5. **NO DATA CHANGES** - Do not change any request/response values or expected results
35
38
  6. **PRESERVE PATH PARAMETERS** - API path parameters must be passed as function parameters
36
39
  7. **PRESERVE ORDER** - Keep all operations in the exact same order
37
40
 
38
- **PARAMETER CONVERSION RULES:**
39
- - Find the values that DIFFER between repetitions (e.g., user IDs, product names)
40
- - Make ONLY those differing values into parameters
41
- - Keep everything else EXACTLY the same
41
+ ${p.utilsReuse ? sharedHelperShape(p) : repetitionParameterRules()}
42
42
 
43
43
  **EXAMPLE OF CORRECT EXTRACTION:**
44
44
  \`\`\`typescript
@@ -49,12 +49,18 @@ expect(response1.status).toBe(200);
49
49
  const response2 = await fetch("/api/users/2");
50
50
  expect(response2.status).toBe(200);
51
51
 
52
- // Correct helper (EXACT copy + parameters):
53
- async function getUser(userId: number) {
52
+ // Correct helper (EXACT copy + parameters${p.utilsReuse ? "; the expected status is a defaulted parameter per HELPER SHAPE" : ""}):
53
+ ${p.utilsReuse
54
+ ? `async function getUser(userId: number, expectedStatus = 200) {
55
+ const response = await fetch(\`/api/users/\${userId}\`);
56
+ expect(response.status).toBe(expectedStatus);
57
+ return response;
58
+ }`
59
+ : `async function getUser(userId: number) {
54
60
  const response = await fetch(\`/api/users/\${userId}\`);
55
61
  expect(response.status).toBe(200);
56
62
  return response;
57
- }
63
+ }`}
58
64
  \`\`\`
59
65
 
60
66
  **WHAT NOT TO DO:**
@@ -64,14 +70,9 @@ Modifying expected status codes
64
70
  Changing request/response validation
65
71
  Reordering operations
66
72
  "Improving" error handling
67
- Adding new assertions
68
-
69
- ## STEP 4: USE HELPERS WITH EXACT SAME DATA
70
- When calling the helpers, use the EXACT same values from the original test.
71
-
72
- ## STEP 5: FINAL VERIFICATION
73
-
74
- **BEFORE WRITING ANY CODE, VERIFY:**
73
+ Adding new assertions`)
74
+ .step("USE", "USE HELPERS WITH EXACT SAME DATA", () => `When calling the helpers, use the EXACT same values from the original test.`)
75
+ .step("VERIFY", "FINAL VERIFICATION", () => `**BEFORE WRITING ANY CODE, VERIFY:**
75
76
  - [ ] I have read and understood the original test completely
76
77
  - [ ] I have identified all API calls and their parameters
77
78
  - [ ] I have documented all expected responses and assertions
@@ -91,5 +92,46 @@ Run through the modularized test mentally:
91
92
  2. Does it use the exact same request data?
92
93
  3. Does it expect the exact same responses?
93
94
 
94
- If ANY answer is "no", DO NOT submit - fix the modularization first.`;
95
+ If ANY answer is "no", DO NOT submit - fix the modularization first.`)
96
+ .done();
97
+ // Shared-file helper shape: the helpers this step creates are consolidated into
98
+ // SkyrampUtils by the reuse pass, so each one must be nameable and callable by
99
+ // the next scenario — canonical names, scenario values as arguments, and no
100
+ // scenario-specific claims inside the helper.
101
+ function sharedHelperShape(p) {
102
+ return `**HELPER SHAPE (one helper per request step from Step ${_plan.labels.IDENTIFY}):**
103
+ - ${API_HELPERS.namingRule}
104
+ - **PARAMETERS**: pass in the client/session object, plus every value the step reads from a previous step's response (IDs used in paths or bodies), plus every body value this scenario varies or its assertions reference (names, prices, quantities, percentages). Values that never vary and that no assertion reads may stay hardcoded — do not invent parameters nothing passes differently.
105
+ - **SCENARIO VALUES GO THROUGH \`data_override\`, NOT THE BODY STRING**: apply each parameterized body value via the request's \`data_override\` map (that is what it is for) and leave the raw body string as generated. A scenario literal edited into the body string makes this helper unmergeable with the same step from another test.
106
+ - **RETURN** the response object so later steps can chain and assert from it.
107
+ - ${API_HELPERS.assertionRule} ${ASSERTION_BOUNDARY_RULE_EXTRACT}
108
+ - Helpers are module-level named functions in ${p.filePath}; the test body becomes a sequence of helper calls plus this scenario's assertions, in the original order.
109
+ - Keep everything else EXACTLY the same.`;
110
+ }
111
+ function repetitionParameterRules() {
112
+ return `**PARAMETER CONVERSION RULES:**
113
+ - Find the values that DIFFER between repetitions (e.g., user IDs, product names)
114
+ - Make ONLY those differing values into parameters
115
+ - Keep everything else EXACTLY the same`;
116
+ }
117
+ export function getModularizationPrompt(filePath) {
118
+ const utilsReuse = isModularizeFirstTarget("integration");
119
+ return renderModularizationPrompt({
120
+ title: "INTEGRATION TEST MODULARIZATION - SIMPLE AND SAFE",
121
+ forbidden: [
122
+ "DO NOT CREATE ANY INTERFACES, CLASSES, TYPES, OR NEW DATA STRUCTURES. USE INLINE TYPES ONLY.",
123
+ "DO NOT CREATE/UPDATE package.json or requirements.txt or pom.xml or build.gradle file",
124
+ `DO NOT CHANGE TEST LOGIC, DATA VALUES, ASSERTIONS, OR API CALLS${utilsReuse ? " (moving a response-body assertion out of a helper into the test body, verbatim, is a placement — not a change)" : ""}`,
125
+ "DO NOT MODIFY EXPECTED RESPONSES OR STATUS CODES",
126
+ ],
127
+ plan: _plan,
128
+ params: { filePath, utilsReuse },
129
+ });
130
+ }
131
+ /** Structured view of which steps render for the given inputs (for tests). */
132
+ export function previewModularizationPlan(filePath) {
133
+ return _plan.preview({
134
+ filePath,
135
+ utilsReuse: isModularizeFirstTarget("integration"),
136
+ });
95
137
  }
@@ -0,0 +1,18 @@
1
+ import type { PromptPlan } from "../test-recommendation/promptPlan.js";
2
+ /**
3
+ * Parameters both modularization plans render against.
4
+ * `utilsReuse` is true on modularize-first flows (see isModularizeFirstTarget):
5
+ * downstream skyramp_reuse_code consolidates this file's helpers into the shared
6
+ * SkyrampUtils file, which changes what a helper may be named and may assert.
7
+ */
8
+ export interface ModularizationParams {
9
+ filePath: string;
10
+ utilsReuse: boolean;
11
+ }
12
+ /** The scaffold shared by the UI and integration modularization prompts. */
13
+ export declare function renderModularizationPrompt(opts: {
14
+ title: string;
15
+ forbidden: string[];
16
+ plan: PromptPlan<ModularizationParams>;
17
+ params: ModularizationParams;
18
+ }): string;
@@ -0,0 +1,12 @@
1
+ /** The scaffold shared by the UI and integration modularization prompts. */
2
+ export function renderModularizationPrompt(opts) {
3
+ return `# ${opts.title}
4
+
5
+ **CRITICAL: Use the 'write' tool to save the modularized code to: ${opts.params.filePath}**
6
+ **DO NOT use search_replace - use the 'write' tool to overwrite the entire file with the modularized version**
7
+
8
+ **ABSOLUTELY FORBIDDEN:**
9
+ ${opts.forbidden.map((f) => `- ${f}`).join("\n")}
10
+
11
+ ${opts.plan.render(opts.params)}`;
12
+ }
@@ -1 +1,3 @@
1
- export declare function getModularizationPrompt(filePath: string): string;
1
+ export declare function getModularizationPrompt(filePath: string, testType: string, language?: string): string;
2
+ /** Structured view of which steps render for the given inputs (for tests). */
3
+ export declare function previewModularizationPlan(filePath: string, testType: string, language?: string): import("../test-recommendation/promptPlan.js").PlanPreview;