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
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ jobs:

- name: Verify the wheel version matches the tag
# The asset URL that build_kbagent_upgrade_command / install.sh construct
# is `keboola_agent_cli-<version>-py3-none-any.whl` under the `v<version>`
# is `keboola_cli-<version>-py3-none-any.whl` under the `v<version>`
# tag. A mismatch here means clients would build a 404 URL, so fail loud.
run: |
tag="$TAG"
version="${tag#v}"
expected="dist/keboola_agent_cli-${version}-py3-none-any.whl"
expected="dist/keboola_cli-${version}-py3-none-any.whl"
if [ ! -f "$expected" ]; then
echo "::error::Expected $expected but built: $(ls dist/)"
exit 1
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ Seven clients, all inheriting `BaseHttpClient` (`http_base.py`) which provides s

**Single source of truth: `pyproject.toml`** (`version = "X.Y.Z"`).

- `src/keboola_agent_cli/__init__.py` reads the version at runtime via `importlib.metadata.version("keboola-agent-cli")`. **Never hardcode a version string in `__init__.py`.**
- `src/keboola_agent_cli/__init__.py` reads the version at runtime via `importlib.metadata.version(APP_NAME)` (where `APP_NAME = "keboola-cli"`). **Never hardcode a version string in `__init__.py`.**
- `plugins/kbagent/.claude-plugin/plugin.json` must match. Run `make version-sync` (or `python scripts/sync_version.py`) to update it.
- The pre-commit hook and CI automatically check version consistency.

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,7 @@ PEP 440 syntax in `pyproject.toml`'s `version` field). Two gates keep stable
users safe from accidentally landing on a beta:

1. **Version string itself.** PEP 440 marks any pre-release suffix as such;
`pip install keboola-agent-cli` and `uv tool install ...` default to
`pip install keboola-cli` and `uv tool install ...` default to
**skipping** pre-releases unless the resolver is told otherwise (`--pre`
for pip, `--prerelease=allow` for uv).
2. **GitHub Release `prerelease: true` flag.** The auto-update startup
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Auto-updates kbagent **and** its `keboola-mcp-server` dependency on every launch
Want a browser dashboard? One command:

```bash
uv tool install --with 'keboola-agent-cli[server]' 'git+https://github.com/keboola/cli'
uv tool install --with 'keboola-cli[server]' 'git+https://github.com/keboola/cli'
kbagent serve --ui
# Open the URL printed at startup -- the browser is auto-authenticated.
```
Expand All @@ -51,7 +51,7 @@ Build the agent once, schedule it, walk away — the platform handles auth, sche
The scheduler runs **inside `kbagent serve`** -- the same single Python process that hosts the Web UI. If you already installed kbagent with the `[server]` extras (see [Web UI](#web-ui-optional) above), you're set; otherwise:

```bash
uv tool install --with 'keboola-agent-cli[server]' 'git+https://github.com/keboola/cli'
uv tool install --with 'keboola-cli[server]' 'git+https://github.com/keboola/cli'
kbagent serve --ui
# Open the URL printed at startup -> sidebar "Agent Tasks" -> "+ New task".
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ Run:
uv build --wheel 2>&1 | tail -5
```

Expected: a `dist/keboola_agent_cli-0.55.0-*.whl` (version bumps later).
Expected: a `dist/keboola_cli-0.55.0-*.whl` (version bumps later).

- [ ] **Step 2: Assert the schema is inside the wheel**

Expand Down
2 changes: 1 addition & 1 deletion docs/use-cases.md
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ Expired tokens clean themselves up. No manual rotation needed.

```bash
# Install
uv pip install keboola-agent-cli
uv pip install keboola-cli

# Add your first project
kbagent project add --project analytics \
Expand Down
4 changes: 2 additions & 2 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
set -eu

REPO="keboola/cli"
PKG="keboola-agent-cli"
DIST="keboola_agent_cli" # normalized distribution name used in the wheel filename
PKG="keboola-cli"
DIST="keboola_cli" # normalized distribution name used in the wheel filename

info() { printf '%s\n' "$*" >&2; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use it from scripts, other AI agents, or `kbagent http` subprocesses.

```bash
# One-time install with server extras
uv tool install --with 'keboola-agent-cli[server]' \
uv tool install --with 'keboola-cli[server]' \
'git+https://github.com/keboola/cli'

# Run (keep this terminal open; scheduler dies when the server stops)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[project]
name = "keboola-agent-cli"
name = "keboola-cli"
version = "0.62.0"
description = "AI-friendly CLI for managing Keboola projects"
readme = "README.md"
Expand Down
2 changes: 1 addition & 1 deletion scripts/hatch_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
- ``uv tool install git+https://github.com/keboola/cli`` --
uv clones the repo, runs ``hatchling`` to produce a wheel, installs it,
then deletes the clone. The user does NOT have a checkout on disk.
- ``pip install keboola-agent-cli`` (PyPI) -- prebuilt wheel.
- ``pip install keboola-cli`` (PyPI) -- prebuilt wheel.

For ``kbagent serve --ui`` to work after either install path, the wheel
must already carry the SPA. This hook arranges that by:
Expand Down
4 changes: 2 additions & 2 deletions scripts/sync_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
- ``plugins/kbagent/.claude-plugin/plugin.json`` (plugin manifest)
- ``.claude-plugin/marketplace.json`` -> ``plugins[*].version``
(per-plugin entry the marketplace descriptor exposes to Claude Code)
- ``uv.lock`` -> the ``keboola-agent-cli`` package's own ``version`` pin
- ``uv.lock`` -> the ``keboola-cli`` package's own ``version`` pin
(uv records the workspace package version; a pyproject bump leaves it
stale until ``uv lock`` reruns, which ``version-check`` then flags)

Expand Down Expand Up @@ -43,7 +43,7 @@
KBAGENT_PLUGIN_NAME = "kbagent"

# Distribution name of this project as it appears in uv.lock's [[package]] table.
KBAGENT_DIST_NAME = "keboola-agent-cli"
KBAGENT_DIST_NAME = "keboola-cli"


def get_pyproject_version() -> str:
Expand Down
2 changes: 1 addition & 1 deletion src/keboola_agent_cli/auto_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def _is_dev_install() -> bool:
return True

try:
dist = distribution("keboola-agent-cli")
dist = distribution("keboola-cli")
direct_url = dist.read_text("direct_url.json")
if direct_url:
data = json.loads(direct_url)
Expand Down
7 changes: 7 additions & 0 deletions src/keboola_agent_cli/changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@
"could drop a column (`delete-column`) but not add one. The Storage add-column "
"endpoint is synchronous (no job to wait on); the operation is classified `write` "
"in the permission registry.",
"Change (#424): the PyPI distribution is renamed from `keboola-agent-cli` to "
"`keboola-cli`; the prebuilt-wheel asset is now `keboola_cli-<version>-py3-none-any.whl`. "
"The import package (`keboola_agent_cli`), the `kbagent` binary, and the config dir "
"(`~/.config/keboola-agent-cli/`) are unchanged, so existing installs keep working. "
"Only a literal `pip install keboola-agent-cli` from PyPI stops resolving -- use "
"`keboola-cli`. The release CI, `install.sh`, and the self-update resolver all build "
"the new wheel name end-to-end.",
],
"0.61.1": [
"Note (#416 follow-up): clarified the value-typing contract of the importable "
Expand Down
2 changes: 1 addition & 1 deletion src/keboola_agent_cli/commands/serve.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def serve_command(
f"(missing: {missing}).\n\n"
"Reinstall with the [server] extras:\n\n"
" # If you installed via uv tool install (recommended for end users):\n"
" uv tool install --force --with 'keboola-agent-cli[server]' \\\n"
" uv tool install --force --with 'keboola-cli[server]' \\\n"
" git+https://github.com/keboola/cli\n\n"
" # If you have a local checkout (development):\n"
" uv pip install -e '.[server]'\n",
Expand Down
2 changes: 1 addition & 1 deletion src/keboola_agent_cli/config_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ def load(self) -> AppConfig:
if version > CURRENT_CONFIG_VERSION:
raise ConfigError(
f"Config file version {version} is newer than supported version "
f"{CURRENT_CONFIG_VERSION}. Please upgrade keboola-agent-cli."
f"{CURRENT_CONFIG_VERSION}. Please upgrade keboola-cli."
)

try:
Expand Down
2 changes: 1 addition & 1 deletion src/keboola_agent_cli/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# --- Application identity ---
# Distribution/package name; single source for importlib.metadata lookup and
# the User-Agent product token that signs every Keboola API call.
APP_NAME: str = "keboola-agent-cli"
APP_NAME: str = "keboola-cli"

# --- Sentinel for missing metadata keys ---
# Distinguishes "key absent" from "value is None/null" in branch metadata lookups.
Expand Down
4 changes: 2 additions & 2 deletions src/keboola_agent_cli/http_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ def build_user_agent() -> str:

Format (RFC 7231 product + comment):

keboola-agent-cli/<version> (<os> <release>; <arch>; <impl> <pyver>)
e.g. keboola-agent-cli/0.45.0 (Darwin 25.3.0; arm64; CPython 3.12.7)
keboola-cli/<version> (<os> <release>; <arch>; <impl> <pyver>)
e.g. keboola-cli/0.45.0 (Darwin 25.3.0; arm64; CPython 3.12.7)

Keboola's edge logs this verbatim (DataDog access logs), so the fleet can
be segmented by version and OS/arch. Only neutral host metadata is sent --
Expand Down
18 changes: 9 additions & 9 deletions src/keboola_agent_cli/services/version_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ def has_server_extras() -> bool:
is pulled in *only* by the optional ``[server]`` extra (declared in
``pyproject.toml``'s ``[project.optional-dependencies]`` table), so its
presence is a reliable proxy for "user originally installed with
``--with 'keboola-agent-cli[server]'``".
``--with 'keboola-cli[server]'``".

Used by every kbagent self-upgrade path (``kbagent update`` and the
startup auto-update hook) to decide whether to pair ``uv tool install``
with ``--with 'keboola-agent-cli[server]'`` -- without that flag, the
with ``--with 'keboola-cli[server]'`` -- without that flag, the
fresh re-resolution silently drops the FastAPI + uvicorn extras and
breaks ``kbagent serve --ui`` for users who originally installed with
``[server]``. (Bug fixed in v0.40.2 for the explicit ``kbagent update``
Expand All @@ -74,7 +74,7 @@ def resolve_kbagent_wheel_url(
"""Return the prebuilt-wheel Release asset URL for ``version`` if present.

The ``release.yml`` workflow (issue #353) attaches a universal
``keboola_agent_cli-<version>-py3-none-any.whl`` to every GitHub release.
``keboola_cli-<version>-py3-none-any.whl`` to every GitHub release.
Installing that prebuilt wheel skips the on-machine npm/React SPA build that
makes ``git+`` installs take minutes on WSL.

Expand All @@ -95,7 +95,7 @@ def resolve_kbagent_wheel_url(
return None
url = (
f"https://github.com/{KBAGENT_GITHUB_REPO}/releases/download/"
f"v{version}/keboola_agent_cli-{version}-py3-none-any.whl"
f"v{version}/keboola_cli-{version}-py3-none-any.whl"
)
try:
resp = httpx.head(url, follow_redirects=True, timeout=timeout)
Expand Down Expand Up @@ -170,9 +170,9 @@ def build_kbagent_upgrade_command(
# (git-source knobs) do not apply here.
if wheel_url is not None:
spec = (
f"keboola-agent-cli[server] @ {wheel_url}"
f"keboola-cli[server] @ {wheel_url}"
if has_server_extras()
else f"keboola-agent-cli @ {wheel_url}"
else f"keboola-cli @ {wheel_url}"
)
uv_path = shutil.which("uv")
if uv_path:
Expand Down Expand Up @@ -205,7 +205,7 @@ def build_kbagent_upgrade_command(
"install",
"--force",
"--with",
"keboola-agent-cli[server]",
"keboola-cli[server]",
install_source,
]
else:
Expand All @@ -221,7 +221,7 @@ def build_kbagent_upgrade_command(
# pip extras syntax: the [server] suffix attaches to the project
# name in the PEP 508 spec; for git+ URLs we wrap with the project
# name on the left of the URL.
install_spec = f"keboola-agent-cli[server] @ {install_source}" if has_server else install_source
install_spec = f"keboola-cli[server] @ {install_source}" if has_server else install_source
cmd = [pip_path, "install", "--upgrade", install_spec]
if prerelease:
cmd.insert(2, "--pre")
Expand Down Expand Up @@ -882,7 +882,7 @@ def _update_kbagent(*, include_prerelease: bool = False) -> dict[str, Any]:
prerelease=include_prerelease, target_version=target_version, wheel_url=wheel_url
)
if cmd is None:
with_flag = "--with 'keboola-agent-cli[server]' " if has_server_extras() else ""
with_flag = "--with 'keboola-cli[server]' " if has_server_extras() else ""
pre_flag = "--prerelease=allow " if include_prerelease else ""
tag_suffix = f"@v{target_version}" if target_version else ""
return {
Expand Down
10 changes: 5 additions & 5 deletions tests/test_auto_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ def test_update_preserves_server_extras(self, mock_run, mock_which, mock_has_ser
Before v0.41.1, ``_perform_update`` ran a bare
``uv tool install --upgrade git+...`` which silently dropped the
FastAPI + uvicorn extras a user originally installed with
``--with 'keboola-agent-cli[server]'`` -- so a user who had
``--with 'keboola-cli[server]'`` -- so a user who had
``kbagent serve --ui`` working would lose it on the next startup
auto-update. Now ``_perform_update`` delegates to
:func:`build_kbagent_upgrade_command`, which pairs ``--with`` and
Expand All @@ -303,10 +303,10 @@ def test_update_preserves_server_extras(self, mock_run, mock_which, mock_has_ser
mock_run.return_value = MagicMock(returncode=0)
assert _perform_update("2.0.0") is UpdateOutcome.SUCCESS
argv = mock_run.call_args[0][0]
# uv tool install --force --with 'keboola-agent-cli[server]' git+...
# uv tool install --force --with 'keboola-cli[server]' git+...
assert "--force" in argv
assert "--with" in argv
assert "keboola-agent-cli[server]" in argv
assert "keboola-cli[server]" in argv
# Must NOT pass --upgrade in this branch (uv rejects --upgrade + --with).
assert "--upgrade" not in argv

Expand All @@ -323,7 +323,7 @@ def test_update_without_server_extras_uses_upgrade(self, mock_run, mock_which, m
argv = mock_run.call_args[0][0]
assert "--upgrade" in argv
assert "--with" not in argv
assert "keboola-agent-cli[server]" not in argv
assert "keboola-cli[server]" not in argv


class TestPerformUpdateWheel:
Expand All @@ -348,7 +348,7 @@ def test_installs_wheel_when_asset_present(
argv = mock_run.call_args[0][0]
# PEP 508 direct ref to the versioned wheel, --force, and no git+ source.
assert "--force" in argv
assert any(part.endswith("keboola_agent_cli-2.0.0-py3-none-any.whl") for part in argv)
assert any(part.endswith("keboola_cli-2.0.0-py3-none-any.whl") for part in argv)
assert all("git+" not in part for part in argv)

@patch("keboola_agent_cli.services.version_service.httpx.head")
Expand Down
2 changes: 1 addition & 1 deletion tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ def test_user_agent_header(self, httpx_mock) -> None:
client.verify_token()

request = httpx_mock.get_request()
assert "keboola-agent-cli/" in request.headers["user-agent"]
assert "keboola-cli/" in request.headers["user-agent"]
client.close()

def test_storage_api_token_header(self, httpx_mock) -> None:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_manage_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def test_sends_manage_api_token_header(self, httpx_mock) -> None:

request = httpx_mock.get_request()
assert request.headers["X-KBC-ManageApiToken"] == MANAGE_TOKEN
assert "keboola-agent-cli" in request.headers["User-Agent"]
assert "keboola-cli" in request.headers["User-Agent"]
client.close()

def test_does_not_send_storage_token_header(self, httpx_mock) -> None:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_metastore_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def test_token_header_set_on_get(self, httpx_mock) -> None:
client.close()
request = httpx_mock.get_requests()[0]
assert request.headers["X-StorageApi-Token"] == TOKEN
assert "keboola-agent-cli/" in request.headers["User-Agent"]
assert "keboola-cli/" in request.headers["User-Agent"]


class TestListItems:
Expand Down
16 changes: 8 additions & 8 deletions tests/test_sync_version_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def isolated_repo(tmp_path: Path, monkeypatch):
"""Lay out a miniature repo tree the sync script can operate on."""
pyproject = tmp_path / "pyproject.toml"
pyproject.write_text(
'[project]\nname = "keboola-agent-cli"\nversion = "9.9.9"\n',
'[project]\nname = "keboola-cli"\nversion = "9.9.9"\n',
encoding="utf-8",
)

Expand All @@ -50,7 +50,7 @@ def isolated_repo(tmp_path: Path, monkeypatch):
marketplace_json.write_text(
json.dumps(
{
"name": "keboola-agent-cli",
"name": "keboola-cli",
"version": "1.0.0",
"plugins": [
{
Expand All @@ -67,10 +67,10 @@ def isolated_repo(tmp_path: Path, monkeypatch):
)

# Minimal uv.lock with our package entry plus an unrelated one, so we can
# assert the version patch is scoped to keboola-agent-cli only.
# assert the version patch is scoped to keboola-cli only.
uv_lock = tmp_path / "uv.lock"
uv_lock.write_text(
'[[package]]\nname = "keboola-agent-cli"\nversion = "0.0.0"\n'
'[[package]]\nname = "keboola-cli"\nversion = "0.0.0"\n'
'source = { editable = "." }\n\n'
'[[package]]\nname = "croniter"\nversion = "1.2.3"\n'
'source = { registry = "https://pypi.org/simple" }\n',
Expand Down Expand Up @@ -194,21 +194,21 @@ def test_main_runs_end_to_end(isolated_repo: dict, capsys) -> None:
out = capsys.readouterr().out
assert "Updated plugin.json to 9.9.9" in out
assert "Updated marketplace.json" in out
assert "Updated uv.lock keboola-agent-cli version to 9.9.9" in out
assert "Updated uv.lock keboola-cli version to 9.9.9" in out

# Second run prints the idempotent message on all targets.
_sync.main()
out = capsys.readouterr().out
assert "plugin.json already at 9.9.9" in out
assert "marketplace.json" in out and "already at 9.9.9" in out
assert "uv.lock keboola-agent-cli version already at 9.9.9" in out
assert "uv.lock keboola-cli version already at 9.9.9" in out


def test_sync_uv_lock_updates_self_version(isolated_repo: dict) -> None:
changed = _sync.sync_uv_lock("9.9.9")
assert changed is True
text = isolated_repo["uv_lock"].read_text(encoding="utf-8")
assert 'name = "keboola-agent-cli"\nversion = "9.9.9"' in text
assert 'name = "keboola-cli"\nversion = "9.9.9"' in text


def test_sync_uv_lock_does_not_touch_other_packages(isolated_repo: dict) -> None:
Expand Down Expand Up @@ -241,4 +241,4 @@ def test_sync_uv_lock_missing_package_entry_warns(isolated_repo: dict, capsys) -
)
changed = _sync.sync_uv_lock("9.9.9")
assert changed is False
assert "keboola-agent-cli" in capsys.readouterr().err.lower()
assert "keboola-cli" in capsys.readouterr().err.lower()
Loading