@bbearai/core 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -377,6 +377,8 @@ interface TestAssignment {
377
377
  startedAt?: string;
378
378
  /** Duration in seconds (calculated when completed) */
379
379
  durationSeconds?: number;
380
+ /** Active time in seconds, computed from presence heartbeats */
381
+ activeSeconds?: number;
380
382
  /** Whether this is a verification assignment for a fixed bug */
381
383
  isVerification?: boolean;
382
384
  /** Original report ID if this is a verification assignment */
@@ -690,6 +692,10 @@ interface QASession {
690
692
  track?: string;
691
693
  /** Platform being tested */
692
694
  platform?: string;
695
+ /** Session type: exploratory or ad_hoc */
696
+ sessionType: QASessionType;
697
+ /** Linked task ID (ad hoc sessions) */
698
+ taskId?: string;
693
699
  /** Timing */
694
700
  startedAt: string;
695
701
  endedAt?: string;
@@ -735,11 +741,17 @@ interface QAFinding {
735
741
  createdAt: string;
736
742
  updatedAt: string;
737
743
  }
744
+ /** Session type */
745
+ type QASessionType = 'exploratory' | 'ad_hoc';
738
746
  /** Options for starting a QA session */
739
747
  interface StartSessionOptions {
740
748
  focusArea?: string;
741
749
  track?: string;
742
750
  platform?: string;
751
+ /** Session type: exploratory (default) or ad_hoc */
752
+ sessionType?: QASessionType;
753
+ /** Link to a qa_task (ad hoc mode) */
754
+ taskId?: string;
743
755
  }
744
756
  /** Options for ending a QA session */
745
757
  interface EndSessionOptions {
@@ -759,6 +771,22 @@ interface AddFindingOptions {
759
771
  deviceInfo?: DeviceInfo;
760
772
  appContext?: AppContext;
761
773
  }
774
+ /** QA Task priority */
775
+ type QATaskPriority = 'high' | 'normal' | 'low';
776
+ /** QA Task status */
777
+ type QATaskStatus = 'active' | 'archived';
778
+ /** Lightweight task prompt for ad hoc testing */
779
+ interface QATask {
780
+ id: string;
781
+ projectId: string;
782
+ title: string;
783
+ description?: string;
784
+ trackId?: string;
785
+ priority: QATaskPriority;
786
+ status: QATaskStatus;
787
+ createdAt: string;
788
+ updatedAt: string;
789
+ }
762
790
  /** Category for filtering tester issues in the widget */
763
791
  type IssueCategory = 'open' | 'done' | 'reopened';
764
792
  /** Issue counts for each category (HomeScreen cards) */
@@ -789,6 +817,14 @@ interface TesterIssue {
789
817
  originalBugId?: string;
790
818
  /** Original bug title (for reopened/test_fail issues) */
791
819
  originalBugTitle?: string;
820
+ /** Resolution notes from the developer (for ready_to_test issues) */
821
+ resolutionNotes?: string;
822
+ /** Fix commit SHA (for ready_to_test issues) */
823
+ fixCommitSha?: string;
824
+ /** Fix commit message */
825
+ fixCommitMessage?: string;
826
+ /** Files changed in the fix */
827
+ fixFilesChanged?: string[];
792
828
  }
793
829
  /** Delivery status for captured emails */
794
830
  type EmailDeliveryStatus = 'pending' | 'sent' | 'delivered' | 'bounced' | 'dropped' | 'deferred';
@@ -1560,6 +1596,14 @@ declare class BugBearClient {
1560
1596
  success: boolean;
1561
1597
  error?: string;
1562
1598
  }>;
1599
+ /**
1600
+ * Get active QA tasks for the project
1601
+ */
1602
+ getTasks(status?: string): Promise<QATask[]>;
1603
+ /**
1604
+ * Transform database task to QATask type
1605
+ */
1606
+ private transformTask;
1563
1607
  /**
1564
1608
  * Transform database session to QASession type
1565
1609
  */
@@ -1686,4 +1730,4 @@ interface EmailInterceptor {
1686
1730
  */
1687
1731
  declare function createEmailInterceptor(client: BugBearClient, options?: EmailInterceptorOptions): EmailInterceptor;
1688
1732
 
1689
- export { type AddFindingOptions, type AppContext, BUG_CATEGORIES, BugBearClient, type BugBearConfig, type BugBearMode, type BugBearReport, type BugBearTheme, type BugCategory, type ChecklistItem, type ChecklistResult, type ConsoleLogEntry, type CoverageGap, type CoverageMatrixCell, type CoverageMatrixRow, DedupWindow, type DeployChecklist, type DeviceInfo, type EmailCaptureMode, type EmailCapturePayload, type EmailCaptureResult, type EmailDeliveryStatus, type EmailInterceptorOptions, type EmailPayloadExtractor, type EndSessionOptions, type EnhancedBugContext, ErrorMonitor, type ExtractedEmailPayload, type FindingSeverity, type FindingType, type HostUserInfo, type IssueCategory, type IssueCounts, LocalStorageAdapter, type MessageSenderType, type MonitorDeps, type MonitoringConfig, type MonitoringEvent, type NetworkRequest, OfflineQueue, type OfflineQueueConfig, type PriorityFactors, type ProjectRole, type QAFinding, type QAHealthMetrics, type QAHealthScore, type QASession, type QASessionStatus, type QATrack, type QueueItem, type QueueItemType, RNApiFailureHandler, RNCrashHandler, RNRageClickHandler, RageClickDetector, type RageClickEvent, type RegressionEvent, type ReportSource, type ReportStatus, type ReportType, type RoutePriority, type RouteTestStats, type RubricMode, type RubricResult, type Severity, type SkipReason, type StartSessionOptions, type StorageAdapter, type SubmitFeedbackOptions, type TestAssignment, type TestFeedback, type TestGroup, type TestResult, type TestStep, type TestTemplate, type TesterInfo, type TesterIssue, type TesterMessage, type TesterProfileUpdate, type TesterThread, type ThreadPriority, type ThreadType, WebApiFailureHandler, WebCrashHandler, WebRageClickHandler, type WidgetColorScheme, type WidgetConfig, captureError, contextCapture, createBugBear, createEmailInterceptor, generateFingerprint, isBugCategory, isNetworkError, scrubUrl };
1733
+ export { type AddFindingOptions, type AppContext, BUG_CATEGORIES, BugBearClient, type BugBearConfig, type BugBearMode, type BugBearReport, type BugBearTheme, type BugCategory, type ChecklistItem, type ChecklistResult, type ConsoleLogEntry, type CoverageGap, type CoverageMatrixCell, type CoverageMatrixRow, DedupWindow, type DeployChecklist, type DeviceInfo, type EmailCaptureMode, type EmailCapturePayload, type EmailCaptureResult, type EmailDeliveryStatus, type EmailInterceptorOptions, type EmailPayloadExtractor, type EndSessionOptions, type EnhancedBugContext, ErrorMonitor, type ExtractedEmailPayload, type FindingSeverity, type FindingType, type HostUserInfo, type IssueCategory, type IssueCounts, LocalStorageAdapter, type MessageSenderType, type MonitorDeps, type MonitoringConfig, type MonitoringEvent, type NetworkRequest, OfflineQueue, type OfflineQueueConfig, type PriorityFactors, type ProjectRole, type QAFinding, type QAHealthMetrics, type QAHealthScore, type QASession, type QASessionStatus, type QASessionType, type QATask, type QATaskPriority, type QATaskStatus, type QATrack, type QueueItem, type QueueItemType, RNApiFailureHandler, RNCrashHandler, RNRageClickHandler, RageClickDetector, type RageClickEvent, type RegressionEvent, type ReportSource, type ReportStatus, type ReportType, type RoutePriority, type RouteTestStats, type RubricMode, type RubricResult, type Severity, type SkipReason, type StartSessionOptions, type StorageAdapter, type SubmitFeedbackOptions, type TestAssignment, type TestFeedback, type TestGroup, type TestResult, type TestStep, type TestTemplate, type TesterInfo, type TesterIssue, type TesterMessage, type TesterProfileUpdate, type TesterThread, type ThreadPriority, type ThreadType, WebApiFailureHandler, WebCrashHandler, WebRageClickHandler, type WidgetColorScheme, type WidgetConfig, captureError, contextCapture, createBugBear, createEmailInterceptor, generateFingerprint, isBugCategory, isNetworkError, scrubUrl };
package/dist/index.d.ts CHANGED
@@ -377,6 +377,8 @@ interface TestAssignment {
377
377
  startedAt?: string;
378
378
  /** Duration in seconds (calculated when completed) */
379
379
  durationSeconds?: number;
380
+ /** Active time in seconds, computed from presence heartbeats */
381
+ activeSeconds?: number;
380
382
  /** Whether this is a verification assignment for a fixed bug */
381
383
  isVerification?: boolean;
382
384
  /** Original report ID if this is a verification assignment */
@@ -690,6 +692,10 @@ interface QASession {
690
692
  track?: string;
691
693
  /** Platform being tested */
692
694
  platform?: string;
695
+ /** Session type: exploratory or ad_hoc */
696
+ sessionType: QASessionType;
697
+ /** Linked task ID (ad hoc sessions) */
698
+ taskId?: string;
693
699
  /** Timing */
694
700
  startedAt: string;
695
701
  endedAt?: string;
@@ -735,11 +741,17 @@ interface QAFinding {
735
741
  createdAt: string;
736
742
  updatedAt: string;
737
743
  }
744
+ /** Session type */
745
+ type QASessionType = 'exploratory' | 'ad_hoc';
738
746
  /** Options for starting a QA session */
739
747
  interface StartSessionOptions {
740
748
  focusArea?: string;
741
749
  track?: string;
742
750
  platform?: string;
751
+ /** Session type: exploratory (default) or ad_hoc */
752
+ sessionType?: QASessionType;
753
+ /** Link to a qa_task (ad hoc mode) */
754
+ taskId?: string;
743
755
  }
744
756
  /** Options for ending a QA session */
745
757
  interface EndSessionOptions {
@@ -759,6 +771,22 @@ interface AddFindingOptions {
759
771
  deviceInfo?: DeviceInfo;
760
772
  appContext?: AppContext;
761
773
  }
774
+ /** QA Task priority */
775
+ type QATaskPriority = 'high' | 'normal' | 'low';
776
+ /** QA Task status */
777
+ type QATaskStatus = 'active' | 'archived';
778
+ /** Lightweight task prompt for ad hoc testing */
779
+ interface QATask {
780
+ id: string;
781
+ projectId: string;
782
+ title: string;
783
+ description?: string;
784
+ trackId?: string;
785
+ priority: QATaskPriority;
786
+ status: QATaskStatus;
787
+ createdAt: string;
788
+ updatedAt: string;
789
+ }
762
790
  /** Category for filtering tester issues in the widget */
763
791
  type IssueCategory = 'open' | 'done' | 'reopened';
764
792
  /** Issue counts for each category (HomeScreen cards) */
@@ -789,6 +817,14 @@ interface TesterIssue {
789
817
  originalBugId?: string;
790
818
  /** Original bug title (for reopened/test_fail issues) */
791
819
  originalBugTitle?: string;
820
+ /** Resolution notes from the developer (for ready_to_test issues) */
821
+ resolutionNotes?: string;
822
+ /** Fix commit SHA (for ready_to_test issues) */
823
+ fixCommitSha?: string;
824
+ /** Fix commit message */
825
+ fixCommitMessage?: string;
826
+ /** Files changed in the fix */
827
+ fixFilesChanged?: string[];
792
828
  }
793
829
  /** Delivery status for captured emails */
794
830
  type EmailDeliveryStatus = 'pending' | 'sent' | 'delivered' | 'bounced' | 'dropped' | 'deferred';
@@ -1560,6 +1596,14 @@ declare class BugBearClient {
1560
1596
  success: boolean;
1561
1597
  error?: string;
1562
1598
  }>;
1599
+ /**
1600
+ * Get active QA tasks for the project
1601
+ */
1602
+ getTasks(status?: string): Promise<QATask[]>;
1603
+ /**
1604
+ * Transform database task to QATask type
1605
+ */
1606
+ private transformTask;
1563
1607
  /**
1564
1608
  * Transform database session to QASession type
1565
1609
  */
@@ -1686,4 +1730,4 @@ interface EmailInterceptor {
1686
1730
  */
1687
1731
  declare function createEmailInterceptor(client: BugBearClient, options?: EmailInterceptorOptions): EmailInterceptor;
1688
1732
 
1689
- export { type AddFindingOptions, type AppContext, BUG_CATEGORIES, BugBearClient, type BugBearConfig, type BugBearMode, type BugBearReport, type BugBearTheme, type BugCategory, type ChecklistItem, type ChecklistResult, type ConsoleLogEntry, type CoverageGap, type CoverageMatrixCell, type CoverageMatrixRow, DedupWindow, type DeployChecklist, type DeviceInfo, type EmailCaptureMode, type EmailCapturePayload, type EmailCaptureResult, type EmailDeliveryStatus, type EmailInterceptorOptions, type EmailPayloadExtractor, type EndSessionOptions, type EnhancedBugContext, ErrorMonitor, type ExtractedEmailPayload, type FindingSeverity, type FindingType, type HostUserInfo, type IssueCategory, type IssueCounts, LocalStorageAdapter, type MessageSenderType, type MonitorDeps, type MonitoringConfig, type MonitoringEvent, type NetworkRequest, OfflineQueue, type OfflineQueueConfig, type PriorityFactors, type ProjectRole, type QAFinding, type QAHealthMetrics, type QAHealthScore, type QASession, type QASessionStatus, type QATrack, type QueueItem, type QueueItemType, RNApiFailureHandler, RNCrashHandler, RNRageClickHandler, RageClickDetector, type RageClickEvent, type RegressionEvent, type ReportSource, type ReportStatus, type ReportType, type RoutePriority, type RouteTestStats, type RubricMode, type RubricResult, type Severity, type SkipReason, type StartSessionOptions, type StorageAdapter, type SubmitFeedbackOptions, type TestAssignment, type TestFeedback, type TestGroup, type TestResult, type TestStep, type TestTemplate, type TesterInfo, type TesterIssue, type TesterMessage, type TesterProfileUpdate, type TesterThread, type ThreadPriority, type ThreadType, WebApiFailureHandler, WebCrashHandler, WebRageClickHandler, type WidgetColorScheme, type WidgetConfig, captureError, contextCapture, createBugBear, createEmailInterceptor, generateFingerprint, isBugCategory, isNetworkError, scrubUrl };
1733
+ export { type AddFindingOptions, type AppContext, BUG_CATEGORIES, BugBearClient, type BugBearConfig, type BugBearMode, type BugBearReport, type BugBearTheme, type BugCategory, type ChecklistItem, type ChecklistResult, type ConsoleLogEntry, type CoverageGap, type CoverageMatrixCell, type CoverageMatrixRow, DedupWindow, type DeployChecklist, type DeviceInfo, type EmailCaptureMode, type EmailCapturePayload, type EmailCaptureResult, type EmailDeliveryStatus, type EmailInterceptorOptions, type EmailPayloadExtractor, type EndSessionOptions, type EnhancedBugContext, ErrorMonitor, type ExtractedEmailPayload, type FindingSeverity, type FindingType, type HostUserInfo, type IssueCategory, type IssueCounts, LocalStorageAdapter, type MessageSenderType, type MonitorDeps, type MonitoringConfig, type MonitoringEvent, type NetworkRequest, OfflineQueue, type OfflineQueueConfig, type PriorityFactors, type ProjectRole, type QAFinding, type QAHealthMetrics, type QAHealthScore, type QASession, type QASessionStatus, type QASessionType, type QATask, type QATaskPriority, type QATaskStatus, type QATrack, type QueueItem, type QueueItemType, RNApiFailureHandler, RNCrashHandler, RNRageClickHandler, RageClickDetector, type RageClickEvent, type RegressionEvent, type ReportSource, type ReportStatus, type ReportType, type RoutePriority, type RouteTestStats, type RubricMode, type RubricResult, type Severity, type SkipReason, type StartSessionOptions, type StorageAdapter, type SubmitFeedbackOptions, type TestAssignment, type TestFeedback, type TestGroup, type TestResult, type TestStep, type TestTemplate, type TesterInfo, type TesterIssue, type TesterMessage, type TesterProfileUpdate, type TesterThread, type ThreadPriority, type ThreadType, WebApiFailureHandler, WebCrashHandler, WebRageClickHandler, type WidgetColorScheme, type WidgetConfig, captureError, contextCapture, createBugBear, createEmailInterceptor, generateFingerprint, isBugCategory, isNetworkError, scrubUrl };
package/dist/index.js CHANGED
@@ -1475,55 +1475,66 @@ var BugBearClient = class {
1475
1475
  ...pendingResult.data || [],
1476
1476
  ...completedResult.data || []
1477
1477
  ];
1478
- const mapItem = (item) => ({
1479
- id: item.id,
1480
- status: item.status,
1481
- startedAt: item.started_at,
1482
- skipReason: item.skip_reason,
1483
- isVerification: item.is_verification || false,
1484
- originalReportId: item.original_report_id,
1485
- testCase: {
1486
- id: item.test_case.id,
1487
- title: item.test_case.title,
1488
- testKey: item.test_case.test_key,
1489
- description: item.test_case.description,
1490
- steps: item.test_case.steps,
1491
- expectedResult: item.test_case.expected_result,
1492
- priority: item.test_case.priority,
1493
- targetRoute: item.test_case.target_route,
1494
- track: item.test_case.track ? {
1495
- id: item.test_case.track.id,
1496
- name: item.test_case.track.name,
1497
- icon: item.test_case.track.icon,
1498
- color: item.test_case.track.color,
1499
- testTemplate: item.test_case.track.test_template,
1500
- rubricMode: item.test_case.track.rubric_mode || "pass_fail",
1501
- description: item.test_case.track.description
1502
- } : void 0,
1503
- group: item.test_case.group ? {
1504
- id: item.test_case.group.id,
1505
- name: item.test_case.group.name,
1506
- description: item.test_case.group.description,
1507
- sortOrder: item.test_case.group.sort_order
1508
- } : void 0,
1509
- role: item.test_case.role ? {
1510
- id: item.test_case.role.id,
1511
- name: item.test_case.role.name,
1512
- slug: item.test_case.role.slug,
1513
- color: item.test_case.role.color,
1514
- description: item.test_case.role.description,
1515
- loginHint: item.test_case.role.login_hint
1516
- } : void 0,
1517
- platforms: item.test_case.platforms || void 0
1518
- }
1519
- });
1520
- const mapped = allData.filter((item) => {
1521
- if (!item.test_case) {
1522
- console.warn("BugBear: Assignment returned without test_case", { id: item.id });
1523
- return false;
1524
- }
1525
- return true;
1526
- }).map(mapItem);
1478
+ const mapItem = (item) => {
1479
+ const tc = item.test_case;
1480
+ return {
1481
+ id: item.id,
1482
+ status: item.status,
1483
+ startedAt: item.started_at,
1484
+ skipReason: item.skip_reason,
1485
+ isVerification: item.is_verification || false,
1486
+ originalReportId: item.original_report_id,
1487
+ testCase: tc ? {
1488
+ id: tc.id,
1489
+ title: tc.title,
1490
+ testKey: tc.test_key,
1491
+ description: tc.description,
1492
+ steps: tc.steps,
1493
+ expectedResult: tc.expected_result,
1494
+ priority: tc.priority,
1495
+ targetRoute: tc.target_route,
1496
+ track: tc.track ? {
1497
+ id: tc.track.id,
1498
+ name: tc.track.name,
1499
+ icon: tc.track.icon,
1500
+ color: tc.track.color,
1501
+ testTemplate: tc.track.test_template,
1502
+ rubricMode: tc.track.rubric_mode || "pass_fail",
1503
+ description: tc.track.description
1504
+ } : void 0,
1505
+ group: tc.group ? {
1506
+ id: tc.group.id,
1507
+ name: tc.group.name,
1508
+ description: tc.group.description,
1509
+ sortOrder: tc.group.sort_order
1510
+ } : void 0,
1511
+ role: tc.role ? {
1512
+ id: tc.role.id,
1513
+ name: tc.role.name,
1514
+ slug: tc.role.slug,
1515
+ color: tc.role.color,
1516
+ description: tc.role.description,
1517
+ loginHint: tc.role.login_hint
1518
+ } : void 0,
1519
+ platforms: tc.platforms || void 0
1520
+ } : {
1521
+ // Standalone verification assignment (bug reported without a test case)
1522
+ id: item.original_report_id || item.id,
1523
+ title: item.notes || "Bug Verification",
1524
+ testKey: "VERIFY",
1525
+ description: "Verify that the reported bug has been fixed",
1526
+ steps: [],
1527
+ expectedResult: "The bug should no longer be reproducible",
1528
+ priority: "P1",
1529
+ targetRoute: void 0,
1530
+ track: void 0,
1531
+ group: void 0,
1532
+ role: void 0,
1533
+ platforms: void 0
1534
+ }
1535
+ };
1536
+ };
1537
+ const mapped = allData.map(mapItem);
1527
1538
  mapped.sort((a, b) => {
1528
1539
  if (a.isVerification && !b.isVerification) return -1;
1529
1540
  if (!a.isVerification && b.isVerification) return 1;
@@ -1617,7 +1628,7 @@ var BugBearClient = class {
1617
1628
  async updateAssignmentStatus(assignmentId, status, options) {
1618
1629
  try {
1619
1630
  await this.ensureReady();
1620
- const { data: currentAssignment, error: fetchError } = await this.supabase.from("test_assignments").select("status, started_at").eq("id", assignmentId).single();
1631
+ const { data: currentAssignment, error: fetchError } = await this.supabase.from("test_assignments").select("status, started_at, tester_id, project_id").eq("id", assignmentId).single();
1621
1632
  if (fetchError || !currentAssignment) {
1622
1633
  console.error("BugBear: Assignment not found", {
1623
1634
  message: fetchError?.message,
@@ -1638,6 +1649,19 @@ var BugBearClient = class {
1638
1649
  const completedAt = /* @__PURE__ */ new Date();
1639
1650
  durationSeconds = Math.round((completedAt.getTime() - startedAt.getTime()) / 1e3);
1640
1651
  updateData.duration_seconds = durationSeconds;
1652
+ if (currentAssignment.tester_id && currentAssignment.project_id) {
1653
+ try {
1654
+ const { data: activeTime } = await this.supabase.rpc("compute_assignment_active_time", {
1655
+ p_tester_id: currentAssignment.tester_id,
1656
+ p_project_id: currentAssignment.project_id,
1657
+ p_started_at: currentAssignment.started_at,
1658
+ p_completed_at: updateData.completed_at
1659
+ });
1660
+ updateData.active_seconds = typeof activeTime === "number" ? activeTime : Math.min(durationSeconds, 1800);
1661
+ } catch {
1662
+ updateData.active_seconds = Math.min(durationSeconds, 1800);
1663
+ }
1664
+ }
1641
1665
  }
1642
1666
  }
1643
1667
  if (options?.notes) {
@@ -1716,6 +1740,7 @@ var BugBearClient = class {
1716
1740
  started_at: (/* @__PURE__ */ new Date()).toISOString(),
1717
1741
  completed_at: null,
1718
1742
  duration_seconds: null,
1743
+ active_seconds: null,
1719
1744
  skip_reason: null
1720
1745
  }).eq("id", assignmentId).eq("status", current.status);
1721
1746
  if (error) {
@@ -2023,7 +2048,11 @@ var BugBearClient = class {
2023
2048
  verifiedByName: row.verified_by_name || void 0,
2024
2049
  verifiedAt: row.verified_at || void 0,
2025
2050
  originalBugId: row.original_bug_id || void 0,
2026
- originalBugTitle: row.original_bug_title || void 0
2051
+ originalBugTitle: row.original_bug_title || void 0,
2052
+ resolutionNotes: row.resolution_notes || void 0,
2053
+ fixCommitSha: row.code_context?.fix?.commit_sha || void 0,
2054
+ fixCommitMessage: row.code_context?.fix?.commit_message || void 0,
2055
+ fixFilesChanged: row.code_context?.fix?.files_changed || void 0
2027
2056
  }));
2028
2057
  } catch (err) {
2029
2058
  console.error("BugBear: Error fetching issues", err);
@@ -2771,7 +2800,9 @@ var BugBearClient = class {
2771
2800
  p_tester_id: testerInfo.id,
2772
2801
  p_focus_area: options.focusArea || null,
2773
2802
  p_track: options.track || null,
2774
- p_platform: options.platform || null
2803
+ p_platform: options.platform || null,
2804
+ p_session_type: options.sessionType || "exploratory",
2805
+ p_task_id: options.taskId || null
2775
2806
  });
2776
2807
  if (error) {
2777
2808
  console.error("BugBear: Failed to start session", formatPgError(error));
@@ -2955,6 +2986,45 @@ var BugBearClient = class {
2955
2986
  return { success: false, error: message };
2956
2987
  }
2957
2988
  }
2989
+ // ============================================
2990
+ // QA Tasks (Ad Hoc Testing)
2991
+ // ============================================
2992
+ /**
2993
+ * Get active QA tasks for the project
2994
+ */
2995
+ async getTasks(status = "active") {
2996
+ try {
2997
+ await this.ensureReady();
2998
+ const { data, error } = await this.supabase.rpc("list_qa_tasks", {
2999
+ p_project_id: this.config.projectId,
3000
+ p_status: status
3001
+ });
3002
+ if (error) {
3003
+ console.error("BugBear: Failed to fetch tasks", formatPgError(error));
3004
+ return [];
3005
+ }
3006
+ return (data || []).map((t) => this.transformTask(t));
3007
+ } catch (err) {
3008
+ console.error("BugBear: Error fetching tasks", err);
3009
+ return [];
3010
+ }
3011
+ }
3012
+ /**
3013
+ * Transform database task to QATask type
3014
+ */
3015
+ transformTask(data) {
3016
+ return {
3017
+ id: data.id,
3018
+ projectId: data.project_id,
3019
+ title: data.title,
3020
+ description: data.description || void 0,
3021
+ trackId: data.track_id || void 0,
3022
+ priority: data.priority,
3023
+ status: data.status,
3024
+ createdAt: data.created_at,
3025
+ updatedAt: data.updated_at
3026
+ };
3027
+ }
2958
3028
  /**
2959
3029
  * Transform database session to QASession type
2960
3030
  */
@@ -2966,6 +3036,8 @@ var BugBearClient = class {
2966
3036
  focusArea: data.focus_area,
2967
3037
  track: data.track,
2968
3038
  platform: data.platform,
3039
+ sessionType: data.session_type || "exploratory",
3040
+ taskId: data.task_id || void 0,
2969
3041
  startedAt: data.started_at,
2970
3042
  endedAt: data.ended_at,
2971
3043
  notes: data.notes,
package/dist/index.mjs CHANGED
@@ -1429,55 +1429,66 @@ var BugBearClient = class {
1429
1429
  ...pendingResult.data || [],
1430
1430
  ...completedResult.data || []
1431
1431
  ];
1432
- const mapItem = (item) => ({
1433
- id: item.id,
1434
- status: item.status,
1435
- startedAt: item.started_at,
1436
- skipReason: item.skip_reason,
1437
- isVerification: item.is_verification || false,
1438
- originalReportId: item.original_report_id,
1439
- testCase: {
1440
- id: item.test_case.id,
1441
- title: item.test_case.title,
1442
- testKey: item.test_case.test_key,
1443
- description: item.test_case.description,
1444
- steps: item.test_case.steps,
1445
- expectedResult: item.test_case.expected_result,
1446
- priority: item.test_case.priority,
1447
- targetRoute: item.test_case.target_route,
1448
- track: item.test_case.track ? {
1449
- id: item.test_case.track.id,
1450
- name: item.test_case.track.name,
1451
- icon: item.test_case.track.icon,
1452
- color: item.test_case.track.color,
1453
- testTemplate: item.test_case.track.test_template,
1454
- rubricMode: item.test_case.track.rubric_mode || "pass_fail",
1455
- description: item.test_case.track.description
1456
- } : void 0,
1457
- group: item.test_case.group ? {
1458
- id: item.test_case.group.id,
1459
- name: item.test_case.group.name,
1460
- description: item.test_case.group.description,
1461
- sortOrder: item.test_case.group.sort_order
1462
- } : void 0,
1463
- role: item.test_case.role ? {
1464
- id: item.test_case.role.id,
1465
- name: item.test_case.role.name,
1466
- slug: item.test_case.role.slug,
1467
- color: item.test_case.role.color,
1468
- description: item.test_case.role.description,
1469
- loginHint: item.test_case.role.login_hint
1470
- } : void 0,
1471
- platforms: item.test_case.platforms || void 0
1472
- }
1473
- });
1474
- const mapped = allData.filter((item) => {
1475
- if (!item.test_case) {
1476
- console.warn("BugBear: Assignment returned without test_case", { id: item.id });
1477
- return false;
1478
- }
1479
- return true;
1480
- }).map(mapItem);
1432
+ const mapItem = (item) => {
1433
+ const tc = item.test_case;
1434
+ return {
1435
+ id: item.id,
1436
+ status: item.status,
1437
+ startedAt: item.started_at,
1438
+ skipReason: item.skip_reason,
1439
+ isVerification: item.is_verification || false,
1440
+ originalReportId: item.original_report_id,
1441
+ testCase: tc ? {
1442
+ id: tc.id,
1443
+ title: tc.title,
1444
+ testKey: tc.test_key,
1445
+ description: tc.description,
1446
+ steps: tc.steps,
1447
+ expectedResult: tc.expected_result,
1448
+ priority: tc.priority,
1449
+ targetRoute: tc.target_route,
1450
+ track: tc.track ? {
1451
+ id: tc.track.id,
1452
+ name: tc.track.name,
1453
+ icon: tc.track.icon,
1454
+ color: tc.track.color,
1455
+ testTemplate: tc.track.test_template,
1456
+ rubricMode: tc.track.rubric_mode || "pass_fail",
1457
+ description: tc.track.description
1458
+ } : void 0,
1459
+ group: tc.group ? {
1460
+ id: tc.group.id,
1461
+ name: tc.group.name,
1462
+ description: tc.group.description,
1463
+ sortOrder: tc.group.sort_order
1464
+ } : void 0,
1465
+ role: tc.role ? {
1466
+ id: tc.role.id,
1467
+ name: tc.role.name,
1468
+ slug: tc.role.slug,
1469
+ color: tc.role.color,
1470
+ description: tc.role.description,
1471
+ loginHint: tc.role.login_hint
1472
+ } : void 0,
1473
+ platforms: tc.platforms || void 0
1474
+ } : {
1475
+ // Standalone verification assignment (bug reported without a test case)
1476
+ id: item.original_report_id || item.id,
1477
+ title: item.notes || "Bug Verification",
1478
+ testKey: "VERIFY",
1479
+ description: "Verify that the reported bug has been fixed",
1480
+ steps: [],
1481
+ expectedResult: "The bug should no longer be reproducible",
1482
+ priority: "P1",
1483
+ targetRoute: void 0,
1484
+ track: void 0,
1485
+ group: void 0,
1486
+ role: void 0,
1487
+ platforms: void 0
1488
+ }
1489
+ };
1490
+ };
1491
+ const mapped = allData.map(mapItem);
1481
1492
  mapped.sort((a, b) => {
1482
1493
  if (a.isVerification && !b.isVerification) return -1;
1483
1494
  if (!a.isVerification && b.isVerification) return 1;
@@ -1571,7 +1582,7 @@ var BugBearClient = class {
1571
1582
  async updateAssignmentStatus(assignmentId, status, options) {
1572
1583
  try {
1573
1584
  await this.ensureReady();
1574
- const { data: currentAssignment, error: fetchError } = await this.supabase.from("test_assignments").select("status, started_at").eq("id", assignmentId).single();
1585
+ const { data: currentAssignment, error: fetchError } = await this.supabase.from("test_assignments").select("status, started_at, tester_id, project_id").eq("id", assignmentId).single();
1575
1586
  if (fetchError || !currentAssignment) {
1576
1587
  console.error("BugBear: Assignment not found", {
1577
1588
  message: fetchError?.message,
@@ -1592,6 +1603,19 @@ var BugBearClient = class {
1592
1603
  const completedAt = /* @__PURE__ */ new Date();
1593
1604
  durationSeconds = Math.round((completedAt.getTime() - startedAt.getTime()) / 1e3);
1594
1605
  updateData.duration_seconds = durationSeconds;
1606
+ if (currentAssignment.tester_id && currentAssignment.project_id) {
1607
+ try {
1608
+ const { data: activeTime } = await this.supabase.rpc("compute_assignment_active_time", {
1609
+ p_tester_id: currentAssignment.tester_id,
1610
+ p_project_id: currentAssignment.project_id,
1611
+ p_started_at: currentAssignment.started_at,
1612
+ p_completed_at: updateData.completed_at
1613
+ });
1614
+ updateData.active_seconds = typeof activeTime === "number" ? activeTime : Math.min(durationSeconds, 1800);
1615
+ } catch {
1616
+ updateData.active_seconds = Math.min(durationSeconds, 1800);
1617
+ }
1618
+ }
1595
1619
  }
1596
1620
  }
1597
1621
  if (options?.notes) {
@@ -1670,6 +1694,7 @@ var BugBearClient = class {
1670
1694
  started_at: (/* @__PURE__ */ new Date()).toISOString(),
1671
1695
  completed_at: null,
1672
1696
  duration_seconds: null,
1697
+ active_seconds: null,
1673
1698
  skip_reason: null
1674
1699
  }).eq("id", assignmentId).eq("status", current.status);
1675
1700
  if (error) {
@@ -1977,7 +2002,11 @@ var BugBearClient = class {
1977
2002
  verifiedByName: row.verified_by_name || void 0,
1978
2003
  verifiedAt: row.verified_at || void 0,
1979
2004
  originalBugId: row.original_bug_id || void 0,
1980
- originalBugTitle: row.original_bug_title || void 0
2005
+ originalBugTitle: row.original_bug_title || void 0,
2006
+ resolutionNotes: row.resolution_notes || void 0,
2007
+ fixCommitSha: row.code_context?.fix?.commit_sha || void 0,
2008
+ fixCommitMessage: row.code_context?.fix?.commit_message || void 0,
2009
+ fixFilesChanged: row.code_context?.fix?.files_changed || void 0
1981
2010
  }));
1982
2011
  } catch (err) {
1983
2012
  console.error("BugBear: Error fetching issues", err);
@@ -2725,7 +2754,9 @@ var BugBearClient = class {
2725
2754
  p_tester_id: testerInfo.id,
2726
2755
  p_focus_area: options.focusArea || null,
2727
2756
  p_track: options.track || null,
2728
- p_platform: options.platform || null
2757
+ p_platform: options.platform || null,
2758
+ p_session_type: options.sessionType || "exploratory",
2759
+ p_task_id: options.taskId || null
2729
2760
  });
2730
2761
  if (error) {
2731
2762
  console.error("BugBear: Failed to start session", formatPgError(error));
@@ -2909,6 +2940,45 @@ var BugBearClient = class {
2909
2940
  return { success: false, error: message };
2910
2941
  }
2911
2942
  }
2943
+ // ============================================
2944
+ // QA Tasks (Ad Hoc Testing)
2945
+ // ============================================
2946
+ /**
2947
+ * Get active QA tasks for the project
2948
+ */
2949
+ async getTasks(status = "active") {
2950
+ try {
2951
+ await this.ensureReady();
2952
+ const { data, error } = await this.supabase.rpc("list_qa_tasks", {
2953
+ p_project_id: this.config.projectId,
2954
+ p_status: status
2955
+ });
2956
+ if (error) {
2957
+ console.error("BugBear: Failed to fetch tasks", formatPgError(error));
2958
+ return [];
2959
+ }
2960
+ return (data || []).map((t) => this.transformTask(t));
2961
+ } catch (err) {
2962
+ console.error("BugBear: Error fetching tasks", err);
2963
+ return [];
2964
+ }
2965
+ }
2966
+ /**
2967
+ * Transform database task to QATask type
2968
+ */
2969
+ transformTask(data) {
2970
+ return {
2971
+ id: data.id,
2972
+ projectId: data.project_id,
2973
+ title: data.title,
2974
+ description: data.description || void 0,
2975
+ trackId: data.track_id || void 0,
2976
+ priority: data.priority,
2977
+ status: data.status,
2978
+ createdAt: data.created_at,
2979
+ updatedAt: data.updated_at
2980
+ };
2981
+ }
2912
2982
  /**
2913
2983
  * Transform database session to QASession type
2914
2984
  */
@@ -2920,6 +2990,8 @@ var BugBearClient = class {
2920
2990
  focusArea: data.focus_area,
2921
2991
  track: data.track,
2922
2992
  platform: data.platform,
2993
+ sessionType: data.session_type || "exploratory",
2994
+ taskId: data.task_id || void 0,
2923
2995
  startedAt: data.started_at,
2924
2996
  endedAt: data.ended_at,
2925
2997
  notes: data.notes,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bbearai/core",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Core utilities and types for BugBear QA platform",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",