@lanonasis/cli 3.8.1 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,6 +14,8 @@ export class MCPClient {
14
14
  retryAttempts = 0;
15
15
  maxRetries = 3;
16
16
  healthCheckInterval = null;
17
+ healthCheckTimeout = null;
18
+ wsReconnectTimeout = null;
17
19
  connectionStartTime = 0;
18
20
  lastHealthCheck = null;
19
21
  activeConnectionMode = 'local'; // Track actual connection mode
@@ -152,6 +154,8 @@ export class MCPClient {
152
154
  else {
153
155
  console.log(chalk.yellow(`Retry ${this.retryAttempts}/${this.maxRetries}: Connecting to remote MCP server...`));
154
156
  }
157
+ // Verify remote health before establishing SSE
158
+ await this.checkRemoteHealth(serverUrl);
155
159
  // Initialize SSE connection for real-time updates
156
160
  await this.initializeSSE(serverUrl);
157
161
  this.isConnected = true;
@@ -174,7 +178,7 @@ export class MCPClient {
174
178
  // Check if the server file exists
175
179
  if (!fs.existsSync(serverPath)) {
176
180
  console.log(chalk.yellow(`⚠️ Local MCP server not found at ${serverPath}`));
177
- console.log(chalk.cyan('💡 For remote use WebSocket: lanonasis mcp connect --mode websocket --url wss://mcp.lanonasis.com/ws'));
181
+ console.log(chalk.cyan('💡 For remote connection, use: lanonasis mcp connect --mode websocket --url wss://mcp.lanonasis.com/ws'));
178
182
  throw new Error(`MCP server not found at ${serverPath}`);
179
183
  }
180
184
  if (this.retryAttempts === 0) {
@@ -248,8 +252,8 @@ export class MCPClient {
248
252
  return false;
249
253
  }
250
254
  this.retryAttempts++;
251
- if (this.retryAttempts >= this.maxRetries) {
252
- console.error(chalk.red(`Failed to connect after ${this.maxRetries} attempts`));
255
+ if (this.retryAttempts > this.maxRetries) {
256
+ console.error(chalk.red(`Failed to connect after ${this.maxRetries + 1} attempts`));
253
257
  this.provideNetworkTroubleshootingGuidance(error);
254
258
  this.isConnected = false;
255
259
  return false;
@@ -356,7 +360,7 @@ export class MCPClient {
356
360
  */
357
361
  async validateAuthBeforeConnect() {
358
362
  const token = this.config.get('token');
359
- const vendorKey = this.config.get('vendorKey');
363
+ const vendorKey = await this.config.getVendorKeyAsync();
360
364
  // Check if we have any authentication credentials
361
365
  if (!token && !vendorKey) {
362
366
  throw new Error('AUTHENTICATION_REQUIRED: No authentication credentials found. Run "lanonasis auth login" first.');
@@ -456,7 +460,7 @@ export class MCPClient {
456
460
  // Use the proper SSE endpoint from config
457
461
  const sseUrl = this.config.getMCPSSEUrl() ?? `${serverUrl}/events`;
458
462
  const token = this.config.get('token');
459
- const vendorKey = this.config.get('vendorKey');
463
+ const vendorKey = await this.config.getVendorKeyAsync();
460
464
  const authKey = token || vendorKey || process.env.LANONASIS_API_KEY;
461
465
  if (authKey) {
462
466
  // EventSource doesn't support headers directly, append token to URL
@@ -480,7 +484,7 @@ export class MCPClient {
480
484
  */
481
485
  async initializeWebSocket(wsUrl) {
482
486
  const token = this.config.get('token');
483
- const vendorKey = this.config.get('vendorKey');
487
+ const vendorKey = await this.config.getVendorKeyAsync();
484
488
  const authKey = token || vendorKey || process.env.LANONASIS_API_KEY;
485
489
  if (!authKey) {
486
490
  throw new Error('API key required for WebSocket mode. Set LANONASIS_API_KEY or login first.');
@@ -534,8 +538,11 @@ export class MCPClient {
534
538
  this.wsConnection.on('close', (code, reason) => {
535
539
  console.log(chalk.yellow(`WebSocket connection closed (${code}): ${reason}`));
536
540
  // Auto-reconnect after delay
537
- setTimeout(() => {
538
- if (this.isConnected) {
541
+ if (this.wsReconnectTimeout) {
542
+ clearTimeout(this.wsReconnectTimeout);
543
+ }
544
+ this.wsReconnectTimeout = setTimeout(() => {
545
+ if (this.isConnected && process.env.NODE_ENV !== 'test') {
539
546
  console.log(chalk.blue('🔄 Attempting to reconnect to WebSocket...'));
540
547
  this.initializeWebSocket(wsUrl).catch(err => {
541
548
  console.error('Failed to reconnect:', err);
@@ -569,7 +576,8 @@ export class MCPClient {
569
576
  await this.performHealthCheck();
570
577
  }, 30000);
571
578
  // Perform initial health check
572
- setTimeout(() => this.performHealthCheck(), 5000);
579
+ const initialDelay = process.env.NODE_ENV === 'test' ? 50 : 5000;
580
+ this.healthCheckTimeout = setTimeout(() => this.performHealthCheck(), initialDelay);
573
581
  }
574
582
  /**
575
583
  * Stop health monitoring
@@ -579,6 +587,10 @@ export class MCPClient {
579
587
  clearInterval(this.healthCheckInterval);
580
588
  this.healthCheckInterval = null;
581
589
  }
590
+ if (this.healthCheckTimeout) {
591
+ clearTimeout(this.healthCheckTimeout);
592
+ this.healthCheckTimeout = null;
593
+ }
582
594
  }
583
595
  /**
584
596
  * Perform a health check on the current connection
@@ -625,10 +637,10 @@ export class MCPClient {
625
637
  /**
626
638
  * Check remote connection health
627
639
  */
628
- async checkRemoteHealth() {
629
- const apiUrl = this.config.getMCPRestUrl() ?? 'https://mcp.lanonasis.com/api/v1';
640
+ async checkRemoteHealth(serverUrl) {
641
+ const apiUrl = serverUrl ?? this.config.getMCPRestUrl() ?? 'https://mcp.lanonasis.com/api/v1';
630
642
  const token = this.config.get('token');
631
- const vendorKey = this.config.get('vendorKey');
643
+ const vendorKey = await this.config.getVendorKeyAsync();
632
644
  const authKey = token || vendorKey || process.env.LANONASIS_API_KEY;
633
645
  if (!authKey) {
634
646
  throw new Error('No authentication token available');
@@ -700,11 +712,14 @@ export class MCPClient {
700
712
  */
701
713
  async disconnect() {
702
714
  this.stopHealthMonitoring();
715
+ this.isConnected = false;
703
716
  if (this.client) {
704
717
  await this.client.close();
705
718
  this.client = null;
706
719
  }
707
720
  if (this.sseConnection) {
721
+ this.sseConnection.onmessage = null;
722
+ this.sseConnection.onerror = null;
708
723
  this.sseConnection.close();
709
724
  this.sseConnection = null;
710
725
  }
@@ -712,7 +727,10 @@ export class MCPClient {
712
727
  this.wsConnection.close();
713
728
  this.wsConnection = null;
714
729
  }
715
- this.isConnected = false;
730
+ if (this.wsReconnectTimeout) {
731
+ clearTimeout(this.wsReconnectTimeout);
732
+ this.wsReconnectTimeout = null;
733
+ }
716
734
  this.activeConnectionMode = 'websocket'; // Reset to default
717
735
  }
718
736
  /**
@@ -755,7 +773,7 @@ export class MCPClient {
755
773
  async callRemoteTool(toolName, args) {
756
774
  const apiUrl = this.config.getMCPRestUrl() ?? 'https://mcp.lanonasis.com/api/v1';
757
775
  const token = this.config.get('token');
758
- const vendorKey = this.config.get('vendorKey');
776
+ const vendorKey = await this.config.getVendorKeyAsync();
759
777
  const authKey = token || vendorKey || process.env.LANONASIS_API_KEY;
760
778
  if (!authKey) {
761
779
  throw new Error('Authentication required. Run "lanonasis auth login" first.');
@@ -897,7 +915,7 @@ export class MCPClient {
897
915
  break;
898
916
  }
899
917
  const connectionUptime = this.connectionStartTime > 0
900
- ? Date.now() - this.connectionStartTime
918
+ ? Math.max(Date.now() - this.connectionStartTime, this.isConnected ? 1 : 0)
901
919
  : undefined;
902
920
  return {
903
921
  connected: this.isConnected,
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Connection Manager Implementation
3
+ *
4
+ * Manages MCP server discovery, configuration, and connection lifecycle
5
+ * Implementation of the ConnectionManager interface.
6
+ */
7
+ import { ConnectionManager, ConnectionResult, ConfigResult, ServerInstance, ConnectionStatus, MCPConfig } from '../interfaces/ConnectionManager.js';
8
+ /**
9
+ * ConnectionManagerImpl manages MCP server discovery, configuration, and connection lifecycle
10
+ *
11
+ * This implementation automatically detects the embedded MCP server location within the CLI package,
12
+ * generates configuration files with correct server paths, and manages server processes.
13
+ */
14
+ export declare class ConnectionManagerImpl implements ConnectionManager {
15
+ private config;
16
+ private connectionStatus;
17
+ private serverProcess;
18
+ private configPath;
19
+ constructor(configPath?: string);
20
+ /**
21
+ * Initialize the connection manager by loading persisted configuration
22
+ */
23
+ init(): Promise<void>;
24
+ /**
25
+ * Connect to the local embedded MCP server
26
+ */
27
+ connectLocal(): Promise<ConnectionResult>;
28
+ /**
29
+ * Automatically configure the local MCP server with correct paths
30
+ */
31
+ autoConfigureLocalServer(): Promise<ConfigResult>;
32
+ /**
33
+ * Detect the embedded MCP server path within the CLI package
34
+ */
35
+ detectServerPath(): Promise<string | null>;
36
+ /**
37
+ * Start the local MCP server process
38
+ */
39
+ startLocalServer(): Promise<ServerInstance>;
40
+ /**
41
+ * Verify that the MCP server connection is working
42
+ */
43
+ verifyConnection(serverPath: string): Promise<boolean>;
44
+ /**
45
+ * Get the current connection status
46
+ */
47
+ getConnectionStatus(): ConnectionStatus;
48
+ /**
49
+ * Stop the local MCP server if running
50
+ */
51
+ stopLocalServer(): Promise<void>;
52
+ /**
53
+ * Get the current MCP configuration
54
+ */
55
+ getConfig(): MCPConfig;
56
+ /**
57
+ * Update the MCP configuration
58
+ */
59
+ updateConfig(config: Partial<MCPConfig>): Promise<void>;
60
+ /**
61
+ * Check if the server is currently running
62
+ */
63
+ private isServerRunning;
64
+ /**
65
+ * Save the current configuration to disk
66
+ */
67
+ private saveConfig;
68
+ /**
69
+ * Load configuration from disk
70
+ */
71
+ private loadConfig;
72
+ }
@@ -0,0 +1,352 @@
1
+ /**
2
+ * Connection Manager Implementation
3
+ *
4
+ * Manages MCP server discovery, configuration, and connection lifecycle
5
+ * Implementation of the ConnectionManager interface.
6
+ */
7
+ import { promises as fs, createWriteStream } from 'fs';
8
+ import { join, dirname, resolve } from 'path';
9
+ import { spawn } from 'child_process';
10
+ import { fileURLToPath } from 'url';
11
+ /**
12
+ * Default MCP configuration
13
+ */
14
+ const DEFAULT_MCP_CONFIG = {
15
+ localServerPath: '',
16
+ serverPort: 3000,
17
+ autoStart: true,
18
+ connectionTimeout: 10000,
19
+ retryAttempts: 3,
20
+ logLevel: 'info',
21
+ };
22
+ /**
23
+ * ConnectionManagerImpl manages MCP server discovery, configuration, and connection lifecycle
24
+ *
25
+ * This implementation automatically detects the embedded MCP server location within the CLI package,
26
+ * generates configuration files with correct server paths, and manages server processes.
27
+ */
28
+ export class ConnectionManagerImpl {
29
+ config;
30
+ connectionStatus;
31
+ serverProcess = null;
32
+ configPath;
33
+ constructor(configPath) {
34
+ this.config = { ...DEFAULT_MCP_CONFIG };
35
+ this.configPath = configPath || join(process.cwd(), '.lanonasis', 'mcp-config.json');
36
+ this.connectionStatus = {
37
+ isConnected: false,
38
+ connectionAttempts: 0,
39
+ };
40
+ }
41
+ /**
42
+ * Initialize the connection manager by loading persisted configuration
43
+ */
44
+ async init() {
45
+ await this.loadConfig();
46
+ }
47
+ /**
48
+ * Connect to the local embedded MCP server
49
+ */
50
+ async connectLocal() {
51
+ try {
52
+ // Load persisted configuration first
53
+ await this.loadConfig();
54
+ // First, try to detect the server path
55
+ const configuredPath = this.config.localServerPath?.trim();
56
+ const serverPath = configuredPath || (await this.detectServerPath());
57
+ if (!serverPath) {
58
+ return {
59
+ success: false,
60
+ error: 'Could not detect local MCP server path',
61
+ suggestions: [
62
+ 'Ensure the CLI package is properly installed',
63
+ 'Check that the MCP server files are present',
64
+ 'Try running: lanonasis init',
65
+ ],
66
+ };
67
+ }
68
+ // Update configuration with detected path
69
+ this.config.localServerPath = serverPath;
70
+ await this.saveConfig();
71
+ // Start the server if not already running
72
+ if (!this.isServerRunning()) {
73
+ const serverInstance = await this.startLocalServer();
74
+ this.connectionStatus.serverInstance = serverInstance;
75
+ }
76
+ // Verify the connection
77
+ const isConnected = await this.verifyConnection(serverPath);
78
+ if (isConnected) {
79
+ this.connectionStatus.isConnected = true;
80
+ this.connectionStatus.lastConnected = new Date();
81
+ this.connectionStatus.connectionAttempts++;
82
+ return {
83
+ success: true,
84
+ serverPath,
85
+ };
86
+ }
87
+ else {
88
+ this.connectionStatus.connectionAttempts++;
89
+ return {
90
+ success: false,
91
+ error: 'Failed to verify MCP server connection',
92
+ suggestions: [
93
+ 'Check server logs for errors',
94
+ 'Ensure no other process is using the port',
95
+ 'Try restarting the CLI',
96
+ ],
97
+ };
98
+ }
99
+ }
100
+ catch (error) {
101
+ this.connectionStatus.connectionAttempts++;
102
+ this.connectionStatus.lastError = error instanceof Error ? error.message : String(error);
103
+ return {
104
+ success: false,
105
+ error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,
106
+ suggestions: [
107
+ 'Check your network connection',
108
+ 'Verify the MCP server is installed correctly',
109
+ 'Try running: lanonasis mcp diagnose',
110
+ ],
111
+ };
112
+ }
113
+ }
114
+ /**
115
+ * Automatically configure the local MCP server with correct paths
116
+ */
117
+ async autoConfigureLocalServer() {
118
+ try {
119
+ const serverPath = await this.detectServerPath();
120
+ if (!serverPath) {
121
+ return {
122
+ success: false,
123
+ error: 'Could not detect MCP server path for auto-configuration',
124
+ };
125
+ }
126
+ // Update configuration
127
+ this.config.localServerPath = serverPath;
128
+ // Ensure config directory exists
129
+ await fs.mkdir(dirname(this.configPath), { recursive: true });
130
+ // Save configuration
131
+ await this.saveConfig();
132
+ return {
133
+ success: true,
134
+ configPath: this.configPath,
135
+ serverPath,
136
+ };
137
+ }
138
+ catch (error) {
139
+ return {
140
+ success: false,
141
+ error: `Auto-configuration failed: ${error instanceof Error ? error.message : String(error)}`,
142
+ };
143
+ }
144
+ }
145
+ /**
146
+ * Detect the embedded MCP server path within the CLI package
147
+ */
148
+ async detectServerPath() {
149
+ try {
150
+ // Get the current module directory
151
+ const currentDir = dirname(fileURLToPath(import.meta.url));
152
+ // Common paths to check for the MCP server
153
+ const candidatePaths = [
154
+ // Relative to current CLI source
155
+ resolve(currentDir, '../../mcp-server-entry.js'),
156
+ resolve(currentDir, '../../../dist/mcp-server-entry.js'),
157
+ // Relative to CLI package root
158
+ resolve(currentDir, '../../../mcp-server-entry.js'),
159
+ resolve(currentDir, '../../dist/mcp-server-entry.js'),
160
+ // In node_modules (if installed as dependency)
161
+ resolve(process.cwd(), 'node_modules/@lanonasis/cli/dist/mcp-server-entry.js'),
162
+ // Global installation paths
163
+ resolve(process.cwd(), 'dist/mcp-server-entry.js'),
164
+ // Development paths
165
+ resolve(process.cwd(), 'cli/dist/mcp-server-entry.js'),
166
+ resolve(process.cwd(), '../cli/dist/mcp-server-entry.js'),
167
+ ];
168
+ // Check each candidate path
169
+ for (const candidatePath of candidatePaths) {
170
+ try {
171
+ await fs.access(candidatePath);
172
+ // Verify it's actually the MCP server by checking file content
173
+ const content = await fs.readFile(candidatePath, 'utf-8');
174
+ if (content.includes('mcp') || content.includes('server')) {
175
+ return candidatePath;
176
+ }
177
+ }
178
+ catch {
179
+ // Path doesn't exist or isn't accessible, continue
180
+ }
181
+ }
182
+ return null;
183
+ }
184
+ catch (error) {
185
+ console.error('Error detecting server path:', error);
186
+ return null;
187
+ }
188
+ }
189
+ /**
190
+ * Start the local MCP server process
191
+ */
192
+ async startLocalServer() {
193
+ if (!this.config.localServerPath) {
194
+ throw new Error('No local server path configured');
195
+ }
196
+ return new Promise((resolve, reject) => {
197
+ const serverProcess = spawn('node', [this.config.localServerPath], {
198
+ stdio: ['pipe', 'pipe', 'pipe'],
199
+ env: {
200
+ ...process.env,
201
+ PORT: this.config.serverPort?.toString() || '3000',
202
+ LOG_LEVEL: this.config.logLevel,
203
+ },
204
+ });
205
+ const serverInstance = {
206
+ pid: serverProcess.pid,
207
+ port: this.config.serverPort || 3000,
208
+ status: 'starting',
209
+ startTime: new Date(),
210
+ logPath: join(dirname(this.configPath), 'mcp-server.log'),
211
+ };
212
+ // Set up logging
213
+ const logStream = createWriteStream(serverInstance.logPath, { flags: 'a' });
214
+ serverProcess.stdout?.pipe(logStream);
215
+ serverProcess.stderr?.pipe(logStream);
216
+ // Handle server startup
217
+ const startupTimeout = setTimeout(() => {
218
+ serverInstance.status = 'error';
219
+ reject(new Error('Server startup timeout'));
220
+ }, this.config.connectionTimeout);
221
+ serverProcess.on('spawn', () => {
222
+ clearTimeout(startupTimeout);
223
+ serverInstance.status = 'running';
224
+ this.serverProcess = serverProcess;
225
+ resolve(serverInstance);
226
+ });
227
+ serverProcess.on('error', (error) => {
228
+ clearTimeout(startupTimeout);
229
+ serverInstance.status = 'error';
230
+ reject(error);
231
+ });
232
+ serverProcess.on('exit', (code) => {
233
+ serverInstance.status = code === 0 ? 'stopped' : 'error';
234
+ this.serverProcess = null;
235
+ });
236
+ });
237
+ }
238
+ /**
239
+ * Verify that the MCP server connection is working
240
+ */
241
+ async verifyConnection(serverPath) {
242
+ try {
243
+ // Simple verification - check if server path exists and is accessible
244
+ await fs.access(serverPath);
245
+ // If we have a running server instance, check if it's responsive
246
+ if (this.connectionStatus.serverInstance) {
247
+ const { status, pid } = this.connectionStatus.serverInstance;
248
+ // Explicitly check for error/stopped states
249
+ if (status === 'error' || status === 'stopped') {
250
+ return false;
251
+ }
252
+ // Only verify process for running servers
253
+ if (status === 'running') {
254
+ try {
255
+ process.kill(pid, 0); // Signal 0 checks if process exists
256
+ return true;
257
+ }
258
+ catch {
259
+ // Process doesn't exist despite status being 'running'
260
+ this.connectionStatus.serverInstance.status = 'stopped';
261
+ return false;
262
+ }
263
+ }
264
+ // Starting state is not yet ready
265
+ if (status === 'starting') {
266
+ return false;
267
+ }
268
+ }
269
+ // No server instance means we haven't started it yet
270
+ // This is okay for initial connection attempts
271
+ return true;
272
+ }
273
+ catch {
274
+ return false;
275
+ }
276
+ }
277
+ /**
278
+ * Get the current connection status
279
+ */
280
+ getConnectionStatus() {
281
+ return { ...this.connectionStatus };
282
+ }
283
+ /**
284
+ * Stop the local MCP server if running
285
+ */
286
+ async stopLocalServer() {
287
+ if (this.serverProcess) {
288
+ return new Promise((resolve) => {
289
+ const forceKillTimeout = setTimeout(() => {
290
+ if (this.serverProcess) {
291
+ this.serverProcess.kill('SIGKILL');
292
+ }
293
+ }, 5000);
294
+ this.serverProcess.on('exit', () => {
295
+ clearTimeout(forceKillTimeout);
296
+ this.serverProcess = null;
297
+ if (this.connectionStatus.serverInstance) {
298
+ this.connectionStatus.serverInstance.status = 'stopped';
299
+ }
300
+ this.connectionStatus.isConnected = false;
301
+ resolve();
302
+ });
303
+ this.serverProcess.kill('SIGTERM');
304
+ });
305
+ }
306
+ }
307
+ /**
308
+ * Get the current MCP configuration
309
+ */
310
+ getConfig() {
311
+ return { ...this.config };
312
+ }
313
+ /**
314
+ * Update the MCP configuration
315
+ */
316
+ async updateConfig(config) {
317
+ this.config = { ...this.config, ...config };
318
+ await this.saveConfig();
319
+ }
320
+ /**
321
+ * Check if the server is currently running
322
+ */
323
+ isServerRunning() {
324
+ return (this.serverProcess !== null && this.connectionStatus.serverInstance?.status === 'running');
325
+ }
326
+ /**
327
+ * Save the current configuration to disk
328
+ */
329
+ async saveConfig() {
330
+ try {
331
+ await fs.mkdir(dirname(this.configPath), { recursive: true });
332
+ await fs.writeFile(this.configPath, JSON.stringify(this.config, null, 2));
333
+ }
334
+ catch (error) {
335
+ throw new Error(`Failed to save configuration: ${error instanceof Error ? error.message : String(error)}`);
336
+ }
337
+ }
338
+ /**
339
+ * Load configuration from disk
340
+ */
341
+ async loadConfig() {
342
+ try {
343
+ const configData = await fs.readFile(this.configPath, 'utf-8');
344
+ const loadedConfig = JSON.parse(configData);
345
+ this.config = { ...DEFAULT_MCP_CONFIG, ...loadedConfig };
346
+ }
347
+ catch {
348
+ // Config file doesn't exist or is invalid, use defaults
349
+ this.config = { ...DEFAULT_MCP_CONFIG };
350
+ }
351
+ }
352
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Onboarding Flow Implementation
3
+ *
4
+ * Guides new users through initial setup and configuration
5
+ * Implementation of the OnboardingFlow interface.
6
+ */
7
+ import { OnboardingFlow, SetupResult, TestResult, UserPreferences, OnboardingState } from '../interfaces/OnboardingFlow.js';
8
+ /**
9
+ * OnboardingFlowImpl guides new users through initial setup and configuration
10
+ *
11
+ * This implementation detects first-run scenarios, creates working default configurations,
12
+ * tests all major functionality, and provides interactive demonstrations.
13
+ */
14
+ export declare class OnboardingFlowImpl implements OnboardingFlow {
15
+ private onboardingState;
16
+ private configPath;
17
+ private connectionManager;
18
+ private textInputHandler;
19
+ constructor(configPath?: string);
20
+ /**
21
+ * Run the complete initial setup process for new users
22
+ */
23
+ runInitialSetup(): Promise<SetupResult>;
24
+ /**
25
+ * Detect if this is a first-run scenario
26
+ */
27
+ detectFirstRun(): boolean;
28
+ /**
29
+ * Configure working default settings for immediate productivity
30
+ */
31
+ configureDefaults(): Promise<void>;
32
+ /**
33
+ * Test connectivity and functionality of all major components
34
+ */
35
+ testConnectivity(): Promise<TestResult[]>;
36
+ /**
37
+ * Show welcome demonstration of key features
38
+ */
39
+ showWelcomeDemo(): Promise<void>;
40
+ /**
41
+ * Get the current onboarding state
42
+ */
43
+ getOnboardingState(): OnboardingState;
44
+ /**
45
+ * Update user preferences during onboarding
46
+ */
47
+ updateUserPreferences(preferences: Partial<UserPreferences>): Promise<void>;
48
+ /**
49
+ * Skip the current onboarding step
50
+ */
51
+ skipCurrentStep(reason?: string): Promise<void>;
52
+ /**
53
+ * Complete the onboarding process
54
+ */
55
+ completeOnboarding(): Promise<void>;
56
+ /**
57
+ * Reset onboarding state (for testing or re-running)
58
+ */
59
+ resetOnboarding(): Promise<void>;
60
+ /**
61
+ * Gather user preferences interactively
62
+ */
63
+ private gatherUserPreferences;
64
+ /**
65
+ * Save the current onboarding state to disk
66
+ */
67
+ private saveOnboardingState;
68
+ /**
69
+ * Load onboarding state from disk
70
+ */
71
+ private loadOnboardingState;
72
+ }