launcher is a .
This file contains setup instructions and other details that are more
appropriate for development rather than consumption. If you want to use
launcher in your build2-based project, then instead see the accompanying
package [README.md](/README.md) file.
The development setup for launcher uses the standard bdep-based workflow.
For example:
git clone .../launcher.git
cd launcher
bdep init -C @gcc cc config.cxx=g++
bdep update
bdep test
graph TB
subgraph "Entry Point"
main[main]
opts[options parser]
end
subgraph "Controller Layer"
ctrl[launcher_controller]
ctx[runtime_context]
rstate[remote_state]
end
subgraph "Coordinators"
github[github_coordinator]
http[http_coordinator]
download[download_coordinator]
progress[progress_coordinator]
cache[cache_coordinator]
end
subgraph "Core Subsystems"
reconciler[reconciler]
db[(cache_database)]
manifest[manifest_parser]
end
subgraph "Platform Layer"
steam[steam_detector]
proton[proton_manager]
end
main --> opts
opts --> ctrl
ctrl --> ctx
ctrl --> rstate
ctrl --> github
ctrl --> http
ctrl --> download
ctrl --> progress
ctrl --> cache
cache --> reconciler
cache --> db
github --> manifest
ctrl --> steam
ctrl --> proton
sequenceDiagram
participant M as main()
participant O as options
participant S as Steam Detection
participant U as Self-Update
participant C as Controller
participant G as GitHub API
participant R as Reconciler
participant D as Downloads
participant P as Proton/Native
M->>M: chdir(exe_directory)
M->>O: parse(argc, argv)
alt --wipe-settings
M->>M: remove cache_root
end
alt path not specified
M->>S: resolve_root()
S-->>M: optional<path>
end
alt !no_self_update
M->>U: check_self_update()
U-->>M: restart?
end
M->>C: run()
par Parallel Fetch
C->>G: fetch_latest_release(client)
C->>G: fetch_latest_release(rawfiles)
C->>G: fetch_latest_release(helper)
C->>G: fetch(dlc_manifest)
end
C->>R: plan(manifest)
R-->>C: reconcile_items[]
loop For each download
C->>D: queue_download(item)
end
C->>D: execute_all()
D-->>C: completion
C->>R: verify pass
C->>R: stamp(versions)
C->>P: execute_payload()
P-->>M: exit_code
flowchart TD
A[Start Reconciliation] --> B{Version tags match?}
B -->|Yes| C[Audit filesystem]
B -->|No| D[Full manifest scan]
C --> E{All files valid?}
E -->|Yes| F[Return: up-to-date]
E -->|No| D
D --> G[For each manifest entry]
G --> H{File in DB?}
H -->|No| I[Action: DOWNLOAD]
H -->|Yes| J{Check strategy}
J -->|mtime| K{mtime matches?}
J -->|mixed| L{mtime + size match?}
J -->|hash| M{BLAKE3 matches?}
K -->|Yes| N[Action: NONE]
K -->|No| O[Action: DOWNLOAD]
L -->|Yes| N
L -->|No| O
M -->|Yes| N
M -->|No| O
I --> P[Add to plan]
O --> P
N --> Q[Skip]
P --> R{More entries?}
Q --> R
R -->|Yes| G
R -->|No| S[Return plan]
sequenceDiagram
participant L as Launcher
participant P as proton_manager
participant S as steam.exe (helper)
participant G as Game
L->>P: detect_proton_versions()
P-->>L: proton_version[]
L->>P: find_best_proton()
P-->>L: Proton 9.0
L->>P: build_environment(appid=10190)
P-->>L: proton_environment
L->>P: create_steam_appid()
L->>P: run_ghost_process(steam.exe)
Note over S: Initializes Steamworks API
S-->>L: steam_running
L->>P: launch_through_proton(iw4x.exe)
P->>G: STEAM_COMPAT_DATA_PATH=... proton run iw4x.exe
flowchart LR
subgraph Remote
GH[GitHub Releases]
CDN[CDN: cdn.iw4x.io]
end
subgraph Fetch
API[github_api]
HTTP[http_client]
end
subgraph Parse
MAN[manifest_parser]
end
subgraph Reconcile
REC[reconciler]
DB[(SQLite)]
FS[Filesystem]
end
subgraph Download
DL[download_manager]
PROG[progress_manager]
end
subgraph Extract
ZIP[miniz]
end
GH --> API
CDN --> HTTP
API --> MAN
HTTP --> MAN
MAN --> REC
DB <--> REC
FS <--> REC
REC -->|plan| DL
DL --> PROG
DL --> ZIP
ZIP --> FS
FS --> DB
flowchart TB
subgraph "io_context (single-threaded)"
direction TB
EQ[Event Queue]
EQ --> H1[HTTP handler]
EQ --> H2[Timer handler]
EQ --> H3[Download handler]
end
subgraph "Coroutines"
C1[fetch_release]
C2[download_file]
C3[verify_hash]
end
C1 -.->|co_await| EQ
C2 -.->|co_await| EQ
C3 -.->|co_await| EQ
subgraph "parallel_group"
PG[make_parallel_group]
PG --> C1
PG --> C2
end
stateDiagram-v2
[*] --> pending: Task created
pending --> downloading: execute()
pending --> cancelled: cancel_requested
downloading --> completed: Success
downloading --> failed: Error/Timeout
downloading --> cancelled: cancel_requested
downloading --> paused: pause_requested
paused --> downloading: resume()
paused --> cancelled: cancel_requested
completed --> [*]
failed --> pending: retry()
cancelled --> [*]
flowchart TB
subgraph "Queue Phase"
REQ[download_request]
TASK[basic_download_task]
QUEUE[(task queue)]
end
subgraph "Execution Phase"
SCHED[Scheduler]
ACTIVE[Active Tasks]
POOL[Connection Pool]
end
subgraph "Completion Phase"
CB[on_progress callback]
STATE[state_callback]
DONE[batch_completion]
end
REQ --> |add_task| TASK
TASK --> QUEUE
QUEUE --> |execute_all| SCHED
SCHED --> |max_parallel| ACTIVE
ACTIVE --> POOL
POOL --> |bytes| CB
POOL --> |state change| STATE
ACTIVE --> |all done| DONE
sequenceDiagram
participant U as update_coordinator
participant D as update_discovery
participant I as update_installer
participant G as GitHub API
participant FS as Filesystem
U->>D: check_for_update(owner, repo, version)
D->>G: fetch_latest_release()
G-->>D: release_info
alt Version matches
D-->>U: empty (up-to-date)
else New version available
D-->>U: update_info{version, asset_url}
U->>I: install_update(info)
I->>G: download_asset(url)
G-->>I: binary_data
I->>FS: write_temp_file()
I->>FS: atomic_replace(executable)
I-->>U: update_result{success}
U->>U: restart()
end
flowchart LR
subgraph "Data Layer (Lock-Free)"
METRICS[progress_metrics]
TRACKER[progress_tracker]
end
subgraph "Manager Layer"
ENTRY[progress_entry]
MANAGER[progress_manager]
end
subgraph "Render Layer"
SNAP[progress_snapshot]
CTX[render_context]
RENDER[progress_renderer]
TTY[Terminal Output]
end
METRICS --> |atomic read| SNAP
TRACKER --> |speed calc| SNAP
ENTRY --> |owns| METRICS
ENTRY --> |owns| TRACKER
MANAGER --> |manages| ENTRY
SNAP --> CTX
CTX --> RENDER
RENDER --> TTY
stateDiagram-v2
[*] --> Stopped: Constructor
Stopped --> Running: start()
Running --> Stopped: stop()
state Running {
[*] --> UpdateLoop
UpdateLoop --> RenderLoop: parallel
state UpdateLoop {
[*] --> WaitUpdate
WaitUpdate --> CollectSnapshots: timer expires
CollectSnapshots --> WaitUpdate
}
state RenderLoop {
[*] --> WaitRender
WaitRender --> RenderFrame: timer expires
RenderFrame --> WaitRender
}
}
Stopped --> [*]
graph LR
subgraph "Component Types"
CLIENT[client]
RAW[rawfiles]
DLC[dlc]
HELPER[helper]
LAUNCHER[launcher]
end
subgraph "Update Rules"
STRICT[Strict Hash Check]
FAST[mtime Check]
SELF[Self-Update Flow]
end
CLIENT --> STRICT
HELPER --> STRICT
RAW --> FAST
DLC --> FAST
LAUNCHER --> SELF
erDiagram
cached_file {
string path PK
component_type component
string version
uint64 size
int64 mtime
string hash
}
component_version {
component_type type PK
string tag
int64 timestamp
}
cached_file }|--|| component_version : "belongs to"
stateDiagram-v2
[*] --> unknown: New file detected
unknown --> valid: Download + track()
unknown --> missing: Not in manifest
valid --> stale: mtime changed
valid --> missing: File deleted
stale --> valid: Re-download
stale --> valid: Hash verified OK
missing --> valid: Download + track()
missing --> [*]: Removed from manifest
sequenceDiagram
participant C as Caller
participant API as github_api
participant SSL as SSL Context
participant NET as Network
participant GH as api.github.com
C->>API: fetch_latest_release(owner, repo)
API->>SSL: create_ssl_stream()
API->>NET: async_connect()
NET->>GH: TCP Handshake
GH-->>NET: Connected
API->>NET: async_handshake(ssl)
NET->>GH: TLS Handshake
GH-->>NET: Secure
API->>NET: async_write(GET /repos/.../releases)
NET->>GH: HTTP Request
GH-->>NET: HTTP Response
NET-->>API: github_response
alt Rate Limited
API-->>C: throw rate_limit_exceeded
else Success
API->>API: parse_release(json)
API-->>C: github_release
end
flowchart TD
subgraph "Sources"
CLIENT_M[Client Manifest]
RAW_M[Rawfiles Manifest]
GH_ASSETS[GitHub Assets]
end
subgraph "Index Building"
HASH_IDX[Hash Index]
ARCH_IDX[Archive Index]
FILE_IDX[File Index]
end
subgraph "Merge"
INJECT[Inject Assets]
MERGED[Unified Manifest]
end
CLIENT_M --> HASH_IDX
RAW_M --> HASH_IDX
RAW_M --> ARCH_IDX
RAW_M --> FILE_IDX
GH_ASSETS --> INJECT
HASH_IDX --> INJECT
ARCH_IDX --> INJECT
FILE_IDX --> INJECT
INJECT --> MERGED
CLIENT_M --> MERGED
flowchart TD
DL[Downloaded ZIP] --> CHECK{In archive map?}
CHECK -->|No| SKIP[Skip extraction]
CHECK -->|Yes| EXTRACT[miniz extract]
EXTRACT --> FILES[Extracted files]
FILES --> TRACK[track files in DB]
TRACK --> CLEANUP[Remove ZIP]
EXTRACT -->|Error| FAIL[throw runtime_error]
flowchart TD
START[proton_coordinator::complete_launch]
START --> DETECT[detect_proton_versions]
DETECT --> VERSIONS{Versions found?}
VERSIONS -->|No| ERROR[Return false]
VERSIONS -->|Yes| BEST[find_best_version]
BEST --> PREPARE[prepare_environment]
subgraph "Environment Setup"
PREPARE --> COMPAT[Set STEAM_COMPAT_DATA_PATH]
COMPAT --> CLIENT[Set STEAM_COMPAT_CLIENT_INSTALL_PATH]
CLIENT --> APPID[Create steam_appid.txt]
end
APPID --> SETUP[setup_for_launch]
SETUP --> GHOST[Check Steam via ghost process]
GHOST --> RUNNING{Steam Running?}
RUNNING -->|No| STARTSTEAM[start_steam]
RUNNING -->|Yes| LAUNCH
STARTSTEAM --> LAUNCH[launch via Proton]
LAUNCH --> EXEC["proton run executable.exe"]
sequenceDiagram
participant C as Caller
participant S as http_session
participant R as Resolver
participant SSL as SSL Context
participant TCP as TCP Socket
C->>S: request(url)
S->>S: parse_url()
S->>R: async_resolve(host, port)
R-->>S: endpoints[]
loop Try each endpoint
S->>TCP: async_connect(endpoint)
alt Success
TCP-->>S: connected
else Timeout
S->>TCP: try next endpoint
end
end
alt HTTPS
S->>SSL: async_handshake()
SSL-->>S: secure
end
S->>TCP: async_write(request)
TCP-->>S: bytes_sent
S->>TCP: async_read(response)
TCP-->>S: response_data
alt Redirect (301/302/307)
S->>S: follow_redirect()
else Success
S-->>C: http_response
end
flowchart TD
subgraph "Exception Sources"
NET[Network Error]
PARSE[Parse Error]
FS[Filesystem Error]
RATE[Rate Limit]
end
subgraph "Propagation"
CORO[Coroutine Exception]
SPAWN[co_spawn callback]
end
subgraph "Handling"
LOG[Log to stderr]
CODE[Set exit_code]
STOP[ioc.stop]
end
NET --> CORO
PARSE --> CORO
FS --> CORO
RATE --> CORO
CORO --> SPAWN
SPAWN --> LOG
LOG --> CODE
CODE --> STOP
classDiagram
class manifest {
+vector~manifest_file~ files
+vector~manifest_archive~ archives
+hash_type hash
}
class manifest_file {
+hash_type hash
+uint64 size
+string path
+optional~string~ asset_name
+optional~string~ archive_name
}
class manifest_archive {
+hash_type hash
+uint64 size
+string name
+string url
+compression_type compression
+vector~manifest_file~ files
}
class hash_type {
+hash_algorithm algorithm
+string value
+verify(buffer) bool
}
manifest "1" *-- "*" manifest_file
manifest "1" *-- "*" manifest_archive
manifest_archive "1" *-- "*" manifest_file
manifest_file --> hash_type
manifest_archive --> hash_type
flowchart TB
subgraph "Traits Layer"
DT[download_task_traits]
DMT[download_manager_traits]
PMT[progress_manager_traits]
RT[reconciler_traits]
HT[http_client_traits]
end
subgraph "Basic Templates"
BDT[basic_download_task]
BDM[basic_download_manager]
BPM[basic_progress_manager]
BR[basic_reconciler]
BHC[basic_http_client]
end
subgraph "Concrete Types"
TASK[download_task]
MGR[download_manager]
PROG[progress_manager]
REC[reconciler]
HTTP[http_client]
end
DT --> BDT
DMT --> BDM
PMT --> BPM
RT --> BR
HT --> BHC
BDT --> TASK
BDM --> MGR
BPM --> PROG
BR --> REC
BHC --> HTTP
sequenceDiagram
participant C as Controller
participant R as Reconciler
participant D as Downloads
participant FS as Filesystem
Note over C,FS: First Pass - Trust Download Results
C->>R: plan(manifest)
R-->>C: items[]
loop Each download item
C->>D: queue_download()
end
C->>D: execute_all()
D-->>C: completion
Note over C,FS: Second Pass - Verify Filesystem
C->>D: clear()
C->>R: plan(manifest) again
R->>FS: stat each file
FS-->>R: file_state
alt Any missing/stale
R-->>C: new items[]
C->>D: re-download stragglers
else All valid
R-->>C: empty plan
C->>R: stamp(versions)
end
stateDiagram-v2
[*] --> idle: Constructor
idle --> checking: check_for_updates()
checking --> idle: up_to_date
checking --> idle: update_available
checking --> failed: check_failed
idle --> downloading: install_update()
downloading --> installing: download complete
downloading --> failed: download error
installing --> verifying: extract complete
verifying --> restarting: verify OK
verifying --> failed: verify failed
restarting --> [*]: exec() new binary
failed --> idle: reset()
flowchart TD
REQ[GitHub API Request] --> RESP{Response Code?}
RESP -->|200-299| SUCCESS[Parse & Return]
RESP -->|403/429| RATE[Rate Limited]
RESP -->|Other| ERROR[HTTP Error]
RATE --> HEADERS[Extract X-RateLimit-*]
HEADERS --> CALC[Calculate wait time]
CALC --> WAIT{Wait or Fail?}
WAIT -->|Retry enabled| SLEEP[co_await timer]
SLEEP --> REQ
WAIT -->|No retry| THROW[throw rate_limit_exceeded]
ERROR --> THROW2[throw http_error]
flowchart TB
subgraph "launcher_controller (owns)"
IOC[io_context&]
CTX[runtime_context]
end
subgraph "Coordinators (owned)"
GH[github_coordinator]
HTTP[http_coordinator]
DL[download_coordinator]
PROG[progress_coordinator]
CACHE[cache_coordinator]
end
subgraph "Managers (owned by coordinators)"
GH --> GHAPI[github_api]
HTTP --> HTTPC[http_client]
DL --> DLM[download_manager]
PROG --> PM[progress_manager]
CACHE --> REC[reconciler]
CACHE --> DB[cache_database]
end
IOC -.->|ref| GH
IOC -.->|ref| HTTP
IOC -.->|ref| DL
IOC -.->|ref| PROG
IOC -.->|ref| CACHE
flowchart LR
subgraph "Version Components"
MAJOR[major]
MINOR[minor]
PATCH[patch]
PRE[pre_release]
SNAP[snapshot_sn]
SNAPID[snapshot_id]
end
subgraph "Examples"
R1["1.1.0 (release)"]
R2["1.2.0-a.1 (alpha)"]
R3["1.2.0-b.2 (beta)"]
R4["1.2.0-a.1.z (dev snapshot)"]
R5["1.2.0-a.1.20260201.fe4660 (commit)"]
end
MAJOR --> R1
MINOR --> R1
PATCH --> R1
PRE --> R2
PRE --> R3
SNAP --> R4
SNAPID --> R5
flowchart TD
START[resolve_cache_root] --> PLATFORM{Platform?}
PLATFORM -->|Windows| WIN_CHECK{LOCALAPPDATA?}
WIN_CHECK -->|Set| WIN_LOCAL["$LOCALAPPDATA/iw4x"]
WIN_CHECK -->|Unset| WIN_APP{APPDATA?}
WIN_APP -->|Set| WIN_ROAM["$APPDATA/iw4x"]
WIN_APP -->|Unset| WIN_CWD["./.iw4x"]
PLATFORM -->|macOS| MAC_CHECK{HOME?}
MAC_CHECK -->|Set| MAC_PATH["~/Library/Application Support/iw4x"]
MAC_CHECK -->|Unset| MAC_CWD["./.iw4x"]
PLATFORM -->|Linux| XDG_CHECK{XDG_CACHE_HOME?}
XDG_CHECK -->|Set| XDG_PATH["$XDG_CACHE_HOME/iw4x"]
XDG_CHECK -->|Unset| HOME_CHECK{HOME?}
HOME_CHECK -->|Set| LINUX_CACHE["~/.cache/iw4x"]
HOME_CHECK -->|Unset| LINUX_CWD["./.iw4x"]
WIN_LOCAL --> SCOPE
WIN_ROAM --> SCOPE
WIN_CWD --> SCOPE
MAC_PATH --> SCOPE
MAC_CWD --> SCOPE
XDG_PATH --> SCOPE
LINUX_CACHE --> SCOPE
LINUX_CWD --> SCOPE
SCOPE{Has scope path?}
SCOPE -->|Yes| DIGEST["+ path_digest(scope)"]
SCOPE -->|No| MKDIR
DIGEST --> MKDIR[create_directories]
MKDIR --> SUCCESS{Created?}
SUCCESS -->|Yes| RETURN[Return path]
SUCCESS -->|No| FALLBACK["./.iw4x fallback"]
FALLBACK --> RETURN
flowchart LR
subgraph "Input"
BYTES[current_bytes]
TIME[current_time]
end
subgraph "Ring Buffer"
S1[sample 0]
S2[sample 1]
S3[sample ...]
S4[sample N-1]
end
subgraph "Calculation"
DELTA_B[Δ bytes]
DELTA_T[Δ time]
INSTANT[instant_speed]
EWMA["EWMA: α×new + (1-α)×old"]
end
BYTES --> DELTA_B
TIME --> DELTA_T
DELTA_B --> INSTANT
DELTA_T --> INSTANT
INSTANT --> S1
S1 --> S2
S2 --> S3
S3 --> S4
S4 --> EWMA
EWMA --> OUTPUT[smoothed speed]
flowchart TB
subgraph "Data Collection"
ENTRIES[progress_entries]
SNAP[Create snapshots]
CTX[render_context]
end
subgraph "FTXUI Components"
ITEMS[render_item per entry]
SUMMARY[render_summary]
LOGS[render_logs]
STATUS[render_status]
end
subgraph "Terminal Output"
VBOX[vbox layout]
SCREEN[screen.Post]
TTY[Terminal]
end
ENTRIES --> SNAP
SNAP --> CTX
CTX --> ITEMS
CTX --> SUMMARY
CTX --> LOGS
CTX --> STATUS
ITEMS --> VBOX
SUMMARY --> VBOX
LOGS --> VBOX
STATUS --> VBOX
VBOX --> SCREEN
SCREEN --> TTY
sequenceDiagram
participant I as update_installer
participant HTTP as http_client
participant TMP as Temp Directory
participant FS as Filesystem
participant EXE as Running Executable
I->>TMP: create staging directory
I->>HTTP: download(asset_url)
HTTP-->>TMP: write binary to temp
I->>I: verify_size()
alt Hash provided
I->>TMP: compute BLAKE3
I->>I: compare hashes
end
Note over I,EXE: Windows: Cannot overwrite running exe
I->>EXE: rename current → .backup
I->>TMP: move new → current location
I->>FS: set executable permissions
alt Success
I-->>I: update_result{success=true}
else Failure
I->>EXE: rollback: restore .backup
I-->>I: update_result{success=false}
end
flowchart TD
QUEUE[Task Queue] --> SCHED{Active < max_parallel?}
SCHED -->|Yes| START[Start next task]
SCHED -->|No| WAIT[Wait for completion]
START --> ACTIVE[Active Tasks Pool]
WAIT --> LISTEN[Listen for completion event]
ACTIVE --> PROGRESS[on_progress callbacks]
ACTIVE --> COMPLETE{Task done?}
COMPLETE -->|Success| SUCCESS[Mark completed]
COMPLETE -->|Failed| FAILED[Mark failed]
SUCCESS --> CALLBACK[on_task_complete]
FAILED --> CALLBACK
CALLBACK --> SCHED
LISTEN --> COMPLETE
flowchart TD
RELEASE[GitHub Release Assets] --> SCAN[Scan asset names]
SCAN --> MATCH{Match pattern?}
subgraph "Windows Patterns"
W1["*-win64.exe"]
W2["*-windows-x64.exe"]
W3["*.exe"]
end
subgraph "Linux Patterns"
L1["*-linux-x64"]
L2["*-linux64"]
L3["* (no extension)"]
end
subgraph "macOS Patterns"
M1["*-macos-x64"]
M2["*-darwin-x64"]
M3["*.app.zip"]
end
MATCH -->|Windows| W1
MATCH -->|Linux| L1
MATCH -->|macOS| M1
W1 --> SELECT[Select asset]
W2 --> SELECT
L1 --> SELECT
L2 --> SELECT
M1 --> SELECT
M2 --> SELECT
SELECT --> URL[browser_download_url]
sequenceDiagram
participant P as proton_coordinator
participant GHOST as steam.exe (helper)
participant WINE as Proton/Wine
participant STEAM as Steam Client
Note over P,STEAM: Check if Steam API is available
P->>WINE: Launch steam.exe --check
WINE->>GHOST: Execute in Wine prefix
GHOST->>GHOST: SteamAPI_Init()
alt Steam Running
GHOST-->>WINE: Exit code 0
WINE-->>P: steam_running
else Steam Not Running
GHOST-->>WINE: Exit code 1
WINE-->>P: steam_not_running
P->>P: start_steam()
end
flowchart LR
subgraph "Operations"
PERSIST[db.persist]
UPDATE[db.update]
ERASE[db.erase]
QUERY[db.query]
end
subgraph "Transactions"
BEGIN[transaction t]
COMMIT[t.commit]
ROLLBACK[t.rollback]
end
subgraph "Tables"
CF[(cached_files)]
CV[(component_versions)]
end
PERSIST --> BEGIN
UPDATE --> BEGIN
ERASE --> BEGIN
QUERY --> BEGIN
BEGIN --> CF
BEGIN --> CV
CF --> COMMIT
CV --> COMMIT
flowchart TD
START[controller.run] --> REMOTE[resolve_remote_state]
subgraph "Parallel API Calls"
C[fetch client release]
R[fetch rawfiles release]
H[fetch helper release]
D[fetch DLC manifest]
end
REMOTE --> C & R & H & D
C & R & H & D --> MERGE[Build remote_state]
MERGE --> RECONCILE[reconcile_artifacts]
subgraph "Reconciliation"
PLAN[Generate plan]
DOWNLOAD[Execute downloads]
VERIFY[Two-pass verify]
EXTRACT[Extract archives]
STAMP[Stamp versions]
end
RECONCILE --> PLAN --> DOWNLOAD --> VERIFY --> EXTRACT --> STAMP
STAMP --> PAYLOAD[execute_payload]
subgraph "Launch"
NATIVE[Native execution]
PROTON[Proton execution]
end
PAYLOAD -->|Windows| NATIVE
PAYLOAD -->|Linux| PROTON
NATIVE --> EXIT[Return exit_code]
PROTON --> EXIT
flowchart TD
REQ[HTTP Request] --> RESULT{Success?}
RESULT -->|Yes| DONE[Return response]
RESULT -->|No| RETRY{Retries left?}
RETRY -->|No| FAIL[Throw error]
RETRY -->|Yes| BACKOFF[Calculate delay]
BACKOFF --> DELAY["delay = base × 2^attempt"]
DELAY --> JITTER["+ random jitter"]
JITTER --> CAP["min(delay, max_delay)"]
CAP --> WAIT[co_await timer]
WAIT --> REQ