@empiricalrun/test-gen 0.79.2 → 0.79.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/agent/chat/exports.d.ts +1 -0
  3. package/dist/agent/chat/exports.d.ts.map +1 -1
  4. package/dist/agent/chat/exports.js +3 -1
  5. package/dist/agent/chat/index.js +1 -1
  6. package/dist/agent/chat/prompt/repo.d.ts.map +1 -1
  7. package/dist/agent/chat/prompt/repo.js +4 -3
  8. package/dist/agent/fast-triage/index.d.ts +8 -0
  9. package/dist/agent/fast-triage/index.d.ts.map +1 -0
  10. package/dist/agent/fast-triage/index.js +51 -0
  11. package/dist/agent/index.d.ts +2 -1
  12. package/dist/agent/index.d.ts.map +1 -1
  13. package/dist/agent/index.js +4 -1
  14. package/dist/agent/triage/index.js +2 -2
  15. package/dist/bin/index.js +5 -3
  16. package/dist/bin/utils/platform/web/index.d.ts.map +1 -1
  17. package/dist/bin/utils/platform/web/index.js +3 -2
  18. package/dist/dashboard/client.d.ts +11 -1
  19. package/dist/dashboard/client.d.ts.map +1 -1
  20. package/dist/dashboard/client.js +22 -9
  21. package/dist/file-info/adapters/github/index.d.ts.map +1 -1
  22. package/dist/file-info/adapters/github/index.js +1 -1
  23. package/dist/generate-summary/frame-sampling.d.ts +12 -0
  24. package/dist/generate-summary/frame-sampling.d.ts.map +1 -0
  25. package/dist/generate-summary/frame-sampling.js +72 -0
  26. package/dist/generate-summary/generate-error-stack-summary.d.ts +11 -0
  27. package/dist/generate-summary/generate-error-stack-summary.d.ts.map +1 -0
  28. package/dist/generate-summary/generate-error-stack-summary.js +44 -0
  29. package/dist/generate-summary/generate-failed-step-screenshot-diff-summary.d.ts +58 -0
  30. package/dist/generate-summary/generate-failed-step-screenshot-diff-summary.d.ts.map +1 -0
  31. package/dist/generate-summary/generate-failed-step-screenshot-diff-summary.js +460 -0
  32. package/dist/generate-summary/generate-grouped-summary.d.ts +18 -0
  33. package/dist/generate-summary/generate-grouped-summary.d.ts.map +1 -0
  34. package/dist/generate-summary/generate-grouped-summary.js +91 -0
  35. package/dist/generate-summary/merge-summary.d.ts +16 -0
  36. package/dist/generate-summary/merge-summary.d.ts.map +1 -0
  37. package/dist/generate-summary/merge-summary.js +46 -0
  38. package/dist/generate-summary/pick-videos-for-comparison.d.ts +9 -0
  39. package/dist/generate-summary/pick-videos-for-comparison.d.ts.map +1 -0
  40. package/dist/generate-summary/pick-videos-for-comparison.js +54 -0
  41. package/dist/telemetry/index.d.ts.map +1 -1
  42. package/dist/telemetry/index.js +3 -1
  43. package/dist/tools/definitions/delete-file.js +1 -1
  44. package/dist/tools/definitions/grep.d.ts.map +1 -1
  45. package/dist/tools/definitions/grep.js +1 -1
  46. package/dist/tools/definitions/rename-file.js +2 -2
  47. package/dist/tools/definitions/safe-bash.d.ts.map +1 -1
  48. package/dist/tools/definitions/safe-bash.js +10 -8
  49. package/dist/tools/definitions/str_replace_editor.d.ts.map +1 -1
  50. package/dist/tools/definitions/str_replace_editor.js +12 -4
  51. package/dist/tools/definitions/trace-dot-zip.d.ts +7 -0
  52. package/dist/tools/definitions/trace-dot-zip.d.ts.map +1 -0
  53. package/dist/tools/definitions/trace-dot-zip.js +16 -0
  54. package/dist/tools/definitions/utils.js +1 -1
  55. package/dist/tools/delete-file/index.d.ts.map +1 -1
  56. package/dist/tools/delete-file/index.js +9 -6
  57. package/dist/tools/diagnosis-fetcher.d.ts.map +1 -1
  58. package/dist/tools/diagnosis-fetcher.js +40 -2
  59. package/dist/tools/fetch-file/index.d.ts.map +1 -1
  60. package/dist/tools/fetch-file/index.js +102 -3
  61. package/dist/tools/file-operations/index.d.ts.map +1 -1
  62. package/dist/tools/file-operations/index.js +7 -5
  63. package/dist/tools/file-operations/shared/helpers.d.ts +13 -0
  64. package/dist/tools/file-operations/shared/helpers.d.ts.map +1 -1
  65. package/dist/tools/file-operations/shared/helpers.js +24 -0
  66. package/dist/tools/file-operations/view/index.d.ts.map +1 -1
  67. package/dist/tools/file-operations/view/index.js +9 -3
  68. package/dist/tools/grep/index.d.ts.map +1 -1
  69. package/dist/tools/grep/index.js +7 -2
  70. package/dist/tools/index.d.ts +1 -1
  71. package/dist/tools/index.d.ts.map +1 -1
  72. package/dist/tools/index.js +6 -6
  73. package/dist/tools/merge-conflicts/index.d.ts.map +1 -1
  74. package/dist/tools/merge-conflicts/index.js +8 -8
  75. package/dist/tools/rename-file/index.d.ts.map +1 -1
  76. package/dist/tools/rename-file/index.js +11 -7
  77. package/dist/tools/run-test.d.ts.map +1 -1
  78. package/dist/tools/run-test.js +12 -7
  79. package/dist/tools/safe-bash/index.d.ts.map +1 -1
  80. package/dist/tools/safe-bash/index.js +18 -2
  81. package/dist/tools/test-gen-browser.d.ts.map +1 -1
  82. package/dist/tools/test-gen-browser.js +12 -9
  83. package/dist/tools/trace-dot-zip/index.d.ts +3 -1
  84. package/dist/tools/trace-dot-zip/index.d.ts.map +1 -1
  85. package/dist/tools/trace-dot-zip/index.js +8 -20
  86. package/dist/tools/trace-dot-zip/utils/console-trace.d.ts.map +1 -1
  87. package/dist/tools/trace-dot-zip/utils/console-trace.js +11 -5
  88. package/dist/tools/trace-dot-zip/utils/extract-screenshots.d.ts +27 -0
  89. package/dist/tools/trace-dot-zip/utils/extract-screenshots.d.ts.map +1 -0
  90. package/dist/tools/trace-dot-zip/utils/extract-screenshots.js +128 -0
  91. package/dist/tools/trace-dot-zip/utils/extract-steps.d.ts +12 -0
  92. package/dist/tools/trace-dot-zip/utils/extract-steps.d.ts.map +1 -0
  93. package/dist/tools/trace-dot-zip/utils/extract-steps.js +130 -0
  94. package/dist/tools/trace-dot-zip/utils/extract-zip.d.ts +13 -16
  95. package/dist/tools/trace-dot-zip/utils/extract-zip.d.ts.map +1 -1
  96. package/dist/tools/trace-dot-zip/utils/extract-zip.js +27 -167
  97. package/dist/tools/trace-dot-zip/utils/network-trace.d.ts.map +1 -1
  98. package/dist/tools/trace-dot-zip/utils/network-trace.js +136 -105
  99. package/dist/trace-utils/cli.d.ts +3 -0
  100. package/dist/trace-utils/cli.d.ts.map +1 -0
  101. package/dist/trace-utils/cli.js +302 -0
  102. package/dist/trace-utils/console.d.ts +11 -0
  103. package/dist/trace-utils/console.d.ts.map +1 -0
  104. package/dist/trace-utils/console.js +74 -0
  105. package/dist/trace-utils/dom-snapshot.d.ts +19 -0
  106. package/dist/trace-utils/dom-snapshot.d.ts.map +1 -0
  107. package/dist/trace-utils/dom-snapshot.js +328 -0
  108. package/dist/trace-utils/index.d.ts +8 -0
  109. package/dist/trace-utils/index.d.ts.map +1 -1
  110. package/dist/trace-utils/index.js +19 -1
  111. package/dist/trace-utils/network.d.ts +16 -0
  112. package/dist/trace-utils/network.d.ts.map +1 -0
  113. package/dist/trace-utils/network.js +178 -0
  114. package/dist/trace-utils/normalize-trace-url.d.ts +2 -0
  115. package/dist/trace-utils/normalize-trace-url.d.ts.map +1 -0
  116. package/dist/trace-utils/normalize-trace-url.js +15 -0
  117. package/dist/trace-utils/screenshots.d.ts +24 -0
  118. package/dist/trace-utils/screenshots.d.ts.map +1 -0
  119. package/dist/trace-utils/screenshots.js +197 -0
  120. package/dist/trace-utils/steps.d.ts +10 -0
  121. package/dist/trace-utils/steps.d.ts.map +1 -0
  122. package/dist/trace-utils/steps.js +126 -0
  123. package/dist/trace-utils/types.d.ts +51 -0
  124. package/dist/trace-utils/types.d.ts.map +1 -0
  125. package/dist/trace-utils/types.js +2 -0
  126. package/dist/utils/playwright-report-parser.d.ts +1 -12
  127. package/dist/utils/playwright-report-parser.d.ts.map +1 -1
  128. package/dist/utils/playwright-report-parser.js +8 -136
  129. package/dist/video-core/index.d.ts.map +1 -1
  130. package/dist/video-core/index.js +17 -33
  131. package/package.json +12 -6
  132. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.pickVideosForComparison = void 0;
4
+ const getVideoSize = async (url) => {
5
+ const response = await fetch(url, { method: "HEAD" });
6
+ if (!response.ok) {
7
+ console.warn(`Failed to fetch ${url}: ${response.statusText}`);
8
+ return 0;
9
+ }
10
+ const contentLength = response.headers.get("content-length");
11
+ if (!contentLength) {
12
+ console.warn(`Content-Length header is missing for ${url}`);
13
+ return 0;
14
+ }
15
+ const videoSize = parseInt(contentLength, 10);
16
+ console.log(`Recording size for ${url} is ------> ${videoSize} bytes`);
17
+ return videoSize;
18
+ };
19
+ const pickVideosForComparison = async ({ testRunId, test, }) => {
20
+ const videosPickedForComparison = {
21
+ failure: "",
22
+ success: "",
23
+ };
24
+ try {
25
+ const failureVideoWithLargestSize = (await Promise.all(test.failure.videos.map(async (video) => {
26
+ const size = await getVideoSize(video);
27
+ return { videoUrl: video, size };
28
+ }))).reduce((max, current) => {
29
+ return current.size > max.size ? current : max;
30
+ }, { videoUrl: "", size: 0 });
31
+ console.log(`Picking failure recording with largest size ------> ${failureVideoWithLargestSize.size}, url - ${failureVideoWithLargestSize.videoUrl}`);
32
+ videosPickedForComparison.failure = failureVideoWithLargestSize.videoUrl;
33
+ const successVideoWithLargestSize = (await Promise.all(test?.success?.videos?.map(async (video) => {
34
+ const size = await getVideoSize(video);
35
+ return { videoUrl: video, size };
36
+ }))).reduce((max, current) => {
37
+ return current.size > max.size ? current : max;
38
+ }, { videoUrl: "", size: 0 });
39
+ console.log(`Picking success recording with largest size ------> ${successVideoWithLargestSize.size}, url - ${successVideoWithLargestSize.videoUrl}`);
40
+ videosPickedForComparison.success = successVideoWithLargestSize.videoUrl;
41
+ if (!videosPickedForComparison.failure) {
42
+ console.warn(`No failure run recordings found for test - "${test.title}", for testRunId - "${testRunId}"`);
43
+ }
44
+ if (!videosPickedForComparison.success) {
45
+ console.warn(`No last successful run recordings found for test - "${test.title}", for testRunId - "${testRunId}"`);
46
+ }
47
+ return videosPickedForComparison;
48
+ }
49
+ catch (e) {
50
+ console.error("Error while processing bookmarks", e);
51
+ return videosPickedForComparison;
52
+ }
53
+ };
54
+ exports.pickVideosForComparison = pickVideosForComparison;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/telemetry/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,UAAU,EACV,KAAK,EACN,MAAM,uCAAuC,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAM3E,MAAM,MAAM,YAAY,GAAG;IACzB,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,wBAAsB,UAAU,CAC9B,KAAK,EAAE,cAAc,EACrB,GAAG,CAAC,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED,wBAAsB,yBAAyB,CAC7C,QAAQ,EAAE,eAAe,EACzB,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,MAAM,EACvB,GAAG,CAAC,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAcf;AAED,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,eAAe,EACzB,UAAU,EAAE,UAAU,EACtB,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,MAAM,EACvB,gBAAgB,EAAE,MAAM,EACxB,GAAG,CAAC,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,CAAC,EAAE,YAAY,CAAC;CACpB,GAAG,IAAI,CAoBP"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/telemetry/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,UAAU,EACV,KAAK,EACN,MAAM,uCAAuC,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAM3E,MAAM,MAAM,YAAY,GAAG;IACzB,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,wBAAsB,UAAU,CAC9B,KAAK,EAAE,cAAc,EACrB,GAAG,CAAC,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED,wBAAsB,yBAAyB,CAC7C,QAAQ,EAAE,eAAe,EACzB,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,MAAM,EACvB,GAAG,CAAC,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAcf;AAED,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,eAAe,EACzB,UAAU,EAAE,UAAU,EACtB,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,MAAM,EACvB,gBAAgB,EAAE,MAAM,EACxB,GAAG,CAAC,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,CAAC,EAAE,YAAY,CAAC;CACpB,GAAG,IAAI,CAsBP"}
@@ -71,13 +71,15 @@ function trackLLMResponse(opts) {
71
71
  properties: {
72
72
  environment,
73
73
  model_name: opts.modelName,
74
- project_repo_name: opts.projectRepoName,
75
74
  chat_session_id: opts.chatSessionId,
76
75
  chat_session_source: opts.chatSessionSource,
77
76
  tokens_input: opts.usage.tokens?.input || 0,
78
77
  tokens_output: opts.usage.tokens?.output || 0,
79
78
  cost_input: opts.usage.cost?.input || 0,
80
79
  cost_output: opts.usage.cost?.output || 0,
80
+ // Moving project_repo_name -> repo_name for consistency with other events
81
+ project_repo_name: opts.projectRepoName,
82
+ repo_name: opts.projectRepoName,
81
83
  },
82
84
  }, opts.env);
83
85
  }
@@ -5,7 +5,7 @@ const zod_1 = require("zod");
5
5
  exports.DeleteFileInputSchema = zod_1.z.object({
6
6
  path: zod_1.z
7
7
  .string()
8
- .describe("The path to the file to delete (relative to the repository root). For example, tests/foo.spec.ts"),
8
+ .describe("The path to the file to delete. Prefer using absolute paths with /repo/ prefix (e.g., /repo/tests/foo.spec.ts), but relative paths from the repository root are also supported (e.g., tests/foo.spec.ts)."),
9
9
  });
10
10
  exports.deleteFileTool = {
11
11
  schema: {
@@ -1 +1 @@
1
- {"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../../src/tools/definitions/grep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAmB5E,eAAO,MAAM,QAAQ,EAAE,cAWtB,CAAC"}
1
+ {"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../../src/tools/definitions/grep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAqB5E,eAAO,MAAM,QAAQ,EAAE,cAWtB,CAAC"}
@@ -9,7 +9,7 @@ const GrepInputSchema = zod_1.z.object({
9
9
  directory: zod_1.z
10
10
  .string()
11
11
  .optional()
12
- .describe("The directory to search in (defaults to current directory)"),
12
+ .describe("The directory to search in (defaults to current directory). Prefer using absolute paths with /repo/ prefix (e.g., /repo/tests), but relative paths are also supported (e.g., tests)."),
13
13
  filePattern: zod_1.z
14
14
  .string()
15
15
  .optional()
@@ -5,10 +5,10 @@ const zod_1 = require("zod");
5
5
  const RenameFileInputSchema = zod_1.z.object({
6
6
  oldPath: zod_1.z
7
7
  .string()
8
- .describe("The current path to the file to rename (relative to the repository root). For example, tests/foo.spec.ts"),
8
+ .describe("The current path to the file to rename. Prefer using absolute paths with /repo/ prefix (e.g., /repo/tests/foo.spec.ts), but relative paths from the repository root are also supported (e.g., tests/foo.spec.ts)."),
9
9
  newPath: zod_1.z
10
10
  .string()
11
- .describe("The new path for the file (relative to the repository root). For example, tests/new-dir/bar.spec.ts"),
11
+ .describe("The new path for the file. Prefer using absolute paths with /repo/ prefix (e.g., /repo/tests/new-dir/bar.spec.ts), but relative paths from the repository root are also supported (e.g., tests/new-dir/bar.spec.ts)."),
12
12
  });
13
13
  exports.renameFileTool = {
14
14
  schema: {
@@ -1 +1 @@
1
- {"version":3,"file":"safe-bash.d.ts","sourceRoot":"","sources":["../../../src/tools/definitions/safe-bash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,mBAAmB;;;iBAM9B,CAAC;AAEH,eAAO,MAAM,YAAY,EAAE,cAoB1B,CAAC"}
1
+ {"version":3,"file":"safe-bash.d.ts","sourceRoot":"","sources":["../../../src/tools/definitions/safe-bash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,mBAAmB;;;iBAM9B,CAAC;AAEH,eAAO,MAAM,YAAY,EAAE,cAsB1B,CAAC"}
@@ -13,18 +13,20 @@ exports.safeBashTool = {
13
13
  schema: {
14
14
  name: "safeBash",
15
15
  description: `Execute a bash script with branch protection and controlled git operations.
16
+ The reo dir is the cwd for this tool: No need to do "cd /repo".
16
17
 
17
- This tool ensures safe execution by:
18
- - Blocking branch-changing commands (git checkout, git switch, git reset --hard)
19
- - Blocking git commit and git push commands (handled by the executor harness)
20
- - Verifying the branch hasn't changed after execution
18
+ IMPORTANT: If the script modifies files that need to be pushed to the repo, the script MUST
19
+ stage them using 'git add' -- but DO NOT commit/push them. The executor harness will automatically
20
+ commit staged files and push to the remote.
21
21
 
22
- If the script modifies files that need to be pushed to the repo, the script MUST stage them using 'git add'.
23
- The executor harness will automatically commit staged files and push to the remote.
22
+ For example, if you use this tool to upgrade NPM packages, you should stage package.json and package-lock.json
23
+ files.
24
24
 
25
- For example, if you use this tool to upgrade NPM packages, you should stage package.json and package-lock.json files.
25
+ The tool returns typescript compiler result after running script, stdout, stderr, staged
26
+ files (which will be committed), and unstaged files.
26
27
 
27
- The tool returns stdout, stderr, staged files (will be committed), and unstaged files.`,
28
+ This tool restricts commits/push, or branch switching, and will throw errors.
29
+ `,
28
30
  parameters: exports.SafeBashInputSchema,
29
31
  },
30
32
  needsBrowser: false,
@@ -1 +1 @@
1
- {"version":3,"file":"str_replace_editor.d.ts","sourceRoot":"","sources":["../../../src/tools/definitions/str_replace_editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AA6EvE,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAK1D,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAExD,CAAC"}
1
+ {"version":3,"file":"str_replace_editor.d.ts","sourceRoot":"","sources":["../../../src/tools/definitions/str_replace_editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AA6FvE,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAK1D,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAExD,CAAC"}
@@ -16,7 +16,9 @@ File contents are returned with line numbers, starting from 1.
16
16
  ...`,
17
17
  parameters: zod_1.z.object({
18
18
  // Does not support view_range for now
19
- path: zod_1.z.string().describe("The path to the file or directory to view."),
19
+ path: zod_1.z
20
+ .string()
21
+ .describe("The path to the file or directory to view. Prefer using absolute paths with /repo/ prefix (e.g., /repo/tests/foo.spec.ts), but relative paths are also supported (e.g., tests/foo.spec.ts)."),
20
22
  }),
21
23
  },
22
24
  needsBrowser: false,
@@ -30,7 +32,9 @@ This tool will also create parent directories that do not exist.
30
32
  For example, for path "tests/example/foo.spec.ts", the tool will create
31
33
  directories "tests", "tests/example", and "tests/example/foo.spec.ts".`,
32
34
  parameters: zod_1.z.object({
33
- path: zod_1.z.string().describe("The path to the new file."),
35
+ path: zod_1.z
36
+ .string()
37
+ .describe("The path to the new file. Prefer using absolute paths with /repo/ prefix (e.g., /repo/tests/foo.spec.ts), but relative paths are also supported (e.g., tests/foo.spec.ts)."),
34
38
  file_text: zod_1.z.string().describe("The contents of the new file."),
35
39
  }),
36
40
  },
@@ -43,7 +47,9 @@ const stringReplaceTool = {
43
47
  description: `A tool to replace a string in a file. This tool requires old_str to be unique
44
48
  in the file. If old_str is not unique, the tool will return an error.`,
45
49
  parameters: zod_1.z.object({
46
- path: zod_1.z.string().describe("The path to the file."),
50
+ path: zod_1.z
51
+ .string()
52
+ .describe("The path to the file. Prefer using absolute paths with /repo/ prefix (e.g., /repo/tests/foo.spec.ts), but relative paths are also supported (e.g., tests/foo.spec.ts)."),
47
53
  old_str: zod_1.z.string().describe("The string to be replaced."),
48
54
  new_str: zod_1.z.string().describe("The string to replace old_str with."),
49
55
  }),
@@ -56,7 +62,9 @@ const stringInsertTool = {
56
62
  name: "stringInsertTool",
57
63
  description: "A tool to insert a string at a specific line in a file.",
58
64
  parameters: zod_1.z.object({
59
- path: zod_1.z.string().describe("The path to the file."),
65
+ path: zod_1.z
66
+ .string()
67
+ .describe("The path to the file. Prefer using absolute paths with /repo/ prefix (e.g., /repo/tests/foo.spec.ts), but relative paths are also supported (e.g., tests/foo.spec.ts)."),
60
68
  insert_line: zod_1.z
61
69
  .number()
62
70
  .int()
@@ -0,0 +1,7 @@
1
+ import { ToolDefinition } from "@empiricalrun/shared-types/chat-agent";
2
+ import { z } from "zod";
3
+ export declare const traceDotZipSchema: z.ZodObject<{
4
+ url: z.ZodString;
5
+ }, z.core.$strip>;
6
+ export declare const traceDotZip: ToolDefinition<z.infer<typeof traceDotZipSchema>>;
7
+ //# sourceMappingURL=trace-dot-zip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-dot-zip.d.ts","sourceRoot":"","sources":["../../../src/tools/definitions/trace-dot-zip.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AACvE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,iBAAiB;;iBAE5B,CAAC;AAEH,eAAO,MAAM,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAQzE,CAAC"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.traceDotZip = exports.traceDotZipSchema = void 0;
4
+ const zod_1 = require("zod");
5
+ exports.traceDotZipSchema = zod_1.z.object({
6
+ url: zod_1.z.string().describe(`The URL to the "trace.zip" file.`),
7
+ });
8
+ exports.traceDotZip = {
9
+ schema: {
10
+ name: "traceDotZip",
11
+ description: `Extracts failed network request and console error traces from a Playwright trace zip file. Pass a trace.zip URL to this tool and get a summary of failed network calls (by status codes) and console error logs (by "messageType") to understand network activity and console logs during the test run.`,
12
+ parameters: exports.traceDotZipSchema,
13
+ },
14
+ needsBrowser: false,
15
+ isInlineTool: false,
16
+ };
@@ -11,6 +11,6 @@ const getCommonTestNameSuitesFilePathSchema = (testNameDescription) => zod_1.z.o
11
11
  .describe("The suites (describe blocks) where the test is located. If the test is not in any describe block, provide an empty array."),
12
12
  filePath: zod_1.z
13
13
  .string()
14
- .describe("Path of the file where the test is located. Path must be relative to the repository. File name must end with .spec.ts. For example: tests/lesson.spec.ts - and NOT /repo/tests/lesson.spec.ts"),
14
+ .describe("Path of the file where the test is located. Prefer using absolute paths with /repo/ prefix, but relative paths are also supported. File name must end with .spec.ts. For example: /repo/tests/lesson.spec.ts (preferred) or tests/lesson.spec.ts (also supported)"),
15
15
  });
16
16
  exports.getCommonTestNameSuitesFilePathSchema = getCommonTestNameSuitesFilePathSchema;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/delete-file/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,IAAI,EAEL,MAAM,uCAAuC,CAAC;AAY/C,eAAO,MAAM,cAAc,EAAE,IAqE5B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/delete-file/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,IAAI,EAEL,MAAM,uCAAuC,CAAC;AAa/C,eAAO,MAAM,cAAc,EAAE,IAuE5B,CAAC"}
@@ -9,25 +9,28 @@ const promises_1 = require("fs/promises");
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const web_1 = require("../../bin/utils/platform/web");
11
11
  const delete_file_1 = require("../definitions/delete-file");
12
+ const helpers_1 = require("../file-operations/shared/helpers");
12
13
  exports.deleteFileTool = {
13
14
  ...delete_file_1.deleteFileTool,
14
15
  execute: async ({ input, repoPath, collectArtifacts, logger, }) => {
15
16
  try {
16
- const filePath = path_1.default.join(repoPath, input.path);
17
+ // Normalize the path to support both /repo/... and relative paths
18
+ const normalizedPath = (0, helpers_1.normalizePath)(input.path);
19
+ const filePath = path_1.default.join(repoPath, normalizedPath);
17
20
  // Validate that the file exists and is actually a file (not a directory)
18
21
  try {
19
22
  const stats = await (0, promises_1.stat)(filePath);
20
23
  if (!stats.isFile()) {
21
24
  return {
22
25
  isError: true,
23
- result: `Error: '${input.path}' is not a file. Use a different tool to delete directories.`,
26
+ result: `Error: '${normalizedPath}' is not a file. Use a different tool to delete directories.`,
24
27
  };
25
28
  }
26
29
  }
27
30
  catch {
28
31
  return {
29
32
  isError: true,
30
- result: `Error: File '${input.path}' does not exist.`,
33
+ result: `Error: File '${normalizedPath}' does not exist.`,
31
34
  };
32
35
  }
33
36
  const resolvedPath = path_1.default.resolve(filePath);
@@ -40,18 +43,18 @@ exports.deleteFileTool = {
40
43
  }
41
44
  await (0, promises_1.unlink)(filePath);
42
45
  // Stage the deletion
43
- (0, child_process_1.execSync)(`git add "${input.path}"`, { cwd: repoPath });
46
+ (0, child_process_1.execSync)(`git add "${normalizedPath}"`, { cwd: repoPath });
44
47
  // Run TypeScript compilation check
45
48
  const tscResult = await (0, web_1.runTypescriptCompiler)(repoPath);
46
49
  if (!tscResult.success) {
47
50
  return {
48
- result: `File ${input.path} has been deleted. However, type checks are failing with errors:\n\n${tscResult.errors.join("\n")}`,
51
+ result: `File ${normalizedPath} has been deleted. However, type checks are failing with errors:\n\n${tscResult.errors.join("\n")}`,
49
52
  isError: false,
50
53
  };
51
54
  }
52
55
  return {
53
56
  isError: false,
54
- result: `Successfully deleted file: ${input.path}`,
57
+ result: `Successfully deleted file: ${normalizedPath}`,
55
58
  };
56
59
  }
57
60
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"diagnosis-fetcher.d.ts","sourceRoot":"","sources":["../../src/tools/diagnosis-fetcher.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uCAAuC,CAAC;AAalE,eAAO,MAAM,wBAAwB,EAAE,IA6FtC,CAAC"}
1
+ {"version":3,"file":"diagnosis-fetcher.d.ts","sourceRoot":"","sources":["../../src/tools/diagnosis-fetcher.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uCAAuC,CAAC;AAmBlE,eAAO,MAAM,wBAAwB,EAAE,IAsItC,CAAC"}
@@ -7,6 +7,9 @@ const DiagnosisSchema = zod_1.z.object({
7
7
  diagnosisId: zod_1.z
8
8
  .string()
9
9
  .describe("12 character random string that identifies a failing test case in a test run"),
10
+ projectSlug: zod_1.z
11
+ .string()
12
+ .describe("The project slug extracted from the URL path, e.g. 'my-project' from https://dash.empirical.run/my-project/..."),
10
13
  });
11
14
  exports.fetchDiagnosisReportTool = {
12
15
  schema: {
@@ -42,7 +45,7 @@ In the above, the diagnosis id is after the double hyphen, which is "ULRHHNwiGZ2
42
45
  needsBrowser: false,
43
46
  isInlineTool: true,
44
47
  execute: async ({ input, apiClient }) => {
45
- const { diagnosisId } = input;
48
+ const { diagnosisId, projectSlug } = input;
46
49
  let data = null;
47
50
  if (!apiClient) {
48
51
  throw new Error("Dashboard API client is not available.");
@@ -61,7 +64,18 @@ In the above, the diagnosis id is after the double hyphen, which is "ULRHHNwiGZ2
61
64
  result: `Failed to fetch diagnosis details: ${error instanceof Error ? error.message : String(error)}`,
62
65
  };
63
66
  }
64
- const { test_case, diagnosis } = data.data;
67
+ const { test_case, diagnosis, test_run } = data.data;
68
+ const repoName = projectSlug.includes("-tests")
69
+ ? projectSlug
70
+ : `${projectSlug}-tests`;
71
+ let testRunEnriched = null;
72
+ try {
73
+ const testRunData = await apiClient.request(`/api/test-runs/${test_run.id}?repo_name=${repoName}`, { method: "GET" });
74
+ testRunEnriched = testRunData.data;
75
+ }
76
+ catch {
77
+ // Ignore errors fetching enriched test run data
78
+ }
65
79
  const project = diagnosis.test_project || "unknown";
66
80
  const retries = diagnosis.retry_details?.retries;
67
81
  const retryInfo = retries?.reduce((acc, current) => {
@@ -75,6 +89,18 @@ In the above, the diagnosis id is after the double hyphen, which is "ULRHHNwiGZ2
75
89
  return `${acc}\n\n## Playwright project: ${project}\n\n${JSON.stringify(value, null, 2)}`;
76
90
  }, "");
77
91
  }
92
+ const enrichedTestRun = testRunEnriched?.test_run?.testRun;
93
+ const environmentInfo = enrichedTestRun?.environment_name
94
+ ? `## Environment
95
+ - Name: ${enrichedTestRun.environment_name}
96
+ - Slug: ${enrichedTestRun.environment_slug}`
97
+ : "";
98
+ const buildInfo = enrichedTestRun?.build_url
99
+ ? `## Build info
100
+ - Build URL: ${enrichedTestRun.build_url}
101
+ - Git branch: ${enrichedTestRun.build_branch}
102
+ - Git commit: ${enrichedTestRun.commit}`
103
+ : "";
78
104
  const markdownResponse = `
79
105
  # Test Case Information
80
106
  - **Name**: ${test_case.name}
@@ -82,6 +108,18 @@ In the above, the diagnosis id is after the double hyphen, which is "ULRHHNwiGZ2
82
108
  - **File path**: tests/${test_case.file_path}
83
109
  - **Playwright project**: ${project}
84
110
 
111
+ # Test Run #${test_run.id}
112
+
113
+ ## Info
114
+ - Status: ${test_run.state}
115
+ - Started at: ${test_run.run_started_at}
116
+ - Ended at: ${test_run.run_ended_at}
117
+ - Duration: ${test_run.duration} seconds
118
+
119
+ ${environmentInfo}
120
+
121
+ ${buildInfo}
122
+
85
123
  # What happened in this test run
86
124
 
87
125
  ${retryInfo}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/fetch-file/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,IAAI,EAGL,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB,QAAA,MAAM,eAAe;;iBAEnB,CAAC;AAEH,eAAO,MAAM,aAAa,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAoI/D,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/fetch-file/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,IAAI,EAGL,MAAM,uCAAuC,CAAC;AAG/C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA2HxB,QAAA,MAAM,eAAe;;iBAEnB,CAAC;AAEH,eAAO,MAAM,aAAa,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAmJ/D,CAAC"}
@@ -1,6 +1,11 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.fetchFileTool = void 0;
7
+ const fs_1 = require("fs");
8
+ const path_1 = __importDefault(require("path"));
4
9
  const zod_1 = require("zod");
5
10
  const url_validation_1 = require("../../utils/url-validation");
6
11
  const utils_1 = require("./utils");
@@ -11,6 +16,88 @@ const SUPPORTED_IMAGE_TYPES = [
11
16
  "image/webp",
12
17
  ];
13
18
  const SUPPORTED_TEXT_TYPES = ["text/markdown", "text/plain"];
19
+ function applyLineLimitIfNeeded(text, featureFlags, url) {
20
+ const isLimitEnabled = featureFlags.includes("useLimitOnFetchFile");
21
+ if (!isLimitEnabled) {
22
+ return text;
23
+ }
24
+ const lines = text.split("\n");
25
+ if (lines.length <= 100) {
26
+ return text;
27
+ }
28
+ const trimmedText = lines.slice(0, 100).join("\n");
29
+ const message = `\n\n[Output trimmed: This file contains ${lines.length} lines, showing first 100 lines. To get the full output, use the Bash tool to fetch via curl and search the response: curl "${url}"]`;
30
+ return trimmedText + message;
31
+ }
32
+ async function handleLocalFile(filePath, logger, featureFlags) {
33
+ const ext = path_1.default.extname(filePath).toLowerCase();
34
+ const isImage = [".png", ".jpg", ".jpeg", ".gif", ".webp"].includes(ext);
35
+ const isText = [".md", ".txt", ".markdown"].includes(ext);
36
+ if (!isImage && !isText) {
37
+ return {
38
+ result: `Unsupported file type: ${ext}. Must be an image (PNG, JPEG, GIF, WebP) or text file (.md, .txt).`,
39
+ isError: true,
40
+ };
41
+ }
42
+ try {
43
+ const buffer = await fs_1.promises.readFile(filePath);
44
+ if (isImage) {
45
+ const contentType = ext === ".png"
46
+ ? "image/png"
47
+ : ext === ".gif"
48
+ ? "image/gif"
49
+ : ext === ".webp"
50
+ ? "image/webp"
51
+ : "image/jpeg";
52
+ const processedBuffer = await (0, utils_1.downscaleImageIfNeeded)(buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength), logger);
53
+ const base64 = Buffer.from(processedBuffer).toString("base64");
54
+ logger.info("Successfully read local image file", {
55
+ tool: "fetchFileTool",
56
+ filePath,
57
+ contentType,
58
+ size: processedBuffer.byteLength,
59
+ });
60
+ return {
61
+ result: [
62
+ {
63
+ type: contentType,
64
+ base64Data: base64,
65
+ },
66
+ ],
67
+ isError: false,
68
+ };
69
+ }
70
+ else {
71
+ const text = buffer.toString("utf-8");
72
+ const processedText = applyLineLimitIfNeeded(text, featureFlags, `file://${filePath}`);
73
+ logger.info("Successfully read local text file", {
74
+ tool: "fetchFileTool",
75
+ filePath,
76
+ size: text.length,
77
+ });
78
+ return {
79
+ result: [
80
+ {
81
+ type: "text",
82
+ text: processedText,
83
+ },
84
+ ],
85
+ isError: false,
86
+ };
87
+ }
88
+ }
89
+ catch (fileError) {
90
+ logger.error("Failed to read local file", {
91
+ tool: "fetchFileTool",
92
+ filePath,
93
+ error: fileError.message,
94
+ });
95
+ return {
96
+ result: `Failed to read file: ${fileError.message}`,
97
+ isError: true,
98
+ };
99
+ }
100
+ }
14
101
  const fetchFileSchema = zod_1.z.object({
15
102
  url: zod_1.z.string(),
16
103
  });
@@ -20,6 +107,10 @@ exports.fetchFileTool = {
20
107
  description: `Use this tool to fetch file data from any valid URL that responds with an image (PNG, JPEG, GIF, WebP) or markdown file.
21
108
  For images, it returns the image in base64 format for you to view or analyse. For markdown files, it returns the text content for you to read and process.
22
109
 
110
+ ## Supported URL schemes
111
+ - \`https://\` - Fetch from remote URLs
112
+ - \`file://\` - Fetch from local filesystem (e.g., \`file:///path/to/image.png\`)
113
+
23
114
  ## Caveats
24
115
  1. This will not work to fetch markdown files from a repo due to access control issues. Use file view tools for that.
25
116
 
@@ -27,18 +118,25 @@ For images, it returns the image in base64 format for you to view or analyse. Fo
27
118
  1. Understand a test report (for the runTest tool) by fetching screenshots and error context files (.md) which contain the accessibility tree of the page at the
28
119
  time of test failures. Both of these are available in the attachments section of the test report from the runTest tool call.
29
120
 
30
- 2. While adding new tests, if the user message contains image URLs, use this tool to fetch the images, and understand the steps that the user is looking to cover..`,
121
+ 2. While adding new tests, if the user message contains image URLs, use this tool to fetch the images, and understand the steps that the user is looking to cover.
122
+
123
+ 3. View screenshots extracted by the traceUtils tool (which returns file:// URLs).`,
31
124
  parameters: fetchFileSchema,
32
125
  },
33
126
  needsBrowser: false,
34
127
  isInlineTool: true,
35
- execute: async ({ input, logger, }) => {
128
+ execute: async ({ input, logger, featureFlags, }) => {
36
129
  const { url } = input;
37
130
  logger.info("Starting file fetch", {
38
131
  tool: "fetchFileTool",
39
132
  url,
40
133
  });
41
134
  try {
135
+ // Handle file:// URLs
136
+ if (url.startsWith("file://")) {
137
+ const filePath = url.replace("file://", "");
138
+ return handleLocalFile(filePath, logger, featureFlags);
139
+ }
42
140
  const headResponse = await (0, url_validation_1.validateUrlAccess)(url);
43
141
  if (!headResponse.ok) {
44
142
  logger.error("Failed to fetch file", {
@@ -105,6 +203,7 @@ time of test failures. Both of these are available in the attachments section of
105
203
  else {
106
204
  // Handle text/markdown files
107
205
  const text = await contentResponse.text();
206
+ const processedText = applyLineLimitIfNeeded(text, featureFlags, url);
108
207
  logger.info("Successfully fetched text file", {
109
208
  tool: "fetchFileTool",
110
209
  url,
@@ -115,7 +214,7 @@ time of test failures. Both of these are available in the attachments section of
115
214
  result: [
116
215
  {
117
216
  type: "text",
118
- text: text,
217
+ text: processedText,
119
218
  },
120
219
  ],
121
220
  isError: false,
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/file-operations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,EACL,gBAAgB,EAChB,IAAI,EAEJ,UAAU,EACX,MAAM,uCAAuC,CAAC;AAQ/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAGzD;;;GAGG;AACH,iBAAe,wBAAwB,CAAC,EACtC,KAAK,EACL,QAAQ,EACR,gBAAgB,EAChB,SAAS,GACV,EAAE;IACD,KAAK,EAAE,qBAAqB,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,SAAS,CAAC,EAAE,mBAAmB,CAAC;CACjC,GAAG,OAAO,CAAC,UAAU,CAAC,CAoDtB;AAgFD,QAAA,MAAM,eAAe,EAAE,IAAI,EAK1B,CAAC;AAEF,QAAA,MAAM,aAAa,EAAE,IAAI,EAAmB,CAAC;AAE7C,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/file-operations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,EACL,gBAAgB,EAChB,IAAI,EAEJ,UAAU,EACX,MAAM,uCAAuC,CAAC;AAQ/C,OAAO,EAAiB,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAGxE;;;GAGG;AACH,iBAAe,wBAAwB,CAAC,EACtC,KAAK,EACL,QAAQ,EACR,gBAAgB,EAChB,SAAS,GACV,EAAE;IACD,KAAK,EAAE,qBAAqB,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,SAAS,CAAC,EAAE,mBAAmB,CAAC;CACjC,GAAG,OAAO,CAAC,UAAU,CAAC,CAqDtB;AAgFD,QAAA,MAAM,eAAe,EAAE,IAAI,EAK1B,CAAC;AAEF,QAAA,MAAM,aAAa,EAAE,IAAI,EAAmB,CAAC;AAE7C,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC"}
@@ -10,6 +10,7 @@ const str_replace_editor_1 = require("../definitions/str_replace_editor");
10
10
  const create_1 = require("./create");
11
11
  const insert_1 = require("./insert");
12
12
  const replace_1 = require("./replace");
13
+ const helpers_1 = require("./shared/helpers");
13
14
  const view_1 = require("./view");
14
15
  /**
15
16
  * Our implementation of Claude's built-in text editor tool
@@ -17,8 +18,9 @@ const view_1 = require("./view");
17
18
  */
18
19
  async function strReplaceEditorExecutor({ input, repoPath, collectArtifacts, apiClient, }) {
19
20
  const repoDir = repoPath;
20
- const { path: filePath } = input;
21
- const absoluteFilePath = path_1.default.join(repoDir, filePath);
21
+ // Normalize the path to support both /repo/... and relative paths
22
+ const normalizedFilePath = (0, helpers_1.normalizePath)(input.path);
23
+ const absoluteFilePath = path_1.default.join(repoDir, normalizedFilePath);
22
24
  const repoName = path_1.default.basename(repoPath);
23
25
  try {
24
26
  switch (input.command) {
@@ -32,7 +34,7 @@ async function strReplaceEditorExecutor({ input, repoPath, collectArtifacts, api
32
34
  case "create":
33
35
  return (0, create_1.fileCreateExecutor)({
34
36
  input,
35
- filePath,
37
+ filePath: normalizedFilePath,
36
38
  absoluteFilePath,
37
39
  repoDir,
38
40
  collectArtifacts,
@@ -40,7 +42,7 @@ async function strReplaceEditorExecutor({ input, repoPath, collectArtifacts, api
40
42
  case "str_replace":
41
43
  return (0, replace_1.fileStrReplaceExecutor)({
42
44
  input,
43
- filePath,
45
+ filePath: normalizedFilePath,
44
46
  absoluteFilePath,
45
47
  repoDir,
46
48
  collectArtifacts,
@@ -48,7 +50,7 @@ async function strReplaceEditorExecutor({ input, repoPath, collectArtifacts, api
48
50
  case "insert":
49
51
  return (0, insert_1.fileInsertExecutor)({
50
52
  input,
51
- filePath,
53
+ filePath: normalizedFilePath,
52
54
  absoluteFilePath,
53
55
  repoDir,
54
56
  collectArtifacts,
@@ -8,6 +8,19 @@ export interface StrReplaceInputParams {
8
8
  insert_line?: number;
9
9
  insert_text?: string;
10
10
  }
11
+ /**
12
+ * Normalizes a path by removing the /repo/ prefix if present.
13
+ * This supports both absolute paths (/repo/...) and relative paths.
14
+ *
15
+ * @param filePath - The path to normalize (can be /repo/path/to/file or path/to/file)
16
+ * @returns The normalized relative path from repository root
17
+ *
18
+ * @example
19
+ * normalizePath('/repo/tests/foo.spec.ts') // returns 'tests/foo.spec.ts'
20
+ * normalizePath('tests/foo.spec.ts') // returns 'tests/foo.spec.ts'
21
+ * normalizePath('/repo/./tests/foo.spec.ts') // returns 'tests/foo.spec.ts'
22
+ */
23
+ export declare function normalizePath(filePath: string): string;
11
24
  export declare function formatLinesWithNumbers(content: string, viewRange?: [number, number]): string;
12
25
  export declare function isBinaryFile(filePath: string): boolean;
13
26
  export declare function getUniqueOccurences(contents: string, old_str: string): {
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../../src/tools/file-operations/shared/helpers.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IAGb,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAG9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,SAAS,CAAC,EAAE,MAAM,CAAC;IAKnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,MAAM,CAaR;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CA2DtD;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,EAAE,CAyDjD"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../../src/tools/file-operations/shared/helpers.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IAGb,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAG9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,SAAS,CAAC,EAAE,MAAM,CAAC;IAKnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAatD;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,MAAM,CAaR;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CA2DtD;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,EAAE,CAyDjD"}