Skip to content

Commit 251fba5

Browse files
authored
feat: add --output json flag for machine-readable output (#67)
## Summary - Add `--output json` (or `-o json`) flag to CLI commands for machine-readable output - For streaming commands (`deploy`, `invoke`), output is JSONL format (one JSON object per line) - For list commands, output is a JSON array - For single-object commands, output is a JSON object - Update README with JSON output documentation ### Commands with JSON output support: **Tier 1 (create/acquire operations):** - `browsers create` - `browser-pools create`, `acquire` - `profiles create` - `extensions upload` - `proxies create` - `deploy` (JSONL streaming) **Tier 2 (list/get operations):** - `browsers list`, `get`, `view` - `browser-pools list`, `get`, `update` - `profiles list`, `get` - `extensions list` - `proxies list`, `get` **Tier 3 (app/invoke/browser sub-operations):** - `app list`, `history` - `deploy history` - `invoke` (JSONL streaming), `history` - `browsers replays list`, `start` - `browsers process exec`, `spawn` - `browsers fs file-info`, `list-files` ## Test plan - [ ] Test `kernel browsers create -o json` returns valid JSON - [ ] Test `kernel deploy index.ts -o json` streams JSONL events - [ ] Test `kernel app list -o json` returns JSON array - [ ] Test invalid `--output` value shows error message <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds machine-readable output across the CLI and documents it. > > - Introduces `--output json`/`-o json` for many commands (apps, browsers, browser-pools, profiles, extensions, proxies), emitting raw JSON objects/arrays; suppresses interactive logs when JSON is selected and validates unsupported values > - Implements JSONL streaming for `deploy` and `invoke` follow operations, including terminal-state handling and JSON-formatted errors; updates `followDeployment`/invocation streaming paths > - Extends subcommands with new flags and JSON marshalling (e.g., `browsers view/get/create`, replays list/start, process exec/spawn, fs file-info/list-files; browser-pools create/get/update/acquire; app list/history; deploy history) > - Minor flag tweak: `browsers replays download` switches to `-f/--output-file` > - Updates README with JSON output examples and per-command support list > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 362c55a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 4570261 commit 251fba5

File tree

15 files changed

+714
-77
lines changed

15 files changed

+714
-77
lines changed

README.md

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,32 @@ Create an API key from the [Kernel dashboard](https://dashboard.onkernel.com).
104104
- `--no-color` - Disable color output
105105
- `--log-level <level>` - Set log level (trace, debug, info, warn, error, fatal, print)
106106

107+
## JSON Output
108+
109+
Many commands support JSON output for scripting and automation. Use `--output json` or `-o json` to get machine-readable output:
110+
111+
```bash
112+
# Get browser session details as JSON
113+
kernel browsers create -o json
114+
115+
# List apps as JSON
116+
kernel app list -o json
117+
118+
# Deploy with JSONL streaming output (one JSON object per line)
119+
kernel deploy index.ts -o json
120+
```
121+
122+
Commands with JSON output support:
123+
- **Browsers**: `create`, `list`, `get`, `view`
124+
- **Browser Pools**: `create`, `list`, `get`, `update`, `acquire`
125+
- **Profiles**: `create`, `list`, `get`
126+
- **Extensions**: `upload`, `list`
127+
- **Proxies**: `create`, `list`, `get`
128+
- **Apps**: `list`, `history`
129+
- **Deploy**: `deploy` (JSONL streaming), `history`
130+
- **Invoke**: `invoke` (JSONL streaming), `history`
131+
- **Browser Sub-commands**: `replays list/start`, `process exec/spawn`, `fs file-info/list-files`
132+
107133
### Authentication
108134

109135
- `kernel login [--force]` - Login via OAuth 2.0
@@ -134,6 +160,7 @@ Create an API key from the [Kernel dashboard](https://dashboard.onkernel.com).
134160
- `--force` - Allow overwriting existing version
135161
- `--env <KEY=VALUE>`, `-e` - Set environment variables (can be used multiple times)
136162
- `--env-file <file>` - Load environment variables from file (can be used multiple times)
163+
- `--output json`, `-o json` - Output JSONL (one JSON object per line for each event)
137164

138165
- `kernel deploy logs <deployment_id>` - Stream logs for a deployment
139166

@@ -143,6 +170,7 @@ Create an API key from the [Kernel dashboard](https://dashboard.onkernel.com).
143170

144171
- `kernel deploy history [app_name]` - Show deployment history
145172
- `--limit <n>` - Max deployments to return (default: 100; 0 = all)
173+
- `--output json`, `-o json` - Output raw JSON array
146174

147175
### App Management
148176

@@ -152,14 +180,17 @@ Create an API key from the [Kernel dashboard](https://dashboard.onkernel.com).
152180
- `--payload <json>`, `-p` - JSON payload for the action
153181
- `--payload-file <path>`, `-f` - Read JSON payload from a file (use `-` for stdin)
154182
- `--sync`, `-s` - Invoke synchronously (timeout after 60s)
183+
- `--output json`, `-o json` - Output JSONL (one JSON object per line for each event)
155184

156185
- `kernel app list` - List deployed apps
157186

158187
- `--name <app_name>` - Filter by app name
159188
- `--version <version>` - Filter by version
189+
- `--output json`, `-o json` - Output raw JSON array
160190

161191
- `kernel app history <app_name>` - Show deployment history for an app
162192
- `--limit <n>` - Max deployments to return (default: 100; 0 = all)
193+
- `--output json`, `-o json` - Output raw JSON array
163194

164195
### Logs
165196

@@ -172,36 +203,44 @@ Create an API key from the [Kernel dashboard](https://dashboard.onkernel.com).
172203
### Browser Management
173204

174205
- `kernel browsers list` - List running browsers
206+
- `--output json`, `-o json` - Output raw JSON array
175207
- `kernel browsers create` - Create a new browser session
176208
- `-s, --stealth` - Launch browser in stealth mode to avoid detection
177209
- `-H, --headless` - Launch browser without GUI access
178210
- `--kiosk` - Launch browser in kiosk mode
179211
- `--pool-id <id>` - Acquire a browser from the specified pool (mutually exclusive with --pool-name; ignores other session flags)
180212
- `--pool-name <name>` - Acquire a browser from the pool name (mutually exclusive with --pool-id; ignores other session flags)
213+
- `--output json`, `-o json` - Output raw JSON object
181214
- _Note: When a pool is specified, omit other session configuration flags—pool settings determine profile, proxy, viewport, etc._
182215
- `kernel browsers delete <id>` - Delete a browser
183216
- `-y, --yes` - Skip confirmation prompt
184217
- `kernel browsers view <id>` - Get live view URL for a browser
218+
- `--output json`, `-o json` - Output JSON with liveViewUrl
219+
- `kernel browsers get <id>` - Get detailed browser session info
220+
- `--output json`, `-o json` - Output raw JSON object
185221

186222
### Browser Pools
187223

188224
- `kernel browser-pools list` - List browser pools
189-
- `-o, --output json` - Output raw JSON response
225+
- `--output json`, `-o json` - Output raw JSON array
190226
- `kernel browser-pools create` - Create a browser pool
191227
- `--name <name>` - Optional unique name for the pool
192228
- `--size <n>` - Number of browsers in the pool (required)
193229
- `--fill-rate <n>` - Percentage of the pool to fill per minute
194230
- `--timeout <seconds>` - Idle timeout for browsers acquired from the pool
195231
- `--stealth`, `--headless`, `--kiosk` - Default pool configuration
196232
- `--profile-id`, `--profile-name`, `--save-changes`, `--proxy-id`, `--extension`, `--viewport` - Same semantics as `kernel browsers create`
233+
- `--output json`, `-o json` - Output raw JSON object
197234
- `kernel browser-pools get <id-or-name>` - Get pool details
198-
- `-o, --output json` - Output raw JSON response
235+
- `--output json`, `-o json` - Output raw JSON object
199236
- `kernel browser-pools update <id-or-name>` - Update pool configuration
200237
- Same flags as create plus `--discard-all-idle` to discard all idle browsers in the pool and refill at the specified fill rate
238+
- `--output json`, `-o json` - Output raw JSON object
201239
- `kernel browser-pools delete <id-or-name>` - Delete a pool
202240
- `--force` - Force delete even if browsers are leased
203241
- `kernel browser-pools acquire <id-or-name>` - Acquire a browser from the pool
204242
- `--timeout <seconds>` - Acquire timeout before returning 204
243+
- `--output json`, `-o json` - Output raw JSON object
205244
- `kernel browser-pools release <id-or-name>` - Release a browser back to the pool
206245
- `--session-id <id>` - Browser session ID to release (required)
207246
- `--reuse` - Reuse the browser instance (default: true)
@@ -218,12 +257,14 @@ Create an API key from the [Kernel dashboard](https://dashboard.onkernel.com).
218257
### Browser Replays
219258

220259
- `kernel browsers replays list <id>` - List replays for a browser
260+
- `--output json`, `-o json` - Output raw JSON array
221261
- `kernel browsers replays start <id>` - Start a replay recording
222262
- `--framerate <fps>` - Recording framerate (fps)
223263
- `--max-duration <seconds>` - Maximum duration in seconds
264+
- `--output json`, `-o json` - Output raw JSON object
224265
- `kernel browsers replays stop <id> <replay-id>` - Stop a replay recording
225266
- `kernel browsers replays download <id> <replay-id>` - Download a replay video
226-
- `-o, --output <path>` - Output file path for the replay video
267+
- `-f, --output-file <path>` - Output file path for the replay video
227268

228269
### Browser Process Control
229270

@@ -234,13 +275,15 @@ Create an API key from the [Kernel dashboard](https://dashboard.onkernel.com).
234275
- `--timeout <seconds>` - Timeout in seconds
235276
- `--as-user <user>` - Run as user
236277
- `--as-root` - Run as root
278+
- `--output json`, `-o json` - Output raw JSON object
237279
- `kernel browsers process spawn <id> [--] [command...]` - Execute a command asynchronously
238280
- `--command <cmd>` - Command to execute (optional; if omitted, trailing args are executed via /bin/bash -c)
239281
- `--args <args>` - Command arguments
240282
- `--cwd <path>` - Working directory
241283
- `--timeout <seconds>` - Timeout in seconds
242284
- `--as-user <user>` - Run as user
243285
- `--as-root` - Run as root
286+
- `--output json`, `-o json` - Output raw JSON object
244287
- `kernel browsers process kill <id> <process-id>` - Send a signal to a process
245288
- `--signal <signal>` - Signal to send: TERM, KILL, INT, HUP (default: TERM)
246289
- `kernel browsers process status <id> <process-id>` - Get process status
@@ -262,8 +305,10 @@ Create an API key from the [Kernel dashboard](https://dashboard.onkernel.com).
262305
- `-o, --output <path>` - Output zip file path
263306
- `kernel browsers fs file-info <id>` - Get file or directory info
264307
- `--path <path>` - Absolute file or directory path (required)
308+
- `--output json`, `-o json` - Output raw JSON object
265309
- `kernel browsers fs list-files <id>` - List files in a directory
266310
- `--path <path>` - Absolute directory path (required)
311+
- `--output json`, `-o json` - Output raw JSON array
267312
- `kernel browsers fs move <id>` - Move or rename a file or directory
268313
- `--src <path>` - Absolute source path (required)
269314
- `--dest <path>` - Absolute destination path (required)
@@ -344,8 +389,10 @@ Create an API key from the [Kernel dashboard](https://dashboard.onkernel.com).
344389
### Extension Management
345390

346391
- `kernel extensions list` - List all uploaded extensions
392+
- `--output json`, `-o json` - Output raw JSON array
347393
- `kernel extensions upload <directory>` - Upload an unpacked browser extension directory
348394
- `--name <name>` - Optional unique extension name
395+
- `--output json`, `-o json` - Output raw JSON object
349396
- `kernel extensions download <id-or-name>` - Download an extension archive
350397
- `--to <directory>` - Output directory (required)
351398
- `kernel extensions download-web-store <url>` - Download an extension from the Chrome Web Store
@@ -357,8 +404,11 @@ Create an API key from the [Kernel dashboard](https://dashboard.onkernel.com).
357404
### Proxy Management
358405

359406
- `kernel proxies list` - List proxy configurations
407+
- `--output json`, `-o json` - Output raw JSON array
360408
- `kernel proxies get <id>` - Get a proxy configuration by ID
409+
- `--output json`, `-o json` - Output raw JSON object
361410
- `kernel proxies create` - Create a new proxy configuration
411+
- `--output json`, `-o json` - Output raw JSON object
362412

363413
- `--name <name>` - Proxy configuration name
364414
- `--type <type>` - Proxy type: datacenter, isp, residential, mobile, custom (required)

cmd/app.go

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cmd
22

33
import (
4+
"encoding/json"
45
"fmt"
56
"strings"
67

@@ -44,9 +45,11 @@ func init() {
4445
appListCmd.Flags().Int("limit", 20, "Max apps to return (default 20)")
4546
appListCmd.Flags().Int("per-page", 20, "Items per page (alias of --limit)")
4647
appListCmd.Flags().Int("page", 1, "Page number (1-based)")
48+
appListCmd.Flags().StringP("output", "o", "", "Output format: json for raw API response")
4749

4850
// Limit rows returned for app history (0 = all)
4951
appHistoryCmd.Flags().Int("limit", 20, "Max deployments to return (default 20)")
52+
appHistoryCmd.Flags().StringP("output", "o", "", "Output format: json for raw API response")
5053
}
5154

5255
func runAppList(cmd *cobra.Command, args []string) error {
@@ -56,6 +59,11 @@ func runAppList(cmd *cobra.Command, args []string) error {
5659
lim, _ := cmd.Flags().GetInt("limit")
5760
perPage, _ := cmd.Flags().GetInt("per-page")
5861
page, _ := cmd.Flags().GetInt("page")
62+
output, _ := cmd.Flags().GetString("output")
63+
64+
if output != "" && output != "json" {
65+
return fmt.Errorf("unsupported --output value: use 'json'")
66+
}
5967

6068
// Determine pagination inputs: prefer page/per-page if provided; else map legacy --limit
6169
usePager := cmd.Flags().Changed("per-page") || cmd.Flags().Changed("page")
@@ -73,7 +81,9 @@ func runAppList(cmd *cobra.Command, args []string) error {
7381
page = 1
7482
}
7583

76-
pterm.Debug.Println("Fetching deployed applications...")
84+
if output != "json" {
85+
pterm.Debug.Println("Fetching deployed applications...")
86+
}
7787

7888
params := kernel.AppListParams{}
7989
if appName != "" {
@@ -92,6 +102,19 @@ func runAppList(cmd *cobra.Command, args []string) error {
92102
return nil
93103
}
94104

105+
if output == "json" {
106+
if apps == nil || len(apps.Items) == 0 {
107+
fmt.Println("[]")
108+
return nil
109+
}
110+
bs, err := json.MarshalIndent(apps.Items, "", " ")
111+
if err != nil {
112+
return err
113+
}
114+
fmt.Println(string(bs))
115+
return nil
116+
}
117+
95118
if apps == nil || len(apps.Items) == 0 {
96119
pterm.Info.Println("No applications found")
97120
return nil
@@ -193,8 +216,15 @@ func runAppHistory(cmd *cobra.Command, args []string) error {
193216
client := getKernelClient(cmd)
194217
appName := args[0]
195218
lim, _ := cmd.Flags().GetInt("limit")
219+
output, _ := cmd.Flags().GetString("output")
196220

197-
pterm.Debug.Printf("Fetching deployment history for app '%s'...\n", appName)
221+
if output != "" && output != "json" {
222+
return fmt.Errorf("unsupported --output value: use 'json'")
223+
}
224+
225+
if output != "json" {
226+
pterm.Debug.Printf("Fetching deployment history for app '%s'...\n", appName)
227+
}
198228

199229
params := kernel.DeploymentListParams{}
200230
if appName != "" {
@@ -207,6 +237,19 @@ func runAppHistory(cmd *cobra.Command, args []string) error {
207237
return nil
208238
}
209239

240+
if output == "json" {
241+
if deployments == nil || len(deployments.Items) == 0 {
242+
fmt.Println("[]")
243+
return nil
244+
}
245+
bs, err := json.MarshalIndent(deployments.Items, "", " ")
246+
if err != nil {
247+
return err
248+
}
249+
fmt.Println(string(bs))
250+
return nil
251+
}
252+
210253
if deployments == nil || len(deployments.Items) == 0 {
211254
pterm.Info.Println("No deployments found for this application")
212255
return nil

0 commit comments

Comments
 (0)