un-inception/un.v
Russell Ballestrini 9329d9365f Fix Crystal test class variables and V implementation syntax
- Crystal: Wrap class variables in TestCounter class (top-level @@ not allowed)
- V: Fix deprecated const() syntax to individual const declarations
- V: Fix os.execute or-blocks to use exit_code checks
- V: Fix shell variable escaping (use $ for literal $ in shell strings)
- README: Add unit test documentation and CI badge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-06 09:57:49 -05:00

726 lines
21 KiB
V

// PUBLIC DOMAIN - NO LICENSE, NO WARRANTY
//
// This is free public domain software for the public good of a permacomputer hosted
// at permacomputer.com - an always-on computer by the people, for the people. One
// which is durable, easy to repair, and distributed like tap water for machine
// learning intelligence.
//
// The permacomputer is community-owned infrastructure optimized around four values:
//
// TRUTH - First principles, math & science, open source code freely distributed
// FREEDOM - Voluntary partnerships, freedom from tyranny & corporate control
// HARMONY - Minimal waste, self-renewing systems with diverse thriving connections
// LOVE - Be yourself without hurting others, cooperation through natural law
//
// This software contributes to that vision by enabling code execution across 42+
// programming languages through a unified interface, accessible to all. Code is
// seeds to sprout on any abandoned technology.
//
// Learn more: https://www.permacomputer.com
//
// Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
// software, either in source code form or as a compiled binary, for any purpose,
// commercial or non-commercial, and by any means.
//
// NO WARRANTY. THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
//
// That said, our permacomputer's digital membrane stratum continuously runs unit,
// integration, and functional tests on all of it's own software - with our
// permacomputer monitoring itself, repairing itself, with minimal human in the
// loop guidance. Our agents do their best.
//
// Copyright 2025 TimeHexOn & foxhop & russell@unturf
// https://www.timehexon.com
// https://www.foxhop.net
// https://www.unturf.com/software
// UN CLI - V Implementation (using curl subprocess for simplicity)
// Compile: v un.v -o un_v
// Usage:
// un_v script.py
// un_v -e KEY=VALUE script.py
// un_v session --list
// un_v service --name web --ports 8080
import os
const api_base = 'https://api.unsandbox.com'
const portal_base = 'https://unsandbox.com'
const blue = '\x1b[34m'
const red = '\x1b[31m'
const green = '\x1b[32m'
const yellow = '\x1b[33m'
const reset = '\x1b[0m'
fn detect_language(filename string) !string {
ext := os.file_ext(filename)
lang_map := {
'.py': 'python'
'.js': 'javascript'
'.ts': 'typescript'
'.go': 'go'
'.rs': 'rust'
'.c': 'c'
'.cpp': 'cpp'
'.d': 'd'
'.zig': 'zig'
'.nim': 'nim'
'.v': 'v'
'.rb': 'ruby'
'.php': 'php'
'.sh': 'bash'
}
if lang := lang_map[ext] {
return lang
}
return error('Cannot detect language from file extension')
}
fn escape_json(s string) string {
mut result := ''
for c in s {
match c {
`"` { result += '\\"' }
`\\` { result += '\\\\' }
`\n` { result += '\\n' }
`\r` { result += '\\r' }
`\t` { result += '\\t' }
else { result += c.ascii_str() }
}
}
return result
}
fn base64_encode_file(filename string) string {
cmd := "base64 -w0 '${filename}'"
result := os.execute(cmd)
return result.output.trim_space()
}
fn build_input_files_json(files []string) string {
if files.len == 0 {
return ''
}
mut entries := []string{}
for f in files {
basename := os.file_name(f)
content := base64_encode_file(f)
entries << '{"filename":"${basename}","content":"${content}"}'
}
return ',"input_files":[' + entries.join(',') + ']'
}
fn exec_curl(cmd string) string {
result := os.execute(cmd)
output := result.output
// Check for timestamp authentication errors
if output.contains('timestamp') &&
(output.contains('401') || output.contains('expired') || output.contains('invalid')) {
eprintln('${red}Error: Request timestamp expired (must be within 5 minutes of server time)${reset}')
eprintln('${yellow}Your computer\'s clock may have drifted.${reset}')
eprintln('Check your system time and sync with NTP if needed:')
eprintln(' Linux: sudo ntpdate -s time.nist.gov')
eprintln(' macOS: sudo sntp -sS time.apple.com')
eprintln(' Windows: w32tm /resync')
exit(1)
}
return output
}
fn extract_json_string(json string, key string) string {
search := '"${key}":"'
start_idx := json.index(search) or { return '' }
start := start_idx + search.len
mut end := start
for end < json.len {
if json[end] == `"` && (end == 0 || json[end - 1] != `\\`) {
break
}
end++
}
if end > start {
raw := json[start..end]
// Unescape JSON string
return raw.replace('\\n', '\n')
.replace('\\r', '\r')
.replace('\\t', '\t')
.replace('\\"', '"')
.replace('\\\\', '\\')
}
return ''
}
fn cmd_key(extend bool, api_key string) {
pub_key := get_public_key()
secret_key := get_secret_key()
body := '{}'
cmd := "BODY='${body}'; TIMESTAMP=\$\$(date +%s); MESSAGE=\"\$\$TIMESTAMP:POST:/keys/validate:\$\$BODY\"; SIGNATURE=\$\$(echo -n \"\$\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${portal_base}/keys/validate' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \$\$TIMESTAMP\" -H \"X-Signature: \$\$SIGNATURE\" -d \"\$\$BODY\""
result := exec_curl(cmd)
public_key := extract_json_string(result, 'public_key')
tier := extract_json_string(result, 'tier')
status := extract_json_string(result, 'status')
expires_at := extract_json_string(result, 'expires_at')
time_remaining := extract_json_string(result, 'time_remaining')
rate_limit := extract_json_string(result, 'rate_limit')
burst := extract_json_string(result, 'burst')
concurrency := extract_json_string(result, 'concurrency')
expired := extract_json_string(result, 'expired')
if extend && public_key != '' {
url := '${portal_base}/keys/extend?pk=${public_key}'
println('${blue}Opening browser to extend key...${reset}')
// Try xdg-open (Linux), open (macOS), or start (Windows)
mut opened := false
result := os.execute('xdg-open "${url}"')
if result.exit_code == 0 {
opened = true
}
if !opened {
result2 := os.execute('open "${url}"')
if result2.exit_code == 0 {
opened = true
}
}
if !opened {
result3 := os.execute('cmd /c start "${url}"')
if result3.exit_code != 0 {
eprintln('${red}Error: Could not open browser${reset}')
}
}
return
}
if expired == 'true' {
println('${red}Expired${reset}')
println('Public Key: ${public_key}')
println('Tier: ${tier}')
if expires_at != '' {
println('Expired: ${expires_at}')
}
println('${yellow}To renew: Visit https://unsandbox.com/keys/extend${reset}')
exit(1)
}
// Valid key
println('${green}Valid${reset}')
println('Public Key: ${public_key}')
if tier != '' {
println('Tier: ${tier}')
}
if status != '' {
println('Status: ${status}')
}
if expires_at != '' {
println('Expires: ${expires_at}')
}
if time_remaining != '' {
println('Time Remaining: ${time_remaining}')
}
if rate_limit != '' {
println('Rate Limit: ${rate_limit}')
}
if burst != '' {
println('Burst: ${burst}')
}
if concurrency != '' {
println('Concurrency: ${concurrency}')
}
}
fn cmd_execute(source_file string, envs []string, artifacts bool, network string, vcpu int, api_key string) {
lang := detect_language(source_file) or {
eprintln('${red}Error: ${err}${reset}')
exit(1)
}
code := os.read_file(source_file) or {
eprintln('${red}Error reading file: ${err}${reset}')
exit(1)
}
mut json := '{"language":"${lang}","code":"${escape_json(code)}"'
if envs.len > 0 {
json += ',"env":{'
for i, e in envs {
parts := e.split_nth('=', 2)
if parts.len == 2 {
if i > 0 {
json += ','
}
json += '"${parts[0]}":"${escape_json(parts[1])}"'
}
}
json += '}'
}
if artifacts {
json += ',"return_artifacts":true'
}
if network != '' {
json += ',"network":"${network}"'
}
if vcpu > 0 {
json += ',"vcpu":${vcpu}'
}
json += '}'
pub_key := get_public_key()
secret_key := get_secret_key()
cmd := "BODY='${json}'; TIMESTAMP=\$\$(date +%s); MESSAGE=\"\$\$TIMESTAMP:POST:/execute:\$\$BODY\"; SIGNATURE=\$\$(echo -n \"\$\$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/execute' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: \$\$TIMESTAMP\" -H \"X-Signature: \$\$SIGNATURE\" -d \"\$\$BODY\""
println(exec_curl(cmd))
}
fn cmd_session(list bool, kill string, shell string, network string, vcpu int, tmux bool, screen bool, input_files []string, api_key string) {
pub_key := get_public_key()
secret_key := get_secret_key()
if list {
cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:GET:/sessions:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/sessions' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
println(exec_curl(cmd))
return
}
if kill != '' {
cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:DELETE:/sessions/${kill}:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X DELETE '${api_base}/sessions/${kill}' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
exec_curl(cmd)
println('${green}Session terminated: ${kill}${reset}')
return
}
sh := if shell != '' { shell } else { 'bash' }
mut json := '{"shell":"${sh}"'
if network != '' {
json += ',"network":"${network}"'
}
if vcpu > 0 {
json += ',"vcpu":${vcpu}'
}
if tmux {
json += ',"persistence":"tmux"'
}
if screen {
json += ',"persistence":"screen"'
}
json += build_input_files_json(input_files)
json += '}'
println('${yellow}Creating session...${reset}')
cmd := "BODY='${json}'; TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:POST:/sessions:$$BODY\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/sessions' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\" -d \"$$BODY\""
println(exec_curl(cmd))
}
fn cmd_service(name string, ports string, service_type string, bootstrap string, bootstrap_file string, list bool, info string, logs string, tail string, sleep string, wake string, destroy string, execute string, command string, dump_bootstrap string, dump_file string, network string, vcpu int, input_files []string, api_key string) {
pub_key := get_public_key()
secret_key := get_secret_key()
if list {
cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:GET:/services:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
println(exec_curl(cmd))
return
}
if info != '' {
cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:GET:/services/${info}:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services/${info}' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
println(exec_curl(cmd))
return
}
if logs != '' {
cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:GET:/services/${logs}/logs:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services/${logs}/logs' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
print(exec_curl(cmd))
return
}
if tail != '' {
cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:GET:/services/${tail}/logs:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X GET '${api_base}/services/${tail}/logs?lines=9000' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
print(exec_curl(cmd))
return
}
if sleep != '' {
cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:POST:/services/${sleep}/sleep:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${sleep}/sleep' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
exec_curl(cmd)
println('${green}Service sleeping: ${sleep}${reset}')
return
}
if wake != '' {
cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:POST:/services/${wake}/wake:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${wake}/wake' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
exec_curl(cmd)
println('${green}Service waking: ${wake}${reset}')
return
}
if destroy != '' {
cmd := "TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:DELETE:/services/${destroy}:\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X DELETE '${api_base}/services/${destroy}' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\""
exec_curl(cmd)
println('${green}Service destroyed: ${destroy}${reset}')
return
}
if execute != '' {
json := '{"command":"${escape_json(command)}"}'
cmd := "BODY='${json}'; TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:POST:/services/${execute}/execute:$$BODY\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${execute}/execute' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\" -d \"$$BODY\""
result := exec_curl(cmd)
stdout_str := extract_json_string(result, 'stdout')
stderr_str := extract_json_string(result, 'stderr')
if stdout_str != '' {
print(stdout_str)
}
if stderr_str != '' {
eprint(stderr_str)
}
return
}
if dump_bootstrap != '' {
eprintln('Fetching bootstrap script from ${dump_bootstrap}...')
json := '{"command":"cat /tmp/bootstrap.sh"}'
cmd := "BODY='${json}'; TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:POST:/services/${dump_bootstrap}/execute:$$BODY\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services/${dump_bootstrap}/execute' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\" -d \"$$BODY\""
result := exec_curl(cmd)
bootstrap_script := extract_json_string(result, 'stdout')
if bootstrap_script != '' {
if dump_file != '' {
os.write_file(dump_file, bootstrap_script) or {
eprintln('${red}Error: Could not write to ${dump_file}: ${err}${reset}')
exit(1)
}
os.chmod(dump_file, 0o755) or {}
println('Bootstrap saved to ${dump_file}')
} else {
print(bootstrap_script)
}
} else {
eprintln('${red}Error: Failed to fetch bootstrap (service not running or no bootstrap file)${reset}')
exit(1)
}
return
}
if name != '' {
mut json := '{"name":"${name}"'
if ports != '' {
json += ',"ports":[${ports}]'
}
if service_type != '' {
json += ',"service_type":"${service_type}"'
}
if bootstrap != '' {
json += ',"bootstrap":"${escape_json(bootstrap)}"'
}
if bootstrap_file != '' {
if os.exists(bootstrap_file) {
boot_code := os.read_file(bootstrap_file) or {
eprintln('${red}Error: Could not read bootstrap file: ${bootstrap_file}${reset}')
exit(1)
}
json += ',"bootstrap_content":"${escape_json(boot_code)}"'
} else {
eprintln('${red}Error: Bootstrap file not found: ${bootstrap_file}${reset}')
exit(1)
}
}
if network != '' {
json += ',"network":"${network}"'
}
if vcpu > 0 {
json += ',"vcpu":${vcpu}'
}
json += build_input_files_json(input_files)
json += '}'
println('${yellow}Creating service...${reset}')
cmd := "BODY='${json}'; TIMESTAMP=$$(date +%s); MESSAGE=\"$$TIMESTAMP:POST:/services:$$BODY\"; SIGNATURE=$$(echo -n \"$$MESSAGE\" | openssl dgst -sha256 -hmac '${secret_key}' -hex | sed 's/.*= //'); curl -s -X POST '${api_base}/services' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${pub_key}' -H \"X-Timestamp: $$TIMESTAMP\" -H \"X-Signature: $$SIGNATURE\" -d \"$$BODY\""
println(exec_curl(cmd))
return
}
eprintln('${red}Error: Specify --name to create a service${reset}')
exit(1)
}
fn get_public_key() string {
pub_key := os.getenv('UNSANDBOX_PUBLIC_KEY')
if pub_key != '' {
return pub_key
}
api_key := os.getenv('UNSANDBOX_API_KEY')
if api_key != '' {
return api_key
}
eprintln('${red}Error: UNSANDBOX_PUBLIC_KEY or UNSANDBOX_API_KEY environment variable not set${reset}')
exit(1)
}
fn get_secret_key() string {
sec_key := os.getenv('UNSANDBOX_SECRET_KEY')
if sec_key != '' {
return sec_key
}
api_key := os.getenv('UNSANDBOX_API_KEY')
if api_key != '' {
return api_key
}
return ''
}
fn main() {
mut api_key := get_public_key()
if os.args.len < 2 {
eprintln('Usage: ${os.args[0]} [options] <source_file>')
eprintln(' ${os.args[0]} session [options]')
eprintln(' ${os.args[0]} service [options]')
eprintln(' ${os.args[0]} key [--extend]')
exit(1)
}
if os.args[1] == 'session' {
mut list := false
mut kill := ''
mut shell := ''
mut network := ''
mut vcpu := 0
mut tmux := false
mut screen := false
mut input_files := []string{}
mut i := 2
for i < os.args.len {
match os.args[i] {
'--list' { list = true }
'--kill' {
i++
kill = os.args[i]
}
'--shell' {
i++
shell = os.args[i]
}
'-n' {
i++
network = os.args[i]
}
'-v' {
i++
vcpu = os.args[i].int()
}
'--tmux' { tmux = true }
'--screen' { screen = true }
'-k' {
i++
api_key = os.args[i]
}
'-f' {
i++
f := os.args[i]
if os.exists(f) {
input_files << f
} else {
eprintln('Error: File not found: ${f}')
exit(1)
}
}
else {}
}
i++
}
cmd_session(list, kill, shell, network, vcpu, tmux, screen, input_files, api_key)
return
}
if os.args[1] == 'service' {
mut name := ''
mut ports := ''
mut service_type := ''
mut bootstrap := ''
mut bootstrap_file := ''
mut list := false
mut info := ''
mut logs := ''
mut tail := ''
mut sleep := ''
mut wake := ''
mut destroy := ''
mut execute := ''
mut command := ''
mut dump_bootstrap := ''
mut dump_file := ''
mut network := ''
mut vcpu := 0
mut input_files := []string{}
mut i := 2
for i < os.args.len {
match os.args[i] {
'--name' {
i++
name = os.args[i]
}
'--ports' {
i++
ports = os.args[i]
}
'--type' {
i++
service_type = os.args[i]
}
'--bootstrap' {
i++
bootstrap = os.args[i]
}
'--bootstrap-file' {
i++
bootstrap_file = os.args[i]
}
'--list' { list = true }
'--info' {
i++
info = os.args[i]
}
'--logs' {
i++
logs = os.args[i]
}
'--tail' {
i++
tail = os.args[i]
}
'--freeze' {
i++
sleep = os.args[i]
}
'--unfreeze' {
i++
wake = os.args[i]
}
'--destroy' {
i++
destroy = os.args[i]
}
'--execute' {
i++
execute = os.args[i]
}
'--command' {
i++
command = os.args[i]
}
'--dump-bootstrap' {
i++
dump_bootstrap = os.args[i]
}
'--dump-file' {
i++
dump_file = os.args[i]
}
'-n' {
i++
network = os.args[i]
}
'-v' {
i++
vcpu = os.args[i].int()
}
'-k' {
i++
api_key = os.args[i]
}
'-f' {
i++
f := os.args[i]
if os.exists(f) {
input_files << f
} else {
eprintln('Error: File not found: ${f}')
exit(1)
}
}
else {}
}
i++
}
cmd_service(name, ports, service_type, bootstrap, bootstrap_file, list, info, logs, tail, sleep, wake, destroy, execute, command, dump_bootstrap, dump_file, network,
vcpu, input_files, api_key)
return
}
if os.args[1] == 'key' {
mut extend := false
mut i := 2
for i < os.args.len {
match os.args[i] {
'--extend' { extend = true }
'-k' {
i++
api_key = os.args[i]
}
else {}
}
i++
}
cmd_key(extend, api_key)
return
}
// Execute mode
mut envs := []string{}
mut artifacts := false
mut network := ''
mut source_file := ''
mut vcpu := 0
mut i := 1
for i < os.args.len {
match os.args[i] {
'-e' {
i++
envs << os.args[i]
}
'-a' { artifacts = true }
'-n' {
i++
network = os.args[i]
}
'-v' {
i++
vcpu = os.args[i].int()
}
'-k' {
i++
api_key = os.args[i]
}
else {
if os.args[i].starts_with('-') {
eprintln('${red}Unknown option: ${os.args[i]}${reset}')
exit(1)
} else {
source_file = os.args[i]
}
}
}
i++
}
if source_file == '' {
eprintln('${red}Error: No source file specified${reset}')
exit(1)
}
cmd_execute(source_file, envs, artifacts, network, vcpu, api_key)
}