diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 5e872b121..5d7823c70 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -10,7 +10,7 @@ "plugins": [ { "name": "kbagent", - "version": "0.93.2", + "version": "0.94.0", "source": "./plugins/kbagent", "description": "DEPRECATED — install from keboola/ai-kit: /plugin marketplace add keboola/ai-kit && /plugin install kbagent@keboola-claude-kit — AI-friendly interface to Keboola Connection projects — explore configs, jobs, lineage, sync configs as files, manage dev branches, and debug SQL in workspaces", "category": "development" diff --git a/CLAUDE.md b/CLAUDE.md index 4b0157621..6bcf84897 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -739,11 +739,11 @@ kbagent branch metadata-list --project NAME [--branch ID|default] kbagent branch metadata-get --project NAME --key KEY [--branch ID|default] kbagent branch metadata-set --project NAME --key KEY [--text STR | --file PATH | --stdin] [--branch ID|default] kbagent branch metadata-delete --project NAME --metadata-id ID [--branch ID|default] -# branch merge is DEPRECATED (since vNEXT): it only builds a UI URL and resets the active branch. On a +# branch merge is DEPRECATED (since 0.94.0): it only builds a UI URL and resets the active branch. On a # project with `branches-merge-requests` use the merge-request group below; the command keeps working # (it also serves projects without the feature) and now carries `deprecation` in --json. -# merge-request (since vNEXT, DMD-1900): the non-SOX Branches 2.0 lifecycle. Hidden alias `mr`. Every +# merge-request (since 0.94.0, DMD-1900): the non-SOX Branches 2.0 lifecycle. Hidden alias `mr`. Every # command except list/create takes `[--merge-request-id N | --id N] [--branch B]`: omitted, the target is # the merge request OF the active branch (`branch use`) -- a branch has at most one MR, ever. Both flags at # once -> exit 2. `--project` is single-project (never fans out). Status is the DERIVED state the web UI diff --git a/plugins/kbagent/.claude-plugin/plugin.json b/plugins/kbagent/.claude-plugin/plugin.json index 23eb0e96f..21a0994e0 100644 --- a/plugins/kbagent/.claude-plugin/plugin.json +++ b/plugins/kbagent/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "kbagent", - "version": "0.93.2", + "version": "0.94.0", "description": "AI-friendly interface to Keboola Connection projects — explore configs, jobs, lineage, sync configs as files, manage dev branches, and debug SQL in workspaces", "author": { "name": "Keboola", diff --git a/plugins/kbagent/agents/keboola-expert.md b/plugins/kbagent/agents/keboola-expert.md index 3fb4febd5..dad595cfc 100644 --- a/plugins/kbagent/agents/keboola-expert.md +++ b/plugins/kbagent/agents/keboola-expert.md @@ -129,7 +129,7 @@ been retired, so its absence is NOT a promise (see §1 Rule 6). | Export a FILTERED or INCREMENTAL slice of a table (no workspace) | `kbagent storage download-table --table-id ... --where-column status --where-value active [--where-operator eq\|neq] [--changed-since "-2 days"]` -- server-side filter on the credential-only export path | `kbagent workspace query` with a `WHERE` clause when you need real SQL | downloading the whole table then filtering locally | | Run Keboola SQL / read-write Storage Files from INSIDE a Python process you control | `from keboola_agent_cli import Client` -- stateless `Client(url, token)`; `.query(workspace_id, sql)`, `.files.upload/.read_bytes/.list`; no subprocess, no `serve`, no config-dir. See [library-workflow.md](../skills/kbagent/references/library-workflow.md) | the CLI or `kbagent serve` REST when you are NOT already inside Python | shelling out to the `kbagent` binary from Python you control; using it for open-ended exploration (fixed set of typed ops) | | Inspect dev branch | `kbagent branch list --project P`, `kbagent branch use --project P --branch ID` | -- | acting on `main` when a dev branch exists | -| Merge a dev branch into production (review, conflicts) | `kbagent merge-request create --title T` from the active branch, `merge-request detail` for readiness, `merge-request merge` (vNEXT+; project feature `branches-merge-requests`). Conflicts: `conflicts` -> `diff --component-id C --config-id I` -> `resolve --take ours\|theirs\|delete`. See [merge-request-workflow.md](../skills/kbagent/references/merge-request-workflow.md) -- read the "What is destructive" section before automating | `branch merge` (deprecated URL builder) on a project WITHOUT the feature | treating `request-review`/`approve`/`resolve` as plain writes (they move the MR toward production and are destructive by command, always -- `--deny-destructive` blocks them); `merge-request auto-merge` without treating it as a production merge (a backend scheduler merges on its own once approved); passing `--auto-merge-strategy` to `create`/`update` (no such option -- arming is its own command); any destructive `--json` call with no `--merge-request-id`/`--branch` (exit 2 by design); `resolve --resolved` with a partial body (rebase REPLACES -- all five keys or refused); reading a `list` row's `allowed_actions` as feature-aware (only `detail` carries `feature_enabled`); `approve` on a 0-approval project (422 in every state) | +| Merge a dev branch into production (review, conflicts) | `kbagent merge-request create --title T` from the active branch, `merge-request detail` for readiness, `merge-request merge` (0.94.0+; project feature `branches-merge-requests`). Conflicts: `conflicts` -> `diff --component-id C --config-id I` -> `resolve --take ours\|theirs\|delete`. See [merge-request-workflow.md](../skills/kbagent/references/merge-request-workflow.md) -- read the "What is destructive" section before automating | `branch merge` (deprecated URL builder) on a project WITHOUT the feature | treating `request-review`/`approve`/`resolve` as plain writes (they move the MR toward production and are destructive by command, always -- `--deny-destructive` blocks them); `merge-request auto-merge` without treating it as a production merge (a backend scheduler merges on its own once approved); passing `--auto-merge-strategy` to `create`/`update` (no such option -- arming is its own command); any destructive `--json` call with no `--merge-request-id`/`--branch` (exit 2 by design); `resolve --resolved` with a partial body (rebase REPLACES -- all five keys or refused); reading a `list` row's `allowed_actions` as feature-aware (only `detail` carries `feature_enabled`); `approve` on a 0-approval project (422 in every state) | | Audit project capabilities / features | `kbagent project info --project P` -- project id, name, backend, enabled features, quota limits, metrics | -- | inspecting the UI project settings manually | | Manage feature flags (stack / project / user) | `kbagent feature list\|project-show\|project-add\|project-remove\|user-show\|user-add\|user-remove --project P [--email E] [--feature NAME] [--dry-run]` -- Manage API, needs a SUPER-ADMIN token (interactive prompt; `--allow-env-manage-token` for CI) | `kbagent project info` for a project's *enabled* features (read-only, no super-admin) | raw `/manage/...` calls; a manage token passed as a CLI flag | | Create a new config (one-shot remote, no scaffold to disk) | `kbagent config new --project P --component-id C --name N --push --no-files [--configuration @body.json]` -- default body `{}` skips validation; an explicit body is schema-validated (`--no-validate` opts out); works for every component type. `--output-dir` + `--push` together is safe only on 0.89.0+ (scaffold records `_keboola.config_id`, lands in the created branch's subtree); older kbagent writes an ID-less scaffold that the next `sync push` DUPLICATES (issue #644) -- there, scaffold and push in two steps | `kbagent config new --output-dir D` then edit + `kbagent sync push` | raw `POST /v2/storage/components/.../configs` (no schema validation, no encryption) | @@ -356,7 +356,7 @@ its absence is NOT a promise the entry is version-independent (see §1 Rule 6). `config detail` -> `configuration.runtime` FIRST (an empty `data-app logs` grep rules nothing out). `create` defaults it ON at **0.87.0+**; <= 0.86.0 patch + redeploy. -- **Data-app type in `sync`**: a `keboola.data-apps` config's runtime type (`python-js` / `streamlit`) lives only on the Data Science `/apps` record. `sync pull` records it as `_keboola.data_app_type`, and `sync push` / `sync clone` send it through `create_app`. A tree pulled before this carries no type, so re-pull the source before you clone, or the app deploys under the platform default, `streamlit` (since vNEXT). +- **Data-app type in `sync`**: a `keboola.data-apps` config's runtime type (`python-js` / `streamlit`) lives only on the Data Science `/apps` record. `sync pull` records it as `_keboola.data_app_type`, and `sync push` / `sync clone` send it through `create_app`. A tree pulled before this carries no type, so re-pull the source before you clone, or the app deploys under the platform default, `streamlit` (since 0.94.0). - **`ENCRYPTION_FAILED` on an Azure stack is a VERSION GATE, not a bad token**: <= 0.85.0 rejected the Azure `KBC::ProjectSecureKV::` cipher, so private-repo `create` and `secrets-set` could not work there at all. Upgrade to 0.86.0+; do diff --git a/plugins/kbagent/skills/kbagent/references/branch-workflow.md b/plugins/kbagent/skills/kbagent/references/branch-workflow.md index 484b62874..04c6383d6 100644 --- a/plugins/kbagent/skills/kbagent/references/branch-workflow.md +++ b/plugins/kbagent/skills/kbagent/references/branch-workflow.md @@ -30,12 +30,12 @@ kbagent --json branch merge --project ALIAS | `branch use --branch ID` | Switch to existing branch | | `branch reset` | Switch back to main/production | | `branch delete --branch ID` | Delete branch (resets if it was active) | -| `branch merge` | DEPRECATED (since vNEXT): get merge URL, reset to main. On a project with `branches-merge-requests` use `merge-request` -- see [merge-request-workflow.md](merge-request-workflow.md) | +| `branch merge` | DEPRECATED (since 0.94.0): get merge URL, reset to main. On a project with `branches-merge-requests` use `merge-request` -- see [merge-request-workflow.md](merge-request-workflow.md) | ## Key details - **Async operations**: `branch create` and `branch delete` are async on the API. kbagent waits for completion (typically 1-3s). No need to poll. -- **Merge from the CLI needs the merge-request group** *(since vNEXT)*: `branch merge` only returns a URL for the Keboola UI (and is deprecated). On a project with the `branches-merge-requests` feature, `kbagent merge-request create` + `merge-request merge` merge via the API with review and conflict resolution -- see [merge-request-workflow.md](merge-request-workflow.md). +- **Merge from the CLI needs the merge-request group** *(since 0.94.0)*: `branch merge` only returns a URL for the Keboola UI (and is deprecated). On a project with the `branches-merge-requests` feature, `kbagent merge-request create` + `merge-request merge` merge via the API with review and conflict resolution -- see [merge-request-workflow.md](merge-request-workflow.md). - **Active branch persistence**: stored in kbagent config. Survives between sessions. - **Config commands respect active branch**: `config list`, `config detail`, and `config search` auto-scope to the active branch. Use `--branch ID` to override. - **Workspaces respect active branch**: `workspace create` and `workspace delete` operate in the active branch context. diff --git a/plugins/kbagent/skills/kbagent/references/commands-reference.md b/plugins/kbagent/skills/kbagent/references/commands-reference.md index 329339f82..239bdc03f 100644 --- a/plugins/kbagent/skills/kbagent/references/commands-reference.md +++ b/plugins/kbagent/skills/kbagent/references/commands-reference.md @@ -243,14 +243,14 @@ Bucket sharing + linking across projects in the same organization. `sharing edge - `branch use --project ALIAS --branch ID` -- switch active branch - `branch reset --project ALIAS` -- reset to main/production - `branch delete --project ALIAS --branch ID` -- delete branch (resets if active) -- `branch merge --project ALIAS [--branch ID]` -- DEPRECATED (since vNEXT): get merge URL (does NOT merge via API), resets the active branch. Prefer `merge-request` on projects with the feature +- `branch merge --project ALIAS [--branch ID]` -- DEPRECATED (since 0.94.0): get merge URL (does NOT merge via API), resets the active branch. Prefer `merge-request` on projects with the feature - `branch metadata-list --project NAME [--branch ID|default]` -- list all metadata entries on a branch (id, key, value, provider, timestamp). `--branch` defaults to `default` (main branch) - `branch metadata-get --project NAME --key KEY [--branch ID|default]` -- read a single metadata value by key. Exits with `NOT_FOUND` (exit 1) if absent - `branch metadata-set --project NAME --key KEY [--text STR | --file PATH | --stdin] [--branch ID|default]` -- set a key/value. Useful for `KBC.projectDescription` and similar dashboard-visible fields. Pass exactly one of `--text`, `--file`, or `--stdin` - `branch metadata-delete --project NAME --metadata-id ID [--branch ID|default]` -- delete a metadata entry by its numeric ID (from `metadata-list`) ## Merge Requests -*(since vNEXT)* +*(since 0.94.0)* Non-SOX Branches 2.0: merge a dev branch into production with review. Alias `mr`. Every command except `list`/`create` takes `[--merge-request-id N | --id N] [--branch B]`; omitted, the target is the merge request of the active branch. A branch has at most one MR, ever. Both flags at once -> exit 2. Status is the derived state the web UI shows. See `merge-request-workflow.md`. - `merge-request list [--project A] [--state STATE]` -- newest first; `--state` filters client-side (unknown -> exit 2); an empty list on a feature-less project says so (`feature_enabled: false`) @@ -358,9 +358,9 @@ Requires the project to be added with its **master ('owner') Storage API token** ## Sync (GitOps) - `sync init --project ALIAS [--directory DIR] [--git-branching] [--adopt-existing]` -- initialize sync working directory; `--adopt-existing` adopts a `.keboola/manifest.json` already written by the kbc Go CLI without overwriting (idempotent; validates `project_id` against the alias token) -- `sync pull --project ALIAS [--all-projects] [--force] [--theirs] [--dry-run] [--with-samples] [--no-storage] [--no-jobs] [--job-limit N] [--branch ID]` -- download configs to local files. **Auto-inits:** if the target directory has no `.keboola/manifest.json`, pull runs `init` first, so a separate `sync init` is not needed for a first checkout of a project. For large projects (>100 configs), automatically fetches jobs per-config when the grouped API limit is insufficient. `--force` is conflict-aware (since 0.53.0): a locally-modified config whose remote is unchanged is **preserved** (pending delta stays pushable, never silently re-stamped); a true merge conflict (local AND remote both changed since last pull) **aborts** the pull (exit 1, `SYNC_CONFLICT`; `--json` lists `details.conflicts`); local-untouched + remote-changed takes remote. `--theirs` (since v0.72.0) is the supported "discard local, take production" reconcile path: overwrites locally-modified configs/rows, restores deleted/missing files, resolves conflicts by taking remote (no abort, no manifest surgery). Since v0.72.0 plain pull also re-materializes a tracked config whose local dir was deleted (manifest<->disk invariant), so delete-dir-then-pull refetches. Config-level `isDisabled` round-trips (since v0.72.0) as sparse `is_disabled: true` in `_config.yml` -- absent key = enabled. `--branch` (0.47.0+) per-invocation dev-branch override, beats every other branch source. Ignored components (since 0.91.0): `keboola.sandboxes` + `keboola.mcp-server-tool` are always excluded, unioned with the manifest's `ignoredComponents` list; a component newly ignored has its manifest entry dropped and local directory removed, reported with pull action `"ignored"` (distinct from `"removed"` = genuinely deleted on remote). Config-folder round-trip *(since vNEXT)*: pull captures each config's UI folder (`KBC.configuration.folderName`, from the branch-only `search/component-configurations` endpoint) into the manifest, and reports `folder_lookup_failed` when that lookup fails, keeping the previously captured folder. +- `sync pull --project ALIAS [--all-projects] [--force] [--theirs] [--dry-run] [--with-samples] [--no-storage] [--no-jobs] [--job-limit N] [--branch ID]` -- download configs to local files. **Auto-inits:** if the target directory has no `.keboola/manifest.json`, pull runs `init` first, so a separate `sync init` is not needed for a first checkout of a project. For large projects (>100 configs), automatically fetches jobs per-config when the grouped API limit is insufficient. `--force` is conflict-aware (since 0.53.0): a locally-modified config whose remote is unchanged is **preserved** (pending delta stays pushable, never silently re-stamped); a true merge conflict (local AND remote both changed since last pull) **aborts** the pull (exit 1, `SYNC_CONFLICT`; `--json` lists `details.conflicts`); local-untouched + remote-changed takes remote. `--theirs` (since v0.72.0) is the supported "discard local, take production" reconcile path: overwrites locally-modified configs/rows, restores deleted/missing files, resolves conflicts by taking remote (no abort, no manifest surgery). Since v0.72.0 plain pull also re-materializes a tracked config whose local dir was deleted (manifest<->disk invariant), so delete-dir-then-pull refetches. Config-level `isDisabled` round-trips (since v0.72.0) as sparse `is_disabled: true` in `_config.yml` -- absent key = enabled. `--branch` (0.47.0+) per-invocation dev-branch override, beats every other branch source. Ignored components (since 0.91.0): `keboola.sandboxes` + `keboola.mcp-server-tool` are always excluded, unioned with the manifest's `ignoredComponents` list; a component newly ignored has its manifest entry dropped and local directory removed, reported with pull action `"ignored"` (distinct from `"removed"` = genuinely deleted on remote). Config-folder round-trip *(since 0.94.0)*: pull captures each config's UI folder (`KBC.configuration.folderName`, from the branch-only `search/component-configurations` endpoint) into the manifest, and reports `folder_lookup_failed` when that lookup fails, keeping the previously captured folder. - `sync push --project ALIAS [--all-projects] [--dry-run] [--force] [--allow-plaintext-on-encrypt-failure] [--branch ID] [--no-name-drift-warnings]` -- push local changes (auto-encrypts secrets, fails if encryption fails). Fresh-CREATE writeback updates placeholder manifest entries in place (since 0.47.0) and propagates any `KBC.configuration.*` metadata via `set_config_metadata`. Fresh-CREATE variable binding (since 0.47.2): when a `keboola.variables` config + its values row are created alongside a transformation in the same push, the transformation's `variables_id` / `variables_values_id` placeholders are rebound to the assigned ULIDs and the row's `values` are hoisted even without a `_keboola` block, so `job run` succeeds with no post-push `config variables-set` step (unresolvable/ambiguous links surface a `variable_link` entry in `errors[]`, never a broken link). Never-fetched guard (since v0.72.0): a manifest entry with an empty `pull_hash` and no local files (pre-0.72 name-collision phantom) is **never** planned as a remote DELETE -- diff/push exclude it and report it under `never_fetched` with a warning (run `sync pull` to materialize); local deletion of a properly-pulled config still deletes on push. Adopted-by-id writeback (since v0.72.0): pushing an untracked file whose `_keboola.config_id` resolves on the branch also writes the manifest entry, so follow-up diffs are stable. `--branch` (0.47.0+) per-invocation override; when no `/` subtree exists on disk (since 0.47.2) the local default tree (`main/`) is promoted to the target branch (API writes still target the branch id); `--no-name-drift-warnings` (0.47.0+) drops the cosmetic warnings array. Branch-scoped since v0.89.0 (issue #649): push consumes the diff's changeset, so configs tracked on another branch's tree are never planned as creates -- they ride along on the result envelope under `orphaned` instead (see `sync diff`). **Since 0.91.0 (#686)** the manifest baseline `pull_config_hash` is stamped from the API response (or a read-back), not from the files on disk, so a pushed multi-statement SQL transformation -- or anything disabled in the UI whose local YAML lacks `is_disabled` -- no longer shows permanent phantom `REMOTE MODIFIED` drift; if the config cannot be read back after the write the baseline is left UNTOUCHED and a `warnings[]` entry says to run `sync pull` (never a disk-derived fallback). One legacy change is refused per-change with `SYNC_LEGACY_BOUNDARY`: a tree pulled before statement-boundary markers existed whose only difference from the remote is the lost boundaries (pushing it would collapse separate SQL statements into one) -- run `sync pull` for that project first. Ignored components (since 0.91.0) are filtered out on both sides of the diff push builds on, so a stale local directory for an ignored component (e.g. `keboola.mcp-server-tool`) is never classified as `DELETED` and can never be pushed as a remote deletion. -- `sync clone --source DIR --target ALIAS --target-dir DIR [--bucket-map FILE] [--variable-values FILE] [--instance-rename FILE] [--dry-run] [--branch ID]` -- clone a reference synced project into a **fresh** target project and parameterize it. Copies the reference tree at `--source` into `--target-dir`, applies declarative overrides from JSON/YAML files (`--bucket-map` `{old_bucket_id: new_bucket_id}` rewrites storage input/output table refs; `--variable-values` `{var_name: value}` overrides `keboola.variables` rows; `--instance-rename` `{old_path_prefix: new_path_prefix}` renames config dirs + manifest paths), re-points the manifest at the target project, and pushes. Because the reference's config ids do not exist in the fresh target, every config is CREATEd fresh and **keboola.flow task `configId`s + transformation variable links are remapped reference->ULID** by push Phase C/D (the push result carries `flow_task_remaps`). **Idempotent**: re-running with an existing `--target-dir` skips copy/overrides and just pushes, reporting `no_changes` / `created: 0`. Fails fast (`CONFIG_ERROR`) if the target already contains the reference's configs -- clone requires a fresh/empty target. `SyncService.clone_project(...)` returns a typed `CloneResult` for in-process SDK callers. Override files must be flat `{id: scalar}` mappings *(since v0.89.0)* -- a nested mapping, list, or null value is rejected with `CONFIG_ERROR` (exit 5) naming the key and its actual type. `--branch` is optional on a fresh clone *(since v0.93.1)*. It defaults to the target's production branch, resolved from the API the same way `sync init` does. Pass `--branch ` only to target a dev branch. The config folder (`KBC.configuration.folderName`) is recreated in the target *(since vNEXT)* -- clone re-points its production configs onto the branch push resolves, so the create-path writeback carries the folder for a plain, `--branch`, and git-branching production clone. **Data-app runtime type (since vNEXT)**: a `keboola.data-apps` config's type (`python-js` / `streamlit`) lives only on the Data Science `/apps` record, so `sync pull` records it in `_keboola.data_app_type` and clone sends it through `create_app`. Re-pull the source before cloning a tree pulled by an older version, or the app deploys under the platform default. +- `sync clone --source DIR --target ALIAS --target-dir DIR [--bucket-map FILE] [--variable-values FILE] [--instance-rename FILE] [--dry-run] [--branch ID]` -- clone a reference synced project into a **fresh** target project and parameterize it. Copies the reference tree at `--source` into `--target-dir`, applies declarative overrides from JSON/YAML files (`--bucket-map` `{old_bucket_id: new_bucket_id}` rewrites storage input/output table refs; `--variable-values` `{var_name: value}` overrides `keboola.variables` rows; `--instance-rename` `{old_path_prefix: new_path_prefix}` renames config dirs + manifest paths), re-points the manifest at the target project, and pushes. Because the reference's config ids do not exist in the fresh target, every config is CREATEd fresh and **keboola.flow task `configId`s + transformation variable links are remapped reference->ULID** by push Phase C/D (the push result carries `flow_task_remaps`). **Idempotent**: re-running with an existing `--target-dir` skips copy/overrides and just pushes, reporting `no_changes` / `created: 0`. Fails fast (`CONFIG_ERROR`) if the target already contains the reference's configs -- clone requires a fresh/empty target. `SyncService.clone_project(...)` returns a typed `CloneResult` for in-process SDK callers. Override files must be flat `{id: scalar}` mappings *(since v0.89.0)* -- a nested mapping, list, or null value is rejected with `CONFIG_ERROR` (exit 5) naming the key and its actual type. `--branch` is optional on a fresh clone *(since v0.93.1)*. It defaults to the target's production branch, resolved from the API the same way `sync init` does. Pass `--branch ` only to target a dev branch. The config folder (`KBC.configuration.folderName`) is recreated in the target *(since 0.94.0)* -- clone re-points its production configs onto the branch push resolves, so the create-path writeback carries the folder for a plain, `--branch`, and git-branching production clone. **Data-app runtime type (since 0.94.0)**: a `keboola.data-apps` config's type (`python-js` / `streamlit`) lives only on the Data Science `/apps` record, so `sync pull` records it in `_keboola.data_app_type` and clone sends it through `create_app`. Re-pull the source before cloning a tree pulled by an older version, or the app deploys under the platform default. - `sync diff --project ALIAS [--all-projects] [--branch ID]` -- 3-way diff (local vs base vs remote), detects conflicts. `--branch` (0.47.0+) per-invocation dev-branch override. Branch-scoped since v0.89.0 (issue #649): the local side is read from exactly ONE tree (the target branch's subtree, or `main/` when the target has none). Manifest entries belonging to another branch's tree -- what `sync pull --branch ` leaves behind when it re-targets the manifest -- are excluded from the changeset and reported under `orphaned` (`summary.orphaned` + details with `component_id`, `config_id`, `path`, `branch_id`, `branch_path`, `exists_on_target`, `reason`, `hint`); human mode previews the first 10. An orphaned FILE whose `_keboola.config_id` still resolves on the target is adopted (diffed as `unchanged`/`modified`), never re-created; same-tree id claims keep the #482/#497 fork-by-copy CREATE. Fix a non-zero `summary.orphaned` with `sync pull`. **Since 0.91.0 (#686)** a manifest entry without `metadata.config_hash_version` (written by a pre-0.91.0 kbagent) is compared leniently: a stored hash equal to the pre-0.91.0 hash of the SAME remote config counts as in sync, so the phantom `codes changed` entries disappear immediately; every other field is still pinned by that hash, so real remote drift is unaffected. One `sync pull` per project stamps the version and ends the leniency. Ignored components (since 0.91.0) -- `keboola.sandboxes`, `keboola.mcp-server-tool`, and anything listed in the manifest's `ignoredComponents` -- are excluded from BOTH sides of the comparison, so a stale local directory for one of them never shows up as `DELETED`. - `sync status [--directory DIR]` -- show locally modified/added/deleted configs. Also surfaces `plaintext_secret_warnings` (since 0.55.0): in-sync configs/rows whose `#`-secrets are still plaintext on the remote (a leftover from pre-0.54.0 writes; #378). Pending (un-pushed) edits are not flagged. Fix = re-push on >=0.54.0 + rotate (version history keeps the plaintext). - `sync branch-link --project ALIAS [--branch-id ID] [--branch-name NAME]` -- link git branch to Keboola dev branch diff --git a/plugins/kbagent/skills/kbagent/references/gotchas.md b/plugins/kbagent/skills/kbagent/references/gotchas.md index 527d1b367..eddaf3d93 100644 --- a/plugins/kbagent/skills/kbagent/references/gotchas.md +++ b/plugins/kbagent/skills/kbagent/references/gotchas.md @@ -179,7 +179,7 @@ Versioning convention: silently skipped, unlike the original 0.80.0 `--register-projects` batch path. Collision handling matches `--register-projects` above: never overwrites an existing `config.json` entry. -- **A session works with almost every client** *(since vNEXT)*. Only three +- **A session works with almost every client** *(since 0.94.0)*. Only three features still require a static Storage token and fail FAST with `AUTH_NOT_SUPPORTED_ON_STACK` on a session project, naming the static-token fallback, rather than silently sending the `kbc-session://` sentinel as if it @@ -751,17 +751,17 @@ fall back to the normal priority chain. ## `sync pull` / `sync clone` now keep the config folder (`KBC.configuration.folderName`) -*(since vNEXT)* +*(since 0.94.0)* A config's UI folder is config metadata under `KBC.configuration.folderName`. It comes from a branch-only `search/component-configurations` call, not from the -`list_components_with_configs` body that pull reads for config data. Before vNEXT +`list_components_with_configs` body that pull reads for config data. Before 0.94.0 `sync pull` never fetched it, so `sync pull` and `sync clone` silently dropped the folder and every config landed in the tree root. Nothing warned about it. On a -pre-vNEXT kbagent a golden-reference `sync clone` still produces a folder-less +pre-0.94.0 kbagent a golden-reference `sync clone` still produces a folder-less clone -- check the version, or verify the folders came across after a clone. -Since vNEXT pull fetches the folder for each config and stores +Since 0.94.0 pull fetches the folder for each config and stores `KBC.configuration.folderName` in the manifest entry's `metadata`. `sync clone` re-points its production configs onto the branch push resolves for the target, so the create-path writeback matches the placeholder and the push create path @@ -814,7 +814,7 @@ without losing data. ## `sync` carries a data app's runtime type: pull records it, push and clone send it -A `keboola.data-apps` config's runtime type (`python-js` / `streamlit` / ...) lives only on the Data Science `/apps` record, never in the Storage config body. So `sync pull` used to drop it, and `sync push` / `sync clone` recreated the config through the Storage API alone. A cloned `python-js` app then deployed under the platform default, `streamlit` (since vNEXT). +A `keboola.data-apps` config's runtime type (`python-js` / `streamlit` / ...) lives only on the Data Science `/apps` record, never in the Storage config body. So `sync pull` used to drop it, and `sync push` / `sync clone` recreated the config through the Storage API alone. A cloned `python-js` app then deployed under the platform default, `streamlit` (since 0.94.0). `sync pull` now reads the type from the DS `/apps` list and records it in the config's `_keboola` block as `data_app_type`. The config hash already ignores that key, so it adds no `sync diff` noise. `sync push` and `sync clone` route a `keboola.data-apps` CREATE through the Data Science `create_app` when the local config carries a `data_app_type`. That call sends the type and writes the new app's `parameters.id`. A config with no recorded type still uses the plain `create_config` path. @@ -5086,7 +5086,7 @@ It carries the command name, the outcome, and the duration -- never argument val ## `merge-request` group: arming auto-merge IS a production merge -*(since vNEXT, DMD-1900)* +*(since 0.94.0, DMD-1900)* `kbagent merge-request` (alias `mr`) merges a dev branch into production with review (non-SOX "Branches 2.0", project feature `branches-merge-requests`). Full playbook: diff --git a/plugins/kbagent/skills/kbagent/references/merge-request-workflow.md b/plugins/kbagent/skills/kbagent/references/merge-request-workflow.md index 589f84045..ba2c39d32 100644 --- a/plugins/kbagent/skills/kbagent/references/merge-request-workflow.md +++ b/plugins/kbagent/skills/kbagent/references/merge-request-workflow.md @@ -1,6 +1,6 @@ # Merge Request Workflow -- merging a dev branch into production with review -*(since vNEXT, DMD-1900)* +*(since 0.94.0, DMD-1900)* `kbagent merge-request` (alias `mr`) is the non-SOX "Branches 2.0" lifecycle: open a merge request from a development branch, optionally get it reviewed, inspect and resolve conflicts, diff --git a/pyproject.toml b/pyproject.toml index f080fd6f1..e156a2434 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "keboola-cli" -version = "0.93.2" +version = "0.94.0" description = "AI-friendly CLI for managing Keboola projects" readme = "README.md" requires-python = ">=3.12" diff --git a/src/keboola_agent_cli/changelog.py b/src/keboola_agent_cli/changelog.py index 80881c953..7c471a60d 100644 --- a/src/keboola_agent_cli/changelog.py +++ b/src/keboola_agent_cli/changelog.py @@ -24,6 +24,36 @@ # Ordered newest-first. Each value is a list of brief one-line descriptions. CHANGELOG: dict[str, list[str]] = { + "0.94.0": [ + "New (#759): a browser-login session (`auth login`) now works with nearly every command, " + "not just the Storage and Manage paths (CLI-13). It reaches the Scheduler (`flow schedule` / " + "`flow schedule-remove`), Data Streams (`stream`), Data Science (`data-app`), the full " + "`semantic-layer` group, the AI Service (`docs query`, `config new` / `examples`, " + "`component detail`, `flow new` / `update` / `validate`), and Storage bucket `sharing`. Only " + "three features still need a static Storage token and fail fast with " + "`AUTH_NOT_SUPPORTED_ON_STACK`: `kai`, `semantic-layer token --encrypt`, and the importable " + "SDK (`keboola_agent_cli.Client`). `auth login` and `auth register-projects` print the list " + "and ship it in `--json` as `session_unsupported_features`.", + "New (#736): a `merge-request` command group (hidden alias `mr`) drives the Branches 2.0 " + "merge lifecycle (DMD-1900). It covers create, request-review, approve, auto-merge, merge, " + "and conflict resolution (`diff` / `resolve`), on a project with the `branches-merge-requests` " + "feature. Each command targets the merge request of the active branch by default, or " + "`--merge-request-id N` / `--branch B` to pick one. Commands that move an MR toward production " + "(`merge`, `request-review`, `approve`, `resolve`, `auto-merge`) are destructive for " + "`--deny-destructive`. `create` / `update` / `request-changes` are writes. `branch merge` is " + "now deprecated -- it only built a UI URL and never merged through the API.", + "Fix (#752): `sync pull` and `sync clone` no longer strip a data app's runtime type when the " + "Data Science list omits it (CLI-8). The type (`python-js` / `streamlit` / ...) lives only on " + "the Data Science API, so a cloned or re-pulled app keeps the type it deploys with.", + "Fix (#753): `sync pull` and `sync clone` now keep each config's UI folder " + "(`KBC.configuration.folderName`) (CLI-9). Before, both silently dropped it and every config " + "landed in the tree root, with nothing warning about it.", + "Note (#764, #729, #730, #733, #734, #750, #751): housekeeping with no user-facing change. " + "#764 shares one session-aware default Data Science client factory between the sync and " + "data-app services. It corrects an import that the #752 and #759 combination broke on `main` " + "before any release. The rest are web UI and backend dependency bumps (fastify, fast-uri, " + "vitest, browserslist, postcss-selector-parser).", + ], "0.93.2": [ "New (#757): each usage event now also carries the kbagent version and an agent-vs-human " "marker for the telemetry team (CLI-12). `params.cliContext` holds the User-Agent " diff --git a/src/keboola_agent_cli/commands/branch.py b/src/keboola_agent_cli/commands/branch.py index 7a000944c..866d2c718 100644 --- a/src/keboola_agent_cli/commands/branch.py +++ b/src/keboola_agent_cli/commands/branch.py @@ -232,7 +232,7 @@ def branch_merge( """[DEPRECATED] Get the KBC UI merge URL for a development branch. Does NOT perform the merge via API -- it builds the URL to the Keboola - UI and then resets the active branch to main. Deprecated since vNEXT: + UI and then resets the active branch to main. Deprecated since 0.94.0: on a project with merge requests enabled ('branches-merge-requests'), use `kbagent merge-request create` and `kbagent merge-request merge`, which merge from the CLI and delete the source branch. This command diff --git a/src/keboola_agent_cli/commands/context.py b/src/keboola_agent_cli/commands/context.py index 2a526f679..8cafa0871 100644 --- a/src/keboola_agent_cli/commands/context.py +++ b/src/keboola_agent_cli/commands/context.py @@ -1206,7 +1206,7 @@ Delete branch (async). Auto-resets to main if it was active. kbagent branch merge --project ALIAS [--branch ID] - DEPRECATED (since vNEXT): builds a KBC UI merge URL (does NOT merge via API) and + DEPRECATED (since 0.94.0): builds a KBC UI merge URL (does NOT merge via API) and resets the active branch. On a project with merge requests enabled use `merge-request create` + `merge-request merge` below. diff --git a/uv.lock b/uv.lock index d3bec9308..b62885090 100644 --- a/uv.lock +++ b/uv.lock @@ -590,7 +590,7 @@ wheels = [ [[package]] name = "keboola-cli" -version = "0.93.2" +version = "0.94.0" source = { editable = "." } dependencies = [ { name = "croniter" },