UNPKG

@semantest/chrome-extension

Version:

Browser extension for ChatGPT-buddy - AI automation extension built on Web-Buddy framework

427 lines (426 loc) 20.5 kB
// TypeScript-EDA Training Application // Application layer - orchestrates training system with @Enable decorators var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); var _, done = false; for (var i = decorators.length - 1; i >= 0; i--) { var context = {}; for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; for (var p in contextIn.access) context.access[p] = contextIn.access[p]; context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); if (kind === "accessor") { if (result === void 0) continue; if (result === null || typeof result !== "object") throw new TypeError("Object expected"); if (_ = accept(result.get)) descriptor.get = _; if (_ = accept(result.set)) descriptor.set = _; if (_ = accept(result.init)) initializers.unshift(_); } else if (_ = accept(result)) { if (kind === "field") initializers.unshift(_); else descriptor[key] = _; } } if (target) Object.defineProperty(target, contextIn.name, descriptor); done = true; }; var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { var useValue = arguments.length > 2; for (var i = 0; i < initializers.length; i++) { value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); } return useValue ? value : void 0; }; var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) { if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : ""; return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name }); }; import { Application, Enable } from 'typescript-eda'; import { TrainingSession } from '../domain/entities/training-session'; import { AutomationPattern } from '../domain/entities/automation-pattern'; import { UIOverlayAdapter } from '../infrastructure/ui-overlay-adapter'; import { PatternStorageAdapter } from '../infrastructure/pattern-storage-adapter'; import { PatternMatchingAdapter } from '../infrastructure/pattern-matching-adapter'; import { TrainingModeRequested, TrainingModeEnabled, TrainingModeDisabled, ElementSelectionRequested, ElementSelected, PatternLearned, AutomationPatternExecuted, PatternExecutionFailed, UserActionConfirmed, UserActionCancelled } from '../domain/events/training-events'; let ChatGPTBuddyTrainingApplication = (() => { let _classDecorators = [Enable(UIOverlayAdapter), Enable(PatternStorageAdapter), Enable(PatternMatchingAdapter), Enable(TrainingSession), Enable(AutomationPattern)]; let _classDescriptor; let _classExtraInitializers = []; let _classThis; let _classSuper = Application; var ChatGPTBuddyTrainingApplication = _classThis = class extends _classSuper { constructor() { super(); this.metadata = new Map([ ['name', 'ChatGPTBuddyTraining'], ['description', 'Interactive training system for automation learning'], ['version', '2.1.0'], ['domain-entities', [TrainingSession, AutomationPattern]], ['primary-ports', ['UIOverlayAdapter', 'PatternMatchingAdapter']], ['secondary-ports', ['PatternStorageAdapter']], ['events', [ 'TrainingModeRequested', 'ElementSelectionRequested', 'PatternLearningRequested', 'AutomationPatternMatched', 'UserActionConfirmed' ]] ]); this.currentSessionId = null; this.state = { isInitialized: false, currentSession: null, trainingMode: 'inactive', totalPatterns: 0, lastActivity: null }; // Initialize adapters this.uiAdapter = new UIOverlayAdapter(); this.storageAdapter = new PatternStorageAdapter(); this.matchingAdapter = new PatternMatchingAdapter(this.storageAdapter); // Setup adapter event handlers this.setupAdapterHandlers(); } // Application lifecycle async start() { if (this.state.isInitialized) { return; } try { // Initialize storage and load patterns const patterns = await this.storageAdapter.exportPatterns(); this.state = { ...this.state, isInitialized: true, totalPatterns: patterns.length, lastActivity: new Date() }; console.log('ChatGPT Buddy Training Application started', { totalPatterns: patterns.length, version: this.metadata.get('version') }); } catch (error) { console.error('Failed to start training application:', error); throw error; } } async stop() { if (!this.state.isInitialized) { return; } // End current training session if active if (this.state.currentSession) { await this.endCurrentSession('Application shutdown'); } // Hide any active UI await this.uiAdapter.hideGuidance(); this.state = { ...this.state, isInitialized: false, currentSession: null, trainingMode: 'inactive' }; console.log('ChatGPT Buddy Training Application stopped'); } // Main application event handlers async handleAutomationRequest(request) { this.updateLastActivity(); try { // Check if we have matching patterns in automatic mode if (this.state.trainingMode === 'automatic') { const matchedEvent = await this.matchingAdapter.handleAutomationRequest(request); if (matchedEvent) { return await this.executeMatchedPattern(matchedEvent); } } // If in training mode or no patterns found, request element selection if (this.state.trainingMode === 'training' || this.state.trainingMode === 'automatic') { return await this.requestElementSelection(request); } // If training is inactive, return failure return new PatternExecutionFailed('no-pattern', 'Training mode inactive and no matching patterns found', this.generateCorrelationId()); } catch (error) { console.error('Error handling automation request:', error); return new PatternExecutionFailed('error', `Application error: ${error.message}`, this.generateCorrelationId()); } } async enableTrainingMode(website) { this.updateLastActivity(); try { // Create new training session const sessionId = this.generateSessionId(); const session = new TrainingSession(sessionId); // Enable training mode const trainingEvent = new TrainingModeRequested(website, this.generateCorrelationId()); const result = await session.enableTrainingMode(trainingEvent); if (result instanceof TrainingModeEnabled) { this.state = { ...this.state, currentSession: session, trainingMode: 'training' }; this.currentSessionId = sessionId; console.log('Training mode enabled for website:', website); } return result; } catch (error) { console.error('Failed to enable training mode:', error); return new TrainingModeDisabled('error', `Failed to enable training mode: ${error.message}`, this.generateCorrelationId()); } } async disableTrainingMode(reason = 'User requested') { this.updateLastActivity(); if (!this.state.currentSession) { return null; } try { // End current session const endedEvent = await this.state.currentSession.endTrainingSession(reason, this.generateCorrelationId()); // Update state this.state = { ...this.state, currentSession: null, trainingMode: 'automatic' // Switch to automatic mode after training }; this.currentSessionId = null; // Hide any active UI await this.uiAdapter.hideGuidance(); console.log('Training mode disabled:', reason); return endedEvent; } catch (error) { console.error('Failed to disable training mode:', error); return null; } } async switchToAutomaticMode() { this.updateLastActivity(); // End training session if active if (this.state.currentSession) { await this.endCurrentSession('Switched to automatic mode'); } this.state = { ...this.state, trainingMode: 'automatic' }; console.log('Switched to automatic mode'); } // Pattern management async getPatternStatistics() { return await this.storageAdapter.getPatternStatistics(); } async cleanupStalePatterns(maxAgeInDays = 30) { const deletedCount = await this.storageAdapter.cleanupStalePatterns(maxAgeInDays); if (deletedCount > 0) { const stats = await this.getPatternStatistics(); this.state = { ...this.state, totalPatterns: stats.totalPatterns }; } return deletedCount; } async exportPatterns() { return await this.storageAdapter.exportPatterns(); } async importPatterns(patterns) { await this.storageAdapter.importPatterns(patterns); const stats = await this.getPatternStatistics(); this.state = { ...this.state, totalPatterns: stats.totalPatterns }; } // State getters getState() { return { ...this.state }; } isTrainingMode() { return this.state.trainingMode === 'training'; } isAutomaticMode() { return this.state.trainingMode === 'automatic'; } getCurrentSession() { return this.state.currentSession; } // Private methods async requestElementSelection(request) { if (!this.state.currentSession) { throw new Error('No active training session'); } const elementSelectionEvent = new ElementSelectionRequested(request.messageType, this.extractElementDescription(request), request.context, this.generateCorrelationId()); // Request element selection from training session const guidanceEvent = await this.state.currentSession.requestElementSelection(elementSelectionEvent); // Show UI guidance await this.uiAdapter.showGuidance(guidanceEvent.guidance); return elementSelectionEvent; } async executeMatchedPattern(matchedEvent) { try { // Create AutomationPattern entity const patternEntity = new AutomationPattern(matchedEvent.pattern); // Execute the pattern const result = await patternEntity.executePattern(matchedEvent); // Update pattern statistics if (result instanceof AutomationPatternExecuted) { await this.matchingAdapter.updatePatternStatistics(matchedEvent.pattern.id, result.executionResult); } return result; } catch (error) { console.error('Pattern execution failed:', error); return new PatternExecutionFailed(matchedEvent.pattern.id, `Execution failed: ${error.message}`, matchedEvent.correlationId); } } setupAdapterHandlers() { // UI adapter event handlers this.uiAdapter.onElementSelectionEvent(async (element, selector) => { if (this.state.currentSession) { await this.handleElementSelection(element, selector); } }); this.uiAdapter.onUserConfirmationEvent(async (action, selector) => { if (this.state.currentSession) { await this.handleUserConfirmation(action, selector); } }); this.uiAdapter.onUserCancellationEvent(async (action, reason) => { if (this.state.currentSession) { await this.handleUserCancellation(action, reason); } }); } async handleElementSelection(element, selector) { if (!this.state.currentSession) return; try { const elementSelectedEvent = new ElementSelected(element, selector, 'unknown', // Will be determined from context this.getCurrentContext(), this.generateCorrelationId()); // Process element selection through training session const result = await this.state.currentSession.learnPattern(elementSelectedEvent); if (result instanceof PatternLearned) { // Store the pattern await this.storageAdapter.storePattern(result.pattern); // Update total patterns count const stats = await this.getPatternStatistics(); this.state = { ...this.state, totalPatterns: stats.totalPatterns }; console.log('Pattern learned and stored:', result.pattern.id); } else { console.error('Pattern learning failed:', result.reason); } } catch (error) { console.error('Error handling element selection:', error); } } async handleUserConfirmation(action, selector) { if (!this.state.currentSession) return; const confirmationEvent = new UserActionConfirmed(action, selector, this.generateCorrelationId()); await this.state.currentSession.handleUserConfirmation(confirmationEvent); await this.uiAdapter.hideGuidance(); } async handleUserCancellation(action, reason) { if (!this.state.currentSession) return; const cancellationEvent = new UserActionCancelled(action, reason, this.generateCorrelationId()); await this.state.currentSession.handleUserCancellation(cancellationEvent); await this.uiAdapter.hideGuidance(); } async endCurrentSession(reason) { if (!this.state.currentSession) return; try { await this.state.currentSession.endTrainingSession(reason, this.generateCorrelationId()); this.state = { ...this.state, currentSession: null }; this.currentSessionId = null; } catch (error) { console.error('Error ending training session:', error); } } extractElementDescription(request) { if (request.payload.element) { return request.payload.element; } // Generate description based on message type and context switch (request.messageType) { case 'FillTextRequested': return 'text input field'; case 'ClickElementRequested': return 'clickable element'; case 'SelectProjectRequested': return 'project selector'; case 'SelectChatRequested': return 'chat selector'; default: return 'page element'; } } getCurrentContext() { return { url: typeof window !== 'undefined' ? window.location.href : 'unknown', hostname: typeof window !== 'undefined' ? window.location.hostname : 'unknown', pathname: typeof window !== 'undefined' ? window.location.pathname : 'unknown', title: typeof document !== 'undefined' ? document.title : 'unknown', timestamp: new Date(), pageStructureHash: this.generatePageStructureHash() }; } generatePageStructureHash() { if (typeof document === 'undefined') return 'unknown'; const elements = document.querySelectorAll('div, input, button, a, form'); const structure = Array.from(elements) .slice(0, 25) // Sample first 25 elements .map(el => `${el.tagName}${el.id ? '#' + el.id : ''}${el.className ? '.' + el.className.split(' ')[0] : ''}`) .join('|'); // Simple hash function let hash = 0; for (let i = 0; i < structure.length; i++) { const char = structure.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash & hash; // Convert to 32-bit integer } return hash.toString(36); } updateLastActivity() { this.state = { ...this.state, lastActivity: new Date() }; } generateSessionId() { return `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; } generateCorrelationId() { return `app-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; } }; __setFunctionName(_classThis, "ChatGPTBuddyTrainingApplication"); (() => { const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); ChatGPTBuddyTrainingApplication = _classThis = _classDescriptor.value; if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); __runInitializers(_classThis, _classExtraInitializers); })(); return ChatGPTBuddyTrainingApplication = _classThis; })(); export { ChatGPTBuddyTrainingApplication }; // Export singleton instance for use in browser extension export const trainingApplication = new ChatGPTBuddyTrainingApplication();