@bbearai/core 0.5.0 → 0.5.1

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/dist/index.d.mts CHANGED
@@ -252,6 +252,8 @@ interface TestAssignment {
252
252
  group?: TestGroup;
253
253
  /** Required app role for testing (e.g., Owner, Manager) */
254
254
  role?: ProjectRole;
255
+ /** Platforms this test applies to (e.g., ['ios', 'web']) */
256
+ platforms?: string[];
255
257
  };
256
258
  status: 'pending' | 'in_progress' | 'passed' | 'failed' | 'blocked' | 'skipped';
257
259
  /** Reason for skipping (when status is 'skipped') */
@@ -881,6 +883,14 @@ declare class BugBearClient {
881
883
  error?: string;
882
884
  durationSeconds?: number;
883
885
  }>;
886
+ /**
887
+ * Reopen a completed assignment — sets it back to in_progress with a fresh timer.
888
+ * Clears completed_at and duration_seconds so it can be re-evaluated.
889
+ */
890
+ reopenAssignment(assignmentId: string): Promise<{
891
+ success: boolean;
892
+ error?: string;
893
+ }>;
884
894
  /**
885
895
  * Skip a test assignment with a required reason
886
896
  * Marks the assignment as 'skipped' and records why it was skipped
package/dist/index.d.ts CHANGED
@@ -252,6 +252,8 @@ interface TestAssignment {
252
252
  group?: TestGroup;
253
253
  /** Required app role for testing (e.g., Owner, Manager) */
254
254
  role?: ProjectRole;
255
+ /** Platforms this test applies to (e.g., ['ios', 'web']) */
256
+ platforms?: string[];
255
257
  };
256
258
  status: 'pending' | 'in_progress' | 'passed' | 'failed' | 'blocked' | 'skipped';
257
259
  /** Reason for skipping (when status is 'skipped') */
@@ -881,6 +883,14 @@ declare class BugBearClient {
881
883
  error?: string;
882
884
  durationSeconds?: number;
883
885
  }>;
886
+ /**
887
+ * Reopen a completed assignment — sets it back to in_progress with a fresh timer.
888
+ * Clears completed_at and duration_seconds so it can be re-evaluated.
889
+ */
890
+ reopenAssignment(assignmentId: string): Promise<{
891
+ success: boolean;
892
+ error?: string;
893
+ }>;
884
894
  /**
885
895
  * Skip a test assignment with a required reason
886
896
  * Marks the assignment as 'skipped' and records why it was skipped
package/dist/index.js CHANGED
@@ -725,10 +725,11 @@ var BugBearClient = class {
725
725
  const pageSize = Math.min(options?.pageSize ?? 100, 100);
726
726
  const from = (options?.page ?? 0) * pageSize;
727
727
  const to = from + pageSize - 1;
728
- const { data, error } = await this.supabase.from("test_assignments").select(`
728
+ const selectFields = `
729
729
  id,
730
730
  status,
731
731
  started_at,
732
+ completed_at,
732
733
  skip_reason,
733
734
  is_verification,
734
735
  original_report_id,
@@ -763,20 +764,24 @@ var BugBearClient = class {
763
764
  color,
764
765
  description,
765
766
  login_hint
766
- )
767
+ ),
768
+ platforms
767
769
  )
768
- `).eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).in("status", ["pending", "in_progress"]).order("created_at", { ascending: true }).range(from, to);
769
- if (error) {
770
- console.error("BugBear: Failed to fetch assignments", formatPgError(error));
770
+ `;
771
+ const twentyFourHoursAgo = new Date(Date.now() - 24 * 60 * 60 * 1e3).toISOString();
772
+ const [pendingResult, completedResult] = await Promise.all([
773
+ this.supabase.from("test_assignments").select(selectFields).eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).in("status", ["pending", "in_progress"]).order("created_at", { ascending: true }).range(from, to),
774
+ this.supabase.from("test_assignments").select(selectFields).eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).in("status", ["passed", "failed", "skipped", "blocked"]).gte("completed_at", twentyFourHoursAgo).order("completed_at", { ascending: false }).limit(50)
775
+ ]);
776
+ if (pendingResult.error) {
777
+ console.error("BugBear: Failed to fetch assignments", formatPgError(pendingResult.error));
771
778
  return [];
772
779
  }
773
- const mapped = (data || []).filter((item) => {
774
- if (!item.test_case) {
775
- console.warn("BugBear: Assignment returned without test_case", { id: item.id });
776
- return false;
777
- }
778
- return true;
779
- }).map((item) => ({
780
+ const allData = [
781
+ ...pendingResult.data || [],
782
+ ...completedResult.data || []
783
+ ];
784
+ const mapItem = (item) => ({
780
785
  id: item.id,
781
786
  status: item.status,
782
787
  startedAt: item.started_at,
@@ -814,12 +819,24 @@ var BugBearClient = class {
814
819
  color: item.test_case.role.color,
815
820
  description: item.test_case.role.description,
816
821
  loginHint: item.test_case.role.login_hint
817
- } : void 0
822
+ } : void 0,
823
+ platforms: item.test_case.platforms || void 0
818
824
  }
819
- }));
825
+ });
826
+ const mapped = allData.filter((item) => {
827
+ if (!item.test_case) {
828
+ console.warn("BugBear: Assignment returned without test_case", { id: item.id });
829
+ return false;
830
+ }
831
+ return true;
832
+ }).map(mapItem);
820
833
  mapped.sort((a, b) => {
821
834
  if (a.isVerification && !b.isVerification) return -1;
822
835
  if (!a.isVerification && b.isVerification) return 1;
836
+ const aActive = a.status === "pending" || a.status === "in_progress";
837
+ const bActive = b.status === "pending" || b.status === "in_progress";
838
+ if (aActive && !bActive) return -1;
839
+ if (!aActive && bActive) return 1;
823
840
  return 0;
824
841
  });
825
842
  return mapped;
@@ -984,6 +1001,36 @@ var BugBearClient = class {
984
1001
  async failAssignment(assignmentId) {
985
1002
  return this.updateAssignmentStatus(assignmentId, "failed");
986
1003
  }
1004
+ /**
1005
+ * Reopen a completed assignment — sets it back to in_progress with a fresh timer.
1006
+ * Clears completed_at and duration_seconds so it can be re-evaluated.
1007
+ */
1008
+ async reopenAssignment(assignmentId) {
1009
+ try {
1010
+ const { data: current, error: fetchError } = await this.supabase.from("test_assignments").select("status").eq("id", assignmentId).single();
1011
+ if (fetchError || !current) {
1012
+ return { success: false, error: "Assignment not found" };
1013
+ }
1014
+ if (current.status === "pending" || current.status === "in_progress") {
1015
+ return { success: true };
1016
+ }
1017
+ const { error } = await this.supabase.from("test_assignments").update({
1018
+ status: "in_progress",
1019
+ started_at: (/* @__PURE__ */ new Date()).toISOString(),
1020
+ completed_at: null,
1021
+ duration_seconds: null,
1022
+ skip_reason: null
1023
+ }).eq("id", assignmentId).eq("status", current.status);
1024
+ if (error) {
1025
+ console.error("BugBear: Failed to reopen assignment", error);
1026
+ return { success: false, error: error.message };
1027
+ }
1028
+ return { success: true };
1029
+ } catch (err) {
1030
+ const message = err instanceof Error ? err.message : "Unknown error";
1031
+ return { success: false, error: message };
1032
+ }
1033
+ }
987
1034
  /**
988
1035
  * Skip a test assignment with a required reason
989
1036
  * Marks the assignment as 'skipped' and records why it was skipped
package/dist/index.mjs CHANGED
@@ -691,10 +691,11 @@ var BugBearClient = class {
691
691
  const pageSize = Math.min(options?.pageSize ?? 100, 100);
692
692
  const from = (options?.page ?? 0) * pageSize;
693
693
  const to = from + pageSize - 1;
694
- const { data, error } = await this.supabase.from("test_assignments").select(`
694
+ const selectFields = `
695
695
  id,
696
696
  status,
697
697
  started_at,
698
+ completed_at,
698
699
  skip_reason,
699
700
  is_verification,
700
701
  original_report_id,
@@ -729,20 +730,24 @@ var BugBearClient = class {
729
730
  color,
730
731
  description,
731
732
  login_hint
732
- )
733
+ ),
734
+ platforms
733
735
  )
734
- `).eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).in("status", ["pending", "in_progress"]).order("created_at", { ascending: true }).range(from, to);
735
- if (error) {
736
- console.error("BugBear: Failed to fetch assignments", formatPgError(error));
736
+ `;
737
+ const twentyFourHoursAgo = new Date(Date.now() - 24 * 60 * 60 * 1e3).toISOString();
738
+ const [pendingResult, completedResult] = await Promise.all([
739
+ this.supabase.from("test_assignments").select(selectFields).eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).in("status", ["pending", "in_progress"]).order("created_at", { ascending: true }).range(from, to),
740
+ this.supabase.from("test_assignments").select(selectFields).eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).in("status", ["passed", "failed", "skipped", "blocked"]).gte("completed_at", twentyFourHoursAgo).order("completed_at", { ascending: false }).limit(50)
741
+ ]);
742
+ if (pendingResult.error) {
743
+ console.error("BugBear: Failed to fetch assignments", formatPgError(pendingResult.error));
737
744
  return [];
738
745
  }
739
- const mapped = (data || []).filter((item) => {
740
- if (!item.test_case) {
741
- console.warn("BugBear: Assignment returned without test_case", { id: item.id });
742
- return false;
743
- }
744
- return true;
745
- }).map((item) => ({
746
+ const allData = [
747
+ ...pendingResult.data || [],
748
+ ...completedResult.data || []
749
+ ];
750
+ const mapItem = (item) => ({
746
751
  id: item.id,
747
752
  status: item.status,
748
753
  startedAt: item.started_at,
@@ -780,12 +785,24 @@ var BugBearClient = class {
780
785
  color: item.test_case.role.color,
781
786
  description: item.test_case.role.description,
782
787
  loginHint: item.test_case.role.login_hint
783
- } : void 0
788
+ } : void 0,
789
+ platforms: item.test_case.platforms || void 0
784
790
  }
785
- }));
791
+ });
792
+ const mapped = allData.filter((item) => {
793
+ if (!item.test_case) {
794
+ console.warn("BugBear: Assignment returned without test_case", { id: item.id });
795
+ return false;
796
+ }
797
+ return true;
798
+ }).map(mapItem);
786
799
  mapped.sort((a, b) => {
787
800
  if (a.isVerification && !b.isVerification) return -1;
788
801
  if (!a.isVerification && b.isVerification) return 1;
802
+ const aActive = a.status === "pending" || a.status === "in_progress";
803
+ const bActive = b.status === "pending" || b.status === "in_progress";
804
+ if (aActive && !bActive) return -1;
805
+ if (!aActive && bActive) return 1;
789
806
  return 0;
790
807
  });
791
808
  return mapped;
@@ -950,6 +967,36 @@ var BugBearClient = class {
950
967
  async failAssignment(assignmentId) {
951
968
  return this.updateAssignmentStatus(assignmentId, "failed");
952
969
  }
970
+ /**
971
+ * Reopen a completed assignment — sets it back to in_progress with a fresh timer.
972
+ * Clears completed_at and duration_seconds so it can be re-evaluated.
973
+ */
974
+ async reopenAssignment(assignmentId) {
975
+ try {
976
+ const { data: current, error: fetchError } = await this.supabase.from("test_assignments").select("status").eq("id", assignmentId).single();
977
+ if (fetchError || !current) {
978
+ return { success: false, error: "Assignment not found" };
979
+ }
980
+ if (current.status === "pending" || current.status === "in_progress") {
981
+ return { success: true };
982
+ }
983
+ const { error } = await this.supabase.from("test_assignments").update({
984
+ status: "in_progress",
985
+ started_at: (/* @__PURE__ */ new Date()).toISOString(),
986
+ completed_at: null,
987
+ duration_seconds: null,
988
+ skip_reason: null
989
+ }).eq("id", assignmentId).eq("status", current.status);
990
+ if (error) {
991
+ console.error("BugBear: Failed to reopen assignment", error);
992
+ return { success: false, error: error.message };
993
+ }
994
+ return { success: true };
995
+ } catch (err) {
996
+ const message = err instanceof Error ? err.message : "Unknown error";
997
+ return { success: false, error: message };
998
+ }
999
+ }
953
1000
  /**
954
1001
  * Skip a test assignment with a required reason
955
1002
  * Marks the assignment as 'skipped' and records why it was skipped
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bbearai/core",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Core utilities and types for BugBear QA platform",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",