@empiricalrun/test-gen 0.62.0 → 0.63.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 (35) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/agent/chat/index.d.ts.map +1 -1
  3. package/dist/agent/chat/index.js +8 -2
  4. package/dist/artifacts/index.d.ts +9 -0
  5. package/dist/artifacts/index.d.ts.map +1 -1
  6. package/dist/artifacts/index.js +28 -0
  7. package/dist/tool-call-service/index.d.ts.map +1 -1
  8. package/dist/tool-call-service/index.js +18 -3
  9. package/dist/tools/commit-and-create-pr.d.ts.map +1 -1
  10. package/dist/tools/commit-and-create-pr.js +11 -4
  11. package/dist/tools/diagnosis-fetcher.d.ts.map +1 -1
  12. package/dist/tools/diagnosis-fetcher.js +4 -3
  13. package/dist/tools/environment-crud.d.ts.map +1 -1
  14. package/dist/tools/environment-crud.js +6 -4
  15. package/dist/tools/grep/index.d.ts.map +1 -1
  16. package/dist/tools/grep/index.js +9 -9
  17. package/dist/tools/str_replace_editor.d.ts +1 -1
  18. package/dist/tools/str_replace_editor.d.ts.map +1 -1
  19. package/dist/tools/str_replace_editor.js +29 -26
  20. package/dist/tools/test-gen-browser.d.ts.map +1 -1
  21. package/dist/tools/test-gen-browser.js +1 -4
  22. package/dist/tools/test-run-fetcher/index.d.ts.map +1 -1
  23. package/dist/tools/test-run-fetcher/index.js +2 -1
  24. package/dist/tools/test-run.d.ts.map +1 -1
  25. package/dist/tools/test-run.js +2 -3
  26. package/dist/tools/utils/index.d.ts +4 -2
  27. package/dist/tools/utils/index.d.ts.map +1 -1
  28. package/dist/tools/utils/index.js +4 -7
  29. package/dist/utils/checkpoint.d.ts +5 -1
  30. package/dist/utils/checkpoint.d.ts.map +1 -1
  31. package/dist/utils/checkpoint.js +8 -3
  32. package/dist/utils/git.d.ts +12 -7
  33. package/dist/utils/git.d.ts.map +1 -1
  34. package/dist/utils/git.js +27 -17
  35. package/package.json +4 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @empiricalrun/test-gen
2
2
 
3
+ ## 0.63.0
4
+
5
+ ### Minor Changes
6
+
7
+ - f926e40: feat: consume repoPath in test run tool
8
+ - 55c7913: feat: artifact collection is fire-and-forget at tool level
9
+ - 2f1ee31: chore: consume repoPath and apikey in tools requiring Dashboard api call
10
+
11
+ ### Patch Changes
12
+
13
+ - c491cdd: fix: insert_line description in text editor tools
14
+ - 0fea8f1: test: add a multiline old_str replacement test
15
+ - 115a023: chore: allow grep tool to consume repoPath for the scope of search
16
+ - 6c7740b: feat: consume repoPath for all file edit tools
17
+ - Updated dependencies [f926e40]
18
+ - Updated dependencies [2f1ee31]
19
+ - @empiricalrun/test-run@0.9.4
20
+ - @empiricalrun/llm@0.17.1
21
+
3
22
  ## 0.62.0
4
23
 
5
24
  ### Minor Changes
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agent/chat/index.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,mBAAmB,EACpB,MAAM,wBAAwB,CAAC;AAyChC,wBAAsB,kBAAkB,CAAC,EACvC,mBAAmB,EACnB,aAAa,EACb,oBAAoB,EACpB,SAAS,GACV,EAAE;IACD,aAAa,EAAE,mBAAmB,CAAC;IACnC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,iBAmHA;AAuBD,wBAAsB,wBAAwB,CAAC,EAC7C,aAAa,EACb,aAAa,GACd,EAAE;IACD,aAAa,EAAE,mBAAmB,CAAC;IACnC,aAAa,EAAE,MAAM,CAAC;CACvB,iBAyDA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agent/chat/index.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,mBAAmB,EACpB,MAAM,wBAAwB,CAAC;AAyChC,wBAAsB,kBAAkB,CAAC,EACvC,mBAAmB,EACnB,aAAa,EACb,oBAAoB,EACpB,SAAS,GACV,EAAE;IACD,aAAa,EAAE,mBAAmB,CAAC;IACnC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,iBAsHA;AAuBD,wBAAsB,wBAAwB,CAAC,EAC7C,aAAa,EACb,aAAa,GACd,EAAE;IACD,aAAa,EAAE,mBAAmB,CAAC;IACnC,aAAa,EAAE,MAAM,CAAC;CACvB,iBA4DA"}
@@ -29,7 +29,7 @@ async function runChatAgentForCLI({ useDiskForChatState, selectedModel, initialP
29
29
  // TODO: Store branch name in chat state so that we don't recreate it every time
30
30
  const randomId = crypto.randomUUID().substring(0, 8);
31
31
  const branchName = `branch-${randomId}`;
32
- await (0, git_1.checkoutBranch)(branchName);
32
+ await (0, git_1.checkoutBranch)(branchName, process.cwd());
33
33
  let messagesLoadedFromDisk = chatState?.messages || [];
34
34
  let chatModel = (0, chat_1.createChatModel)(messagesLoadedFromDisk, selectedModel);
35
35
  if (initialPromptContent && chatModel.messages.length === 0) {
@@ -100,6 +100,9 @@ async function runChatAgentForCLI({ useDiskForChatState, selectedModel, initialP
100
100
  }
101
101
  else {
102
102
  // TODO: Should we pass a loader function? That would allow us to show a spinner
103
+ if (!process.env.EMPIRICALRUN_API_KEY) {
104
+ throw new Error("EMPIRICALRUN_API_KEY is not set");
105
+ }
103
106
  const toolCallService = new tool_call_service_1.ToolCallService({
104
107
  chatSessionId: null,
105
108
  selectedModel,
@@ -159,6 +162,9 @@ async function runChatAgentForDashboard({ chatSessionId, selectedModel, }) {
159
162
  chatSessionId,
160
163
  },
161
164
  });
165
+ if (!process.env.EMPIRICALRUN_API_KEY) {
166
+ throw new Error("EMPIRICALRUN_API_KEY is not set");
167
+ }
162
168
  const toolCallService = new tool_call_service_1.ToolCallService({
163
169
  chatSessionId,
164
170
  selectedModel,
@@ -167,7 +173,7 @@ async function runChatAgentForDashboard({ chatSessionId, selectedModel, }) {
167
173
  apiKey: process.env.EMPIRICALRUN_API_KEY,
168
174
  trace,
169
175
  });
170
- await (0, git_1.checkoutBranch)(branchName);
176
+ await (0, git_1.checkoutBranch)(branchName, process.cwd());
171
177
  let chatModel = (0, chat_1.createChatModel)(chatState.messages, selectedModel);
172
178
  let reporterFunc = async (chatState, latest) => {
173
179
  const response = await fetch(`${DASHBOARD_DOMAIN}/api/chat-sessions/${chatSessionId}`, {
@@ -40,4 +40,13 @@ export declare function isArtifactCollectionEnabled(): string | undefined;
40
40
  * // Throws: "Invalid path: relative/path/test.png..."
41
41
  */
42
42
  export declare function collectArtifacts(inputs: ArtifactInput[], repoDir: string, toolCallId: string): Promise<Artifact[]>;
43
+ export declare class UploadArtifactsQueue {
44
+ private toolCallId;
45
+ private baseRepoPath;
46
+ private artifactResults;
47
+ private uploadPromise;
48
+ constructor(baseRepoPath: string, toolCallId: string);
49
+ addTask(artifacts: ArtifactInput[]): Promise<void>;
50
+ waitForCompletion(): Promise<Artifact[]>;
51
+ }
43
52
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/artifacts/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,QAAQ,EACR,aAAa,EAGd,MAAM,4BAA4B,CAAC;AAkBpC,wBAAgB,2BAA2B,uBAM1C;AA6HD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,aAAa,EAAE,EACvB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,QAAQ,EAAE,CAAC,CA6DrB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/artifacts/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,QAAQ,EACR,aAAa,EAGd,MAAM,4BAA4B,CAAC;AAkBpC,wBAAgB,2BAA2B,uBAM1C;AA6HD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,aAAa,EAAE,EACvB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,QAAQ,EAAE,CAAC,CA6DrB;AAED,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,aAAa,CAA8B;gBAEvC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;IAKvC,OAAO,CAAC,SAAS,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAelD,iBAAiB,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;CAMtD"}
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.UploadArtifactsQueue = void 0;
6
7
  exports.isArtifactCollectionEnabled = isArtifactCollectionEnabled;
7
8
  exports.collectArtifacts = collectArtifacts;
8
9
  const r2_uploader_1 = require("@empiricalrun/r2-uploader");
@@ -207,3 +208,30 @@ async function collectArtifacts(inputs, repoDir, toolCallId) {
207
208
  return [];
208
209
  }
209
210
  }
211
+ class UploadArtifactsQueue {
212
+ toolCallId;
213
+ baseRepoPath;
214
+ artifactResults = [];
215
+ uploadPromise = null;
216
+ constructor(baseRepoPath, toolCallId) {
217
+ this.baseRepoPath = baseRepoPath;
218
+ this.toolCallId = toolCallId;
219
+ }
220
+ async addTask(artifacts) {
221
+ this.uploadPromise = collectArtifacts(artifacts, this.baseRepoPath, this.toolCallId)
222
+ .then((results) => {
223
+ this.artifactResults.push(...results);
224
+ })
225
+ .catch((error) => {
226
+ console.error("Error processing artifact upload task:", error);
227
+ throw error;
228
+ });
229
+ }
230
+ async waitForCompletion() {
231
+ if (this.uploadPromise) {
232
+ await this.uploadPromise;
233
+ }
234
+ return this.artifactResults;
235
+ }
236
+ }
237
+ exports.UploadArtifactsQueue = UploadArtifactsQueue;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tool-call-service/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAEL,eAAe,EACf,mBAAmB,EACnB,IAAI,EACJ,WAAW,EACX,UAAU,EACX,MAAM,wBAAwB,CAAC;AAiBhC,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,KAAK,aAAa,GAAG;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAAC;CAC5B,CAAC;AAEF,qBAAa,eAAe;IAC1B,KAAK,EAAE,IAAI,EAAE,CAAM;IACnB,aAAa,EAAE,aAAa,CAAM;IAClC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAE,mBAAmB,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,KAAK,CAAC,EAAE,WAAW,CAAC;gBACR,EACV,aAAa,EACb,aAAa,EACb,UAAU,EACV,QAAQ,EACR,MAAM,EACN,KAAK,GACN,EAAE;QACD,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,aAAa,EAAE,mBAAmB,CAAC;QACnC,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;QAC3B,KAAK,CAAC,EAAE,WAAW,CAAC;KACrB;IAiCK,WAAW,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAcxD,OAAO,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;CAmDnE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tool-call-service/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAEL,eAAe,EACf,mBAAmB,EACnB,IAAI,EACJ,WAAW,EACX,UAAU,EACX,MAAM,wBAAwB,CAAC;AAkBhC,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,KAAK,aAAa,GAAG;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAAC;CAC5B,CAAC;AAEF,qBAAa,eAAe;IAC1B,KAAK,EAAE,IAAI,EAAE,CAAM;IACnB,aAAa,EAAE,aAAa,CAAM;IAClC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAE,mBAAmB,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,KAAK,CAAC,EAAE,WAAW,CAAC;gBACR,EACV,aAAa,EACb,aAAa,EACb,UAAU,EACV,QAAQ,EACR,MAAM,EACN,KAAK,GACN,EAAE;QACD,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,aAAa,EAAE,mBAAmB,CAAC;QACnC,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;QAC3B,KAAK,CAAC,EAAE,WAAW,CAAC;KACrB;IAiCK,WAAW,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAcxD,OAAO,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;CAsEnE"}
@@ -79,6 +79,13 @@ class ToolCallService {
79
79
  name: `tool: ${toolCall.name}`,
80
80
  input: toolCall.input,
81
81
  });
82
+ const uploadArtifactsQueue = new artifacts_1.UploadArtifactsQueue(this.repoPath, toolCall.id);
83
+ const collectArtifactsFn = (artifactsInput) => {
84
+ uploadArtifactsQueue.addTask(artifactsInput).catch((error) => {
85
+ console.error("Error collecting artifacts:", error);
86
+ });
87
+ return;
88
+ };
82
89
  const toolExecutor = this.toolExecutors[toolCall.name];
83
90
  if (!toolExecutor) {
84
91
  const errorResult = {
@@ -90,9 +97,13 @@ class ToolCallService {
90
97
  span?.end({ output: errorResult });
91
98
  continue;
92
99
  }
100
+ if (!this.apiKey) {
101
+ throw new Error("API key is required for tool execution");
102
+ }
93
103
  try {
94
- const result = await toolExecutor(toolCall.input, this.repoPath, this.apiKey, this.trace, artifacts_1.collectArtifacts);
95
- toolResults.push(result);
104
+ const result = await toolExecutor(toolCall.input, this.repoPath, this.apiKey, this.trace, collectArtifactsFn);
105
+ const artifacts = await uploadArtifactsQueue.waitForCompletion();
106
+ toolResults.push({ ...result, artifacts });
96
107
  span?.end({ output: result });
97
108
  }
98
109
  catch (error) {
@@ -105,7 +116,11 @@ class ToolCallService {
105
116
  span?.end({ output: errorResult });
106
117
  }
107
118
  }
108
- await (0, checkpoint_1.createCheckpoint)(toolCalls, this.branchName);
119
+ await (0, checkpoint_1.createCheckpoint)({
120
+ toolCalls,
121
+ branchName: this.branchName,
122
+ repoPath: this.repoPath,
123
+ });
109
124
  executeSpan?.end({ output: { toolResults } });
110
125
  return toolResults;
111
126
  }
@@ -1 +1 @@
1
- {"version":3,"file":"commit-and-create-pr.d.ts","sourceRoot":"","sources":["../../src/tools/commit-and-create-pr.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAOnD,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAiB1D;AA2CD,eAAO,MAAM,qBAAqB,EAAE,IA2EnC,CAAC"}
1
+ {"version":3,"file":"commit-and-create-pr.d.ts","sourceRoot":"","sources":["../../src/tools/commit-and-create-pr.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAOnD,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAiB1D;AA2CD,eAAO,MAAM,qBAAqB,EAAE,IAsFnC,CAAC"}
@@ -55,11 +55,13 @@ Don't ask the user for this information, just come up with it yourself.
55
55
  `,
56
56
  parameters: createPullRequestSchema,
57
57
  },
58
- execute: async (input) => {
58
+ execute: async (input, repoPath, apiKey) => {
59
59
  try {
60
60
  const { pullRequestTitle, pullRequestDescription } = input;
61
- const branchName = await (0, git_1.getCurrentBranchName)();
62
- const repoUrl = (0, child_process_1.execSync)("git config --get remote.origin.url")
61
+ const branchName = await (0, git_1.getCurrentBranchName)(repoPath);
62
+ const repoUrl = (0, child_process_1.execSync)("git config --get remote.origin.url", {
63
+ cwd: repoPath,
64
+ })
63
65
  .toString()
64
66
  .trim();
65
67
  const { owner, repo } = parseGitHubUrl(repoUrl);
@@ -70,8 +72,11 @@ Don't ask the user for this information, just come up with it yourself.
70
72
  head: `${owner}:${branchName}`,
71
73
  state: "open",
72
74
  },
75
+ apiKey,
73
76
  }));
74
- (0, child_process_1.execSync)(`git push origin ${branchName} --set-upstream`);
77
+ (0, child_process_1.execSync)(`git push origin ${branchName} --set-upstream`, {
78
+ cwd: repoPath,
79
+ });
75
80
  const existingPR = existingPRs?.find((pr) => pr.head.ref === branchName);
76
81
  if (existingPR) {
77
82
  // Append the new description to the existing PR description
@@ -82,6 +87,7 @@ Don't ask the user for this information, just come up with it yourself.
82
87
  body: {
83
88
  body: updatedDescription,
84
89
  },
90
+ apiKey,
85
91
  });
86
92
  return {
87
93
  isError: false,
@@ -98,6 +104,7 @@ Don't ask the user for this information, just come up with it yourself.
98
104
  base: "main",
99
105
  body: initialDescription,
100
106
  },
107
+ apiKey,
101
108
  }));
102
109
  return {
103
110
  isError: false,
@@ -1 +1 @@
1
- {"version":3,"file":"diagnosis-fetcher.d.ts","sourceRoot":"","sources":["../../src/tools/diagnosis-fetcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAenD,eAAO,MAAM,wBAAwB,EAAE,IAgFtC,CAAC"}
1
+ {"version":3,"file":"diagnosis-fetcher.d.ts","sourceRoot":"","sources":["../../src/tools/diagnosis-fetcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAenD,eAAO,MAAM,wBAAwB,EAAE,IAqFtC,CAAC"}
@@ -19,7 +19,7 @@ exports.fetchDiagnosisReportTool = {
19
19
  description: "Fetch details about a test case diagnosis using its URL or slug",
20
20
  parameters: DiagnosisSchema,
21
21
  },
22
- execute: async (input) => {
22
+ execute: async (input, repoPath, apiKey) => {
23
23
  const { diagnosisUrl } = input;
24
24
  // Extract the slug from the URL - it's the part after the last '--'
25
25
  const slug = diagnosisUrl.split("--").pop();
@@ -33,6 +33,7 @@ exports.fetchDiagnosisReportTool = {
33
33
  try {
34
34
  data = await (0, utils_1.makeDashboardRequest)({
35
35
  path: `/api/diagnosis/${slug}/detailed`,
36
+ apiKey,
36
37
  });
37
38
  }
38
39
  catch (error) {
@@ -43,8 +44,8 @@ exports.fetchDiagnosisReportTool = {
43
44
  }
44
45
  const { test_case, diagnosis } = data.data;
45
46
  const project = diagnosis?.test_project || "unknown";
46
- const sourceContext = await promises_1.default.readFile(path_1.default.join("tests", test_case.file_path), "utf-8");
47
- const repoName = path_1.default.basename(process.cwd());
47
+ const sourceContext = await promises_1.default.readFile(path_1.default.join(repoPath, "tests", test_case.file_path), "utf-8");
48
+ const repoName = path_1.default.basename(repoPath);
48
49
  const cleanErrorStack = diagnosis?.failed_run_metadata?.stack?.replace(`"/runner/_work/${repoName}/${repoName}/source-repo/"`, "");
49
50
  // Format the response as markdown
50
51
  const markdownResponse = `
@@ -1 +1 @@
1
- {"version":3,"file":"environment-crud.d.ts","sourceRoot":"","sources":["../../src/tools/environment-crud.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAyDnD,eAAO,MAAM,kBAAkB,EAAE,IAwEhC,CAAC;AAGF,eAAO,MAAM,gBAAgB,EAAE,IAAI,EAAyB,CAAC"}
1
+ {"version":3,"file":"environment-crud.d.ts","sourceRoot":"","sources":["../../src/tools/environment-crud.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AA6DnD,eAAO,MAAM,kBAAkB,EAAE,IA6EhC,CAAC;AAGF,eAAO,MAAM,gBAAgB,EAAE,IAAI,EAAyB,CAAC"}
@@ -5,10 +5,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.environmentTools = exports.getEnvironmentTool = void 0;
7
7
  const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
8
9
  const zod_1 = require("zod");
9
10
  const utils_1 = require("./utils");
10
- const getProjectRepoName = () => {
11
- const packageJson = fs_1.default.readFileSync("package.json", "utf8");
11
+ const getProjectRepoName = (repoPath) => {
12
+ const packageJson = fs_1.default.readFileSync(path_1.default.join(repoPath, "package.json"), "utf8");
12
13
  if (!packageJson) {
13
14
  throw new Error("Could not find or read package.json file");
14
15
  }
@@ -30,11 +31,11 @@ exports.getEnvironmentTool = {
30
31
  description: "Fetch details of an existing environment",
31
32
  parameters: GetEnvironmentSchema,
32
33
  },
33
- execute: async (input) => {
34
+ execute: async (input, repoPath, apiKey) => {
34
35
  // Get project repo name
35
36
  let projectRepoName;
36
37
  try {
37
- projectRepoName = getProjectRepoName();
38
+ projectRepoName = getProjectRepoName(repoPath);
38
39
  }
39
40
  catch (error) {
40
41
  return {
@@ -52,6 +53,7 @@ exports.getEnvironmentTool = {
52
53
  response = await (0, utils_1.makeDashboardRequest)({
53
54
  path: `/api/environments?${queryParams.toString()}`,
54
55
  method: "GET",
56
+ apiKey,
55
57
  });
56
58
  }
57
59
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/grep/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,wBAAwB,CAAC;AA2H/D,eAAO,MAAM,QAAQ,EAAE,IAmBtB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/grep/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,wBAAwB,CAAC;AA6H/D,eAAO,MAAM,QAAQ,EAAE,IAoBtB,CAAC"}
@@ -23,9 +23,9 @@ const GrepInputSchema = zod_1.z.object({
23
23
  .optional()
24
24
  .describe("File pattern to search in (e.g., '*.ts' for TypeScript files)"),
25
25
  });
26
- async function usingSystemGrep(input) {
26
+ async function usingSystemGrep(input, repoPath) {
27
27
  try {
28
- const dir = input.directory || process.cwd();
28
+ const dir = path_1.default.join(repoPath, input.directory || "");
29
29
  // Create exclude pattern for grep
30
30
  const excludePatterns = repo_tree_1.DEFAULT_EXCLUDE.map((pattern) => typeof pattern === "string" ? pattern : pattern.source)
31
31
  .map((pattern) => `--exclude-dir="${pattern}"`)
@@ -71,9 +71,9 @@ async function usingSystemGrep(input) {
71
71
  };
72
72
  }
73
73
  }
74
- async function usingRipgrep(input) {
74
+ async function usingRipgrep(input, repoPath) {
75
75
  try {
76
- const dir = path_1.default.join(process.cwd(), input.directory || "");
76
+ const dir = path_1.default.join(repoPath, input.directory || "");
77
77
  const escapedPattern = input.pattern
78
78
  .replace(/\s+/g, "\\ ")
79
79
  .replace(/([[\]()])/g, "\\$1");
@@ -86,7 +86,7 @@ async function usingRipgrep(input) {
86
86
  // Can add submatches and offset info to the summary if needed
87
87
  return {
88
88
  lines: result.lines.text,
89
- path: path_1.default.relative(process.cwd(), result.path.text),
89
+ path: path_1.default.relative(repoPath, result.path.text),
90
90
  // line number is 1-indexed
91
91
  line_number: result.line_number,
92
92
  };
@@ -98,7 +98,7 @@ ${result.path}:${result.line_number}
98
98
  ${result.lines}\`\`\`
99
99
  `;
100
100
  });
101
- const relDir = path_1.default.relative(process.cwd(), dir);
101
+ const relDir = path_1.default.relative(repoPath, dir);
102
102
  const header = `Found ${resultsSummary.length} results for "${input.pattern}" in "${relDir}".
103
103
  All paths are relative to the current working directory.`;
104
104
  return {
@@ -123,13 +123,13 @@ If ripgrep is not available, it will fall back to using system grep.
123
123
  Search is case insensitive and regex patterns are not supported.`,
124
124
  parameters: GrepInputSchema,
125
125
  },
126
- execute: async (input) => {
126
+ execute: async (input, repoPath) => {
127
127
  if ((0, ripgrep_1.isRgAvailable)()) {
128
- return usingRipgrep(input);
128
+ return usingRipgrep(input, repoPath);
129
129
  }
130
130
  else {
131
131
  console.warn("ripgrep is not available, falling back to system grep.");
132
- return usingSystemGrep(input);
132
+ return usingSystemGrep(input, repoPath);
133
133
  }
134
134
  },
135
135
  };
@@ -17,7 +17,7 @@ export declare function cleanupBackupFiles(repoDir: string): number;
17
17
  * Our implementation of Claude's built-in text editor tool
18
18
  * https://docs.anthropic.com/en/docs/build-with-claude/tool-use/text-editor-tool
19
19
  */
20
- export declare function strReplaceEditorExecutor(input: StrReplaceInput): Promise<ToolResult>;
20
+ export declare function strReplaceEditorExecutor(input: StrReplaceInput, repoPath: string): Promise<ToolResult>;
21
21
  export declare const textEditorTools: Tool[];
22
22
  export {};
23
23
  //# sourceMappingURL=str_replace_editor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"str_replace_editor.d.ts","sourceRoot":"","sources":["../../src/tools/str_replace_editor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AA2B1D,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAqED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAwC1D;AAMD;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,UAAU,CAAC,CAiNrB;AAiGD,eAAO,MAAM,eAAe,EAAE,IAAI,EAKjC,CAAC"}
1
+ {"version":3,"file":"str_replace_editor.d.ts","sourceRoot":"","sources":["../../src/tools/str_replace_editor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AA2B1D,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAqED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAwC1D;AAMD;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,eAAe,EACtB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,UAAU,CAAC,CAkNrB;AAuHD,eAAO,MAAM,eAAe,EAAE,IAAI,EAKjC,CAAC"}
@@ -139,24 +139,25 @@ function escapeRegExp(text) {
139
139
  * Our implementation of Claude's built-in text editor tool
140
140
  * https://docs.anthropic.com/en/docs/build-with-claude/tool-use/text-editor-tool
141
141
  */
142
- async function strReplaceEditorExecutor(input) {
143
- const repoDir = process.cwd();
142
+ async function strReplaceEditorExecutor(input, repoPath) {
143
+ const repoDir = repoPath;
144
144
  const { path: filePath } = input;
145
+ const absoluteFilePath = path_1.default.join(repoDir, filePath);
145
146
  try {
146
147
  let content;
147
148
  let lines;
148
149
  let newContent;
149
150
  switch (input.command) {
150
151
  case "view":
151
- if (!fs_1.default.existsSync(filePath)) {
152
+ if (!fs_1.default.existsSync(absoluteFilePath)) {
152
153
  return {
153
154
  result: "Error: File not found",
154
155
  isError: true,
155
156
  };
156
157
  }
157
158
  // Handle directory view
158
- if (fs_1.default.statSync(filePath).isDirectory()) {
159
- const files = fs_1.default.readdirSync(filePath);
159
+ if (fs_1.default.statSync(absoluteFilePath).isDirectory()) {
160
+ const files = fs_1.default.readdirSync(absoluteFilePath);
160
161
  return {
161
162
  result: files.join("\n"),
162
163
  isError: false,
@@ -165,7 +166,7 @@ async function strReplaceEditorExecutor(input) {
165
166
  else {
166
167
  // Check if file is binary, which is not supported
167
168
  const { isBinary } = await import("istextorbinary");
168
- const binary = isBinary(filePath);
169
+ const binary = isBinary(absoluteFilePath);
169
170
  if (binary) {
170
171
  return {
171
172
  result: "Error: File is binary, which is not supported",
@@ -174,7 +175,7 @@ async function strReplaceEditorExecutor(input) {
174
175
  }
175
176
  }
176
177
  // Handle file view
177
- content = fs_1.default.readFileSync(filePath, "utf8");
178
+ content = fs_1.default.readFileSync(absoluteFilePath, "utf8");
178
179
  lines = content.split("\n");
179
180
  if (input.view_range) {
180
181
  const [start, end] = input.view_range;
@@ -201,12 +202,12 @@ async function strReplaceEditorExecutor(input) {
201
202
  if (filePath.endsWith("spec.ts") && !filePath.startsWith("tests/")) {
202
203
  throw new Error("Creating spec.ts files is not allowed outside tests/ directory");
203
204
  }
204
- const parentDir = path_1.default.dirname(filePath);
205
+ const parentDir = path_1.default.dirname(absoluteFilePath);
205
206
  if (parentDir !== "." && !fs_1.default.existsSync(parentDir)) {
206
207
  // Ensure parent directory exists
207
208
  fs_1.default.mkdirSync(parentDir, { recursive: true });
208
209
  }
209
- fs_1.default.writeFileSync(filePath, input.file_text);
210
+ fs_1.default.writeFileSync(absoluteFilePath, input.file_text);
210
211
  let createTypescriptResult = await (0, web_1.runTypescriptCompiler)(repoDir);
211
212
  if (!createTypescriptResult.success) {
212
213
  return {
@@ -226,8 +227,8 @@ async function strReplaceEditorExecutor(input) {
226
227
  // "" is valid as new_str, so we check for nullish -- not falsy
227
228
  throw new Error("new_str is required for str_replace command");
228
229
  }
229
- createBackup(filePath);
230
- content = fs_1.default.readFileSync(filePath, "utf8");
230
+ createBackup(absoluteFilePath);
231
+ content = fs_1.default.readFileSync(absoluteFilePath, "utf8");
231
232
  // Normalize newlines in both the content and search string
232
233
  const normalizedContent = content.replace(/\r\n/g, "\n");
233
234
  const normalizedOldStr = input.old_str
@@ -259,7 +260,7 @@ async function strReplaceEditorExecutor(input) {
259
260
  };
260
261
  }
261
262
  newContent = normalizedContent.replace(normalizedOldStr, input.new_str);
262
- fs_1.default.writeFileSync(filePath, newContent);
263
+ fs_1.default.writeFileSync(absoluteFilePath, newContent);
263
264
  let strReplaceTypescriptResult = await (0, web_1.runTypescriptCompiler)(repoDir);
264
265
  if (!strReplaceTypescriptResult.success) {
265
266
  return {
@@ -278,8 +279,8 @@ async function strReplaceEditorExecutor(input) {
278
279
  if (input.insert_line === undefined || !input.new_str) {
279
280
  throw new Error("insert_line and new_str are required for insert command");
280
281
  }
281
- createBackup(filePath);
282
- content = fs_1.default.readFileSync(filePath, "utf8");
282
+ createBackup(absoluteFilePath);
283
+ content = fs_1.default.readFileSync(absoluteFilePath, "utf8");
283
284
  lines = content.split("\n");
284
285
  if (input.insert_line < 1) {
285
286
  throw new Error("insert_line must be greater than or equal to 1 (line numbers are 1-indexed).");
@@ -288,7 +289,7 @@ async function strReplaceEditorExecutor(input) {
288
289
  throw new Error(`The file at ${filePath} has only ${lines.length} lines, so insert_line must be less than or equal to ${lines.length + 1}. At the maximum value of ${lines.length + 1}, you can insert at the end of the file.`);
289
290
  }
290
291
  lines.splice(input.insert_line - 1, 0, input.new_str);
291
- fs_1.default.writeFileSync(filePath, lines.join("\n"));
292
+ fs_1.default.writeFileSync(absoluteFilePath, lines.join("\n"));
292
293
  let insertTypescriptResult = await (0, web_1.runTypescriptCompiler)(repoDir);
293
294
  if (!insertTypescriptResult.success) {
294
295
  return {
@@ -303,8 +304,8 @@ async function strReplaceEditorExecutor(input) {
303
304
  };
304
305
  }
305
306
  case "undo_edit":
306
- if (hasBackup(filePath)) {
307
- restoreBackup(filePath);
307
+ if (hasBackup(absoluteFilePath)) {
308
+ restoreBackup(absoluteFilePath);
308
309
  return {
309
310
  result: `Successfully restored ${filePath} from backup`,
310
311
  isError: false,
@@ -342,11 +343,11 @@ File contents are returned with line numbers, starting from 1.
342
343
  path: zod_1.z.string().describe("The path to the file or directory to view."),
343
344
  }),
344
345
  },
345
- execute: async (input) => {
346
+ execute: async (input, repoPath) => {
346
347
  return strReplaceEditorExecutor({
347
348
  command: "view",
348
349
  path: input.path,
349
- });
350
+ }, repoPath);
350
351
  },
351
352
  };
352
353
  const fileCreateTool = {
@@ -358,12 +359,12 @@ const fileCreateTool = {
358
359
  file_text: zod_1.z.string().describe("The contents of the new file."),
359
360
  }),
360
361
  },
361
- execute: async (input) => {
362
+ execute: async (input, repoPath) => {
362
363
  return strReplaceEditorExecutor({
363
364
  command: "create",
364
365
  path: input.path,
365
366
  file_text: input.file_text,
366
- });
367
+ }, repoPath);
367
368
  },
368
369
  };
369
370
  const stringReplaceTool = {
@@ -377,13 +378,13 @@ in the file. If old_str is not unique, the tool will return an error.`,
377
378
  new_str: zod_1.z.string().describe("The string to replace old_str with."),
378
379
  }),
379
380
  },
380
- execute: async (input) => {
381
+ execute: async (input, repoPath) => {
381
382
  return strReplaceEditorExecutor({
382
383
  command: "str_replace",
383
384
  path: input.path,
384
385
  old_str: input.old_str,
385
386
  new_str: input.new_str,
386
- });
387
+ }, repoPath);
387
388
  },
388
389
  };
389
390
  const stringInsertTool = {
@@ -396,17 +397,19 @@ const stringInsertTool = {
396
397
  .number()
397
398
  .int()
398
399
  .min(1)
399
- .describe("The line number after which to insert the text (1 for beginning of file)."),
400
+ .describe(`The line number on which to insert the text (1 for beginning of file).
401
+ To insert a string at the beginning of the file, you should use insert_line = 1.
402
+ To insert a string at the end of the file, you should use insert_line = (total lines + 1).`),
400
403
  new_str: zod_1.z.string().describe("The string to insert."),
401
404
  }),
402
405
  },
403
- execute: async (input) => {
406
+ execute: async (input, repoPath) => {
404
407
  return strReplaceEditorExecutor({
405
408
  command: "insert",
406
409
  path: input.path,
407
410
  insert_line: input.insert_line,
408
411
  new_str: input.new_str,
409
- });
412
+ }, repoPath);
410
413
  },
411
414
  };
412
415
  exports.textEditorTools = [
@@ -1 +1 @@
1
- {"version":3,"file":"test-gen-browser.d.ts","sourceRoot":"","sources":["../../src/tools/test-gen-browser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AA4FnD,eAAO,MAAM,4BAA4B,EAAE,IAoH1C,CAAC"}
1
+ {"version":3,"file":"test-gen-browser.d.ts","sourceRoot":"","sources":["../../src/tools/test-gen-browser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AA2FnD,eAAO,MAAM,4BAA4B,EAAE,IA8G1C,CAAC"}
@@ -12,7 +12,6 @@ const utils_1 = require("../agent/browsing/utils");
12
12
  const pw_pause_1 = require("../agent/cua/pw-codegen/pw-pause");
13
13
  const web_1 = require("../bin/utils/platform/web");
14
14
  const scenarios_1 = require("../bin/utils/scenarios");
15
- const slug_1 = require("../utils/slug");
16
15
  const BrowserAgentSchema = zod_1.z.object({
17
16
  testName: zod_1.z.string().describe("The name of the test to create or modify"),
18
17
  testSuites: zod_1.z
@@ -153,9 +152,8 @@ exports.generateTestWithBrowserAgent = {
153
152
  await (0, pw_pause_1.revertToOriginalPwCode)(repoDir);
154
153
  await promises_1.default.writeFile(fileName, fileBackup, "utf-8");
155
154
  const { isError, error, actionsSummary, artifacts } = toolResult;
156
- let collectedArtifacts;
157
155
  if (artifacts) {
158
- collectedArtifacts = await collectArtifacts?.(artifacts, repoDir, (0, slug_1.slugify)(testName));
156
+ void collectArtifacts?.(artifacts);
159
157
  }
160
158
  if (!isError) {
161
159
  return {
@@ -165,7 +163,6 @@ and the generated Playwright code:
165
163
 
166
164
  ${actionsSummary}
167
165
  `,
168
- artifacts: collectedArtifacts,
169
166
  };
170
167
  }
171
168
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/test-run-fetcher/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAcnD,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOnE;AAED,eAAO,MAAM,sBAAsB,EAAE,IAwHpC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/test-run-fetcher/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAcnD,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOnE;AAED,eAAO,MAAM,sBAAsB,EAAE,IA6HpC,CAAC"}
@@ -24,7 +24,7 @@ exports.fetchTestRunReportTool = {
24
24
  description: "Fetch details about a test run using its URL",
25
25
  parameters: TestRunSchema,
26
26
  },
27
- execute: async (input) => {
27
+ execute: async (input, repoPath, apiKey) => {
28
28
  const { testRunUrl } = input;
29
29
  // Remove query parameters if they exist
30
30
  const urlWithoutParams = testRunUrl.split("?")[0] || testRunUrl;
@@ -42,6 +42,7 @@ exports.fetchTestRunReportTool = {
42
42
  try {
43
43
  data = await (0, utils_1.makeDashboardRequest)({
44
44
  path: `/api/test-runs/${runId}?repo_name=${repoName}`,
45
+ apiKey,
45
46
  });
46
47
  }
47
48
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"test-run.d.ts","sourceRoot":"","sources":["../../src/tools/test-run.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,wBAAwB,CAAC;AA4C/D,eAAO,MAAM,WAAW,EAAE,IAsEzB,CAAC"}
1
+ {"version":3,"file":"test-run.d.ts","sourceRoot":"","sources":["../../src/tools/test-run.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,wBAAwB,CAAC;AA4C/D,eAAO,MAAM,WAAW,EAAE,IAiEzB,CAAC"}
@@ -50,7 +50,7 @@ exports.runTestTool = {
50
50
  console.warn("R2 credentials not found: report artifacts will not be uploaded");
51
51
  }
52
52
  const { testName, suites, fileName, project } = input;
53
- const repoDir = process.cwd();
53
+ const repoDir = repoPath;
54
54
  try {
55
55
  const result = await (0, test_run_1.runSingleTest)({
56
56
  testName,
@@ -61,7 +61,7 @@ exports.runTestTool = {
61
61
  repoDir,
62
62
  });
63
63
  const attachments = (0, utils_1.extractAttachmentsFromPlaywrightJSONReport)(result.summaryJson);
64
- const artifacts = await collectArtifacts?.(attachments, repoDir, Date.now().toString());
64
+ void collectArtifacts?.(attachments);
65
65
  return {
66
66
  isError: false,
67
67
  result: buildResult({
@@ -69,7 +69,6 @@ exports.runTestTool = {
69
69
  summaryJson: result.summaryJson,
70
70
  reportUrl: reportUrl,
71
71
  }),
72
- artifacts,
73
72
  };
74
73
  }
75
74
  catch (error) {
@@ -1,13 +1,15 @@
1
1
  import { JSONReport as PlaywrightJSONReport } from "@playwright/test/reporter";
2
- export declare function makeDashboardRequest<T>({ path, method, body, }: {
2
+ export declare function makeDashboardRequest<T>({ path, method, body, apiKey, }: {
3
3
  path: string;
4
4
  method?: string;
5
5
  body?: any;
6
+ apiKey: string;
6
7
  }): Promise<T>;
7
- export declare function callGitHubProxy({ method, url, body, }: {
8
+ export declare function callGitHubProxy({ method, url, body, apiKey, }: {
8
9
  method: string;
9
10
  url: string;
10
11
  body?: any;
12
+ apiKey: string;
11
13
  }): Promise<unknown>;
12
14
  type AttachmentInfo = {
13
15
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,IAAI,oBAAoB,EAEnC,MAAM,2BAA2B,CAAC;AAEnC,wBAAsB,oBAAoB,CAAC,CAAC,EAAE,EAC5C,IAAI,EACJ,MAAc,EACd,IAAI,GACL,EAAE;IACD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ,GAAG,OAAO,CAAC,CAAC,CAAC,CAuBb;AAED,wBAAsB,eAAe,CAAC,EACpC,MAAM,EACN,GAAG,EACH,IAAI,GACL,EAAE;IACD,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ,oBAWA;AAED,KAAK,cAAc,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,0CAA0C,CACxD,MAAM,EAAE,oBAAoB,GAC3B,cAAc,EAAE,CA4ClB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,IAAI,oBAAoB,EAEnC,MAAM,2BAA2B,CAAC;AAEnC,wBAAsB,oBAAoB,CAAC,CAAC,EAAE,EAC5C,IAAI,EACJ,MAAc,EACd,IAAI,EACJ,MAAM,GACP,EAAE;IACD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,CAAC,CAAC,CAmBb;AAED,wBAAsB,eAAe,CAAC,EACpC,MAAM,EACN,GAAG,EACH,IAAI,EACJ,MAAM,GACP,EAAE;IACD,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;CAChB,oBAYA;AAED,KAAK,cAAc,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,0CAA0C,CACxD,MAAM,EAAE,oBAAoB,GAC3B,cAAc,EAAE,CA4ClB"}
@@ -3,14 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.makeDashboardRequest = makeDashboardRequest;
4
4
  exports.callGitHubProxy = callGitHubProxy;
5
5
  exports.extractAttachmentsFromPlaywrightJSONReport = extractAttachmentsFromPlaywrightJSONReport;
6
- async function makeDashboardRequest({ path, method = "GET", body, }) {
7
- const API_KEY = process.env.EMPIRICALRUN_API_KEY;
8
- if (!API_KEY) {
9
- throw new Error("EMPIRICALRUN_API_KEY is not found");
10
- }
6
+ async function makeDashboardRequest({ path, method = "GET", body, apiKey, }) {
11
7
  const requestHeaders = {
12
8
  "Content-Type": "application/json",
13
- Authorization: `Bearer ${API_KEY}`,
9
+ Authorization: `Bearer ${apiKey}`,
14
10
  "User-Agent": "empiricalrun/test-gen",
15
11
  };
16
12
  const baseUrl = process.env.DASHBOARD_DOMAIN || "https://dash.empirical.run";
@@ -25,7 +21,7 @@ async function makeDashboardRequest({ path, method = "GET", body, }) {
25
21
  }
26
22
  return await response.json();
27
23
  }
28
- async function callGitHubProxy({ method, url, body, }) {
24
+ async function callGitHubProxy({ method, url, body, apiKey, }) {
29
25
  const githubApiPath = url.replace("https://api.github.com", "");
30
26
  return makeDashboardRequest({
31
27
  path: "/api/github/proxy",
@@ -35,6 +31,7 @@ async function callGitHubProxy({ method, url, body, }) {
35
31
  url: githubApiPath,
36
32
  body,
37
33
  },
34
+ apiKey,
38
35
  });
39
36
  }
40
37
  /**
@@ -1,3 +1,7 @@
1
1
  import { PendingToolCall } from "@empiricalrun/llm/chat";
2
- export declare function createCheckpoint(toolCalls: PendingToolCall[], branchName: string): Promise<void>;
2
+ export declare function createCheckpoint({ toolCalls, branchName, repoPath, }: {
3
+ toolCalls: PendingToolCall[];
4
+ branchName: string;
5
+ repoPath: string;
6
+ }): Promise<void>;
3
7
  //# sourceMappingURL=checkpoint.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"checkpoint.d.ts","sourceRoot":"","sources":["../../src/utils/checkpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAIzD,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,eAAe,EAAE,EAC5B,UAAU,EAAE,MAAM,iBAqBnB"}
1
+ {"version":3,"file":"checkpoint.d.ts","sourceRoot":"","sources":["../../src/utils/checkpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAIzD,wBAAsB,gBAAgB,CAAC,EACrC,SAAS,EACT,UAAU,EACV,QAAQ,GACT,EAAE;IACD,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,iBAyBA"}
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createCheckpoint = createCheckpoint;
4
4
  const git_1 = require("./git");
5
- async function createCheckpoint(toolCalls, branchName) {
6
- const filesChanged = await (0, git_1.getFilesChanged)();
5
+ async function createCheckpoint({ toolCalls, branchName, repoPath, }) {
6
+ const filesChanged = await (0, git_1.getFilesChanged)(repoPath);
7
7
  const toolsWithUpdatedFiles = toolCalls
8
8
  .filter((tc) => "path" in tc.input &&
9
9
  tc.input.path &&
@@ -15,6 +15,11 @@ async function createCheckpoint(toolCalls, branchName) {
15
15
  const filesToCommit = toolsWithUpdatedFiles.map((tool) => tool.path);
16
16
  if (toolsWithUpdatedFiles.length > 0) {
17
17
  let commitMessage = `${toolsWithUpdatedFiles.map((tool) => `${tool.name} on ${tool.path}`).join(", ")}`;
18
- await (0, git_1.commitFilesAndPushBranch)(commitMessage, branchName, filesToCommit);
18
+ await (0, git_1.commitFilesAndPushBranch)({
19
+ commitMessage,
20
+ branchName,
21
+ files: filesToCommit,
22
+ repoPath,
23
+ });
19
24
  }
20
25
  }
@@ -1,8 +1,13 @@
1
- export declare function getGitDiff(filepath: string): string;
2
- export declare function checkoutBranch(branchName: string): Promise<void>;
3
- export declare function commitAsBotUser(commitMessage: string): Promise<void>;
4
- export declare function getCurrentBranchName(): Promise<string>;
5
- export declare function pullBranch(branchName: string): Promise<void>;
6
- export declare function commitFilesAndPushBranch(commitMessage: string, branchName: string, files: string[]): Promise<void>;
7
- export declare function getFilesChanged(): Promise<string[]>;
1
+ export declare function getGitDiff(filepath: string, cwd: string): string;
2
+ export declare function checkoutBranch(branchName: string, cwd: string): Promise<void>;
3
+ export declare function commitAsBotUser(commitMessage: string, cwd: string): Promise<void>;
4
+ export declare function getCurrentBranchName(repoPath: string): Promise<string>;
5
+ export declare function pullBranch(branchName: string, cwd: string): Promise<void>;
6
+ export declare function commitFilesAndPushBranch({ commitMessage, branchName, files, repoPath, }: {
7
+ commitMessage: string;
8
+ branchName: string;
9
+ files: string[];
10
+ repoPath: string;
11
+ }): Promise<void>;
12
+ export declare function getFilesChanged(cwd: string): Promise<string[]>;
8
13
  //# sourceMappingURL=git.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/utils/git.ts"],"names":[],"mappings":"AAKA,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKnD;AAED,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,iBAQtD;AAED,wBAAsB,eAAe,CAAC,aAAa,EAAE,MAAM,iBAS1D;AAED,wBAAsB,oBAAoB,oBAGzC;AAED,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,iBAElD;AAED,wBAAsB,wBAAwB,CAC5C,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EAAE,iBAKhB;AAED,wBAAsB,eAAe,sBAUpC"}
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/utils/git.ts"],"names":[],"mappings":"AAKA,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAMhE;AAED,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,iBAQnE;AAED,wBAAsB,eAAe,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,iBAavE;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,mBAO1D;AAED,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,iBAE/D;AAED,wBAAsB,wBAAwB,CAAC,EAC7C,aAAa,EACb,UAAU,EACV,KAAK,EACL,QAAQ,GACT,EAAE;IACD,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB,iBAIA;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,qBAUhD"}
package/dist/utils/git.js CHANGED
@@ -10,44 +10,54 @@ exports.getFilesChanged = getFilesChanged;
10
10
  const child_process_1 = require("child_process");
11
11
  const GIT_USER_NAME = "empiricalrun[bot]";
12
12
  const GIT_USER_EMAIL = "180257021+empiricalrun[bot]@users.noreply.github.com";
13
- function getGitDiff(filepath) {
13
+ function getGitDiff(filepath, cwd) {
14
14
  const diff = (0, child_process_1.execSync)(`git diff ${filepath}`, {
15
15
  encoding: "utf-8",
16
+ cwd,
16
17
  });
17
18
  return diff;
18
19
  }
19
- async function checkoutBranch(branchName) {
20
+ async function checkoutBranch(branchName, cwd) {
20
21
  // TODO: This assumes repoDir is process.cwd()
21
22
  try {
22
- (0, child_process_1.execSync)(`git checkout ${branchName}`);
23
+ (0, child_process_1.execSync)(`git checkout ${branchName}`, { cwd });
23
24
  }
24
25
  catch (e) {
25
26
  // If branch doesn't exist, create it
26
- (0, child_process_1.execSync)(`git checkout -b ${branchName}`);
27
+ (0, child_process_1.execSync)(`git checkout -b ${branchName}`, { cwd });
27
28
  }
28
29
  }
29
- async function commitAsBotUser(commitMessage) {
30
- const status = (0, child_process_1.execSync)("git status --porcelain", { encoding: "utf-8" });
30
+ async function commitAsBotUser(commitMessage, cwd) {
31
+ const status = (0, child_process_1.execSync)("git status --porcelain", {
32
+ encoding: "utf-8",
33
+ cwd,
34
+ });
31
35
  if (!status) {
32
36
  return; // Nothing to commit
33
37
  }
34
38
  const commitMessageWithSkipCi = `${commitMessage} [skip ci]`;
35
- (0, child_process_1.execSync)(`git -c user.name="${GIT_USER_NAME}" -c user.email="${GIT_USER_EMAIL}" commit -m "${commitMessageWithSkipCi}"`);
39
+ (0, child_process_1.execSync)(`git -c user.name="${GIT_USER_NAME}" -c user.email="${GIT_USER_EMAIL}" commit -m "${commitMessageWithSkipCi}"`, { cwd });
36
40
  }
37
- async function getCurrentBranchName() {
38
- const branchName = (0, child_process_1.execSync)("git branch --show-current").toString().trim();
41
+ async function getCurrentBranchName(repoPath) {
42
+ const branchName = (0, child_process_1.execSync)("git branch --show-current", {
43
+ cwd: repoPath,
44
+ })
45
+ .toString()
46
+ .trim();
39
47
  return branchName;
40
48
  }
41
- async function pullBranch(branchName) {
42
- (0, child_process_1.execSync)(`git pull origin ${branchName}`);
49
+ async function pullBranch(branchName, cwd) {
50
+ (0, child_process_1.execSync)(`git pull origin ${branchName}`, { cwd });
43
51
  }
44
- async function commitFilesAndPushBranch(commitMessage, branchName, files) {
45
- (0, child_process_1.execSync)(`git add ${files.join(" ")}`);
46
- await commitAsBotUser(commitMessage);
47
- (0, child_process_1.execSync)(`git push origin ${branchName}`);
52
+ async function commitFilesAndPushBranch({ commitMessage, branchName, files, repoPath, }) {
53
+ (0, child_process_1.execSync)(`git add ${files.join(" ")}`, { cwd: repoPath });
54
+ await commitAsBotUser(commitMessage, repoPath);
55
+ (0, child_process_1.execSync)(`git push origin ${branchName}`, { cwd: repoPath });
48
56
  }
49
- async function getFilesChanged() {
50
- const output = (0, child_process_1.execSync)("git status --porcelain --untracked-files").toString();
57
+ async function getFilesChanged(cwd) {
58
+ const output = (0, child_process_1.execSync)("git status --porcelain --untracked-files", {
59
+ cwd,
60
+ }).toString();
51
61
  let filesChanged = output
52
62
  .split("\n")
53
63
  .map((line) => line.trim().split(" ").pop())
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empiricalrun/test-gen",
3
- "version": "0.62.0",
3
+ "version": "0.63.0",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"
@@ -62,9 +62,9 @@
62
62
  "tsx": "^4.16.2",
63
63
  "typescript": "^5.3.3",
64
64
  "zod": "^3.23.8",
65
- "@empiricalrun/llm": "^0.17.0",
65
+ "@empiricalrun/llm": "^0.17.1",
66
66
  "@empiricalrun/r2-uploader": "^0.3.9",
67
- "@empiricalrun/test-run": "^0.9.3"
67
+ "@empiricalrun/test-run": "^0.9.4"
68
68
  },
69
69
  "devDependencies": {
70
70
  "@playwright/test": "1.47.1",
@@ -79,7 +79,7 @@
79
79
  "playwright": "1.47.1",
80
80
  "serve-handler": "^6.1.6",
81
81
  "ts-patch": "^3.3.0",
82
- "@empiricalrun/shared-types": "0.3.0"
82
+ "@empiricalrun/shared-types": "0.4.0"
83
83
  },
84
84
  "scripts": {
85
85
  "dev": "tspc --build --watch",