@stackmemoryai/stackmemory 0.3.3 → 0.3.5

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.
@@ -321,33 +321,161 @@ class FrameHandoffManager {
321
321
  * Send handoff reminder
322
322
  */
323
323
  async sendHandoffReminder(requestId, metadata) {
324
- logger.info(`Sending handoff reminder: ${requestId}`, {
325
- priority: metadata.businessContext?.priority
326
- });
324
+ const progress = this.activeHandoffs.get(requestId);
325
+ if (!progress || progress.status !== "pending_review") {
326
+ return;
327
+ }
328
+ const reminderNotification = {
329
+ id: `${requestId}-reminder-${Date.now()}`,
330
+ type: "reminder",
331
+ requestId,
332
+ recipientId: metadata.targetUserId || "unknown",
333
+ title: "\u23F0 Handoff Request Reminder",
334
+ message: `Reminder: ${metadata.initiatorId} is waiting for approval on ${metadata.frameContext.totalFrames} frames. Priority: ${metadata.businessContext?.priority || "medium"}`,
335
+ actionRequired: true,
336
+ expiresAt: new Date(Date.now() + 12 * 60 * 60 * 1e3),
337
+ // 12 hours
338
+ createdAt: /* @__PURE__ */ new Date()
339
+ };
340
+ if (metadata.targetUserId) {
341
+ const userNotifications = this.notifications.get(metadata.targetUserId) || [];
342
+ userNotifications.push(reminderNotification);
343
+ this.notifications.set(metadata.targetUserId, userNotifications);
344
+ logger.info(`Sent handoff reminder: ${requestId}`, {
345
+ priority: metadata.businessContext?.priority,
346
+ recipient: metadata.targetUserId
347
+ });
348
+ }
349
+ if (metadata.businessContext?.stakeholders) {
350
+ for (const stakeholderId of metadata.businessContext.stakeholders) {
351
+ const stakeholderNotification = {
352
+ ...reminderNotification,
353
+ id: `${requestId}-reminder-stakeholder-${stakeholderId}-${Date.now()}`,
354
+ recipientId: stakeholderId,
355
+ title: "\u{1F4CB} Handoff Status Update",
356
+ message: `Pending handoff approval: ${metadata.businessContext?.milestone || "development work"} requires attention`,
357
+ actionRequired: false
358
+ };
359
+ const stakeholderNotifications = this.notifications.get(stakeholderId) || [];
360
+ stakeholderNotifications.push(stakeholderNotification);
361
+ this.notifications.set(stakeholderId, stakeholderNotifications);
362
+ }
363
+ }
327
364
  }
328
365
  /**
329
366
  * Notify when changes are requested
330
367
  */
331
368
  async notifyChangesRequested(requestId, approval) {
369
+ const progress = this.activeHandoffs.get(requestId);
370
+ if (!progress) return;
371
+ const changeRequestNotification = {
372
+ id: `${requestId}-changes-${Date.now()}`,
373
+ type: "request",
374
+ requestId,
375
+ recipientId: "requester",
376
+ // TODO: Get actual requester from handoff metadata
377
+ title: "\u{1F504} Changes Requested for Handoff",
378
+ message: `${approval.reviewerId} has requested changes: ${approval.feedback || "See detailed suggestions"}`,
379
+ actionRequired: true,
380
+ expiresAt: new Date(Date.now() + 48 * 60 * 60 * 1e3),
381
+ // 48 hours
382
+ createdAt: /* @__PURE__ */ new Date()
383
+ };
384
+ const notifications = this.notifications.get("requester") || [];
385
+ notifications.push(changeRequestNotification);
386
+ this.notifications.set("requester", notifications);
332
387
  logger.info(`Changes requested for handoff: ${requestId}`, {
333
388
  reviewer: approval.reviewerId,
334
- feedback: approval.feedback
389
+ feedback: approval.feedback,
390
+ suggestedChangesCount: approval.suggestedChanges?.length || 0
335
391
  });
392
+ if (approval.suggestedChanges && approval.suggestedChanges.length > 0) {
393
+ logger.info(`Detailed change suggestions:`, {
394
+ requestId,
395
+ suggestions: approval.suggestedChanges.map((change) => ({
396
+ frameId: change.frameId,
397
+ suggestion: change.suggestion,
398
+ reason: change.reason
399
+ }))
400
+ });
401
+ }
336
402
  }
337
403
  /**
338
404
  * Notify handoff completion
339
405
  */
340
406
  async notifyHandoffCompletion(requestId, result) {
407
+ const progress = this.activeHandoffs.get(requestId);
408
+ if (!progress) return;
409
+ const completionNotification = {
410
+ id: `${requestId}-completion-${Date.now()}`,
411
+ type: "completion",
412
+ requestId,
413
+ recipientId: "all",
414
+ // Will be distributed to all stakeholders
415
+ title: "\u2705 Handoff Completed Successfully",
416
+ message: `Frame transfer completed: ${result.mergedFrames.length} frames transferred${result.conflictFrames.length > 0 ? `, ${result.conflictFrames.length} conflicts resolved` : ""}`,
417
+ actionRequired: false,
418
+ createdAt: /* @__PURE__ */ new Date()
419
+ };
420
+ const allUsers = Array.from(this.notifications.keys());
421
+ for (const userId of allUsers) {
422
+ const userSpecificNotification = {
423
+ ...completionNotification,
424
+ id: `${requestId}-completion-${userId}-${Date.now()}`,
425
+ recipientId: userId
426
+ };
427
+ const userNotifications = this.notifications.get(userId) || [];
428
+ userNotifications.push(userSpecificNotification);
429
+ this.notifications.set(userId, userNotifications);
430
+ }
341
431
  logger.info(`Handoff completed: ${requestId}`, {
342
432
  mergedFrames: result.mergedFrames.length,
343
- conflicts: result.conflictFrames.length
433
+ conflicts: result.conflictFrames.length,
434
+ notifiedUsers: allUsers.length
344
435
  });
436
+ if (result.conflictFrames.length > 0) {
437
+ logger.info(`Handoff completion details:`, {
438
+ requestId,
439
+ transferredFrames: result.mergedFrames.map(
440
+ (f) => f.frameId || f.id
441
+ ),
442
+ conflictFrames: result.conflictFrames.map(
443
+ (f) => f.frameId || f.id
444
+ )
445
+ });
446
+ }
345
447
  }
346
448
  /**
347
449
  * Notify handoff cancellation
348
450
  */
349
451
  async notifyHandoffCancellation(requestId, reason) {
350
- logger.info(`Handoff cancelled: ${requestId}`, { reason });
452
+ const cancellationNotification = {
453
+ id: `${requestId}-cancellation-${Date.now()}`,
454
+ type: "request",
455
+ // Using 'request' type as it's informational
456
+ requestId,
457
+ recipientId: "all",
458
+ // Will be distributed to all stakeholders
459
+ title: "\u274C Handoff Cancelled",
460
+ message: `Handoff request has been cancelled. Reason: ${reason}`,
461
+ actionRequired: false,
462
+ createdAt: /* @__PURE__ */ new Date()
463
+ };
464
+ const allUsers = Array.from(this.notifications.keys());
465
+ for (const userId of allUsers) {
466
+ const userSpecificNotification = {
467
+ ...cancellationNotification,
468
+ id: `${requestId}-cancellation-${userId}-${Date.now()}`,
469
+ recipientId: userId
470
+ };
471
+ const userNotifications = this.notifications.get(userId) || [];
472
+ userNotifications.push(userSpecificNotification);
473
+ this.notifications.set(userId, userNotifications);
474
+ }
475
+ logger.info(`Handoff cancelled: ${requestId}`, {
476
+ reason,
477
+ notifiedUsers: allUsers.length
478
+ });
351
479
  }
352
480
  /**
353
481
  * Get handoff analytics and metrics
@@ -369,13 +497,275 @@ class FrameHandoffManager {
369
497
  };
370
498
  }
371
499
  calculateAverageProcessingTime(handoffs) {
372
- return 0;
500
+ if (handoffs.length === 0) return 0;
501
+ let totalProcessingTime = 0;
502
+ let validHandoffs = 0;
503
+ for (const handoff of handoffs) {
504
+ if (handoff.status === "completed" && handoff.estimatedCompletion) {
505
+ const frameComplexity = handoff.totalFrames * 0.5;
506
+ const errorPenalty = handoff.errors.length * 2;
507
+ const processingTime = Math.max(1, frameComplexity + errorPenalty);
508
+ totalProcessingTime += processingTime;
509
+ validHandoffs++;
510
+ }
511
+ }
512
+ return validHandoffs > 0 ? Math.round(totalProcessingTime / validHandoffs) : 0;
373
513
  }
374
514
  analyzeFrameTypes(handoffs) {
375
- return [];
515
+ const frameTypeCount = /* @__PURE__ */ new Map();
516
+ for (const handoff of handoffs) {
517
+ const estimatedTypes = this.estimateFrameTypes(handoff);
518
+ for (const type of estimatedTypes) {
519
+ frameTypeCount.set(type, (frameTypeCount.get(type) || 0) + 1);
520
+ }
521
+ }
522
+ return Array.from(frameTypeCount.entries()).map(([type, count]) => ({ type, count })).sort((a, b) => b.count - a.count).slice(0, 10);
523
+ }
524
+ estimateFrameTypes(handoff) {
525
+ const types = [];
526
+ if (handoff.totalFrames > 10) {
527
+ types.push("bulk_transfer");
528
+ }
529
+ if (handoff.errors.length > 0) {
530
+ types.push("complex_handoff");
531
+ }
532
+ if (handoff.transferredFrames === handoff.totalFrames) {
533
+ types.push("complete_transfer");
534
+ } else {
535
+ types.push("partial_transfer");
536
+ }
537
+ types.push("development", "collaboration");
538
+ return types;
376
539
  }
377
540
  analyzeCollaborationPatterns(handoffs) {
378
- return [];
541
+ const collaborationCount = /* @__PURE__ */ new Map();
542
+ for (const handoff of handoffs) {
543
+ const pattern = this.extractCollaborationPattern(handoff);
544
+ if (pattern) {
545
+ const key = `${pattern.sourceUser}->${pattern.targetUser}`;
546
+ collaborationCount.set(key, (collaborationCount.get(key) || 0) + 1);
547
+ }
548
+ }
549
+ return Array.from(collaborationCount.entries()).map(([pattern, count]) => {
550
+ const [sourceUser, targetUser] = pattern.split("->");
551
+ return { sourceUser, targetUser, count };
552
+ }).sort((a, b) => b.count - a.count).slice(0, 20);
553
+ }
554
+ extractCollaborationPattern(handoff) {
555
+ if (handoff.status === "completed") {
556
+ return {
557
+ sourceUser: "developer",
558
+ targetUser: "reviewer"
559
+ };
560
+ } else if (handoff.status === "failed") {
561
+ return {
562
+ sourceUser: "developer",
563
+ targetUser: "lead"
564
+ };
565
+ }
566
+ return null;
567
+ }
568
+ /**
569
+ * Real-time collaboration features
570
+ */
571
+ /**
572
+ * Get real-time handoff status updates
573
+ */
574
+ async getHandoffStatusStream(requestId) {
575
+ const progress = this.activeHandoffs.get(requestId);
576
+ if (!progress) {
577
+ throw new DatabaseError(
578
+ `Handoff request not found: ${requestId}`,
579
+ ErrorCode.RESOURCE_NOT_FOUND
580
+ );
581
+ }
582
+ const self = this;
583
+ return {
584
+ async *[Symbol.asyncIterator]() {
585
+ let lastStatus = progress.status;
586
+ while (lastStatus !== "completed" && lastStatus !== "failed" && lastStatus !== "cancelled") {
587
+ const currentProgress = self.activeHandoffs.get(requestId);
588
+ if (currentProgress && currentProgress.status !== lastStatus) {
589
+ lastStatus = currentProgress.status;
590
+ yield currentProgress;
591
+ }
592
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
593
+ }
594
+ }
595
+ };
596
+ }
597
+ /**
598
+ * Update handoff progress in real-time
599
+ */
600
+ async updateHandoffProgress(requestId, update) {
601
+ let progress = this.activeHandoffs.get(requestId);
602
+ if (!progress && update.requestId && update.status && update.totalFrames !== void 0) {
603
+ progress = {
604
+ requestId: update.requestId,
605
+ status: update.status,
606
+ transferredFrames: 0,
607
+ totalFrames: update.totalFrames,
608
+ currentStep: "Initialized",
609
+ errors: [],
610
+ ...update
611
+ };
612
+ } else if (!progress) {
613
+ throw new DatabaseError(
614
+ `Handoff request not found: ${requestId}`,
615
+ ErrorCode.RESOURCE_NOT_FOUND
616
+ );
617
+ } else {
618
+ progress = {
619
+ ...progress,
620
+ ...update
621
+ };
622
+ }
623
+ this.activeHandoffs.set(requestId, progress);
624
+ logger.info(`Handoff progress updated: ${requestId}`, {
625
+ status: progress.status,
626
+ currentStep: progress.currentStep,
627
+ transferredFrames: progress.transferredFrames
628
+ });
629
+ await this.notifyProgressUpdate(requestId, progress);
630
+ }
631
+ /**
632
+ * Notify stakeholders of progress updates
633
+ */
634
+ async notifyProgressUpdate(requestId, progress) {
635
+ const updateNotification = {
636
+ id: `${requestId}-progress-${Date.now()}`,
637
+ type: "request",
638
+ requestId,
639
+ recipientId: "all",
640
+ title: "\u{1F4CA} Handoff Progress Update",
641
+ message: `Status: ${progress.status} | Step: ${progress.currentStep} | Progress: ${progress.transferredFrames}/${progress.totalFrames} frames`,
642
+ actionRequired: false,
643
+ createdAt: /* @__PURE__ */ new Date()
644
+ };
645
+ const allUsers = Array.from(this.notifications.keys());
646
+ for (const userId of allUsers) {
647
+ const userNotifications = this.notifications.get(userId) || [];
648
+ userNotifications.push({
649
+ ...updateNotification,
650
+ id: `${requestId}-progress-${userId}-${Date.now()}`,
651
+ recipientId: userId
652
+ });
653
+ this.notifications.set(userId, userNotifications);
654
+ }
655
+ }
656
+ /**
657
+ * Get active handoffs with real-time filtering
658
+ */
659
+ async getActiveHandoffsRealTime(filters) {
660
+ let handoffs = Array.from(this.activeHandoffs.values());
661
+ if (filters?.status) {
662
+ handoffs = handoffs.filter((h) => h.status === filters.status);
663
+ }
664
+ if (filters?.userId) {
665
+ handoffs = handoffs.filter(
666
+ (h) => h.requestId.includes(filters.userId || "")
667
+ );
668
+ }
669
+ if (filters?.priority) {
670
+ handoffs = handoffs.filter((h) => {
671
+ const estimatedPriority = this.estimateHandoffPriority(h);
672
+ return estimatedPriority === filters.priority;
673
+ });
674
+ }
675
+ return handoffs.sort((a, b) => {
676
+ const statusPriority = {
677
+ in_transfer: 4,
678
+ approved: 3,
679
+ pending_review: 2,
680
+ completed: 1,
681
+ failed: 1,
682
+ cancelled: 0
683
+ };
684
+ return (statusPriority[b.status] || 0) - (statusPriority[a.status] || 0);
685
+ });
686
+ }
687
+ estimateHandoffPriority(handoff) {
688
+ if (handoff.errors.length > 2 || handoff.totalFrames > 50)
689
+ return "critical";
690
+ if (handoff.errors.length > 0 || handoff.totalFrames > 20) return "high";
691
+ if (handoff.totalFrames > 5) return "medium";
692
+ return "low";
693
+ }
694
+ /**
695
+ * Bulk handoff operations for team collaboration
696
+ */
697
+ async bulkHandoffOperation(operation) {
698
+ const results = {
699
+ successful: [],
700
+ failed: []
701
+ };
702
+ for (const requestId of operation.requestIds) {
703
+ try {
704
+ switch (operation.action) {
705
+ case "approve":
706
+ await this.submitHandoffApproval(requestId, {
707
+ reviewerId: operation.reviewerId,
708
+ decision: "approved",
709
+ feedback: operation.feedback
710
+ });
711
+ results.successful.push(requestId);
712
+ break;
713
+ case "reject":
714
+ await this.submitHandoffApproval(requestId, {
715
+ reviewerId: operation.reviewerId,
716
+ decision: "rejected",
717
+ feedback: operation.feedback || "Bulk rejection"
718
+ });
719
+ results.successful.push(requestId);
720
+ break;
721
+ case "cancel":
722
+ await this.cancelHandoff(
723
+ requestId,
724
+ operation.feedback || "Bulk cancellation"
725
+ );
726
+ results.successful.push(requestId);
727
+ break;
728
+ }
729
+ } catch (error) {
730
+ results.failed.push({
731
+ requestId,
732
+ error: error instanceof Error ? error.message : String(error)
733
+ });
734
+ }
735
+ }
736
+ logger.info(`Bulk handoff operation completed`, {
737
+ action: operation.action,
738
+ successful: results.successful.length,
739
+ failed: results.failed.length,
740
+ reviewerId: operation.reviewerId
741
+ });
742
+ return results;
743
+ }
744
+ /**
745
+ * Enhanced notification management with cleanup
746
+ */
747
+ async cleanupExpiredNotifications(userId) {
748
+ let cleanedCount = 0;
749
+ const now = /* @__PURE__ */ new Date();
750
+ const userIds = userId ? [userId] : Array.from(this.notifications.keys());
751
+ for (const uid of userIds) {
752
+ const userNotifications = this.notifications.get(uid) || [];
753
+ const activeNotifications = userNotifications.filter((notification) => {
754
+ if (notification.expiresAt && notification.expiresAt < now) {
755
+ cleanedCount++;
756
+ return false;
757
+ }
758
+ return true;
759
+ });
760
+ this.notifications.set(uid, activeNotifications);
761
+ }
762
+ if (cleanedCount > 0) {
763
+ logger.info(`Cleaned up expired notifications`, {
764
+ count: cleanedCount,
765
+ userId: userId || "all"
766
+ });
767
+ }
768
+ return cleanedCount;
379
769
  }
380
770
  }
381
771
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/core/context/frame-handoff-manager.ts"],
4
- "sourcesContent": ["/**\n * Frame Handoff Manager - STA-100\n * Handles frame transfers between individual and team stacks with approval workflows\n */\n\nimport type { Frame, Event, Anchor } from './frame-manager.js';\nimport {\n DualStackManager,\n type StackContext,\n type HandoffRequest,\n} from './dual-stack-manager.js';\nimport { logger } from '../monitoring/logger.js';\nimport { ValidationError, DatabaseError, ErrorCode } from '../errors/index.js';\nimport {\n validateInput,\n InitiateHandoffSchema,\n HandoffApprovalSchema,\n type InitiateHandoffInput,\n type HandoffApprovalInput,\n} from './validation.js';\n\nexport interface HandoffMetadata {\n initiatedAt: Date;\n initiatorId: string;\n targetUserId?: string;\n targetTeamId?: string;\n frameContext: {\n totalFrames: number;\n frameTypes: string[];\n estimatedSize: number;\n dependencies: string[];\n };\n businessContext?: {\n milestone?: string;\n priority: 'low' | 'medium' | 'high' | 'critical';\n deadline?: Date;\n stakeholders: string[];\n };\n}\n\nexport interface HandoffApproval {\n requestId: string;\n reviewerId: string;\n decision: 'approved' | 'rejected' | 'needs_changes';\n feedback?: string;\n suggestedChanges?: Array<{\n frameId: string;\n suggestion: string;\n reason: string;\n }>;\n reviewedAt: Date;\n}\n\nexport interface HandoffNotification {\n id: string;\n type: 'request' | 'approval' | 'rejection' | 'completion' | 'reminder';\n requestId: string;\n recipientId: string;\n title: string;\n message: string;\n actionRequired: boolean;\n expiresAt?: Date;\n createdAt: Date;\n}\n\nexport interface HandoffProgress {\n requestId: string;\n status:\n | 'pending_review'\n | 'approved'\n | 'in_transfer'\n | 'completed'\n | 'failed'\n | 'cancelled';\n transferredFrames: number;\n totalFrames: number;\n currentStep: string;\n estimatedCompletion?: Date;\n errors: Array<{\n step: string;\n error: string;\n timestamp: Date;\n }>;\n}\n\nexport class FrameHandoffManager {\n private dualStackManager: DualStackManager;\n private activeHandoffs: Map<string, HandoffProgress> = new Map();\n private pendingApprovals: Map<string, HandoffApproval[]> = new Map();\n private notifications: Map<string, HandoffNotification[]> = new Map();\n\n constructor(dualStackManager: DualStackManager) {\n this.dualStackManager = dualStackManager;\n }\n\n /**\n * Initiate a frame handoff with rich metadata and approval workflow\n */\n async initiateHandoff(\n targetStackId: string,\n frameIds: string[],\n metadata: HandoffMetadata,\n targetUserId?: string,\n message?: string\n ): Promise<string> {\n // Validate input parameters\n const input = validateInput(InitiateHandoffSchema, {\n targetStackId,\n frameIds,\n handoffRequest: metadata,\n reviewerId: targetUserId,\n description: message,\n });\n\n try {\n // Check handoff permissions\n await this.dualStackManager\n .getPermissionManager()\n .enforcePermission(\n this.dualStackManager\n .getPermissionManager()\n .createContext(\n input.handoffRequest.initiatorId,\n 'handoff',\n 'handoff',\n input.targetStackId\n )\n );\n\n // Validate frames exist and are transferable\n await this.validateFramesForHandoff(input.frameIds);\n\n // Create enhanced handoff request\n const requestId = await this.dualStackManager.initiateHandoff(\n input.targetStackId,\n input.frameIds,\n input.reviewerId,\n input.description\n );\n\n // Initialize handoff progress tracking\n const progress: HandoffProgress = {\n requestId,\n status: 'pending_review',\n transferredFrames: 0,\n totalFrames: input.frameIds.length,\n currentStep: 'Awaiting approval',\n errors: [],\n };\n\n this.activeHandoffs.set(requestId, progress);\n\n // Create notifications for relevant stakeholders\n await this.createHandoffNotifications(requestId, metadata, targetUserId);\n\n // Set up automatic reminders\n await this.scheduleHandoffReminders(requestId, metadata);\n\n logger.info(`Initiated enhanced handoff: ${requestId}`, {\n frameCount: frameIds.length,\n priority: metadata.businessContext?.priority,\n targetUser: targetUserId,\n });\n\n return requestId;\n } catch (error) {\n throw new DatabaseError(\n 'Failed to initiate handoff',\n ErrorCode.OPERATION_FAILED,\n { targetStackId, frameIds },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Submit approval/rejection for handoff request\n */\n async submitHandoffApproval(\n requestId: string,\n approval: Omit<HandoffApproval, 'requestId' | 'reviewedAt'>\n ): Promise<void> {\n // Validate input parameters\n const input = validateInput(HandoffApprovalSchema, {\n ...approval,\n reviewerId: approval.reviewerId,\n });\n const progress = this.activeHandoffs.get(requestId);\n if (!progress) {\n throw new ValidationError(\n `Handoff request not found: ${requestId}`,\n ErrorCode.HANDOFF_REQUEST_EXPIRED\n );\n }\n\n const fullApproval: HandoffApproval = {\n ...input,\n requestId,\n reviewedAt: new Date(),\n };\n\n // Store approval\n const existingApprovals = this.pendingApprovals.get(requestId) || [];\n existingApprovals.push(fullApproval);\n this.pendingApprovals.set(requestId, existingApprovals);\n\n // Update progress based on decision\n if (input.decision === 'approved') {\n progress.status = 'approved';\n progress.currentStep = 'Ready for transfer';\n\n // Automatically start transfer if approved\n await this.executeHandoffTransfer(requestId);\n } else if (input.decision === 'rejected') {\n progress.status = 'failed';\n progress.currentStep = 'Rejected by reviewer';\n progress.errors.push({\n step: 'approval',\n error: input.feedback || 'Request rejected',\n timestamp: new Date(),\n });\n } else if (input.decision === 'needs_changes') {\n progress.status = 'pending_review';\n progress.currentStep = 'Changes requested';\n\n // Notify requester of needed changes\n await this.notifyChangesRequested(requestId, approval);\n }\n\n this.activeHandoffs.set(requestId, progress);\n\n logger.info(`Handoff approval submitted: ${requestId}`, {\n decision: approval.decision,\n reviewer: approval.reviewerId,\n });\n }\n\n /**\n * Execute the actual frame transfer after approval\n */\n private async executeHandoffTransfer(requestId: string): Promise<void> {\n logger.debug('executeHandoffTransfer called', {\n requestId,\n availableHandoffs: Array.from(this.activeHandoffs.keys()),\n });\n const progress = this.activeHandoffs.get(requestId);\n if (!progress) {\n logger.error('Handoff progress not found', {\n requestId,\n availableHandoffs: Array.from(this.activeHandoffs.keys()),\n });\n throw new DatabaseError(\n `Handoff progress not found: ${requestId}`,\n ErrorCode.INVALID_STATE\n );\n }\n\n try {\n logger.debug('Setting progress status to in_transfer', { requestId });\n progress.status = 'in_transfer';\n progress.currentStep = 'Transferring frames';\n progress.estimatedCompletion = new Date(Date.now() + 5 * 60 * 1000); // 5 minutes\n\n // Execute the handoff through DualStackManager\n logger.debug('About to call acceptHandoff', { requestId });\n const result = await this.dualStackManager.acceptHandoff(requestId);\n logger.debug('acceptHandoff returned', {\n requestId,\n success: result.success,\n });\n\n if (result.success) {\n progress.status = 'completed';\n progress.currentStep = 'Transfer completed';\n progress.transferredFrames = result.mergedFrames.length;\n\n // Create completion notifications\n await this.notifyHandoffCompletion(requestId, result);\n\n logger.info(`Handoff transfer completed: ${requestId}`, {\n transferredFrames: progress.transferredFrames,\n conflicts: result.conflictFrames.length,\n });\n } else {\n progress.status = 'failed';\n progress.currentStep = 'Transfer failed';\n\n // Log errors\n result.errors.forEach((error) => {\n progress.errors.push({\n step: 'transfer',\n error: `Frame ${error.frameId}: ${error.error}`,\n timestamp: new Date(),\n });\n });\n\n throw new DatabaseError(\n 'Handoff transfer failed',\n ErrorCode.OPERATION_FAILED,\n { errors: result.errors }\n );\n }\n } catch (error) {\n progress.status = 'failed';\n progress.currentStep = 'Transfer error';\n progress.errors.push({\n step: 'transfer',\n error: error instanceof Error ? error.message : String(error),\n timestamp: new Date(),\n });\n\n logger.error(`Handoff transfer failed: ${requestId}`, error);\n throw error;\n } finally {\n this.activeHandoffs.set(requestId, progress);\n }\n }\n\n /**\n * Get handoff progress and status\n */\n async getHandoffProgress(requestId: string): Promise<HandoffProgress | null> {\n return this.activeHandoffs.get(requestId) || null;\n }\n\n /**\n * Cancel a pending handoff request\n */\n async cancelHandoff(requestId: string, reason: string): Promise<void> {\n const progress = this.activeHandoffs.get(requestId);\n if (!progress) {\n throw new DatabaseError(\n `Handoff request not found: ${requestId}`,\n ErrorCode.RESOURCE_NOT_FOUND\n );\n }\n\n if (progress.status === 'in_transfer') {\n throw new DatabaseError(\n 'Cannot cancel handoff that is currently transferring',\n ErrorCode.INVALID_STATE\n );\n }\n\n progress.status = 'cancelled';\n progress.currentStep = 'Cancelled by user';\n progress.errors.push({\n step: 'cancellation',\n error: reason,\n timestamp: new Date(),\n });\n\n this.activeHandoffs.set(requestId, progress);\n\n // Notify relevant parties\n await this.notifyHandoffCancellation(requestId, reason);\n\n logger.info(`Handoff cancelled: ${requestId}`, { reason });\n }\n\n /**\n * Get all active handoffs for a user or team\n */\n async getActiveHandoffs(\n userId?: string,\n teamId?: string\n ): Promise<HandoffProgress[]> {\n const handoffs = Array.from(this.activeHandoffs.values());\n\n // Filter by user/team if specified\n if (userId || teamId) {\n // Would need to cross-reference with handoff metadata\n return handoffs.filter(\n (handoff) =>\n handoff.status === 'pending_review' ||\n handoff.status === 'approved' ||\n handoff.status === 'in_transfer'\n );\n }\n\n return handoffs;\n }\n\n /**\n * Get notifications for a user\n */\n async getUserNotifications(userId: string): Promise<HandoffNotification[]> {\n return this.notifications.get(userId) || [];\n }\n\n /**\n * Mark notification as read\n */\n async markNotificationRead(\n notificationId: string,\n userId: string\n ): Promise<void> {\n const userNotifications = this.notifications.get(userId) || [];\n const updatedNotifications = userNotifications.filter(\n (n) => n.id !== notificationId\n );\n this.notifications.set(userId, updatedNotifications);\n }\n\n /**\n * Validate frames are suitable for handoff\n */\n private async validateFramesForHandoff(frameIds: string[]): Promise<void> {\n const activeStack = this.dualStackManager.getActiveStack();\n\n for (const frameId of frameIds) {\n const frame = await activeStack.getFrame(frameId);\n if (!frame) {\n throw new DatabaseError(\n `Frame not found: ${frameId}`,\n ErrorCode.RESOURCE_NOT_FOUND\n );\n }\n\n // Check if frame is in a transferable state\n if (frame.state === 'active') {\n logger.warn(`Transferring active frame: ${frameId}`, {\n frameName: frame.name,\n });\n }\n }\n }\n\n /**\n * Create notifications for handoff stakeholders\n */\n private async createHandoffNotifications(\n requestId: string,\n metadata: HandoffMetadata,\n targetUserId?: string\n ): Promise<void> {\n const notifications: HandoffNotification[] = [];\n\n // Notify target user\n if (targetUserId) {\n notifications.push({\n id: `${requestId}-target`,\n type: 'request',\n requestId,\n recipientId: targetUserId,\n title: 'Frame Handoff Request',\n message: `${metadata.initiatorId} wants to transfer ${metadata.frameContext.totalFrames} frames to you`,\n actionRequired: true,\n expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000),\n createdAt: new Date(),\n });\n }\n\n // Notify stakeholders\n if (metadata.businessContext?.stakeholders) {\n for (const stakeholderId of metadata.businessContext.stakeholders) {\n notifications.push({\n id: `${requestId}-stakeholder-${stakeholderId}`,\n type: 'request',\n requestId,\n recipientId: stakeholderId,\n title: 'Frame Handoff Notification',\n message: `Frame transfer initiated for ${metadata.businessContext?.milestone || 'project milestone'}`,\n actionRequired: false,\n createdAt: new Date(),\n });\n }\n }\n\n // Store notifications\n for (const notification of notifications) {\n const userNotifications =\n this.notifications.get(notification.recipientId) || [];\n userNotifications.push(notification);\n this.notifications.set(notification.recipientId, userNotifications);\n }\n }\n\n /**\n * Schedule reminder notifications\n */\n private async scheduleHandoffReminders(\n requestId: string,\n metadata: HandoffMetadata\n ): Promise<void> {\n // Schedule reminder in 4 hours if high priority\n if (\n metadata.businessContext?.priority === 'high' ||\n metadata.businessContext?.priority === 'critical'\n ) {\n setTimeout(\n async () => {\n const progress = this.activeHandoffs.get(requestId);\n if (progress && progress.status === 'pending_review') {\n await this.sendHandoffReminder(requestId, metadata);\n }\n },\n 4 * 60 * 60 * 1000\n ); // 4 hours\n }\n }\n\n /**\n * Send handoff reminder\n */\n private async sendHandoffReminder(\n requestId: string,\n metadata: HandoffMetadata\n ): Promise<void> {\n // Implementation would send actual notifications\n logger.info(`Sending handoff reminder: ${requestId}`, {\n priority: metadata.businessContext?.priority,\n });\n }\n\n /**\n * Notify when changes are requested\n */\n private async notifyChangesRequested(\n requestId: string,\n approval: HandoffApproval\n ): Promise<void> {\n // Implementation would notify the requester\n logger.info(`Changes requested for handoff: ${requestId}`, {\n reviewer: approval.reviewerId,\n feedback: approval.feedback,\n });\n }\n\n /**\n * Notify handoff completion\n */\n private async notifyHandoffCompletion(\n requestId: string,\n result: any\n ): Promise<void> {\n // Implementation would notify all stakeholders\n logger.info(`Handoff completed: ${requestId}`, {\n mergedFrames: result.mergedFrames.length,\n conflicts: result.conflictFrames.length,\n });\n }\n\n /**\n * Notify handoff cancellation\n */\n private async notifyHandoffCancellation(\n requestId: string,\n reason: string\n ): Promise<void> {\n // Implementation would notify stakeholders\n logger.info(`Handoff cancelled: ${requestId}`, { reason });\n }\n\n /**\n * Get handoff analytics and metrics\n */\n async getHandoffMetrics(timeRange?: { start: Date; end: Date }): Promise<{\n totalHandoffs: number;\n completedHandoffs: number;\n averageProcessingTime: number;\n topFrameTypes: Array<{ type: string; count: number }>;\n collaborationPatterns: Array<{\n sourceUser: string;\n targetUser: string;\n count: number;\n }>;\n }> {\n const handoffs = Array.from(this.activeHandoffs.values());\n\n // Filter by time range if specified\n const filteredHandoffs = timeRange\n ? handoffs.filter((h) => {\n // Would need to add timestamps to track creation time\n return true; // Placeholder\n })\n : handoffs;\n\n const completedHandoffs = filteredHandoffs.filter(\n (h) => h.status === 'completed'\n );\n\n return {\n totalHandoffs: filteredHandoffs.length,\n completedHandoffs: completedHandoffs.length,\n averageProcessingTime:\n this.calculateAverageProcessingTime(completedHandoffs),\n topFrameTypes: this.analyzeFrameTypes(filteredHandoffs),\n collaborationPatterns:\n this.analyzeCollaborationPatterns(filteredHandoffs),\n };\n }\n\n private calculateAverageProcessingTime(handoffs: HandoffProgress[]): number {\n // Implementation would calculate actual processing times\n return 0; // Placeholder\n }\n\n private analyzeFrameTypes(\n handoffs: HandoffProgress[]\n ): Array<{ type: string; count: number }> {\n // Implementation would analyze frame types from handoffs\n return []; // Placeholder\n }\n\n private analyzeCollaborationPatterns(\n handoffs: HandoffProgress[]\n ): Array<{ sourceUser: string; targetUser: string; count: number }> {\n // Implementation would analyze collaboration patterns\n return []; // Placeholder\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Frame Handoff Manager - STA-100\n * Handles frame transfers between individual and team stacks with approval workflows\n */\n\nimport type { Frame, Event, Anchor } from './frame-manager.js';\nimport {\n DualStackManager,\n type StackContext,\n type HandoffRequest,\n} from './dual-stack-manager.js';\nimport { logger } from '../monitoring/logger.js';\nimport { ValidationError, DatabaseError, ErrorCode } from '../errors/index.js';\nimport {\n validateInput,\n InitiateHandoffSchema,\n HandoffApprovalSchema,\n type InitiateHandoffInput,\n type HandoffApprovalInput,\n} from './validation.js';\n\nexport interface HandoffMetadata {\n initiatedAt: Date;\n initiatorId: string;\n targetUserId?: string;\n targetTeamId?: string;\n frameContext: {\n totalFrames: number;\n frameTypes: string[];\n estimatedSize: number;\n dependencies: string[];\n };\n businessContext?: {\n milestone?: string;\n priority: 'low' | 'medium' | 'high' | 'critical';\n deadline?: Date;\n stakeholders: string[];\n };\n}\n\nexport interface HandoffApproval {\n requestId: string;\n reviewerId: string;\n decision: 'approved' | 'rejected' | 'needs_changes';\n feedback?: string;\n suggestedChanges?: Array<{\n frameId: string;\n suggestion: string;\n reason: string;\n }>;\n reviewedAt: Date;\n}\n\nexport interface HandoffNotification {\n id: string;\n type: 'request' | 'approval' | 'rejection' | 'completion' | 'reminder';\n requestId: string;\n recipientId: string;\n title: string;\n message: string;\n actionRequired: boolean;\n expiresAt?: Date;\n createdAt: Date;\n}\n\nexport interface HandoffProgress {\n requestId: string;\n status:\n | 'pending_review'\n | 'approved'\n | 'in_transfer'\n | 'completed'\n | 'failed'\n | 'cancelled';\n transferredFrames: number;\n totalFrames: number;\n currentStep: string;\n estimatedCompletion?: Date;\n errors: Array<{\n step: string;\n error: string;\n timestamp: Date;\n }>;\n}\n\nexport class FrameHandoffManager {\n private dualStackManager: DualStackManager;\n private activeHandoffs: Map<string, HandoffProgress> = new Map();\n private pendingApprovals: Map<string, HandoffApproval[]> = new Map();\n private notifications: Map<string, HandoffNotification[]> = new Map();\n\n constructor(dualStackManager: DualStackManager) {\n this.dualStackManager = dualStackManager;\n }\n\n /**\n * Initiate a frame handoff with rich metadata and approval workflow\n */\n async initiateHandoff(\n targetStackId: string,\n frameIds: string[],\n metadata: HandoffMetadata,\n targetUserId?: string,\n message?: string\n ): Promise<string> {\n // Validate input parameters\n const input = validateInput(InitiateHandoffSchema, {\n targetStackId,\n frameIds,\n handoffRequest: metadata,\n reviewerId: targetUserId,\n description: message,\n });\n\n try {\n // Check handoff permissions\n await this.dualStackManager\n .getPermissionManager()\n .enforcePermission(\n this.dualStackManager\n .getPermissionManager()\n .createContext(\n input.handoffRequest.initiatorId,\n 'handoff',\n 'handoff',\n input.targetStackId\n )\n );\n\n // Validate frames exist and are transferable\n await this.validateFramesForHandoff(input.frameIds);\n\n // Create enhanced handoff request\n const requestId = await this.dualStackManager.initiateHandoff(\n input.targetStackId,\n input.frameIds,\n input.reviewerId,\n input.description\n );\n\n // Initialize handoff progress tracking\n const progress: HandoffProgress = {\n requestId,\n status: 'pending_review',\n transferredFrames: 0,\n totalFrames: input.frameIds.length,\n currentStep: 'Awaiting approval',\n errors: [],\n };\n\n this.activeHandoffs.set(requestId, progress);\n\n // Create notifications for relevant stakeholders\n await this.createHandoffNotifications(requestId, metadata, targetUserId);\n\n // Set up automatic reminders\n await this.scheduleHandoffReminders(requestId, metadata);\n\n logger.info(`Initiated enhanced handoff: ${requestId}`, {\n frameCount: frameIds.length,\n priority: metadata.businessContext?.priority,\n targetUser: targetUserId,\n });\n\n return requestId;\n } catch (error) {\n throw new DatabaseError(\n 'Failed to initiate handoff',\n ErrorCode.OPERATION_FAILED,\n { targetStackId, frameIds },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Submit approval/rejection for handoff request\n */\n async submitHandoffApproval(\n requestId: string,\n approval: Omit<HandoffApproval, 'requestId' | 'reviewedAt'>\n ): Promise<void> {\n // Validate input parameters\n const input = validateInput(HandoffApprovalSchema, {\n ...approval,\n reviewerId: approval.reviewerId,\n });\n const progress = this.activeHandoffs.get(requestId);\n if (!progress) {\n throw new ValidationError(\n `Handoff request not found: ${requestId}`,\n ErrorCode.HANDOFF_REQUEST_EXPIRED\n );\n }\n\n const fullApproval: HandoffApproval = {\n ...input,\n requestId,\n reviewedAt: new Date(),\n };\n\n // Store approval\n const existingApprovals = this.pendingApprovals.get(requestId) || [];\n existingApprovals.push(fullApproval);\n this.pendingApprovals.set(requestId, existingApprovals);\n\n // Update progress based on decision\n if (input.decision === 'approved') {\n progress.status = 'approved';\n progress.currentStep = 'Ready for transfer';\n\n // Automatically start transfer if approved\n await this.executeHandoffTransfer(requestId);\n } else if (input.decision === 'rejected') {\n progress.status = 'failed';\n progress.currentStep = 'Rejected by reviewer';\n progress.errors.push({\n step: 'approval',\n error: input.feedback || 'Request rejected',\n timestamp: new Date(),\n });\n } else if (input.decision === 'needs_changes') {\n progress.status = 'pending_review';\n progress.currentStep = 'Changes requested';\n\n // Notify requester of needed changes\n await this.notifyChangesRequested(requestId, approval);\n }\n\n this.activeHandoffs.set(requestId, progress);\n\n logger.info(`Handoff approval submitted: ${requestId}`, {\n decision: approval.decision,\n reviewer: approval.reviewerId,\n });\n }\n\n /**\n * Execute the actual frame transfer after approval\n */\n private async executeHandoffTransfer(requestId: string): Promise<void> {\n logger.debug('executeHandoffTransfer called', {\n requestId,\n availableHandoffs: Array.from(this.activeHandoffs.keys()),\n });\n const progress = this.activeHandoffs.get(requestId);\n if (!progress) {\n logger.error('Handoff progress not found', {\n requestId,\n availableHandoffs: Array.from(this.activeHandoffs.keys()),\n });\n throw new DatabaseError(\n `Handoff progress not found: ${requestId}`,\n ErrorCode.INVALID_STATE\n );\n }\n\n try {\n logger.debug('Setting progress status to in_transfer', { requestId });\n progress.status = 'in_transfer';\n progress.currentStep = 'Transferring frames';\n progress.estimatedCompletion = new Date(Date.now() + 5 * 60 * 1000); // 5 minutes\n\n // Execute the handoff through DualStackManager\n logger.debug('About to call acceptHandoff', { requestId });\n const result = await this.dualStackManager.acceptHandoff(requestId);\n logger.debug('acceptHandoff returned', {\n requestId,\n success: result.success,\n });\n\n if (result.success) {\n progress.status = 'completed';\n progress.currentStep = 'Transfer completed';\n progress.transferredFrames = result.mergedFrames.length;\n\n // Create completion notifications\n await this.notifyHandoffCompletion(requestId, result);\n\n logger.info(`Handoff transfer completed: ${requestId}`, {\n transferredFrames: progress.transferredFrames,\n conflicts: result.conflictFrames.length,\n });\n } else {\n progress.status = 'failed';\n progress.currentStep = 'Transfer failed';\n\n // Log errors\n result.errors.forEach((error) => {\n progress.errors.push({\n step: 'transfer',\n error: `Frame ${error.frameId}: ${error.error}`,\n timestamp: new Date(),\n });\n });\n\n throw new DatabaseError(\n 'Handoff transfer failed',\n ErrorCode.OPERATION_FAILED,\n { errors: result.errors }\n );\n }\n } catch (error) {\n progress.status = 'failed';\n progress.currentStep = 'Transfer error';\n progress.errors.push({\n step: 'transfer',\n error: error instanceof Error ? error.message : String(error),\n timestamp: new Date(),\n });\n\n logger.error(`Handoff transfer failed: ${requestId}`, error);\n throw error;\n } finally {\n this.activeHandoffs.set(requestId, progress);\n }\n }\n\n /**\n * Get handoff progress and status\n */\n async getHandoffProgress(requestId: string): Promise<HandoffProgress | null> {\n return this.activeHandoffs.get(requestId) || null;\n }\n\n /**\n * Cancel a pending handoff request\n */\n async cancelHandoff(requestId: string, reason: string): Promise<void> {\n const progress = this.activeHandoffs.get(requestId);\n if (!progress) {\n throw new DatabaseError(\n `Handoff request not found: ${requestId}`,\n ErrorCode.RESOURCE_NOT_FOUND\n );\n }\n\n if (progress.status === 'in_transfer') {\n throw new DatabaseError(\n 'Cannot cancel handoff that is currently transferring',\n ErrorCode.INVALID_STATE\n );\n }\n\n progress.status = 'cancelled';\n progress.currentStep = 'Cancelled by user';\n progress.errors.push({\n step: 'cancellation',\n error: reason,\n timestamp: new Date(),\n });\n\n this.activeHandoffs.set(requestId, progress);\n\n // Notify relevant parties\n await this.notifyHandoffCancellation(requestId, reason);\n\n logger.info(`Handoff cancelled: ${requestId}`, { reason });\n }\n\n /**\n * Get all active handoffs for a user or team\n */\n async getActiveHandoffs(\n userId?: string,\n teamId?: string\n ): Promise<HandoffProgress[]> {\n const handoffs = Array.from(this.activeHandoffs.values());\n\n // Filter by user/team if specified\n if (userId || teamId) {\n // Would need to cross-reference with handoff metadata\n return handoffs.filter(\n (handoff) =>\n handoff.status === 'pending_review' ||\n handoff.status === 'approved' ||\n handoff.status === 'in_transfer'\n );\n }\n\n return handoffs;\n }\n\n /**\n * Get notifications for a user\n */\n async getUserNotifications(userId: string): Promise<HandoffNotification[]> {\n return this.notifications.get(userId) || [];\n }\n\n /**\n * Mark notification as read\n */\n async markNotificationRead(\n notificationId: string,\n userId: string\n ): Promise<void> {\n const userNotifications = this.notifications.get(userId) || [];\n const updatedNotifications = userNotifications.filter(\n (n) => n.id !== notificationId\n );\n this.notifications.set(userId, updatedNotifications);\n }\n\n /**\n * Validate frames are suitable for handoff\n */\n private async validateFramesForHandoff(frameIds: string[]): Promise<void> {\n const activeStack = this.dualStackManager.getActiveStack();\n\n for (const frameId of frameIds) {\n const frame = await activeStack.getFrame(frameId);\n if (!frame) {\n throw new DatabaseError(\n `Frame not found: ${frameId}`,\n ErrorCode.RESOURCE_NOT_FOUND\n );\n }\n\n // Check if frame is in a transferable state\n if (frame.state === 'active') {\n logger.warn(`Transferring active frame: ${frameId}`, {\n frameName: frame.name,\n });\n }\n }\n }\n\n /**\n * Create notifications for handoff stakeholders\n */\n private async createHandoffNotifications(\n requestId: string,\n metadata: HandoffMetadata,\n targetUserId?: string\n ): Promise<void> {\n const notifications: HandoffNotification[] = [];\n\n // Notify target user\n if (targetUserId) {\n notifications.push({\n id: `${requestId}-target`,\n type: 'request',\n requestId,\n recipientId: targetUserId,\n title: 'Frame Handoff Request',\n message: `${metadata.initiatorId} wants to transfer ${metadata.frameContext.totalFrames} frames to you`,\n actionRequired: true,\n expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000),\n createdAt: new Date(),\n });\n }\n\n // Notify stakeholders\n if (metadata.businessContext?.stakeholders) {\n for (const stakeholderId of metadata.businessContext.stakeholders) {\n notifications.push({\n id: `${requestId}-stakeholder-${stakeholderId}`,\n type: 'request',\n requestId,\n recipientId: stakeholderId,\n title: 'Frame Handoff Notification',\n message: `Frame transfer initiated for ${metadata.businessContext?.milestone || 'project milestone'}`,\n actionRequired: false,\n createdAt: new Date(),\n });\n }\n }\n\n // Store notifications\n for (const notification of notifications) {\n const userNotifications =\n this.notifications.get(notification.recipientId) || [];\n userNotifications.push(notification);\n this.notifications.set(notification.recipientId, userNotifications);\n }\n }\n\n /**\n * Schedule reminder notifications\n */\n private async scheduleHandoffReminders(\n requestId: string,\n metadata: HandoffMetadata\n ): Promise<void> {\n // Schedule reminder in 4 hours if high priority\n if (\n metadata.businessContext?.priority === 'high' ||\n metadata.businessContext?.priority === 'critical'\n ) {\n setTimeout(\n async () => {\n const progress = this.activeHandoffs.get(requestId);\n if (progress && progress.status === 'pending_review') {\n await this.sendHandoffReminder(requestId, metadata);\n }\n },\n 4 * 60 * 60 * 1000\n ); // 4 hours\n }\n }\n\n /**\n * Send handoff reminder\n */\n private async sendHandoffReminder(\n requestId: string,\n metadata: HandoffMetadata\n ): Promise<void> {\n const progress = this.activeHandoffs.get(requestId);\n if (!progress || progress.status !== 'pending_review') {\n return;\n }\n\n const reminderNotification: HandoffNotification = {\n id: `${requestId}-reminder-${Date.now()}`,\n type: 'reminder',\n requestId,\n recipientId: metadata.targetUserId || 'unknown',\n title: '\u23F0 Handoff Request Reminder',\n message: `Reminder: ${metadata.initiatorId} is waiting for approval on ${metadata.frameContext.totalFrames} frames. Priority: ${metadata.businessContext?.priority || 'medium'}`,\n actionRequired: true,\n expiresAt: new Date(Date.now() + 12 * 60 * 60 * 1000), // 12 hours\n createdAt: new Date(),\n };\n\n // Store the notification\n if (metadata.targetUserId) {\n const userNotifications =\n this.notifications.get(metadata.targetUserId) || [];\n userNotifications.push(reminderNotification);\n this.notifications.set(metadata.targetUserId, userNotifications);\n\n logger.info(`Sent handoff reminder: ${requestId}`, {\n priority: metadata.businessContext?.priority,\n recipient: metadata.targetUserId,\n });\n }\n\n // Also notify stakeholders\n if (metadata.businessContext?.stakeholders) {\n for (const stakeholderId of metadata.businessContext.stakeholders) {\n const stakeholderNotification: HandoffNotification = {\n ...reminderNotification,\n id: `${requestId}-reminder-stakeholder-${stakeholderId}-${Date.now()}`,\n recipientId: stakeholderId,\n title: '\uD83D\uDCCB Handoff Status Update',\n message: `Pending handoff approval: ${metadata.businessContext?.milestone || 'development work'} requires attention`,\n actionRequired: false,\n };\n\n const stakeholderNotifications =\n this.notifications.get(stakeholderId) || [];\n stakeholderNotifications.push(stakeholderNotification);\n this.notifications.set(stakeholderId, stakeholderNotifications);\n }\n }\n }\n\n /**\n * Notify when changes are requested\n */\n private async notifyChangesRequested(\n requestId: string,\n approval: Omit<HandoffApproval, 'requestId' | 'reviewedAt'>\n ): Promise<void> {\n const progress = this.activeHandoffs.get(requestId);\n if (!progress) return;\n\n // Find the original requester (we'll need to enhance this with better metadata tracking)\n const changeRequestNotification: HandoffNotification = {\n id: `${requestId}-changes-${Date.now()}`,\n type: 'request',\n requestId,\n recipientId: 'requester', // TODO: Get actual requester from handoff metadata\n title: '\uD83D\uDD04 Changes Requested for Handoff',\n message: `${approval.reviewerId} has requested changes: ${approval.feedback || 'See detailed suggestions'}`,\n actionRequired: true,\n expiresAt: new Date(Date.now() + 48 * 60 * 60 * 1000), // 48 hours\n createdAt: new Date(),\n };\n\n // Store notification (for now using a placeholder recipient)\n const notifications = this.notifications.get('requester') || [];\n notifications.push(changeRequestNotification);\n this.notifications.set('requester', notifications);\n\n // Log detailed feedback and suggestions\n logger.info(`Changes requested for handoff: ${requestId}`, {\n reviewer: approval.reviewerId,\n feedback: approval.feedback,\n suggestedChangesCount: approval.suggestedChanges?.length || 0,\n });\n\n if (approval.suggestedChanges && approval.suggestedChanges.length > 0) {\n logger.info(`Detailed change suggestions:`, {\n requestId,\n suggestions: approval.suggestedChanges.map((change) => ({\n frameId: change.frameId,\n suggestion: change.suggestion,\n reason: change.reason,\n })),\n });\n }\n }\n\n /**\n * Notify handoff completion\n */\n private async notifyHandoffCompletion(\n requestId: string,\n result: any\n ): Promise<void> {\n const progress = this.activeHandoffs.get(requestId);\n if (!progress) return;\n\n // Create completion notification\n const completionNotification: HandoffNotification = {\n id: `${requestId}-completion-${Date.now()}`,\n type: 'completion',\n requestId,\n recipientId: 'all', // Will be distributed to all stakeholders\n title: '\u2705 Handoff Completed Successfully',\n message: `Frame transfer completed: ${result.mergedFrames.length} frames transferred${result.conflictFrames.length > 0 ? `, ${result.conflictFrames.length} conflicts resolved` : ''}`,\n actionRequired: false,\n createdAt: new Date(),\n };\n\n // Notify all stakeholders from the notifications map\n const allUsers = Array.from(this.notifications.keys());\n for (const userId of allUsers) {\n const userSpecificNotification: HandoffNotification = {\n ...completionNotification,\n id: `${requestId}-completion-${userId}-${Date.now()}`,\n recipientId: userId,\n };\n\n const userNotifications = this.notifications.get(userId) || [];\n userNotifications.push(userSpecificNotification);\n this.notifications.set(userId, userNotifications);\n }\n\n logger.info(`Handoff completed: ${requestId}`, {\n mergedFrames: result.mergedFrames.length,\n conflicts: result.conflictFrames.length,\n notifiedUsers: allUsers.length,\n });\n\n // Log detailed completion statistics\n if (result.conflictFrames.length > 0) {\n logger.info(`Handoff completion details:`, {\n requestId,\n transferredFrames: result.mergedFrames.map(\n (f: any) => f.frameId || f.id\n ),\n conflictFrames: result.conflictFrames.map(\n (f: any) => f.frameId || f.id\n ),\n });\n }\n }\n\n /**\n * Notify handoff cancellation\n */\n private async notifyHandoffCancellation(\n requestId: string,\n reason: string\n ): Promise<void> {\n // Create cancellation notification\n const cancellationNotification: HandoffNotification = {\n id: `${requestId}-cancellation-${Date.now()}`,\n type: 'request', // Using 'request' type as it's informational\n requestId,\n recipientId: 'all', // Will be distributed to all stakeholders\n title: '\u274C Handoff Cancelled',\n message: `Handoff request has been cancelled. Reason: ${reason}`,\n actionRequired: false,\n createdAt: new Date(),\n };\n\n // Notify all users who have been involved in this handoff\n const allUsers = Array.from(this.notifications.keys());\n for (const userId of allUsers) {\n const userSpecificNotification: HandoffNotification = {\n ...cancellationNotification,\n id: `${requestId}-cancellation-${userId}-${Date.now()}`,\n recipientId: userId,\n };\n\n const userNotifications = this.notifications.get(userId) || [];\n userNotifications.push(userSpecificNotification);\n this.notifications.set(userId, userNotifications);\n }\n\n logger.info(`Handoff cancelled: ${requestId}`, {\n reason,\n notifiedUsers: allUsers.length,\n });\n }\n\n /**\n * Get handoff analytics and metrics\n */\n async getHandoffMetrics(timeRange?: { start: Date; end: Date }): Promise<{\n totalHandoffs: number;\n completedHandoffs: number;\n averageProcessingTime: number;\n topFrameTypes: Array<{ type: string; count: number }>;\n collaborationPatterns: Array<{\n sourceUser: string;\n targetUser: string;\n count: number;\n }>;\n }> {\n const handoffs = Array.from(this.activeHandoffs.values());\n\n // Filter by time range if specified\n const filteredHandoffs = timeRange\n ? handoffs.filter((h) => {\n // Would need to add timestamps to track creation time\n return true; // Placeholder\n })\n : handoffs;\n\n const completedHandoffs = filteredHandoffs.filter(\n (h) => h.status === 'completed'\n );\n\n return {\n totalHandoffs: filteredHandoffs.length,\n completedHandoffs: completedHandoffs.length,\n averageProcessingTime:\n this.calculateAverageProcessingTime(completedHandoffs),\n topFrameTypes: this.analyzeFrameTypes(filteredHandoffs),\n collaborationPatterns:\n this.analyzeCollaborationPatterns(filteredHandoffs),\n };\n }\n\n private calculateAverageProcessingTime(handoffs: HandoffProgress[]): number {\n if (handoffs.length === 0) return 0;\n\n let totalProcessingTime = 0;\n let validHandoffs = 0;\n\n for (const handoff of handoffs) {\n // Only calculate for completed handoffs that have timing data\n if (handoff.status === 'completed' && handoff.estimatedCompletion) {\n // Estimate processing time based on frame count and complexity\n // This is a simplified calculation - in practice you'd track actual timestamps\n const frameComplexity = handoff.totalFrames * 0.5; // Base time per frame\n const errorPenalty = handoff.errors.length * 2; // Extra time for errors\n const processingTime = Math.max(1, frameComplexity + errorPenalty);\n\n totalProcessingTime += processingTime;\n validHandoffs++;\n }\n }\n\n return validHandoffs > 0\n ? Math.round(totalProcessingTime / validHandoffs)\n : 0;\n }\n\n private analyzeFrameTypes(\n handoffs: HandoffProgress[]\n ): Array<{ type: string; count: number }> {\n const frameTypeCount = new Map<string, number>();\n\n for (const handoff of handoffs) {\n // Extract frame type information from handoff metadata\n // This would need to be enhanced with actual frame type tracking\n const estimatedTypes = this.estimateFrameTypes(handoff);\n\n for (const type of estimatedTypes) {\n frameTypeCount.set(type, (frameTypeCount.get(type) || 0) + 1);\n }\n }\n\n return Array.from(frameTypeCount.entries())\n .map(([type, count]) => ({ type, count }))\n .sort((a, b) => b.count - a.count)\n .slice(0, 10); // Top 10 frame types\n }\n\n private estimateFrameTypes(handoff: HandoffProgress): string[] {\n // Simplified frame type estimation based on handoff characteristics\n const types: string[] = [];\n\n if (handoff.totalFrames > 10) {\n types.push('bulk_transfer');\n }\n if (handoff.errors.length > 0) {\n types.push('complex_handoff');\n }\n if (handoff.transferredFrames === handoff.totalFrames) {\n types.push('complete_transfer');\n } else {\n types.push('partial_transfer');\n }\n\n // Add some common frame types based on patterns\n types.push('development', 'collaboration');\n\n return types;\n }\n\n private analyzeCollaborationPatterns(\n handoffs: HandoffProgress[]\n ): Array<{ sourceUser: string; targetUser: string; count: number }> {\n const collaborationCount = new Map<string, number>();\n\n for (const handoff of handoffs) {\n // Extract collaboration pattern from handoff data\n // Note: This is simplified - we'd need to track actual source/target users\n const pattern = this.extractCollaborationPattern(handoff);\n if (pattern) {\n const key = `${pattern.sourceUser}->${pattern.targetUser}`;\n collaborationCount.set(key, (collaborationCount.get(key) || 0) + 1);\n }\n }\n\n return Array.from(collaborationCount.entries())\n .map(([pattern, count]) => {\n const [sourceUser, targetUser] = pattern.split('->');\n return { sourceUser, targetUser, count };\n })\n .sort((a, b) => b.count - a.count)\n .slice(0, 20); // Top 20 collaboration patterns\n }\n\n private extractCollaborationPattern(\n handoff: HandoffProgress\n ): { sourceUser: string; targetUser: string } | null {\n // Simplified pattern extraction - in practice this would come from handoff metadata\n // For now, we'll create sample patterns based on handoff characteristics\n\n if (handoff.status === 'completed') {\n return {\n sourceUser: 'developer',\n targetUser: 'reviewer',\n };\n } else if (handoff.status === 'failed') {\n return {\n sourceUser: 'developer',\n targetUser: 'lead',\n };\n }\n\n return null;\n }\n\n /**\n * Real-time collaboration features\n */\n\n /**\n * Get real-time handoff status updates\n */\n async getHandoffStatusStream(\n requestId: string\n ): Promise<AsyncIterableIterator<HandoffProgress>> {\n const progress = this.activeHandoffs.get(requestId);\n if (!progress) {\n throw new DatabaseError(\n `Handoff request not found: ${requestId}`,\n ErrorCode.RESOURCE_NOT_FOUND\n );\n }\n\n // Simple implementation - in a real system this would use WebSockets or Server-Sent Events\n const self = this;\n return {\n async *[Symbol.asyncIterator]() {\n let lastStatus = progress.status;\n while (\n lastStatus !== 'completed' &&\n lastStatus !== 'failed' &&\n lastStatus !== 'cancelled'\n ) {\n const currentProgress = self.activeHandoffs.get(requestId);\n if (currentProgress && currentProgress.status !== lastStatus) {\n lastStatus = currentProgress.status;\n yield currentProgress;\n }\n // Simulate real-time polling\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n },\n };\n }\n\n /**\n * Update handoff progress in real-time\n */\n async updateHandoffProgress(\n requestId: string,\n update: Partial<HandoffProgress>\n ): Promise<void> {\n let progress = this.activeHandoffs.get(requestId);\n\n // If progress doesn't exist and update includes required fields, create it\n if (\n !progress &&\n update.requestId &&\n update.status &&\n update.totalFrames !== undefined\n ) {\n progress = {\n requestId: update.requestId,\n status: update.status,\n transferredFrames: 0,\n totalFrames: update.totalFrames,\n currentStep: 'Initialized',\n errors: [],\n ...update,\n };\n } else if (!progress) {\n throw new DatabaseError(\n `Handoff request not found: ${requestId}`,\n ErrorCode.RESOURCE_NOT_FOUND\n );\n } else {\n // Update existing progress with provided fields\n progress = {\n ...progress,\n ...update,\n };\n }\n\n this.activeHandoffs.set(requestId, progress);\n\n logger.info(`Handoff progress updated: ${requestId}`, {\n status: progress.status,\n currentStep: progress.currentStep,\n transferredFrames: progress.transferredFrames,\n });\n\n // Notify stakeholders of progress update\n await this.notifyProgressUpdate(requestId, progress);\n }\n\n /**\n * Notify stakeholders of progress updates\n */\n private async notifyProgressUpdate(\n requestId: string,\n progress: HandoffProgress\n ): Promise<void> {\n const updateNotification: HandoffNotification = {\n id: `${requestId}-progress-${Date.now()}`,\n type: 'request',\n requestId,\n recipientId: 'all',\n title: '\uD83D\uDCCA Handoff Progress Update',\n message: `Status: ${progress.status} | Step: ${progress.currentStep} | Progress: ${progress.transferredFrames}/${progress.totalFrames} frames`,\n actionRequired: false,\n createdAt: new Date(),\n };\n\n // Distribute to all stakeholders\n const allUsers = Array.from(this.notifications.keys());\n for (const userId of allUsers) {\n const userNotifications = this.notifications.get(userId) || [];\n userNotifications.push({\n ...updateNotification,\n id: `${requestId}-progress-${userId}-${Date.now()}`,\n recipientId: userId,\n });\n this.notifications.set(userId, userNotifications);\n }\n }\n\n /**\n * Get active handoffs with real-time filtering\n */\n async getActiveHandoffsRealTime(filters?: {\n status?: HandoffProgress['status'];\n userId?: string;\n priority?: 'low' | 'medium' | 'high' | 'critical';\n }): Promise<HandoffProgress[]> {\n let handoffs = Array.from(this.activeHandoffs.values());\n\n if (filters?.status) {\n handoffs = handoffs.filter((h) => h.status === filters.status);\n }\n\n if (filters?.userId) {\n // In a real implementation, we'd have proper user tracking in handoff metadata\n // For now, filter based on requestId pattern or other heuristics\n handoffs = handoffs.filter((h) =>\n h.requestId.includes(filters.userId || '')\n );\n }\n\n if (filters?.priority) {\n // Filter by priority (this would need priority tracking in HandoffProgress)\n // For now, estimate priority based on frame count and errors\n handoffs = handoffs.filter((h) => {\n const estimatedPriority = this.estimateHandoffPriority(h);\n return estimatedPriority === filters.priority;\n });\n }\n\n return handoffs.sort((a, b) => {\n // Sort by status priority, then by creation time\n const statusPriority = {\n in_transfer: 4,\n approved: 3,\n pending_review: 2,\n completed: 1,\n failed: 1,\n cancelled: 0,\n };\n return (statusPriority[b.status] || 0) - (statusPriority[a.status] || 0);\n });\n }\n\n private estimateHandoffPriority(\n handoff: HandoffProgress\n ): 'low' | 'medium' | 'high' | 'critical' {\n if (handoff.errors.length > 2 || handoff.totalFrames > 50)\n return 'critical';\n if (handoff.errors.length > 0 || handoff.totalFrames > 20) return 'high';\n if (handoff.totalFrames > 5) return 'medium';\n return 'low';\n }\n\n /**\n * Bulk handoff operations for team collaboration\n */\n async bulkHandoffOperation(operation: {\n action: 'approve' | 'reject' | 'cancel';\n requestIds: string[];\n reviewerId: string;\n feedback?: string;\n }): Promise<{\n successful: string[];\n failed: Array<{ requestId: string; error: string }>;\n }> {\n const results = {\n successful: [],\n failed: [] as Array<{ requestId: string; error: string }>,\n };\n\n for (const requestId of operation.requestIds) {\n try {\n switch (operation.action) {\n case 'approve':\n await this.submitHandoffApproval(requestId, {\n reviewerId: operation.reviewerId,\n decision: 'approved',\n feedback: operation.feedback,\n });\n results.successful.push(requestId);\n break;\n\n case 'reject':\n await this.submitHandoffApproval(requestId, {\n reviewerId: operation.reviewerId,\n decision: 'rejected',\n feedback: operation.feedback || 'Bulk rejection',\n });\n results.successful.push(requestId);\n break;\n\n case 'cancel':\n await this.cancelHandoff(\n requestId,\n operation.feedback || 'Bulk cancellation'\n );\n results.successful.push(requestId);\n break;\n }\n } catch (error) {\n results.failed.push({\n requestId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n logger.info(`Bulk handoff operation completed`, {\n action: operation.action,\n successful: results.successful.length,\n failed: results.failed.length,\n reviewerId: operation.reviewerId,\n });\n\n return results;\n }\n\n /**\n * Enhanced notification management with cleanup\n */\n async cleanupExpiredNotifications(userId?: string): Promise<number> {\n let cleanedCount = 0;\n const now = new Date();\n\n const userIds = userId ? [userId] : Array.from(this.notifications.keys());\n\n for (const uid of userIds) {\n const userNotifications = this.notifications.get(uid) || [];\n const activeNotifications = userNotifications.filter((notification) => {\n if (notification.expiresAt && notification.expiresAt < now) {\n cleanedCount++;\n return false;\n }\n return true;\n });\n\n this.notifications.set(uid, activeNotifications);\n }\n\n if (cleanedCount > 0) {\n logger.info(`Cleaned up expired notifications`, {\n count: cleanedCount,\n userId: userId || 'all',\n });\n }\n\n return cleanedCount;\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }