ralph-cli-sandboxed 0.2.5 → 0.2.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/README.md +29 -66
- package/dist/commands/docker.js +329 -25
- package/dist/commands/help.js +1 -0
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.js +156 -72
- package/dist/commands/once.js +251 -13
- package/dist/commands/run.js +233 -5
- package/dist/config/languages.json +1 -1
- package/dist/config/skills.json +12 -0
- package/dist/templates/prompts.d.ts +11 -0
- package/dist/templates/prompts.js +17 -0
- package/dist/utils/config.d.ts +35 -0
- package/dist/utils/prompt.d.ts +1 -1
- package/dist/utils/prompt.js +8 -2
- package/docs/DEVELOPMENT.md +161 -0
- package/docs/DOCKER.md +225 -0
- package/docs/HOW-TO-WRITE-PRDs.md +4 -2
- package/docs/PRD-GENERATOR.md +2 -1
- package/docs/SECURITY.md +78 -0
- package/docs/run-state-machine.md +73 -64
- package/package.json +1 -1
package/docs/DOCKER.md
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# Docker Sandbox
|
|
2
|
+
|
|
3
|
+
Ralph runs AI agents in isolated Docker containers for security. This document covers Docker setup and usage.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Run container (auto-builds image on first run)
|
|
9
|
+
ralph docker run
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
> **Note:** `ralph init` automatically creates Docker files in `.ralph/docker/`. Use `ralph docker init` to regenerate them if needed.
|
|
13
|
+
|
|
14
|
+
## Docker Commands
|
|
15
|
+
|
|
16
|
+
| Command | Description |
|
|
17
|
+
|---------|-------------|
|
|
18
|
+
| `ralph docker init` | Generate/regenerate Docker configuration files |
|
|
19
|
+
| `ralph docker build` | Build the Docker image |
|
|
20
|
+
| `ralph docker run` | Run ralph inside the container (auto-builds if needed) |
|
|
21
|
+
| `ralph docker shell` | Open an interactive shell in the container |
|
|
22
|
+
| `ralph docker status` | Show container and image status |
|
|
23
|
+
|
|
24
|
+
## Generated Files
|
|
25
|
+
|
|
26
|
+
After running `ralph init` or `ralph docker init`, you'll find:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
.ralph/docker/
|
|
30
|
+
├── Dockerfile # Container image definition
|
|
31
|
+
├── docker-compose.yml # Container orchestration
|
|
32
|
+
└── firewall.sh # Network sandbox rules
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
The Docker setup is based on [Claude Code devcontainer](https://github.com/anthropics/claude-code/tree/main/.devcontainer) and includes:
|
|
38
|
+
|
|
39
|
+
- **Network sandboxing** - Firewall allows only GitHub, npm, and Anthropic API
|
|
40
|
+
- **Credential mounting** - Your `~/.claude` OAuth credentials are mounted automatically
|
|
41
|
+
- **Language tooling** - Pre-installed based on your selected language
|
|
42
|
+
- **Non-root user** - Runs as `node` user for security
|
|
43
|
+
|
|
44
|
+
## Customization
|
|
45
|
+
|
|
46
|
+
### Adding Ports
|
|
47
|
+
|
|
48
|
+
Edit `.ralph/config.json`:
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"docker": {
|
|
53
|
+
"ports": ["3000:3000", "5432:5432"]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Then regenerate: `ralph docker init`
|
|
59
|
+
|
|
60
|
+
### Adding Volumes
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"docker": {
|
|
65
|
+
"volumes": ["./data:/app/data"]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Environment Variables
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"docker": {
|
|
75
|
+
"environment": {
|
|
76
|
+
"NODE_ENV": "development",
|
|
77
|
+
"DEBUG": "true"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Git Configuration
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"docker": {
|
|
88
|
+
"git": {
|
|
89
|
+
"name": "Your Name",
|
|
90
|
+
"email": "your@email.com"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Asciinema Recording
|
|
97
|
+
|
|
98
|
+
Record terminal sessions inside the container for demos, debugging, or sharing AI coding sessions. Recordings are saved as `.cast` files that can be played back with `asciinema play` or uploaded to asciinema.org.
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"docker": {
|
|
103
|
+
"asciinema": {
|
|
104
|
+
"enabled": true,
|
|
105
|
+
"autoRecord": true,
|
|
106
|
+
"outputDir": ".recordings"
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
| Setting | Description |
|
|
113
|
+
|---------|-------------|
|
|
114
|
+
| `enabled` | Install asciinema in the container |
|
|
115
|
+
| `autoRecord` | Automatically start recording when container starts |
|
|
116
|
+
| `outputDir` | Directory for recordings (default: `.recordings`) |
|
|
117
|
+
|
|
118
|
+
After enabling, regenerate Docker files: `ralph docker init`
|
|
119
|
+
|
|
120
|
+
**Where recordings are stored:**
|
|
121
|
+
|
|
122
|
+
Recordings are saved to the mounted workspace directory (e.g., `.recordings/`). They never leave the container automatically - no network access is needed.
|
|
123
|
+
|
|
124
|
+
To upload recordings:
|
|
125
|
+
1. Exit the container
|
|
126
|
+
2. From your host machine: `asciinema upload .recordings/session-*.cast`
|
|
127
|
+
3. Or set `ASCIINEMA_SERVER_URL` environment variable before uploading to use a self-hosted server
|
|
128
|
+
|
|
129
|
+
**Manual recording** (when `autoRecord: false`):
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Inside the container
|
|
133
|
+
asciinema rec .recordings/session.cast # Start recording
|
|
134
|
+
exit # Stop recording
|
|
135
|
+
|
|
136
|
+
# After exiting the container, from your host machine:
|
|
137
|
+
asciinema play .recordings/session.cast # Playback
|
|
138
|
+
asciinema upload .recordings/session.cast # Upload to asciinema.org
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Auto-recording** (when `autoRecord: true`):
|
|
142
|
+
|
|
143
|
+
Sessions are automatically recorded to `<outputDir>/session-YYYYMMDD-HHMMSS.cast` when the container starts. Recording stops when you exit the container. Files are available on your host machine in the configured output directory.
|
|
144
|
+
|
|
145
|
+
### Firewall Configuration
|
|
146
|
+
|
|
147
|
+
The container firewall allows only specific domains by default: GitHub, npm registry, and Anthropic API. To allow additional domains (e.g., PyPI, internal registries), configure `firewall.allowedDomains`:
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
"docker": {
|
|
152
|
+
"firewall": {
|
|
153
|
+
"allowedDomains": ["pypi.org", "files.pythonhosted.org"]
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
After adding domains, regenerate Docker files: `ralph docker init`
|
|
160
|
+
|
|
161
|
+
The firewall script resolves domains to IPs at container startup using `dig`. Common use cases:
|
|
162
|
+
|
|
163
|
+
| Use Case | Domains |
|
|
164
|
+
|----------|---------|
|
|
165
|
+
| Python/PyPI | `pypi.org`, `files.pythonhosted.org` |
|
|
166
|
+
| Maven Central | `repo1.maven.org`, `repo.maven.apache.org` |
|
|
167
|
+
| Internal registry | `registry.mycompany.com` |
|
|
168
|
+
|
|
169
|
+
## Installing Packages
|
|
170
|
+
|
|
171
|
+
To install additional packages inside the container, run as root:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
# Update package list and install
|
|
175
|
+
docker compose run -u root ralph apt-get update
|
|
176
|
+
docker compose run -u root ralph apt-get install <package>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
For persistent changes, add the installation to the Dockerfile and rebuild:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
ralph docker build
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Troubleshooting
|
|
186
|
+
|
|
187
|
+
### Image won't build
|
|
188
|
+
|
|
189
|
+
Check Docker is running and you have sufficient disk space:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
docker info
|
|
193
|
+
df -h
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Permission denied errors
|
|
197
|
+
|
|
198
|
+
The container runs as user `node`. If you have permission issues with mounted volumes:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# Fix ownership on host
|
|
202
|
+
sudo chown -R $(id -u):$(id -g) .ralph/
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Network connectivity issues
|
|
206
|
+
|
|
207
|
+
The firewall script restricts outbound connections. If you need additional access:
|
|
208
|
+
|
|
209
|
+
1. Edit `.ralph/docker/firewall.sh`
|
|
210
|
+
2. Add your required domains/IPs
|
|
211
|
+
3. Rebuild: `ralph docker build`
|
|
212
|
+
|
|
213
|
+
### Platform-specific dependencies
|
|
214
|
+
|
|
215
|
+
If you switch between running on host and in container, reinstall node_modules:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
rm -rf node_modules && npm install
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Or use a separate volume for node_modules:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
docker run -v $(pwd):/workspace -v /workspace/node_modules your-image
|
|
225
|
+
```
|
|
@@ -30,9 +30,11 @@ Use consistent categories to organize your PRD:
|
|
|
30
30
|
| `bugfix` | Fixing broken behavior |
|
|
31
31
|
| `refactor` | Code improvements without behavior change |
|
|
32
32
|
| `docs` | Documentation updates |
|
|
33
|
+
| `test` | Adding or updating tests |
|
|
33
34
|
| `release` | Version bumps, changelog updates |
|
|
34
35
|
| `config` | Configuration file changes |
|
|
35
|
-
| `
|
|
36
|
+
| `ui` | User interface changes |
|
|
37
|
+
| `integration` | Connecting components, wiring, orchestration |
|
|
36
38
|
|
|
37
39
|
## Writing Good Descriptions
|
|
38
40
|
|
|
@@ -200,7 +202,7 @@ Break large features into smaller, independently completable items. Each item sh
|
|
|
200
202
|
|
|
201
203
|
```json
|
|
202
204
|
{
|
|
203
|
-
"category": "feature|bugfix|docs|release|
|
|
205
|
+
"category": "setup|feature|bugfix|refactor|docs|test|release|config|ui|integration",
|
|
204
206
|
"description": "Imperative verb + specific what + where (context)",
|
|
205
207
|
"steps": [
|
|
206
208
|
"Concrete action with `commands` and file paths",
|
package/docs/PRD-GENERATOR.md
CHANGED
|
@@ -92,6 +92,7 @@ If a task takes 2 minutes without thinking, combine with related work.
|
|
|
92
92
|
| `test` | Test coverage (unit, integration, e2e) |
|
|
93
93
|
| `release` | Version bumps, changelogs, packaging |
|
|
94
94
|
| `config` | Configuration files, settings |
|
|
95
|
+
| `ui` | User interface changes, frontend components |
|
|
95
96
|
| `integration` | Connecting components, wiring, orchestration |
|
|
96
97
|
|
|
97
98
|
## Writing Descriptions
|
|
@@ -307,7 +308,7 @@ Convert the following document into a Ralph prd.json file.
|
|
|
307
308
|
|
|
308
309
|
Rules:
|
|
309
310
|
1. Each sub-task or atomic feature = one PRD item
|
|
310
|
-
2. Use categories: setup, feature, bugfix, refactor, docs, test, release, config, integration
|
|
311
|
+
2. Use categories: setup, feature, bugfix, refactor, docs, test, release, config, ui, integration
|
|
311
312
|
3. Descriptions: imperative verb + specific what + context
|
|
312
313
|
4. Steps: 2-4 concrete actions + verification step
|
|
313
314
|
5. Reference source document sections instead of copying code
|
package/docs/SECURITY.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Security
|
|
2
|
+
|
|
3
|
+
Ralph automates AI agents that execute code and modify files autonomously. This document explains the security model and requirements.
|
|
4
|
+
|
|
5
|
+
## Container Requirement
|
|
6
|
+
|
|
7
|
+
**It is strongly recommended to run ralph inside a Docker container for security.** The Ralph Wiggum technique involves running an AI agent autonomously, which means granting it elevated permissions to execute code and modify files without manual approval for each action.
|
|
8
|
+
|
|
9
|
+
## The `--dangerously-skip-permissions` Flag
|
|
10
|
+
|
|
11
|
+
When running inside a container, ralph automatically passes the `--dangerously-skip-permissions` flag to Claude Code. This flag:
|
|
12
|
+
|
|
13
|
+
- Allows Claude to execute commands and modify files without prompting for permission
|
|
14
|
+
- Is **only** enabled when ralph detects it's running inside a container
|
|
15
|
+
- Is required for autonomous operation (otherwise Claude would pause for approval on every action)
|
|
16
|
+
|
|
17
|
+
**Warning:** The `--dangerously-skip-permissions` flag gives the AI agent full control over the environment. This is why container isolation is critical:
|
|
18
|
+
|
|
19
|
+
- The container provides a sandbox boundary
|
|
20
|
+
- Network access is restricted to essential services (GitHub, npm, Anthropic API)
|
|
21
|
+
- Your host system remains protected even if something goes wrong
|
|
22
|
+
|
|
23
|
+
## Container Detection
|
|
24
|
+
|
|
25
|
+
Ralph detects container environments by checking:
|
|
26
|
+
|
|
27
|
+
1. `DEVCONTAINER` environment variable
|
|
28
|
+
2. Presence of `/.dockerenv` file
|
|
29
|
+
3. Container indicators in `/proc/1/cgroup` (docker, podman, lxc, containerd)
|
|
30
|
+
4. `container` environment variable (podman, docker)
|
|
31
|
+
|
|
32
|
+
If you're running outside a container and need autonomous mode, use `ralph docker` to set up a safe sandbox environment first.
|
|
33
|
+
|
|
34
|
+
## Network Sandboxing
|
|
35
|
+
|
|
36
|
+
The Docker configuration includes firewall rules limiting network access to:
|
|
37
|
+
|
|
38
|
+
- **GitHub** - For git operations (clone, push, pull)
|
|
39
|
+
- **npm registry** - For dependency installation
|
|
40
|
+
- **Anthropic API** - For Claude API calls
|
|
41
|
+
|
|
42
|
+
All other outbound network traffic is blocked by default.
|
|
43
|
+
|
|
44
|
+
## Credential Handling
|
|
45
|
+
|
|
46
|
+
### OAuth Credentials (Claude Code)
|
|
47
|
+
|
|
48
|
+
For Claude Code users with Pro/Max subscriptions, the `~/.claude` directory is mounted into the container:
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
volumes:
|
|
52
|
+
- ~/.claude:/home/node/.claude:ro
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
This allows the AI agent to use your existing OAuth credentials without exposing API keys.
|
|
56
|
+
|
|
57
|
+
### API Keys
|
|
58
|
+
|
|
59
|
+
For API key-based authentication, pass environment variables to the container:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
docker compose run -e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY ralph
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Never commit API keys to version control.** Use environment variables or Docker secrets.
|
|
66
|
+
|
|
67
|
+
## Best Practices
|
|
68
|
+
|
|
69
|
+
1. **Always use containers** - Never run `ralph run` or `ralph once` outside a container
|
|
70
|
+
2. **Review PRD items** - Check what you're asking the AI to do before running
|
|
71
|
+
3. **Use separate branches** - Let the AI work on feature branches, review before merging
|
|
72
|
+
4. **Monitor progress** - Check `.ralph/progress.txt` and git commits periodically
|
|
73
|
+
5. **Limit scope** - Keep PRD items small and focused to reduce risk
|
|
74
|
+
|
|
75
|
+
## Reporting Security Issues
|
|
76
|
+
|
|
77
|
+
If you discover a security vulnerability, please report it by opening an issue at:
|
|
78
|
+
https://github.com/choas/ralph-cli-sandboxed/issues
|
|
@@ -1,68 +1,77 @@
|
|
|
1
1
|
# Run Command State Machine
|
|
2
2
|
|
|
3
3
|
```mermaid
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
4
|
+
flowchart TD
|
|
5
|
+
subgraph Initialization ["1. Initialization"]
|
|
6
|
+
Start([Start]) --> ParseArgs[Parse CLI Arguments]
|
|
7
|
+
ParseArgs --> ModeSelect{Determine Mode}
|
|
8
|
+
|
|
9
|
+
ModeSelect -- "--loop flag" --> LoopMode[Loop Mode]
|
|
10
|
+
ModeSelect -- "number N" --> CountMode[Count Mode]
|
|
11
|
+
ModeSelect -- "default" --> AllMode[All Mode]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
subgraph Validation ["2. Item Validation"]
|
|
15
|
+
CreateFilteredPRD[Create Filtered PRD] --> HasIncomplete{Incomplete Items?}
|
|
16
|
+
|
|
17
|
+
HasIncomplete -- "Yes" --> StartIteration
|
|
18
|
+
HasIncomplete -- "No" --> ModeCheck
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
subgraph Execution ["3. Execution"]
|
|
22
|
+
StartIteration[Start Iteration] --> SpawnProcess[Spawn CLI Process]
|
|
23
|
+
SpawnProcess --> MonitorProcess[Monitor & Wait]
|
|
24
|
+
MonitorProcess --> CaptureResult[Capture Exit Code]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
subgraph Analysis ["4. Result Analysis"]
|
|
28
|
+
ExitCheck{Exit Code == 0?}
|
|
29
|
+
|
|
30
|
+
ExitCheck -- "No" --> FailurePath[Increment Failure Counter]
|
|
31
|
+
FailurePath --> CriticalCheck{Failures >= 3?}
|
|
32
|
+
CriticalCheck -- "Yes" --> Abort([Abort: Too Many Errors])
|
|
33
|
+
CriticalCheck -- "No" --> SignalCheck
|
|
34
|
+
|
|
35
|
+
ExitCheck -- "Yes" --> SuccessPath[Reset Failure Counter]
|
|
36
|
+
SuccessPath --> SignalCheck
|
|
37
|
+
|
|
38
|
+
SignalCheck{COMPLETE Signal?}
|
|
39
|
+
SignalCheck -- "Yes" --> CompleteModeCheck
|
|
40
|
+
SignalCheck -- "No" --> IterationCheck
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
subgraph Completion ["5. Completion & Polling"]
|
|
44
|
+
ModeCheck{Mode?}
|
|
45
|
+
ModeCheck -- "Loop Mode" --> PollWait
|
|
46
|
+
ModeCheck -- "All/Count Mode" --> FinalReport
|
|
47
|
+
|
|
48
|
+
CompleteModeCheck{Mode?}
|
|
49
|
+
CompleteModeCheck -- "Loop Mode" --> PollWait[Wait 30 Seconds]
|
|
50
|
+
CompleteModeCheck -- "All/Count Mode" --> FinalReport[Final Report]
|
|
51
|
+
|
|
52
|
+
PollWait --> CheckNewItems{New Items Found?}
|
|
53
|
+
CheckNewItems -- "Yes" --> StartIteration
|
|
54
|
+
CheckNewItems -- "No" --> PollWait
|
|
55
|
+
|
|
56
|
+
FinalReport --> End([End])
|
|
57
|
+
|
|
58
|
+
IterationCheck{Limit Reached?}
|
|
59
|
+
IterationCheck -- "Yes" --> FinalReport
|
|
60
|
+
IterationCheck -- "No" --> CreateFilteredPRD
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
%% Cross-subgraph connections
|
|
64
|
+
LoopMode --> CreateFilteredPRD
|
|
65
|
+
CountMode --> CreateFilteredPRD
|
|
66
|
+
AllMode --> CreateFilteredPRD
|
|
67
|
+
CaptureResult --> ExitCheck
|
|
68
|
+
|
|
69
|
+
%% Styling
|
|
70
|
+
style Initialization fill:#f9f9f9,stroke:#333,stroke-width:2px
|
|
71
|
+
style Validation fill:#fff4dd,stroke:#d4a017,stroke-width:2px
|
|
72
|
+
style Execution fill:#e1f5fe,stroke:#01579b,stroke-width:2px
|
|
73
|
+
style Analysis fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
|
|
74
|
+
style Completion fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
|
|
75
|
+
style Abort fill:#ffebee,stroke:#c62828,color:#c62828
|
|
76
|
+
style End fill:#e8f5e9,stroke:#2e7d32,color:#2e7d32
|
|
68
77
|
```
|