wilfredwake 1.0.6 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wilfredwake",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "CLI Tool for Multi-Developer Development Environment Wake & Status Management",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -82,13 +82,22 @@ export async function wakeCommand(target, options) {
82
82
  _displayWakeResults(results);
83
83
 
84
84
  // ═══════════════════════════════════════════════════════════════
85
- // DISPLAY FINAL STATUS
85
+ // DISPLAY FINAL STATUS AND START MONITORING
86
86
  // ═══════════════════════════════════════════════════════════════
87
87
  if (shouldWait) {
88
88
  _displayFinalStatus(results);
89
+
90
+ // Start 5-minute monitoring period
91
+ await _monitorServicesForDuration(
92
+ config.orchestratorUrl,
93
+ config.token,
94
+ env,
95
+ wakeTarget,
96
+ 5 * 60 * 1000 // 5 minutes in milliseconds
97
+ );
89
98
  }
90
99
 
91
- process.exit(results.success ? 0 : 1);
100
+ process.exit(0);
92
101
  } catch (error) {
93
102
  stopSpinner?.();
94
103
  throw error;
@@ -180,3 +189,167 @@ function _displayFinalStatus(results) {
180
189
 
181
190
  console.log('');
182
191
  }
192
+
193
+ /**
194
+ * Monitor services for a duration and display live status updates
195
+ * @private
196
+ * @param {string} orchestratorUrl - Orchestrator URL
197
+ * @param {string} token - Authorization token
198
+ * @param {string} env - Environment name
199
+ * @param {string} wakeTarget - Wake target (all, <service>, or <group>)
200
+ * @param {number} duration - Duration in milliseconds
201
+ */
202
+ async function _monitorServicesForDuration(
203
+ orchestratorUrl,
204
+ token,
205
+ env,
206
+ wakeTarget,
207
+ duration
208
+ ) {
209
+ const pollInterval = 10000; // Poll every 10 seconds
210
+ const startTime = Date.now();
211
+ const endTime = startTime + duration;
212
+ let pollCount = 0;
213
+
214
+ console.log(
215
+ chalk.magentaBright.bold(
216
+ `📡 Monitoring services for ${Math.round(duration / 1000)}s...\n`
217
+ )
218
+ );
219
+
220
+ while (Date.now() < endTime) {
221
+ pollCount++;
222
+ const elapsedSeconds = Math.round((Date.now() - startTime) / 1000);
223
+
224
+ try {
225
+ // Fetch current status from orchestrator
226
+ const response = await axios.get(
227
+ `${orchestratorUrl}/api/status`,
228
+ {
229
+ params: {
230
+ environment: env,
231
+ },
232
+ timeout: 5000,
233
+ headers: {
234
+ Authorization: token ? `Bearer ${token}` : undefined,
235
+ },
236
+ }
237
+ );
238
+
239
+ const services = response.data.services || [];
240
+
241
+ // Clear screen and display updated status
242
+ console.clear();
243
+ console.log(chalk.cyanBright.bold('📡 Live Service Monitoring\n'));
244
+ console.log(
245
+ chalk.gray(`Elapsed: ${chalk.yellow(elapsedSeconds)}s / ${Math.round(duration / 1000)}s | Poll #${pollCount}\n`)
246
+ );
247
+
248
+ // Display table with current status
249
+ _displayLiveMonitoringTable(services, env);
250
+
251
+ // Display summary stats
252
+ _displayLiveMonitoringSummary(services);
253
+ } catch (error) {
254
+ console.clear();
255
+ console.log(chalk.cyanBright.bold('📡 Live Service Monitoring\n'));
256
+ console.log(
257
+ chalk.gray(`Elapsed: ${chalk.yellow(elapsedSeconds)}s / ${Math.round(duration / 1000)}s | Poll #${pollCount}\n`)
258
+ );
259
+ logger.warn(`Status check failed: ${error.message}`);
260
+ }
261
+
262
+ // Wait before next poll (unless we're at the end)
263
+ if (Date.now() < endTime) {
264
+ await new Promise(resolve => setTimeout(resolve, pollInterval));
265
+ }
266
+ }
267
+
268
+ // Final summary
269
+ console.clear();
270
+ console.log(chalk.cyanBright.bold('📡 Monitoring Complete\n'));
271
+ console.log(chalk.yellow(`Total monitoring duration: ${Math.round(duration / 1000)}s\n`));
272
+
273
+ try {
274
+ // Fetch final status
275
+ const response = await axios.get(
276
+ `${orchestratorUrl}/api/status`,
277
+ {
278
+ params: {
279
+ environment: env,
280
+ },
281
+ timeout: 5000,
282
+ headers: {
283
+ Authorization: token ? `Bearer ${token}` : undefined,
284
+ },
285
+ }
286
+ );
287
+
288
+ const services = response.data.services || [];
289
+ _displayLiveMonitoringTable(services, env);
290
+ _displayLiveMonitoringSummary(services);
291
+ } catch (error) {
292
+ logger.warn(`Could not fetch final status: ${error.message}`);
293
+ }
294
+
295
+ console.log('');
296
+ }
297
+
298
+ /**
299
+ * Display live monitoring status table
300
+ * @private
301
+ * @param {Array} services - Services array
302
+ * @param {string} environment - Environment name
303
+ */
304
+ function _displayLiveMonitoringTable(services, environment) {
305
+ if (services.length === 0) {
306
+ logger.info('No services to display.');
307
+ return;
308
+ }
309
+
310
+ console.log(chalk.cyanBright.bold(`Services (${environment.toUpperCase()})\n`));
311
+
312
+ const headers = ['Service', 'Status', 'Last Woken', 'URL'];
313
+ console.log(format.tableHeader(headers));
314
+
315
+ services.forEach((service) => {
316
+ const statusColor = colors.status[service.status] || colors.status.unknown;
317
+ const lastWoken = service.lastWakeTime
318
+ ? new Date(service.lastWakeTime).toLocaleString()
319
+ : 'Never';
320
+ const cells = [
321
+ chalk.cyan(service.name.padEnd(20)),
322
+ statusColor(service.status.toUpperCase().padEnd(20)),
323
+ chalk.yellow(lastWoken.padEnd(20)),
324
+ chalk.gray((service.url || '').substring(0, 20).padEnd(20)),
325
+ ];
326
+ console.log(format.tableRow(cells));
327
+ console.log('');
328
+ });
329
+
330
+ console.log('');
331
+ }
332
+
333
+ /**
334
+ * Display live monitoring summary stats
335
+ * @private
336
+ * @param {Array} services - Services array
337
+ */
338
+ function _displayLiveMonitoringSummary(services) {
339
+ if (services.length === 0) return;
340
+
341
+ const stats = {
342
+ total: services.length,
343
+ live: services.filter(s => s.status === 'live').length,
344
+ dead: services.filter(s => s.status === 'dead').length,
345
+ waking: services.filter(s => s.status === 'waking').length,
346
+ failed: services.filter(s => s.status === 'failed').length,
347
+ unknown: services.filter(s => s.status === 'unknown').length,
348
+ };
349
+
350
+ console.log(chalk.magentaBright.bold('Summary'));
351
+ console.log(
352
+ ` ${colors.status.live('✓')} Live: ${colors.status.live(stats.live)} | ${colors.status.dead('⚫')} Dead: ${colors.status.dead(stats.dead)} | ${colors.status.waking('⟳')} Waking: ${colors.status.waking(stats.waking)} | ${colors.status.failed('✗')} Failed: ${colors.status.failed(stats.failed)} | ${colors.status.unknown('?')} Unknown: ${colors.status.unknown(stats.unknown)}`
353
+ );
354
+ console.log(` Total: ${stats.total} services\n`);
355
+ }
@@ -283,14 +283,13 @@ export class Orchestrator {
283
283
  // ═══════════════════════════════════════════════════════════════
284
284
  // DETERMINE STATE FROM STATUS CODE
285
285
  // ═══════════════════════════════════════════════════════════════
286
- // Consider any HTTP response (2xx/3xx/4xx/5xx) as evidence the
287
- // service is responsive — treat as LIVE. Only mark FAILED for
288
- // server errors (5xx). This follows "mark as woken when any
289
- // response is received" behavior.
286
+ // NEW LOGIC: If we get ANY response from the API (2xx, 3xx, 4xx, 5xx),
287
+ // mark the service as LIVE. This means the service is responsive.
288
+ // Only mark as FAILED if no response is received at all.
290
289
  let state = ServiceState.LIVE;
291
- if (response.status >= 500) {
292
- state = ServiceState.FAILED;
293
- }
290
+
291
+ // If we got a response, the service is responsive = LIVE
292
+ // No need to check status code, any response means service can be reached
294
293
 
295
294
  this._logTimestamp(
296
295
  service.name,
@@ -313,7 +312,7 @@ export class Orchestrator {
313
312
  );
314
313
 
315
314
  return {
316
- state: ServiceState.DEAD, // Changed: assume dead on error
315
+ state: ServiceState.DEAD, // Only dead if no response received
317
316
  statusCode: null,
318
317
  responseTime,
319
318
  error: error.message,