wilfredwake 1.0.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.
package/bin/cli.js ADDED
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * ╔═══════════════════════════════════════════════════════════════╗
5
+ * ║ ║
6
+ * ║ WILFREDWAKE - CLI TOOL FOR SERVICE ORCHESTRATION ║
7
+ * ║ Multi-Developer Development Environment Management ║
8
+ * ║ ║
9
+ * ║ Entry Point: Main CLI executable with command routing ║
10
+ * ║ Uses Commander.js for robust command-line interface ║
11
+ * ║ ║
12
+ * ╚═══════════════════════════════════════════════════════════════╝
13
+ */
14
+
15
+ import { Command } from 'commander';
16
+ import chalk from 'chalk';
17
+ import { initCommand } from '../src/cli/commands/init.js';
18
+ import { statusCommand } from '../src/cli/commands/status.js';
19
+ import { wakeCommand } from '../src/cli/commands/wake.js';
20
+ import { healthCommand } from '../src/cli/commands/health.js';
21
+
22
+ // ═══════════════════════════════════════════════════════════════
23
+ // MAIN CLI SETUP
24
+ // ═══════════════════════════════════════════════════════════════
25
+
26
+ const program = new Command();
27
+
28
+ program
29
+ .name('wilfredwake')
30
+ .description(
31
+ chalk.cyan('🌅 CLI Tool for Multi-Developer Development Environment Wake & Status Management')
32
+ )
33
+ .version('1.0.0')
34
+ .usage(chalk.yellow('[command] [options]'));
35
+
36
+ // ═══════════════════════════════════════════════════════════════
37
+ // COMMAND REGISTRATION
38
+ // ═══════════════════════════════════════════════════════════════
39
+
40
+ /**
41
+ * INIT COMMAND
42
+ * Initializes wilfredwake configuration on first-time setup
43
+ * Sets up ~/.wilfredwake directory and config.json
44
+ */
45
+ program
46
+ .command('init')
47
+ .description(
48
+ chalk.magenta('Initialize wilfredwake configuration (first-time setup)')
49
+ )
50
+ .option('-o, --orchestrator <url>', 'Orchestrator URL', 'http://localhost:3000')
51
+ .option('-t, --token <token>', 'Developer API token')
52
+ .action(initCommand);
53
+
54
+ /**
55
+ * STATUS COMMAND
56
+ * Displays current status of all services
57
+ * Connects to orchestrator for real-time state
58
+ */
59
+ program
60
+ .command('status [service]')
61
+ .description(chalk.green('Check status of all services or a specific service'))
62
+ .option('-e, --env <environment>', 'Environment (dev, staging, prod)', 'dev')
63
+ .option('-f, --format <format>', 'Output format (table, json)', 'table')
64
+ .action(statusCommand);
65
+
66
+ /**
67
+ * WAKE COMMAND
68
+ * Wakes services on demand with dependency ordering
69
+ * Defaults to all services if no target specified
70
+ * Supports waking individual services, groups, or all services
71
+ */
72
+ program
73
+ .command('wake [target]')
74
+ .description(chalk.blue('Wake services on demand (all, <service>, or <group>)'))
75
+ .option('-e, --env <environment>', 'Environment (dev, staging, prod)', 'dev')
76
+ .option('--no-wait', 'Don\'t wait for services to be ready')
77
+ .option('--timeout <seconds>', 'Timeout for service readiness', '300')
78
+ .action(wakeCommand);
79
+
80
+ /**
81
+ * HEALTH COMMAND
82
+ * Performs health check on services without waking
83
+ * Useful for monitoring and diagnostics
84
+ */
85
+ program
86
+ .command('health [service]')
87
+ .description(chalk.cyan('Check health status of services'))
88
+ .option('-e, --env <environment>', 'Environment (dev, staging, prod)', 'dev')
89
+ .action(healthCommand);
90
+
91
+ // ═══════════════════════════════════════════════════════════════
92
+ // HELP & ERROR HANDLING
93
+ // ═══════════════════════════════════════════════════════════════
94
+
95
+ // Default help message with visual enhancements
96
+ program.on('--help', () => {
97
+ console.log('');
98
+ console.log(chalk.dim('Examples:'));
99
+ console.log(chalk.yellow(' $ wilfredwake init # Setup configuration'));
100
+ console.log(chalk.yellow(' $ wilfredwake status # Check all services'));
101
+ console.log(chalk.yellow(' $ wilfredwake wake all # Wake all services'));
102
+ console.log(chalk.yellow(' $ wilfredwake wake auth # Wake single service'));
103
+ console.log(chalk.yellow(' $ wilfredwake health # Check health'));
104
+ console.log('');
105
+ console.log(
106
+ chalk.dim(
107
+ 'For more information, visit: https://github.com/wilfred/wilfredwake'
108
+ )
109
+ );
110
+ console.log('');
111
+ });
112
+
113
+ // Error handling for unknown commands
114
+ program.on('command:*', () => {
115
+ console.error(
116
+ chalk.red(
117
+ '\n❌ Invalid command. Use --help for available commands.\n'
118
+ )
119
+ );
120
+ process.exit(1);
121
+ });
122
+
123
+ // ═══════════════════════════════════════════════════════════════
124
+ // CLI EXECUTION
125
+ // ═══════════════════════════════════════════════════════════════
126
+
127
+ // Parse command-line arguments and execute
128
+ program.parse(process.argv);
129
+
130
+ // Show help if no command provided
131
+ if (process.argv.length < 3) {
132
+ program.outputHelp();
133
+ }
package/index.js ADDED
@@ -0,0 +1,222 @@
1
+ /**
2
+ * ╔═══════════════════════════════════════════════════════════════╗
3
+ * ║ ║
4
+ * ║ WILFREDWAKE - CLI TOOL FOR SERVICE ORCHESTRATION ║
5
+ * ║ ║
6
+ * ║ Multi-Developer Development Environment Management ║
7
+ * ║ Wake & Status Management for Distributed Systems ║
8
+ * ║ ║
9
+ * ║ Project: wilfredwake ║
10
+ * ║ Version: 1.0.0 ║
11
+ * ║ License: MIT ║
12
+ * ║ ║
13
+ * ╚═══════════════════════════════════════════════════════════════╝
14
+ *
15
+ * PURPOSE
16
+ * ═══════════════════════════════════════════════════════════════
17
+ * wilfredwake is a CLI tool to manage sleeping development services
18
+ * in distributed systems, ensuring developers can wake services on
19
+ * demand while respecting dependency order and checking readiness.
20
+ *
21
+ * CORE FEATURES
22
+ * ═══════════════════════════════════════════════════════════════
23
+ * • Service status checking and health monitoring
24
+ * • On-demand service waking with dependency awareness
25
+ * • Multi-developer support with centralized orchestrator
26
+ * • Configuration-driven service registry (YAML/JSON)
27
+ * • Human-readable colored output
28
+ * • Timeout and error handling
29
+ * • Multi-environment support (dev, staging, prod)
30
+ *
31
+ * ARCHITECTURE
32
+ * ═══════════════════════════════════════════════════════════════
33
+ * Developer CLI → Orchestrator (always-on) → Services
34
+ *
35
+ * CLI: Local interface developers use (this package)
36
+ * Orchestrator: Backend service managing state and wake operations
37
+ * Services: Individual microservices with /health and /wake endpoints
38
+ *
39
+ * SYSTEM COMPONENTS
40
+ * ═══════════════════════════════════════════════════════════════
41
+ * src/
42
+ * ├── cli/ # CLI interface
43
+ * │ ├── commands/ # CLI command implementations
44
+ * │ │ ├── init.js # Configuration setup
45
+ * │ │ ├── status.js # Service status checking
46
+ * │ │ ├── wake.js # Service wake operations
47
+ * │ │ └── health.js # Health checks
48
+ * │ ├── config.js # Configuration management
49
+ * │ └── utils.js # CLI utilities
50
+ * ├── orchestrator/ # Backend orchestrator
51
+ * │ ├── server.js # Express.js API server
52
+ * │ ├── registry.js # Service registry loader
53
+ * │ ├── orchestrator.js # Wake orchestration logic
54
+ * │ └── handlers/ # API request handlers
55
+ * ├── shared/ # Shared modules
56
+ * │ ├── colors.js # Color schemes and formatting
57
+ * │ ├── logger.js # Logging utilities
58
+ * │ └── errors.js # Error definitions
59
+ * └── config/ # Configuration files
60
+ * └── services.yaml # Service registry
61
+ * ├── bin/ # Executable entry point
62
+ * │ └── cli.js # CLI executable
63
+ * ├── package.json # NPM package definition
64
+ * └── index.js # Main entry point
65
+ *
66
+ * USAGE EXAMPLES
67
+ * ═══════════════════════════════════════════════════════════════
68
+ *
69
+ * # Initialize configuration (first-time setup)
70
+ * $ wilfredwake init
71
+ *
72
+ * # Check status of all services
73
+ * $ wilfredwake status
74
+ *
75
+ * # Check specific service status
76
+ * $ wilfredwake status auth
77
+ *
78
+ * # Wake all services
79
+ * $ wilfredwake wake all
80
+ *
81
+ * # Wake specific service
82
+ * $ wilfredwake wake auth
83
+ *
84
+ * # Wake service group
85
+ * $ wilfredwake wake payments
86
+ *
87
+ * # Health check (no waking)
88
+ * $ wilfredwake health
89
+ *
90
+ * # Environment-specific operations
91
+ * $ wilfredwake wake all --env staging
92
+ *
93
+ * # JSON output format
94
+ * $ wilfredwake status --format json
95
+ *
96
+ * CONFIGURATION
97
+ * ═══════════════════════════════════════════════════════════════
98
+ * Configuration is stored in ~/.wilfredwake/config.json
99
+ *
100
+ * Default values:
101
+ * {
102
+ * "orchestratorUrl": "http://localhost:3000",
103
+ * "token": null,
104
+ * "environment": "dev",
105
+ * "preferences": {
106
+ * "outputFormat": "table",
107
+ * "verbose": false,
108
+ * "autoWait": true,
109
+ * "timeout": 300
110
+ * }
111
+ * }
112
+ *
113
+ * SERVICE REGISTRY
114
+ * ═══════════════════════════════════════════════════════════════
115
+ * Service registry (services.yaml) defines:
116
+ * • Service name, URL, and health/wake endpoints
117
+ * • Service dependencies (for dependency-aware waking)
118
+ * • Environment configurations (dev, staging, prod)
119
+ * • Service grouping for bulk operations
120
+ *
121
+ * Example service definition:
122
+ * services:
123
+ * dev:
124
+ * auth:
125
+ * url: https://auth-dev.onrender.com
126
+ * health: /health
127
+ * wake: /wake
128
+ * dependsOn: []
129
+ *
130
+ * payment-consumer:
131
+ * url: https://payment-consumer-dev.onrender.com
132
+ * health: /health
133
+ * wake: /wake
134
+ * dependsOn: [auth]
135
+ *
136
+ * ORCHESTRATOR API
137
+ * ═══════════════════════════════════════════════════════════════
138
+ * The orchestrator backend provides REST APIs:
139
+ *
140
+ * GET /health - Orchestrator health check
141
+ * GET /api/status - Get service status
142
+ * GET /api/health - Perform health checks
143
+ * POST /api/wake - Wake services
144
+ * GET /api/registry - View service registry
145
+ * POST /api/reload - Reload service registry
146
+ *
147
+ * MULTI-DEVELOPER SUPPORT
148
+ * ═══════════════════════════════════════════════════════════════
149
+ * • CLI uses per-user token to identify developer
150
+ * • Orchestrator is shared/always-on (single source of truth)
151
+ * • Multiple developers can wake services concurrently
152
+ * • State is centralized in orchestrator
153
+ *
154
+ * DEPENDENCY ORDERING
155
+ * ═══════════════════════════════════════════════════════════════
156
+ * Services are woken in dependency order using topological sort:
157
+ *
158
+ * Example dependency chain:
159
+ * auth (no deps) → payment-producer (depends on auth)
160
+ * → payment-consumer (depends on payment-producer)
161
+ *
162
+ * When waking "all":
163
+ * 1. auth wakes first
164
+ * 2. Once auth is ready, payment-producer wakes
165
+ * 3. Once payment-producer is ready, payment-consumer wakes
166
+ *
167
+ * HEALTH CHECKS
168
+ * ═══════════════════════════════════════════════════════════════
169
+ * • Health endpoint: GET {service-url}/health (configurable)
170
+ * • Wake endpoint: POST {service-url}/wake (configurable)
171
+ * • Status codes < 300: Service is ready
172
+ * • Status code 503: Service is sleeping
173
+ * • Status codes >= 400: Service has issues
174
+ * • Timeout: Service not responding
175
+ *
176
+ * ERROR HANDLING
177
+ * ═══════════════════════════════════════════════════════════════
178
+ * • Timeouts: Services that don't respond within timeout
179
+ * • Failed health checks: Services that fail health validation
180
+ * • Circular dependencies: Detected and reported
181
+ * • Connection errors: Clear error messages with guidance
182
+ * • Partial success: Some services wake, others fail
183
+ *
184
+ * ENVIRONMENT VARIABLES
185
+ * ═══════════════════════════════════════════════════════════════
186
+ * PORT - Orchestrator port (default: 3000)
187
+ * REGISTRY_FILE - Path to service registry (default: src/config/services.yaml)
188
+ * NODE_ENV - Environment (development, production)
189
+ * REQUIRE_AUTH - Require authentication tokens
190
+ *
191
+ * FUTURE ENHANCEMENTS
192
+ * ═══════════════════════════════════════════════════════════════
193
+ * • CLI auto-completion support
194
+ * • Hot reload of service registry
195
+ * • Web UI for orchestration overview
196
+ * • Scoped groups and service tagging
197
+ * • API-based dynamic service registration
198
+ * • Slack/email notifications for sleeping services
199
+ * • Service metrics and performance tracking
200
+ * • Automatic health monitoring and alerting
201
+ * • Service lifecycle management (pause, stop, restart)
202
+ * • Multi-user authentication and authorization
203
+ *
204
+ * LICENSE
205
+ * ═══════════════════════════════════════════════════════════════
206
+ * MIT License - See LICENSE file for details
207
+ *
208
+ * REFERENCES
209
+ * ═══════════════════════════════════════════════════════════════
210
+ * • Render sleeping service behavior
211
+ * • Kubernetes orchestration concepts
212
+ * • Terraform infrastructure as code patterns
213
+ * • DevOps tooling best practices
214
+ *
215
+ */
216
+
217
+ // Entry point - exports CLI version and utilities for programmatic use
218
+ export { default as ConfigManager } from './src/cli/config.js';
219
+ export { Logger, utils } from './src/shared/logger.js';
220
+ export { colors, format } from './src/shared/colors.js';
221
+ export { ServiceRegistry } from './src/orchestrator/registry.js';
222
+ export { Orchestrator, ServiceState } from './src/orchestrator/orchestrator.js';
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "wilfredwake",
3
+ "version": "1.0.0",
4
+ "description": "CLI Tool for Multi-Developer Development Environment Wake & Status Management",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "bin": {
8
+ "wilfredwake": "./bin/cli.js"
9
+ },
10
+ "scripts": {
11
+ "start": "node bin/cli.js",
12
+ "dev": "node --experimental-watch bin/cli.js",
13
+ "orchestrator": "node src/orchestrator/server.js",
14
+ "orchestrator:dev": "node --experimental-watch src/orchestrator/server.js",
15
+ "test": "node --test tests/**/*.test.js"
16
+ },
17
+ "keywords": [
18
+ "cli",
19
+ "service-management",
20
+ "orchestration",
21
+ "development",
22
+ "wake",
23
+ "status"
24
+ ],
25
+ "author": "Wilfred Wake",
26
+ "license": "MIT",
27
+ "dependencies": {
28
+ "chalk": "^5.3.0",
29
+ "commander": "^11.1.0",
30
+ "axios": "^1.6.0",
31
+ "js-yaml": "^4.1.0",
32
+ "dotenv": "^16.3.1",
33
+ "express": "^4.18.2"
34
+ },
35
+ "devDependencies": {
36
+
37
+ },
38
+ "engines": {
39
+ "node": ">=18.0.0"
40
+ }
41
+ }
@@ -0,0 +1,238 @@
1
+ /**
2
+ * ╔═══════════════════════════════════════════════════════════════╗
3
+ * ║ HEALTH COMMAND - Check Service Health ║
4
+ * ║ Performs health checks without waking services ║
5
+ * ║ Useful for monitoring and diagnostics ║
6
+ * ╚═══════════════════════════════════════════════════════════════╝
7
+ */
8
+
9
+ import axios from 'axios';
10
+ import ConfigManager from '../config.js';
11
+ import { Logger, utils } from '../../shared/logger.js';
12
+ import { colors, format } from '../../shared/colors.js';
13
+ import chalk from 'chalk';
14
+
15
+ const logger = new Logger();
16
+
17
+ /**
18
+ * Check health status of services
19
+ * Does NOT wake services, only checks their current health
20
+ *
21
+ * @param {string} service - Optional service name to check
22
+ * @param {Object} options - Command options
23
+ * @param {string} options.env - Environment (dev, staging, prod)
24
+ */
25
+ export async function healthCommand(service, options) {
26
+ try {
27
+ // ═══════════════════════════════════════════════════════════════
28
+ // LOAD CONFIGURATION
29
+ // ═══════════════════════════════════════════════════════════════
30
+ const configManager = new ConfigManager();
31
+ const config = await configManager.loadConfig();
32
+
33
+ const env = options.env || config.environment;
34
+
35
+ logger.section('Service Health Check');
36
+
37
+ // ═══════════════════════════════════════════════════════════════
38
+ // FETCH HEALTH FROM ORCHESTRATOR
39
+ // ═══════════════════════════════════════════════════════════════
40
+ let stopSpinner;
41
+ try {
42
+ stopSpinner = logger.spinner('Checking service health...');
43
+
44
+ const response = await axios.get(
45
+ `${config.orchestratorUrl}/api/health`,
46
+ {
47
+ params: {
48
+ environment: env,
49
+ service: service || undefined,
50
+ },
51
+ timeout: 15000,
52
+ }
53
+ );
54
+
55
+ stopSpinner();
56
+ console.log(''); // New line after spinner
57
+
58
+ const services = response.data.services || [];
59
+ const timestamp = response.data.timestamp || new Date().toISOString();
60
+
61
+ // ═══════════════════════════════════════════════════════════════
62
+ // DISPLAY HEALTH RESULTS
63
+ // ═══════════════════════════════════════════════════════════════
64
+ _displayHealthStatus(services, env, timestamp);
65
+
66
+ // ═══════════════════════════════════════════════════════════════
67
+ // HEALTH SUMMARY
68
+ // ═══════════════════════════════════════════════════════════════
69
+ _displayHealthSummary(services);
70
+
71
+ process.exit(0);
72
+ } catch (error) {
73
+ stopSpinner?.();
74
+ throw error;
75
+ }
76
+ } catch (error) {
77
+ logger.error(`Health check failed: ${error.message}`);
78
+
79
+ if (error.code === 'ECONNREFUSED') {
80
+ console.log(
81
+ chalk.yellowBright(
82
+ '\n⚠ Could not connect to orchestrator. Make sure it\'s running.'
83
+ )
84
+ );
85
+ console.log(chalk.dim('Run: wilfredwake init'));
86
+ }
87
+
88
+ process.exit(1);
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Display detailed health status
94
+ * @private
95
+ * @param {Array} services - Services health data
96
+ * @param {string} environment - Environment name
97
+ * @param {string} timestamp - Check timestamp
98
+ */
99
+ function _displayHealthStatus(services, environment, timestamp) {
100
+ if (services.length === 0) {
101
+ logger.info('No services found in registry.');
102
+ return;
103
+ }
104
+
105
+ console.log(chalk.cyanBright.bold(`\n💓 Health Status (${environment.toUpperCase()})\n`));
106
+ console.log(chalk.gray(`Last checked: ${new Date(timestamp).toLocaleString()}\n`));
107
+
108
+ // ═══════════════════════════════════════════════════════════════
109
+ // DISPLAY EACH SERVICE'S HEALTH
110
+ // ═══════════════════════════════════════════════════════════════
111
+ services.forEach((service) => {
112
+ const statusEmoji = _getHealthEmoji(service.status);
113
+ const statusColor = colors.status[service.status] || colors.status.unknown;
114
+
115
+ // Service header
116
+ console.log(
117
+ `${statusEmoji} ${statusColor.bold(service.name)} ${chalk.gray(
118
+ `(${service.status})`
119
+ )}`
120
+ );
121
+
122
+ // Service details
123
+ if (service.url) {
124
+ console.log(
125
+ chalk.dim(` URL: ${service.url}`)
126
+ );
127
+ }
128
+
129
+ if (service.responseTime) {
130
+ const timeColor =
131
+ service.responseTime > 1000 ? chalk.yellow : chalk.green;
132
+ console.log(
133
+ chalk.dim(` Response time: ${timeColor(
134
+ `${service.responseTime}ms`
135
+ )}`)
136
+ );
137
+ }
138
+
139
+ if (service.lastWakeTime) {
140
+ const lastWake = new Date(service.lastWakeTime).toLocaleString();
141
+ console.log(chalk.dim(` Last woken: ${lastWake}`));
142
+ }
143
+
144
+ if (service.lastChecked) {
145
+ const lastCheck = new Date(service.lastChecked).toLocaleTimeString();
146
+ console.log(chalk.dim(` Last checked: ${lastCheck}`));
147
+ }
148
+
149
+ if (service.statusCode) {
150
+ const codeColor =
151
+ service.statusCode < 300 ? chalk.green :
152
+ service.statusCode < 400 ? chalk.yellow :
153
+ chalk.red;
154
+ console.log(
155
+ chalk.dim(` Status code: ${codeColor(service.statusCode)}`)
156
+ );
157
+ }
158
+
159
+ if (service.error) {
160
+ console.log(chalk.redBright(` Error: ${service.error}`));
161
+ }
162
+
163
+ if (service.dependencies && service.dependencies.length > 0) {
164
+ console.log(
165
+ chalk.dim(` Dependencies: ${service.dependencies.join(', ')}`)
166
+ );
167
+ }
168
+
169
+ console.log(''); // Spacing
170
+ });
171
+ }
172
+
173
+ /**
174
+ * Display health summary statistics
175
+ * @private
176
+ * @param {Array} services - Services health data
177
+ */
178
+ function _displayHealthSummary(services) {
179
+ if (services.length === 0) return;
180
+
181
+ const stats = {
182
+ total: services.length,
183
+ live: services.filter(s => s.status === 'live').length,
184
+ waking: services.filter(s => s.status === 'waking').length,
185
+ dead: services.filter(s => s.status === 'dead').length,
186
+ failed: services.filter(s => s.status === 'failed').length,
187
+ unknown: services.filter(s => s.status === 'unknown').length,
188
+ };
189
+
190
+ console.log(chalk.magentaBright.bold('Summary'));
191
+ console.log(` Total services: ${stats.total}`);
192
+ console.log(` ${chalk.greenBright('✓')} Live: ${chalk.greenBright(
193
+ stats.live
194
+ )}`);
195
+ if (stats.waking > 0) {
196
+ console.log(` ${chalk.yellowBright('⟳')} Waking: ${chalk.yellowBright(
197
+ stats.waking
198
+ )}`);
199
+ }
200
+ if (stats.dead > 0) {
201
+ console.log(` ${chalk.gray('⚫')} Dead: ${chalk.gray(
202
+ stats.dead
203
+ )}`);
204
+ }
205
+ if (stats.failed > 0) {
206
+ console.log(` ${chalk.redBright('✗')} Failed: ${chalk.redBright(
207
+ stats.failed
208
+ )}`);
209
+ }
210
+ if (stats.unknown > 0) {
211
+ console.log(` ${chalk.magentaBright('?')} Unknown: ${chalk.magentaBright(
212
+ stats.unknown
213
+ )}`);
214
+ }
215
+ console.log('');
216
+ }
217
+
218
+ /**
219
+ * Get emoji for health status
220
+ * @private
221
+ * @param {string} status - Service status
222
+ * @returns {string} Emoji character
223
+ */
224
+ function _getHealthEmoji(status) {
225
+ const emojis = {
226
+ live: '💚',
227
+ dead: '😴',
228
+ waking: '🌅',
229
+ failed: '❌',
230
+ unknown: '❓',
231
+ // Backward compatibility
232
+ ready: '💚',
233
+ sleeping: '😴',
234
+ pending: '⏳',
235
+ };
236
+
237
+ return emojis[status] || '❓';
238
+ }