diff --git a/un.js b/un.js index 67ced04..d58257d 100644 --- a/un.js +++ b/un.js @@ -321,14 +321,28 @@ async function cmdExecute(args) { const { publicKey, secretKey } = getApiKeys(args.apiKey); let code; - try { - code = fs.readFileSync(args.sourceFile, 'utf-8'); - } catch (e) { - console.error(`${RED}Error: File not found: ${args.sourceFile}${RESET}`); - process.exit(1); + let language; + + // Check for inline mode: -s/--shell specified, or sourceFile doesn't exist + if (args.execShell) { + // Inline mode with specified language + code = args.sourceFile; + language = args.execShell; + } else if (!fs.existsSync(args.sourceFile)) { + // File doesn't exist - treat as inline bash code + code = args.sourceFile; + language = "bash"; + } else { + // Normal file execution + try { + code = fs.readFileSync(args.sourceFile, 'utf-8'); + } catch (e) { + console.error(`${RED}Error: File not found: ${args.sourceFile}${RESET}`); + process.exit(1); + } + language = detectLanguage(args.sourceFile); } - const language = detectLanguage(args.sourceFile); const payload = { language, code }; if (args.env && args.env.length > 0) { @@ -607,6 +621,7 @@ function parseArgs(argv) { dumpBootstrap: null, dumpFile: null, extend: false, + execShell: null, }; let i = 2; @@ -638,7 +653,12 @@ function parseArgs(argv) { args.apiKey = argv[++i]; i++; } else if (arg === '-s' || arg === '--shell') { - args.shell = argv[++i]; + // For session command, this is shell type. For execute, it's inline exec language. + if (args.command === 'session') { + args.shell = argv[++i]; + } else { + args.execShell = argv[++i]; + } i++; } else if (arg === '-l' || arg === '--list') { args.list = true; diff --git a/un.lua b/un.lua index 3cb4c0e..a41a0a8 100644 --- a/un.lua +++ b/un.lua @@ -242,10 +242,34 @@ local function base64_decode(data) end)) end +local function file_exists(filename) + local file = io.open(filename, "r") + if file then + file:close() + return true + end + return false +end + local function cmd_execute(options) local keys = get_api_keys(options.api_key) - local code = read_file(options.source_file) - local language = detect_language(options.source_file) + local code + local language + + -- Check for inline mode: -s/--shell specified, or source_file doesn't exist + if options.exec_shell then + -- Inline mode with specified language + code = options.source_file + language = options.exec_shell + elseif not file_exists(options.source_file) then + -- File doesn't exist - treat as inline bash code + code = options.source_file + language = "bash" + else + -- Normal file execution + code = read_file(options.source_file) + language = detect_language(options.source_file) + end local payload = { language = language, code = code } @@ -668,7 +692,8 @@ local function main() command = nil, dump_bootstrap = nil, dump_file = nil, - extend = false + extend = false, + exec_shell = nil } local i = 1 @@ -699,7 +724,12 @@ local function main() options.api_key = arg[i] elseif a == "-s" or a == "--shell" then i = i + 1 - options.shell = arg[i] + -- For session command, this is shell type. For execute, it's inline exec language. + if options.command == "session" then + options.shell = arg[i] + else + options.exec_shell = arg[i] + end elseif a == "-l" or a == "--list" then options.list = true elseif a == "--attach" then diff --git a/un.py b/un.py index f87f028..4924557 100644 --- a/un.py +++ b/un.py @@ -200,15 +200,28 @@ def cmd_execute(args): """Execute source code""" public_key, secret_key = get_api_keys(args.api_key) - # Read source file - try: - with open(args.source_file, 'r') as f: - code = f.read() - except FileNotFoundError: - print(f"{RED}Error: File not found: {args.source_file}{RESET}", file=sys.stderr) - sys.exit(1) + # Check for inline mode: -s/--shell specified, or source_file doesn't exist + inline_mode = False + if args.exec_shell: + inline_mode = True + language = args.exec_shell + code = args.source_file # The "file" argument is actually the code + elif not os.path.exists(args.source_file): + # File doesn't exist - treat as inline bash code + inline_mode = True + language = "bash" + code = args.source_file - language = detect_language(args.source_file) + if not inline_mode: + # Read source file + try: + with open(args.source_file, 'r') as f: + code = f.read() + except FileNotFoundError: + print(f"{RED}Error: File not found: {args.source_file}{RESET}", file=sys.stderr) + sys.exit(1) + + language = detect_language(args.source_file) # Build request payload payload = { @@ -746,6 +759,7 @@ Examples: # Execute options (default command) parser.add_argument("source_file", nargs="?", help="Source file to execute") + parser.add_argument("-s", "--shell", dest="exec_shell", metavar="LANG", help="Execute inline code with specified language (defaults to bash if arg is not a file)") parser.add_argument("-e", "--env", action="append", metavar="KEY=VALUE", help="Set environment variable") parser.add_argument("-f", "--files", action="append", metavar="FILE", help="Add input file") parser.add_argument("-a", "--artifacts", action="store_true", help="Return artifacts") diff --git a/un.rb b/un.rb index 77d7334..834e505 100644 --- a/un.rb +++ b/un.rb @@ -172,14 +172,21 @@ end def cmd_execute(options) keys = get_api_keys(options[:api_key]) - unless File.exist?(options[:source_file]) - warn "#{RED}Error: File not found: #{options[:source_file]}#{RESET}" - exit 1 + # Check for inline mode: -s/--shell specified, or source_file doesn't exist + if options[:exec_shell] + # Inline mode with specified language + code = options[:source_file] + language = options[:exec_shell] + elsif !File.exist?(options[:source_file]) + # File doesn't exist - treat as inline bash code + code = options[:source_file] + language = "bash" + else + # Normal file execution + code = File.read(options[:source_file]) + language = detect_language(options[:source_file]) end - code = File.read(options[:source_file]) - language = detect_language(options[:source_file]) - payload = { language: language, code: code } if options[:env] && !options[:env].empty? @@ -670,7 +677,8 @@ def main dump_bootstrap: nil, dump_file: nil, extend: false, - bootstrap_file: nil + bootstrap_file: nil, + exec_shell: nil } # Manual argument parsing @@ -703,7 +711,12 @@ def main options[:api_key] = ARGV[i] when '-s', '--shell' i += 1 - options[:shell] = ARGV[i] + # For session command, this is shell type. For execute, it's inline exec language. + if options[:command] == 'session' + options[:shell] = ARGV[i] + else + options[:exec_shell] = ARGV[i] + end when '-l', '--list' options[:list] = true when '--attach' diff --git a/un.sh b/un.sh index 6f7fa5e..da83b37 100644 --- a/un.sh +++ b/un.sh @@ -215,10 +215,15 @@ cmd_execute() { local network="" local vcpu="" local api_key="${UNSANDBOX_API_KEY:-}" + local exec_shell="" # Parse arguments while [[ $# -gt 0 ]]; do case "$1" in + -s|--shell) + exec_shell="$2" + shift 2 + ;; -e) env_vars+=("$2") shift 2 @@ -258,13 +263,23 @@ cmd_execute() { esac done - if [[ ! -f "$source_file" ]]; then - echo -e "${RED}Error: File not found: $source_file${RESET}" >&2 - exit 1 - fi + local code + local language - local code=$(cat "$source_file") - local language=$(detect_language "$source_file") + # Check for inline mode: -s/--shell specified, or source_file doesn't exist + if [[ -n "$exec_shell" ]]; then + # Inline mode with specified language + code="$source_file" + language="$exec_shell" + elif [[ ! -f "$source_file" ]]; then + # File doesn't exist - treat as inline bash code + code="$source_file" + language="bash" + else + # Normal file execution + code=$(cat "$source_file") + language=$(detect_language "$source_file") + fi # Build JSON payload local payload=$(jq -n \