@skyramp/mcp 0.2.6 → 0.2.150-rc.mntnc

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 (233) hide show
  1. package/build/commands/commandLibrary.d.ts +12 -0
  2. package/build/commands/recommendTestsAndExecuteCommand.d.ts +2 -0
  3. package/build/commands/testThisEndpointCommand.d.ts +2 -0
  4. package/build/index.d.ts +2 -0
  5. package/build/index.js +6 -4
  6. package/build/playwright/PlaywrightTraceService.d.ts +32 -0
  7. package/build/playwright/index.d.ts +3 -0
  8. package/build/playwright/registerPlaywrightTools.d.ts +8 -0
  9. package/build/playwright/registerPlaywrightTools.js +12 -11
  10. package/build/playwright/traceRecordingPrompt.d.ts +13 -0
  11. package/build/playwright/traceRecordingPrompt.js +3 -11
  12. package/build/prompts/code-reuse.d.ts +1 -0
  13. package/build/prompts/enhance-assertions/contractProviderAssertionsPrompt.d.ts +2 -0
  14. package/build/prompts/enhance-assertions/integrationAssertionsPrompt.d.ts +2 -0
  15. package/build/prompts/enhance-assertions/sharedAssertionRules.d.ts +15 -0
  16. package/build/prompts/enhance-assertions/uiAssertionsPrompt.d.ts +2 -0
  17. package/build/prompts/enhance-assertions/uiAssertionsPrompt.js +24 -5
  18. package/build/prompts/fix-error-prompt.d.ts +1 -0
  19. package/build/prompts/initialize-workspace/initializeWorkspacePrompt.d.ts +1 -0
  20. package/build/prompts/modularization/integration-test-modularization.d.ts +1 -0
  21. package/build/prompts/modularization/ui-test-modularization.d.ts +1 -0
  22. package/build/prompts/personas.d.ts +21 -0
  23. package/build/prompts/pom-aware-code-reuse.d.ts +1 -0
  24. package/build/prompts/startTraceCollectionPrompts.d.ts +2 -0
  25. package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.d.ts +2 -0
  26. package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.js +114 -0
  27. package/build/prompts/sut-setup/modes/dockerComposePrompt.d.ts +2 -0
  28. package/build/prompts/sut-setup/modes/dockerComposePrompt.js +292 -0
  29. package/build/prompts/sut-setup/shared.d.ts +39 -0
  30. package/build/prompts/sut-setup/shared.js +132 -0
  31. package/build/prompts/test-maintenance/actionsInstructions.d.ts +35 -0
  32. package/build/prompts/test-maintenance/drift-analysis-prompt.d.ts +4 -0
  33. package/build/prompts/test-maintenance/driftAnalysisSections.d.ts +13 -0
  34. package/build/prompts/test-maintenance/driftAnalysisSections.js +9 -3
  35. package/build/prompts/test-recommendation/analysisOutputPrompt.d.ts +84 -0
  36. package/build/prompts/test-recommendation/analysisOutputPrompt.js +1 -1
  37. package/build/prompts/test-recommendation/analysisOutputPrompt.test.d.ts +1 -0
  38. package/build/prompts/test-recommendation/analysisOutputPrompt.test.js +1 -0
  39. package/build/prompts/test-recommendation/diffExecutionPlan.d.ts +17 -0
  40. package/build/prompts/test-recommendation/diffExecutionPlan.js +7 -16
  41. package/build/prompts/test-recommendation/fullRepoCatalog.d.ts +7 -0
  42. package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.d.ts +1 -0
  43. package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.js +1 -0
  44. package/build/prompts/test-recommendation/promptPlan.d.ts +203 -0
  45. package/build/prompts/test-recommendation/promptPlan.test.d.ts +1 -0
  46. package/build/prompts/test-recommendation/recommendationSections.d.ts +35 -0
  47. package/build/prompts/test-recommendation/recommendationShared.d.ts +31 -0
  48. package/build/prompts/test-recommendation/registerRecommendTestsPrompt.d.ts +7 -0
  49. package/build/prompts/test-recommendation/scopeAssessment.d.ts +55 -0
  50. package/build/prompts/test-recommendation/scopeAssessment.js +2 -2
  51. package/build/prompts/test-recommendation/scopeAssessment.test.d.ts +1 -0
  52. package/build/prompts/test-recommendation/scopeAssessment.test.js +1 -0
  53. package/build/prompts/test-recommendation/test-recommendation-prompt.d.ts +6 -0
  54. package/build/prompts/test-recommendation/test-recommendation-prompt.js +4 -4
  55. package/build/prompts/test-recommendation/test-recommendation-prompt.test.d.ts +1 -0
  56. package/build/prompts/test-recommendation/test-recommendation-prompt.test.js +6 -99
  57. package/build/prompts/testbot/testbot-prompts.d.ts +11 -0
  58. package/build/prompts/testbot/testbot-prompts.js +213 -42
  59. package/build/prompts/testbot/testbot-prompts.test.d.ts +1 -0
  60. package/build/prompts/testbot/testbot-prompts.test.js +15 -117
  61. package/build/resources/analysisResources.d.ts +17 -0
  62. package/build/resources/progressResource.d.ts +2 -0
  63. package/build/resources/sutSetupResource.d.ts +2 -0
  64. package/build/resources/sutSetupResource.js +45 -0
  65. package/build/resources/testbotResource.d.ts +2 -0
  66. package/build/resources/testbotResource.js +1 -1
  67. package/build/services/AnalyticsService.d.ts +13 -0
  68. package/build/services/AnalyticsService.test.d.ts +1 -0
  69. package/build/services/AnalyticsService.test.js +86 -0
  70. package/build/services/ModularizationService.d.ts +11 -0
  71. package/build/services/ScenarioGenerationService.d.ts +37 -0
  72. package/build/services/ScenarioGenerationService.integration.test.d.ts +1 -0
  73. package/build/services/ScenarioGenerationService.integration.test.js +4 -0
  74. package/build/services/ScenarioGenerationService.test.d.ts +1 -0
  75. package/build/services/TestDiscoveryService.d.ts +128 -0
  76. package/build/services/TestDiscoveryService.js +22 -12
  77. package/build/services/TestDiscoveryService.test.d.ts +1 -0
  78. package/build/services/TestDiscoveryService.test.js +4 -3
  79. package/build/services/TestExecutionService.d.ts +55 -0
  80. package/build/services/TestExecutionService.js +158 -26
  81. package/build/services/TestExecutionService.test.d.ts +1 -0
  82. package/build/services/TestExecutionService.test.js +339 -25
  83. package/build/services/TestGenerationService.d.ts +56 -0
  84. package/build/services/TestGenerationService.test.d.ts +1 -0
  85. package/build/services/TestGenerationService.test.js +10 -8
  86. package/build/services/containerEnv.d.ts +14 -0
  87. package/build/tool-phase-coverage.test.d.ts +1 -0
  88. package/build/tool-phase-coverage.test.js +2 -0
  89. package/build/tool-phases.d.ts +38 -0
  90. package/build/tools/auth/loginTool.d.ts +2 -0
  91. package/build/tools/auth/logoutTool.d.ts +2 -0
  92. package/build/tools/code-refactor/codeReuseTool.d.ts +2 -0
  93. package/build/tools/code-refactor/enhanceAssertionsTool.d.ts +2 -0
  94. package/build/tools/code-refactor/modularizationTool.d.ts +2 -0
  95. package/build/tools/executeSkyrampTestTool.d.ts +2 -0
  96. package/build/tools/executeSkyrampTestTool.js +17 -4
  97. package/build/tools/fixErrorTool.d.ts +2 -0
  98. package/build/tools/generate-tests/generateBatchScenarioRestTool.d.ts +45 -0
  99. package/build/tools/generate-tests/generateBatchScenarioRestTool.js +1 -1
  100. package/build/tools/generate-tests/generateBatchScenarioRestTool.test.d.ts +1 -0
  101. package/build/tools/generate-tests/generateBatchScenarioRestTool.test.js +11 -9
  102. package/build/tools/generate-tests/generateContractRestTool.d.ts +31 -0
  103. package/build/tools/generate-tests/generateE2ERestTool.d.ts +13 -0
  104. package/build/tools/generate-tests/generateFuzzRestTool.d.ts +10 -0
  105. package/build/tools/generate-tests/generateIntegrationRestTool.d.ts +16 -0
  106. package/build/tools/generate-tests/generateLoadRestTool.d.ts +18 -0
  107. package/build/tools/generate-tests/generateLoadRestTool.test.d.ts +1 -0
  108. package/build/tools/generate-tests/generateMockRestTool.d.ts +64 -0
  109. package/build/tools/generate-tests/generateSmokeRestTool.d.ts +8 -0
  110. package/build/tools/generate-tests/generateUIRestTool.d.ts +14 -0
  111. package/build/tools/generate-tests/generateUIRestTool.js +1 -1
  112. package/build/tools/generate-tests/loadTestSchema.d.ts +39 -0
  113. package/build/tools/one-click/oneClickTool.d.ts +11 -0
  114. package/build/tools/submitReportTool.d.ts +384 -0
  115. package/build/tools/submitReportTool.js +225 -37
  116. package/build/tools/submitReportTool.test.d.ts +1 -0
  117. package/build/tools/submitReportTool.test.js +479 -55
  118. package/build/tools/test-management/actionsTool.d.ts +10 -0
  119. package/build/tools/test-management/actionsTool.js +10 -0
  120. package/build/tools/test-management/analyzeChangesTool.d.ts +26 -0
  121. package/build/tools/test-management/analyzeChangesTool.js +128 -48
  122. package/build/tools/test-management/analyzeChangesTool.test.d.ts +1 -0
  123. package/build/tools/test-management/analyzeChangesTool.test.js +80 -73
  124. package/build/tools/test-management/analyzeTestHealthTool.d.ts +2 -0
  125. package/build/tools/test-management/analyzeTestHealthTool.js +6 -3
  126. package/build/tools/test-management/index.d.ts +3 -0
  127. package/build/tools/test-management/index.js +0 -1
  128. package/build/tools/trace/resolveSaveStoragePath.d.ts +7 -0
  129. package/build/tools/trace/resolveSaveStoragePath.test.d.ts +1 -0
  130. package/build/tools/trace/resolveSessionPaths.d.ts +40 -0
  131. package/build/tools/trace/resolveSessionPaths.test.d.ts +1 -0
  132. package/build/tools/trace/sessionState.d.ts +2 -0
  133. package/build/tools/trace/sessionState.test.d.ts +1 -0
  134. package/build/tools/trace/startTraceCollectionTool.d.ts +2 -0
  135. package/build/tools/trace/stopTraceCollectionTool.d.ts +2 -0
  136. package/build/tools/workspace/initScanWorkspaceTool.d.ts +4 -0
  137. package/build/tools/workspace/initializeWorkspaceTool.d.ts +2 -0
  138. package/build/tools/workspace/initializeWorkspaceTool.test.d.ts +1 -0
  139. package/build/tools/workspace/initializeWorkspaceTool.test.js +134 -0
  140. package/build/types/OneClickCommands.d.ts +68 -0
  141. package/build/types/RepositoryAnalysis.d.ts +3004 -0
  142. package/build/types/TestAnalysis.d.ts +97 -0
  143. package/build/types/TestExecution.d.ts +63 -0
  144. package/build/types/TestExecution.js +11 -1
  145. package/build/types/TestRecommendation.d.ts +12 -0
  146. package/build/types/TestTypes.d.ts +234 -0
  147. package/build/types/TestbotReport.d.ts +68 -0
  148. package/build/types/TestbotReport.js +1 -0
  149. package/build/types/index.d.ts +4 -0
  150. package/build/types/index.js +3 -0
  151. package/build/utils/AnalysisStateManager.d.ts +182 -0
  152. package/build/utils/AnalysisStateManager.js +10 -1
  153. package/build/utils/AnalysisStateManager.test.d.ts +1 -0
  154. package/build/utils/analyze-openapi.d.ts +1 -0
  155. package/build/utils/branchDiff.d.ts +18 -0
  156. package/build/utils/dartRouteExtractor.d.ts +45 -0
  157. package/build/utils/dartRouteExtractor.test.d.ts +1 -0
  158. package/build/utils/docker.d.ts +19 -0
  159. package/build/utils/docker.test.d.ts +1 -0
  160. package/build/utils/docker.test.js +10 -9
  161. package/build/utils/featureFlags.d.ts +37 -0
  162. package/build/utils/featureFlags.test.d.ts +1 -0
  163. package/build/utils/gitStaging.d.ts +24 -0
  164. package/build/utils/gitStaging.test.d.ts +1 -0
  165. package/build/utils/gitStaging.test.js +13 -7
  166. package/build/utils/httpDefaults.d.ts +10 -0
  167. package/build/utils/httpDefaults.test.d.ts +1 -0
  168. package/build/utils/initAgent.d.ts +36 -0
  169. package/build/utils/language-helper.d.ts +6 -0
  170. package/build/utils/logger.d.ts +11 -0
  171. package/build/utils/normalizeParams.d.ts +14 -0
  172. package/build/utils/normalizeSkyrampImports.d.ts +13 -0
  173. package/build/utils/pr-comment-parser.d.ts +31 -0
  174. package/build/utils/pr-comment-parser.test.d.ts +1 -0
  175. package/build/utils/pr-comment-parser.test.js +6 -5
  176. package/build/utils/projectMetadata.d.ts +15 -0
  177. package/build/utils/projectMetadata.test.d.ts +1 -0
  178. package/build/utils/proxy-terminal.d.ts +2 -0
  179. package/build/utils/repoScanner.d.ts +27 -0
  180. package/build/utils/repoScanner.test.d.ts +1 -0
  181. package/build/utils/routeParsers.d.ts +53 -0
  182. package/build/utils/routeParsers.js +31 -38
  183. package/build/utils/routeParsers.test.d.ts +1 -0
  184. package/build/utils/scenarioDrafting.d.ts +71 -0
  185. package/build/utils/scenarioDrafting.js +23 -1
  186. package/build/utils/scenarioDrafting.test.d.ts +1 -0
  187. package/build/utils/skyrampMdContent.d.ts +5 -0
  188. package/build/utils/sourceRouteExtractor.d.ts +48 -0
  189. package/build/utils/sourceRouteExtractor.test.d.ts +1 -0
  190. package/build/utils/telemetry.d.ts +32 -0
  191. package/build/utils/telemetry.test.d.ts +1 -0
  192. package/build/utils/trace-parser.d.ts +32 -0
  193. package/build/utils/trace-parser.test.d.ts +6 -0
  194. package/build/utils/uiPageEnumerator.d.ts +146 -0
  195. package/build/utils/uiPageEnumerator.js +58 -14
  196. package/build/utils/uiPageEnumerator.test.d.ts +1 -0
  197. package/build/utils/uiPageEnumerator.test.js +223 -43
  198. package/build/utils/utils.d.ts +45 -0
  199. package/build/utils/utils.js +10 -0
  200. package/build/utils/utils.test.d.ts +1 -0
  201. package/build/utils/versions.d.ts +3 -0
  202. package/build/utils/versions.js +1 -1
  203. package/build/utils/workspaceAuth.d.ts +127 -0
  204. package/build/utils/workspaceAuth.test.d.ts +1 -0
  205. package/build/utils/workspaceAuth.test.js +25 -25
  206. package/build/workspace/index.d.ts +1 -0
  207. package/build/workspace/workspace.d.ts +390 -0
  208. package/build/workspace/workspace.test.d.ts +1 -0
  209. package/node_modules/playwright/LICENSE +202 -0
  210. package/node_modules/playwright/NOTICE +5 -0
  211. package/node_modules/playwright/README.md +168 -0
  212. package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +13 -9
  213. package/node_modules/playwright/lib/mcp/test/skyRampExport.js +4 -3
  214. package/node_modules/playwright/node_modules/playwright-core/LICENSE +202 -0
  215. package/node_modules/playwright/node_modules/playwright-core/NOTICE +5 -0
  216. package/node_modules/playwright/node_modules/playwright-core/ThirdPartyNotices.txt +23 -126
  217. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/{codeMirrorModule-B0JOjboO.js → codeMirrorModule-B5kqh2EV.js} +1 -1
  218. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/{defaultSettingsView-1anWeyDf.js → defaultSettingsView-CZ9npQ3N.js} +79 -79
  219. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{index.Cc5029a3.js → index.BCnxj-_b.js} +1 -1
  220. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.html +2 -2
  221. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{uiMode.Wo5yvvVh.js → uiMode.1Ym0Ivn8.js} +1 -1
  222. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.html +2 -2
  223. package/node_modules/playwright/node_modules/playwright-core/package.json +1 -1
  224. package/node_modules/playwright/package.json +1 -1
  225. package/package.json +16 -4
  226. package/build/tools/test-management/uiAnalyzeChangesTool.js +0 -155
  227. package/build/tools/test-management/uiAnalyzeChangesTool.test.js +0 -147
  228. package/node_modules/playwright/node_modules/playwright-core/.DS_Store +0 -0
  229. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/.bin/node-which +0 -52
  230. package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/.bin/is-docker +0 -5
  231. package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/.bin/mime +0 -46
  232. package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/.bin/yaml +0 -11
  233. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.CP3Y8Zsb.js +0 -2
@@ -0,0 +1,292 @@
1
+ import { buildContextBlock, buildInputsBody, buildCommonSutErrorsSection, buildLocalValidationSection, buildSutDefinitionBlock, } from "../shared.js";
2
+ import { getPersonaPrefix } from "../../personas.js";
3
+ import { PromptPlan } from "../../test-recommendation/promptPlan.js";
4
+ // ── Step body builders ────────────────────────────────────────────────────────
5
+ function buildScanComposeBody(args) {
6
+ const composeFile = args.sutSourceDockerComposeFile?.trim();
7
+ if (composeFile) {
8
+ return `A specific compose file was provided: \`${composeFile}\`. Use it directly — do NOT scan for other compose files and do NOT generate a new one. (Strategy in Step 2 will be REUSE with this file.)`;
9
+ }
10
+ return `Search the repository for existing docker-compose files:
11
+ - \`docker-compose.yml\`, \`docker-compose.yaml\`, \`compose.yml\`, \`compose.yaml\` at root
12
+ - \`docker-compose.*.yml\` variants (e.g., \`docker-compose.dev.yml\`, \`docker-compose.e2e.yml\`)
13
+ - Compose files in subdirectories (\`deploy/\`, \`.docker/\`, etc.)
14
+
15
+ For each compose file found, determine if it is:
16
+ - **Application compose** — builds or runs the actual backend API / frontend UI (has \`build:\` directives pointing to repo source, or services that are the app's entry points). USE THIS.
17
+ - **Infrastructure-only compose** — contains only databases, Redis, message queues, mail servers, object storage. NOT sufficient for SUT setup alone.`;
18
+ }
19
+ function buildDecideStrategyBody(args) {
20
+ const composeFile = args.sutSourceDockerComposeFile?.trim();
21
+ if (composeFile) {
22
+ return `A specific compose file was provided in Step 1 (\`${composeFile}\`). Strategy is REUSE with this file. Confirm your decision:
23
+
24
+ \`\`\`
25
+ Decision: REUSE
26
+ Compose file: ${composeFile}
27
+ Reason: provided by the user
28
+ \`\`\``;
29
+ }
30
+ return `Choose between reuse and generate based on what Step 1 found:
31
+ - If an application docker-compose file was found → strategy is REUSE.
32
+ - If only infrastructure-only compose files exist, or no compose files found → strategy is GENERATE.
33
+
34
+ Output your decision:
35
+ \`\`\`
36
+ Decision: REUSE | GENERATE
37
+ Compose file: <path to file if reusing, or "none" if generating>
38
+ Reason: <brief explanation>
39
+ \`\`\``;
40
+ }
41
+ function buildPrAccurateSutSection() {
42
+ return `The SUT must run code from the PR branch, not a pre-built upstream image. Determine how to build the application from the PR source:
43
+
44
+ 1. If the repo uses Docker images for deployment (e.g., \`SERVER_IMAGE\` env var in compose), then build a local image from the PR code and use it. Do NOT use commit-SHA-tagged images from upstream registries (those only exist for the upstream repo's CI, not for forks or testbot PRs).
45
+ 2. If the repo builds from source (Go binary, Node app, Python package), then include the build step in the workflow before starting services.
46
+ 3. Use a stable base/build image (e.g., the repo's official build container or a standard runtime image).
47
+ 4. The built image or binary stays local to the runner — no registry push needed.`;
48
+ }
49
+ /**
50
+ * Build the reuse instructions body (no section header — the caller supplies it).
51
+ * When `composeFile` is provided the concrete path is interpolated into the
52
+ * `docker compose -f <path>` commands so the agent wires the given file directly;
53
+ * otherwise generic `<path>` placeholders are kept for the discovery flow where
54
+ * the agent picks the file itself.
55
+ */
56
+ function getReuseDockerComposeInstructions(composeFile) {
57
+ const file = composeFile?.trim();
58
+ const ref = file ?? "<path>";
59
+ const intro = file
60
+ ? `Use the provided application docker-compose file \`${file}\` directly. Wire it as \`targetSetupCommand\`.`
61
+ : `You found an existing application docker-compose file. Wire it directly as \`targetSetupCommand\`.`;
62
+ return `${intro}
63
+
64
+ 1. Verify the compose file starts the application (not just infrastructure).
65
+ 2. Determine the correct command:
66
+ - If the compose uses \`build:\` directives: \`docker compose -f ${ref} up -d --build\`
67
+ - If it uses pre-built images: \`docker compose -f ${ref} up -d\`
68
+ - If it has builder services (one-shot build steps): run builders first, then start runtime services.
69
+ 3. Determine the health check command from the compose file's \`healthcheck:\` definitions or from known health endpoints.
70
+ 4. Determine the teardown command: \`docker compose -f ${ref} down -v\`
71
+ 5. If the compose file defines admin credentials in environment variables, create \`.skyramp/sut/get-auth-token.sh\` using those credentials.
72
+
73
+ These resolved commands are wired onto the \`skyramp/testbot\` action step using the input semantics from Step 3 above.`;
74
+ }
75
+ /** Generate instructions used when no reusable application compose file exists. */
76
+ const GENERATE_DOCKER_COMPOSE_INSTRUCTIONS = `No usable application docker-compose was found. Generate one from scratch.
77
+
78
+ Steps:
79
+ 1. Inspect the repository to determine how to build and run the application:
80
+ - Does it have a Dockerfile? → Use \`build: { context: . }\`
81
+ - No Dockerfile but has package.json? → Use \`node:20-alpine\` base image + volume mount + npm install + start
82
+ - No Dockerfile but has requirements.txt/pyproject.toml? → Use \`python:3.12-slim\` base image + pip install + start
83
+ - No Dockerfile but has pom.xml/build.gradle? → Use appropriate JDK image + build + run
84
+
85
+ 2. Determine database requirements:
86
+ - If app references PostgreSQL → add postgres service with healthcheck
87
+ - If app references MongoDB → add mongo service with replica set
88
+ - If app references Redis → add redis service
89
+ - Prefer SQLite when the app supports it (simpler, no extra service)
90
+
91
+ 3. Generate \`.skyramp/sut/docker-compose.testbot.yml\` with:
92
+ - The compose file must be runnable with: \`docker compose -f .skyramp/sut/docker-compose.testbot.yml --project-directory . up -d --build\`
93
+ - The \`--project-directory .\` means build context is the repository root (NOT .skyramp/sut/)
94
+ - Healthchecks for ALL services (testbot relies on \`--wait\`)
95
+ - Simple testbot credentials in environment (admin@testbot.com / testbot)
96
+ - Generous \`start_period\` (30-120s) for CI cold builds
97
+ - For monorepos: may need a builder service that runs first
98
+
99
+ 4. Generate \`.skyramp/sut/get-auth-token.sh\` if the application requires authentication:
100
+ - Script must output ONLY the token to stdout (debug output to stderr)
101
+ - Poll health endpoint before attempting auth (300s timeout)
102
+ - Credentials must match what's in the docker-compose environment variables
103
+ - Use \`set -euo pipefail\` and \`jq\` for JSON parsing
104
+
105
+ <example label="simple-single-service">
106
+ \`\`\`yaml
107
+ # .skyramp/sut/docker-compose.testbot.yml
108
+ services:
109
+ app:
110
+ build:
111
+ context: .
112
+ dockerfile: Dockerfile
113
+ ports:
114
+ - "8055:8055"
115
+ environment:
116
+ SECRET: testbot-secret
117
+ ADMIN_EMAIL: admin@testbot.com
118
+ ADMIN_PASSWORD: testbot
119
+ DB_CLIENT: sqlite3
120
+ healthcheck:
121
+ test: ["CMD", "curl", "-sf", "http://localhost:8055/health"]
122
+ interval: 5s
123
+ timeout: 5s
124
+ retries: 24
125
+ start_period: 15s
126
+ \`\`\`
127
+ </example>
128
+
129
+ <example label="service-with-postgres">
130
+ \`\`\`yaml
131
+ services:
132
+ postgres:
133
+ image: postgres:16-alpine
134
+ environment:
135
+ POSTGRES_DB: app
136
+ POSTGRES_USER: app
137
+ POSTGRES_PASSWORD: testbot
138
+ healthcheck:
139
+ test: ["CMD-SHELL", "pg_isready -U app"]
140
+ interval: 5s
141
+ timeout: 5s
142
+ retries: 10
143
+
144
+ app:
145
+ build:
146
+ context: .
147
+ ports:
148
+ - "3000:3000"
149
+ environment:
150
+ DATABASE_URL: postgres://app:testbot@postgres/app
151
+ depends_on:
152
+ postgres:
153
+ condition: service_healthy
154
+ healthcheck:
155
+ test: ["CMD", "curl", "-sf", "http://localhost:3000/health"]
156
+ interval: 10s
157
+ timeout: 5s
158
+ retries: 30
159
+ start_period: 30s
160
+ \`\`\`
161
+ </example>
162
+
163
+ <example label="monorepo-with-builder">
164
+ \`\`\`yaml
165
+ services:
166
+ builder:
167
+ image: node:20-alpine
168
+ working_dir: /app
169
+ volumes:
170
+ - .:/app
171
+ command: sh -c "corepack enable && pnpm install --frozen-lockfile && pnpm build"
172
+
173
+ postgres:
174
+ image: postgres:16-alpine
175
+ environment:
176
+ POSTGRES_DB: app
177
+ POSTGRES_USER: app
178
+ POSTGRES_PASSWORD: testbot
179
+ healthcheck:
180
+ test: ["CMD-SHELL", "pg_isready -U app"]
181
+ interval: 5s
182
+ timeout: 5s
183
+ retries: 10
184
+
185
+ backend:
186
+ build: { context: . }
187
+ depends_on:
188
+ builder:
189
+ condition: service_completed_successfully
190
+ postgres:
191
+ condition: service_healthy
192
+ ports:
193
+ - "9000:9000"
194
+ environment:
195
+ DATABASE_URL: postgres://app:testbot@postgres/app
196
+ JWT_SECRET: testbot-jwt-secret
197
+ healthcheck:
198
+ test: ["CMD", "wget", "--spider", "-q", "http://localhost:9000/health"]
199
+ interval: 10s
200
+ timeout: 5s
201
+ retries: 30
202
+ start_period: 90s
203
+
204
+ frontend:
205
+ image: node:20-alpine
206
+ working_dir: /app/apps/web
207
+ volumes:
208
+ - .:/app
209
+ depends_on:
210
+ backend:
211
+ condition: service_healthy
212
+ ports:
213
+ - "3000:3000"
214
+ environment:
215
+ NEXT_PUBLIC_API_URL: http://localhost:9000
216
+ command: sh -c "npm run dev -- --hostname 0.0.0.0 --port 3000"
217
+ healthcheck:
218
+ test: ["CMD-SHELL", "bash -c '</dev/tcp/localhost/3000' || exit 1"]
219
+ interval: 10s
220
+ timeout: 5s
221
+ retries: 30
222
+ start_period: 120s
223
+ \`\`\`
224
+ </example>
225
+
226
+ <example label="source-mount-no-dockerfile">
227
+ \`\`\`yaml
228
+ services:
229
+ app:
230
+ image: python:3.12-slim
231
+ working_dir: /app
232
+ volumes:
233
+ - .:/app
234
+ command: sh -c "pip install -e . && uvicorn main:app --host 0.0.0.0 --port 8000"
235
+ ports:
236
+ - "8000:8000"
237
+ healthcheck:
238
+ test: ["CMD", "curl", "-sf", "http://localhost:8000/health"]
239
+ interval: 10s
240
+ timeout: 5s
241
+ retries: 30
242
+ start_period: 60s
243
+ \`\`\`
244
+ </example>
245
+ `;
246
+ function buildApplyStrategyBody(args) {
247
+ const composeFile = args.sutSourceDockerComposeFile?.trim();
248
+ if (composeFile) {
249
+ return `#### Reuse the provided Docker Compose file
250
+ ${getReuseDockerComposeInstructions(composeFile)}`;
251
+ }
252
+ return `Apply the strategy selected in Step 2:
253
+
254
+ #### If REUSE selected — Reuse existing Docker Compose
255
+ ${getReuseDockerComposeInstructions()}
256
+
257
+ #### If GENERATE selected — Generate new Docker Compose
258
+ ${GENERATE_DOCKER_COMPOSE_INSTRUCTIONS}`;
259
+ }
260
+ // ── PromptPlan declaration ────────────────────────────────────────────────────
261
+ const _composePlan = new PromptPlan()
262
+ .addPhase("compose", "", { headerLevel: "hidden", stepFormat: "hash" })
263
+ .step("SCAN", "Understand the System Under Test in this repository", buildScanComposeBody)
264
+ .step("DECIDE", "Decide SUT setup strategy", buildDecideStrategyBody)
265
+ .step("INPUTS", "Plan the Testbot action inputs", () => buildInputsBody())
266
+ .step("BUILD", "Edit the Testbot workflow and generate SUT files", () => "")
267
+ .subStep("PR_ACCURATE", "Build PR-accurate SUT", buildPrAccurateSutSection)
268
+ .subStep("APPLY", "Apply the chosen strategy", buildApplyStrategyBody)
269
+ .step("VERIFY", "Verify", () => "")
270
+ .subStep("COMMON_ERRORS", "Common SUT errors", () => buildCommonSutErrorsSection())
271
+ .subStep("LOCAL_VALIDATION", "Local validation", () => buildLocalValidationSection())
272
+ .done();
273
+ export function getDockerComposePrompt(args) {
274
+ const composeFile = args.sutSourceDockerComposeFile?.trim();
275
+ const taskLine = composeFile
276
+ ? `Your task is to find a working System Under Test (SUT) setup using the given Docker Compose file \`${composeFile}\`. You will reuse this file, validate that services start correctly, fix any errors, and wire the working commands into the testbot workflow.`
277
+ : `Your task is to find a working System Under Test (SUT) setup using Docker Compose that builds and deploys the services in this repository. You will either reuse an existing docker-compose file or generate a new one, validate that services start correctly, fix any errors, and wire the working commands into the testbot workflow.`;
278
+ const thinkingStep = composeFile
279
+ ? `1. Output a <thinking> block to explain how the provided compose file \`${composeFile}\` starts the application and what commands are needed to bring it up.`
280
+ : `1. Output a <thinking> block to explain whether you found an existing compose file, whether it is application or infrastructure-only, and your decision to reuse or generate.`;
281
+ return `${getPersonaPrefix()}${taskLine}
282
+
283
+ ${buildSutDefinitionBlock()}The testbot installer has already created a basic \`.github/workflows/skyramp-testbot.yml\` in this PR with no SUT setup commands. Manage the SUT lifecycle exclusively through inputs on the existing \`skyramp/testbot\` action step — do NOT add separate GHA setup/teardown steps and do NOT set \`skipTargetSetup\`.
284
+
285
+ Before generating any files, you MUST:
286
+ ${thinkingStep}
287
+ 2. Then proceed with the instructions below.
288
+ ${buildContextBlock(args)}
289
+
290
+ ${_composePlan.render(args)}
291
+ `;
292
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Path of the Testbot workflow file relative to the repo root. Created by the
3
+ * Testbot installer and edited in-place by every SUT setup mode.
4
+ */
5
+ export declare const TESTBOT_WORKFLOW_PATH = ".github/workflows/skyramp-testbot.yml";
6
+ export declare enum SutSetupMode {
7
+ None = "none",
8
+ AdaptWorkflow = "adapt_workflow",
9
+ DockerCompose = "docker_compose"
10
+ }
11
+ export interface SutPromptArgs {
12
+ repositoryPath: string;
13
+ sutSetupMode: string;
14
+ sutSourceWorkflowFile: string;
15
+ sutSourceDockerComposeFile: string;
16
+ }
17
+ /**
18
+ * Glossary block rendered right after the first mention of "SUT" in each
19
+ * setup prompt. Shared across modes so the LLM gets a single explicit
20
+ * definition rather than inferring it from context.
21
+ */
22
+ export declare function buildSutDefinitionBlock(): string;
23
+ export declare function buildContextBlock(args: SutPromptArgs): string;
24
+ export declare function buildLocalValidationSection(): string;
25
+ /**
26
+ * Returns the canonical "add to the Testbot workflow" block: every input that
27
+ * controls the SUT lifecycle, auth, and workflow-level setup, followed by the
28
+ * shared What to do / What not to do guidance (including the sutSetupMode
29
+ * bootstrap guard). Shared by every SUT setup mode (adapt_workflow and
30
+ * docker_compose) so the input semantics and rules never drift between prompts.
31
+ */
32
+ export declare function buildAddToTestbotWorkflowSection(): string;
33
+ /**
34
+ * `buildAddToTestbotWorkflowSection()` output with its leading
35
+ * `#### Testbot action inputs ...` header stripped — for use as a PromptPlan
36
+ * step body where the PromptPlan step header replaces the inline `####`.
37
+ */
38
+ export declare function buildInputsBody(): string;
39
+ export declare function buildCommonSutErrorsSection(): string;
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Path of the Testbot workflow file relative to the repo root. Created by the
3
+ * Testbot installer and edited in-place by every SUT setup mode.
4
+ */
5
+ export const TESTBOT_WORKFLOW_PATH = ".github/workflows/skyramp-testbot.yml";
6
+ export var SutSetupMode;
7
+ (function (SutSetupMode) {
8
+ SutSetupMode["None"] = "none";
9
+ SutSetupMode["AdaptWorkflow"] = "adapt_workflow";
10
+ SutSetupMode["DockerCompose"] = "docker_compose";
11
+ })(SutSetupMode || (SutSetupMode = {}));
12
+ /**
13
+ * Glossary block rendered right after the first mention of "SUT" in each
14
+ * setup prompt. Shared across modes so the LLM gets a single explicit
15
+ * definition rather than inferring it from context.
16
+ */
17
+ export function buildSutDefinitionBlock() {
18
+ return `**System Under Test (SUT)** — the application services this workflow brings up so Testbot can exercise them end-to-end. The SUT is what runs the PR's source code: backend services (REST/gRPC APIs), their supporting infrastructure (databases, queues, caches), and any frontend UI under test. The SUT does NOT include the test runner itself or Testbot. Bringing up the SUT means building from PR source, starting all required services, seeding any data tests rely on, and exposing a health check that proves the system is ready for traffic.
19
+
20
+ `;
21
+ }
22
+ export function buildContextBlock(args) {
23
+ const lines = [];
24
+ lines.push(`<context>`);
25
+ lines.push(`Repository path: ${args.repositoryPath}`);
26
+ lines.push(`Setup mode: ${args.sutSetupMode}`);
27
+ if (args.sutSourceWorkflowFile)
28
+ lines.push(`Source workflow file: ${args.sutSourceWorkflowFile}`);
29
+ if (args.sutSourceDockerComposeFile)
30
+ lines.push(`Source docker-compose file: ${args.sutSourceDockerComposeFile}`);
31
+ lines.push(`</context>`);
32
+ return lines.join("\n");
33
+ }
34
+ export function buildLocalValidationSection() {
35
+ return `Before reporting success, exercise the adapted workflow locally. Testbot's external fix loop only retries when SUT lifecycle commands are set on the Testbot action. When the SUT is brought up by surrounding GHA steps (skipTargetSetup: 'true'), the fix loop is skipped — so the local check below is the only safety net before the workflow is committed.
36
+ Run commands one at a time in your shell — individual execution pinpoints failures far faster than running the whole workflow at once. Any non-zero exit is a fix-needed signal: adjust the workflow, re-run the failing command, and do not proceed until it passes.
37
+ 1. Validate build scripts and helper programs first — run these before anything else so build and auth failures surface cheaply:
38
+ a. Every helper script the workflow calls (e.g., \`./scripts/*.sh\`, \`make <target>\`, \`./gradlew <task>\`) — run each and confirm exit 0.
39
+ b. \`.skyramp/sut/get-auth-token.sh\` if present — run it and confirm it prints a non-empty token to stdout.
40
+ c. Validate any standalone Dockerfile referenced by GHA \`steps:\` (not by a compose service) with \`docker build\`. Do NOT also run \`docker build\` on Dockerfiles that belong to a compose service — \`docker compose build\` (next step) already builds them in one BuildKit graph; doubling up wastes ~5-10 GB of cache per service.
41
+ d. Every docker-compose file the workflow references — run \`docker compose -f <path> config\` to validate the YAML, then \`docker compose -f <path> build\`.
42
+ e. **Disk hygiene between heavy builds.** Between any two build commands (Dockerfile, compose, helper scripts that build), if the runner is under ~5 GB free or you see \`no space left on device\`, run \`docker builder prune -af -f && docker image prune -af\` before the next build. This frees BuildKit cache + dangling images without losing the running stack. Skipping this on heavy SUTs (medusa, calcom, mattermost, supabase) exhausts the ~14 GB \`ubuntu-latest\` disk mid-validation.
43
+ 2. Validate the SUT lifecycle — choose the branch that matches the chosen pattern:
44
+ a. If lifecycle commands are set on the Testbot action (skipTargetSetup is unset):
45
+ i. Run \`targetSetupCommand\` — confirm exit 0.
46
+ ii. Poll \`targetReadyCheckCommand\` until it exits 0 within \`targetReadyCheckTimeout\` seconds.
47
+ iii. Run \`targetTeardownCommand\` — confirm cleanup and exit 0.
48
+ b. If GHA steps wrap the Testbot action (skipTargetSetup: 'true'):
49
+ i. Extract the shell body of each SETUP step and run them in order. If a step depends entirely on a \${{ secrets.* }} value your shell cannot resolve, note it in <thinking> and skip — do not fabricate a value.
50
+ ii. Poll \`targetReadyCheckCommand\` until it exits 0.
51
+ iii. Extract and run each TEARDOWN step's body in order so the next iteration starts clean.
52
+ Only proceed to the success report once setup → health check → teardown all pass.`;
53
+ }
54
+ /**
55
+ * Returns the canonical "add to the Testbot workflow" block: every input that
56
+ * controls the SUT lifecycle, auth, and workflow-level setup, followed by the
57
+ * shared What to do / What not to do guidance (including the sutSetupMode
58
+ * bootstrap guard). Shared by every SUT setup mode (adapt_workflow and
59
+ * docker_compose) so the input semantics and rules never drift between prompts.
60
+ */
61
+ export function buildAddToTestbotWorkflowSection() {
62
+ return `#### Testbot action inputs - Add target lifecycle commands and auth to Testbot Workflow
63
+ For the full Testbot action input reference (defaults, edge cases, advanced options beyond the ones called out below), see the Testbot README: https://github.com/letsramp/testbot#inputs
64
+
65
+ Target lifecycle inputs (control how Testbot starts, validates, and stops the SUT):
66
+ 1. \`targetSetupCommand\` — shell command that builds and starts all SUT services. Testbot runs this before tests.
67
+ a. Default when unset: \`docker compose up -d\` (starts existing images, does NOT build).
68
+ b. For PR-source builds use \`docker compose up -d --build\` or the equivalent for helm/script-based SUTs.
69
+ c. With a dedicated compose file (reused or generated), point at it explicitly: \`docker compose -f .skyramp/sut/docker-compose.testbot.yml --project-directory . up -d --build\`.
70
+ d. Override whenever the source workflow's start sequence differs from the default.
71
+ 2. \`targetReadyCheckCommand\` — polling command (e.g., \`curl -sf http://localhost:8080/health\`) that Testbot runs repeatedly after setup until it exits 0 (service is ready) or the timeout is reached.
72
+ a. **CRITICAL: Always set this to a valid target readiness check command.** Required in every pattern: when \`targetSetupCommand\` is explicit, when relying on the \`docker compose up -d\` default, AND when surrounding GHA steps bring the SUT up before the Testbot action (\`skipTargetSetup: 'true'\`). Testbot's fail-early gate throws \`Unable to verify service readiness\` when no readiness signal is available (neither this nor a workspace service \`baseUrl\`) and the action exits non-zero. It is also what gates a backgrounded \`targetSetupCommand\` — without it Testbot can't tell when the service is actually listening.
73
+ 3. \`targetReadyCheckTimeout\` — seconds to wait for \`targetReadyCheckCommand\` to succeed.
74
+ a. Default: \`1800\` (30 min) — sized for cold \`docker compose --build\` runs on multi-service stacks. The loop exits on the first success, so fast services pay no extra cost. Override only if you want to fail faster on stuck setups (e.g. \`'300'\` for a small single-service SUT).
75
+ 4. \`targetTeardownCommand\` — shell command that stops and cleans up the SUT after tests (e.g., \`docker compose down -v\`, or \`docker compose -f .skyramp/sut/docker-compose.testbot.yml --project-directory . down -v\` for a dedicated compose file).
76
+ a. Always set this so each run starts from a clean state.
77
+ b. Omit only when teardown is handled by surrounding GHA steps with \`if: always()\`.
78
+ 5. \`skipTargetSetup\` — when \`'true'\`, Testbot skips running \`targetSetupCommand\` entirely.
79
+ a. Set this only when GHA steps surrounding the Testbot action already bring the SUT up.
80
+ b. Leave it unset (or \`'false'\`) when Testbot should run the full lifecycle via the inputs above.
81
+ Auth inputs (used by Testbot to authenticate against the running SUT during test recording and execution):
82
+ 6. \`authTokenCommand\` — shell command whose stdout is the auth credential for REST/gRPC API testing (e.g., a Bearer token, API key, or session cookie). Testbot captures the output and injects it as the \`Authorization\` header.
83
+ a. Set this when the SUT requires authentication for API calls.
84
+ b. If the source workflow exports a token via a step output or script, wire that same script here (e.g., \`bash .skyramp/sut/get-auth-token.sh\`).
85
+ c. If the workflow seeds a test user during setup, create \`.skyramp/sut/get-auth-token.sh\` that logs in with those credentials and prints the token.
86
+ d. Omit when the SUT APIs are unauthenticated.
87
+ 7. \`uiCredentials\` — \`username:password\` pair typed into the browser login form during UI test recording (format: \`myuser:mypassword\`).
88
+ a. Set for any frontend service that requires browser-based login.
89
+ b. Use \`\${{ secrets.SKYRAMP_UI_CREDENTIALS }}\` if the secret exists, otherwise use credentials seeded during SUT setup.
90
+ Workflow / job level settings (set on the workflow or job, not as \`skyramp/testbot\` action inputs):
91
+ 8. Secrets / environment variables — pass every secret/env var the setup needs into the workflow via an \`env:\` block or \`secrets: inherit\`, and add any dependency-resolution steps/jobs the SUT requires.
92
+ 9. \`runs-on\` runner label — switch to a larger runner when the SUT needs more disk or memory: heavy Docker builds, large dependency installs, or a multi-service (3+) compose stack. Standard runners run out of disk and crash with \`No space left on device\`. Runner names vary by org — do not hardcode \`large-ubuntu\`. Pick the label by (a) preserving whatever larger label the source workflow already uses (never downgrade to \`ubuntu-latest\`), (b) reusing the label adjacent heavy or integration jobs in \`.github/workflows/\` already use, or (c) falling back to a known GitHub-hosted large label such as \`ubuntu-latest-large\`.
93
+
94
+ #### What to do
95
+ Edit \`${TESTBOT_WORKFLOW_PATH}\` in place (already created by the Testbot installer) — do NOT recreate it. Add only what the SUT needs onto the existing \`skyramp/testbot\` action step, alongside the inputs the installer already added:
96
+ 1. The 4 target lifecycle inputs — \`targetSetupCommand\`, \`targetReadyCheckCommand\`, \`targetReadyCheckTimeout\`, \`targetTeardownCommand\`.
97
+ 2. The 2 auth inputs when the SUT needs them — \`authTokenCommand\` and/or \`uiCredentials\`.
98
+ 3. Any secrets / environment variables and dependency-resolution steps/jobs the setup needs (input 8).
99
+ 4. The \`runs-on\` runner label, if a larger runner is needed (input 9).
100
+ 5. Use a daemon/detached form for \`targetSetupCommand\` — \`docker compose up -d --build\`, \`nohup npm start &\`, \`./server &\`, \`pnpm --prefix ./apps/studio start &\`. The command should launch the service and exit; \`targetReadyCheckCommand\` is what gates readiness. Testbot backgrounds foreground-blocking commands (\`npm start\`, \`python app.py\`, \`./server\`) automatically after a 5-minute timeout as a safety net, so they will eventually work — but daemon mode is faster (no 5-minute wait) and surfaces startup crashes clearly via the command's exit code. If no daemon form is available and the repo has no \`docker-compose.yml\`, wrap the foreground command in compose (a \`Dockerfile\` + \`docker-compose.yml\` running \`npm start\`) so it can be launched with \`docker compose up -d --build\`. Only fall back to a GHA pre-step with \`&\` (e.g. \`run: npm start &\`) if Docker is not feasible.
101
+
102
+ #### What not to do
103
+ 1. IMPORTANT — do NOT remove or change the existing \`sutSetupMode\` input (nor \`sutSourceWorkflowFile\` / \`sutSourceDockerComposeFile\`). Leave \`sutSetupMode\` exactly as provided: Testbot flips it to \`none\` automatically after validation succeeds, and the committed \`sutSetupMode\` value is the signal that tells the next CI run to validate this adapted workflow rather than run tests. Deleting it or setting it to \`none\` breaks the bootstrap/validation cycle.
104
+ 2. Do not point the SUT at a prebuilt upstream image (e.g. \`image: org/app:latest\` or a fixed commit SHA from \`main\`) for any application service under test. The image will lag the PR and Testbot will validate stale code.
105
+ 3. Do not point the SUT at a remote staging or production environment for application services under test. Staging code drifts from PR source and turns Testbot's results into noise. External infra is acceptable only for sidecar dependencies the PR does not change (e.g. a managed test database).
106
+ 4. Do not use a foreground-blocking command as \`targetSetupCommand\` (e.g. \`npm start\`, \`pnpm --prefix ./apps/studio start\`, \`python app.py\`, \`prefect server start\`, \`./server\`) — see input 5 in "What to do" above for daemon forms and the compose-wrap fallback.
107
+ 5. Do not leave server processes running between fix-loop retries. If \`targetSetupCommand\` starts a direct process (not \`docker compose\`), always set \`targetTeardownCommand\` to kill it (e.g. \`pkill -f "node dist/index.js"\` or \`docker compose down\`). Without teardown, retried setup attempts will fail with \`EADDRINUSE\` because the previous process still holds the port.
108
+ `;
109
+ }
110
+ /**
111
+ * `buildAddToTestbotWorkflowSection()` output with its leading
112
+ * `#### Testbot action inputs ...` header stripped — for use as a PromptPlan
113
+ * step body where the PromptPlan step header replaces the inline `####`.
114
+ */
115
+ export function buildInputsBody() {
116
+ const text = buildAddToTestbotWorkflowSection();
117
+ const firstNewline = text.indexOf("\n");
118
+ return text.slice(firstNewline + 1);
119
+ }
120
+ export function buildCommonSutErrorsSection() {
121
+ return `Before finishing, verify the adapted Testbot workflow setup against common errors seen during SUT setup:
122
+ 1. port_conflict — another container is already using the port. Pick a free host port or stop the conflicting container.
123
+ 2. image_not_found / build_failed — the referenced image does not exist for this SHA, or the build step has the wrong context/Dockerfile path. Build from PR source, do not rely on upstream commit-SHA tags.
124
+ 3. healthcheck_timeout — the service is slow to come up. Use \`targetReadyCheckTimeout >= 120\` and ensure the health endpoint actually exists.
125
+ 4. connection_refused — the service is not listening on the expected host/port (often binding to 127.0.0.1 inside the container; bind to 0.0.0.0).
126
+ 5. dependency_error — required service (DB, cache, queue) is missing from compose or not healthy before the app starts. Add \`depends_on\` with \`condition: service_healthy\`.
127
+ 6. permission_denied — script is not executable (\`chmod +x\`) or volume mount has wrong ownership.
128
+ 7. auth_endpoint_404 / auth_credentials_invalid — the auth script hits a wrong path, or the database has no seeded user. The auth script must create the user before login when starting from a fresh DB.
129
+ 8. missing env vars / secrets — required env vars are unset on the runner. Either default them in the script or pass them through workflow \`env:\`.
130
+ 9. no_space_left — the runner ran out of disk space (\`No space left on device\`). This happens on standard runners when the SUT involves large Docker builds, many npm packages, or multiple compose services that pull large images. Switch \`runs-on\` to a larger runner — runner names vary by org, do not hardcode \`large-ubuntu\`. Pick the label by (a) preserving whatever larger label the source workflow already uses, (b) reusing the label adjacent heavy or integration jobs in \`.github/workflows/\` already use, or (c) falling back to a known GitHub-hosted large label such as \`ubuntu-latest-large\`. Indicator: source workflow already specifies a large runner, or the SUT has multi-stage Docker builds / a compose file with 3+ services.
131
+ Do not add an in-prompt fix loop — Testbot's external validator will retry with concrete error context if any of these occur.`;
132
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Prompt language for skyramp_actions output — the LLM_INSTRUCTIONS block
3
+ * emitted to the agent that applies UPDATE and REGENERATE edits.
4
+ *
5
+ * Kept separate from actionsTool.ts so prompt text is co-located with other
6
+ * maintenance prompts and can be reviewed/edited without touching tool logic.
7
+ */
8
+ export interface RenameEntry {
9
+ oldPath: string;
10
+ newPath: string;
11
+ method: string;
12
+ }
13
+ /** Strategy string for URL-path find-and-replace updates. */
14
+ export declare function buildRenameStrategy(): string;
15
+ /** Strategy string for file renames after path substitution. */
16
+ export declare function buildFileRenameStrategy(): string;
17
+ /** Strategy string for in-place UPDATE edits. */
18
+ export declare function buildUpdateStrategy(): string;
19
+ /** Strategy string for REGENERATE — call generation tool to overwrite the file. */
20
+ export declare function buildRegenerateStrategy(): string;
21
+ /** Per-file instruction block for a single UPDATE recommendation. */
22
+ export declare function buildUpdateFileInstruction(params: {
23
+ testFile: string;
24
+ renames: RenameEntry[];
25
+ suggestedNewFile?: string;
26
+ updateInstructions?: string;
27
+ rationale?: string;
28
+ }): string;
29
+ /** Per-file instruction block for a single REGENERATE recommendation. */
30
+ export declare function buildRegenerateFileInstruction(params: {
31
+ testFile: string;
32
+ updateInstructions?: string;
33
+ outputDir: string;
34
+ outputFile: string;
35
+ }): string;
@@ -0,0 +1,4 @@
1
+ export declare function buildDriftAnalysisPrompt(stateFile?: string, existingTests?: Array<{
2
+ testFile: string;
3
+ source?: string;
4
+ }>): string;
@@ -0,0 +1,13 @@
1
+ export declare function buildActionDecisionTree(): string;
2
+ /** @deprecated use the individual check functions; this function is no longer part of the prompt */
3
+ export declare function buildBreakingChangePatterns(): string;
4
+ export declare function buildCheckEndpointExistence(): string;
5
+ export declare function buildCheckResponseShape(): string;
6
+ export declare function buildCheckAuthAndAuthorization(): string;
7
+ export declare function buildCheckBehavioralContract(): string;
8
+ export declare function buildCheckAssignAction(): string;
9
+ export declare function buildCheckAdditiveFields(): string;
10
+ export declare function buildDriftOutputChecklist(stateFile?: string, existingTests?: Array<{
11
+ testFile: string;
12
+ source?: string;
13
+ }>): string;
@@ -136,7 +136,9 @@ Actions:
136
136
  **UPDATE vs REGENERATE — the deciding question is whether the root response wrapper changed:**
137
137
  - **REGENERATE** only when a new top-level envelope object wraps the entire payload or the root key is renamed so that essentially every existing assertion must change.
138
138
  - **UPDATE** for everything else. If you can describe the fix as "patch these N assertion paths", it is UPDATE regardless of how many paths there are.
139
- - When every assertion in the file is invalid, it is REGENERATE. When you can still patch individual paths, it is UPDATE.`;
139
+ - When every assertion in the file is invalid, it is REGENERATE. When you can still patch individual paths, it is UPDATE.
140
+
141
+ **Non-test consumer check:** When the diff removes or renames response fields, also grep the repository for non-test source files that import or reference the changed schema type (e.g. \`grep -r "WorkQueueStatusDetail" src/\`). If any client model, SDK class, or serializer references the old field names, add a VERIFY entry for each such file in your recommendations so the developer is alerted — these are not test files but they will break at runtime.`;
140
142
  }
141
143
  export function buildCheckAuthAndAuthorization() {
142
144
  return `Has the authentication or authorization for this endpoint changed?
@@ -180,7 +182,7 @@ export function buildCheckAssignAction() {
180
182
  **Every action requires a specific rationale — including IGNORE:**
181
183
  - UPDATE / REGENERATE / DELETE: quote the specific diff line that triggered it.
182
184
  - VERIFY: name the uncertain element (e.g. "model-only change, cannot confirm field is exposed without checking the output layer").
183
- - IGNORE: name the specific reason the changed code cannot reach this test's endpoint (e.g. "diff only touches \`auth/session-service.js\` — this test targets \`/api/v1/orders\` which has no session dependency"). Generic "unrelated endpoint" or "service boundary" without a diff reference is not sufficient.
185
+ - IGNORE: name the changed file(s) from the diff AND explain why they cannot reach this test's endpoint (e.g. "diff only touches \`auth/session-service.js\` — this test targets \`/api/v1/orders\` which has no session dependency"). You must reference at least one specific changed file from the diff. Generic "unrelated endpoint" or "service boundary" without naming the changed file is not sufficient.
184
186
 
185
187
  - If the Additive Fields check flagged a new field with output layer signal confirmed in the diff → action is UPDATE. If the Additive Fields check returned VERIFY (model-only signal, no output layer change) → action remains VERIFY.
186
188
  - **Scope gate:** If the changed code is clearly not reachable through the service or base URL this test targets, assign IGNORE.
@@ -222,12 +224,16 @@ export function buildDriftOutputChecklist(stateFile, existingTests) {
222
224
  const noTestsNote = !hasTests
223
225
  ? `\nNo existing tests were found. Call \`skyramp_actions\` with \`recommendations: []\` and explain in your report why no maintenance was needed (e.g. "no existing tests cover the changed endpoints" or "PR adds a new endpoint with no prior coverage").\n`
224
226
  : "";
227
+ const symbolDiscoveryStep = hasTests
228
+ ? `**Symbol import discovery (before assessing tests):** If the diff adds or modifies class, function, or type definitions, grep the repository for test files that import those symbol names. Add any matched test files not already in the list below to your assessment — these files may need updating even if their path doesn't match the changed resource name. Include all discovered files in the \`recommendations[]\` passed to \`skyramp_actions\` — do NOT edit them directly without going through \`skyramp_actions\` first.`
229
+ : "";
225
230
  const existingTestSection = `**Existing tests (${existingTests?.length ?? 0} total) — assess ALL of the following:**
226
231
  ${testList}
227
232
  ${noTestsNote}
228
233
  **UPDATE scope notes:**
229
234
  - UPDATE is an in-place edit — do not recommend creating a new file for an already-tested endpoint.
230
235
  - If a new HTTP method is added to a resource, emit a separate UPDATE entry for every existing test file that covers that resource (contract, integration, UI).
236
+ - **When multiple test files cover the same changed resource, prefer the most resource-specific file** (e.g. a file whose name directly reflects the changed resource) over a generic shared test file. Only UPDATE both if the change affects base types shared across both files.
231
237
 
232
238
  For each test above, output one entry:
233
239
  - **IGNORE**: \`{testFile} — IGNORE: {reason the diff cannot reach this test's endpoint}\`
@@ -253,7 +259,7 @@ Rationale: DELETE because {quoted diff signal}; all covered endpoints removed
253
259
  \`\`\`
254
260
  Include ALL actions — IGNORE, VERIFY, UPDATE, REGENERATE, DELETE — in the \`recommendations[]\` passed to \`skyramp_actions\`. For \`[external]\` tests: \`skyramp_actions\` will apply UPDATE edits and surface REGENERATE/DELETE as report-only findings.
255
261
  Be concise — one line per IGNORE/VERIFY entry.`;
256
- const sections = [existingTestSection, finalStep];
262
+ const sections = [symbolDiscoveryStep, existingTestSection, finalStep].filter(Boolean);
257
263
  return `<output_format>
258
264
  Complete ALL of the following:
259
265