1 Commits

Author SHA1 Message Date
dependabot[bot]
ff6bb07283 chore(deps): bump rand from 0.8.5 to 0.9.2 in /llmx-rs
Bumps [rand](https://github.com/rust-random/rand) from 0.8.5 to 0.9.2.
- [Release notes](https://github.com/rust-random/rand/releases)
- [Changelog](https://github.com/rust-random/rand/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-random/rand/compare/0.8.5...rand_core-0.9.2)

---
updated-dependencies:
- dependency-name: rand
  dependency-version: 0.9.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-12 19:46:12 +00:00
14 changed files with 76 additions and 58 deletions

View File

@@ -27,6 +27,34 @@
"path": "llmx.exe" "path": "llmx.exe"
} }
} }
},
"llmx-responses-api-proxy": {
"platforms": {
"macos-aarch64": {
"regex": "^llmx-responses-api-proxy-aarch64-apple-darwin\\.zst$",
"path": "llmx-responses-api-proxy"
},
"macos-x86_64": {
"regex": "^llmx-responses-api-proxy-x86_64-apple-darwin\\.zst$",
"path": "llmx-responses-api-proxy"
},
"linux-x86_64": {
"regex": "^llmx-responses-api-proxy-x86_64-unknown-linux-musl\\.zst$",
"path": "llmx-responses-api-proxy"
},
"linux-aarch64": {
"regex": "^llmx-responses-api-proxy-aarch64-unknown-linux-musl\\.zst$",
"path": "llmx-responses-api-proxy"
},
"windows-x86_64": {
"regex": "^llmx-responses-api-proxy-x86_64-pc-windows-msvc\\.exe\\.zst$",
"path": "llmx-responses-api-proxy.exe"
},
"windows-aarch64": {
"regex": "^llmx-responses-api-proxy-aarch64-pc-windows-msvc\\.exe\\.zst$",
"path": "llmx-responses-api-proxy.exe"
}
}
} }
} }
} }

BIN
.github/llmx-cli-login.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

BIN
.github/llmx-cli-permissions.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 KiB

BIN
.github/llmx-cli-splash.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

View File

@@ -445,19 +445,7 @@ jobs:
run: | run: |
./scripts/stage_npm_packages.py \ ./scripts/stage_npm_packages.py \
--release-version "${{ steps.release_name.outputs.name }}" \ --release-version "${{ steps.release_name.outputs.name }}" \
--package llmx --package @valknar/llmx
# Delete any existing release to avoid conflicts with dotslash manifest file
- name: Delete existing release if present
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if gh release view "${{ github.ref_name }}" --repo "${{ github.repository }}" >/dev/null 2>&1; then
echo "Deleting existing release ${{ github.ref_name }}"
gh release delete "${{ github.ref_name }}" --repo "${{ github.repository }}" --yes
else
echo "No existing release found for ${{ github.ref_name }}"
fi
- name: Create GitHub Release - name: Create GitHub Release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2
@@ -476,7 +464,9 @@ jobs:
tag: ${{ github.ref_name }} tag: ${{ github.ref_name }}
config: .github/dotslash-config.json config: .github/dotslash-config.json
# Publish to npm using authentication token # Publish to npm using OIDC authentication.
# July 31, 2025: https://github.blog/changelog/2025-07-31-npm-trusted-publishing-with-oidc-is-generally-available/
# npm docs: https://docs.npmjs.com/trusted-publishers
publish-npm: publish-npm:
# Publish to npm for stable releases and alpha pre-releases with numeric suffixes. # Publish to npm for stable releases and alpha pre-releases with numeric suffixes.
if: ${{ needs.release.outputs.should_publish_npm == 'true' }} if: ${{ needs.release.outputs.should_publish_npm == 'true' }}
@@ -484,6 +474,7 @@ jobs:
needs: release needs: release
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
id-token: write # Required for OIDC
contents: read contents: read
steps: steps:
@@ -492,6 +483,11 @@ jobs:
with: with:
node-version: 22 node-version: 22
registry-url: "https://registry.npmjs.org" registry-url: "https://registry.npmjs.org"
scope: "@valknar"
# Trusted publishing requires npm CLI version 11.5.1 or later.
- name: Update npm
run: npm install -g npm@latest
- name: Download npm tarballs from release - name: Download npm tarballs from release
env: env:
@@ -503,18 +499,15 @@ jobs:
mkdir -p dist/npm mkdir -p dist/npm
gh release download "$tag" \ gh release download "$tag" \
--repo "${GITHUB_REPOSITORY}" \ --repo "${GITHUB_REPOSITORY}" \
--pattern "llmx-npm-${version}.tgz" \ --pattern "valknar-llmx-npm-${version}.tgz" \
--dir dist/npm --dir dist/npm
# No NODE_AUTH_TOKEN needed because we use OIDC.
- name: Publish to npm - name: Publish to npm
env: env:
VERSION: ${{ needs.release.outputs.version }} VERSION: ${{ needs.release.outputs.version }}
NPM_TAG: ${{ needs.release.outputs.npm_tag }} NPM_TAG: ${{ needs.release.outputs.npm_tag }}
run: | run: |
# Write auth token to the .npmrc file that setup-node created
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" >> ${NPM_CONFIG_USERCONFIG}
set -euo pipefail set -euo pipefail
tag_args=() tag_args=()
if [[ -n "${NPM_TAG}" ]]; then if [[ -n "${NPM_TAG}" ]]; then
@@ -522,7 +515,7 @@ jobs:
fi fi
tarballs=( tarballs=(
"llmx-npm-${VERSION}.tgz" "valknar-llmx-npm-${VERSION}.tgz"
) )
for tarball in "${tarballs[@]}"; do for tarball in "${tarballs[@]}"; do

View File

@@ -1,9 +1,13 @@
<p align="center"><code>npm i -g @valknarthing/llmx</code></p> <p align="center"><code>npm i -g @valknar/llmx</code><br />or <code>brew install --cask llmx</code></p>
<p align="center"><strong>LLMX CLI</strong> is a coding agent powered by LiteLLM that runs locally on your computer. <p align="center"><strong>LLMX CLI</strong> is a coding agent powered by LiteLLM that runs locally on your computer.
</br> </br>
</br>This project is a community fork with enhanced support for multiple LLM providers via LiteLLM. </br>This project is a community fork with enhanced support for multiple LLM providers via LiteLLM.
</br>Original project: <a href="https://github.com/openai/codex">github.com/openai/codex</a></p> </br>Original project: <a href="https://github.com/openai/llmx">github.com/openai/llmx</a></p>
<p align="center">
<img src="./.github/llmx-cli-splash.png" alt="LLMX CLI splash" width="80%" />
</p>
--- ---
@@ -11,10 +15,16 @@
### Installing and running LLMX CLI ### Installing and running LLMX CLI
Install globally with npm: Install globally with your preferred package manager. If you use npm:
```shell ```shell
npm install -g @valknarthing/llmx npm install -g @valknar/llmx
```
Alternatively, if you use Homebrew:
```shell
brew install --cask llmx
``` ```
Then simply run `llmx` to get started: Then simply run `llmx` to get started:
@@ -23,8 +33,10 @@ Then simply run `llmx` to get started:
llmx llmx
``` ```
If you're running into upgrade issues with Homebrew, see the [FAQ entry on brew upgrade llmx](./docs/faq.md#brew-upgrade-llmx-isnt-upgrading-me).
<details> <details>
<summary>You can also go to the <a href="https://github.com/valknarthing/llmx/releases/latest">latest GitHub Release</a> and download the appropriate binary for your platform.</summary> <summary>You can also go to the <a href="https://github.com/valknar/llmx/releases/latest">latest GitHub Release</a> and download the appropriate binary for your platform.</summary>
Each GitHub Release contains many executables, but in practice, you likely want one of these: Each GitHub Release contains many executables, but in practice, you likely want one of these:
@@ -84,7 +96,7 @@ LLMX CLI supports a rich set of configuration options, with preferences stored i
- [Auth methods](./docs/authentication.md#forcing-a-specific-auth-method-advanced) - [Auth methods](./docs/authentication.md#forcing-a-specific-auth-method-advanced)
- [Login on a "Headless" machine](./docs/authentication.md#connecting-on-a-headless-machine) - [Login on a "Headless" machine](./docs/authentication.md#connecting-on-a-headless-machine)
- **Automating LLMX** - **Automating LLMX**
- [GitHub Action](https://github.com/valknarthing/llmx-action) - [GitHub Action](https://github.com/valknar/llmx-action)
- [TypeScript SDK](./sdk/typescript/README.md) - [TypeScript SDK](./sdk/typescript/README.md)
- [Non-interactive mode (`llmx exec`)](./docs/exec.md) - [Non-interactive mode (`llmx exec`)](./docs/exec.md)
- [**Advanced**](./docs/advanced.md) - [**Advanced**](./docs/advanced.md)

View File

@@ -1,5 +1,5 @@
{ {
"name": "@valknarthing/llmx", "name": "@valknar/llmx",
"version": "0.1.0", "version": "0.1.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"description": "LLMX CLI - Multi-provider coding agent powered by LiteLLM", "description": "LLMX CLI - Multi-provider coding agent powered by LiteLLM",
@@ -16,7 +16,7 @@
], ],
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/valknarthing/llmx.git", "url": "git+https://github.com/valknar/llmx.git",
"directory": "llmx-cli" "directory": "llmx-cli"
} }
} }

View File

@@ -33,7 +33,7 @@ def parse_args() -> argparse.Namespace:
"--package", "--package",
choices=("llmx", "llmx-responses-api-proxy", "llmx-sdk"), choices=("llmx", "llmx-responses-api-proxy", "llmx-sdk"),
default="llmx", default="llmx",
help="Which npm package to stage (default: llmx).", help="Which npm package to stage (default: codex).",
) )
parser.add_argument( parser.add_argument(
"--version", "--version",

2
llmx-rs/Cargo.lock generated
View File

@@ -3559,7 +3559,7 @@ dependencies = [
"anyhow", "anyhow",
"dirs-next", "dirs-next",
"dunce", "dunce",
"rand 0.8.5", "rand 0.9.2",
"serde", "serde",
"serde_json", "serde_json",
"windows-sys 0.52.0", "windows-sys 0.52.0",

View File

@@ -2,6 +2,7 @@ use anyhow::Result;
use app_test_support::McpProcess; use app_test_support::McpProcess;
use app_test_support::to_response; use app_test_support::to_response;
use llmx_app_server_protocol::CancelLoginChatGptParams; use llmx_app_server_protocol::CancelLoginChatGptParams;
use llmx_app_server_protocol::CancelLoginChatGptResponse;
use llmx_app_server_protocol::GetAuthStatusParams; use llmx_app_server_protocol::GetAuthStatusParams;
use llmx_app_server_protocol::GetAuthStatusResponse; use llmx_app_server_protocol::GetAuthStatusResponse;
use llmx_app_server_protocol::JSONRPCError; use llmx_app_server_protocol::JSONRPCError;
@@ -109,35 +110,21 @@ async fn login_and_cancel_chatgpt() -> Result<()> {
login_id: login.login_id, login_id: login.login_id,
}) })
.await?; .await?;
let cancel_resp: JSONRPCResponse = timeout(
// The cancel might succeed or fail with "login id not found" if the login DEFAULT_READ_TIMEOUT,
// completed/cancelled already due to a race condition. Either outcome is acceptable.
// Use a timeout and allow either success or error response.
let cancel_result = timeout(
Duration::from_secs(5),
mcp.read_stream_until_response_message(RequestId::Integer(cancel_id)), mcp.read_stream_until_response_message(RequestId::Integer(cancel_id)),
) )
.await; .await??;
let _ok: CancelLoginChatGptResponse = to_response(cancel_resp)?;
match cancel_result {
Ok(Ok(_)) => {
// Successfully cancelled
eprintln!("cancel succeeded");
}
Ok(Err(_)) | Err(_) => {
// Cancel failed or timed out - acceptable in race condition
eprintln!("cancel failed or timed out (expected in race condition)");
}
}
// Optionally observe the completion notification; do not fail if it races. // Optionally observe the completion notification; do not fail if it races.
let maybe_note = timeout( let maybe_note = timeout(
Duration::from_secs(2), Duration::from_secs(2),
mcp.read_stream_until_notification_message("loginChatGptComplete"), mcp.read_stream_until_notification_message("llmx/event/login_chat_gpt_complete"),
) )
.await; .await;
if maybe_note.is_err() { if maybe_note.is_err() {
eprintln!("warning: did not observe loginChatGptComplete notification after cancel"); eprintln!("warning: did not observe login_chat_gpt_complete notification after cancel");
} }
Ok(()) Ok(())
} }

View File

@@ -1,5 +1,5 @@
{ {
"name": "@valknarthing/llmx-responses-api-proxy", "name": "@valknar/llmx-responses-api-proxy",
"version": "0.1.0", "version": "0.1.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {
@@ -15,7 +15,7 @@
], ],
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/valknarthing/llmx.git", "url": "git+https://github.com/valknar/llmx.git",
"directory": "llmx-rs/responses-api-proxy/npm" "directory": "llmx-rs/responses-api-proxy/npm"
} }
} }

View File

@@ -13,7 +13,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
dunce = "1.0" dunce = "1.0"
[dependencies.rand] [dependencies.rand]
version = "0.8" version = "0.9"
default-features = false default-features = false
features = ["std", "small_rng"] features = ["std", "small_rng"]
[dependencies.dirs-next] [dependencies.dirs-next]

View File

@@ -148,9 +148,7 @@ def main() -> int:
print(f"should `git checkout {resolved_head_sha}`") print(f"should `git checkout {resolved_head_sha}`")
for package in packages: for package in packages:
# Sanitize package name for use in filesystem path (replace / with -) staging_dir = Path(tempfile.mkdtemp(prefix=f"npm-stage-{package}-", dir=runner_temp))
safe_package_name = package.replace("/", "-").replace("@", "")
staging_dir = Path(tempfile.mkdtemp(prefix=f"npm-stage-{safe_package_name}-", dir=runner_temp))
pack_output = output_dir / f"{package}-npm-{args.release_version}.tgz" pack_output = output_dir / f"{package}-npm-{args.release_version}.tgz"
cmd = [ cmd = [

View File

@@ -1,10 +1,10 @@
{ {
"name": "@valknarthing/llmx-sdk", "name": "@valknar/llmx-sdk",
"version": "0.1.0", "version": "0.1.0",
"description": "TypeScript SDK for LLMX - Multi-provider coding agent", "description": "TypeScript SDK for LLMX - Multi-provider coding agent",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/valknarthing/llmx.git", "url": "git+https://github.com/valknar/llmx.git",
"directory": "sdk/typescript" "directory": "sdk/typescript"
}, },
"keywords": [ "keywords": [