albus-cli 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- albus_cli-0.1.0/.github/workflows/check.yml +32 -0
- albus_cli-0.1.0/.gitignore +9 -0
- albus_cli-0.1.0/LICENSE +21 -0
- albus_cli-0.1.0/Makefile +19 -0
- albus_cli-0.1.0/PKG-INFO +98 -0
- albus_cli-0.1.0/README.md +83 -0
- albus_cli-0.1.0/RELEASING.md +59 -0
- albus_cli-0.1.0/install.ps1 +110 -0
- albus_cli-0.1.0/install.sh +111 -0
- albus_cli-0.1.0/pyproject.toml +52 -0
- albus_cli-0.1.0/src/albus_cli/__init__.py +0 -0
- albus_cli-0.1.0/src/albus_cli/__main__.py +6 -0
- albus_cli-0.1.0/src/albus_cli/client.py +30 -0
- albus_cli-0.1.0/src/albus_cli/commands/__init__.py +0 -0
- albus_cli-0.1.0/src/albus_cli/commands/agents.py +39 -0
- albus_cli-0.1.0/src/albus_cli/commands/secrets.py +62 -0
- albus_cli-0.1.0/src/albus_cli/commands/sessions.py +223 -0
- albus_cli-0.1.0/src/albus_cli/context.py +24 -0
- albus_cli-0.1.0/src/albus_cli/main.py +63 -0
- albus_cli-0.1.0/src/albus_cli/output.py +16 -0
- albus_cli-0.1.0/tests/__init__.py +0 -0
- albus_cli-0.1.0/tests/conftest.py +78 -0
- albus_cli-0.1.0/tests/test_cli.py +186 -0
- albus_cli-0.1.0/tools/check +5 -0
- albus_cli-0.1.0/tools/publish +175 -0
- albus_cli-0.1.0/uv.lock +597 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: Check
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
check:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
env:
|
|
12
|
+
NO_COLOR: "1"
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- name: Install uv
|
|
17
|
+
uses: astral-sh/setup-uv@v6
|
|
18
|
+
with:
|
|
19
|
+
enable-cache: true
|
|
20
|
+
|
|
21
|
+
- name: Check
|
|
22
|
+
run: ./tools/check
|
|
23
|
+
|
|
24
|
+
- name: Assert pure-Python wheel
|
|
25
|
+
run: |
|
|
26
|
+
rm -rf dist
|
|
27
|
+
uv build
|
|
28
|
+
wheel=$(echo dist/*.whl)
|
|
29
|
+
case "$(basename "$wheel")" in
|
|
30
|
+
*-py3-none-any.whl) echo "ok: $wheel" ;;
|
|
31
|
+
*) echo "error: expected py3-none-any, got $wheel" >&2; exit 1 ;;
|
|
32
|
+
esac
|
albus_cli-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Albus
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
albus_cli-0.1.0/Makefile
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
.PHONY: install lint fmt typecheck test check
|
|
2
|
+
|
|
3
|
+
install:
|
|
4
|
+
uv sync
|
|
5
|
+
|
|
6
|
+
lint: install
|
|
7
|
+
uv run ruff check .
|
|
8
|
+
uv run ruff format --check .
|
|
9
|
+
|
|
10
|
+
fmt: install
|
|
11
|
+
uv run ruff format .
|
|
12
|
+
|
|
13
|
+
typecheck: install
|
|
14
|
+
uv run mypy
|
|
15
|
+
|
|
16
|
+
test: install
|
|
17
|
+
uv run pytest
|
|
18
|
+
|
|
19
|
+
check: lint typecheck test
|
albus_cli-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: albus-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Command-line client for the Albus REST API
|
|
5
|
+
Project-URL: Homepage, https://github.com/albusgroup/albus-cli
|
|
6
|
+
Project-URL: Repository, https://github.com/albusgroup/albus-cli
|
|
7
|
+
Project-URL: Issues, https://github.com/albusgroup/albus-cli/issues
|
|
8
|
+
Author: Albus
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Python: >=3.11
|
|
12
|
+
Requires-Dist: albus-sdk==0.4.0
|
|
13
|
+
Requires-Dist: typer<0.28,>=0.26.8
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# albus CLI
|
|
17
|
+
|
|
18
|
+
Command-line client for the Albus REST API. Thin shell over the public
|
|
19
|
+
[`albus-sdk`](https://pypi.org/project/albus-sdk/) Python package: every
|
|
20
|
+
command maps to one API operation and prints JSON (pipe into `jq`).
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
macOS / Linux:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
curl -fsSL https://raw.githubusercontent.com/albusgroup/albus-cli/master/install.sh | sh
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Windows (PowerShell):
|
|
31
|
+
|
|
32
|
+
```powershell
|
|
33
|
+
irm https://raw.githubusercontent.com/albusgroup/albus-cli/master/install.ps1 | iex
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Pin a version:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
ALBUS_CLI_VERSION=0.1.0 curl -fsSL https://raw.githubusercontent.com/albusgroup/albus-cli/master/install.sh | sh
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The installer uses, in order: `uv tool install`, `pip install --user`, or
|
|
43
|
+
`pip` inside a conda environment. It does not download OS-specific Albus
|
|
44
|
+
binaries and does not check OS versions.
|
|
45
|
+
|
|
46
|
+
You can also install directly:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
uv tool install albus-cli
|
|
50
|
+
# or
|
|
51
|
+
pip install --user albus-cli
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Authentication
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
export ALBUS_API_KEY=... # organization API key
|
|
58
|
+
export ALBUS_BASE_URL=... # optional; defaults to production
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`--base-url` overrides `ALBUS_BASE_URL`, and `--timeout` bounds each request
|
|
62
|
+
(a waiting `sessions run` long-polls and is exempt).
|
|
63
|
+
|
|
64
|
+
The API key is the only credential, so the CLI covers only the operations that
|
|
65
|
+
accept `apiKeyAuth`.
|
|
66
|
+
|
|
67
|
+
## Commands
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
albus health
|
|
71
|
+
|
|
72
|
+
albus sessions run my-session -p "summarize the incident" \
|
|
73
|
+
--agent-name support-triage --model gemini-3.6-flash \
|
|
74
|
+
--provider gemini --credential albus.sh/secrets/gemini-key
|
|
75
|
+
albus sessions list
|
|
76
|
+
albus sessions get my-session --limit 20
|
|
77
|
+
albus sessions audit my-session --after "$cursor"
|
|
78
|
+
albus sessions delete my-session
|
|
79
|
+
|
|
80
|
+
albus secrets list
|
|
81
|
+
albus secrets create gemini-key --value ...
|
|
82
|
+
albus secrets get gemini-key
|
|
83
|
+
albus secrets update gemini-key < value.txt
|
|
84
|
+
albus secrets delete gemini-key
|
|
85
|
+
|
|
86
|
+
albus agents list
|
|
87
|
+
albus agents get support-triage
|
|
88
|
+
albus agents revision support-triage "$revision"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Development
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
make install
|
|
95
|
+
make check # ruff, mypy --strict, pytest
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
See [RELEASING.md](RELEASING.md) to publish a PyPI version.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# albus CLI
|
|
2
|
+
|
|
3
|
+
Command-line client for the Albus REST API. Thin shell over the public
|
|
4
|
+
[`albus-sdk`](https://pypi.org/project/albus-sdk/) Python package: every
|
|
5
|
+
command maps to one API operation and prints JSON (pipe into `jq`).
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
macOS / Linux:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
curl -fsSL https://raw.githubusercontent.com/albusgroup/albus-cli/master/install.sh | sh
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Windows (PowerShell):
|
|
16
|
+
|
|
17
|
+
```powershell
|
|
18
|
+
irm https://raw.githubusercontent.com/albusgroup/albus-cli/master/install.ps1 | iex
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Pin a version:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
ALBUS_CLI_VERSION=0.1.0 curl -fsSL https://raw.githubusercontent.com/albusgroup/albus-cli/master/install.sh | sh
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The installer uses, in order: `uv tool install`, `pip install --user`, or
|
|
28
|
+
`pip` inside a conda environment. It does not download OS-specific Albus
|
|
29
|
+
binaries and does not check OS versions.
|
|
30
|
+
|
|
31
|
+
You can also install directly:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
uv tool install albus-cli
|
|
35
|
+
# or
|
|
36
|
+
pip install --user albus-cli
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Authentication
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
export ALBUS_API_KEY=... # organization API key
|
|
43
|
+
export ALBUS_BASE_URL=... # optional; defaults to production
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`--base-url` overrides `ALBUS_BASE_URL`, and `--timeout` bounds each request
|
|
47
|
+
(a waiting `sessions run` long-polls and is exempt).
|
|
48
|
+
|
|
49
|
+
The API key is the only credential, so the CLI covers only the operations that
|
|
50
|
+
accept `apiKeyAuth`.
|
|
51
|
+
|
|
52
|
+
## Commands
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
albus health
|
|
56
|
+
|
|
57
|
+
albus sessions run my-session -p "summarize the incident" \
|
|
58
|
+
--agent-name support-triage --model gemini-3.6-flash \
|
|
59
|
+
--provider gemini --credential albus.sh/secrets/gemini-key
|
|
60
|
+
albus sessions list
|
|
61
|
+
albus sessions get my-session --limit 20
|
|
62
|
+
albus sessions audit my-session --after "$cursor"
|
|
63
|
+
albus sessions delete my-session
|
|
64
|
+
|
|
65
|
+
albus secrets list
|
|
66
|
+
albus secrets create gemini-key --value ...
|
|
67
|
+
albus secrets get gemini-key
|
|
68
|
+
albus secrets update gemini-key < value.txt
|
|
69
|
+
albus secrets delete gemini-key
|
|
70
|
+
|
|
71
|
+
albus agents list
|
|
72
|
+
albus agents get support-triage
|
|
73
|
+
albus agents revision support-triage "$revision"
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Development
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
make install
|
|
80
|
+
make check # ruff, mypy --strict, pytest
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
See [RELEASING.md](RELEASING.md) to publish a PyPI version.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Releasing the Albus CLI
|
|
2
|
+
|
|
3
|
+
Releases are intentionally manual during the MVP. The repository provides a
|
|
4
|
+
guarded publisher; it does not create commits, tags, or PyPI credentials.
|
|
5
|
+
|
|
6
|
+
## One-time PyPI setup
|
|
7
|
+
|
|
8
|
+
1. Create a PyPI account, verify email, enable 2FA, and save recovery codes.
|
|
9
|
+
2. Create the `albus-cli` project (first upload) or ask an owner to add you.
|
|
10
|
+
3. Create an API token limited to the `albus-cli` project and store it in a
|
|
11
|
+
password manager.
|
|
12
|
+
|
|
13
|
+
TestPyPI has separate accounts and tokens.
|
|
14
|
+
|
|
15
|
+
Never put an API token in this repository, a command-line argument, shell
|
|
16
|
+
history, or a pull request.
|
|
17
|
+
|
|
18
|
+
## Choose a version
|
|
19
|
+
|
|
20
|
+
Use a normalized PEP 440 version. Bump `project.version` in `pyproject.toml`
|
|
21
|
+
and pin `albus-sdk` to the intended public SDK release before publishing.
|
|
22
|
+
|
|
23
|
+
Published versions cannot be reused.
|
|
24
|
+
|
|
25
|
+
## Prepare a release
|
|
26
|
+
|
|
27
|
+
1. Sync package sources from the private monorepo `cli/` if development
|
|
28
|
+
happened there.
|
|
29
|
+
2. Update `version` and the `albus-sdk==…` pin in `pyproject.toml`.
|
|
30
|
+
3. Merge to `master` on a clean tree.
|
|
31
|
+
4. Validate:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
./tools/publish --dry-run 0.1.0
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Publish
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
read -s UV_PUBLISH_TOKEN
|
|
41
|
+
export UV_PUBLISH_TOKEN
|
|
42
|
+
./tools/publish 0.1.0
|
|
43
|
+
unset UV_PUBLISH_TOKEN
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
TestPyPI:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
./tools/publish --testpypi 0.1.0
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Verify:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
uv tool install albus-cli==0.1.0
|
|
56
|
+
albus --help
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Or exercise the public installer after the release is visible on PyPI.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Install the Albus CLI (albus) from PyPI.
|
|
2
|
+
# Prefers uv, then pip --user, then pip inside a conda env.
|
|
3
|
+
# Usage:
|
|
4
|
+
# irm https://raw.githubusercontent.com/albusgroup/albus-cli/master/install.ps1 | iex
|
|
5
|
+
# Optional:
|
|
6
|
+
# $env:ALBUS_CLI_VERSION = "0.1.0"
|
|
7
|
+
|
|
8
|
+
$ErrorActionPreference = "Stop"
|
|
9
|
+
|
|
10
|
+
$Package = "albus-cli"
|
|
11
|
+
$Version = $env:ALBUS_CLI_VERSION
|
|
12
|
+
if ([string]::IsNullOrEmpty($Version)) {
|
|
13
|
+
$Spec = $Package
|
|
14
|
+
} else {
|
|
15
|
+
$Spec = "$Package==$Version"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function Test-Command($Name) {
|
|
19
|
+
return $null -ne (Get-Command $Name -ErrorAction SilentlyContinue)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function Get-PipCommand {
|
|
23
|
+
if (Test-Command "py") {
|
|
24
|
+
try {
|
|
25
|
+
& py -m pip --version | Out-Null
|
|
26
|
+
if ($LASTEXITCODE -eq 0) { return @("py", "-m", "pip") }
|
|
27
|
+
} catch {}
|
|
28
|
+
}
|
|
29
|
+
if (Test-Command "python") {
|
|
30
|
+
try {
|
|
31
|
+
& python -m pip --version | Out-Null
|
|
32
|
+
if ($LASTEXITCODE -eq 0) { return @("python", "-m", "pip") }
|
|
33
|
+
} catch {}
|
|
34
|
+
}
|
|
35
|
+
if (Test-Command "python3") {
|
|
36
|
+
try {
|
|
37
|
+
& python3 -m pip --version | Out-Null
|
|
38
|
+
if ($LASTEXITCODE -eq 0) { return @("python3", "-m", "pip") }
|
|
39
|
+
} catch {}
|
|
40
|
+
}
|
|
41
|
+
return $null
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function Install-WithUv {
|
|
45
|
+
Write-Host "Installing $Spec with uv tool install..."
|
|
46
|
+
& uv tool install $Spec
|
|
47
|
+
if ($LASTEXITCODE -ne 0) { throw "uv tool install failed" }
|
|
48
|
+
Write-Host "Installed with uv. Ensure the uv tool bin directory is on PATH."
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function Install-WithPip {
|
|
52
|
+
$pip = Get-PipCommand
|
|
53
|
+
if ($null -eq $pip) { return $false }
|
|
54
|
+
Write-Host "Installing $Spec with $($pip -join ' ') --user..."
|
|
55
|
+
& $pip[0] $pip[1..($pip.Length - 1)] install --user $Spec
|
|
56
|
+
if ($LASTEXITCODE -ne 0) { throw "pip install failed" }
|
|
57
|
+
Write-Host "Installed with pip --user. Ensure your user Scripts directory is on PATH."
|
|
58
|
+
return $true
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function Install-WithConda {
|
|
62
|
+
if (-not (Test-Command "conda")) { return $false }
|
|
63
|
+
|
|
64
|
+
if (-not [string]::IsNullOrEmpty($env:CONDA_PREFIX)) {
|
|
65
|
+
$envPython = Join-Path $env:CONDA_PREFIX "python.exe"
|
|
66
|
+
$envLabel = $env:CONDA_PREFIX
|
|
67
|
+
} else {
|
|
68
|
+
$base = (& conda info --base).Trim()
|
|
69
|
+
$envPython = Join-Path $base "python.exe"
|
|
70
|
+
$envLabel = $base
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (-not (Test-Path $envPython)) {
|
|
74
|
+
throw "conda found but Python is missing at $envPython"
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
& $envPython -m pip --version | Out-Null
|
|
79
|
+
if ($LASTEXITCODE -ne 0) { throw "pip missing" }
|
|
80
|
+
} catch {
|
|
81
|
+
Write-Host "pip missing in conda env; installing pip via conda..."
|
|
82
|
+
& conda install -y pip
|
|
83
|
+
if ($LASTEXITCODE -ne 0) { throw "conda install pip failed" }
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
Write-Host "Installing $Spec with pip into conda env ($envLabel)..."
|
|
87
|
+
& $envPython -m pip install $Spec
|
|
88
|
+
if ($LASTEXITCODE -ne 0) { throw "conda env pip install failed" }
|
|
89
|
+
Write-Host "Installed into the conda env. Activate that env to run albus."
|
|
90
|
+
return $true
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (Test-Command "uv") {
|
|
94
|
+
Install-WithUv
|
|
95
|
+
} elseif (Install-WithPip) {
|
|
96
|
+
# done
|
|
97
|
+
} elseif (Install-WithConda) {
|
|
98
|
+
# done
|
|
99
|
+
} else {
|
|
100
|
+
throw "need uv, pip, or conda on PATH. Install one of them, then re-run."
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (Test-Command "albus") {
|
|
104
|
+
Write-Host "Running: albus --help"
|
|
105
|
+
& albus --help
|
|
106
|
+
} else {
|
|
107
|
+
Write-Host "albus is installed but not on PATH yet. Open a new shell or add the scripts directory to PATH, then run: albus --help"
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
Write-Host "Set ALBUS_API_KEY before calling the API."
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Install the Albus CLI (albus) from PyPI.
|
|
3
|
+
# Prefers uv, then pip --user, then pip inside a conda env.
|
|
4
|
+
# Usage:
|
|
5
|
+
# curl -fsSL https://raw.githubusercontent.com/albusgroup/albus-cli/master/install.sh | sh
|
|
6
|
+
# Optional:
|
|
7
|
+
# ALBUS_CLI_VERSION=0.1.0 curl -fsSL ... | sh
|
|
8
|
+
|
|
9
|
+
set -eu
|
|
10
|
+
|
|
11
|
+
PACKAGE="albus-cli"
|
|
12
|
+
VERSION="${ALBUS_CLI_VERSION:-}"
|
|
13
|
+
|
|
14
|
+
spec="$PACKAGE"
|
|
15
|
+
if [ -n "$VERSION" ]; then
|
|
16
|
+
spec="${PACKAGE}==${VERSION}"
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
say() {
|
|
20
|
+
printf '%s\n' "$*"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
err() {
|
|
24
|
+
printf 'error: %s\n' "$*" >&2
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
have() {
|
|
28
|
+
command -v "$1" >/dev/null 2>&1
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
pip_cmd() {
|
|
32
|
+
if have python3; then
|
|
33
|
+
if python3 -m pip --version >/dev/null 2>&1; then
|
|
34
|
+
printf '%s\n' "python3 -m pip"
|
|
35
|
+
return 0
|
|
36
|
+
fi
|
|
37
|
+
fi
|
|
38
|
+
if have python; then
|
|
39
|
+
if python -m pip --version >/dev/null 2>&1; then
|
|
40
|
+
printf '%s\n' "python -m pip"
|
|
41
|
+
return 0
|
|
42
|
+
fi
|
|
43
|
+
fi
|
|
44
|
+
return 1
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
install_with_uv() {
|
|
48
|
+
say "Installing ${spec} with uv tool install..."
|
|
49
|
+
uv tool install "$spec"
|
|
50
|
+
say "Installed with uv. Ensure the uv tool bin directory is on your PATH"
|
|
51
|
+
say "(usually ~/.local/bin)."
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
install_with_pip() {
|
|
55
|
+
cmd=$(pip_cmd) || return 1
|
|
56
|
+
say "Installing ${spec} with ${cmd} --user..."
|
|
57
|
+
# shellcheck disable=SC2086
|
|
58
|
+
$cmd install --user "$spec"
|
|
59
|
+
say "Installed with pip --user. Ensure your user scripts directory is on"
|
|
60
|
+
say "PATH (often ~/.local/bin on Unix)."
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
install_with_conda() {
|
|
64
|
+
have conda || return 1
|
|
65
|
+
|
|
66
|
+
if [ -n "${CONDA_PREFIX:-}" ]; then
|
|
67
|
+
env_python="${CONDA_PREFIX}/bin/python"
|
|
68
|
+
env_label="$CONDA_PREFIX"
|
|
69
|
+
else
|
|
70
|
+
base_prefix=$(conda info --base 2>/dev/null) || return 1
|
|
71
|
+
env_python="${base_prefix}/bin/python"
|
|
72
|
+
env_label="$base_prefix"
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
if [ ! -x "$env_python" ]; then
|
|
76
|
+
err "conda found but Python is missing at ${env_python}"
|
|
77
|
+
return 1
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
if ! "$env_python" -m pip --version >/dev/null 2>&1; then
|
|
81
|
+
say "pip missing in conda env; installing pip via conda..."
|
|
82
|
+
conda install -y pip
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
say "Installing ${spec} with pip into conda env (${env_label})..."
|
|
86
|
+
"$env_python" -m pip install "$spec"
|
|
87
|
+
say "Installed into the conda env. Activate that env (or ensure its"
|
|
88
|
+
say "bin/Scripts directory is on PATH) to run albus."
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if have uv; then
|
|
92
|
+
install_with_uv
|
|
93
|
+
elif pip_cmd >/dev/null 2>&1; then
|
|
94
|
+
install_with_pip
|
|
95
|
+
elif have conda; then
|
|
96
|
+
install_with_conda
|
|
97
|
+
else
|
|
98
|
+
err "need uv, pip, or conda on PATH"
|
|
99
|
+
err "Install one of them, then re-run this script."
|
|
100
|
+
exit 1
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
if have albus; then
|
|
104
|
+
say "Running: albus --help"
|
|
105
|
+
albus --help
|
|
106
|
+
else
|
|
107
|
+
say "albus is installed but not on PATH yet. Open a new shell or add"
|
|
108
|
+
say "the scripts directory reported above to PATH, then run: albus --help"
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
say "Set ALBUS_API_KEY before calling the API."
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27,<2"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "albus-cli"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Command-line client for the Albus REST API"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
authors = [{ name = "Albus" }]
|
|
13
|
+
dependencies = [
|
|
14
|
+
"albus-sdk==0.4.0",
|
|
15
|
+
"typer>=0.26.8,<0.28",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.urls]
|
|
19
|
+
Homepage = "https://github.com/albusgroup/albus-cli"
|
|
20
|
+
Repository = "https://github.com/albusgroup/albus-cli"
|
|
21
|
+
Issues = "https://github.com/albusgroup/albus-cli/issues"
|
|
22
|
+
|
|
23
|
+
[project.scripts]
|
|
24
|
+
albus = "albus_cli.main:main"
|
|
25
|
+
|
|
26
|
+
[dependency-groups]
|
|
27
|
+
dev = [
|
|
28
|
+
"mypy>=1.17,<2",
|
|
29
|
+
"pytest>=8.4,<10",
|
|
30
|
+
"ruff>=0.16,<0.17",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[tool.hatch.build.targets.wheel]
|
|
34
|
+
packages = ["src/albus_cli"]
|
|
35
|
+
|
|
36
|
+
[tool.ruff]
|
|
37
|
+
line-length = 81
|
|
38
|
+
src = ["src", "tests"]
|
|
39
|
+
|
|
40
|
+
[tool.ruff.lint]
|
|
41
|
+
select = ["E", "F", "I", "UP", "B", "SIM"]
|
|
42
|
+
|
|
43
|
+
[tool.ruff.lint.isort]
|
|
44
|
+
known-first-party = ["albus_cli", "tests"]
|
|
45
|
+
|
|
46
|
+
[tool.mypy]
|
|
47
|
+
python_version = "3.11"
|
|
48
|
+
files = ["src", "tests"]
|
|
49
|
+
strict = true
|
|
50
|
+
|
|
51
|
+
[tool.pytest.ini_options]
|
|
52
|
+
testpaths = ["tests"]
|
|
File without changes
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Albus SDK client construction from the shell environment."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
from albus_sdk import Albus, models
|
|
7
|
+
|
|
8
|
+
API_KEY_ENV = "ALBUS_API_KEY"
|
|
9
|
+
BASE_URL_ENV = "ALBUS_BASE_URL"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class MissingAPIKey(Exception):
|
|
13
|
+
def __init__(self) -> None:
|
|
14
|
+
super().__init__(
|
|
15
|
+
f"{API_KEY_ENV} is not set. Export an Albus API key, e.g. "
|
|
16
|
+
f"`export {API_KEY_ENV}=...`."
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def client(base_url: str | None, timeout: float | None) -> Albus:
|
|
21
|
+
"""Build an SDK client. A timeout of None disables the read timeout."""
|
|
22
|
+
api_key = os.environ.get(API_KEY_ENV)
|
|
23
|
+
if not api_key:
|
|
24
|
+
raise MissingAPIKey
|
|
25
|
+
|
|
26
|
+
return Albus(
|
|
27
|
+
security=models.Security(api_key_auth=api_key),
|
|
28
|
+
server_url=base_url,
|
|
29
|
+
client=httpx.Client(follow_redirects=True, timeout=timeout),
|
|
30
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""`albus agents` — inspect the agents that have run in the org."""
|
|
2
|
+
|
|
3
|
+
from typing import Annotated
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from albus_cli.context import sdk
|
|
8
|
+
from albus_cli.output import emit
|
|
9
|
+
|
|
10
|
+
app = typer.Typer(no_args_is_help=True, help="Inspect agents.")
|
|
11
|
+
|
|
12
|
+
AgentName = Annotated[
|
|
13
|
+
str, typer.Argument(metavar="AGENT_NAME", help="Agent name.")
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@app.command("list")
|
|
18
|
+
def list_agents(ctx: typer.Context) -> None:
|
|
19
|
+
"""List agents."""
|
|
20
|
+
emit(sdk(ctx).agents.list_agents())
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@app.command("get")
|
|
24
|
+
def get(ctx: typer.Context, name: AgentName) -> None:
|
|
25
|
+
"""Get an agent with its current revision."""
|
|
26
|
+
emit(sdk(ctx).agents.get_agent(name=name))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@app.command("revision")
|
|
30
|
+
def revision(
|
|
31
|
+
ctx: typer.Context,
|
|
32
|
+
name: AgentName,
|
|
33
|
+
revision: Annotated[
|
|
34
|
+
str,
|
|
35
|
+
typer.Argument(metavar="REVISION", help="Agent revision identifier."),
|
|
36
|
+
],
|
|
37
|
+
) -> None:
|
|
38
|
+
"""Get one revision of an agent."""
|
|
39
|
+
emit(sdk(ctx).agents.get_agent_revision(name=name, revision=revision))
|