@empiricalrun/test-gen 0.53.7 → 0.53.9

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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # @empiricalrun/test-gen
2
2
 
3
+ ## 0.53.9
4
+
5
+ ### Patch Changes
6
+
7
+ - 2e5d412: fix: grep tool should first return stdout, not stderr
8
+ - 2619c58: fix: add selected model info to chat state
9
+ - 58d170d: fix: skip all serial tests after browser agent is done
10
+
11
+ ## 0.53.8
12
+
13
+ ### Patch Changes
14
+
15
+ - ba5422f: fix: push intermediate file system changes to remote branch for chat agent
16
+
3
17
  ## 0.53.7
4
18
 
5
19
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/agent/browsing/run.ts"],"names":[],"mappings":"AAiBA,KAAK,iBAAiB,GAAG;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB,EAAE,OAAO,CAAC;CACpC,CAAC;AAEF,wBAAsB,6BAA6B,CAAC,EAClD,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,OAAO,EACP,yBAAyB,GAC1B,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC,CAqFD"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/agent/browsing/run.ts"],"names":[],"mappings":"AAiBA,KAAK,iBAAiB,GAAG;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB,EAAE,OAAO,CAAC;CACpC,CAAC;AAEF,wBAAsB,6BAA6B,CAAC,EAClD,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,OAAO,EACP,yBAAyB,GAC1B,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC,CAsFD"}
@@ -14,14 +14,15 @@ async function generateTestsUsingMasterAgent({ testFilePath, filePathToUpdate, p
14
14
  if (!fs_extra_1.default.existsSync(testFilePath)) {
15
15
  throw new Error(`File for master agent to run not found: ${testFilePath}`);
16
16
  }
17
- // detect available http port on the machine
18
- const port = await (0, detect_port_1.default)(3030);
17
+ const pm = new exec_1.ProcessManager();
18
+ const availablePort = await (0, detect_port_1.default)(3030);
19
19
  // start a file service to handle file updates from agent
20
20
  // - also update the file path with updates when agent is done spitting out code
21
21
  const fileServer = new server_1.FileServiceServer({
22
- port,
22
+ port: availablePort,
23
23
  repoDir,
24
24
  updateFile: editFileWithGeneratedCode,
25
+ onComplete: () => pm.terminate(),
25
26
  });
26
27
  await fileServer.startFileService();
27
28
  fileServer.setFilePath(filePathToUpdate);
@@ -44,9 +45,9 @@ async function generateTestsUsingMasterAgent({ testFilePath, filePathToUpdate, p
44
45
  if (!isTestRunTriggeredForTeardown) {
45
46
  removeListeners = await teardowns.skipAll();
46
47
  }
47
- await (0, exec_1.cmd)(command.split(" "), {
48
+ await pm.execute(command.split(" "), {
48
49
  env: {
49
- IPC_FILE_SERVICE_PORT: port.toString(),
50
+ IPC_FILE_SERVICE_PORT: availablePort.toString(),
50
51
  PW_TEST_HTML_REPORT_OPEN: "never",
51
52
  // pass the test gen token so that the agent has the same configuration as cli
52
53
  TEST_GEN_TOKEN: testGenToken,
@@ -84,7 +84,7 @@ async function chatAgentLoop({ chatModel, selectedModel, reporter, trace, }) {
84
84
  }
85
85
  chatModel.pushMessage(response);
86
86
  const latest = chatModel.getHumanReadableLatestMessage();
87
- await reporter((0, state_1.chatStateFromModel)(chatModel), latest);
87
+ await reporter((0, state_1.chatStateFromModel)(chatModel, selectedModel), latest);
88
88
  }
89
89
  (0, chat_1.cleanupBackupFiles)(process.cwd());
90
90
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agent/chat/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAoB,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAgBhE,wBAAsB,kBAAkB,CAAC,EACvC,mBAAmB,EACnB,aAAa,EACb,oBAAoB,GACrB,EAAE;IACD,aAAa,EAAE,mBAAmB,CAAC;IACnC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C,iBAoFA;AA+BD,wBAAsB,wBAAwB,CAAC,EAC7C,aAAa,EACb,aAAa,GACd,EAAE;IACD,aAAa,EAAE,mBAAmB,CAAC;IACnC,aAAa,EAAE,MAAM,CAAC;CACvB,iBA8BA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agent/chat/index.ts"],"names":[],"mappings":"AAYA,OAAO,EAAoB,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAiBhE,wBAAsB,kBAAkB,CAAC,EACvC,mBAAmB,EACnB,aAAa,EACb,oBAAoB,GACrB,EAAE;IACD,aAAa,EAAE,mBAAmB,CAAC;IACnC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C,iBAoFA;AAqBD,wBAAsB,wBAAwB,CAAC,EAC7C,aAAa,EACb,aAAa,GACd,EAAE;IACD,aAAa,EAAE,mBAAmB,CAAC;IACnC,aAAa,EAAE,MAAM,CAAC;CACvB,iBA+BA"}
@@ -2,19 +2,19 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runChatAgentForDashboard = exports.runChatAgentForCLI = void 0;
4
4
  const llm_1 = require("@empiricalrun/llm");
5
- const child_process_1 = require("child_process");
6
5
  const picocolors_1 = require("picocolors");
7
6
  const human_in_the_loop_1 = require("../../human-in-the-loop");
7
+ const git_1 = require("../../utils/git");
8
8
  const agent_loop_1 = require("./agent-loop");
9
9
  const model_1 = require("./model");
10
10
  const state_1 = require("./state");
11
11
  function stopCriteria(userPrompt) {
12
12
  return userPrompt?.toLowerCase() === "stop";
13
13
  }
14
- function concludeAgent(chatModel, useDiskForChatState) {
14
+ function concludeAgent(chatModel, useDiskForChatState, selectedModel) {
15
15
  console.log(`\n${(0, picocolors_1.gray)("Usage summary -> " + chatModel.getUsageSummary())}`);
16
16
  if (useDiskForChatState) {
17
- (0, state_1.saveToDisk)(chatModel.messages);
17
+ (0, state_1.saveToDisk)(chatModel.messages, selectedModel);
18
18
  }
19
19
  }
20
20
  async function runChatAgentForCLI({ useDiskForChatState, selectedModel, initialPromptContent, }) {
@@ -39,7 +39,7 @@ async function runChatAgentForCLI({ useDiskForChatState, selectedModel, initialP
39
39
  }
40
40
  }
41
41
  const handleSigInt = () => {
42
- concludeAgent(chatModel, useDiskForChatState);
42
+ concludeAgent(chatModel, useDiskForChatState, selectedModel);
43
43
  process.exit(0);
44
44
  };
45
45
  process.once("SIGINT", handleSigInt);
@@ -47,7 +47,7 @@ async function runChatAgentForCLI({ useDiskForChatState, selectedModel, initialP
47
47
  let userPrompt;
48
48
  let reporterFunc = async (chatState, latest) => {
49
49
  if (useDiskForChatState) {
50
- (0, state_1.saveToDisk)(chatState.messages);
50
+ (0, state_1.saveToDisk)(chatState.messages, selectedModel);
51
51
  }
52
52
  if (latest) {
53
53
  console.log(`${(0, picocolors_1.blue)(latest.role)}: ${latest.textMessage}`);
@@ -72,7 +72,7 @@ async function runChatAgentForCLI({ useDiskForChatState, selectedModel, initialP
72
72
  catch (e) {
73
73
  // https://github.com/SBoudrias/Inquirer.js/issues/1502#issuecomment-2275991680
74
74
  if (e instanceof Error && e.name === "ExitPromptError") {
75
- concludeAgent(chatModel, useDiskForChatState);
75
+ concludeAgent(chatModel, useDiskForChatState, selectedModel);
76
76
  process.exit(0);
77
77
  }
78
78
  throw e;
@@ -112,21 +112,11 @@ async function getChatSessionFromDashboard(chatSessionId) {
112
112
  const data = await response.json();
113
113
  return data.data.chat_session;
114
114
  }
115
- async function checkoutBranch(branchName) {
116
- // TODO: This assumes repoDir is process.cwd()
117
- try {
118
- (0, child_process_1.execSync)(`git checkout ${branchName}`);
119
- }
120
- catch (e) {
121
- // If branch doesn't exist, create it
122
- (0, child_process_1.execSync)(`git checkout -b ${branchName}`);
123
- }
124
- }
125
115
  async function runChatAgentForDashboard({ chatSessionId, selectedModel, }) {
126
116
  const chatSession = await getChatSessionFromDashboard(chatSessionId);
127
117
  const chatState = chatSession.chat_state;
128
118
  const branchName = chatSession.branch_name;
129
- await checkoutBranch(branchName);
119
+ await (0, git_1.checkoutBranch)(branchName);
130
120
  let chatModel = (0, model_1.createChatModel)(chatState.messages, selectedModel);
131
121
  let reporterFunc = async (chatState, latest) => {
132
122
  const response = await fetch(`${DASHBOARD_DOMAIN}/api/chat-sessions/${chatSessionId}`, {
@@ -148,5 +138,6 @@ async function runChatAgentForDashboard({ chatSessionId, selectedModel, }) {
148
138
  selectedModel,
149
139
  reporter: reporterFunc,
150
140
  });
141
+ await (0, git_1.commitLocalAndPushBranchToRemote)(branchName);
151
142
  }
152
143
  exports.runChatAgentForDashboard = runChatAgentForDashboard;
@@ -4,11 +4,12 @@ export declare const CURRENT_CHAT_STATE_VERSION = "20250327.1";
4
4
  export declare const CHAT_STATE_PATH: string;
5
5
  export type ChatStateOnDisk<T> = {
6
6
  version: typeof CURRENT_CHAT_STATE_VERSION;
7
+ model: SupportedChatModels;
7
8
  messages: T[];
8
9
  };
9
10
  export declare function createChatState(userPrompt: string, existingState: ChatStateOnDisk<any>, selectedModel: SupportedChatModels): ChatStateOnDisk<unknown>;
10
- export declare function createChatStateForMessages<T>(messages: any): ChatStateOnDisk<T>;
11
- export declare function chatStateFromModel<T>(chatModel: IChatModel<T>): ChatStateOnDisk<unknown>;
11
+ export declare function createChatStateForMessages<T>(messages: any, selectedModel: SupportedChatModels): ChatStateOnDisk<T>;
12
+ export declare function chatStateFromModel<T>(chatModel: IChatModel<T>, selectedModel: SupportedChatModels): ChatStateOnDisk<unknown>;
12
13
  export declare function loadChatState<T>(): ChatStateOnDisk<T> | undefined;
13
- export declare function saveToDisk<T>(messages: Array<T>): void;
14
+ export declare function saveToDisk<T>(messages: Array<T>, selectedModel: SupportedChatModels): void;
14
15
  //# sourceMappingURL=state.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/agent/chat/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAKpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAE9C,eAAO,MAAM,0BAA0B,eAAe,CAAC;AAEvD,eAAO,MAAM,eAAe,QAI3B,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI;IAC/B,OAAO,EAAE,OAAO,0BAA0B,CAAC;IAC3C,QAAQ,EAAE,CAAC,EAAE,CAAC;CACf,CAAC;AAEF,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,eAAe,CAAC,GAAG,CAAC,EACnC,aAAa,EAAE,mBAAmB,4BAMnC;AAED,wBAAgB,0BAA0B,CAAC,CAAC,EAC1C,QAAQ,EAAE,GAAG,GACZ,eAAe,CAAC,CAAC,CAAC,CAMpB;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,4BAE7D;AAED,wBAAgB,aAAa,CAAC,CAAC,KAAK,eAAe,CAAC,CAAC,CAAC,GAAG,SAAS,CAajE;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,QAmB/C"}
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/agent/chat/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAKpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAE9C,eAAO,MAAM,0BAA0B,eAAe,CAAC;AAEvD,eAAO,MAAM,eAAe,QAI3B,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI;IAC/B,OAAO,EAAE,OAAO,0BAA0B,CAAC;IAC3C,KAAK,EAAE,mBAAmB,CAAC;IAC3B,QAAQ,EAAE,CAAC,EAAE,CAAC;CACf,CAAC;AAEF,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,eAAe,CAAC,GAAG,CAAC,EACnC,aAAa,EAAE,mBAAmB,4BAMnC;AAED,wBAAgB,0BAA0B,CAAC,CAAC,EAC1C,QAAQ,EAAE,GAAG,EACb,aAAa,EAAE,mBAAmB,GACjC,eAAe,CAAC,CAAC,CAAC,CAOpB;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,EACxB,aAAa,EAAE,mBAAmB,4BAGnC;AAED,wBAAgB,aAAa,CAAC,CAAC,KAAK,eAAe,CAAC,CAAC,CAAC,GAAG,SAAS,CAajE;AAED,wBAAgB,UAAU,CAAC,CAAC,EAC1B,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,EAClB,aAAa,EAAE,mBAAmB,QAsBnC"}
@@ -13,19 +13,20 @@ function createChatState(userPrompt, existingState, selectedModel) {
13
13
  const messages = existingState.messages || [];
14
14
  const chatModel = (0, model_1.createChatModel)(messages, selectedModel);
15
15
  chatModel.pushUserMessage(userPrompt);
16
- return createChatStateForMessages(chatModel.messages);
16
+ return createChatStateForMessages(chatModel.messages, selectedModel);
17
17
  }
18
18
  exports.createChatState = createChatState;
19
- function createChatStateForMessages(messages) {
19
+ function createChatStateForMessages(messages, selectedModel) {
20
20
  // TODO: Add better types for messages
21
21
  return {
22
22
  version: exports.CURRENT_CHAT_STATE_VERSION,
23
+ model: selectedModel,
23
24
  messages: messages,
24
25
  };
25
26
  }
26
27
  exports.createChatStateForMessages = createChatStateForMessages;
27
- function chatStateFromModel(chatModel) {
28
- return createChatStateForMessages(chatModel.messages);
28
+ function chatStateFromModel(chatModel, selectedModel) {
29
+ return createChatStateForMessages(chatModel.messages, selectedModel);
29
30
  }
30
31
  exports.chatStateFromModel = chatStateFromModel;
31
32
  function loadChatState() {
@@ -40,10 +41,11 @@ function loadChatState() {
40
41
  return state;
41
42
  }
42
43
  exports.loadChatState = loadChatState;
43
- function saveToDisk(messages) {
44
+ function saveToDisk(messages, selectedModel) {
44
45
  const statePath = exports.CHAT_STATE_PATH;
45
46
  let existingState = {
46
47
  version: exports.CURRENT_CHAT_STATE_VERSION,
48
+ model: selectedModel,
47
49
  messages: [],
48
50
  };
49
51
  // Ensure directory exists before trying to read/write
@@ -57,6 +59,7 @@ function saveToDisk(messages) {
57
59
  const newState = {
58
60
  ...existingState,
59
61
  messages: messages,
62
+ model: selectedModel,
60
63
  };
61
64
  fs_1.default.writeFileSync(statePath, JSON.stringify(newState, null, 2));
62
65
  }
@@ -5,10 +5,12 @@ export declare class FileServiceServer {
5
5
  private server;
6
6
  private actionsSummary;
7
7
  private updateFile;
8
- constructor({ port, repoDir, updateFile, }: {
8
+ private onComplete?;
9
+ constructor({ port, repoDir, updateFile, onComplete, }: {
9
10
  port: number;
10
11
  repoDir: string;
11
12
  updateFile: boolean;
13
+ onComplete?: () => void;
12
14
  });
13
15
  getActionsSummary(): string | undefined;
14
16
  setFilePath(filePath: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/file/server.ts"],"names":[],"mappings":"AAWA,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,MAAM,CAA4C;IAC1D,OAAO,CAAC,cAAc,CAAqB;IAC3C,OAAO,CAAC,UAAU,CAAkB;gBAExB,EACV,IAAI,EACJ,OAAO,EACP,UAAU,GACX,EAAE;QACD,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,OAAO,CAAC;KACrB;IAMD,iBAAiB;IAIjB,WAAW,CAAC,QAAQ,EAAE,MAAM;IAItB,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;IA+CnC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAgB5B;AAED,wBAAsB,gBAAgB,kBAAK"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/file/server.ts"],"names":[],"mappings":"AAWA,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,MAAM,CAA4C;IAC1D,OAAO,CAAC,cAAc,CAAqB;IAC3C,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,UAAU,CAAC,CAAa;gBAEpB,EACV,IAAI,EACJ,OAAO,EACP,UAAU,EACV,UAAU,GACX,EAAE;QACD,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,OAAO,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;KACzB;IAOD,iBAAiB;IAIjB,WAAW,CAAC,QAAQ,EAAE,MAAM;IAItB,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;IAmDnC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAgB5B;AAED,wBAAsB,gBAAgB,kBAAK"}
@@ -16,10 +16,12 @@ class FileServiceServer {
16
16
  server;
17
17
  actionsSummary;
18
18
  updateFile = false;
19
- constructor({ port, repoDir, updateFile, }) {
19
+ onComplete;
20
+ constructor({ port, repoDir, updateFile, onComplete, }) {
20
21
  this.port = port;
21
22
  this.repoDir = repoDir;
22
23
  this.updateFile = updateFile;
24
+ this.onComplete = onComplete;
23
25
  }
24
26
  getActionsSummary() {
25
27
  return this.actionsSummary;
@@ -35,6 +37,9 @@ class FileServiceServer {
35
37
  const { generatedCode, importPaths, actionsSummary } = req.body;
36
38
  this.actionsSummary = actionsSummary;
37
39
  if (!this.updateFile) {
40
+ // Not updating the file in this scenario
41
+ if (this.onComplete)
42
+ this.onComplete();
38
43
  return res.send({ success: true });
39
44
  }
40
45
  try {
@@ -45,6 +50,8 @@ class FileServiceServer {
45
50
  const importStatements = await (0, web_1.importAllExportsStmtFromFilePaths)(this.repoDir, importPaths, this.filePath);
46
51
  fs_1.default.writeFileSync(testFilePath, `${importStatements.join("\n")}\n${newContents}`, "utf-8");
47
52
  await (0, web_1.lintErrors)(testFilePath);
53
+ if (this.onComplete)
54
+ this.onComplete();
48
55
  return res.send({ success: true });
49
56
  }
50
57
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAQlC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAqBpC,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,SAAS,iBAyD3E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAQlC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAoBpC,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,SAAS,iBAsD3E"}
package/dist/index.js CHANGED
@@ -11,7 +11,6 @@ const scenarios_1 = require("./bin/utils/scenarios");
11
11
  const client_1 = __importDefault(require("./file/client"));
12
12
  const reporter_1 = require("./reporter");
13
13
  const session_1 = require("./session");
14
- const pw_test_1 = require("./utils/pw-test");
15
14
  const flushEvents = async () => {
16
15
  await (0, llm_1.flushAllTraces)();
17
16
  };
@@ -68,8 +67,6 @@ async function createTest(task, page, scope) {
68
67
  importPaths,
69
68
  actionsSummary,
70
69
  });
71
- // skip the rest of the test once generation is over
72
- await (0, pw_test_1.skipTest)();
73
70
  }
74
71
  finally {
75
72
  // Ensure listeners are removed even if an error occurs
@@ -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;AAUnD,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAiB1D;AAiBD,eAAO,MAAM,wBAAwB,EAAE,IAqFtC,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;AAQnD,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAiB1D;AAiBD,eAAO,MAAM,wBAAwB,EAAE,IAkFtC,CAAC"}
@@ -7,9 +7,8 @@ exports.commitAndPushChangesTool = exports.parseGitHubUrl = void 0;
7
7
  const child_process_1 = require("child_process");
8
8
  const crypto_1 = __importDefault(require("crypto"));
9
9
  const zod_1 = require("zod");
10
+ const git_1 = require("../utils/git");
10
11
  const utils_1 = require("./utils");
11
- const GIT_USER_NAME = "empiricalrun[bot]";
12
- const GIT_USER_EMAIL = "180257021+empiricalrun[bot]@users.noreply.github.com";
13
12
  function parseGitHubUrl(url) {
14
13
  const githubIndex = url.indexOf("github.com");
15
14
  if (githubIndex === -1) {
@@ -67,8 +66,7 @@ Returns the URL of the created or updated pull request.`,
67
66
  for (const file of modifiedFiles) {
68
67
  (0, child_process_1.execSync)(`git add "${file}"`);
69
68
  }
70
- // Use -c flag to set config just for this commit
71
- (0, child_process_1.execSync)(`git -c user.name="${GIT_USER_NAME}" -c user.email="${GIT_USER_EMAIL}" commit -m "${commitMessage} [skip ci]"`);
69
+ await (0, git_1.commitAsBotUser)(commitMessage);
72
70
  const repoUrl = (0, child_process_1.execSync)("git config --get remote.origin.url")
73
71
  .toString()
74
72
  .trim();
@@ -41,15 +41,15 @@ exports.grepTool = {
41
41
  cmd = `find ${dir} ${excludeFind} -name "${input.filePattern}" -exec grep -rin "${input.pattern}" {} \\;`;
42
42
  }
43
43
  const { stdout, stderr } = await execAsync(cmd);
44
- if (stderr) {
44
+ if (stdout) {
45
45
  return {
46
- isError: true,
47
- result: stderr,
46
+ isError: false,
47
+ result: stdout,
48
48
  };
49
49
  }
50
50
  return {
51
- isError: false,
52
- result: stdout,
51
+ isError: true,
52
+ result: stderr,
53
53
  };
54
54
  }
55
55
  catch (error) {
@@ -1,3 +1,11 @@
1
+ export declare class ProcessManager {
2
+ private childProcess;
3
+ execute(command: string[], options: {
4
+ env?: Record<string, string>;
5
+ }): Promise<number>;
6
+ terminate(): void;
7
+ isRunning(): boolean;
8
+ }
1
9
  export declare function cmd(command: string[], options: {
2
10
  env?: Record<string, string>;
3
11
  }): Promise<number>;
@@ -1 +1 @@
1
- {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/utils/exec.ts"],"names":[],"mappings":"AAGA,wBAAsB,GAAG,CACvB,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACxC,OAAO,CAAC,MAAM,CAAC,CAuCjB"}
1
+ {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/utils/exec.ts"],"names":[],"mappings":"AAQA,qBAAa,cAAc;IACzB,OAAO,CAAC,YAAY,CAA6B;IAE3C,OAAO,CACX,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GACxC,OAAO,CAAC,MAAM,CAAC;IAkDlB,SAAS,IAAI,IAAI;IASjB,SAAS,IAAI,OAAO;CAGrB;AAED,wBAAsB,GAAG,CACvB,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACxC,OAAO,CAAC,MAAM,CAAC,CAGjB"}
@@ -3,43 +3,73 @@ 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.cmd = void 0;
6
+ exports.cmd = exports.ProcessManager = void 0;
7
7
  const child_process_1 = require("child_process");
8
8
  const process_1 = __importDefault(require("process"));
9
- async function cmd(command, options) {
10
- let errorLogs = [];
11
- return new Promise((resolveFunc, rejectFunc) => {
12
- if (!command[0]) {
13
- rejectFunc(new Error("Command cannot be empty"));
14
- return;
9
+ const acceptableExitCodes = [
10
+ 0, // Implies successful execution (no errors)
11
+ 130, // Implies user interrupted the process (for SIGINT)
12
+ ];
13
+ class ProcessManager {
14
+ childProcess = null;
15
+ async execute(command, options) {
16
+ if (this.childProcess) {
17
+ throw new Error("Process is already running");
15
18
  }
16
- let p = (0, child_process_1.spawn)(command[0], command.slice(1), {
17
- env: { ...process_1.default.env, ...options.env },
18
- });
19
- p.stdout.on("data", (x) => {
20
- const log = x.toString();
21
- if (log.includes("Error")) {
22
- errorLogs.push(log);
23
- }
24
- process_1.default.stdout.write(log);
25
- });
26
- p.stderr.on("data", (x) => {
27
- const log = x.toString();
28
- process_1.default.stderr.write(log);
29
- errorLogs.push(log);
30
- });
31
- p.on("error", async (err) => {
32
- rejectFunc(err);
33
- });
34
- p.on("exit", async (code) => {
35
- if (code !== 0) {
36
- const errorMessage = errorLogs.slice(-3).join("\n");
37
- rejectFunc(new Error(errorMessage));
38
- }
39
- else {
40
- resolveFunc(code ?? 1);
19
+ let errorLogs = [];
20
+ return new Promise((resolveFunc, rejectFunc) => {
21
+ if (!command[0]) {
22
+ rejectFunc(new Error("Command cannot be empty"));
23
+ return;
41
24
  }
25
+ const p = (0, child_process_1.spawn)(command[0], command.slice(1), {
26
+ env: { ...process_1.default.env, ...options.env },
27
+ detached: true, // Create process group so we can terminate all child processes
28
+ });
29
+ this.childProcess = p;
30
+ p.stdout.on("data", (x) => {
31
+ const log = x.toString();
32
+ if (log.includes("Error")) {
33
+ errorLogs.push(log);
34
+ }
35
+ process_1.default.stdout.write(log);
36
+ });
37
+ p.stderr.on("data", (x) => {
38
+ const log = x.toString();
39
+ process_1.default.stderr.write(log);
40
+ errorLogs.push(log);
41
+ });
42
+ p.on("error", async (err) => {
43
+ this.childProcess = null;
44
+ rejectFunc(err);
45
+ });
46
+ p.on("exit", async (code) => {
47
+ this.childProcess = null;
48
+ if (!acceptableExitCodes.includes(code ?? 1)) {
49
+ const errorMessage = errorLogs.slice(-3).join("\n");
50
+ rejectFunc(new Error(errorMessage));
51
+ }
52
+ else {
53
+ resolveFunc(code ?? 1);
54
+ }
55
+ });
42
56
  });
43
- });
57
+ }
58
+ terminate() {
59
+ if (!this.childProcess) {
60
+ throw new Error("No process is currently running");
61
+ }
62
+ if (this.childProcess.pid) {
63
+ process_1.default.kill(-this.childProcess.pid, "SIGINT");
64
+ }
65
+ }
66
+ isRunning() {
67
+ return this.childProcess !== null;
68
+ }
69
+ }
70
+ exports.ProcessManager = ProcessManager;
71
+ async function cmd(command, options) {
72
+ const manager = new ProcessManager();
73
+ return manager.execute(command, options);
44
74
  }
45
75
  exports.cmd = cmd;
@@ -1,2 +1,5 @@
1
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 commitLocalAndPushBranchToRemote(branchName: string): Promise<void>;
2
5
  //# sourceMappingURL=git.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/utils/git.ts"],"names":[],"mappings":"AAEA,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKnD"}
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,gCAAgC,CAAC,UAAU,EAAE,MAAM,iBAIxE"}
package/dist/utils/git.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getGitDiff = void 0;
3
+ exports.commitLocalAndPushBranchToRemote = exports.commitAsBotUser = exports.checkoutBranch = exports.getGitDiff = void 0;
4
4
  const child_process_1 = require("child_process");
5
+ const GIT_USER_NAME = "empiricalrun[bot]";
6
+ const GIT_USER_EMAIL = "180257021+empiricalrun[bot]@users.noreply.github.com";
5
7
  function getGitDiff(filepath) {
6
8
  const diff = (0, child_process_1.execSync)(`git diff ${filepath}`, {
7
9
  encoding: "utf-8",
@@ -9,3 +11,29 @@ function getGitDiff(filepath) {
9
11
  return diff;
10
12
  }
11
13
  exports.getGitDiff = getGitDiff;
14
+ async function checkoutBranch(branchName) {
15
+ // TODO: This assumes repoDir is process.cwd()
16
+ try {
17
+ (0, child_process_1.execSync)(`git checkout ${branchName}`);
18
+ }
19
+ catch (e) {
20
+ // If branch doesn't exist, create it
21
+ (0, child_process_1.execSync)(`git checkout -b ${branchName}`);
22
+ }
23
+ }
24
+ exports.checkoutBranch = checkoutBranch;
25
+ async function commitAsBotUser(commitMessage) {
26
+ const status = (0, child_process_1.execSync)("git status --porcelain", { encoding: "utf-8" });
27
+ if (!status) {
28
+ return; // Nothing to commit
29
+ }
30
+ const commitMessageWithSkipCi = `${commitMessage} [skip ci]`;
31
+ (0, child_process_1.execSync)(`git -c user.name="${GIT_USER_NAME}" -c user.email="${GIT_USER_EMAIL}" commit -m "${commitMessageWithSkipCi}"`);
32
+ }
33
+ exports.commitAsBotUser = commitAsBotUser;
34
+ async function commitLocalAndPushBranchToRemote(branchName) {
35
+ (0, child_process_1.execSync)(`git add .`);
36
+ await commitAsBotUser("Intermediate commit from @empiricalrun/test-gen");
37
+ (0, child_process_1.execSync)(`git push origin ${branchName}`);
38
+ }
39
+ exports.commitLocalAndPushBranchToRemote = commitLocalAndPushBranchToRemote;
@@ -1,3 +1,2 @@
1
1
  export declare function getTestFixtureModuleFromRepo(repoDir: string): Promise<any>;
2
- export declare function skipTest(): Promise<void>;
3
2
  //# sourceMappingURL=pw-test.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pw-test.d.ts","sourceRoot":"","sources":["../../src/utils/pw-test.ts"],"names":[],"mappings":"AAEA,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,GAAG,CAAC,CAKd;AAED,wBAAsB,QAAQ,kBAS7B"}
1
+ {"version":3,"file":"pw-test.d.ts","sourceRoot":"","sources":["../../src/utils/pw-test.ts"],"names":[],"mappings":"AAEA,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,GAAG,CAAC,CAKd"}
@@ -3,7 +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.skipTest = exports.getTestFixtureModuleFromRepo = void 0;
6
+ exports.getTestFixtureModuleFromRepo = void 0;
7
7
  const api_1 = __importDefault(require("tsx/cjs/api"));
8
8
  async function getTestFixtureModuleFromRepo(repoDir) {
9
9
  const [lastDir] = repoDir.split("/").reverse();
@@ -12,15 +12,3 @@ async function getTestFixtureModuleFromRepo(repoDir) {
12
12
  return test;
13
13
  }
14
14
  exports.getTestFixtureModuleFromRepo = getTestFixtureModuleFromRepo;
15
- async function skipTest() {
16
- let test;
17
- let repoDir = process.cwd();
18
- try {
19
- test = await getTestFixtureModuleFromRepo(repoDir);
20
- }
21
- catch (e) {
22
- console.error("Error while importing fixture module to extract test:", e);
23
- }
24
- test.skip();
25
- }
26
- exports.skipTest = skipTest;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empiricalrun/test-gen",
3
- "version": "0.53.7",
3
+ "version": "0.53.9",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"