mirror of
				https://gitcode.com/github-mirrors/react-native-update-cli.git
				synced 2025-10-31 14:53:11 +08:00 
			
		
		
		
	cli modular refactor (#16)
* add logic to support SENTRY_PROPERTIES parameter * remove update.json and meta.json files in ppk * udpapte * refactor modles * update * add package-module file * update * update readme file * modifu cli.json file * fix command issues * improve version workflow logic * udpate * update * update * update * udpate * udpate * add example * update readme file * udpate version * change logic to use pushy command uniformly
This commit is contained in:
		
							
								
								
									
										205
									
								
								src/modules/app-module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										205
									
								
								src/modules/app-module.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,205 @@ | ||||
| import { appCommands } from '../app'; | ||||
| import type { CLIModule, CommandContext } from '../types'; | ||||
|  | ||||
| export const appModule: CLIModule = { | ||||
|   name: 'app', | ||||
|   version: '1.0.0', | ||||
|  | ||||
|   commands: [], | ||||
|  | ||||
|   workflows: [ | ||||
|     { | ||||
|       name: 'setup-app', | ||||
|       description: 'Setup a new app with initial configuration', | ||||
|       steps: [ | ||||
|         { | ||||
|           name: 'create', | ||||
|           description: 'Create the app', | ||||
|           execute: async (context: CommandContext) => { | ||||
|             console.log('Creating app in workflow'); | ||||
|             const { name, downloadUrl, platform } = context.options; | ||||
|             await appCommands.createApp({ | ||||
|               options: { | ||||
|                 name: name || '', | ||||
|                 downloadUrl: downloadUrl || '', | ||||
|                 platform: platform || '', | ||||
|               }, | ||||
|             }); | ||||
|             return { appCreated: true }; | ||||
|           }, | ||||
|         }, | ||||
|         { | ||||
|           name: 'select', | ||||
|           description: 'Select the created app', | ||||
|           execute: async (context: CommandContext, previousResult: any) => { | ||||
|             console.log('Selecting app in workflow'); | ||||
|             const { platform } = context.options; | ||||
|             await appCommands.selectApp({ | ||||
|               args: [], | ||||
|               options: { platform: platform || '' }, | ||||
|             }); | ||||
|             return { ...previousResult, appSelected: true }; | ||||
|           }, | ||||
|         }, | ||||
|       ], | ||||
|     }, | ||||
|     { | ||||
|       name: 'manage-apps', | ||||
|       description: 'Manage multiple apps', | ||||
|       steps: [ | ||||
|         { | ||||
|           name: 'list-apps', | ||||
|           description: 'List all apps', | ||||
|           execute: async (context: CommandContext) => { | ||||
|             console.log('Listing all apps'); | ||||
|             const { platform } = context.options; | ||||
|             await appCommands.apps({ | ||||
|               options: { platform: platform || '' }, | ||||
|             }); | ||||
|             return { appsListed: true }; | ||||
|           }, | ||||
|         }, | ||||
|         { | ||||
|           name: 'select-target-app', | ||||
|           description: 'Select target app for operations', | ||||
|           execute: async (context: CommandContext, previousResult: any) => { | ||||
|             console.log('Selecting target app'); | ||||
|             const { platform } = context.options; | ||||
|             await appCommands.selectApp({ | ||||
|               args: [], | ||||
|               options: { platform: platform || '' }, | ||||
|             }); | ||||
|             return { ...previousResult, targetAppSelected: true }; | ||||
|           }, | ||||
|         }, | ||||
|       ], | ||||
|     }, | ||||
|     { | ||||
|       name: 'multi-platform-app-management', | ||||
|       description: 'Multi-platform app unified management workflow', | ||||
|       steps: [ | ||||
|         { | ||||
|           name: 'scan-platforms', | ||||
|           description: 'Scan apps on all platforms', | ||||
|           execute: async (context: CommandContext) => { | ||||
|             console.log('🔍 Scanning apps on all platforms...'); | ||||
|  | ||||
|             const platforms = ['ios', 'android', 'harmony']; | ||||
|             const appsData = {}; | ||||
|  | ||||
|             for (const platform of platforms) { | ||||
|               console.log(`  Scanning ${platform} platform...`); | ||||
|  | ||||
|               // Simulate getting app list | ||||
|               await new Promise((resolve) => setTimeout(resolve, 500)); | ||||
|  | ||||
|               const appCount = Math.floor(Math.random() * 5) + 1; | ||||
|               const apps = Array.from({ length: appCount }, (_, i) => ({ | ||||
|                 id: `${platform}_app_${i + 1}`, | ||||
|                 name: `App ${i + 1}`, | ||||
|                 platform, | ||||
|                 version: `1.${i}.0`, | ||||
|                 status: Math.random() > 0.2 ? 'active' : 'inactive', | ||||
|               })); | ||||
|  | ||||
|               appsData[platform] = apps; | ||||
|               console.log(`    ✅ Found ${appCount} apps`); | ||||
|             } | ||||
|  | ||||
|             console.log('✅ Platform scanning completed'); | ||||
|  | ||||
|             return { platforms, appsData, scanned: true }; | ||||
|           }, | ||||
|         }, | ||||
|         { | ||||
|           name: 'analyze-apps', | ||||
|           description: 'Analyze app status', | ||||
|           execute: async (context: CommandContext, previousResult: any) => { | ||||
|             console.log('📊 Analyzing app status...'); | ||||
|  | ||||
|             const { appsData } = previousResult; | ||||
|             const analysis = { | ||||
|               totalApps: 0, | ||||
|               activeApps: 0, | ||||
|               inactiveApps: 0, | ||||
|               platformDistribution: {}, | ||||
|               issues: [], | ||||
|             }; | ||||
|  | ||||
|             for (const [platform, apps] of Object.entries(appsData)) { | ||||
|               const platformApps = apps as any[]; | ||||
|               analysis.totalApps += platformApps.length; | ||||
|               analysis.platformDistribution[platform] = platformApps.length; | ||||
|  | ||||
|               for (const app of platformApps) { | ||||
|                 if (app.status === 'active') { | ||||
|                   analysis.activeApps++; | ||||
|                 } else { | ||||
|                   analysis.inactiveApps++; | ||||
|                   analysis.issues.push( | ||||
|                     `${platform}/${app.name}: App is inactive`, | ||||
|                   ); | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|  | ||||
|             console.log('📈 Analysis results:'); | ||||
|             console.log(`  Total apps: ${analysis.totalApps}`); | ||||
|             console.log(`  Active apps: ${analysis.activeApps}`); | ||||
|             console.log(`  Inactive apps: ${analysis.inactiveApps}`); | ||||
|  | ||||
|             if (analysis.issues.length > 0) { | ||||
|               console.log('⚠️ Issues found:'); | ||||
|               analysis.issues.forEach((issue) => console.log(`    - ${issue}`)); | ||||
|             } | ||||
|  | ||||
|             return { ...previousResult, analysis }; | ||||
|           }, | ||||
|         }, | ||||
|         { | ||||
|           name: 'optimize-apps', | ||||
|           description: 'Optimize app configuration', | ||||
|           execute: async (context: CommandContext, previousResult: any) => { | ||||
|             console.log('⚡ Optimizing app configuration...'); | ||||
|  | ||||
|             const { analysis } = previousResult; | ||||
|             const optimizations = []; | ||||
|  | ||||
|             if (analysis.inactiveApps > 0) { | ||||
|               console.log('  Handling inactive apps...'); | ||||
|               optimizations.push('Reactivate inactive apps'); | ||||
|             } | ||||
|  | ||||
|             if (analysis.totalApps > 10) { | ||||
|               console.log('  Many apps detected, suggest grouping...'); | ||||
|               optimizations.push('Create app groups'); | ||||
|             } | ||||
|  | ||||
|             // Simulate optimization process | ||||
|             for (const optimization of optimizations) { | ||||
|               console.log(`    Executing: ${optimization}...`); | ||||
|               await new Promise((resolve) => setTimeout(resolve, 800)); | ||||
|               console.log(`    ✅ ${optimization} completed`); | ||||
|             } | ||||
|  | ||||
|             console.log('✅ App optimization completed'); | ||||
|  | ||||
|             return { ...previousResult, optimizations, optimized: true }; | ||||
|           }, | ||||
|         }, | ||||
|       ], | ||||
|       options: { | ||||
|         includeInactive: { | ||||
|           hasValue: false, | ||||
|           default: true, | ||||
|           description: 'Include inactive apps', | ||||
|         }, | ||||
|         autoOptimize: { | ||||
|           hasValue: false, | ||||
|           default: true, | ||||
|           description: 'Auto optimize configuration', | ||||
|         }, | ||||
|       }, | ||||
|     }, | ||||
|   ], | ||||
| }; | ||||
							
								
								
									
										202
									
								
								src/modules/bundle-module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								src/modules/bundle-module.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,202 @@ | ||||
| import { bundleCommands } from '../bundle'; | ||||
| import type { CLIModule, CommandContext } from '../types'; | ||||
|  | ||||
| export const bundleModule: CLIModule = { | ||||
|   name: 'bundle', | ||||
|   version: '1.0.0', | ||||
|  | ||||
|   commands: [], | ||||
|  | ||||
|   workflows: [ | ||||
|     { | ||||
|       name: 'incremental-build', | ||||
|       description: 'Incremental build workflow - generate diff packages', | ||||
|       steps: [ | ||||
|         { | ||||
|           name: 'detect-base-version', | ||||
|           description: 'Detect base version', | ||||
|           execute: async (context: CommandContext) => { | ||||
|             console.log('🔍 Detecting base version...'); | ||||
|  | ||||
|             const { baseVersion, platform } = context.options; | ||||
|  | ||||
|             if (baseVersion) { | ||||
|               console.log(`✅ Using specified base version: ${baseVersion}`); | ||||
|               return { baseVersion, specified: true }; | ||||
|             } | ||||
|  | ||||
|             console.log('Auto detecting latest version...'); | ||||
|             await new Promise((resolve) => setTimeout(resolve, 800)); | ||||
|  | ||||
|             const autoDetectedVersion = `v${Math.floor(Math.random() * 3) + 1}.${Math.floor(Math.random() * 10)}.${Math.floor(Math.random() * 10)}`; | ||||
|  | ||||
|             console.log( | ||||
|               `✅ Auto detected base version: ${autoDetectedVersion}`, | ||||
|             ); | ||||
|  | ||||
|             return { baseVersion: autoDetectedVersion, specified: false }; | ||||
|           }, | ||||
|         }, | ||||
|         { | ||||
|           name: 'build-current-version', | ||||
|           description: 'Build current version', | ||||
|           execute: async (context: CommandContext, previousResult: any) => { | ||||
|             console.log('🏗️ Building current version...'); | ||||
|  | ||||
|             const { | ||||
|               platform, | ||||
|               dev = false, | ||||
|               sourcemap = false, | ||||
|               bundleName = 'index.bundlejs', | ||||
|               entryFile = 'index.js', | ||||
|               intermediaDir, | ||||
|               taro = false, | ||||
|               expo = false, | ||||
|               rncli = false, | ||||
|               disableHermes = false, | ||||
|               output, | ||||
|             } = context.options; | ||||
|  | ||||
|             console.log(`Building ${platform} platform...`); | ||||
|             console.log(`  Entry file: ${entryFile}`); | ||||
|             console.log(`  Bundle name: ${bundleName}`); | ||||
|             console.log(`  Development mode: ${dev}`); | ||||
|             console.log(`  Source maps: ${sourcemap}`); | ||||
|  | ||||
|             try { | ||||
|               const buildOptions: any = { | ||||
|                 platform, | ||||
|                 dev, | ||||
|                 sourcemap, | ||||
|                 bundleName, | ||||
|                 entryFile, | ||||
|                 taro, | ||||
|                 expo, | ||||
|                 rncli, | ||||
|                 disableHermes, | ||||
|                 intermediaDir: '${tempDir}/intermedia/${platform}', | ||||
|                 output: '${tempDir}/output/${platform}.${time}.ppk', | ||||
|               }; | ||||
|               if (intermediaDir) { | ||||
|                 buildOptions.intermediaDir = intermediaDir; | ||||
|               } | ||||
|  | ||||
|               await bundleCommands.bundle({ | ||||
|                 args: [], | ||||
|                 options: buildOptions, | ||||
|               }); | ||||
|  | ||||
|               const currentBuild = { | ||||
|                 version: `v${Math.floor(Math.random() * 3) + 2}.0.0`, | ||||
|                 platform, | ||||
|                 bundlePath: `./build/current_${platform}.ppk`, | ||||
|                 size: Math.floor(Math.random() * 15) + 10, | ||||
|                 buildTime: Date.now(), | ||||
|               }; | ||||
|  | ||||
|               console.log( | ||||
|                 `✅ Current version build completed: ${currentBuild.version}`, | ||||
|               ); | ||||
|  | ||||
|               return { ...previousResult, currentBuild }; | ||||
|             } catch (error) { | ||||
|               console.error('❌ Current version build failed:', error); | ||||
|               throw error; | ||||
|             } | ||||
|           }, | ||||
|         }, | ||||
|       ], | ||||
|       validate: (context: CommandContext) => { | ||||
|         if (!context.options.platform) { | ||||
|           console.error('❌ Incremental build requires platform specification'); | ||||
|           return false; | ||||
|         } | ||||
|         return true; | ||||
|       }, | ||||
|       options: { | ||||
|         platform: { | ||||
|           hasValue: true, | ||||
|           description: 'Target platform (required)', | ||||
|         }, | ||||
|         baseVersion: { | ||||
|           hasValue: true, | ||||
|           description: 'Base version (auto detect if not specified)', | ||||
|         }, | ||||
|         skipValidation: { | ||||
|           hasValue: false, | ||||
|           default: false, | ||||
|           description: 'Skip diff package validation', | ||||
|         }, | ||||
|         dev: { | ||||
|           hasValue: false, | ||||
|           default: false, | ||||
|           description: 'Development mode build', | ||||
|         }, | ||||
|         bundleName: { | ||||
|           hasValue: true, | ||||
|           default: 'index.bundlejs', | ||||
|           description: 'Bundle file name', | ||||
|         }, | ||||
|         entryFile: { | ||||
|           hasValue: true, | ||||
|           default: 'index.js', | ||||
|           description: 'Entry file', | ||||
|         }, | ||||
|         sourcemap: { | ||||
|           hasValue: false, | ||||
|           default: false, | ||||
|           description: 'Generate source maps', | ||||
|         }, | ||||
|         output: { | ||||
|           hasValue: true, | ||||
|           description: 'Custom output path for diff package', | ||||
|         }, | ||||
|         intermediaDir: { | ||||
|           hasValue: true, | ||||
|           description: 'Intermediate directory', | ||||
|         }, | ||||
|         taro: { | ||||
|           hasValue: false, | ||||
|           default: false, | ||||
|           description: 'Use Taro CLI', | ||||
|         }, | ||||
|         expo: { | ||||
|           hasValue: false, | ||||
|           default: false, | ||||
|           description: 'Use Expo CLI', | ||||
|         }, | ||||
|         rncli: { | ||||
|           hasValue: false, | ||||
|           default: false, | ||||
|           description: 'Use React Native CLI', | ||||
|         }, | ||||
|         disableHermes: { | ||||
|           hasValue: false, | ||||
|           default: false, | ||||
|           description: 'Disable Hermes', | ||||
|         }, | ||||
|         name: { | ||||
|           hasValue: true, | ||||
|           description: 'Version name for publishing', | ||||
|         }, | ||||
|         description: { | ||||
|           hasValue: true, | ||||
|           description: 'Version description for publishing', | ||||
|         }, | ||||
|         metaInfo: { | ||||
|           hasValue: true, | ||||
|           description: 'Meta information for publishing', | ||||
|         }, | ||||
|         rollout: { | ||||
|           hasValue: true, | ||||
|           description: 'Rollout percentage', | ||||
|         }, | ||||
|         dryRun: { | ||||
|           hasValue: false, | ||||
|           default: false, | ||||
|           description: 'Dry run mode', | ||||
|         }, | ||||
|       }, | ||||
|     }, | ||||
|   ], | ||||
| }; | ||||
							
								
								
									
										19
									
								
								src/modules/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/modules/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| import { appModule } from './app-module'; | ||||
| import { bundleModule } from './bundle-module'; | ||||
| import { packageModule } from './package-module'; | ||||
| import { userModule } from './user-module'; | ||||
| import { versionModule } from './version-module'; | ||||
|  | ||||
| export { bundleModule } from './bundle-module'; | ||||
| export { versionModule } from './version-module'; | ||||
| export { appModule } from './app-module'; | ||||
| export { userModule } from './user-module'; | ||||
| export { packageModule } from './package-module'; | ||||
|  | ||||
| export const builtinModules = [ | ||||
|   bundleModule, | ||||
|   versionModule, | ||||
|   appModule, | ||||
|   userModule, | ||||
|   packageModule, | ||||
| ]; | ||||
							
								
								
									
										11
									
								
								src/modules/package-module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/modules/package-module.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| import { packageCommands } from '../package'; | ||||
| import type { CLIModule } from '../types'; | ||||
|  | ||||
| export const packageModule: CLIModule = { | ||||
|   name: 'package', | ||||
|   version: '1.0.0', | ||||
|  | ||||
|   commands: [], | ||||
|  | ||||
|   workflows: [], | ||||
| }; | ||||
							
								
								
									
										406
									
								
								src/modules/user-module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										406
									
								
								src/modules/user-module.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,406 @@ | ||||
| import { getSession, loadSession } from '../api'; | ||||
| import type { CLIModule, CommandContext } from '../types'; | ||||
| import { userCommands } from '../user'; | ||||
|  | ||||
| export const userModule: CLIModule = { | ||||
|   name: 'user', | ||||
|   version: '1.0.0', | ||||
|  | ||||
|   commands: [], | ||||
|  | ||||
|   workflows: [ | ||||
|     { | ||||
|       name: 'auth-check', | ||||
|       description: 'Check authentication status and user information', | ||||
|       options: { | ||||
|         autoLogin: { | ||||
|           default: false, | ||||
|           description: 'Automatically login if not authenticated', | ||||
|         }, | ||||
|         showDetails: { | ||||
|           default: true, | ||||
|           description: 'Show detailed user information', | ||||
|         }, | ||||
|       }, | ||||
|       steps: [ | ||||
|         { | ||||
|           name: 'load-session', | ||||
|           description: 'Load existing session from local storage', | ||||
|           execute: async (context: CommandContext) => { | ||||
|             console.log('Loading session from local storage...'); | ||||
|  | ||||
|             try { | ||||
|               await loadSession(); | ||||
|               const session = getSession(); | ||||
|  | ||||
|               if (session && session.token) { | ||||
|                 console.log('✓ Session found in local storage'); | ||||
|                 return { | ||||
|                   sessionLoaded: true, | ||||
|                   hasToken: true, | ||||
|                   session, | ||||
|                 }; | ||||
|               } else { | ||||
|                 console.log('✗ No valid session found in local storage'); | ||||
|                 return { | ||||
|                   sessionLoaded: true, | ||||
|                   hasToken: false, | ||||
|                   session: null, | ||||
|                 }; | ||||
|               } | ||||
|             } catch (error) { | ||||
|               console.log( | ||||
|                 '✗ Failed to load session:', | ||||
|                 error instanceof Error ? error.message : 'Unknown error', | ||||
|               ); | ||||
|               return { | ||||
|                 sessionLoaded: false, | ||||
|                 hasToken: false, | ||||
|                 session: null, | ||||
|                 error: error instanceof Error ? error.message : 'Unknown error', | ||||
|               }; | ||||
|             } | ||||
|           }, | ||||
|         }, | ||||
|         { | ||||
|           name: 'validate-session', | ||||
|           description: 'Validate session by calling API', | ||||
|           execute: async (context: CommandContext, previousResult: any) => { | ||||
|             if (!previousResult.hasToken) { | ||||
|               console.log('No token available, skipping validation'); | ||||
|               return { | ||||
|                 ...previousResult, | ||||
|                 validated: false, | ||||
|                 reason: 'No token available', | ||||
|               }; | ||||
|             } | ||||
|  | ||||
|             console.log('Validating session with server...'); | ||||
|  | ||||
|             try { | ||||
|               await userCommands.me(); | ||||
|               console.log('✓ Session is valid'); | ||||
|               return { | ||||
|                 ...previousResult, | ||||
|                 validated: true, | ||||
|                 reason: 'Session validated successfully', | ||||
|               }; | ||||
|             } catch (error) { | ||||
|               console.log( | ||||
|                 '✗ Session validation failed:', | ||||
|                 error instanceof Error ? error.message : 'Unknown error', | ||||
|               ); | ||||
|               return { | ||||
|                 ...previousResult, | ||||
|                 validated: false, | ||||
|                 reason: | ||||
|                   error instanceof Error ? error.message : 'Unknown error', | ||||
|               }; | ||||
|             } | ||||
|           }, | ||||
|         }, | ||||
|         { | ||||
|           name: 'get-user-info', | ||||
|           description: 'Get current user information', | ||||
|           execute: async (context: CommandContext, previousResult: any) => { | ||||
|             if (!previousResult.validated) { | ||||
|               console.log('Session not valid, cannot get user info'); | ||||
|               return { | ||||
|                 ...previousResult, | ||||
|                 userInfo: null, | ||||
|                 reason: 'Session not valid', | ||||
|               }; | ||||
|             } | ||||
|  | ||||
|             console.log('Getting user information...'); | ||||
|  | ||||
|             try { | ||||
|               const { get } = await import('../api'); | ||||
|               const userInfo = await get('/user/me'); | ||||
|  | ||||
|               console.log('✓ User information retrieved successfully'); | ||||
|  | ||||
|               if (context.options.showDetails !== false) { | ||||
|                 console.log('\n=== User Information ==='); | ||||
|                 for (const [key, value] of Object.entries(userInfo)) { | ||||
|                   if (key !== 'ok') { | ||||
|                     console.log(`${key}: ${value}`); | ||||
|                   } | ||||
|                 } | ||||
|                 console.log('========================\n'); | ||||
|               } | ||||
|  | ||||
|               return { | ||||
|                 ...previousResult, | ||||
|                 userInfo, | ||||
|                 reason: 'User info retrieved successfully', | ||||
|               }; | ||||
|             } catch (error) { | ||||
|               console.log( | ||||
|                 '✗ Failed to get user info:', | ||||
|                 error instanceof Error ? error.message : 'Unknown error', | ||||
|               ); | ||||
|               return { | ||||
|                 ...previousResult, | ||||
|                 userInfo: null, | ||||
|                 reason: | ||||
|                   error instanceof Error ? error.message : 'Unknown error', | ||||
|               }; | ||||
|             } | ||||
|           }, | ||||
|         }, | ||||
|         { | ||||
|           name: 'handle-auth-failure', | ||||
|           description: 'Handle authentication failure', | ||||
|           execute: async (context: CommandContext, previousResult: any) => { | ||||
|             if (previousResult.validated) { | ||||
|               console.log('✓ Authentication check completed successfully'); | ||||
|               return { | ||||
|                 ...previousResult, | ||||
|                 authCheckComplete: true, | ||||
|                 status: 'authenticated', | ||||
|               }; | ||||
|             } | ||||
|  | ||||
|             console.log('✗ Authentication check failed'); | ||||
|  | ||||
|             if (context.options.autoLogin) { | ||||
|               console.log('Attempting automatic login...'); | ||||
|               try { | ||||
|                 await userCommands.login({ args: [] }); | ||||
|                 console.log('✓ Automatic login successful'); | ||||
|                 return { | ||||
|                   ...previousResult, | ||||
|                   authCheckComplete: true, | ||||
|                   status: 'auto-logged-in', | ||||
|                   autoLoginSuccess: true, | ||||
|                 }; | ||||
|               } catch (error) { | ||||
|                 console.log( | ||||
|                   '✗ Automatic login failed:', | ||||
|                   error instanceof Error ? error.message : 'Unknown error', | ||||
|                 ); | ||||
|                 return { | ||||
|                   ...previousResult, | ||||
|                   authCheckComplete: true, | ||||
|                   status: 'failed', | ||||
|                   autoLoginSuccess: false, | ||||
|                   autoLoginError: | ||||
|                     error instanceof Error ? error.message : 'Unknown error', | ||||
|                 }; | ||||
|               } | ||||
|             } else { | ||||
|               console.log('Please run login command to authenticate'); | ||||
|               return { | ||||
|                 ...previousResult, | ||||
|                 authCheckComplete: true, | ||||
|                 status: 'unauthenticated', | ||||
|                 suggestion: 'Run login command to authenticate', | ||||
|               }; | ||||
|             } | ||||
|           }, | ||||
|         }, | ||||
|       ], | ||||
|     }, | ||||
|     { | ||||
|       name: 'login-flow', | ||||
|       description: 'Complete login flow with validation', | ||||
|       options: { | ||||
|         email: { hasValue: true, description: 'User email' }, | ||||
|         password: { hasValue: true, description: 'User password' }, | ||||
|         validateAfterLogin: { | ||||
|           default: true, | ||||
|           description: 'Validate session after login', | ||||
|         }, | ||||
|       }, | ||||
|       steps: [ | ||||
|         { | ||||
|           name: 'check-existing-session', | ||||
|           description: 'Check if user is already logged in', | ||||
|           execute: async (context: CommandContext) => { | ||||
|             console.log('Checking existing session...'); | ||||
|  | ||||
|             try { | ||||
|               await loadSession(); | ||||
|               const session = getSession(); | ||||
|  | ||||
|               if (session && session.token) { | ||||
|                 try { | ||||
|                   await userCommands.me(); | ||||
|                   console.log('✓ User is already logged in'); | ||||
|                   return { | ||||
|                     alreadyLoggedIn: true, | ||||
|                     session: session, | ||||
|                     status: 'authenticated', | ||||
|                   }; | ||||
|                 } catch (error) { | ||||
|                   console.log( | ||||
|                     '✗ Existing session is invalid, proceeding with login', | ||||
|                   ); | ||||
|                   return { | ||||
|                     alreadyLoggedIn: false, | ||||
|                     session: null, | ||||
|                     status: 'session-expired', | ||||
|                   }; | ||||
|                 } | ||||
|               } else { | ||||
|                 console.log('No existing session found'); | ||||
|                 return { | ||||
|                   alreadyLoggedIn: false, | ||||
|                   session: null, | ||||
|                   status: 'no-session', | ||||
|                 }; | ||||
|               } | ||||
|             } catch (error) { | ||||
|               console.log( | ||||
|                 'Error checking existing session:', | ||||
|                 error instanceof Error ? error.message : 'Unknown error', | ||||
|               ); | ||||
|               return { | ||||
|                 alreadyLoggedIn: false, | ||||
|                 session: null, | ||||
|                 status: 'error', | ||||
|                 error: error instanceof Error ? error.message : 'Unknown error', | ||||
|               }; | ||||
|             } | ||||
|           }, | ||||
|         }, | ||||
|         { | ||||
|           name: 'perform-login', | ||||
|           description: 'Perform user login', | ||||
|           execute: async (context: CommandContext, previousResult: any) => { | ||||
|             if (previousResult.alreadyLoggedIn) { | ||||
|               console.log('Skipping login - user already authenticated'); | ||||
|               return { | ||||
|                 ...previousResult, | ||||
|                 loginPerformed: false, | ||||
|                 loginSuccess: true, | ||||
|               }; | ||||
|             } | ||||
|  | ||||
|             console.log('Performing login...'); | ||||
|  | ||||
|             try { | ||||
|               const loginArgs = []; | ||||
|               if (context.options.email) { | ||||
|                 loginArgs.push(context.options.email); | ||||
|               } | ||||
|               if (context.options.password) { | ||||
|                 loginArgs.push(context.options.password); | ||||
|               } | ||||
|  | ||||
|               await userCommands.login({ args: loginArgs }); | ||||
|               console.log('✓ Login successful'); | ||||
|  | ||||
|               return { | ||||
|                 ...previousResult, | ||||
|                 loginPerformed: true, | ||||
|                 loginSuccess: true, | ||||
|               }; | ||||
|             } catch (error) { | ||||
|               console.log( | ||||
|                 '✗ Login failed:', | ||||
|                 error instanceof Error ? error.message : 'Unknown error', | ||||
|               ); | ||||
|               return { | ||||
|                 ...previousResult, | ||||
|                 loginPerformed: true, | ||||
|                 loginSuccess: false, | ||||
|                 loginError: | ||||
|                   error instanceof Error ? error.message : 'Unknown error', | ||||
|               }; | ||||
|             } | ||||
|           }, | ||||
|         }, | ||||
|         { | ||||
|           name: 'validate-login', | ||||
|           description: 'Validate login by getting user info', | ||||
|           execute: async (context: CommandContext, previousResult: any) => { | ||||
|             if ( | ||||
|               !previousResult.loginSuccess && | ||||
|               !previousResult.alreadyLoggedIn | ||||
|             ) { | ||||
|               console.log('Login failed, skipping validation'); | ||||
|               return { | ||||
|                 ...previousResult, | ||||
|                 validationPerformed: false, | ||||
|                 validationSuccess: false, | ||||
|               }; | ||||
|             } | ||||
|  | ||||
|             if (context.options.validateAfterLogin === false) { | ||||
|               console.log('Skipping validation as requested'); | ||||
|               return { | ||||
|                 ...previousResult, | ||||
|                 validationPerformed: false, | ||||
|                 validationSuccess: true, | ||||
|               }; | ||||
|             } | ||||
|  | ||||
|             console.log('Validating login by getting user information...'); | ||||
|  | ||||
|             try { | ||||
|               const userInfo = await userCommands.me(); | ||||
|               console.log('✓ Login validation successful'); | ||||
|  | ||||
|               return { | ||||
|                 ...previousResult, | ||||
|                 validationPerformed: true, | ||||
|                 validationSuccess: true, | ||||
|                 userInfo, | ||||
|               }; | ||||
|             } catch (error) { | ||||
|               console.log( | ||||
|                 '✗ Login validation failed:', | ||||
|                 error instanceof Error ? error.message : 'Unknown error', | ||||
|               ); | ||||
|               return { | ||||
|                 ...previousResult, | ||||
|                 validationPerformed: true, | ||||
|                 validationSuccess: false, | ||||
|                 validationError: | ||||
|                   error instanceof Error ? error.message : 'Unknown error', | ||||
|               }; | ||||
|             } | ||||
|           }, | ||||
|         }, | ||||
|         { | ||||
|           name: 'login-summary', | ||||
|           description: 'Provide login flow summary', | ||||
|           execute: async (context: CommandContext, previousResult: any) => { | ||||
|             console.log('\n=== Login Flow Summary ==='); | ||||
|  | ||||
|             if (previousResult.alreadyLoggedIn) { | ||||
|               console.log('Status: Already logged in'); | ||||
|               console.log('Session: Valid'); | ||||
|             } else if (previousResult.loginSuccess) { | ||||
|               console.log('Status: Login successful'); | ||||
|               if (previousResult.validationSuccess) { | ||||
|                 console.log('Validation: Passed'); | ||||
|               } else { | ||||
|                 console.log('Validation: Failed'); | ||||
|               } | ||||
|             } else { | ||||
|               console.log('Status: Login failed'); | ||||
|               console.log( | ||||
|                 'Error:', | ||||
|                 previousResult.loginError || 'Unknown error', | ||||
|               ); | ||||
|             } | ||||
|  | ||||
|             console.log('==========================\n'); | ||||
|  | ||||
|             return { | ||||
|               ...previousResult, | ||||
|               flowComplete: true, | ||||
|               finalStatus: | ||||
|                 previousResult.alreadyLoggedIn || previousResult.loginSuccess | ||||
|                   ? 'success' | ||||
|                   : 'failed', | ||||
|             }; | ||||
|           }, | ||||
|         }, | ||||
|       ], | ||||
|     }, | ||||
|   ], | ||||
| }; | ||||
							
								
								
									
										8
									
								
								src/modules/version-module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/modules/version-module.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| import type { CLIModule} from '../types'; | ||||
|  | ||||
| export const versionModule: CLIModule = { | ||||
|   name: 'version', | ||||
|   version: '1.0.0', | ||||
|   commands: [], | ||||
|   workflows: [], | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user
	 波仔糕
					波仔糕