Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,48 @@ jobs:
- name: Run lints
run: ./scripts/lint

build:
timeout-minutes: 10
name: build
permissions:
contents: read
id-token: write
runs-on: ${{ github.repository == 'stainless-sdks/stainless-v0-cli' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
steps:
- uses: actions/checkout@v6

- name: Setup go
uses: actions/setup-go@v5
with:
go-version-file: ./go.mod

- name: Bootstrap
run: ./scripts/bootstrap

- name: Run goreleaser
uses: goreleaser/goreleaser-action@v6.1.0
with:
version: latest
args: release --snapshot --clean --skip=publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Get GitHub OIDC Token
if: github.repository == 'stainless-sdks/stainless-v0-cli'
id: github-oidc
uses: actions/github-script@v8
with:
script: core.setOutput('github_token', await core.getIDToken());

- name: Upload tarball
if: github.repository == 'stainless-sdks/stainless-v0-cli'
env:
URL: https://pkg.stainless.com/s
AUTH: ${{ steps.github-oidc.outputs.github_token }}
SHA: ${{ github.sha }}
run: ./scripts/utils/upload-artifact.sh

test:
timeout-minutes: 10
name: test
Expand Down
2 changes: 1 addition & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ snapshot:

nfpms:
- license: Apache-2.0
maintainer: local-dev@stainless.com
maintainer: support@stainless.com
bindir: /usr
formats:
- apk
Expand Down
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.1.0-alpha.70"
".": "0.1.0-alpha.71"
}
6 changes: 3 additions & 3 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 21
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/stainless%2Fstainless-v0-8eddc28ac84a2e35494e0698cb6d1b3a682d14f4f9692b89870e3cb9cd30e952.yml
openapi_spec_hash: 1d3a92a6fcfc9efb7b1fe04461952a03
config_hash: 3a9b615b799ae43753c266e776f34e74
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/stainless%2Fstainless-v0-2726a5c9d1b5921ca1eae4d3074e01d53b6a368df847a21722f30b34de324794.yml
openapi_spec_hash: bdbc8f5388f88acaeff72e8f79e57e46
config_hash: 3e46d270da9f524c0dee35db0bcf76df
33 changes: 33 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,38 @@
# Changelog

## 0.1.0-alpha.71 (2026-02-06)

Full Changelog: [v0.1.0-alpha.70...v0.1.0-alpha.71](https://github.com/stainless-api/stainless-api-cli/compare/v0.1.0-alpha.70...v0.1.0-alpha.71)

### ⚠ BREAKING CHANGES

* add support for passing files as parameters

### Features

* add github version check ([3596cbb](https://github.com/stainless-api/stainless-api-cli/commit/3596cbba986e3019e9fc1f9b555728a5c737fe27))
* add readme documentation for passing files as arguments ([3d5c3eb](https://github.com/stainless-api/stainless-api-cli/commit/3d5c3eb26a45dd52a3113fff16e6beda69434199))
* add support for passing files as parameters ([5a44115](https://github.com/stainless-api/stainless-api-cli/commit/5a44115f285231ae36c872a9ad510b48b8d4f55c))
* **api:** update support email address ([a9113c7](https://github.com/stainless-api/stainless-api-cli/commit/a9113c7c26bb474e3118a1d4f096763881cafa15))
* **client:** provide file completions when using file embed syntax ([d480ff2](https://github.com/stainless-api/stainless-api-cli/commit/d480ff2c074f611580f0a36cf96f316d5bc516ca))
* **cli:** improve shell completions for namespaced commands and flags ([d11eba5](https://github.com/stainless-api/stainless-api-cli/commit/d11eba51ee4b07e1360cefde3e329c24d47067d0))


### Bug Fixes

* cleanup and make passing project flag make more sense ([91a6b99](https://github.com/stainless-api/stainless-api-cli/commit/91a6b9977b85c115ca97eee02e655401809c19e3))
* fix for file uploads to octet stream and form encoding endpoints ([55530da](https://github.com/stainless-api/stainless-api-cli/commit/55530da089f0017c9815c456b5a2f850a241f122))
* fix for nullable arguments ([7bbd057](https://github.com/stainless-api/stainless-api-cli/commit/7bbd05715c474f582ce2d076831d01a6fb32e2e4))
* fix for when terminal width is not available ([78d7919](https://github.com/stainless-api/stainless-api-cli/commit/78d791948a88bb9e509da315f8b51b89d452e945))
* fix mock tests with inner fields that have underscores ([0fb140a](https://github.com/stainless-api/stainless-api-cli/commit/0fb140aa40f3e52e01a9a8b8142876e9fcee8647))
* use RawJSON for iterated values instead of re-marshalling ([fcc55a6](https://github.com/stainless-api/stainless-api-cli/commit/fcc55a618a14bf956aa0af852d66e463e0073fbf))


### Chores

* add build step to ci ([c957b31](https://github.com/stainless-api/stainless-api-cli/commit/c957b31381e935c9f8c80738bf003deb5b05727e))
* update documentation in readme ([dc0fd28](https://github.com/stainless-api/stainless-api-cli/commit/dc0fd28e141c8f50c90a47144d7257d596612ada))

## 0.1.0-alpha.70 (2026-01-28)

Full Changelog: [v0.1.0-alpha.69...v0.1.0-alpha.70](https://github.com/stainless-api/stainless-api-cli/compare/v0.1.0-alpha.69...v0.1.0-alpha.70)
Expand Down
61 changes: 59 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,31 @@ brew install stl

### Installing with Go

To test or install the CLI locally, you need [Go](https://go.dev/doc/install) version 1.22 or later installed.

```sh
go install 'github.com/stainless-api/stainless-api-cli/cmd/stl@latest'
```

Once you have run `go install`, the binary is placed in your Go bin directory:

- **Default location**: `$HOME/go/bin` (or `$GOPATH/bin` if GOPATH is set)
- **Check your path**: Run `go env GOPATH` to see the base directory

If commands aren't found after installation, add the Go bin directory to your PATH:

```sh
# Add to your shell profile (.zshrc, .bashrc, etc.)
export PATH="$PATH:$(go env GOPATH)/bin"
```

<!-- x-release-please-end -->

### Running Locally

After cloning the git repository for this project, you can use the
`scripts/run` script to run the tool locally:

```sh
./scripts/run args...
```
Expand All @@ -38,7 +55,7 @@ go install 'github.com/stainless-api/stainless-api-cli/cmd/stl@latest'
The CLI follows a resource-based command structure:

```sh
stl [resource] [command] [flags]
stl [resource] <command> [flags...]
```

```sh
Expand All @@ -55,7 +72,7 @@ stl builds create \

For details about specific commands, use the `--help` flag.

## Global Flags
### Global Flags

- `--help` - Show command line usage
- `--debug` - Enable debug logging (includes HTTP request/response details)
Expand All @@ -66,6 +83,46 @@ For details about specific commands, use the `--help` flag.
- `--format-error` - Change the output format for errors (`auto`, `explore`, `json`, `jsonl`, `pretty`, `raw`, `yaml`)
- `--transform` - Transform the data output using [GJSON syntax](https://github.com/tidwall/gjson/blob/master/SYNTAX.md)
- `--transform-error` - Transform the error output using [GJSON syntax](https://github.com/tidwall/gjson/blob/master/SYNTAX.md)

### Passing files as arguments

To pass files to your API, you can use the `@myfile.ext` syntax:

```bash
stl <command> --arg @abe.jpg
```

Files can also be passed inside JSON or YAML blobs:

```bash
stl <command> --arg '{image: "@abe.jpg"}'
# Equivalent:
stl <command> <<YAML
arg:
image: "@abe.jpg"
YAML
```

If you need to pass a string literal that begins with an `@` sign, you can
escape the `@` sign to avoid accidentally passing a file.

```bash
stl <command> --username '\@abe'
```

#### Explicit encoding

For JSON endpoints, the CLI tool does filetype sniffing to determine whether the
file contents should be sent as a string literal (for plain text files) or as a
base64-encoded string literal (for binary files). If you need to explicitly send
the file as either plain text or base64-encoded data, you can use
`@file://myfile.txt` (for string encoding) or `@data://myfile.dat` (for
base64-encoding). Note that absolute paths will begin with `@file://` or
`@data://`, followed by a third `/` (for example, `@file:///tmp/file.txt`).

```bash
stl <command> --arg @data://file.txt
```
## Workspace Configuration

The CLI supports workspace configuration to avoid repeatedly specifying the project name. When you run a command, the CLI will:
Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ or products provided by Stainless, please follow the respective company's securi

### Stainless Terms and Policies

Please contact local-dev@stainless.com for any questions or concerns regarding the security of our services.
Please contact support@stainless.com for any questions or concerns regarding the security of our services.

---

Expand Down
37 changes: 36 additions & 1 deletion cmd/stl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,34 @@ import (
"fmt"
"net/http"
"os"
"slices"

"github.com/stainless-api/stainless-api-cli/pkg/cmd"
"github.com/stainless-api/stainless-api-cli/pkg/console"
"github.com/stainless-api/stainless-api-go"
"github.com/tidwall/gjson"
"github.com/urfave/cli/v3"
)

func main() {
updateCheck := cmd.CheckForUpdate()

app := cmd.Command

if slices.Contains(os.Args, "__complete") {
prepareForAutocomplete(app)
}

checkVersionUpdate(updateCheck)

if err := app.Run(context.Background(), os.Args); err != nil {
exitCode := 1

// Check if error has a custom exit code
if exitErr, ok := err.(cli.ExitCoder); ok {
exitCode = exitErr.ExitCode()
}

var apierr *stainless.Error
if errors.As(err, &apierr) {
fmt.Fprintf(os.Stderr, "%s %q: %d %s\n", apierr.Request.Method, apierr.Request.URL, apierr.Response.StatusCode, http.StatusText(apierr.Response.StatusCode))
Expand All @@ -30,6 +49,22 @@ func main() {
} else {
fmt.Fprintf(os.Stderr, "%s\n", err.Error())
}
os.Exit(1)
checkVersionUpdate(updateCheck)
os.Exit(exitCode)
}
}

func prepareForAutocomplete(cmd *cli.Command) {
// urfave/cli does not handle flag completions and will print an error if we inspect a command with invalid flags.
// This skips that sort of validation
cmd.SkipFlagParsing = true
for _, child := range cmd.Commands {
prepareForAutocomplete(child)
}
}

func checkVersionUpdate(updateCheck <-chan string) {
if msg := <-updateCheck; msg != "" {
console.Warn("%s", msg)
}
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ require (
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/yuin/goldmark v1.7.16 // indirect
github.com/yuin/goldmark-emoji v1.0.6 // indirect
golang.org/x/mod v0.32.0 // indirect
golang.org/x/net v0.49.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ github.com/yuin/goldmark-emoji v1.0.6 h1:QWfF2FYaXwL74tfGOW5izeiZepUDroDJfWubQI9
github.com/yuin/goldmark-emoji v1.0.6/go.mod h1:ukxJDKFpdFb5x0a5HqbdlcKtebh086iJpI31LTKmWuA=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down
Loading
Loading