@supatest/cli 0.0.44 → 0.0.45

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 (2) hide show
  1. package/dist/index.js +175 -92
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -6146,7 +6146,7 @@ var init_shared_es = __esm({
6146
6146
  assigned: numberType(),
6147
6147
  completed: numberType(),
6148
6148
  failed: numberType(),
6149
- free: numberType()
6149
+ unassigned: numberType()
6150
6150
  })
6151
6151
  });
6152
6152
  assigneeInfoSchema = objectType({
@@ -6218,7 +6218,7 @@ var init_shared_es = __esm({
6218
6218
  assigned: numberType(),
6219
6219
  completed: numberType(),
6220
6220
  failed: numberType(),
6221
- free: numberType()
6221
+ unassigned: numberType()
6222
6222
  })
6223
6223
  });
6224
6224
  bulkReassignResponseSchema = objectType({
@@ -6688,7 +6688,7 @@ var CLI_VERSION;
6688
6688
  var init_version = __esm({
6689
6689
  "src/version.ts"() {
6690
6690
  "use strict";
6691
- CLI_VERSION = "0.0.44";
6691
+ CLI_VERSION = "0.0.45";
6692
6692
  }
6693
6693
  });
6694
6694
 
@@ -7424,15 +7424,39 @@ var init_api_client = __esm({
7424
7424
  return data;
7425
7425
  }
7426
7426
  /**
7427
- * Assign tests to yourself (or someone else)
7427
+ * Bulk get test details for multiple tests
7428
+ * @param testIds - Array of test IDs
7429
+ * @returns Array of test details (null for not found tests)
7430
+ */
7431
+ async getTestDetailsBulk(testIds) {
7432
+ const url = `${this.apiUrl}/v1/reporting/tests/bulk`;
7433
+ logger.debug(`Bulk fetching ${testIds.length} test details`);
7434
+ const response = await fetch(url, {
7435
+ method: "POST",
7436
+ headers: {
7437
+ "Content-Type": "application/json",
7438
+ Authorization: `Bearer ${this.apiKey}`
7439
+ },
7440
+ body: JSON.stringify({ testIds })
7441
+ });
7442
+ if (!response.ok) {
7443
+ const errorText = await response.text();
7444
+ throw new ApiError(response.status, response.statusText, errorText);
7445
+ }
7446
+ const data = await response.json();
7447
+ logger.debug(`Fetched ${data.tests.length} test details`);
7448
+ return data.tests;
7449
+ }
7450
+ /**
7451
+ * Assign a test to yourself (or someone else)
7428
7452
  * @param params - Assignment parameters
7429
- * @returns Assignment result with assigned tests and conflicts
7453
+ * @returns Assignment result
7430
7454
  */
7431
- async assignTests(params) {
7432
- const url = `${this.apiUrl}/v1/fix-assignments/assign`;
7433
- logger.debug(`Assigning tests`, {
7434
- runId: params.runId,
7435
- count: params.testRunIds.length
7455
+ async assignTest(params) {
7456
+ const url = `${this.apiUrl}/v1/tests-catalog/assign`;
7457
+ logger.debug(`Assigning test`, {
7458
+ testId: params.testId,
7459
+ assignedTo: params.assignedTo
7436
7460
  });
7437
7461
  const response = await fetch(url, {
7438
7462
  method: "POST",
@@ -7441,7 +7465,37 @@ var init_api_client = __esm({
7441
7465
  Authorization: `Bearer ${this.apiKey}`
7442
7466
  },
7443
7467
  body: JSON.stringify({
7444
- testRunIds: params.testRunIds,
7468
+ testId: params.testId,
7469
+ assignedTo: params.assignedTo
7470
+ })
7471
+ });
7472
+ if (!response.ok) {
7473
+ const errorText = await response.text();
7474
+ throw new ApiError(response.status, response.statusText, errorText);
7475
+ }
7476
+ const data = await response.json();
7477
+ logger.debug(`Test assigned: ${params.testId} -> ${params.assignedTo}`);
7478
+ return data;
7479
+ }
7480
+ /**
7481
+ * Bulk assign multiple tests to yourself (or someone else)
7482
+ * @param params - Bulk assignment parameters
7483
+ * @returns Bulk assignment result with successful assignments and conflicts
7484
+ */
7485
+ async assignTestsBulk(params) {
7486
+ const url = `${this.apiUrl}/v1/tests-catalog/assign-bulk`;
7487
+ logger.debug(`Bulk assigning ${params.testIds.length} tests`, {
7488
+ testIds: params.testIds,
7489
+ assignedTo: params.assignedTo
7490
+ });
7491
+ const response = await fetch(url, {
7492
+ method: "POST",
7493
+ headers: {
7494
+ "Content-Type": "application/json",
7495
+ Authorization: `Bearer ${this.apiKey}`
7496
+ },
7497
+ body: JSON.stringify({
7498
+ testIds: params.testIds,
7445
7499
  assignedTo: params.assignedTo
7446
7500
  })
7447
7501
  });
@@ -7451,18 +7505,18 @@ var init_api_client = __esm({
7451
7505
  }
7452
7506
  const data = await response.json();
7453
7507
  logger.debug(
7454
- `Assigned ${data.assigned.length} tests, ${data.conflicts.length} conflicts`
7508
+ `Bulk assigned ${data.successful.length} tests, ${data.conflicts.length} conflicts`
7455
7509
  );
7456
7510
  return data;
7457
7511
  }
7458
7512
  /**
7459
- * Mark assignment as complete
7513
+ * Mark assignment as complete or failed
7460
7514
  * @param params - Completion parameters
7461
7515
  * @returns Success status
7462
7516
  */
7463
7517
  async completeAssignment(params) {
7464
- const url = `${this.apiUrl}/v1/fix-assignments/${params.assignmentId}/status`;
7465
- logger.debug(`Completing assignment`, {
7518
+ const url = `${this.apiUrl}/v1/tests-catalog/${params.assignmentId}/status`;
7519
+ logger.debug(`Updating assignment status`, {
7466
7520
  assignmentId: params.assignmentId,
7467
7521
  status: params.status
7468
7522
  });
@@ -7474,7 +7528,7 @@ var init_api_client = __esm({
7474
7528
  },
7475
7529
  body: JSON.stringify({
7476
7530
  status: params.status,
7477
- fixSessionId: params.fixSessionId
7531
+ notes: params.notes
7478
7532
  })
7479
7533
  });
7480
7534
  if (!response.ok) {
@@ -7482,7 +7536,7 @@ var init_api_client = __esm({
7482
7536
  throw new ApiError(response.status, response.statusText, errorText);
7483
7537
  }
7484
7538
  const data = await response.json();
7485
- logger.debug(`Assignment completed: ${params.assignmentId}`);
7539
+ logger.debug(`Assignment updated: ${params.assignmentId} -> ${params.status}`);
7486
7540
  return data;
7487
7541
  }
7488
7542
  /**
@@ -7491,7 +7545,7 @@ var init_api_client = __esm({
7491
7545
  * @returns Success status
7492
7546
  */
7493
7547
  async releaseAssignment(assignmentId) {
7494
- const url = `${this.apiUrl}/v1/fix-assignments/${assignmentId}`;
7548
+ const url = `${this.apiUrl}/v1/tests-catalog/${assignmentId}`;
7495
7549
  logger.debug(`Releasing assignment: ${assignmentId}`);
7496
7550
  const response = await fetch(url, {
7497
7551
  method: "DELETE",
@@ -7508,12 +7562,12 @@ var init_api_client = __esm({
7508
7562
  return data;
7509
7563
  }
7510
7564
  /**
7511
- * Get my current assignments
7512
- * @returns List of current assignments
7565
+ * Get my current work (active test assignments)
7566
+ * @returns List of current assignments with test info
7513
7567
  */
7514
- async getMyAssignments() {
7515
- const url = `${this.apiUrl}/v1/fix-assignments?status=assigned`;
7516
- logger.debug(`Fetching my assignments`);
7568
+ async getMyWork() {
7569
+ const url = `${this.apiUrl}/v1/tests-catalog/my-work`;
7570
+ logger.debug(`Fetching my work assignments`);
7517
7571
  const response = await fetch(url, {
7518
7572
  method: "GET",
7519
7573
  headers: {
@@ -7525,17 +7579,22 @@ var init_api_client = __esm({
7525
7579
  throw new ApiError(response.status, response.statusText, errorText);
7526
7580
  }
7527
7581
  const data = await response.json();
7528
- logger.debug(`Fetched ${data.assignments.length} assignments`);
7529
- return { assignments: data.assignments };
7582
+ logger.debug(`Fetched ${data.assignments?.length || 0} active assignments`);
7583
+ return data;
7530
7584
  }
7531
7585
  /**
7532
- * Get assignments for a specific run (to show what others are working on)
7586
+ * Get test catalog tests for a run (to show tests and their assignment status)
7533
7587
  * @param runId - The run ID
7534
- * @returns List of assignments for the run
7588
+ * @param query - Optional query parameters for filtering
7589
+ * @returns List of tests with their assignment info
7535
7590
  */
7536
- async getRunAssignments(runId) {
7537
- const url = `${this.apiUrl}/v1/fix-assignments?runId=${runId}&status=assigned`;
7538
- logger.debug(`Fetching assignments for run: ${runId}`);
7591
+ async getRunTestsCatalog(runId, query2) {
7592
+ const urlParams = new URLSearchParams();
7593
+ if (query2?.page) urlParams.set("page", query2.page.toString());
7594
+ if (query2?.limit) urlParams.set("limit", query2.limit.toString());
7595
+ if (query2?.status) urlParams.set("status", query2.status);
7596
+ const url = `${this.apiUrl}/v1/tests-catalog/runs/${runId}?${urlParams.toString()}`;
7597
+ logger.debug(`Fetching tests catalog for run: ${runId}`);
7539
7598
  const response = await fetch(url, {
7540
7599
  method: "GET",
7541
7600
  headers: {
@@ -7547,14 +7606,10 @@ var init_api_client = __esm({
7547
7606
  throw new ApiError(response.status, response.statusText, errorText);
7548
7607
  }
7549
7608
  const data = await response.json();
7550
- logger.debug(`Fetched ${data.assignments.length} assignments for run ${runId}`);
7551
- return {
7552
- assignments: data.assignments.map((a) => ({
7553
- testRunId: a.testRunId,
7554
- assignedTo: a.assignedTo,
7555
- assignedAt: a.assignedAt
7556
- }))
7557
- };
7609
+ logger.debug(
7610
+ `Fetched ${data.tests?.length || 0} tests for run ${runId}`
7611
+ );
7612
+ return data;
7558
7613
  }
7559
7614
  };
7560
7615
  }
@@ -12615,36 +12670,22 @@ var init_TestSelector = __esm({
12615
12670
  run,
12616
12671
  onSelect,
12617
12672
  onCancel,
12618
- assignments = []
12673
+ assignments = /* @__PURE__ */ new Map()
12619
12674
  }) => {
12620
12675
  const [allTests, setAllTests] = useState7([]);
12621
12676
  const [selectedTests, setSelectedTests] = useState7(/* @__PURE__ */ new Set());
12622
12677
  const [cursorIndex, setCursorIndex] = useState7(0);
12623
12678
  const [isLoading, setIsLoading] = useState7(false);
12624
- const [isLoadingAssignments, setIsLoadingAssignments] = useState7(true);
12625
12679
  const [hasMore, setHasMore] = useState7(true);
12626
12680
  const [totalTests, setTotalTests] = useState7(0);
12627
12681
  const [error, setError] = useState7(null);
12628
12682
  const [showAvailableOnly, setShowAvailableOnly] = useState7(true);
12629
12683
  const [groupByFile, setGroupByFile] = useState7(false);
12630
- const assignedTestMap = new Map(assignments.map((a) => [a.testRunId, a]));
12631
- const assignedTestIds = new Set(assignments.map((a) => a.testRunId));
12684
+ const assignedTestMap = assignments;
12685
+ const assignedTestIds = new Set(assignments.keys());
12632
12686
  useEffect7(() => {
12633
12687
  loadMoreTests();
12634
12688
  }, []);
12635
- useEffect7(() => {
12636
- fetchAssignments();
12637
- }, [run.id]);
12638
- const fetchAssignments = async () => {
12639
- setIsLoadingAssignments(true);
12640
- try {
12641
- const result = await apiClient.getRunAssignments(run.id);
12642
- } catch (err) {
12643
- console.error("Failed to load assignments:", err);
12644
- } finally {
12645
- setIsLoadingAssignments(false);
12646
- }
12647
- };
12648
12689
  const loadMoreTests = async () => {
12649
12690
  if (isLoading || !hasMore) {
12650
12691
  return;
@@ -12653,15 +12694,16 @@ var init_TestSelector = __esm({
12653
12694
  setError(null);
12654
12695
  try {
12655
12696
  const page = Math.floor(allTests.length / PAGE_SIZE2) + 1;
12656
- const result = await apiClient.getRunTests(run.id, {
12697
+ const result = await apiClient.getRunTestsCatalog(run.id, {
12657
12698
  page,
12658
12699
  limit: PAGE_SIZE2,
12659
12700
  status: "failed"
12660
12701
  // Only fetch failed tests
12661
12702
  });
12662
- setTotalTests(result.total);
12703
+ setTotalTests(result.total ?? result.tests.length);
12663
12704
  const loadedCount = allTests.length + result.tests.length;
12664
- setHasMore(result.tests.length === PAGE_SIZE2 && loadedCount < result.total);
12705
+ const total = result.total ?? loadedCount;
12706
+ setHasMore(result.tests.length === PAGE_SIZE2 && loadedCount < total);
12665
12707
  setAllTests((prev) => [...prev, ...result.tests]);
12666
12708
  } catch (err) {
12667
12709
  setError(err instanceof Error ? err.message : String(err));
@@ -12732,7 +12774,7 @@ var init_TestSelector = __esm({
12732
12774
  setSelectedTests(newSelected);
12733
12775
  };
12734
12776
  useInput3((input, key) => {
12735
- if (allTests.length === 0 && !isLoading && !isLoadingAssignments) {
12777
+ if (allTests.length === 0 && !isLoading) {
12736
12778
  if (key.escape || input === "q") {
12737
12779
  onCancel();
12738
12780
  }
@@ -12863,7 +12905,7 @@ var init_TestSelector = __esm({
12863
12905
  const displayAssignee = assignee.startsWith("cli:") ? assignee.slice(4) : assignee;
12864
12906
  return /* @__PURE__ */ React21.createElement(Box18, { key: test.id, marginBottom: 0 }, /* @__PURE__ */ React21.createElement(Text16, { backgroundColor: bgColor, bold: isSelected, color: isSelected ? "black" : isAssigned ? theme.text.dim : theme.text.primary }, indicator), /* @__PURE__ */ React21.createElement(Text16, { backgroundColor: bgColor, color: isAssigned ? theme.text.dim : isChecked ? "green" : isSelected ? "black" : theme.text.dim }, isAssigned ? "\u{1F504}" : checkbox), /* @__PURE__ */ React21.createElement(Text16, null, " "), /* @__PURE__ */ React21.createElement(Text16, { backgroundColor: bgColor, bold: isSelected, color: isSelected ? "black" : isAssigned ? theme.text.dim : theme.text.primary }, file, line && /* @__PURE__ */ React21.createElement(Text16, { color: isSelected ? "black" : theme.text.dim }, ":", line), isAssigned && /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, " \u2022 "), /* @__PURE__ */ React21.createElement(Text16, { color: "yellow" }, displayAssignee)), /* @__PURE__ */ React21.createElement(Text16, { color: isSelected ? "black" : theme.text.dim }, " - "), title));
12865
12907
  })
12866
- )), /* @__PURE__ */ React21.createElement(Box18, { flexDirection: "column", marginTop: 1 }, !groupByFile && filteredTests.length > VISIBLE_ITEMS2 && /* @__PURE__ */ React21.createElement(Box18, { marginBottom: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: "yellow" }, "Showing ", adjustedStart + 1, "-", adjustedEnd, " of ", filteredTests.length, " ", showAvailableOnly ? "available" : "", " tests", hasMore && !isLoading && /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, " (scroll for more)"))), groupByFile && /* @__PURE__ */ React21.createElement(Box18, { marginBottom: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: "yellow" }, "Showing ", fileGroups.length, " file", fileGroups.length !== 1 ? "s" : "", " \u2022 ", filteredTests.length, " total test", filteredTests.length !== 1 ? "s" : "")), /* @__PURE__ */ React21.createElement(Box18, null, /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "\u2191\u2193"), " navigate \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "Space"), " toggle \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "n"), " none \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "s"), " next 10 \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "f"), " group files \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "t"), " toggle filter \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "Enter"), " fix selected")), selectedTests.size > 0 && /* @__PURE__ */ React21.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: "green" }, selectedTests.size, " test", selectedTests.size !== 1 ? "s" : "", " selected")), (isLoading || isLoadingAssignments) && /* @__PURE__ */ React21.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: "cyan" }, isLoading ? "Loading more tests..." : "Loading assignments..."))));
12908
+ )), /* @__PURE__ */ React21.createElement(Box18, { flexDirection: "column", marginTop: 1 }, !groupByFile && filteredTests.length > VISIBLE_ITEMS2 && /* @__PURE__ */ React21.createElement(Box18, { marginBottom: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: "yellow" }, "Showing ", adjustedStart + 1, "-", adjustedEnd, " of ", filteredTests.length, " ", showAvailableOnly ? "available" : "", " tests", hasMore && !isLoading && /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, " (scroll for more)"))), groupByFile && /* @__PURE__ */ React21.createElement(Box18, { marginBottom: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: "yellow" }, "Showing ", fileGroups.length, " file", fileGroups.length !== 1 ? "s" : "", " \u2022 ", filteredTests.length, " total test", filteredTests.length !== 1 ? "s" : "")), /* @__PURE__ */ React21.createElement(Box18, null, /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "\u2191\u2193"), " navigate \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "Space"), " toggle \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "n"), " none \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "s"), " next 10 \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "f"), " group files \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "t"), " toggle filter \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "Enter"), " fix selected")), selectedTests.size > 0 && /* @__PURE__ */ React21.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: "green" }, selectedTests.size, " test", selectedTests.size !== 1 ? "s" : "", " selected")), isLoading && /* @__PURE__ */ React21.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: "cyan" }, "Loading more tests..."))));
12867
12909
  };
12868
12910
  }
12869
12911
  });
@@ -12889,7 +12931,8 @@ var init_FixFlow = __esm({
12889
12931
  const [step, setStep] = useState8(initialRunId ? "select-run" : "select-run");
12890
12932
  const [selectedRun, setSelectedRun] = useState8(null);
12891
12933
  const [selectedTests, setSelectedTests] = useState8([]);
12892
- const [assignments, setAssignments] = useState8([]);
12934
+ const [assignments, setAssignments] = useState8(/* @__PURE__ */ new Map());
12935
+ const [testCatalogMap, setTestCatalogMap] = useState8(/* @__PURE__ */ new Map());
12893
12936
  const [assignmentIds, setAssignmentIds] = useState8(/* @__PURE__ */ new Map());
12894
12937
  const [loadingProgress, setLoadingProgress] = useState8({ current: 0, total: 0 });
12895
12938
  const [loadError, setLoadError] = useState8(null);
@@ -12913,8 +12956,25 @@ var init_FixFlow = __esm({
12913
12956
  };
12914
12957
  const fetchAssignments = async (runId) => {
12915
12958
  try {
12916
- const result = await apiClient.getRunAssignments(runId);
12917
- setAssignments(result.assignments);
12959
+ const result = await apiClient.getRunTestsCatalog(runId, {
12960
+ status: "failed",
12961
+ limit: 1e3
12962
+ // Get all failed tests for assignment lookup
12963
+ });
12964
+ const assignmentMap = /* @__PURE__ */ new Map();
12965
+ const catalogMap = /* @__PURE__ */ new Map();
12966
+ for (const test of result.tests) {
12967
+ catalogMap.set(test.id, test.testId);
12968
+ if (test.assignment) {
12969
+ assignmentMap.set(test.id, {
12970
+ testId: test.testId,
12971
+ assignedTo: test.assignment.assignedTo,
12972
+ assignedAt: test.assignment.assignedAt
12973
+ });
12974
+ }
12975
+ }
12976
+ setAssignments(assignmentMap);
12977
+ setTestCatalogMap(catalogMap);
12918
12978
  } catch (err) {
12919
12979
  console.error("Failed to load assignments:", err);
12920
12980
  }
@@ -12924,16 +12984,46 @@ var init_FixFlow = __esm({
12924
12984
  setStep("claiming-tests");
12925
12985
  setLoadError(null);
12926
12986
  try {
12927
- if (selectedRun) {
12928
- const claimResult = await apiClient.assignTests({
12929
- runId: selectedRun.id,
12930
- testRunIds: tests.map((t) => t.id)
12931
- });
12932
- if (claimResult.conflicts.length > 0) {
12933
- const conflictList = claimResult.conflicts.slice(0, 5).map((c) => `${c.file}: ${c.title} (claimed by ${c.currentAssignee})`).join("\n\u2022 ");
12934
- const moreCount = claimResult.conflicts.length - 5;
12987
+ const assignmentMap = /* @__PURE__ */ new Map();
12988
+ const testCatalogUuids = [];
12989
+ const testRunToCatalogMap = /* @__PURE__ */ new Map();
12990
+ for (const test of tests) {
12991
+ const testCatalogUuid = testCatalogMap.get(test.id);
12992
+ if (!testCatalogUuid) {
12993
+ throw new Error(`Test catalog entry not found for test: ${test.file}:${test.title}`);
12994
+ }
12995
+ testCatalogUuids.push(testCatalogUuid);
12996
+ testRunToCatalogMap.set(testCatalogUuid, test.id);
12997
+ }
12998
+ const result = await apiClient.assignTestsBulk({
12999
+ testIds: testCatalogUuids
13000
+ });
13001
+ for (const assignment of result.successful) {
13002
+ const testRunId = testRunToCatalogMap.get(assignment.testId);
13003
+ if (testRunId) {
13004
+ assignmentMap.set(testRunId, assignment.id);
13005
+ }
13006
+ }
13007
+ const conflicts = [];
13008
+ for (const conflict of result.conflicts) {
13009
+ const testRunId = testRunToCatalogMap.get(conflict.testId);
13010
+ if (testRunId) {
13011
+ const test = tests.find((t) => t.id === testRunId);
13012
+ if (test) {
13013
+ conflicts.push({
13014
+ test,
13015
+ assignee: conflict.assignedTo
13016
+ });
13017
+ }
13018
+ }
13019
+ }
13020
+ if (conflicts.length > 0) {
13021
+ const successfullyClaimed = tests.filter((test) => assignmentMap.has(test.id));
13022
+ if (successfullyClaimed.length === 0) {
13023
+ const conflictList = conflicts.slice(0, 3).map((c) => `${c.test.file}: ${c.test.title} (claimed by ${c.assignee})`).join("\n\u2022 ");
13024
+ const moreCount = conflicts.length - 3;
12935
13025
  setLoadError(
12936
- `${claimResult.conflicts.length} test${claimResult.conflicts.length > 1 ? "s were" : " was"} already claimed by others:
13026
+ `All selected tests are already claimed by others:
12937
13027
  \u2022 ${conflictList}${moreCount > 0 ? `
12938
13028
  \u2022 ... and ${moreCount} more` : ""}
12939
13029
 
@@ -12942,28 +13032,22 @@ Please select different tests.`
12942
13032
  setStep("error");
12943
13033
  return;
12944
13034
  }
12945
- const assignmentMap = /* @__PURE__ */ new Map();
12946
- claimResult.assigned.forEach((assignment) => {
12947
- assignmentMap.set(assignment.testRunId, assignment.id);
12948
- });
12949
- setAssignmentIds(assignmentMap);
13035
+ setSelectedTests(successfullyClaimed);
13036
+ console.log(`Skipped ${conflicts.length} already claimed test(s), continuing with ${successfullyClaimed.length} test(s)`);
12950
13037
  }
13038
+ setAssignmentIds(assignmentMap);
13039
+ const testsToLoad = conflicts.length > 0 ? tests.filter((test) => assignmentMap.has(test.id)) : tests;
12951
13040
  setStep("loading-details");
12952
- setLoadingProgress({ current: 0, total: tests.length });
12953
- const testDetails = [];
12954
- const batchSize = 5;
12955
- for (let i = 0; i < tests.length; i += batchSize) {
12956
- const batch = tests.slice(i, i + batchSize);
12957
- const batchResults = await Promise.all(
12958
- batch.map((test) => apiClient.getTestDetail(test.id))
12959
- );
12960
- testDetails.push(...batchResults);
12961
- setLoadingProgress({ current: testDetails.length, total: tests.length });
12962
- }
13041
+ setLoadingProgress({ current: 0, total: testsToLoad.length });
13042
+ const testIds = testsToLoad.map((test) => test.id);
13043
+ const testDetailsArray = await apiClient.getTestDetailsBulk(testIds);
13044
+ const testDetails = testDetailsArray.filter(
13045
+ (detail) => detail !== null
13046
+ );
12963
13047
  const testContexts = testDetails.map((test) => ({ test }));
12964
13048
  const prompt = buildFixPrompt(testContexts);
12965
13049
  setStep("fixing");
12966
- onStartFix(prompt, tests);
13050
+ onStartFix(prompt, testsToLoad);
12967
13051
  } catch (err) {
12968
13052
  const errorMessage = err instanceof Error ? err.message : String(err);
12969
13053
  if (errorMessage.includes("network") || errorMessage.includes("fetch")) {
@@ -12991,7 +13075,7 @@ Press ESC to go back and try again.`);
12991
13075
  };
12992
13076
  const handleTestCancel = () => {
12993
13077
  setSelectedRun(null);
12994
- setAssignments([]);
13078
+ setAssignments(/* @__PURE__ */ new Map());
12995
13079
  setStep("select-run");
12996
13080
  };
12997
13081
  const markAssignmentsComplete = async (fixSessionId) => {
@@ -13003,8 +13087,7 @@ Press ESC to go back and try again.`);
13003
13087
  Array.from(assignmentIds.values()).map(
13004
13088
  (assignmentId) => apiClient.completeAssignment({
13005
13089
  assignmentId,
13006
- status: "completed",
13007
- fixSessionId
13090
+ status: "completed"
13008
13091
  })
13009
13092
  )
13010
13093
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supatest/cli",
3
- "version": "0.0.44",
3
+ "version": "0.0.45",
4
4
  "description": "Supatest CLI - AI-powered task automation for CI/CD",
5
5
  "type": "module",
6
6
  "bin": {