@skyramp/mcp 0.2.6 → 0.2.8-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) 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 +83 -18
  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 +97 -99
  57. package/build/prompts/testbot/testbot-prompts.d.ts +26 -0
  58. package/build/prompts/testbot/testbot-prompts.js +301 -46
  59. package/build/prompts/testbot/testbot-prompts.test.d.ts +1 -0
  60. package/build/prompts/testbot/testbot-prompts.test.js +109 -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 +2 -2
  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 +26 -7
  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 +394 -0
  115. package/build/tools/submitReportTool.js +250 -41
  116. package/build/tools/submitReportTool.test.d.ts +1 -0
  117. package/build/tools/submitReportTool.test.js +511 -55
  118. package/build/tools/test-management/actionsTool.d.ts +10 -0
  119. package/build/tools/test-management/actionsTool.js +21 -7
  120. package/build/tools/test-management/analyzeChangesTool.d.ts +27 -0
  121. package/build/tools/test-management/analyzeChangesTool.js +150 -48
  122. package/build/tools/test-management/analyzeChangesTool.test.d.ts +1 -0
  123. package/build/tools/test-management/analyzeChangesTool.test.js +95 -78
  124. package/build/tools/test-management/analyzeTestHealthTool.d.ts +2 -0
  125. package/build/tools/test-management/analyzeTestHealthTool.js +16 -9
  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.js +39 -22
  139. package/build/tools/workspace/initializeWorkspaceTool.test.d.ts +1 -0
  140. package/build/tools/workspace/initializeWorkspaceTool.test.js +134 -0
  141. package/build/tools/workspace/serviceUpsert.d.ts +12 -0
  142. package/build/tools/workspace/serviceUpsert.js +23 -0
  143. package/build/tools/workspace/serviceUpsert.test.d.ts +1 -0
  144. package/build/tools/workspace/serviceUpsert.test.js +50 -0
  145. package/build/types/OneClickCommands.d.ts +68 -0
  146. package/build/types/RepositoryAnalysis.d.ts +3004 -0
  147. package/build/types/TestAnalysis.d.ts +97 -0
  148. package/build/types/TestExecution.d.ts +63 -0
  149. package/build/types/TestExecution.js +11 -1
  150. package/build/types/TestRecommendation.d.ts +12 -0
  151. package/build/types/TestTypes.d.ts +234 -0
  152. package/build/types/TestbotReport.d.ts +68 -0
  153. package/build/types/TestbotReport.js +1 -0
  154. package/build/types/index.d.ts +4 -0
  155. package/build/types/index.js +3 -0
  156. package/build/utils/AnalysisStateManager.d.ts +242 -0
  157. package/build/utils/AnalysisStateManager.js +144 -3
  158. package/build/utils/AnalysisStateManager.test.d.ts +1 -0
  159. package/build/utils/AnalysisStateManager.test.js +98 -0
  160. package/build/utils/analyze-openapi.d.ts +1 -0
  161. package/build/utils/branchDiff.d.ts +18 -0
  162. package/build/utils/dartRouteExtractor.d.ts +45 -0
  163. package/build/utils/dartRouteExtractor.test.d.ts +1 -0
  164. package/build/utils/docker.d.ts +19 -0
  165. package/build/utils/docker.test.d.ts +1 -0
  166. package/build/utils/docker.test.js +10 -9
  167. package/build/utils/featureFlags.d.ts +37 -0
  168. package/build/utils/featureFlags.test.d.ts +1 -0
  169. package/build/utils/gitStaging.d.ts +24 -0
  170. package/build/utils/gitStaging.test.d.ts +1 -0
  171. package/build/utils/gitStaging.test.js +13 -7
  172. package/build/utils/httpDefaults.d.ts +10 -0
  173. package/build/utils/httpDefaults.test.d.ts +1 -0
  174. package/build/utils/initAgent.d.ts +36 -0
  175. package/build/utils/language-helper.d.ts +6 -0
  176. package/build/utils/logger.d.ts +11 -0
  177. package/build/utils/normalizeParams.d.ts +14 -0
  178. package/build/utils/normalizeSkyrampImports.d.ts +13 -0
  179. package/build/utils/pr-comment-parser.d.ts +31 -0
  180. package/build/utils/pr-comment-parser.test.d.ts +1 -0
  181. package/build/utils/pr-comment-parser.test.js +6 -5
  182. package/build/utils/projectMetadata.d.ts +15 -0
  183. package/build/utils/projectMetadata.test.d.ts +1 -0
  184. package/build/utils/proxy-terminal.d.ts +2 -0
  185. package/build/utils/repoScanner.d.ts +27 -0
  186. package/build/utils/repoScanner.test.d.ts +1 -0
  187. package/build/utils/routeParsers.d.ts +53 -0
  188. package/build/utils/routeParsers.js +31 -38
  189. package/build/utils/routeParsers.test.d.ts +1 -0
  190. package/build/utils/scenarioDrafting.d.ts +71 -0
  191. package/build/utils/scenarioDrafting.js +23 -1
  192. package/build/utils/scenarioDrafting.test.d.ts +1 -0
  193. package/build/utils/skyrampMdContent.d.ts +5 -0
  194. package/build/utils/sourceRouteExtractor.d.ts +48 -0
  195. package/build/utils/sourceRouteExtractor.test.d.ts +1 -0
  196. package/build/utils/telemetry.d.ts +32 -0
  197. package/build/utils/telemetry.test.d.ts +1 -0
  198. package/build/utils/trace-parser.d.ts +32 -0
  199. package/build/utils/trace-parser.test.d.ts +6 -0
  200. package/build/utils/uiPageEnumerator.d.ts +146 -0
  201. package/build/utils/uiPageEnumerator.js +58 -14
  202. package/build/utils/uiPageEnumerator.test.d.ts +1 -0
  203. package/build/utils/uiPageEnumerator.test.js +223 -43
  204. package/build/utils/utils.d.ts +45 -0
  205. package/build/utils/utils.js +10 -0
  206. package/build/utils/utils.test.d.ts +1 -0
  207. package/build/utils/versions.d.ts +3 -0
  208. package/build/utils/versions.js +1 -1
  209. package/build/utils/workspaceAuth.d.ts +127 -0
  210. package/build/utils/workspaceAuth.test.d.ts +1 -0
  211. package/build/utils/workspaceAuth.test.js +25 -25
  212. package/build/workspace/index.d.ts +1 -0
  213. package/build/workspace/workspace.d.ts +390 -0
  214. package/build/workspace/workspace.js +7 -7
  215. package/build/workspace/workspace.test.d.ts +1 -0
  216. package/build/workspace/workspace.test.js +6 -6
  217. package/node_modules/playwright/lib/mcp/skyramp/loadTraceTool.js +31 -13
  218. package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +88 -15
  219. package/node_modules/playwright/lib/mcp/test/skyRampExport.js +4 -3
  220. package/node_modules/playwright/node_modules/playwright-core/ThirdPartyNotices.txt +23 -126
  221. package/node_modules/playwright/node_modules/playwright-core/lib/generated/injectedScriptSource.js +1 -1
  222. package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/recorderApp.js +79 -19
  223. package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/skyramp/aliasRemapper.js +84 -0
  224. package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/skyramp/replayEngine.js +15 -4
  225. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/{codeMirrorModule-CPZKmjFR.js → codeMirrorModule-D0BjbCb7.js} +1 -1
  226. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/index-lvTRGFx-.js +193 -0
  227. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/index.html +1 -1
  228. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/{codeMirrorModule-B0JOjboO.js → codeMirrorModule-Cqp3cwEJ.js} +1 -1
  229. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/{defaultSettingsView-1anWeyDf.js → defaultSettingsView-CYf9adZh.js} +79 -79
  230. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{index.Cc5029a3.js → index.B_7ywgmr.js} +1 -1
  231. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.html +2 -2
  232. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.html +2 -2
  233. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{uiMode.Wo5yvvVh.js → uiMode.u4_8VnCV.js} +1 -1
  234. package/node_modules/playwright/node_modules/playwright-core/package.json +1 -1
  235. package/node_modules/playwright/node_modules/playwright-core/src/generated/injectedScriptSource.ts +1 -1
  236. package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/recorderApp.ts +129 -43
  237. package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/skyramp/aliasRemapper.ts +119 -0
  238. package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/skyramp/replayEngine.ts +33 -10
  239. package/node_modules/playwright/package.json +1 -1
  240. package/package.json +16 -4
  241. package/build/tools/test-management/uiAnalyzeChangesTool.js +0 -155
  242. package/build/tools/test-management/uiAnalyzeChangesTool.test.js +0 -147
  243. package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/.bin/node-which +0 -52
  244. package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/.bin/is-docker +0 -5
  245. package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/.bin/mime +0 -46
  246. package/node_modules/playwright/node_modules/playwright-core/bundles/utils/node_modules/.bin/yaml +0 -11
  247. package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/index-CsgPR2wy.js +0 -193
  248. package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.CP3Y8Zsb.js +0 -2
@@ -1,29 +1,29 @@
1
- import { getWorkspaceBaseUrl } from "./workspaceAuth.js";
1
+ // @ts-nocheck - Jest ESM mock type inference issues
2
+ import { jest } from "@jest/globals";
2
3
  const REPO = "/some/repo";
3
- jest.mock("../workspace/workspace.js", () => {
4
- const twoServiceConfig = {
5
- services: [
6
- {
7
- serviceName: "backend",
8
- language: "python",
9
- testDirectory: "backend/tests",
10
- api: { baseUrl: "http://localhost:8000" },
11
- },
12
- {
13
- serviceName: "frontend",
14
- language: "typescript",
15
- testDirectory: "frontend/tests",
16
- api: { baseUrl: "http://localhost:5173" },
17
- },
18
- ],
19
- };
20
- return {
21
- WorkspaceConfigManager: jest.fn().mockImplementation(() => ({
22
- exists: jest.fn().mockResolvedValue(true),
23
- read: jest.fn().mockResolvedValue(twoServiceConfig),
24
- })),
25
- };
26
- });
4
+ const twoServiceConfig = {
5
+ services: [
6
+ {
7
+ serviceName: "backend",
8
+ language: "python",
9
+ testDirectory: "backend/tests",
10
+ api: { baseUrl: "http://localhost:8000" },
11
+ },
12
+ {
13
+ serviceName: "frontend",
14
+ language: "typescript",
15
+ testDirectory: "frontend/tests",
16
+ api: { baseUrl: "http://localhost:5173" },
17
+ },
18
+ ],
19
+ };
20
+ jest.unstable_mockModule("../workspace/workspace.js", () => ({
21
+ WorkspaceConfigManager: jest.fn().mockImplementation(() => ({
22
+ exists: jest.fn().mockResolvedValue(true),
23
+ read: jest.fn().mockResolvedValue(twoServiceConfig),
24
+ })),
25
+ }));
26
+ const { getWorkspaceBaseUrl } = await import("./workspaceAuth.js");
27
27
  describe("getWorkspaceBaseUrl", () => {
28
28
  it("should return no match when testFile is not provided", async () => {
29
29
  const result = await getWorkspaceBaseUrl(REPO);
@@ -0,0 +1 @@
1
+ export * from "./workspace.js";
@@ -0,0 +1,390 @@
1
+ import { z } from "zod";
2
+ export declare const WORKSPACE_DIR = ".skyramp";
3
+ export declare const WORKSPACE_FILENAME = "workspace.yml";
4
+ export declare const serviceSchema: z.ZodObject<{
5
+ serviceName: z.ZodString;
6
+ repository: z.ZodOptional<z.ZodString>;
7
+ language: z.ZodOptional<z.ZodEnum<["python", "typescript", "javascript", "java"]>>;
8
+ framework: z.ZodOptional<z.ZodEnum<["playwright", "pytest", "robot", "junit"]>>;
9
+ testDirectory: z.ZodOptional<z.ZodString>;
10
+ api: z.ZodOptional<z.ZodObject<{
11
+ schemaPath: z.ZodOptional<z.ZodString>;
12
+ authType: z.ZodOptional<z.ZodEnum<["bearer", "basic", "oauth", "apiKey", "cookie", "session", "token", "none"]>>;
13
+ authHeader: z.ZodOptional<z.ZodString>;
14
+ authScheme: z.ZodOptional<z.ZodString>;
15
+ baseUrl: z.ZodOptional<z.ZodString>;
16
+ }, "strict", z.ZodTypeAny, {
17
+ authHeader?: string | undefined;
18
+ authScheme?: string | undefined;
19
+ schemaPath?: string | undefined;
20
+ authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
21
+ baseUrl?: string | undefined;
22
+ }, {
23
+ authHeader?: string | undefined;
24
+ authScheme?: string | undefined;
25
+ schemaPath?: string | undefined;
26
+ authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
27
+ baseUrl?: string | undefined;
28
+ }>>;
29
+ runtimeDetails: z.ZodOptional<z.ZodObject<{
30
+ serverStartCommand: z.ZodOptional<z.ZodString>;
31
+ runtime: z.ZodEnum<["local", "docker", "k8s"]>;
32
+ dockerNetwork: z.ZodOptional<z.ZodString>;
33
+ k8sNamespace: z.ZodOptional<z.ZodString>;
34
+ k8sContext: z.ZodOptional<z.ZodString>;
35
+ }, "strict", z.ZodTypeAny, {
36
+ runtime: "local" | "docker" | "k8s";
37
+ dockerNetwork?: string | undefined;
38
+ k8sNamespace?: string | undefined;
39
+ k8sContext?: string | undefined;
40
+ serverStartCommand?: string | undefined;
41
+ }, {
42
+ runtime: "local" | "docker" | "k8s";
43
+ dockerNetwork?: string | undefined;
44
+ k8sNamespace?: string | undefined;
45
+ k8sContext?: string | undefined;
46
+ serverStartCommand?: string | undefined;
47
+ }>>;
48
+ }, "strict", z.ZodTypeAny, {
49
+ serviceName: string;
50
+ language?: "python" | "typescript" | "javascript" | "java" | undefined;
51
+ framework?: "playwright" | "pytest" | "robot" | "junit" | undefined;
52
+ repository?: string | undefined;
53
+ testDirectory?: string | undefined;
54
+ api?: {
55
+ authHeader?: string | undefined;
56
+ authScheme?: string | undefined;
57
+ schemaPath?: string | undefined;
58
+ authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
59
+ baseUrl?: string | undefined;
60
+ } | undefined;
61
+ runtimeDetails?: {
62
+ runtime: "local" | "docker" | "k8s";
63
+ dockerNetwork?: string | undefined;
64
+ k8sNamespace?: string | undefined;
65
+ k8sContext?: string | undefined;
66
+ serverStartCommand?: string | undefined;
67
+ } | undefined;
68
+ }, {
69
+ serviceName: string;
70
+ language?: "python" | "typescript" | "javascript" | "java" | undefined;
71
+ framework?: "playwright" | "pytest" | "robot" | "junit" | undefined;
72
+ repository?: string | undefined;
73
+ testDirectory?: string | undefined;
74
+ api?: {
75
+ authHeader?: string | undefined;
76
+ authScheme?: string | undefined;
77
+ schemaPath?: string | undefined;
78
+ authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
79
+ baseUrl?: string | undefined;
80
+ } | undefined;
81
+ runtimeDetails?: {
82
+ runtime: "local" | "docker" | "k8s";
83
+ dockerNetwork?: string | undefined;
84
+ k8sNamespace?: string | undefined;
85
+ k8sContext?: string | undefined;
86
+ serverStartCommand?: string | undefined;
87
+ } | undefined;
88
+ }>;
89
+ export declare const workspaceConfigSchema: z.ZodObject<{
90
+ workspace: z.ZodOptional<z.ZodObject<{
91
+ repoName: z.ZodOptional<z.ZodString>;
92
+ repoUrl: z.ZodOptional<z.ZodString>;
93
+ }, "strict", z.ZodTypeAny, {
94
+ repoName?: string | undefined;
95
+ repoUrl?: string | undefined;
96
+ }, {
97
+ repoName?: string | undefined;
98
+ repoUrl?: string | undefined;
99
+ }>>;
100
+ metadata: z.ZodOptional<z.ZodObject<{
101
+ schemaVersion: z.ZodString;
102
+ mcpVersion: z.ZodString;
103
+ executorVersion: z.ZodString;
104
+ createdAt: z.ZodString;
105
+ updatedAt: z.ZodString;
106
+ }, "strict", z.ZodTypeAny, {
107
+ createdAt: string;
108
+ schemaVersion: string;
109
+ mcpVersion: string;
110
+ executorVersion: string;
111
+ updatedAt: string;
112
+ }, {
113
+ createdAt: string;
114
+ schemaVersion: string;
115
+ mcpVersion: string;
116
+ executorVersion: string;
117
+ updatedAt: string;
118
+ }>>;
119
+ services: z.ZodOptional<z.ZodArray<z.ZodObject<{
120
+ serviceName: z.ZodString;
121
+ repository: z.ZodOptional<z.ZodString>;
122
+ language: z.ZodOptional<z.ZodEnum<["python", "typescript", "javascript", "java"]>>;
123
+ framework: z.ZodOptional<z.ZodEnum<["playwright", "pytest", "robot", "junit"]>>;
124
+ testDirectory: z.ZodOptional<z.ZodString>;
125
+ api: z.ZodOptional<z.ZodObject<{
126
+ schemaPath: z.ZodOptional<z.ZodString>;
127
+ authType: z.ZodOptional<z.ZodEnum<["bearer", "basic", "oauth", "apiKey", "cookie", "session", "token", "none"]>>;
128
+ authHeader: z.ZodOptional<z.ZodString>;
129
+ authScheme: z.ZodOptional<z.ZodString>;
130
+ baseUrl: z.ZodOptional<z.ZodString>;
131
+ }, "strict", z.ZodTypeAny, {
132
+ authHeader?: string | undefined;
133
+ authScheme?: string | undefined;
134
+ schemaPath?: string | undefined;
135
+ authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
136
+ baseUrl?: string | undefined;
137
+ }, {
138
+ authHeader?: string | undefined;
139
+ authScheme?: string | undefined;
140
+ schemaPath?: string | undefined;
141
+ authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
142
+ baseUrl?: string | undefined;
143
+ }>>;
144
+ runtimeDetails: z.ZodOptional<z.ZodObject<{
145
+ serverStartCommand: z.ZodOptional<z.ZodString>;
146
+ runtime: z.ZodEnum<["local", "docker", "k8s"]>;
147
+ dockerNetwork: z.ZodOptional<z.ZodString>;
148
+ k8sNamespace: z.ZodOptional<z.ZodString>;
149
+ k8sContext: z.ZodOptional<z.ZodString>;
150
+ }, "strict", z.ZodTypeAny, {
151
+ runtime: "local" | "docker" | "k8s";
152
+ dockerNetwork?: string | undefined;
153
+ k8sNamespace?: string | undefined;
154
+ k8sContext?: string | undefined;
155
+ serverStartCommand?: string | undefined;
156
+ }, {
157
+ runtime: "local" | "docker" | "k8s";
158
+ dockerNetwork?: string | undefined;
159
+ k8sNamespace?: string | undefined;
160
+ k8sContext?: string | undefined;
161
+ serverStartCommand?: string | undefined;
162
+ }>>;
163
+ }, "strict", z.ZodTypeAny, {
164
+ serviceName: string;
165
+ language?: "python" | "typescript" | "javascript" | "java" | undefined;
166
+ framework?: "playwright" | "pytest" | "robot" | "junit" | undefined;
167
+ repository?: string | undefined;
168
+ testDirectory?: string | undefined;
169
+ api?: {
170
+ authHeader?: string | undefined;
171
+ authScheme?: string | undefined;
172
+ schemaPath?: string | undefined;
173
+ authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
174
+ baseUrl?: string | undefined;
175
+ } | undefined;
176
+ runtimeDetails?: {
177
+ runtime: "local" | "docker" | "k8s";
178
+ dockerNetwork?: string | undefined;
179
+ k8sNamespace?: string | undefined;
180
+ k8sContext?: string | undefined;
181
+ serverStartCommand?: string | undefined;
182
+ } | undefined;
183
+ }, {
184
+ serviceName: string;
185
+ language?: "python" | "typescript" | "javascript" | "java" | undefined;
186
+ framework?: "playwright" | "pytest" | "robot" | "junit" | undefined;
187
+ repository?: string | undefined;
188
+ testDirectory?: string | undefined;
189
+ api?: {
190
+ authHeader?: string | undefined;
191
+ authScheme?: string | undefined;
192
+ schemaPath?: string | undefined;
193
+ authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
194
+ baseUrl?: string | undefined;
195
+ } | undefined;
196
+ runtimeDetails?: {
197
+ runtime: "local" | "docker" | "k8s";
198
+ dockerNetwork?: string | undefined;
199
+ k8sNamespace?: string | undefined;
200
+ k8sContext?: string | undefined;
201
+ serverStartCommand?: string | undefined;
202
+ } | undefined;
203
+ }>, "many">>;
204
+ }, "strict", z.ZodTypeAny, {
205
+ metadata?: {
206
+ createdAt: string;
207
+ schemaVersion: string;
208
+ mcpVersion: string;
209
+ executorVersion: string;
210
+ updatedAt: string;
211
+ } | undefined;
212
+ workspace?: {
213
+ repoName?: string | undefined;
214
+ repoUrl?: string | undefined;
215
+ } | undefined;
216
+ services?: {
217
+ serviceName: string;
218
+ language?: "python" | "typescript" | "javascript" | "java" | undefined;
219
+ framework?: "playwright" | "pytest" | "robot" | "junit" | undefined;
220
+ repository?: string | undefined;
221
+ testDirectory?: string | undefined;
222
+ api?: {
223
+ authHeader?: string | undefined;
224
+ authScheme?: string | undefined;
225
+ schemaPath?: string | undefined;
226
+ authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
227
+ baseUrl?: string | undefined;
228
+ } | undefined;
229
+ runtimeDetails?: {
230
+ runtime: "local" | "docker" | "k8s";
231
+ dockerNetwork?: string | undefined;
232
+ k8sNamespace?: string | undefined;
233
+ k8sContext?: string | undefined;
234
+ serverStartCommand?: string | undefined;
235
+ } | undefined;
236
+ }[] | undefined;
237
+ }, {
238
+ metadata?: {
239
+ createdAt: string;
240
+ schemaVersion: string;
241
+ mcpVersion: string;
242
+ executorVersion: string;
243
+ updatedAt: string;
244
+ } | undefined;
245
+ workspace?: {
246
+ repoName?: string | undefined;
247
+ repoUrl?: string | undefined;
248
+ } | undefined;
249
+ services?: {
250
+ serviceName: string;
251
+ language?: "python" | "typescript" | "javascript" | "java" | undefined;
252
+ framework?: "playwright" | "pytest" | "robot" | "junit" | undefined;
253
+ repository?: string | undefined;
254
+ testDirectory?: string | undefined;
255
+ api?: {
256
+ authHeader?: string | undefined;
257
+ authScheme?: string | undefined;
258
+ schemaPath?: string | undefined;
259
+ authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
260
+ baseUrl?: string | undefined;
261
+ } | undefined;
262
+ runtimeDetails?: {
263
+ runtime: "local" | "docker" | "k8s";
264
+ dockerNetwork?: string | undefined;
265
+ k8sNamespace?: string | undefined;
266
+ k8sContext?: string | undefined;
267
+ serverStartCommand?: string | undefined;
268
+ } | undefined;
269
+ }[] | undefined;
270
+ }>;
271
+ export type Service = z.infer<typeof serviceSchema>;
272
+ export type ServiceApi = NonNullable<Service["api"]>;
273
+ export type ServiceRuntimeDetails = NonNullable<Service["runtimeDetails"]>;
274
+ export type WorkspaceConfig = z.infer<typeof workspaceConfigSchema>;
275
+ export type WorkspaceSection = NonNullable<WorkspaceConfig["workspace"]>;
276
+ export type MetadataSection = NonNullable<WorkspaceConfig["metadata"]>;
277
+ /** Validates a workspace configuration object against the Zod schema. */
278
+ export declare function validateWorkspaceConfig(config: unknown): z.SafeParseReturnType<{
279
+ metadata?: {
280
+ createdAt: string;
281
+ schemaVersion: string;
282
+ mcpVersion: string;
283
+ executorVersion: string;
284
+ updatedAt: string;
285
+ } | undefined;
286
+ workspace?: {
287
+ repoName?: string | undefined;
288
+ repoUrl?: string | undefined;
289
+ } | undefined;
290
+ services?: {
291
+ serviceName: string;
292
+ language?: "python" | "typescript" | "javascript" | "java" | undefined;
293
+ framework?: "playwright" | "pytest" | "robot" | "junit" | undefined;
294
+ repository?: string | undefined;
295
+ testDirectory?: string | undefined;
296
+ api?: {
297
+ authHeader?: string | undefined;
298
+ authScheme?: string | undefined;
299
+ schemaPath?: string | undefined;
300
+ authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
301
+ baseUrl?: string | undefined;
302
+ } | undefined;
303
+ runtimeDetails?: {
304
+ runtime: "local" | "docker" | "k8s";
305
+ dockerNetwork?: string | undefined;
306
+ k8sNamespace?: string | undefined;
307
+ k8sContext?: string | undefined;
308
+ serverStartCommand?: string | undefined;
309
+ } | undefined;
310
+ }[] | undefined;
311
+ }, {
312
+ metadata?: {
313
+ createdAt: string;
314
+ schemaVersion: string;
315
+ mcpVersion: string;
316
+ executorVersion: string;
317
+ updatedAt: string;
318
+ } | undefined;
319
+ workspace?: {
320
+ repoName?: string | undefined;
321
+ repoUrl?: string | undefined;
322
+ } | undefined;
323
+ services?: {
324
+ serviceName: string;
325
+ language?: "python" | "typescript" | "javascript" | "java" | undefined;
326
+ framework?: "playwright" | "pytest" | "robot" | "junit" | undefined;
327
+ repository?: string | undefined;
328
+ testDirectory?: string | undefined;
329
+ api?: {
330
+ authHeader?: string | undefined;
331
+ authScheme?: string | undefined;
332
+ schemaPath?: string | undefined;
333
+ authType?: "none" | "token" | "bearer" | "basic" | "oauth" | "apiKey" | "cookie" | "session" | undefined;
334
+ baseUrl?: string | undefined;
335
+ } | undefined;
336
+ runtimeDetails?: {
337
+ runtime: "local" | "docker" | "k8s";
338
+ dockerNetwork?: string | undefined;
339
+ k8sNamespace?: string | undefined;
340
+ k8sContext?: string | undefined;
341
+ serverStartCommand?: string | undefined;
342
+ } | undefined;
343
+ }[] | undefined;
344
+ }>;
345
+ /** Creates a default workspace config with empty sections and timestamps. */
346
+ export declare function createDefaultConfig(): WorkspaceConfig;
347
+ /**
348
+ * High-level manager for .skyramp/workspace.yml.
349
+ *
350
+ * Provides three focused mutation methods:
351
+ * 1. initialize() — create workspace file with repo info
352
+ * 2. updateMetadata() — update metadata section
353
+ * 3. addService() — upsert a single service entry
354
+ */
355
+ export declare class WorkspaceConfigManager {
356
+ private workspacePath;
357
+ private skyrampDir;
358
+ private configPath;
359
+ constructor(workspacePath: string);
360
+ /** Check if workspace config file exists */
361
+ exists(): Promise<boolean>;
362
+ /** Get the absolute path to the config file */
363
+ getConfigPath(): string;
364
+ /** Get the workspace root path */
365
+ getWorkspacePath(): string;
366
+ /** Read and parse workspace config from disk. */
367
+ read(): Promise<WorkspaceConfig>;
368
+ /**
369
+ * Initialize workspace — creates .skyramp/workspace.yml with repo info.
370
+ * Auto-detects repoName and repoUrl from git when not provided.
371
+ * Produces an empty services array and default metadata timestamps.
372
+ */
373
+ initialize(workspaceInfo?: WorkspaceSection): Promise<WorkspaceConfig>;
374
+ /**
375
+ * Update the metadata section of an existing workspace config.
376
+ * Only the provided fields are merged; metadata.updatedAt is refreshed
377
+ * automatically.
378
+ */
379
+ updateMetadata(metadata: Partial<MetadataSection>): Promise<WorkspaceConfig>;
380
+ /**
381
+ * Add a single service entry to the services array.
382
+ * If a service with the same identity already exists it is replaced
383
+ * (upsert semantics), otherwise the new entry is appended. Service identity
384
+ * is the composite (repo, serviceName) — a service's `repo` (absent → primary)
385
+ * is part of its key, so the same serviceName can coexist across repos in a
386
+ * unified multi-repo workspace.
387
+ * metadata.updatedAt is refreshed automatically.
388
+ */
389
+ addService(service: Service): Promise<WorkspaceConfig>;
390
+ }
@@ -27,9 +27,9 @@ export const serviceSchema = z
27
27
  .object({
28
28
  serviceName: z.string(),
29
29
  // owner/repo this service belongs to (multi-repo workspaces). Absent → the
30
- // primary repo. Service identity is the composite (repo, serviceName), so the
31
- // same serviceName can appear once per repo without colliding.
32
- repo: z.string().optional(),
30
+ // primary repo. Service identity is the composite (repository, serviceName),
31
+ // so the same serviceName can appear once per repo without colliding.
32
+ repository: z.string().optional(),
33
33
  language: z.enum(["python", "typescript", "javascript", "java"]).optional(),
34
34
  framework: z.enum(["playwright", "pytest", "robot", "junit"]).optional(),
35
35
  testDirectory: z.string().optional(),
@@ -318,11 +318,11 @@ export class WorkspaceConfigManager {
318
318
  const validatedService = svcResult.data;
319
319
  const config = await this.read();
320
320
  const services = config.services || [];
321
- // Upsert keyed on the composite (repo, serviceName). Absent repo normalizes
322
- // to "" (primary) so a primary service and a same-named additional-repo
321
+ // Upsert keyed on the composite (repository, serviceName). Absent repository
322
+ // normalizes to "" (primary) so a primary service and a same-named related-repo
323
323
  // service are distinct entries.
324
- const repoKey = validatedService.repo || "";
325
- const idx = services.findIndex((s) => (s.repo || "") === repoKey &&
324
+ const repoKey = validatedService.repository || "";
325
+ const idx = services.findIndex((s) => (s.repository || "") === repoKey &&
326
326
  s.serviceName === validatedService.serviceName);
327
327
  if (idx >= 0) {
328
328
  services[idx] = validatedService;
@@ -0,0 +1 @@
1
+ export {};
@@ -6,10 +6,10 @@ import yaml from "js-yaml";
6
6
  import { serviceSchema, WorkspaceConfigManager, validateWorkspaceConfig, createDefaultConfig, WORKSPACE_DIR, WORKSPACE_FILENAME, } from "./workspace.js";
7
7
  describe("workspace module (ported from @skyramp/skyramp, SKYR-3794)", () => {
8
8
  describe("serviceSchema", () => {
9
- it("accepts an optional repo and rejects a non-string repo", () => {
10
- expect(serviceSchema.safeParse({ serviceName: "api", repo: "org/api" }).success).toBe(true);
9
+ it("accepts an optional repository and rejects a non-string repository", () => {
10
+ expect(serviceSchema.safeParse({ serviceName: "api", repository: "org/api" }).success).toBe(true);
11
11
  expect(serviceSchema.safeParse({ serviceName: "api" }).success).toBe(true);
12
- expect(serviceSchema.safeParse({ serviceName: "api", repo: 123 }).success).toBe(false);
12
+ expect(serviceSchema.safeParse({ serviceName: "api", repository: 123 }).success).toBe(false);
13
13
  });
14
14
  it("rejects unknown fields (strict)", () => {
15
15
  expect(serviceSchema.safeParse({ serviceName: "api", bogus: true }).success).toBe(false);
@@ -42,12 +42,12 @@ describe("workspace module (ported from @skyramp/skyramp, SKYR-3794)", () => {
42
42
  const mgr = new WorkspaceConfigManager(repoDir);
43
43
  await mgr.initialize();
44
44
  await mgr.addService({ serviceName: "svc", testDirectory: "tests/primary" });
45
- await mgr.addService({ serviceName: "svc", repo: "letsramp/api-insight", testDirectory: "tests/py" });
45
+ await mgr.addService({ serviceName: "svc", repository: "letsramp/api-insight", testDirectory: "tests/py" });
46
46
  await mgr.addService({ serviceName: "svc", testDirectory: "tests/primary-v2" }); // upsert primary
47
47
  const cfg = read();
48
48
  expect(cfg.services).toHaveLength(2);
49
- expect(cfg.services.find((s) => !s.repo).testDirectory).toBe("tests/primary-v2");
50
- expect(cfg.services.find((s) => s.repo === "letsramp/api-insight").testDirectory).toBe("tests/py");
49
+ expect(cfg.services.find((s) => !s.repository).testDirectory).toBe("tests/primary-v2");
50
+ expect(cfg.services.find((s) => s.repository === "letsramp/api-insight").testDirectory).toBe("tests/py");
51
51
  // repoName auto-detected from the git remote.
52
52
  expect(cfg.workspace.repoName).toBe("letsramp/primary");
53
53
  });
@@ -36,20 +36,23 @@ const loadTraceSchema = {
36
36
  name: "skyramp_load_trace",
37
37
  title: "Load and replay a Skyramp trace",
38
38
  description: [
39
- "Load a previously recorded Skyramp trace (.zip or .jsonl/.txt) and replay its actions against the live browser to restore state, then continue recording from that point.",
40
- "The replayed actions are merged into the current recording, so subsequent browser_* steps append to them and skyramp_export_zip writes a combined trace.",
41
- "STOPPING EARLY: when the user wants to stop partway through the loaded trace before continuing, set ONE of stopAtStep / stopAtUrl / stopBefore based on their prompt. Omit all three to replay the whole trace.",
42
- "- stopAtStep: replay steps 1..N then stop (N is 1-based, from the numbered step list).",
39
+ "Load a previously recorded Skyramp trace (.zip or .jsonl/.txt) and replay a range of its actions against the live browser to restore state, then continue recording from that point.",
40
+ "The replayed actions are merged into the current recording, so subsequent browser_* steps append to them and skyramp_export_zip writes a combined trace. You can record some steps FIRST, then load a trace to insert an already-recorded fragment at the current point.",
41
+ "STARTING LATER (skip a stale prefix): set startAtStep to begin replay partway in, skipping earlier steps. Use this when the live browser is already past the trace's opening steps - e.g. the login page changed, you recorded the NEW login manually, and now want to append only the still-valid post-login part of the old trace. Omit to start from step 1.",
42
+ "- startAtStep: begin replay at step N (1-based, from the numbered step list); steps 1..N-1 are skipped (neither replayed nor recorded).",
43
+ "STOPPING EARLY: when the user wants to stop partway through the loaded trace before continuing, set ONE of stopAtStep / stopAtUrl / stopBefore based on their prompt. Omit all three to replay to the end.",
44
+ "- stopAtStep: replay up to and including step N then stop (N is 1-based, from the numbered step list).",
43
45
  "- stopAtUrl: stop once the active page URL matches this glob/regex/substring (checked after each action).",
44
46
  '- stopBefore: stop right BEFORE the first action whose description contains this text (case-insensitive), e.g. "Checkout" to stop before clicking Checkout.',
45
- "If unsure where to stop, first call with dryRun:true to read the numbered step list, then call again with the chosen stop parameter."
47
+ "If unsure where to start/stop, first call with dryRun:true to read the numbered step list, then call again with the chosen start/stop parameters."
46
48
  ].join(" "),
47
49
  inputSchema: import_mcpBundle.z.object({
48
50
  path: import_mcpBundle.z.string().describe("Absolute path to the trace file (.zip, .jsonl, or .txt)."),
49
- stopAtStep: import_mcpBundle.z.number().int().positive().optional().describe("Replay steps 1..N (1-based), then stop before continuing."),
51
+ startAtStep: import_mcpBundle.z.number().int().positive().optional().describe("Begin replay at step N (1-based); skip steps 1..N-1. Use to skip a stale prefix (e.g. old login)."),
52
+ stopAtStep: import_mcpBundle.z.number().int().positive().optional().describe("Replay up to and including step N (1-based), then stop before continuing."),
50
53
  stopAtUrl: import_mcpBundle.z.string().optional().describe("Stop once the active page URL matches this glob/regex/substring."),
51
54
  stopBefore: import_mcpBundle.z.string().optional().describe("Stop before the first action whose description contains this text (case-insensitive)."),
52
- dryRun: import_mcpBundle.z.boolean().optional().describe("Parse and list the steps WITHOUT replaying. Use to choose a stop point."),
55
+ dryRun: import_mcpBundle.z.boolean().optional().describe("Parse and list the steps WITHOUT replaying. Use to choose start/stop points."),
53
56
  speed: import_mcpBundle.z.enum(["fast", "slow"]).optional().describe('Replay speed. "slow" adds a 1s delay between actions (default "fast").')
54
57
  }),
55
58
  // Replaying drives the live browser and mutates the recording, so this is an
@@ -134,17 +137,30 @@ function describeStopReason(result) {
134
137
  async function replayActions(actionsList, callbacks, params) {
135
138
  const delay = params.speed === "slow" ? 1e3 : 0;
136
139
  const stopBefore = params.stopBefore?.toLowerCase();
137
- let completedCount = 0;
138
- for (let i = 0; i < actionsList.length; i++) {
140
+ const startIndex = params.startAtStep ? Math.max(0, Math.min(params.startAtStep - 1, actionsList.length)) : 0;
141
+ let completedCount = startIndex;
142
+ for (let i = startIndex; i < actionsList.length; i++) {
139
143
  const action = actionsList[i];
140
144
  if (stopBefore && describeStep(action, i).toLowerCase().includes(stopBefore))
141
- return { completedCount, stopIndex: i, stopReason: "stopBefore" };
145
+ return { completedCount, startIndex, stopIndex: i, stopReason: "stopBefore" };
146
+ try {
147
+ callbacks.beforeAction?.(action);
148
+ } catch (e) {
149
+ return {
150
+ completedCount,
151
+ startIndex,
152
+ stopIndex: i,
153
+ stopReason: "error",
154
+ error: { message: e.message, actionName: action.action.name, stepIndex: i + 1 }
155
+ };
156
+ }
142
157
  const alias = action.frame.pageAlias || "page";
143
158
  const page = callbacks.pageForAlias(alias);
144
159
  if (!METADATA_ONLY_ACTIONS.has(action.action.name)) {
145
160
  if (!page) {
146
161
  return {
147
162
  completedCount,
163
+ startIndex,
148
164
  stopIndex: i,
149
165
  stopReason: "error",
150
166
  error: { message: `No live page for alias "${alias}"`, actionName: action.action.name, stepIndex: i + 1 }
@@ -152,9 +168,11 @@ async function replayActions(actionsList, callbacks, params) {
152
168
  }
153
169
  try {
154
170
  await performClientAction(page, action);
171
+ await callbacks.afterAction?.(action);
155
172
  } catch (e) {
156
173
  return {
157
174
  completedCount,
175
+ startIndex,
158
176
  stopIndex: i,
159
177
  stopReason: "error",
160
178
  error: { message: e.message, actionName: action.action.name, stepIndex: i + 1 }
@@ -163,16 +181,16 @@ async function replayActions(actionsList, callbacks, params) {
163
181
  }
164
182
  completedCount = i + 1;
165
183
  if (params.stopAtStep !== void 0 && completedCount >= params.stopAtStep)
166
- return { completedCount, stopIndex: i + 1, stopReason: "stopAtStep" };
184
+ return { completedCount, startIndex, stopIndex: i + 1, stopReason: "stopAtStep" };
167
185
  if (params.stopAtUrl) {
168
186
  const currentUrl = page?.url() ?? "";
169
187
  if (urlMatchesPattern(currentUrl, params.stopAtUrl))
170
- return { completedCount, stopIndex: i + 1, stopReason: "stopAtUrl" };
188
+ return { completedCount, startIndex, stopIndex: i + 1, stopReason: "stopAtUrl" };
171
189
  }
172
190
  if (delay)
173
191
  await new Promise((resolve) => setTimeout(resolve, delay));
174
192
  }
175
- return { completedCount, stopIndex: actionsList.length, stopReason: "done" };
193
+ return { completedCount, startIndex, stopIndex: actionsList.length, stopReason: "done" };
176
194
  }
177
195
  function urlMatchesPattern(currentUrl, pattern) {
178
196
  const regexLiteral = /^\/(.*)\/([a-z]*)$/i.exec(pattern);