Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .agents/skills/custom-commands/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@ with the following sub-clients:
| `client.settings` | `elevenlabs_sdk::api::SettingsClient2` | settings operations |
| `client.speech_engine` | `elevenlabs_sdk::api::SpeechEngineClient` | speech_engine operations |
| `client.environment_variables` | `elevenlabs_sdk::api::EnvironmentVariablesClient` | environment_variables operations |
| `client.assets` | `elevenlabs_sdk::api::AssetsClient` | assets operations |
| `client.flows` | `elevenlabs_sdk::api::FlowsClient` | flows operations |
| `client.video` | `elevenlabs_sdk::api::VideoClient` | video operations |
| `client.image` | `elevenlabs_sdk::api::ImageClient` | image operations |
| `client.text_to_speech` | `elevenlabs_sdk::api::TextToSpeechClient2` | text_to_speech operations |
| `client.productions` | `elevenlabs_sdk::api::ProductionsClient` | productions operations |
| `client.orders` | `elevenlabs_sdk::api::OrdersClient` | orders operations |
| `client.media` | `elevenlabs_sdk::api::MediaClient` | media operations |
Expand Down
234 changes: 234 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,36 @@ jobs:
fi
- name: Install dist
run: ${{ matrix.install_dist.run }}
# cargo-dist guards the installer download with pipefail in the `plan`
# job but not here, where the same `curl ... | sh` runs once per matrix
# leg. A dead curl pipes nothing into `sh`, which exits 0, so the step
# above reports success and `dist build` fails two steps later with an
# opaque exit 127. Observed on 2 of 3 real releases.
#
# Deliberately does not branch on `matrix.install_dist.shell`: steps 1
# and 3 reuse the matrix's own command and shell exactly as upstream
# does, so this can only ever add a retry — it cannot mis-route a leg
# and skip the install entirely.
- id: dist-check
name: Check dist installed
shell: bash
run: |
if dist --version > /dev/null 2>&1; then
echo "ok=yes" >> "$GITHUB_OUTPUT"
else
echo "ok=no" >> "$GITHUB_OUTPUT"
echo "::warning::The dist installer did not put 'dist' on PATH — most likely a transient download failure. Retrying."
fi
- name: Install dist (retry)
if: ${{ steps.dist-check.outputs.ok == 'no' }}
run: ${{ matrix.install_dist.run }}
- name: Verify dist
shell: bash
run: |
dist --version || {
echo "::error::The cargo-dist installer failed twice on this runner, so 'dist' is not available. This is usually a transient network failure downloading https://github.com/axodotdev/cargo-dist/releases — re-run this job."
exit 1
}
# Get the dist-manifest
- name: Fetch local artifacts
uses: actions/download-artifact@v7
Expand Down Expand Up @@ -287,10 +317,214 @@ jobs:

gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/*

publish-homebrew-formula:
needs:
- plan
- host
runs-on: "ubuntu-22.04"
env:
GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
PLAN: ${{ needs.plan.outputs.val }}
GITHUB_USER: "github-actions[bot]"
GITHUB_EMAIL: "41898282+github-actions[bot]@users.noreply.github.com"
if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
steps:
- uses: actions/checkout@v6
with:
repository: "elevenlabs/homebrew-tap"
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
# Credentials must persist — the final step pushes the formula back.
persist-credentials: true
# So we have access to the formula
fetch-depth: 1
# So we have access to "dist"
- name: Install cached dist
uses: actions/download-artifact@v7
with:
name: cargo-dist-cache
path: ~/.cargo/bin/
- run: chmod +x ~/.cargo/bin/dist
- name: Fetch homebrew formulae
uses: actions/download-artifact@v7
with:
pattern: artifacts-*
path: Formula/
merge-multiple: true
# This is extra complex because you can make your Formula name not match your app name
# so we need to find the formula file based on the app name
- name: Commit formula files
run: |
git config --global user.name "${GITHUB_USER}"
git config --global user.email "${GITHUB_EMAIL}"

for release in $(echo "$PLAN" | jq --compact-output '.releases[] | select([.artifacts[] | endswith(".rb")] | any)'); do
name=$(echo "$release" | jq .app_name --raw-output)
version=$(echo "$release" | jq .app_version --raw-output)

# GitHub's ubuntu runner images no longer ship Homebrew, so
# cargo-dist's unconditional `brew --prefix` aborts this step
# under `bash -e` with exit 127 — before the formula is ever
# committed. `brew style` is only cosmetic reformatting of a
# file cargo-dist already renders validly, so skip it when brew
# is absent instead of failing the publish.
if command -v brew > /dev/null 2>&1; then
export PATH="$(brew --prefix)/bin:$PATH"
brew update
# We avoid reformatting user-provided data such as the app description and homepage.
for filename in $(echo "$release" | jq --compact-output --raw-output '.artifacts[] | select(endswith(".rb"))'); do
brew style --except-cops FormulaAudit/Homepage,FormulaAudit/Desc,FormulaAuditStrict --fix "Formula/${filename}" || true
done
else
echo "::notice::brew is not available on this runner; skipping the formula style pass."
fi

git add Formula/*.rb
# Re-running a release must be a no-op rather than an
# empty-commit failure, matching the Scoop job.
if git diff --cached --quiet; then
echo "Formula for ${name} ${version} is already up to date; nothing to commit."
else
git commit -m "${name} ${version}"
fi
done

git push

publish-scoop:
needs:
- plan
- host
runs-on: "ubuntu-22.04"
# The same expression cargo-dist uses for its own publish jobs. A Scoop
# bucket has no prerelease channel — a manifest simply *is* the version
# `scoop install` hands out — so an RC must not become what every user
# installs. Deferring to cargo-dist's own semver determination instead of
# re-parsing the tag keeps both channels in agreement by construction.
if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
steps:
- name: Resolve the Windows release archive
id: archive
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
set -euo pipefail

TAG="${GITHUB_REF_NAME}"
SUFFIX="-x86_64-pc-windows-msvc.zip"

# Resolved by target-triple suffix rather than full name: cargo-dist
# names archives after the cargo *package*, which the generator does
# not always control.
ASSET_NAME=""
for attempt in $(seq 1 6); do
ASSET_NAME=$(gh release view "${TAG}" --repo "${GITHUB_REPOSITORY}" --json assets \
--jq ".assets[].name | select(endswith(\"${SUFFIX}\"))" 2>/dev/null | head -n1 || true)
if [ -n "${ASSET_NAME}" ]; then
break
fi
echo "Release assets not listable yet (attempt ${attempt}/6); retrying..."
sleep 10
done

if [ -z "${ASSET_NAME}" ]; then
echo "::error::No asset ending in ${SUFFIX} on release ${TAG}. The host job already created the release, so this means the Windows archive was never built — check the build-local-artifacts leg for x86_64-pc-windows-msvc."
exit 1
fi

echo "asset-name=${ASSET_NAME}" >> "$GITHUB_OUTPUT"

- name: Download the archive and hash it
id: manifest
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ASSET_NAME: ${{ steps.archive.outputs.asset-name }}
shell: bash
run: |
set -euo pipefail

TAG="${GITHUB_REF_NAME}"
VERSION="${TAG#v}"

gh release download "${TAG}" --repo "${GITHUB_REPOSITORY}" \
--pattern "${ASSET_NAME}" --dir "${RUNNER_TEMP}/scoop"
HASH=$(sha256sum "${RUNNER_TEMP}/scoop/${ASSET_NAME}" | cut -d' ' -f1)

# cargo-dist archive names carry no version, so the autoupdate URL
# is the release URL with the tag replaced by Scoop's $version
# placeholder. Preserve whether the tag is v-prefixed.
if [ "${TAG}" = "v${VERSION}" ]; then
TAG_TEMPLATE='v$version'
else
TAG_TEMPLATE='$version'
fi

{
echo "version=${VERSION}"
echo "hash=${HASH}"
echo "url=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/download/${TAG}/${ASSET_NAME}"
echo "autoupdate-url=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/download/${TAG_TEMPLATE}/${ASSET_NAME}"
} >> "$GITHUB_OUTPUT"

- name: Check out the Scoop bucket
uses: actions/checkout@v6
with:
repository: "elevenlabs/scoop-bucket"
token: ${{ secrets.SCOOP_BUCKET_TOKEN }}
path: scoop-bucket
# Credentials must persist — the next step pushes the manifest back.
persist-credentials: true
fetch-depth: 1

- name: Write and push the manifest
env:
VERSION: ${{ steps.manifest.outputs.version }}
URL: ${{ steps.manifest.outputs.url }}
HASH: ${{ steps.manifest.outputs.hash }}
AUTOUPDATE_URL: ${{ steps.manifest.outputs.autoupdate-url }}
shell: bash
run: |
set -euo pipefail

mkdir -p scoop-bucket/bucket
jq -n \
--arg version "${VERSION}" \
--arg description 'CLI for the ElevenLabs API Documentation' \
--arg homepage 'https://github.com/elevenlabs/cli' \
--arg url "${URL}" \
--arg hash "${HASH}" \
--arg bin 'elevenlabs.exe' \
--arg autoupdate "${AUTOUPDATE_URL}" \
--arg checkver 'https://github.com/elevenlabs/cli' \
'{
version: $version,
description: $description,
homepage: $homepage,
architecture: { "64bit": { url: $url, hash: $hash, bin: $bin } },
autoupdate: { architecture: { "64bit": { url: $autoupdate } } },
checkver: { github: $checkver }
}' > "scoop-bucket/bucket/elevenlabs.json"

cd scoop-bucket
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add "bucket/elevenlabs.json"

# Re-running a release must be a no-op rather than an empty-commit
# failure — unlike npm, this channel is idempotent.
if git diff --cached --quiet; then
echo "bucket/elevenlabs.json is already up to date; nothing to commit."
else
git commit -m "elevenlabs ${VERSION}"
git push
fi

announce:
needs:
- plan
- host
- publish-homebrew-formula
- publish-scoop
# use "always() && ..." to allow us to wait for all publish jobs while
# still allowing individual publish jobs to skip themselves (for prereleases).
# "host" however must run to completion, no skipping allowed!
Expand Down
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
name = "fern-cli-sdk"
version = "1.0.0"
edition = "2021"
description = "CLI generator — dynamic command surface from OpenAPI and GraphQL schemas"
description = "CLI for the ElevenLabs API Documentation"
license = "Apache-2.0"
repository = "https://github.com/fern-api/cli-sdk"
homepage = "https://github.com/fern-api/cli-sdk"
repository = "https://github.com/elevenlabs/cli"
homepage = "https://github.com/elevenlabs/cli"
authors = ["Fern <hey@buildwithfern.com>"]
keywords = ["cli", "openapi", "graphql", "fern", "codegen"]
categories = ["command-line-utilities", "web-programming"]
Expand Down
2 changes: 1 addition & 1 deletion cli/elevenlabs/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use fern_cli_sdk::auth::{PkceLoginFlow};

fn main() {
let app = CliApp::new("elevenlabs")
.login_flow(PkceLoginFlow::new("OAuth").client_id("c9c18126-5718-406a-8a12-21b69e5a888d").authorization_url("https://elevenlabs.io/app/oauth/authorize").token_url("https://api.us.elevenlabs.io/v1/oauth/token").redirect_host("localhost").redirect_ports([8484, 8483, 8482]))
.login_flow(PkceLoginFlow::new("OAuth").client_id("c9c18126-5718-406a-8a12-21b69e5a888d").authorization_url("https://elevenlabs.io/app/oauth/authorize").token_url("https://api.us.elevenlabs.io/v1/oauth/token").scopes(["text_to_speech", "speech_to_speech", "speech_to_text", "sound_generation", "audio_isolation", "voice_generation", "forced_alignment", "music_generation", "image_video_generation", "flows", "models_read", "voices_read", "voices_write", "speech_history_read", "speech_history_write", "dubbing_read", "dubbing_write", "pronunciation_dictionaries_read", "pronunciation_dictionaries_write", "projects_read", "projects_write", "convai_read", "convai_write", "add_voice_from_voice_library", "create_instant_voice_clone", "create_professional_voice_clone", "user_read", "workspace_read"]).redirect_host("localhost").redirect_ports([8484, 8483, 8482]))
.binding(
OpenApiBinding::new()
.spec(include_str!("openapi0.json"))
Expand Down
2 changes: 1 addition & 1 deletion cli/elevenlabs/openapi0.json

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions cli/elevenlabs/sdk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,13 @@ pub fn client(ctx: &AppContext) -> elevenlabs_sdk::api::ApiClient {
},
speech_engine: elevenlabs_sdk::api::SpeechEngineClient { http_client: http_client.clone() },
environment_variables: elevenlabs_sdk::api::EnvironmentVariablesClient { http_client: http_client.clone() },
assets: elevenlabs_sdk::api::AssetsClient { http_client: http_client.clone() },
flows: elevenlabs_sdk::api::FlowsClient {
http_client: http_client.clone(),
video: elevenlabs_sdk::api::resources::flows::VideoClient { http_client: http_client.clone() },
image: elevenlabs_sdk::api::resources::flows::ImageClient { http_client: http_client.clone() },
text_to_speech: elevenlabs_sdk::api::resources::flows::TextToSpeechClient2 { http_client: http_client.clone() },
},
productions: elevenlabs_sdk::api::ProductionsClient {
http_client: http_client.clone(),
orders: elevenlabs_sdk::api::resources::productions::OrdersClient {
Expand Down
10 changes: 7 additions & 3 deletions dist-workspace.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ ci = "github"
# musl builds.
precise-builds = true
# The installers to generate for each app
installers = ["shell", "powershell"]
installers = ["shell", "powershell", "homebrew"]
# Whether to enable GitHub Attestations
github-attestations = true
# Target platforms to build apps for (Rust target-triple syntax)
targets = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "aarch64-unknown-linux-musl", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl", "x86_64-pc-windows-msvc"]
targets = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl", "x86_64-pc-windows-msvc"]
# Which actions to run on pull requests
pr-run-mode = "plan"
# Publish jobs to run (npm publishing deferred until pipeline is validated)
publish-jobs = []
publish-jobs = ["homebrew"]
# Don't overwrite release.yml on `dist init` (preserves customizations)
allow-dirty = ["ci"]
# The archive format to use for windows builds (defaults .zip)
Expand All @@ -32,3 +32,7 @@ unix-archive = ".tar.gz"
install-path = "CARGO_HOME"
# Whether to install an updater program
install-updater = false
default-features = false
features = ["rustls"]
tap = "elevenlabs/homebrew-tap"
formula = "elevenlabs"
14 changes: 7 additions & 7 deletions elevenlabs-sdk/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
pub mod resources;

pub use resources::{
AgentsClient, ApiClient, AudioIsolationClient, AudioNativeClient, DubbingClient,
EnvironmentVariablesClient, ForcedAlignmentClient, HistoryClient, ModelsClient, MusicClient,
ProductionsClient, PronunciationDictionariesClient, SamplesClient, ServiceAccountsClient,
SpeechEngineClient, SpeechToSpeechClient, SpeechToTextClient, StudioClient,
TextToDialogueClient, TextToSoundEffectsClient, TextToSpeechClient, TextToVoiceClient,
TokensClient, UsageClient, UserClient, VoicesClient, WebhooksClient, WorkspaceClient,
WorkspacesClient,
AgentsClient, ApiClient, AssetsClient, AudioIsolationClient, AudioNativeClient, DubbingClient,
EnvironmentVariablesClient, FlowsClient, ForcedAlignmentClient, HistoryClient, ModelsClient,
MusicClient, ProductionsClient, PronunciationDictionariesClient, SamplesClient,
ServiceAccountsClient, SpeechEngineClient, SpeechToSpeechClient, SpeechToTextClient,
StudioClient, TextToDialogueClient, TextToSoundEffectsClient, TextToSpeechClient,
TextToVoiceClient, TokensClient, UsageClient, UserClient, VoicesClient, WebhooksClient,
WorkspaceClient, WorkspacesClient,
};

pub use elevenlabs_types::*;
Loading
Loading