@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.
- package/CHANGELOG.md +19 -0
- package/dist/agent/chat/index.d.ts.map +1 -1
- package/dist/agent/chat/index.js +8 -2
- package/dist/artifacts/index.d.ts +9 -0
- package/dist/artifacts/index.d.ts.map +1 -1
- package/dist/artifacts/index.js +28 -0
- package/dist/tool-call-service/index.d.ts.map +1 -1
- package/dist/tool-call-service/index.js +18 -3
- package/dist/tools/commit-and-create-pr.d.ts.map +1 -1
- package/dist/tools/commit-and-create-pr.js +11 -4
- package/dist/tools/diagnosis-fetcher.d.ts.map +1 -1
- package/dist/tools/diagnosis-fetcher.js +4 -3
- package/dist/tools/environment-crud.d.ts.map +1 -1
- package/dist/tools/environment-crud.js +6 -4
- package/dist/tools/grep/index.d.ts.map +1 -1
- package/dist/tools/grep/index.js +9 -9
- package/dist/tools/str_replace_editor.d.ts +1 -1
- package/dist/tools/str_replace_editor.d.ts.map +1 -1
- package/dist/tools/str_replace_editor.js +29 -26
- package/dist/tools/test-gen-browser.d.ts.map +1 -1
- package/dist/tools/test-gen-browser.js +1 -4
- package/dist/tools/test-run-fetcher/index.d.ts.map +1 -1
- package/dist/tools/test-run-fetcher/index.js +2 -1
- package/dist/tools/test-run.d.ts.map +1 -1
- package/dist/tools/test-run.js +2 -3
- package/dist/tools/utils/index.d.ts +4 -2
- package/dist/tools/utils/index.d.ts.map +1 -1
- package/dist/tools/utils/index.js +4 -7
- package/dist/utils/checkpoint.d.ts +5 -1
- package/dist/utils/checkpoint.d.ts.map +1 -1
- package/dist/utils/checkpoint.js +8 -3
- package/dist/utils/git.d.ts +12 -7
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +27 -17
- 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,
|
|
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"}
|
package/dist/agent/chat/index.js
CHANGED
|
@@ -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"}
|
package/dist/artifacts/index.js
CHANGED
|
@@ -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;
|
|
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,
|
|
95
|
-
|
|
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)(
|
|
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,
|
|
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,
|
|
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(
|
|
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;
|
|
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;
|
|
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"}
|
package/dist/tools/grep/index.js
CHANGED
|
@@ -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 ||
|
|
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(
|
|
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(
|
|
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(
|
|
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,
|
|
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 =
|
|
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(
|
|
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(
|
|
159
|
-
const files = fs_1.default.readdirSync(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
230
|
-
content = fs_1.default.readFileSync(
|
|
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(
|
|
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(
|
|
282
|
-
content = fs_1.default.readFileSync(
|
|
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(
|
|
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(
|
|
307
|
-
restoreBackup(
|
|
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(
|
|
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;
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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"}
|
package/dist/tools/test-run.js
CHANGED
|
@@ -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 =
|
|
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
|
-
|
|
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,
|
|
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 ${
|
|
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
|
|
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,
|
|
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"}
|
package/dist/utils/checkpoint.js
CHANGED
|
@@ -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)(
|
|
18
|
+
await (0, git_1.commitFilesAndPushBranch)({
|
|
19
|
+
commitMessage,
|
|
20
|
+
branchName,
|
|
21
|
+
files: filesToCommit,
|
|
22
|
+
repoPath,
|
|
23
|
+
});
|
|
19
24
|
}
|
|
20
25
|
}
|
package/dist/utils/git.d.ts
CHANGED
|
@@ -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
|
|
7
|
-
|
|
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
|
package/dist/utils/git.d.ts.map
CHANGED
|
@@ -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,
|
|
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", {
|
|
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"
|
|
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"
|
|
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.
|
|
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.
|
|
65
|
+
"@empiricalrun/llm": "^0.17.1",
|
|
66
66
|
"@empiricalrun/r2-uploader": "^0.3.9",
|
|
67
|
-
"@empiricalrun/test-run": "^0.9.
|
|
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.
|
|
82
|
+
"@empiricalrun/shared-types": "0.4.0"
|
|
83
83
|
},
|
|
84
84
|
"scripts": {
|
|
85
85
|
"dev": "tspc --build --watch",
|