@empiricalrun/test-gen 0.74.1 → 0.75.0

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 (100) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/agent/base/index.d.ts +36 -0
  3. package/dist/agent/base/index.d.ts.map +1 -0
  4. package/dist/agent/base/index.js +74 -0
  5. package/dist/agent/chat/agent-loop.d.ts +4 -5
  6. package/dist/agent/chat/agent-loop.d.ts.map +1 -1
  7. package/dist/agent/chat/agent-loop.js +2 -9
  8. package/dist/agent/chat/exports.d.ts +3 -3
  9. package/dist/agent/chat/exports.d.ts.map +1 -1
  10. package/dist/agent/chat/exports.js +5 -5
  11. package/dist/agent/chat/index.d.ts.map +1 -1
  12. package/dist/agent/chat/index.js +8 -11
  13. package/dist/agent/chat/state.d.ts +2 -3
  14. package/dist/agent/chat/state.d.ts.map +1 -1
  15. package/dist/agent/chat/state.js +0 -8
  16. package/dist/agent/chat/utils.d.ts +0 -1
  17. package/dist/agent/chat/utils.d.ts.map +1 -1
  18. package/dist/agent/chat/utils.js +1 -14
  19. package/dist/file-info/adapters/github/index.d.ts +2 -2
  20. package/dist/file-info/adapters/github/index.d.ts.map +1 -1
  21. package/dist/file-info/adapters/github/index.js +3 -2
  22. package/dist/file-info/adapters/github/reader.d.ts +3 -3
  23. package/dist/file-info/adapters/github/reader.d.ts.map +1 -1
  24. package/dist/file-info/adapters/github/reader.js +17 -16
  25. package/dist/tools/commit-and-create-pr/index.js +1 -1
  26. package/dist/tools/definitions/fetch-video-analysis.d.ts +28 -0
  27. package/dist/tools/definitions/fetch-video-analysis.d.ts.map +1 -1
  28. package/dist/tools/definitions/fetch-video-analysis.js +39 -4
  29. package/dist/tools/definitions/list-tests-and-projects.d.ts +12 -0
  30. package/dist/tools/definitions/list-tests-and-projects.d.ts.map +1 -0
  31. package/dist/tools/definitions/list-tests-and-projects.js +25 -0
  32. package/dist/tools/definitions/rename-file.d.ts +3 -0
  33. package/dist/tools/definitions/rename-file.d.ts.map +1 -0
  34. package/dist/tools/definitions/rename-file.js +23 -0
  35. package/dist/tools/delete-file/index.d.ts.map +1 -1
  36. package/dist/tools/delete-file/index.js +13 -1
  37. package/dist/tools/executor/index.d.ts.map +1 -1
  38. package/dist/tools/executor/index.js +6 -3
  39. package/dist/tools/executor/utils/checkpoint.d.ts +1 -3
  40. package/dist/tools/executor/utils/checkpoint.d.ts.map +1 -1
  41. package/dist/tools/executor/utils/checkpoint.js +17 -17
  42. package/dist/tools/executor/utils/git.d.ts +9 -1
  43. package/dist/tools/executor/utils/git.d.ts.map +1 -1
  44. package/dist/tools/executor/utils/git.js +72 -2
  45. package/dist/tools/{fetch-image → fetch-file}/index.d.ts +2 -2
  46. package/dist/tools/fetch-file/index.d.ts.map +1 -0
  47. package/dist/tools/fetch-file/index.js +97 -0
  48. package/dist/tools/fetch-video-analysis/index.d.ts +3 -3
  49. package/dist/tools/fetch-video-analysis/index.d.ts.map +1 -1
  50. package/dist/tools/fetch-video-analysis/index.js +71 -22
  51. package/dist/tools/fetch-video-analysis/local-ffmpeg-client.d.ts +8 -9
  52. package/dist/tools/fetch-video-analysis/local-ffmpeg-client.d.ts.map +1 -1
  53. package/dist/tools/fetch-video-analysis/local-ffmpeg-client.js +55 -17
  54. package/dist/tools/fetch-video-analysis/open-ai.d.ts +6 -0
  55. package/dist/tools/fetch-video-analysis/open-ai.d.ts.map +1 -0
  56. package/dist/tools/fetch-video-analysis/open-ai.js +37 -0
  57. package/dist/tools/fetch-video-analysis/utils.d.ts +6 -3
  58. package/dist/tools/fetch-video-analysis/utils.d.ts.map +1 -1
  59. package/dist/tools/fetch-video-analysis/utils.js +41 -15
  60. package/dist/tools/fetch-video-analysis/video-analysis.js +1 -1
  61. package/dist/tools/file-operations/create.d.ts.map +1 -1
  62. package/dist/tools/file-operations/create.js +6 -3
  63. package/dist/tools/file-operations/insert.d.ts.map +1 -1
  64. package/dist/tools/file-operations/insert.js +6 -3
  65. package/dist/tools/file-operations/replace.d.ts.map +1 -1
  66. package/dist/tools/file-operations/replace.js +6 -3
  67. package/dist/tools/file-operations/shared/git-helper.d.ts.map +1 -1
  68. package/dist/tools/file-operations/shared/git-helper.js +1 -1
  69. package/dist/tools/file-operations/view/index.d.ts +2 -5
  70. package/dist/tools/file-operations/view/index.d.ts.map +1 -1
  71. package/dist/tools/file-operations/view/index.js +2 -22
  72. package/dist/tools/index.d.ts +1 -1
  73. package/dist/tools/index.d.ts.map +1 -1
  74. package/dist/tools/index.js +19 -6
  75. package/dist/tools/issues/update-issue.d.ts.map +1 -1
  76. package/dist/tools/issues/update-issue.js +16 -9
  77. package/dist/tools/list-tests-and-projects/index.d.ts +6 -0
  78. package/dist/tools/list-tests-and-projects/index.d.ts.map +1 -0
  79. package/dist/tools/list-tests-and-projects/index.js +57 -0
  80. package/dist/tools/merge-conflicts/index.js +1 -1
  81. package/dist/tools/rename-file/index.d.ts +3 -0
  82. package/dist/tools/rename-file/index.d.ts.map +1 -0
  83. package/dist/tools/rename-file/index.js +88 -0
  84. package/dist/tools/run-test.js +2 -2
  85. package/dist/tools/test-gen-browser.js +1 -1
  86. package/dist/tools/trace-dot-zip/index.d.ts.map +1 -1
  87. package/dist/tools/trace-dot-zip/index.js +2 -1
  88. package/dist/tools/trace-dot-zip/types.d.ts +35 -3
  89. package/dist/tools/trace-dot-zip/types.d.ts.map +1 -1
  90. package/dist/tools/trace-dot-zip/utils/network-trace.d.ts +7 -2
  91. package/dist/tools/trace-dot-zip/utils/network-trace.d.ts.map +1 -1
  92. package/dist/tools/trace-dot-zip/utils/network-trace.js +130 -10
  93. package/dist/tools/upgrade-packages/index.js +1 -1
  94. package/dist/utils/index.d.ts +0 -1
  95. package/dist/utils/index.d.ts.map +1 -1
  96. package/dist/utils/index.js +1 -3
  97. package/package.json +5 -5
  98. package/tsconfig.tsbuildinfo +1 -1
  99. package/dist/tools/fetch-image/index.d.ts.map +0 -1
  100. package/dist/tools/fetch-image/index.js +0 -63
@@ -6,10 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.fileViewExecutor = fileViewExecutor;
7
7
  const path_1 = __importDefault(require("path"));
8
8
  const file_info_1 = require("../../../file-info");
9
- const git_1 = require("../../executor/utils/git");
10
9
  const helpers_1 = require("../shared/helpers");
11
- async function fileViewExecutor(params, options) {
12
- const { input, repoName, apiClient, repoPath } = params;
10
+ async function fileViewExecutor(params) {
11
+ const { input, repoPath } = params;
13
12
  const filePath = input.path;
14
13
  if (filePath === undefined || filePath === null) {
15
14
  return {
@@ -23,26 +22,7 @@ async function fileViewExecutor(params, options) {
23
22
  isError: true,
24
23
  };
25
24
  }
26
- const { use } = options || {};
27
- const wantsToUseGitHub = use && use === "github";
28
- const canUseGitHub = wantsToUseGitHub && apiClient && repoName;
29
- if (wantsToUseGitHub && !canUseGitHub) {
30
- return {
31
- result: "Error: GitHub integration is not available",
32
- isError: true,
33
- };
34
- }
35
25
  try {
36
- if (canUseGitHub) {
37
- const branchName = await (0, git_1.getCurrentBranchName)(repoName);
38
- return (0, file_info_1.viewFileUsingGitHub)({
39
- input,
40
- filePath,
41
- repoName,
42
- apiClient,
43
- branchName,
44
- });
45
- }
46
26
  const absoluteFilePath = path_1.default.join(repoPath, filePath);
47
27
  return (0, file_info_1.viewFileUsingFileSystem)({ input, filePath, absoluteFilePath });
48
28
  }
@@ -1,7 +1,7 @@
1
1
  import { PendingToolCall, ServicePayload, SupportedChatModels, Tool, ToolDefinition } from "@empiricalrun/shared-types";
2
2
  type ToolOrToolDefinition = Tool | ToolDefinition;
3
3
  export declare const allToolsDefinitions: ToolOrToolDefinition[];
4
- export declare function availableTools(model?: SupportedChatModels, isTriage?: boolean): Array<ToolDefinition | Tool>;
4
+ export declare function availableTools(model?: SupportedChatModels, isTriage?: boolean, featureFlags?: string[]): Array<ToolDefinition | Tool>;
5
5
  export declare function toolsNeedBrowser(toolCalls: PendingToolCall[]): boolean;
6
6
  export declare function nameForTelemetry(toolCall: PendingToolCall): string;
7
7
  export declare function sendToolRequestToRemoteQueue(payload: ServicePayload): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,IAAI,EACJ,cAAc,EACf,MAAM,4BAA4B,CAAC;AAwBpC,KAAK,oBAAoB,GAAG,IAAI,GAAG,cAAc,CAAC;AAiClD,eAAO,MAAM,mBAAmB,EAAE,oBAAoB,EAIrD,CAAC;AAEF,wBAAgB,cAAc,CAC5B,KAAK,CAAC,EAAE,mBAAmB,EAC3B,QAAQ,CAAC,EAAE,OAAO,GACjB,KAAK,CAAC,cAAc,GAAG,IAAI,CAAC,CAW9B;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,eAAe,EAAE,WAM5D;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAQlE;AAED,wBAAsB,4BAA4B,CAAC,OAAO,EAAE,cAAc,iBAoBzE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,IAAI,EACJ,cAAc,EACf,MAAM,4BAA4B,CAAC;AA6BpC,KAAK,oBAAoB,GAAG,IAAI,GAAG,cAAc,CAAC;AAkClD,eAAO,MAAM,mBAAmB,EAAE,oBAAoB,EAMrD,CAAC;AAEF,wBAAgB,cAAc,CAC5B,KAAK,CAAC,EAAE,mBAAmB,EAC3B,QAAQ,CAAC,EAAE,OAAO,EAClB,YAAY,CAAC,EAAE,MAAM,EAAE,GACtB,KAAK,CAAC,cAAc,GAAG,IAAI,CAAC,CAmB9B;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,eAAe,EAAE,WAM5D;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAQlE;AAED,wBAAsB,4BAA4B,CAAC,OAAO,EAAE,cAAc,iBAoBzE"}
@@ -12,13 +12,15 @@ const delete_file_1 = require("./definitions/delete-file");
12
12
  const download_build_1 = require("./definitions/download-build");
13
13
  const fetch_video_analysis_1 = require("./definitions/fetch-video-analysis");
14
14
  const grep_1 = require("./definitions/grep");
15
+ const list_tests_and_projects_1 = require("./definitions/list-tests-and-projects");
15
16
  const merge_conflicts_1 = require("./definitions/merge-conflicts");
17
+ const rename_file_1 = require("./definitions/rename-file");
16
18
  const run_test_1 = require("./definitions/run-test");
17
19
  const str_replace_editor_1 = require("./definitions/str_replace_editor");
18
20
  const test_gen_browser_1 = require("./definitions/test-gen-browser");
19
21
  const upgrade_packages_1 = require("./definitions/upgrade-packages");
20
22
  const diagnosis_fetcher_1 = require("./diagnosis-fetcher");
21
- const fetch_image_1 = require("./fetch-image");
23
+ const fetch_file_1 = require("./fetch-file");
22
24
  const fetch_last_successful_test_run_1 = require("./fetch-last-successful-test-run");
23
25
  const issues_1 = require("./issues");
24
26
  const list_environments_1 = require("./list-environments");
@@ -35,7 +37,7 @@ const commonTools = [
35
37
  diagnosis_fetcher_1.fetchDiagnosisReportTool,
36
38
  list_environments_1.listEnvironmentsTool,
37
39
  download_build_1.downloadBuildTool,
38
- fetch_image_1.fetchImageTool,
40
+ fetch_file_1.fetchFileTool,
39
41
  trace_dot_zip_1.traceDotZipTool,
40
42
  ];
41
43
  const testGenerationTools = [
@@ -43,6 +45,7 @@ const testGenerationTools = [
43
45
  commit_and_create_pr_1.createPullRequestTool,
44
46
  merge_conflicts_1.mergeConflictsTool,
45
47
  delete_file_1.deleteFileTool,
48
+ rename_file_1.renameFileTool,
46
49
  upgrade_packages_1.upgradePackagesTool,
47
50
  test_run_fetcher_1.fetchTestRunReportTool,
48
51
  ];
@@ -59,14 +62,24 @@ exports.allToolsDefinitions = [
59
62
  ...commonTools,
60
63
  ...testGenerationTools,
61
64
  ...triageOnlyTools,
65
+ list_tests_and_projects_1.listProjectsTool,
66
+ list_tests_and_projects_1.listTestsForProjectTool,
62
67
  ];
63
- function availableTools(model, isTriage) {
68
+ function availableTools(model, isTriage, featureFlags) {
64
69
  let tools = [...commonTools];
65
70
  if (isTriage) {
66
- tools = [...tools, ...triageOnlyTools];
71
+ let triageTools = [...triageOnlyTools];
72
+ tools = [...tools, ...triageTools];
67
73
  }
68
74
  else {
69
75
  tools = [...tools, ...testGenerationTools];
76
+ // Also add fetchVideoAnalysis to normal agent if feature flag is enabled
77
+ if (!isTriage && featureFlags?.includes("useVideoAnalysis")) {
78
+ // Avoid duplicate if already present
79
+ if (!tools.some((tool) => tool.schema.name === "fetchVideoAnalysis")) {
80
+ tools.push(fetch_video_analysis_1.fetchVideoAnalysis);
81
+ }
82
+ }
70
83
  }
71
84
  if (model && (0, chat_1.getProviderForModel)(model) !== "claude") {
72
85
  tools.push(...Object.values(str_replace_editor_1.textEditorTools));
@@ -74,8 +87,8 @@ function availableTools(model, isTriage) {
74
87
  return tools;
75
88
  }
76
89
  function toolsNeedBrowser(toolCalls) {
77
- const allTools = availableTools();
78
- return toolCalls.some((toolCall) => allTools.find((t) => t.schema.name === toolCall.name)?.needsBrowser);
90
+ return toolCalls.some((toolCall) => exports.allToolsDefinitions.find((t) => t.schema.name === toolCall.name)
91
+ ?.needsBrowser);
79
92
  }
80
93
  function nameForTelemetry(toolCall) {
81
94
  const toolName = toolCall.name;
@@ -1 +1 @@
1
- {"version":3,"file":"update-issue.d.ts","sourceRoot":"","sources":["../../../src/tools/issues/update-issue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,4BAA4B,CAAC;AAwBvD,eAAO,MAAM,eAAe,EAAE,IA4D7B,CAAC"}
1
+ {"version":3,"file":"update-issue.d.ts","sourceRoot":"","sources":["../../../src/tools/issues/update-issue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,IAAI,EAAE,MAAM,4BAA4B,CAAC;AAwB9D,eAAO,MAAM,eAAe,EAAE,IAsE7B,CAAC"}
@@ -31,22 +31,29 @@ exports.updateIssueTool = {
31
31
  isInlineTool: true,
32
32
  execute: async ({ input, apiClient }) => {
33
33
  try {
34
- const { id, title, description, issue_type, test_issue_prompt, test_cases_affected = [], test_run_info = [], } = input;
34
+ const { id, title, description, issue_type, test_issue_prompt, test_cases_affected, test_run_info, } = input;
35
35
  if (!apiClient) {
36
36
  throw new Error("Dashboard API client is not available.");
37
37
  }
38
- const updateData = {
39
- test_cases_affected,
40
- test_run_info,
41
- };
42
- if (title !== undefined)
38
+ const updateData = {};
39
+ if (title !== undefined) {
43
40
  updateData.title = title;
44
- if (description !== undefined)
41
+ }
42
+ if (description !== undefined) {
45
43
  updateData.description = description;
46
- if (issue_type !== undefined)
44
+ }
45
+ if (issue_type !== undefined) {
47
46
  updateData.issue_type = issue_type;
48
- if (test_issue_prompt !== undefined)
47
+ }
48
+ if (test_issue_prompt !== undefined) {
49
49
  updateData.test_issue_prompt = test_issue_prompt;
50
+ }
51
+ if (test_cases_affected !== undefined && test_cases_affected.length > 0) {
52
+ updateData.test_cases_affected = test_cases_affected;
53
+ }
54
+ if (test_run_info !== undefined && test_run_info.length > 0) {
55
+ updateData.test_run_info = test_run_info;
56
+ }
50
57
  const response = await (0, utils_1.updateIssue)(apiClient, id, updateData);
51
58
  if (!response.data?.issue) {
52
59
  return {
@@ -0,0 +1,6 @@
1
+ import { Tool } from "@empiricalrun/shared-types";
2
+ export declare const objectAsString: (obj: any) => string;
3
+ export declare function parseObjectString(objectString: string): any;
4
+ export declare const listProjectsTool: Tool;
5
+ export declare const listTestsForProjectTool: Tool;
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/list-tests-and-projects/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAc,MAAM,4BAA4B,CAAC;AAgB9D,eAAO,MAAM,cAAc,GAAI,KAAK,GAAG,WAKnC,CAAC;AAEL,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,GAAG,CAkB3D;AAED,eAAO,MAAM,gBAAgB,EAAE,IAY9B,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,IAgBrC,CAAC"}
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.listTestsForProjectTool = exports.listProjectsTool = exports.objectAsString = void 0;
7
+ exports.parseObjectString = parseObjectString;
8
+ const test_run_1 = require("@empiricalrun/test-run");
9
+ const util_1 = __importDefault(require("util"));
10
+ const vm_1 = __importDefault(require("vm"));
11
+ const list_tests_and_projects_1 = require("../definitions/list-tests-and-projects");
12
+ const objectAsString = (obj) => util_1.default.inspect(obj, {
13
+ depth: null,
14
+ colors: false, // Important: false for plain string
15
+ compact: false,
16
+ });
17
+ exports.objectAsString = objectAsString;
18
+ function parseObjectString(objectString) {
19
+ try {
20
+ const code = `(${objectString})`;
21
+ const context = {
22
+ RegExp: RegExp,
23
+ undefined: undefined,
24
+ null: null,
25
+ true: true,
26
+ false: false,
27
+ };
28
+ return vm_1.default.runInNewContext(code, context, {
29
+ timeout: 1000,
30
+ });
31
+ }
32
+ catch (error) {
33
+ console.error("Error parsing object string:", error);
34
+ return null;
35
+ }
36
+ }
37
+ exports.listProjectsTool = {
38
+ ...list_tests_and_projects_1.listProjectsTool,
39
+ execute: async ({ repoPath }) => {
40
+ const projects = await (0, test_run_1.getProjectsFromPlaywrightConfig)(test_run_1.Platform.WEB, repoPath);
41
+ return {
42
+ isError: false,
43
+ result: JSON.stringify(projects),
44
+ };
45
+ },
46
+ };
47
+ exports.listTestsForProjectTool = {
48
+ ...list_tests_and_projects_1.listTestsForProjectTool,
49
+ execute: async ({ repoPath, input, }) => {
50
+ const data = await (0, test_run_1.listProjectsAndTests)(repoPath);
51
+ const projectToFilter = input.project;
52
+ return {
53
+ isError: false,
54
+ result: JSON.stringify(data.projectsToTestCases[projectToFilter]),
55
+ };
56
+ },
57
+ };
@@ -59,7 +59,7 @@ exports.mergeConflictsTool = {
59
59
  }
60
60
  else if (mergeResult === "CONFLICTS") {
61
61
  const files = getConflictedFilesWithContents(repoPath);
62
- (0, git_1.commitFilesAsBotUser)({
62
+ (0, git_1.stageAndCommitFilesAsBotUser)({
63
63
  commitMessage: "Merge from main with conflicts",
64
64
  files: Object.keys(files),
65
65
  repoPath,
@@ -0,0 +1,3 @@
1
+ import type { Tool } from "@empiricalrun/shared-types";
2
+ export declare const renameFileTool: Tool;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/rename-file/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,4BAA4B,CAAC;AAQnE,eAAO,MAAM,cAAc,EAAE,IA6E5B,CAAC"}
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.renameFileTool = void 0;
7
+ const child_process_1 = require("child_process");
8
+ const promises_1 = require("fs/promises");
9
+ const path_1 = __importDefault(require("path"));
10
+ const web_1 = require("../../bin/utils/platform/web");
11
+ const rename_file_1 = require("../definitions/rename-file");
12
+ exports.renameFileTool = {
13
+ ...rename_file_1.renameFileTool,
14
+ execute: async ({ input, repoPath }) => {
15
+ try {
16
+ const oldFilePath = path_1.default.join(repoPath, input.oldPath);
17
+ const newFilePath = path_1.default.join(repoPath, input.newPath);
18
+ try {
19
+ const stats = await (0, promises_1.stat)(oldFilePath);
20
+ if (!stats.isFile()) {
21
+ return {
22
+ isError: true,
23
+ result: `Error: '${input.oldPath}' is not a file. Use a different tool to rename directories.`,
24
+ };
25
+ }
26
+ }
27
+ catch {
28
+ return {
29
+ isError: true,
30
+ result: `Error: File '${input.oldPath}' does not exist.`,
31
+ };
32
+ }
33
+ const resolvedOldPath = path_1.default.resolve(oldFilePath);
34
+ const resolvedNewPath = path_1.default.resolve(newFilePath);
35
+ const resolvedRepoPath = path_1.default.resolve(repoPath);
36
+ if (!resolvedOldPath.startsWith(resolvedRepoPath)) {
37
+ return {
38
+ isError: true,
39
+ result: `Error: Source file is outside the repository root.`,
40
+ };
41
+ }
42
+ if (!resolvedNewPath.startsWith(resolvedRepoPath)) {
43
+ return {
44
+ isError: true,
45
+ result: `Error: Destination path is outside the repository root.`,
46
+ };
47
+ }
48
+ try {
49
+ await (0, promises_1.stat)(newFilePath);
50
+ return {
51
+ isError: true,
52
+ result: `Error: Destination file '${input.newPath}' already exists.`,
53
+ };
54
+ }
55
+ catch {
56
+ // File doesn't exist, which is what we want
57
+ }
58
+ const newDir = path_1.default.dirname(newFilePath);
59
+ await (0, promises_1.mkdir)(newDir, { recursive: true });
60
+ await (0, promises_1.rename)(oldFilePath, newFilePath);
61
+ // Stage both files for git porcelain
62
+ function stageFile(filePath) {
63
+ return (0, child_process_1.execSync)(`git add ${filePath}`, { cwd: repoPath });
64
+ }
65
+ stageFile(oldFilePath);
66
+ stageFile(newFilePath);
67
+ // Run TypeScript compilation check
68
+ const tscResult = await (0, web_1.runTypescriptCompiler)(repoPath);
69
+ if (!tscResult.success) {
70
+ return {
71
+ result: `File renamed from '${input.oldPath}' to '${input.newPath}'. However, type checks are failing with errors:\n\n${tscResult.errors.join("\n")}`,
72
+ isError: true,
73
+ };
74
+ }
75
+ return {
76
+ isError: false,
77
+ result: `Successfully renamed file from '${input.oldPath}' to '${input.newPath}'`,
78
+ };
79
+ }
80
+ catch (error) {
81
+ console.error("Error renaming file", error);
82
+ return {
83
+ isError: true,
84
+ result: error instanceof Error ? error.message : String(error),
85
+ };
86
+ }
87
+ },
88
+ };
@@ -9,7 +9,7 @@ const fs_1 = __importDefault(require("fs"));
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const artifacts_1 = require("../artifacts");
11
11
  const utils_1 = require("../artifacts/utils");
12
- const utils_2 = require("../utils");
12
+ const json_1 = require("../utils/json");
13
13
  const run_test_1 = require("./definitions/run-test");
14
14
  function buildReportUrl(projectName, testRunId) {
15
15
  return `https://reports.empirical.run/${projectName}/${testRunId}/index.html`;
@@ -17,7 +17,7 @@ function buildReportUrl(projectName, testRunId) {
17
17
  function buildResult({ hasTestPassed, summaryJson, reportUrl, }) {
18
18
  const summaryWithoutConfig = { ...summaryJson, config: undefined };
19
19
  delete summaryWithoutConfig["config"];
20
- const truncatedSummaryJson = (0, utils_2.truncateJsonValues)(summaryWithoutConfig);
20
+ const truncatedSummaryJson = (0, json_1.truncateJsonValues)(summaryWithoutConfig);
21
21
  return `
22
22
  Test run is complete. Result: ${hasTestPassed ? "Passed" : "Failed"}
23
23
 
@@ -25,7 +25,7 @@ exports.generateTestWithBrowserAgent = {
25
25
  };
26
26
  }
27
27
  try {
28
- const { projects } = await (0, test_run_1.getAllPlaywrightProjects)(repoPath);
28
+ const { projects } = await (0, test_run_1.listProjectsAndTests)(repoPath);
29
29
  if (!projects.includes(project)) {
30
30
  return {
31
31
  isError: true,
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/trace-dot-zip/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAc,MAAM,4BAA4B,CAAC;AAa9D,eAAO,MAAM,eAAe,EAAE,IAqD7B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/trace-dot-zip/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAc,MAAM,4BAA4B,CAAC;AAa9D,eAAO,MAAM,eAAe,EAAE,IAwD7B,CAAC"}
@@ -28,11 +28,12 @@ exports.traceDotZipTool = {
28
28
  (0, network_trace_1.generateNetworkTraceFromZipUrl)({ url: traceFileUrl }),
29
29
  (0, console_trace_1.generateConsoleTraceFromZipUrl)({ url: traceFileUrl }),
30
30
  ]);
31
- const cleanNetworkTraceOutput = (0, network_trace_1.stripIrrelevantInfoFromNetworkFailureArray)(networkTraceOutput);
31
+ const cleanNetworkTraceOutput = (0, network_trace_1.stripIrrelevantInfoFromNetworkFailureArray)(networkTraceOutput.hydratedFailedCalls);
32
32
  return {
33
33
  isError: false,
34
34
  result: JSON.stringify({
35
35
  failed_network_requests: cleanNetworkTraceOutput,
36
+ request_sequence: networkTraceOutput.networkCallSequence,
36
37
  console_error_logs: consoleTraceOutput,
37
38
  }, null, 2),
38
39
  };
@@ -8,13 +8,35 @@ export type CapturedNetworkFailure = {
8
8
  headers: {
9
9
  [any: string]: string;
10
10
  }[] | [];
11
+ body?: {
12
+ mimeType?: string;
13
+ text?: string;
14
+ params?: any[];
15
+ _sha1?: string;
16
+ content?: string;
17
+ };
11
18
  };
12
19
  response: {
13
20
  headers: {
14
21
  [any: string]: string;
15
22
  }[] | [];
23
+ body?: {
24
+ mimeType?: string;
25
+ text?: string;
26
+ params?: any[];
27
+ _sha1?: string;
28
+ content?: string;
29
+ };
16
30
  };
17
31
  };
32
+ export type NetworkRequestSequence = {
33
+ step: number;
34
+ method: string;
35
+ endpoint: string;
36
+ status: number;
37
+ redirect_to?: string;
38
+ duration_ms: number;
39
+ };
18
40
  export type CapturedConsoleLog = {
19
41
  type: "console";
20
42
  messageType: "log" | "info" | "warning" | "error" | string;
@@ -44,11 +66,12 @@ export type PlaywrightNetworkTrace = {
44
66
  queryString: any[];
45
67
  headersSize: number;
46
68
  bodySize: number;
47
- postData: {
69
+ postData?: {
48
70
  mimeType: string;
49
- text: string;
71
+ text?: string;
50
72
  params: any[];
51
- _sha1: string;
73
+ _sha1?: string;
74
+ _file?: string;
52
75
  };
53
76
  };
54
77
  response: {
@@ -61,6 +84,15 @@ export type PlaywrightNetworkTrace = {
61
84
  bodySize: number;
62
85
  redirectURL: string;
63
86
  _transferSize: number;
87
+ content: {
88
+ size: number;
89
+ mimeType: string;
90
+ text?: string;
91
+ encoding?: string;
92
+ _sha1?: string;
93
+ _file?: string;
94
+ compression?: number;
95
+ };
64
96
  };
65
97
  cache: any;
66
98
  timings: {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/tools/trace-dot-zip/types.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,iCAAiC,EAAE,MAAM,CAAC;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE;QACP,OAAO,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,EAAE,GAAG,EAAE,CAAC;KAC3C,CAAC;IACF,QAAQ,EAAE;QACR,OAAO,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,EAAE,GAAG,EAAE,CAAC;KAC3C,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,SAAS,CAAC;IAChB,WAAW,EAAE,KAAK,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,QAAQ,EAAE;QACR,GAAG,EAAE,MAAM,CAAC;QACZ,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE;QACR,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,EAAE,MAAM,CAAC;QACvB,eAAe,EAAE,MAAM,CAAC;QACxB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE;YACP,MAAM,EAAE,MAAM,CAAC;YACf,GAAG,EAAE,MAAM,CAAC;YACZ,WAAW,EAAE,MAAM,CAAC;YACpB,OAAO,EAAE,GAAG,EAAE,CAAC;YACf,OAAO,EAAE,GAAG,EAAE,CAAC;YACf,WAAW,EAAE,GAAG,EAAE,CAAC;YACnB,WAAW,EAAE,MAAM,CAAC;YACpB,QAAQ,EAAE,MAAM,CAAC;YACjB,QAAQ,EAAE;gBACR,QAAQ,EAAE,MAAM,CAAC;gBACjB,IAAI,EAAE,MAAM,CAAC;gBACb,MAAM,EAAE,GAAG,EAAE,CAAC;gBACd,KAAK,EAAE,MAAM,CAAC;aACf,CAAC;SACH,CAAC;QACF,QAAQ,EAAE;YACR,MAAM,EAAE,MAAM,CAAC;YACf,UAAU,EAAE,MAAM,CAAC;YACnB,WAAW,EAAE,MAAM,CAAC;YACpB,OAAO,EAAE,GAAG,EAAE,CAAC;YACf,OAAO,EAAE,GAAG,EAAE,CAAC;YACf,WAAW,EAAE,MAAM,CAAC;YACpB,QAAQ,EAAE,MAAM,CAAC;YACjB,WAAW,EAAE,MAAM,CAAC;YACpB,aAAa,EAAE,MAAM,CAAC;SACvB,CAAC;QACF,KAAK,EAAE,GAAG,CAAC;QACX,OAAO,EAAE;YACP,GAAG,EAAE,MAAM,CAAC;YACZ,OAAO,EAAE,MAAM,CAAC;YAChB,GAAG,EAAE,MAAM,CAAC;YACZ,IAAI,EAAE,MAAM,CAAC;YACb,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,EAAE,MAAM,CAAC;SACjB,CAAC;QACF,OAAO,EAAE,MAAM,CAAC;QAChB,eAAe,EAAE,MAAM,CAAC;QACxB,WAAW,EAAE,MAAM,CAAC;QACpB,gBAAgB,EAAE;YAChB,QAAQ,EAAE,MAAM,CAAC;YACjB,WAAW,EAAE,MAAM,CAAC;YACpB,MAAM,EAAE,MAAM,CAAC;YACf,SAAS,EAAE,MAAM,CAAC;YAClB,OAAO,EAAE,MAAM,CAAC;SACjB,CAAC;KACH,CAAC;CACH,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/tools/trace-dot-zip/types.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { CapturedNetworkFailure } from "../types";
1
+ import { CapturedNetworkFailure, NetworkRequestSequence, PlaywrightNetworkTrace } from "../types";
2
2
  type ArgsT = {
3
3
  url: string;
4
4
  logPrefix?: string;
@@ -15,7 +15,12 @@ export declare const generateNetworkTrace: ({ logPrefix, url, failure, }: ArgsT)
15
15
  allFailedCalls: CapturedNetworkFailure[];
16
16
  failedCallsWithinTimeRange: CapturedNetworkFailure[];
17
17
  }>;
18
- export declare const generateNetworkTraceFromZipUrl: ({ url, }: ArgsT) => Promise<CapturedNetworkFailure[]>;
18
+ export declare const generateNetworkTraceFromZipUrl: ({ url, }: ArgsT) => Promise<{
19
+ hydratedFailedCalls: CapturedNetworkFailure[];
20
+ networkCallSequence: NetworkRequestSequence[];
21
+ }>;
19
22
  export declare const stripIrrelevantInfoFromNetworkFailureArray: (failures: CapturedNetworkFailure[]) => Partial<CapturedNetworkFailure>[];
23
+ export declare const hydrateSha1Bodies: (failures: CapturedNetworkFailure[], zipUrl: string) => Promise<CapturedNetworkFailure[]>;
24
+ export declare const buildNetworkCallSequence: (unformattedFailedNetworkCallsWithHeaders: PlaywrightNetworkTrace[]) => NetworkRequestSequence[];
20
25
  export {};
21
26
  //# sourceMappingURL=network-trace.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"network-trace.d.ts","sourceRoot":"","sources":["../../../../src/tools/trace-dot-zip/utils/network-trace.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,sBAAsB,EAA0B,MAAM,UAAU,CAAC;AAU1E,KAAK,KAAK,GAAG;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,EACJ;YACE,IAAI,EAAE,MAAM,CAAC;YACb,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,EAAE,MAAM,CAAC;SAChB,GACD,SAAS,CAAC;KACf,CAAC;CACH,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAU,8BAIxC,KAAK,KAAG,OAAO,CAAC;IACjB,cAAc,EAAE,sBAAsB,EAAE,CAAC;IACzC,0BAA0B,EAAE,sBAAsB,EAAE,CAAC;CACtD,CA8KA,CAAC;AAEF,eAAO,MAAM,8BAA8B,GAAU,UAElD,KAAK,KAAG,OAAO,CAAC,sBAAsB,EAAE,CAmC1C,CAAC;AAoBF,eAAO,MAAM,0CAA0C,GACrD,UAAU,sBAAsB,EAAE,KACjC,OAAO,CAAC,sBAAsB,CAAC,EAUjC,CAAC"}
1
+ {"version":3,"file":"network-trace.d.ts","sourceRoot":"","sources":["../../../../src/tools/trace-dot-zip/utils/network-trace.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACvB,MAAM,UAAU,CAAC;AAUlB,KAAK,KAAK,GAAG;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,EACJ;YACE,IAAI,EAAE,MAAM,CAAC;YACb,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,EAAE,MAAM,CAAC;SAChB,GACD,SAAS,CAAC;KACf,CAAC;CACH,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAU,8BAIxC,KAAK,KAAG,OAAO,CAAC;IACjB,cAAc,EAAE,sBAAsB,EAAE,CAAC;IACzC,0BAA0B,EAAE,sBAAsB,EAAE,CAAC;CACtD,CA+KA,CAAC;AAEF,eAAO,MAAM,8BAA8B,GAAU,UAElD,KAAK,KAAG,OAAO,CAAC;IACjB,mBAAmB,EAAE,sBAAsB,EAAE,CAAC;IAC9C,mBAAmB,EAAE,sBAAsB,EAAE,CAAC;CAC/C,CAyEA,CAAC;AAsBF,eAAO,MAAM,0CAA0C,GACrD,UAAU,sBAAsB,EAAE,KACjC,OAAO,CAAC,sBAAsB,CAAC,EAoBjC,CAAC;AAmCF,eAAO,MAAM,iBAAiB,GAC5B,UAAU,sBAAsB,EAAE,EAClC,QAAQ,MAAM,KACb,OAAO,CAAC,sBAAsB,EAAE,CA+BlC,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,0CAA0C,sBAAsB,EAAE,KACjE,sBAAsB,EA2BxB,CAAC"}