Compare commits
13 Commits
dependabot
...
rust-v0.1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e89209d021 | ||
|
|
4ddd4e078f | ||
|
|
5a9de8e195 | ||
|
|
89228842fc | ||
|
|
edefb6eb9c | ||
|
|
8c04526619 | ||
|
|
3821a18ec1 | ||
|
|
40cd73936c | ||
|
|
ec0c5a6fb7 | ||
|
|
2c0196efd3 | ||
|
|
f58398dfbb | ||
|
|
91ce3a3838 | ||
|
|
f3a1034d5d |
28
.github/dotslash-config.json
vendored
28
.github/dotslash-config.json
vendored
@@ -27,34 +27,6 @@
|
||||
"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
BIN
.github/llmx-cli-login.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 2.9 MiB |
BIN
.github/llmx-cli-permissions.png
vendored
BIN
.github/llmx-cli-permissions.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 408 KiB |
BIN
.github/llmx-cli-splash.png
vendored
BIN
.github/llmx-cli-splash.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 3.1 MiB |
33
.github/workflows/rust-release.yml
vendored
33
.github/workflows/rust-release.yml
vendored
@@ -445,7 +445,19 @@ jobs:
|
||||
run: |
|
||||
./scripts/stage_npm_packages.py \
|
||||
--release-version "${{ steps.release_name.outputs.name }}" \
|
||||
--package @valknar/llmx
|
||||
--package 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
|
||||
uses: softprops/action-gh-release@v2
|
||||
@@ -464,9 +476,7 @@ jobs:
|
||||
tag: ${{ github.ref_name }}
|
||||
config: .github/dotslash-config.json
|
||||
|
||||
# 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 to npm using authentication token
|
||||
publish-npm:
|
||||
# Publish to npm for stable releases and alpha pre-releases with numeric suffixes.
|
||||
if: ${{ needs.release.outputs.should_publish_npm == 'true' }}
|
||||
@@ -474,7 +484,6 @@ jobs:
|
||||
needs: release
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write # Required for OIDC
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
@@ -483,11 +492,6 @@ jobs:
|
||||
with:
|
||||
node-version: 22
|
||||
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
|
||||
env:
|
||||
@@ -499,15 +503,18 @@ jobs:
|
||||
mkdir -p dist/npm
|
||||
gh release download "$tag" \
|
||||
--repo "${GITHUB_REPOSITORY}" \
|
||||
--pattern "valknar-llmx-npm-${version}.tgz" \
|
||||
--pattern "llmx-npm-${version}.tgz" \
|
||||
--dir dist/npm
|
||||
|
||||
# No NODE_AUTH_TOKEN needed because we use OIDC.
|
||||
- name: Publish to npm
|
||||
env:
|
||||
VERSION: ${{ needs.release.outputs.version }}
|
||||
NPM_TAG: ${{ needs.release.outputs.npm_tag }}
|
||||
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
|
||||
tag_args=()
|
||||
if [[ -n "${NPM_TAG}" ]]; then
|
||||
@@ -515,7 +522,7 @@ jobs:
|
||||
fi
|
||||
|
||||
tarballs=(
|
||||
"valknar-llmx-npm-${VERSION}.tgz"
|
||||
"llmx-npm-${VERSION}.tgz"
|
||||
)
|
||||
|
||||
for tarball in "${tarballs[@]}"; do
|
||||
|
||||
24
README.md
24
README.md
@@ -1,13 +1,9 @@
|
||||
<p align="center"><code>npm i -g @valknar/llmx</code><br />or <code>brew install --cask llmx</code></p>
|
||||
<p align="center"><code>npm i -g @valknarthing/llmx</code></p>
|
||||
|
||||
<p align="center"><strong>LLMX CLI</strong> is a coding agent powered by LiteLLM that runs locally on your computer.
|
||||
</br>
|
||||
</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/llmx">github.com/openai/llmx</a></p>
|
||||
|
||||
<p align="center">
|
||||
<img src="./.github/llmx-cli-splash.png" alt="LLMX CLI splash" width="80%" />
|
||||
</p>
|
||||
</br>Original project: <a href="https://github.com/openai/codex">github.com/openai/codex</a></p>
|
||||
|
||||
---
|
||||
|
||||
@@ -15,16 +11,10 @@
|
||||
|
||||
### Installing and running LLMX CLI
|
||||
|
||||
Install globally with your preferred package manager. If you use npm:
|
||||
Install globally with npm:
|
||||
|
||||
```shell
|
||||
npm install -g @valknar/llmx
|
||||
```
|
||||
|
||||
Alternatively, if you use Homebrew:
|
||||
|
||||
```shell
|
||||
brew install --cask llmx
|
||||
npm install -g @valknarthing/llmx
|
||||
```
|
||||
|
||||
Then simply run `llmx` to get started:
|
||||
@@ -33,10 +23,8 @@ Then simply run `llmx` to get started:
|
||||
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>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
Each GitHub Release contains many executables, but in practice, you likely want one of these:
|
||||
|
||||
@@ -96,7 +84,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)
|
||||
- [Login on a "Headless" machine](./docs/authentication.md#connecting-on-a-headless-machine)
|
||||
- **Automating LLMX**
|
||||
- [GitHub Action](https://github.com/valknar/llmx-action)
|
||||
- [GitHub Action](https://github.com/valknarthing/llmx-action)
|
||||
- [TypeScript SDK](./sdk/typescript/README.md)
|
||||
- [Non-interactive mode (`llmx exec`)](./docs/exec.md)
|
||||
- [**Advanced**](./docs/advanced.md)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "@valknar/llmx",
|
||||
"name": "@valknarthing/llmx",
|
||||
"version": "0.1.0",
|
||||
"license": "Apache-2.0",
|
||||
"description": "LLMX CLI - Multi-provider coding agent powered by LiteLLM",
|
||||
@@ -16,7 +16,7 @@
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/valknar/llmx.git",
|
||||
"url": "git+https://github.com/valknarthing/llmx.git",
|
||||
"directory": "llmx-cli"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ def parse_args() -> argparse.Namespace:
|
||||
"--package",
|
||||
choices=("llmx", "llmx-responses-api-proxy", "llmx-sdk"),
|
||||
default="llmx",
|
||||
help="Which npm package to stage (default: codex).",
|
||||
help="Which npm package to stage (default: llmx).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--version",
|
||||
|
||||
@@ -2,7 +2,6 @@ use anyhow::Result;
|
||||
use app_test_support::McpProcess;
|
||||
use app_test_support::to_response;
|
||||
use llmx_app_server_protocol::CancelLoginChatGptParams;
|
||||
use llmx_app_server_protocol::CancelLoginChatGptResponse;
|
||||
use llmx_app_server_protocol::GetAuthStatusParams;
|
||||
use llmx_app_server_protocol::GetAuthStatusResponse;
|
||||
use llmx_app_server_protocol::JSONRPCError;
|
||||
@@ -110,21 +109,35 @@ async fn login_and_cancel_chatgpt() -> Result<()> {
|
||||
login_id: login.login_id,
|
||||
})
|
||||
.await?;
|
||||
let cancel_resp: JSONRPCResponse = timeout(
|
||||
DEFAULT_READ_TIMEOUT,
|
||||
|
||||
// The cancel might succeed or fail with "login id not found" if the login
|
||||
// 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)),
|
||||
)
|
||||
.await??;
|
||||
let _ok: CancelLoginChatGptResponse = to_response(cancel_resp)?;
|
||||
.await;
|
||||
|
||||
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.
|
||||
let maybe_note = timeout(
|
||||
Duration::from_secs(2),
|
||||
mcp.read_stream_until_notification_message("llmx/event/login_chat_gpt_complete"),
|
||||
mcp.read_stream_until_notification_message("loginChatGptComplete"),
|
||||
)
|
||||
.await;
|
||||
if maybe_note.is_err() {
|
||||
eprintln!("warning: did not observe login_chat_gpt_complete notification after cancel");
|
||||
eprintln!("warning: did not observe loginChatGptComplete notification after cancel");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "@valknar/llmx-responses-api-proxy",
|
||||
"name": "@valknarthing/llmx-responses-api-proxy",
|
||||
"version": "0.1.0",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
@@ -15,7 +15,7 @@
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/valknar/llmx.git",
|
||||
"url": "git+https://github.com/valknarthing/llmx.git",
|
||||
"directory": "llmx-rs/responses-api-proxy/npm"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +148,9 @@ def main() -> int:
|
||||
print(f"should `git checkout {resolved_head_sha}`")
|
||||
|
||||
for package in packages:
|
||||
staging_dir = Path(tempfile.mkdtemp(prefix=f"npm-stage-{package}-", dir=runner_temp))
|
||||
# Sanitize package name for use in filesystem path (replace / with -)
|
||||
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"
|
||||
|
||||
cmd = [
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "@valknar/llmx-sdk",
|
||||
"name": "@valknarthing/llmx-sdk",
|
||||
"version": "0.1.0",
|
||||
"description": "TypeScript SDK for LLMX - Multi-provider coding agent",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/valknar/llmx.git",
|
||||
"url": "git+https://github.com/valknarthing/llmx.git",
|
||||
"directory": "sdk/typescript"
|
||||
},
|
||||
"keywords": [
|
||||
|
||||
Reference in New Issue
Block a user