dayhoff-tools 1.1.10__py3-none-any.whl → 1.13.12__py3-none-any.whl
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.
- dayhoff_tools/__init__.py +10 -0
- dayhoff_tools/cli/cloud_commands.py +179 -43
- dayhoff_tools/cli/engine1/__init__.py +323 -0
- dayhoff_tools/cli/engine1/engine_core.py +703 -0
- dayhoff_tools/cli/engine1/engine_lifecycle.py +136 -0
- dayhoff_tools/cli/engine1/engine_maintenance.py +431 -0
- dayhoff_tools/cli/engine1/engine_management.py +505 -0
- dayhoff_tools/cli/engine1/shared.py +501 -0
- dayhoff_tools/cli/engine1/studio_commands.py +825 -0
- dayhoff_tools/cli/engines_studios/__init__.py +6 -0
- dayhoff_tools/cli/engines_studios/api_client.py +351 -0
- dayhoff_tools/cli/engines_studios/auth.py +144 -0
- dayhoff_tools/cli/engines_studios/engine-studio-cli.md +1230 -0
- dayhoff_tools/cli/engines_studios/engine_commands.py +1151 -0
- dayhoff_tools/cli/engines_studios/progress.py +260 -0
- dayhoff_tools/cli/engines_studios/simulators/cli-simulators.md +151 -0
- dayhoff_tools/cli/engines_studios/simulators/demo.sh +75 -0
- dayhoff_tools/cli/engines_studios/simulators/engine_list_simulator.py +319 -0
- dayhoff_tools/cli/engines_studios/simulators/engine_status_simulator.py +369 -0
- dayhoff_tools/cli/engines_studios/simulators/idle_status_simulator.py +476 -0
- dayhoff_tools/cli/engines_studios/simulators/simulator_utils.py +180 -0
- dayhoff_tools/cli/engines_studios/simulators/studio_list_simulator.py +374 -0
- dayhoff_tools/cli/engines_studios/simulators/studio_status_simulator.py +164 -0
- dayhoff_tools/cli/engines_studios/studio_commands.py +755 -0
- dayhoff_tools/cli/main.py +106 -7
- dayhoff_tools/cli/utility_commands.py +896 -179
- dayhoff_tools/deployment/base.py +70 -6
- dayhoff_tools/deployment/deploy_aws.py +165 -25
- dayhoff_tools/deployment/deploy_gcp.py +78 -5
- dayhoff_tools/deployment/deploy_utils.py +20 -7
- dayhoff_tools/deployment/job_runner.py +9 -4
- dayhoff_tools/deployment/processors.py +230 -418
- dayhoff_tools/deployment/swarm.py +47 -12
- dayhoff_tools/embedders.py +28 -26
- dayhoff_tools/fasta.py +181 -64
- dayhoff_tools/warehouse.py +268 -1
- {dayhoff_tools-1.1.10.dist-info → dayhoff_tools-1.13.12.dist-info}/METADATA +20 -5
- dayhoff_tools-1.13.12.dist-info/RECORD +54 -0
- {dayhoff_tools-1.1.10.dist-info → dayhoff_tools-1.13.12.dist-info}/WHEEL +1 -1
- dayhoff_tools-1.1.10.dist-info/RECORD +0 -32
- {dayhoff_tools-1.1.10.dist-info → dayhoff_tools-1.13.12.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
"""Progress display utilities for async operations."""
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from typing import Any, Callable, Dict, Optional
|
|
5
|
+
|
|
6
|
+
import click
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def wait_with_progress(
|
|
10
|
+
status_func: Callable[[], Dict[str, Any]],
|
|
11
|
+
is_complete_func: Callable[[Dict[str, Any]], bool],
|
|
12
|
+
label: str = "Progress",
|
|
13
|
+
timeout_seconds: int = 300,
|
|
14
|
+
poll_interval: float = 2.0,
|
|
15
|
+
show_stages: bool = True,
|
|
16
|
+
) -> Dict[str, Any]:
|
|
17
|
+
"""Wait for an async operation with progress display.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
status_func: Function that returns current status dict
|
|
21
|
+
is_complete_func: Function that checks if operation is complete
|
|
22
|
+
label: Label for progress bar
|
|
23
|
+
timeout_seconds: Maximum time to wait
|
|
24
|
+
poll_interval: Seconds between status checks
|
|
25
|
+
show_stages: Whether to show stage/step updates
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
Final status dict
|
|
29
|
+
|
|
30
|
+
Raises:
|
|
31
|
+
TimeoutError: If operation exceeds timeout
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
stages_shown = set()
|
|
35
|
+
start_time = time.time()
|
|
36
|
+
|
|
37
|
+
with click.progressbar(length=100, label=label) as bar:
|
|
38
|
+
while True:
|
|
39
|
+
# Check timeout
|
|
40
|
+
if time.time() - start_time > timeout_seconds:
|
|
41
|
+
raise TimeoutError(f"Operation exceeded {timeout_seconds}s timeout")
|
|
42
|
+
|
|
43
|
+
# Get current status
|
|
44
|
+
try:
|
|
45
|
+
status = status_func()
|
|
46
|
+
except Exception as e:
|
|
47
|
+
click.echo(f"\nError fetching status: {e}", err=True)
|
|
48
|
+
time.sleep(poll_interval)
|
|
49
|
+
continue
|
|
50
|
+
|
|
51
|
+
# Update progress bar
|
|
52
|
+
progress = status.get("progress_percent", 0)
|
|
53
|
+
if progress > bar.pos:
|
|
54
|
+
bar.update(progress - bar.pos)
|
|
55
|
+
|
|
56
|
+
# Show stage/step updates
|
|
57
|
+
if show_stages:
|
|
58
|
+
current_stage = status.get("current_stage") or status.get(
|
|
59
|
+
"current_step"
|
|
60
|
+
)
|
|
61
|
+
if current_stage and current_stage not in stages_shown:
|
|
62
|
+
stages_shown.add(current_stage)
|
|
63
|
+
elapsed = int(time.time() - start_time)
|
|
64
|
+
display_name = current_stage.replace("_", " ").title()
|
|
65
|
+
click.echo(f" [{elapsed}s] {display_name}")
|
|
66
|
+
|
|
67
|
+
# Check completion
|
|
68
|
+
if is_complete_func(status):
|
|
69
|
+
bar.update(100 - bar.pos)
|
|
70
|
+
return status
|
|
71
|
+
|
|
72
|
+
# Check for failure
|
|
73
|
+
status_value = status.get("status", "").lower()
|
|
74
|
+
if status_value == "failed" or status_value == "error":
|
|
75
|
+
error = status.get("error", "Unknown error")
|
|
76
|
+
raise Exception(f"Operation failed: {error}")
|
|
77
|
+
|
|
78
|
+
time.sleep(poll_interval)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def format_sensor_status(sensor_data: Dict[str, Any]) -> str:
|
|
82
|
+
"""Format sensor status for display.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
sensor_data: Sensor data dict
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
Formatted string
|
|
89
|
+
"""
|
|
90
|
+
active = sensor_data.get("active", False)
|
|
91
|
+
reason = sensor_data.get("reason", "No reason provided")
|
|
92
|
+
|
|
93
|
+
if active:
|
|
94
|
+
return f"🟢\n {reason}"
|
|
95
|
+
else:
|
|
96
|
+
return "⚪"
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def format_idle_state(
|
|
100
|
+
idle_state: Dict[str, Any],
|
|
101
|
+
detailed: bool = False,
|
|
102
|
+
attached_studios: Optional[list] = None,
|
|
103
|
+
) -> str:
|
|
104
|
+
"""Format idle state for display.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
idle_state: Idle state dict
|
|
108
|
+
detailed: Whether to show detailed sensor information
|
|
109
|
+
attached_studios: Optional list of attached studio dicts
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Formatted string
|
|
113
|
+
"""
|
|
114
|
+
is_idle = idle_state.get("is_idle", False)
|
|
115
|
+
|
|
116
|
+
lines = []
|
|
117
|
+
|
|
118
|
+
# Status line
|
|
119
|
+
icon = "🟡 IDLE" if is_idle else "🟢 ACTIVE"
|
|
120
|
+
lines.append(f"Idle Status: {icon}")
|
|
121
|
+
|
|
122
|
+
# Timing information
|
|
123
|
+
if idle_state.get("idle_seconds"):
|
|
124
|
+
timeout = idle_state.get("timeout_seconds", 1800)
|
|
125
|
+
elapsed = idle_state["idle_seconds"]
|
|
126
|
+
remaining = max(0, timeout - elapsed)
|
|
127
|
+
lines.append(f"Idle Time: {elapsed}s / {timeout}s")
|
|
128
|
+
if remaining > 0:
|
|
129
|
+
minutes = remaining // 60
|
|
130
|
+
# Yellow text using ANSI escape codes
|
|
131
|
+
lines.append(f"\033[33mWill shutdown in: {remaining}s ({minutes}m)\033[0m")
|
|
132
|
+
|
|
133
|
+
# Attached studios (show before sensors)
|
|
134
|
+
if attached_studios:
|
|
135
|
+
# Purple text for studio names
|
|
136
|
+
studio_names = ", ".join(
|
|
137
|
+
[
|
|
138
|
+
f"\033[35m{s.get('user', s.get('studio_id', 'unknown'))}\033[0m"
|
|
139
|
+
for s in attached_studios
|
|
140
|
+
]
|
|
141
|
+
)
|
|
142
|
+
lines.append(f"\nAttached Studios: {studio_names}")
|
|
143
|
+
else:
|
|
144
|
+
# Normal text for "None"
|
|
145
|
+
lines.append(f"\nAttached Studios: None")
|
|
146
|
+
|
|
147
|
+
# Detailed sensor information with colorful emojis
|
|
148
|
+
if detailed and idle_state.get("sensors"):
|
|
149
|
+
lines.append(f"\n{'═'*60}")
|
|
150
|
+
lines.append("🔍 Activity Sensors:")
|
|
151
|
+
lines.append(f"{'═'*60}")
|
|
152
|
+
|
|
153
|
+
# Sensor emoji mapping
|
|
154
|
+
sensor_emojis = {
|
|
155
|
+
"coffee": "☕",
|
|
156
|
+
"ssh": "🐚",
|
|
157
|
+
"ide": "💻",
|
|
158
|
+
"docker": "🐳",
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
for sensor_name, sensor_data in idle_state["sensors"].items():
|
|
162
|
+
emoji = sensor_emojis.get(sensor_name.lower(), "📊")
|
|
163
|
+
active = sensor_data.get("active", False)
|
|
164
|
+
|
|
165
|
+
# Special formatting for coffee sensor
|
|
166
|
+
if sensor_name.lower() == "coffee" and active:
|
|
167
|
+
# Extract minutes from details for cleaner display
|
|
168
|
+
details = sensor_data.get("details", {})
|
|
169
|
+
remaining_seconds = int(details.get("remaining_seconds", 0))
|
|
170
|
+
remaining_minutes = remaining_seconds // 60
|
|
171
|
+
lines.append(f"\n{emoji} {sensor_name.upper()} 🟢")
|
|
172
|
+
lines.append(f" Caffeinated for another {remaining_minutes}m")
|
|
173
|
+
else:
|
|
174
|
+
status_icon = format_sensor_status(sensor_data)
|
|
175
|
+
# Format: emoji NAME status_icon (on same line for inactive, split for active)
|
|
176
|
+
if active:
|
|
177
|
+
lines.append(
|
|
178
|
+
f"\n{emoji} {sensor_name.upper()} {status_icon.split(chr(10))[0]}"
|
|
179
|
+
)
|
|
180
|
+
# Add reason on next line
|
|
181
|
+
reason_line = (
|
|
182
|
+
status_icon.split("\n")[1] if "\n" in status_icon else ""
|
|
183
|
+
)
|
|
184
|
+
if reason_line:
|
|
185
|
+
lines.append(reason_line)
|
|
186
|
+
else:
|
|
187
|
+
lines.append(f"\n{emoji} {sensor_name.upper()} {status_icon}")
|
|
188
|
+
|
|
189
|
+
# Show details if available (skip for active coffee sensor with special formatting)
|
|
190
|
+
if sensor_name.lower() == "coffee" and active:
|
|
191
|
+
continue # Already showed coffee details in special format above
|
|
192
|
+
|
|
193
|
+
details = sensor_data.get("details", {})
|
|
194
|
+
if details:
|
|
195
|
+
for key, value in details.items():
|
|
196
|
+
# Skip internal bookkeeping fields and redundant info
|
|
197
|
+
if key in [
|
|
198
|
+
"unique_flavor_count",
|
|
199
|
+
"unique_pid_count",
|
|
200
|
+
"expires_at",
|
|
201
|
+
"flavors",
|
|
202
|
+
"remaining_seconds", # Redundant with time shown in reason
|
|
203
|
+
"pid_count", # Redundant with connections list
|
|
204
|
+
"connections", # Redundant, connections shown in sessions/containers
|
|
205
|
+
]:
|
|
206
|
+
continue
|
|
207
|
+
|
|
208
|
+
if isinstance(value, list):
|
|
209
|
+
if value: # Only show non-empty lists
|
|
210
|
+
# Show workload containers with clear header
|
|
211
|
+
if key == "containers":
|
|
212
|
+
# Show actual workload container names that are keeping engine active
|
|
213
|
+
for item in value[:5]:
|
|
214
|
+
lines.append(f" • {item}")
|
|
215
|
+
elif key in ["connections", "sessions"]:
|
|
216
|
+
# Just show the items with bullets, no header
|
|
217
|
+
for item in value[:5]:
|
|
218
|
+
lines.append(f" • {item}")
|
|
219
|
+
elif key == "ignored":
|
|
220
|
+
# Ignored list at same indentation level, with header
|
|
221
|
+
lines.append(f" {key}:")
|
|
222
|
+
for item in value[:5]:
|
|
223
|
+
lines.append(f" • {item}")
|
|
224
|
+
else:
|
|
225
|
+
# Other lists get shown with bullets only
|
|
226
|
+
for item in value[:5]:
|
|
227
|
+
lines.append(f" • {item}")
|
|
228
|
+
elif not isinstance(value, (dict, list)):
|
|
229
|
+
lines.append(f" ℹ️ {key}: {value}")
|
|
230
|
+
|
|
231
|
+
return "\n".join(lines)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def format_time_ago(timestamp: str) -> str:
|
|
235
|
+
"""Format timestamp as time ago.
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
timestamp: ISO format timestamp
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
Human readable time ago string
|
|
242
|
+
"""
|
|
243
|
+
from datetime import datetime
|
|
244
|
+
|
|
245
|
+
try:
|
|
246
|
+
dt = datetime.fromisoformat(timestamp.replace("Z", "+00:00"))
|
|
247
|
+
now = datetime.now(dt.tzinfo)
|
|
248
|
+
delta = now - dt
|
|
249
|
+
|
|
250
|
+
seconds = int(delta.total_seconds())
|
|
251
|
+
if seconds < 60:
|
|
252
|
+
return f"{seconds}s ago"
|
|
253
|
+
elif seconds < 3600:
|
|
254
|
+
return f"{seconds // 60}m ago"
|
|
255
|
+
elif seconds < 86400:
|
|
256
|
+
return f"{seconds // 3600}h ago"
|
|
257
|
+
else:
|
|
258
|
+
return f"{seconds // 86400}d ago"
|
|
259
|
+
except:
|
|
260
|
+
return timestamp
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# CLI Output Simulators
|
|
2
|
+
|
|
3
|
+
This directory contains simulators for iterating on CLI output design without needing AWS access. They're useful for:
|
|
4
|
+
|
|
5
|
+
- Rapid UI iteration during development
|
|
6
|
+
- Visualizing edge cases and different states
|
|
7
|
+
- Testing output formatting without live infrastructure
|
|
8
|
+
- Documentation and examples
|
|
9
|
+
|
|
10
|
+
## Available Simulators
|
|
11
|
+
|
|
12
|
+
### 1. Engine List Simulator
|
|
13
|
+
|
|
14
|
+
Simulates `dh engine2 list` output with different configurations.
|
|
15
|
+
|
|
16
|
+
**Usage:**
|
|
17
|
+
```bash
|
|
18
|
+
# Show all scenarios
|
|
19
|
+
python dayhoff_tools/cli/engines_studios/simulators/engine_list_simulator.py
|
|
20
|
+
|
|
21
|
+
# Show specific scenario
|
|
22
|
+
python dayhoff_tools/cli/engines_studios/simulators/engine_list_simulator.py --scenario few
|
|
23
|
+
|
|
24
|
+
# Override environment
|
|
25
|
+
python dayhoff_tools/cli/engines_studios/simulators/engine_list_simulator.py --scenario many --env prod
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Scenarios:**
|
|
29
|
+
- `single` - Single running engine
|
|
30
|
+
- `few` - Few engines with mixed states (running, stopped, starting)
|
|
31
|
+
- `many` - Many engines (production-like)
|
|
32
|
+
- `empty` - No engines
|
|
33
|
+
- `transitions` - All transitional states (starting, stopping, pending)
|
|
34
|
+
- `all` - Show all scenarios
|
|
35
|
+
|
|
36
|
+
### 2. Engine Status Simulator
|
|
37
|
+
|
|
38
|
+
Simulates `dh engine2 status` output for different engine states.
|
|
39
|
+
|
|
40
|
+
**Usage:**
|
|
41
|
+
```bash
|
|
42
|
+
# Show all scenarios
|
|
43
|
+
python dayhoff_tools/cli/engines_studios/simulators/engine_status_simulator.py
|
|
44
|
+
|
|
45
|
+
# Show specific scenario
|
|
46
|
+
python dayhoff_tools/cli/engines_studios/simulators/engine_status_simulator.py --scenario running_active
|
|
47
|
+
|
|
48
|
+
# Override environment
|
|
49
|
+
python dayhoff_tools/cli/engines_studios/simulators/engine_status_simulator.py --scenario stopped --env sand
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Scenarios:**
|
|
53
|
+
- `running_idle` - Running engine with all sensors idle
|
|
54
|
+
- `running_active` - Running engine with SSH, IDE, and coffee active
|
|
55
|
+
- `stopped` - Stopped engine (no idle detection)
|
|
56
|
+
- `starting` - Engine in starting state
|
|
57
|
+
- `stopping` - Engine in stopping state
|
|
58
|
+
- `running_docker` - Running engine with Docker containers
|
|
59
|
+
- `all` - Show all scenarios
|
|
60
|
+
|
|
61
|
+
### 3. Studio Status Simulator
|
|
62
|
+
|
|
63
|
+
Simulates `dh studio2 status` output for different studio states.
|
|
64
|
+
|
|
65
|
+
**Usage:**
|
|
66
|
+
```bash
|
|
67
|
+
# Show all scenarios
|
|
68
|
+
python dayhoff_tools/cli/engines_studios/simulators/studio_status_simulator.py
|
|
69
|
+
|
|
70
|
+
# Show specific scenario
|
|
71
|
+
python dayhoff_tools/cli/engines_studios/simulators/studio_status_simulator.py --scenario attached
|
|
72
|
+
|
|
73
|
+
# Override environment
|
|
74
|
+
python dayhoff_tools/cli/engines_studios/simulators/studio_status_simulator.py --scenario large --env prod
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Scenarios:**
|
|
78
|
+
- `available` - Available studio (not attached)
|
|
79
|
+
- `attached` - Studio attached to an engine
|
|
80
|
+
- `large` - Large production studio
|
|
81
|
+
- `new` - Newly created studio
|
|
82
|
+
- `modifying` - Studio being modified
|
|
83
|
+
- `all` - Show all scenarios
|
|
84
|
+
|
|
85
|
+
### 4. Idle Status Simulator
|
|
86
|
+
|
|
87
|
+
Simulates detailed idle detection output with various sensor configurations.
|
|
88
|
+
|
|
89
|
+
**Usage:**
|
|
90
|
+
```bash
|
|
91
|
+
# Show all scenarios
|
|
92
|
+
python dayhoff_tools/cli/engines_studios/simulators/idle_status_simulator.py
|
|
93
|
+
|
|
94
|
+
# Show specific scenario
|
|
95
|
+
python dayhoff_tools/cli/engines_studios/simulators/idle_status_simulator.py --scenario coffee_lock
|
|
96
|
+
|
|
97
|
+
# Use more emojis
|
|
98
|
+
python dayhoff_tools/cli/engines_studios/simulators/idle_status_simulator.py --colorful
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Scenarios:**
|
|
102
|
+
- `idle` - Completely idle engine (all sensors inactive)
|
|
103
|
+
- `active_ssh_docker` - Active SSH sessions and Docker containers
|
|
104
|
+
- `active_ide` - Active IDE connection (Cursor)
|
|
105
|
+
- `coffee_lock` - Coffee lock active (prevents shutdown)
|
|
106
|
+
- `near_timeout` - Engine near idle timeout
|
|
107
|
+
- `initializing` - Engine just started (initializing state)
|
|
108
|
+
- `stopped` - Stopped engine (no idle detection)
|
|
109
|
+
- `all` - Show all scenarios
|
|
110
|
+
|
|
111
|
+
## Implementation Notes
|
|
112
|
+
|
|
113
|
+
### Standalone Design
|
|
114
|
+
|
|
115
|
+
The simulators are completely standalone and don't require:
|
|
116
|
+
- AWS credentials
|
|
117
|
+
- Network access
|
|
118
|
+
- Installed Python packages (beyond stdlib)
|
|
119
|
+
|
|
120
|
+
They use `simulator_utils.py` which contains formatting functions copied from the main codebase but with no external dependencies.
|
|
121
|
+
|
|
122
|
+
### Synchronization
|
|
123
|
+
|
|
124
|
+
When modifying formatting in the actual CLI code (`engine_commands.py`, `studio_commands.py`, `progress.py`), update the corresponding simulators to match:
|
|
125
|
+
|
|
126
|
+
1. **Output changes** → Update simulator `format_*_output()` functions
|
|
127
|
+
2. **New scenarios** → Add scenarios to `generate_scenarios()`
|
|
128
|
+
3. **New formatters** → Copy to `simulator_utils.py` (without dependencies)
|
|
129
|
+
|
|
130
|
+
### Color Codes
|
|
131
|
+
|
|
132
|
+
The simulators use ANSI escape codes for colors:
|
|
133
|
+
- `\033[32m` - Green (running states, active)
|
|
134
|
+
- `\033[31m` - Red (stopped/terminated)
|
|
135
|
+
- `\033[33m` - Yellow (transitional states, warnings)
|
|
136
|
+
- `\033[34m` - Blue (names, environments)
|
|
137
|
+
- `\033[35m` - Purple (studios)
|
|
138
|
+
- `\033[0m` - Reset
|
|
139
|
+
|
|
140
|
+
## Development Workflow
|
|
141
|
+
|
|
142
|
+
When designing new CLI output:
|
|
143
|
+
|
|
144
|
+
1. **Add scenarios** to the appropriate simulator
|
|
145
|
+
2. **Iterate quickly** by running the simulator
|
|
146
|
+
3. **Review output** for readability and information density
|
|
147
|
+
4. **Implement** in actual CLI code
|
|
148
|
+
5. **Update simulator** to match final implementation
|
|
149
|
+
|
|
150
|
+
This is much faster than deploying infrastructure changes and running real CLI commands for every tweak.
|
|
151
|
+
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Demo script to showcase all CLI output simulators
|
|
3
|
+
|
|
4
|
+
set -e
|
|
5
|
+
|
|
6
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
7
|
+
cd "$SCRIPT_DIR"
|
|
8
|
+
|
|
9
|
+
echo "╔════════════════════════════════════════════════════════════════════════════╗"
|
|
10
|
+
echo "║ CLI Output Simulators Demo ║"
|
|
11
|
+
echo "╚════════════════════════════════════════════════════════════════════════════╝"
|
|
12
|
+
echo ""
|
|
13
|
+
echo "These simulators let you iterate on CLI design without AWS access."
|
|
14
|
+
echo ""
|
|
15
|
+
|
|
16
|
+
read -p "Press Enter to start the demo..."
|
|
17
|
+
|
|
18
|
+
# Engine List Simulator
|
|
19
|
+
echo ""
|
|
20
|
+
echo "┌────────────────────────────────────────────────────────────────────────────┐"
|
|
21
|
+
echo "│ 1. ENGINE LIST - Few engines in different states │"
|
|
22
|
+
echo "└────────────────────────────────────────────────────────────────────────────┘"
|
|
23
|
+
echo ""
|
|
24
|
+
python engine_list_simulator.py --scenario few
|
|
25
|
+
read -p "Press Enter to continue..."
|
|
26
|
+
|
|
27
|
+
# Engine Status - Running with activity
|
|
28
|
+
echo ""
|
|
29
|
+
echo "┌────────────────────────────────────────────────────────────────────────────┐"
|
|
30
|
+
echo "│ 2. ENGINE STATUS - Running engine with SSH, IDE, and Coffee active │"
|
|
31
|
+
echo "└────────────────────────────────────────────────────────────────────────────┘"
|
|
32
|
+
echo ""
|
|
33
|
+
python engine_status_simulator.py --scenario running_active
|
|
34
|
+
read -p "Press Enter to continue..."
|
|
35
|
+
|
|
36
|
+
# Engine Status - Stopped
|
|
37
|
+
echo ""
|
|
38
|
+
echo "┌────────────────────────────────────────────────────────────────────────────┐"
|
|
39
|
+
echo "│ 3. ENGINE STATUS - Stopped engine (no idle detection) │"
|
|
40
|
+
echo "└────────────────────────────────────────────────────────────────────────────┘"
|
|
41
|
+
echo ""
|
|
42
|
+
python engine_status_simulator.py --scenario stopped
|
|
43
|
+
read -p "Press Enter to continue..."
|
|
44
|
+
|
|
45
|
+
# Studio Status - Attached
|
|
46
|
+
echo ""
|
|
47
|
+
echo "┌────────────────────────────────────────────────────────────────────────────┐"
|
|
48
|
+
echo "│ 4. STUDIO STATUS - Studio attached to engine │"
|
|
49
|
+
echo "└────────────────────────────────────────────────────────────────────────────┘"
|
|
50
|
+
echo ""
|
|
51
|
+
python studio_status_simulator.py --scenario attached
|
|
52
|
+
read -p "Press Enter to continue..."
|
|
53
|
+
|
|
54
|
+
# Idle Status - Coffee lock
|
|
55
|
+
echo ""
|
|
56
|
+
echo "┌────────────────────────────────────────────────────────────────────────────┐"
|
|
57
|
+
echo "│ 5. IDLE STATUS - Engine with coffee lock active │"
|
|
58
|
+
echo "└────────────────────────────────────────────────────────────────────────────┘"
|
|
59
|
+
echo ""
|
|
60
|
+
python idle_status_simulator.py --scenario coffee_lock
|
|
61
|
+
read -p "Press Enter to continue..."
|
|
62
|
+
|
|
63
|
+
echo ""
|
|
64
|
+
echo "╔════════════════════════════════════════════════════════════════════════════╗"
|
|
65
|
+
echo "║ Demo Complete! ║"
|
|
66
|
+
echo "╚════════════════════════════════════════════════════════════════════════════╝"
|
|
67
|
+
echo ""
|
|
68
|
+
echo "Try running simulators with different scenarios:"
|
|
69
|
+
echo " • python engine_list_simulator.py --scenario many"
|
|
70
|
+
echo " • python engine_status_simulator.py --scenario running_docker"
|
|
71
|
+
echo " • python studio_status_simulator.py --scenario all"
|
|
72
|
+
echo " • python idle_status_simulator.py --scenario all"
|
|
73
|
+
echo ""
|
|
74
|
+
echo "See README.md for full documentation."
|
|
75
|
+
|