@empiricalrun/test-gen 0.72.0 → 0.73.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 (123) 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 +12 -22
  4. package/dist/agent/chat/prompt/index.d.ts.map +1 -1
  5. package/dist/agent/chat/prompt/index.js +3 -2
  6. package/dist/agent/code-review/prompt.d.ts +2 -0
  7. package/dist/agent/code-review/prompt.d.ts.map +1 -0
  8. package/dist/agent/code-review/prompt.js +19 -0
  9. package/dist/agent/codegen/create-test-block.d.ts.map +1 -1
  10. package/dist/agent/codegen/create-test-block.js +0 -10
  11. package/dist/agent/diagnosis-agent/index.d.ts.map +1 -1
  12. package/dist/agent/diagnosis-agent/index.js +0 -9
  13. package/dist/agent/master/execute-browser-action.d.ts +1 -1
  14. package/dist/agent/master/execute-browser-action.d.ts.map +1 -1
  15. package/dist/agent/master/execute-skill-action.d.ts +1 -1
  16. package/dist/agent/master/execute-skill-action.d.ts.map +1 -1
  17. package/dist/agent/master/run.d.ts.map +1 -1
  18. package/dist/agent/master/run.js +0 -74
  19. package/dist/artifacts/index.d.ts.map +1 -1
  20. package/dist/artifacts/index.js +18 -6
  21. package/dist/artifacts/utils.d.ts +2 -2
  22. package/dist/artifacts/utils.d.ts.map +1 -1
  23. package/dist/artifacts/utils.js +16 -5
  24. package/dist/auth/cli-auth.d.ts.map +1 -1
  25. package/dist/auth/cli-auth.js +3 -7
  26. package/dist/auth/index.d.ts +1 -2
  27. package/dist/auth/index.d.ts.map +1 -1
  28. package/dist/auth/index.js +2 -4
  29. package/dist/auth/token-store.d.ts +1 -1
  30. package/dist/auth/token-store.d.ts.map +1 -1
  31. package/dist/auth/token-store.js +3 -3
  32. package/dist/bin/environments.d.ts +5 -1
  33. package/dist/bin/environments.d.ts.map +1 -1
  34. package/dist/bin/environments.js +9 -11
  35. package/dist/bin/index.js +33 -74
  36. package/dist/bin/setup.d.ts +3 -1
  37. package/dist/bin/setup.d.ts.map +1 -1
  38. package/dist/bin/setup.js +6 -10
  39. package/dist/dashboard/client.d.ts +26 -0
  40. package/dist/dashboard/client.d.ts.map +1 -0
  41. package/dist/dashboard/client.js +185 -0
  42. package/dist/dashboard/index.d.ts +2 -20
  43. package/dist/dashboard/index.d.ts.map +1 -1
  44. package/dist/dashboard/index.js +7 -81
  45. package/dist/dashboard/totp.d.ts +1 -1
  46. package/dist/dashboard/totp.d.ts.map +1 -1
  47. package/dist/dashboard/totp.js +2 -6
  48. package/dist/dashboard/types.d.ts +9 -0
  49. package/dist/dashboard/types.d.ts.map +1 -0
  50. package/dist/dashboard/types.js +17 -0
  51. package/dist/file-info/github.d.ts +2 -2
  52. package/dist/file-info/github.d.ts.map +1 -1
  53. package/dist/file-info/github.js +9 -10
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +0 -9
  56. package/dist/recorder/env-variables.d.ts.map +1 -1
  57. package/dist/recorder/env-variables.js +3 -7
  58. package/dist/recorder/index.js +5 -5
  59. package/dist/recorder/request.js +4 -9
  60. package/dist/recorder/upload.d.ts +3 -2
  61. package/dist/recorder/upload.d.ts.map +1 -1
  62. package/dist/recorder/upload.js +20 -22
  63. package/dist/tools/commit-and-create-pr.d.ts.map +1 -1
  64. package/dist/tools/commit-and-create-pr.js +42 -35
  65. package/dist/tools/delete-file.d.ts +3 -0
  66. package/dist/tools/delete-file.d.ts.map +1 -0
  67. package/dist/tools/delete-file.js +83 -0
  68. package/dist/tools/diagnosis-fetcher.d.ts.map +1 -1
  69. package/dist/tools/diagnosis-fetcher.js +3 -7
  70. package/dist/tools/executor/index.d.ts +6 -9
  71. package/dist/tools/executor/index.d.ts.map +1 -1
  72. package/dist/tools/executor/index.js +23 -29
  73. package/dist/tools/executor/utils/checkpoint.d.ts +2 -2
  74. package/dist/tools/executor/utils/checkpoint.d.ts.map +1 -1
  75. package/dist/tools/executor/utils/checkpoint.js +6 -5
  76. package/dist/tools/executor/utils/git.d.ts +7 -12
  77. package/dist/tools/executor/utils/git.d.ts.map +1 -1
  78. package/dist/tools/executor/utils/git.js +11 -36
  79. package/dist/tools/executor/utils/index.d.ts +37 -21
  80. package/dist/tools/executor/utils/index.d.ts.map +1 -1
  81. package/dist/tools/executor/utils/index.js +57 -58
  82. package/dist/tools/executor/utils/pr-description.d.ts +4 -0
  83. package/dist/tools/executor/utils/pr-description.d.ts.map +1 -0
  84. package/dist/tools/executor/utils/pr-description.js +24 -0
  85. package/dist/tools/fetch-image/index.d.ts +3 -0
  86. package/dist/tools/fetch-image/index.d.ts.map +1 -0
  87. package/dist/tools/fetch-image/index.js +56 -0
  88. package/dist/tools/grep/index.d.ts.map +1 -1
  89. package/dist/tools/grep/index.js +1 -1
  90. package/dist/tools/index.d.ts +4 -0
  91. package/dist/tools/index.d.ts.map +1 -0
  92. package/dist/tools/index.js +60 -0
  93. package/dist/tools/list-environments.d.ts.map +1 -1
  94. package/dist/tools/list-environments.js +2 -5
  95. package/dist/tools/merge-conflicts.d.ts +3 -0
  96. package/dist/tools/merge-conflicts.d.ts.map +1 -0
  97. package/dist/tools/merge-conflicts.js +107 -0
  98. package/dist/tools/run-test.d.ts.map +1 -1
  99. package/dist/tools/run-test.js +2 -2
  100. package/dist/tools/test-run-fetcher/index.d.ts.map +1 -1
  101. package/dist/tools/test-run-fetcher/index.js +2 -6
  102. package/dist/tools/upgrade-packages/index.d.ts.map +1 -1
  103. package/dist/tools/upgrade-packages/index.js +10 -11
  104. package/dist/tools/upgrade-packages/utils.d.ts +3 -2
  105. package/dist/tools/upgrade-packages/utils.d.ts.map +1 -1
  106. package/dist/tools/upgrade-packages/utils.js +5 -8
  107. package/dist/tools/utils/queue.d.ts +5 -0
  108. package/dist/tools/utils/queue.d.ts.map +1 -0
  109. package/dist/tools/utils/queue.js +41 -0
  110. package/package.json +5 -5
  111. package/tsconfig.tsbuildinfo +1 -1
  112. package/dist/auth/api-client.d.ts +0 -13
  113. package/dist/auth/api-client.d.ts.map +0 -1
  114. package/dist/auth/api-client.js +0 -107
  115. package/dist/session/index.d.ts +0 -20
  116. package/dist/session/index.d.ts.map +0 -1
  117. package/dist/session/index.js +0 -104
  118. package/dist/tools/definitions/index.d.ts +0 -22
  119. package/dist/tools/definitions/index.d.ts.map +0 -1
  120. package/dist/tools/definitions/index.js +0 -61
  121. package/dist/tools/definitions/utils/queue.d.ts +0 -8
  122. package/dist/tools/definitions/utils/queue.d.ts.map +0 -1
  123. package/dist/tools/definitions/utils/queue.js +0 -58
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.storeTokens = storeTokens;
4
- exports.getStoredTokens = getStoredTokens;
4
+ exports.getStoredUserTokens = getStoredUserTokens;
5
5
  exports.clearTokens = clearTokens;
6
6
  exports.isAuthenticated = isAuthenticated;
7
7
  const crypto_1 = require("crypto");
@@ -81,7 +81,7 @@ async function storeTokens(tokens) {
81
81
  throw new Error(`Failed to store authentication tokens: ${error}`);
82
82
  }
83
83
  }
84
- async function getStoredTokens() {
84
+ async function getStoredUserTokens() {
85
85
  try {
86
86
  const dashboardDomain = getDashboardDomain();
87
87
  const tokenStorage = await getTokenStorage();
@@ -138,7 +138,7 @@ async function clearTokens() {
138
138
  }
139
139
  }
140
140
  async function isAuthenticated() {
141
- const tokens = await getStoredTokens();
141
+ const tokens = await getStoredUserTokens();
142
142
  if (!tokens)
143
143
  return false;
144
144
  // Check if token is not expired (with 5 minute buffer)
@@ -1,2 +1,6 @@
1
- export declare function listEnvironments(repoDir: string): Promise<void>;
1
+ import type { IDashboardAPIClient } from "@empiricalrun/shared-types";
2
+ export declare function listEnvironments({ apiClient, repoPath: repoDir, }: {
3
+ repoPath: string;
4
+ apiClient: IDashboardAPIClient;
5
+ }): Promise<void>;
2
6
  //# sourceMappingURL=environments.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"environments.d.ts","sourceRoot":"","sources":["../../src/bin/environments.ts"],"names":[],"mappings":"AAkEA,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,MAAM,iBAqDrD"}
1
+ {"version":3,"file":"environments.d.ts","sourceRoot":"","sources":["../../src/bin/environments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EAEpB,MAAM,4BAA4B,CAAC;AAiEpC,wBAAsB,gBAAgB,CAAC,EACrC,SAAS,EACT,QAAQ,EAAE,OAAO,GAClB,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,mBAAmB,CAAC;CAChC,iBAiDA"}
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.listEnvironments = listEnvironments;
4
4
  const test_run_1 = require("@empiricalrun/test-run");
5
- const api_client_1 = require("../auth/api-client");
6
5
  const validation_1 = require("../recorder/validation");
7
6
  async function getMatchingPlaywrightProjects(patterns, repoDir) {
8
7
  if (patterns.length === 0) {
@@ -58,18 +57,17 @@ function printLatestBuild(latestBuild) {
58
57
  console.log(` │ URL: ${latestBuild.build_url}`);
59
58
  console.log(` └─`);
60
59
  }
61
- async function listEnvironments(repoDir) {
60
+ async function listEnvironments({ apiClient, repoPath: repoDir, }) {
62
61
  try {
63
62
  let repoName = await (0, validation_1.validatePackageJson)(repoDir);
64
- const response = await api_client_1.apiClient.request(`/api/environments/list?project_repo_name=${encodeURIComponent(repoName)}`);
65
- if (!response.ok) {
66
- console.error(`❌ Failed to fetch environments for repo ${repoName}:`, response.statusText);
67
- process.exit(1);
68
- }
69
- const result = await response.json();
70
- if (result.data?.environments && result.data.environments.length > 0) {
71
- for (const env of result.data.environments) {
72
- const envIndex = result.data.environments.indexOf(env);
63
+ const data = await apiClient.request(`/api/environments/list`, {
64
+ method: "GET",
65
+ params: { project_repo_name: repoName },
66
+ });
67
+ if (data.data?.environments && data.data.environments.length > 0) {
68
+ const environments = data.data.environments;
69
+ for (const env of environments) {
70
+ const envIndex = environments.indexOf(env);
73
71
  if (envIndex > 0) {
74
72
  console.log("");
75
73
  }
package/dist/bin/index.js CHANGED
@@ -18,10 +18,9 @@ const enrich_prompt_1 = require("../agent/enrich-prompt");
18
18
  const infer_agent_1 = require("../agent/infer-agent");
19
19
  const run_3 = require("../agent/planner/run");
20
20
  const auth_1 = require("../auth");
21
- const api_client_1 = require("../auth/api-client");
21
+ const client_1 = require("../dashboard/client");
22
22
  const recorder_1 = require("../recorder");
23
23
  const validation_1 = require("../recorder/validation");
24
- const session_1 = require("../session");
25
24
  const test_build_1 = require("../test-build");
26
25
  const environments_1 = require("./environments");
27
26
  const logger_1 = require("./logger");
@@ -56,33 +55,12 @@ async function runChatAgent({ modelInput, useDiskForChatState, initialPromptPath
56
55
  async function runAgentsWorkflow(testGenConfig, testGenToken) {
57
56
  const logger = new logger_1.CustomLogger();
58
57
  const { specPath, testCase } = testGenConfig;
59
- const session = (0, session_1.getSessionDetails)();
60
- const trace = llm_1.langfuseInstance?.trace({
61
- name: "generate-test",
62
- id: crypto.randomUUID(),
63
- release: session.version,
64
- tags: [
65
- testGenConfig.options?.metadata.projectName || "",
66
- testGenConfig.options?.metadata.environment || "",
67
- ].filter((s) => !!s),
68
- });
69
- if (await (0, session_1.shouldStopSession)()) {
70
- return;
71
- }
72
58
  let agentFromConfig = testGenConfig.options?.agent;
73
59
  let agent = agentFromConfig || "auto";
74
- trace?.update({
75
- metadata: {
76
- generationId: session.generationId,
77
- sessionId: session.sessionId,
78
- testUrl: session.testUrl,
79
- },
80
- });
81
60
  // assuming if there is no test case specific test name, we need to update the test case name
82
61
  if (!testCase.name) {
83
62
  logger.success(`Generating code for the provided task. ${process.env.LOG_URL ? `[view log](${process.env.LOG_URL})` : ""}`);
84
63
  await (0, repo_edit_1.repoEditAgent)({
85
- trace,
86
64
  task: testGenConfig.testCase.steps.join("\n"),
87
65
  logger,
88
66
  });
@@ -93,7 +71,6 @@ async function runAgentsWorkflow(testGenConfig, testGenToken) {
93
71
  // If failure context is available, we can enrich the user prompt to contain
94
72
  // the failure context
95
73
  const requestedChangeResp = await (0, enrich_prompt_1.enrichPromptWithFailingLine)({
96
- trace,
97
74
  testBlock: testGenConfig.testErrorDiagnosis.failingLine,
98
75
  testFilePath: testGenConfig.testErrorDiagnosis.failingFile,
99
76
  suggestionForFix: testCase.steps.join("\n"),
@@ -105,7 +82,6 @@ async function runAgentsWorkflow(testGenConfig, testGenToken) {
105
82
  // TODO: fix this hardcoding of user prompt - ideally its an auto fix intent
106
83
  testCase.steps[0]?.toLowerCase().trim() == "can you please fix the test") {
107
84
  const { task: updatedTask } = await (0, diagnosis_agent_1.createTaskUsingFailureDiagnosis)({
108
- trace,
109
85
  diagnosis: testGenConfig.testErrorDiagnosis,
110
86
  });
111
87
  if (updatedTask) {
@@ -116,7 +92,6 @@ async function runAgentsWorkflow(testGenConfig, testGenToken) {
116
92
  if (!agent || agent === "auto") {
117
93
  const { response } = await (0, infer_agent_1.inferAgentBasedTask)({
118
94
  task: testCase.steps.join("\n"),
119
- trace,
120
95
  });
121
96
  agent = response;
122
97
  }
@@ -126,7 +101,6 @@ async function runAgentsWorkflow(testGenConfig, testGenToken) {
126
101
  const plan = await (0, run_3.planTask)({
127
102
  task,
128
103
  specPath,
129
- trace,
130
104
  });
131
105
  new logger_1.CustomLogger({ useReporter: false }).log("Generated Plan:");
132
106
  console.log(plan);
@@ -135,17 +109,12 @@ async function runAgentsWorkflow(testGenConfig, testGenToken) {
135
109
  await (0, run_2.generateTestWithCodegen)({
136
110
  testCase,
137
111
  file: specPath,
138
- trace,
139
112
  });
140
113
  }
141
114
  else {
142
115
  const filePathToUpdate = await (0, utils_1.prepareFileForMasterAgent)({
143
116
  testCase,
144
117
  specPath,
145
- trace,
146
- });
147
- void (0, session_1.updateSessionStatus)(testGenConfig.options?.metadata.testSessionId, {
148
- status: "agent_live_session_started",
149
118
  });
150
119
  const projectName = await (0, run_1.convertProjectsFilterToProject)({
151
120
  pwProjectsFilter: testGenConfig.environment?.playwrightProjects,
@@ -247,15 +216,14 @@ async function main() {
247
216
  program
248
217
  .command("repos")
249
218
  .description("List your projects and repositories")
250
- .action(async () => {
219
+ .option("--auth-type <type>", 'Use "user-access-token" or "project-api-key"', "user-access-token")
220
+ .action(async (opts) => {
221
+ const apiClient = new client_1.DashboardAPIClient({
222
+ authType: opts.authType,
223
+ });
251
224
  try {
252
- const response = await api_client_1.apiClient.request("/api/projects");
253
- if (!response.ok) {
254
- console.error("❌ Failed to fetch projects:", response.statusText);
255
- process.exit(1);
256
- }
257
- const result = await response.json();
258
- result.data.projects.forEach((project) => {
225
+ const data = await apiClient.request("/api/projects", { method: "GET" });
226
+ data.data?.projects?.forEach((project) => {
259
227
  console.log(` ${project.repo_name}`);
260
228
  });
261
229
  }
@@ -265,11 +233,27 @@ async function main() {
265
233
  }
266
234
  process.exit(0);
267
235
  });
236
+ program
237
+ .command("setup")
238
+ .description("Clone a repository from your projects")
239
+ .requiredOption("--repo-name <string>", "Name of the repository to clone")
240
+ .option("--auth-type <type>", 'Use "user-access-token" or "project-api-key"', "user-access-token")
241
+ .action(async (opts) => {
242
+ const apiClient = new client_1.DashboardAPIClient({
243
+ authType: opts.authType,
244
+ });
245
+ await (0, setup_1.runSetup)({ apiClient, repoName: opts.repoName });
246
+ process.exit(0);
247
+ });
268
248
  program
269
249
  .command("environments")
270
250
  .description("List environments and their latest builds")
271
- .action(async () => {
272
- await (0, environments_1.listEnvironments)(process.cwd());
251
+ .option("--auth-type <type>", 'Use "user-access-token" or "project-api-key"', "user-access-token")
252
+ .action(async (opts) => {
253
+ const apiClient = new client_1.DashboardAPIClient({
254
+ authType: opts.authType,
255
+ });
256
+ await (0, environments_1.listEnvironments)({ apiClient, repoPath: process.cwd() });
273
257
  process.exit(0);
274
258
  });
275
259
  program
@@ -304,28 +288,14 @@ async function main() {
304
288
  });
305
289
  process.exit(0);
306
290
  });
307
- program
308
- .command("setup")
309
- .description("Clone a repository from your projects")
310
- .option("--repo-name <string>", "Name of the repository to clone")
311
- .action(async (opts) => {
312
- const options = await (0, utils_2.validateAndCompleteCliOptions)(opts, ["repoName"]);
313
- await (0, setup_1.runSetup)({ repoName: options.repoName });
314
- process.exit(0);
315
- });
316
291
  program
317
292
  .command("fetch-chat-state")
318
293
  .description("Fetch chat session state from the dashboard")
319
294
  .requiredOption("--id <id>", "Chat session ID")
320
295
  .action(async (opts) => {
321
296
  try {
322
- const response = await api_client_1.apiClient.request(`/api/chat-sessions/${opts.id}`);
323
- if (!response.ok) {
324
- console.error("❌ Failed to fetch chat session:", response.statusText);
325
- process.exit(1);
326
- }
327
- const responseData = await response.json();
328
- const chatState = responseData.data.chat_session.chat_state;
297
+ const data = await client_1.apiClient.request(`/api/chat-sessions/${opts.id}`, { method: "GET" });
298
+ const chatState = data.data.chat_session.chat_state;
329
299
  const filename = `chat-session-${opts.id}.json`;
330
300
  fs_1.default.writeFileSync(filename, JSON.stringify(chatState, null, 2));
331
301
  console.log(`✅ Chat state saved to ${filename}`);
@@ -347,15 +317,11 @@ async function main() {
347
317
  console.error("❌ Not a valid git repo with package.json. Run this command inside a project directory.");
348
318
  process.exit(1);
349
319
  }
350
- const response = await api_client_1.apiClient.request(`/api/projects/clone?project_repo_name=${repoName}`);
351
- const json = await response.json();
352
- if (!response.ok || !json.data || !json.data.access_token) {
353
- const errorMsg = json?.error ||
354
- response.statusText ||
355
- "Failed to fetch GitHub token for the repository";
356
- throw new Error(errorMsg);
357
- }
358
- const { access_token } = json.data;
320
+ const data = await client_1.apiClient.request(`/api/projects/clone`, {
321
+ method: "GET",
322
+ params: { project_repo_name: repoName },
323
+ });
324
+ const { access_token } = data.data;
359
325
  if (options.raw) {
360
326
  console.log("username=x-access-token");
361
327
  console.log(`password=${access_token}`);
@@ -378,12 +344,6 @@ async function main() {
378
344
  const testGenToken = options.token
379
345
  ? options.token
380
346
  : (0, scenarios_1.buildTokenFromOptions)(options);
381
- (0, session_1.setSessionDetails)({
382
- testCaseId: testGenConfig.testCase.id,
383
- sessionId: testGenConfig.options?.metadata.testSessionId,
384
- generationId: testGenConfig.options?.metadata.generationId,
385
- projectRepoName: testGenConfig.options?.metadata.projectRepoName,
386
- });
387
347
  if (testGenConfig.build?.url) {
388
348
  // Download the build if repo has a download script
389
349
  await (0, test_build_1.downloadBuild)({
@@ -401,7 +361,6 @@ async function main() {
401
361
  }
402
362
  await (0, llm_1.flushAllTraces)();
403
363
  await (0, logger_1.waitForLogsToFlush)();
404
- await (0, session_1.endSession)();
405
364
  if (testGenFailed) {
406
365
  process.exit(1);
407
366
  }
@@ -1,4 +1,6 @@
1
- export declare function runSetup({ repoName }: {
1
+ import { IDashboardAPIClient } from "@empiricalrun/shared-types";
2
+ export declare function runSetup({ apiClient, repoName, }: {
3
+ apiClient: IDashboardAPIClient;
2
4
  repoName: string;
3
5
  }): Promise<void>;
4
6
  //# sourceMappingURL=setup.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/bin/setup.ts"],"names":[],"mappings":"AA2HA,wBAAsB,QAAQ,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,iBA4BhE"}
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/bin/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AA2HjE,wBAAsB,QAAQ,CAAC,EAC7B,SAAS,EACT,QAAQ,GACT,EAAE;IACD,SAAS,EAAE,mBAAmB,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;CAClB,iBAqBA"}
package/dist/bin/setup.js CHANGED
@@ -8,7 +8,6 @@ const child_process_1 = require("child_process");
8
8
  const fs_1 = __importDefault(require("fs"));
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const util_1 = require("util");
11
- const api_client_1 = require("../auth/api-client");
12
11
  const utils_1 = require("./utils");
13
12
  const execAsync = (0, util_1.promisify)(child_process_1.exec);
14
13
  async function cloneRepository(cloneUrl, repoName) {
@@ -101,17 +100,14 @@ async function validateAndSetupRepo(repoPath) {
101
100
  console.error("⚠️ Authentication test failed:", error.message);
102
101
  }
103
102
  }
104
- async function runSetup({ repoName }) {
103
+ async function runSetup({ apiClient, repoName, }) {
105
104
  try {
106
105
  console.log(`🔍 Fetching details for repository: ${repoName}`);
107
- const response = await api_client_1.apiClient.request(`/api/projects/clone?project_repo_name=${repoName}`);
108
- if (!response.ok) {
109
- if (response.status === 404) {
110
- throw new Error(`Repository '${repoName}' not found in your projects`);
111
- }
112
- throw new Error(`Failed to fetch repository details: ${response.statusText}`);
113
- }
114
- const { data: repoDetails } = await response.json();
106
+ const data = await apiClient.request(`/api/projects/clone`, {
107
+ method: "GET",
108
+ params: { project_repo_name: repoName },
109
+ });
110
+ const { data: repoDetails } = data;
115
111
  const { clone_url } = repoDetails;
116
112
  console.log(`📂 Clone URL: ${(0, utils_1.cleanUpGithubUrl)(clone_url)}`);
117
113
  const targetDir = await cloneRepository(clone_url, repoName);
@@ -0,0 +1,26 @@
1
+ import { IDashboardAPIClient, RequestOptions } from "@empiricalrun/shared-types";
2
+ type AuthenticationType = "user-access-token" | "project-api-key" | "admin-totp";
3
+ export declare class DashboardAPIClient implements IDashboardAPIClient {
4
+ private baseUrl;
5
+ private authType;
6
+ private projectApiKey?;
7
+ private secretKey?;
8
+ constructor({ authType, projectApiKey, secretKey, baseUrl, }: {
9
+ authType: AuthenticationType;
10
+ projectApiKey?: string;
11
+ secretKey?: string;
12
+ baseUrl?: string;
13
+ });
14
+ request<T>(endpoint: string, options: RequestOptions): Promise<T>;
15
+ callGitHubProxy<T>({ method, url, body, }: {
16
+ method: "GET" | "POST" | "PATCH" | "PUT" | "DELETE";
17
+ url: string;
18
+ body?: any;
19
+ }): Promise<T>;
20
+ ensureUserIsAuthenticated(): Promise<void>;
21
+ private _makeRequest;
22
+ private refreshUserToken;
23
+ }
24
+ export declare const apiClient: DashboardAPIClient;
25
+ export {};
26
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/dashboard/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,cAAc,EACf,MAAM,4BAA4B,CAAC;AAapC,KAAK,kBAAkB,GACnB,mBAAmB,GACnB,iBAAiB,GACjB,YAAY,CAAC;AAEjB,qBAAa,kBAAmB,YAAW,mBAAmB;IAC5D,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,SAAS,CAAC,CAAS;gBAEf,EACV,QAAQ,EACR,aAAa,EACb,SAAS,EACT,OAAO,GACR,EAAE;QACD,QAAQ,EAAE,kBAAkB,CAAC;QAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB;IAsBK,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC;IAmDjE,eAAe,CAAC,CAAC,EAAE,EACvB,MAAM,EACN,GAAG,EACH,IAAI,GACL,EAAE;QACD,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,QAAQ,CAAC;QACpD,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,CAAC,EAAE,GAAG,CAAC;KACZ,GAAG,OAAO,CAAC,CAAC,CAAC;IAYR,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC;YAelC,YAAY;YAmDZ,gBAAgB;CAyC/B;AAED,eAAO,MAAM,SAAS,oBAEpB,CAAC"}
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.apiClient = exports.DashboardAPIClient = void 0;
7
+ const async_retry_1 = __importDefault(require("async-retry"));
8
+ const token_store_1 = require("../auth/token-store");
9
+ const logger_1 = require("../logger");
10
+ const totp_1 = require("./totp");
11
+ const types_1 = require("./types");
12
+ class DashboardAPIClient {
13
+ baseUrl;
14
+ authType;
15
+ projectApiKey;
16
+ secretKey;
17
+ constructor({ authType, projectApiKey, secretKey, baseUrl, }) {
18
+ this.baseUrl =
19
+ baseUrl || process.env.DASHBOARD_DOMAIN || "https://dash.empirical.run";
20
+ this.authType = authType;
21
+ if (this.authType === "project-api-key") {
22
+ if (!projectApiKey && !process.env.EMPIRICALRUN_API_KEY) {
23
+ throw new Error("Project API key is required when authentication type is 'project-api-key'");
24
+ }
25
+ this.projectApiKey = projectApiKey || process.env.EMPIRICALRUN_API_KEY;
26
+ }
27
+ else if (this.authType === "admin-totp") {
28
+ if (!secretKey && !process.env.EMPIRICAL_TOTP_SK) {
29
+ throw new Error("Secret key is required when authentication type is 'admin-totp'");
30
+ }
31
+ this.secretKey = secretKey || process.env.EMPIRICAL_TOTP_SK;
32
+ }
33
+ }
34
+ async request(endpoint, options) {
35
+ let response;
36
+ if (this.secretKey) {
37
+ const totp = await (0, totp_1.getTOTP)(this.secretKey);
38
+ const authHeader = {
39
+ "X-Empirical-Auth-TOTP": totp,
40
+ };
41
+ response = await this._makeRequest(endpoint, options, authHeader);
42
+ }
43
+ else if (this.projectApiKey) {
44
+ const authHeader = {
45
+ Authorization: `Bearer ${this.projectApiKey}`,
46
+ };
47
+ response = await this._makeRequest(endpoint, options, authHeader);
48
+ }
49
+ else {
50
+ await this.ensureUserIsAuthenticated();
51
+ const tokens = await (0, token_store_1.getStoredUserTokens)();
52
+ if (!tokens) {
53
+ throw new Error("Not authenticated. Please run the login command first.");
54
+ }
55
+ const authHeader = {
56
+ Authorization: `Bearer ${tokens.access_token}`,
57
+ };
58
+ response = await this._makeRequest(endpoint, options, authHeader);
59
+ if (response && response.status === 401) {
60
+ logger_1.logger.debug("Access token expired, attempting to refresh...");
61
+ const refreshed = await this.refreshUserToken();
62
+ if (refreshed) {
63
+ const newTokens = await (0, token_store_1.getStoredUserTokens)();
64
+ if (newTokens) {
65
+ const authHeader = {
66
+ Authorization: `Bearer ${newTokens.access_token}`,
67
+ };
68
+ response = this._makeRequest(endpoint, options, authHeader);
69
+ }
70
+ }
71
+ throw new Error("Authentication failed. Please run the login command again.");
72
+ }
73
+ }
74
+ if (!response) {
75
+ throw new Error("No response received from the API");
76
+ }
77
+ return response.json();
78
+ }
79
+ async callGitHubProxy({ method, url, body, }) {
80
+ const requestBody = {
81
+ method,
82
+ url,
83
+ body,
84
+ };
85
+ return await this.request(`/api/github/proxy`, {
86
+ method: "POST",
87
+ body: requestBody,
88
+ });
89
+ }
90
+ async ensureUserIsAuthenticated() {
91
+ if (!(await (0, token_store_1.isAuthenticated)())) {
92
+ const tokens = await (0, token_store_1.getStoredUserTokens)();
93
+ if (!tokens) {
94
+ throw new Error("Not authenticated. Please run the login command first.");
95
+ }
96
+ const refreshed = await this.refreshUserToken();
97
+ if (!refreshed) {
98
+ throw new Error("Session expired. Please run the login command again.");
99
+ }
100
+ }
101
+ }
102
+ async _makeRequest(endpoint, options, authHeader) {
103
+ const method = options.method || "GET";
104
+ const url = new URL(endpoint, this.baseUrl);
105
+ if (options.params) {
106
+ Object.entries(options.params).forEach(([key, value]) => {
107
+ url.searchParams.append(key, value);
108
+ });
109
+ }
110
+ const headers = {
111
+ ...authHeader,
112
+ "Content-Type": "application/json",
113
+ "User-Agent": "@empiricalrun/test-gen",
114
+ };
115
+ return await (0, async_retry_1.default)(async (bail) => {
116
+ const response = await fetch(url, {
117
+ headers,
118
+ method: method,
119
+ body: options.body ? JSON.stringify(options.body) : undefined,
120
+ });
121
+ if (!response.ok) {
122
+ let error;
123
+ const msg = `HTTP error in ${method} request to ${url}! Status code: ${response.status}`;
124
+ if (response.status < 500) {
125
+ // Don't retry for status codes less than 500 (client errors)
126
+ error = new types_1.NonRetryableHTTPError(msg, response.status);
127
+ bail(error);
128
+ return;
129
+ }
130
+ else {
131
+ error = new types_1.RetryableHTTPError(msg, response.status);
132
+ }
133
+ throw error;
134
+ }
135
+ return response;
136
+ }, {
137
+ retries: 3,
138
+ factor: 2,
139
+ minTimeout: 1_000,
140
+ maxTimeout: 5_000,
141
+ });
142
+ }
143
+ async refreshUserToken() {
144
+ const tokens = await (0, token_store_1.getStoredUserTokens)();
145
+ if (!tokens || !tokens.refresh_token) {
146
+ return false;
147
+ }
148
+ try {
149
+ const response = await fetch(`${this.baseUrl}/api/cli/refresh`, {
150
+ method: "POST",
151
+ headers: {
152
+ "Content-Type": "application/json",
153
+ },
154
+ body: JSON.stringify({
155
+ refresh_token: tokens.refresh_token,
156
+ }),
157
+ });
158
+ if (!response.ok) {
159
+ const errorText = await response.text();
160
+ console.error("Token refresh failed:", errorText);
161
+ await (0, token_store_1.clearTokens)();
162
+ return false;
163
+ }
164
+ const data = await response.json();
165
+ await (0, token_store_1.storeTokens)({
166
+ access_token: data.access_token,
167
+ refresh_token: data.refresh_token,
168
+ expires_at: data.expires_at,
169
+ user_id: data.user?.id || tokens.user_id,
170
+ user_email: data.user?.email || tokens.user_email,
171
+ });
172
+ logger_1.logger.debug("Access token refreshed successfully via dashboard");
173
+ return true;
174
+ }
175
+ catch (error) {
176
+ console.error("Token refresh error:", error);
177
+ await (0, token_store_1.clearTokens)();
178
+ return false;
179
+ }
180
+ }
181
+ }
182
+ exports.DashboardAPIClient = DashboardAPIClient;
183
+ exports.apiClient = new DashboardAPIClient({
184
+ authType: "user-access-token",
185
+ });
@@ -1,21 +1,3 @@
1
- export declare class HTTPError extends Error {
2
- status: number;
3
- constructor(message: string, status: number);
4
- }
5
- export declare class NonRetryableHTTPError extends HTTPError {
6
- }
7
- export declare class RetryableHTTPError extends HTTPError {
8
- }
9
- export interface RequestOptions {
10
- params?: Record<string, string>;
11
- body?: Record<string, unknown>;
12
- method: "GET" | "POST";
13
- headers?: Record<string, string>;
14
- }
15
- export declare function makeAuthenticatedRequest<T>(url: string, options: RequestOptions, secretKey?: string, dashboardDomain?: string): Promise<T>;
16
- export declare function callGitHubProxy({ method, url, body, }: {
17
- method: "GET" | "POST";
18
- url: string;
19
- body?: any;
20
- }): Promise<unknown>;
1
+ export { DashboardAPIClient } from "./client";
2
+ export { HTTPError, NonRetryableHTTPError, RetryableHTTPError } from "./types";
21
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dashboard/index.ts"],"names":[],"mappings":"AAIA,qBAAa,SAAU,SAAQ,KAAK;IAClC,MAAM,EAAE,MAAM,CAAC;gBACH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAI5C;AAED,qBAAa,qBAAsB,SAAQ,SAAS;CAAG;AAEvD,qBAAa,kBAAmB,SAAQ,SAAS;CAAG;AAEpD,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,wBAAsB,wBAAwB,CAAC,CAAC,EAC9C,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,cAAc,EACvB,SAAS,CAAC,EAAE,MAAM,EAClB,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,CAAC,CAAC,CAqDZ;AAED,wBAAsB,eAAe,CAAC,EACpC,MAAM,EACN,GAAG,EACH,IAAI,GACL,EAAE;IACD,MAAM,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ,oBAYA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dashboard/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC"}