qodo-cli 0.4.0__tar.gz → 0.9.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.
- qodo_cli-0.9.0/.pr_agent.toml +26 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/CHANGELOG.md +196 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/PKG-INFO +1 -1
- qodo_cli-0.9.0/best_practices.md +59 -0
- qodo_cli-0.9.0/docs/manual-verification.md +115 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/docs/qodo-skills-sources.md +53 -8
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/pyproject.toml +1 -1
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/qodo/cli/__init__.py +2 -0
- qodo_cli-0.9.0/qodo/cli/_commands/config.py +395 -0
- qodo_cli-0.9.0/qodo/cli/_commands/doctor.py +262 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/qodo/cli/_commands/learn.py +4 -2
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/qodo/cli/_commands/overview.py +14 -6
- qodo_cli-0.9.0/qodo/cli/_commands/review.py +308 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/qodo/cli/_commands/rules.py +32 -7
- qodo_cli-0.9.0/qodo/cli/_providers.py +947 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/qodo/cli/_qodo_api.py +92 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/qodo/explain/catalog.py +88 -14
- qodo_cli-0.9.0/tests/fixtures/rules_search_response.json +28 -0
- qodo_cli-0.9.0/tests/test_cli_introspection.py +197 -0
- qodo_cli-0.9.0/tests/test_config.py +244 -0
- qodo_cli-0.9.0/tests/test_contracts.py +157 -0
- qodo_cli-0.9.0/tests/test_review.py +1012 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/tests/test_rules.py +136 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/uv.lock +1 -1
- qodo_cli-0.4.0/qodo/cli/_commands/doctor.py +0 -124
- qodo_cli-0.4.0/qodo/cli/_commands/review.py +0 -139
- qodo_cli-0.4.0/qodo/cli/_providers.py +0 -333
- qodo_cli-0.4.0/tests/test_cli_introspection.py +0 -106
- qodo_cli-0.4.0/tests/test_review.py +0 -372
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/agent-config/SKILL.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/agent-config/data/backend-fingerprints.yaml +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/agent-config/scripts/show.sh +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/ask-colleague/SKILL.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/ask-colleague/prompts/explore.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/ask-colleague/prompts/review.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/ask-colleague/prompts/write.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/ask-colleague/scripts/ask-colleague.sh +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/assign-to-workforce/SKILL.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/cicd/SKILL.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/cicd/scripts/_resolve-nick.sh +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/cicd/scripts/portability-lint.sh +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/cicd/scripts/pr-reply.sh +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/cicd/scripts/pr-status.sh +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/cicd/scripts/workflow.sh +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/communicate/SKILL.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/communicate/scripts/fetch-issues.sh +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/communicate/scripts/mesh-message.sh +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/communicate/scripts/post-comment.sh +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/communicate/scripts/post-issue.sh +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/communicate/scripts/templates/skill-new-brief.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/communicate/scripts/templates/skill-update-brief.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/doc-test-alignment/SKILL.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/doc-test-alignment/scripts/check.sh +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/pypi-maintainer/SKILL.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/pypi-maintainer/scripts/switch-source.sh +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/run-tests/SKILL.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/run-tests/scripts/test.sh +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/sonarclaude/SKILL.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/sonarclaude/scripts/sonar.sh +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/spec-to-plan/SKILL.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/spec-to-plan/scripts/spec-to-plan.sh +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/think/SKILL.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/think/scripts/think.sh +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/version-bump/SKILL.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills/version-bump/scripts/bump.py +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.claude/skills.local.yaml.example +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.devague/current +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.devague/frames/qodo-cli-now-does-qodo-s-two-core-jobs-natively-fr.json +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.flake8 +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.github/workflows/publish.yml +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.github/workflows/tests.yml +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.gitignore +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/.markdownlint-cli2.yaml +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/AGENTS.colleague.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/CLAUDE.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/LICENSE +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/README.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/culture.yaml +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/docs/skill-sources.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/docs/specs/2026-06-16-qodo-cli-now-does-qodo-s-two-core-jobs-natively-fr.md +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/qodo/__init__.py +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/qodo/__main__.py +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/qodo/cli/_commands/__init__.py +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/qodo/cli/_commands/cli.py +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/qodo/cli/_commands/explain.py +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/qodo/cli/_commands/whoami.py +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/qodo/cli/_errors.py +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/qodo/cli/_output.py +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/qodo/explain/__init__.py +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/sonar-project.properties +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/tests/__init__.py +0 -0
- {qodo_cli-0.4.0 → qodo_cli-0.9.0}/tests/test_cli.py +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Qodo Merge / PR-Agent configuration for qodo-cli.
|
|
2
|
+
# Docs: https://docs.qodo.ai/qodo-documentation/qodo-merge/configuration/configuration-file
|
|
3
|
+
#
|
|
4
|
+
# Kept minimal on purpose (per Qodo's guidance: only override what you need).
|
|
5
|
+
# The repo's coding conventions live in best_practices.md at the root, which the
|
|
6
|
+
# reviewer auto-references; this file just reinforces a few intentional patterns
|
|
7
|
+
# that an earlier review flagged as false positives.
|
|
8
|
+
|
|
9
|
+
[pr_reviewer]
|
|
10
|
+
extra_instructions = """
|
|
11
|
+
qodo-cli is an unofficial, community CLI to manage Qodo, built as a
|
|
12
|
+
zero-runtime-dependency, stdlib-only Python package. Intentional patterns (do
|
|
13
|
+
not flag these as issues):
|
|
14
|
+
- Command handlers return a bare 0/1/None for the exit code. The EXIT_* constants
|
|
15
|
+
in qodo/cli/_errors.py are for CliError codes (the failure path), not for
|
|
16
|
+
handler return values. `return 0` in a handler is intentional and consistent
|
|
17
|
+
across every command.
|
|
18
|
+
- Nested argparse subparsers inherit the structured-error parser class via
|
|
19
|
+
`add_subparsers(parser_class=type(p))` (see qodo/cli/_commands/cli.py). Passing
|
|
20
|
+
`type(p)` is the established idiom and is equivalent to naming
|
|
21
|
+
`_CliArgumentParser` directly — it is not a missing parser_class.
|
|
22
|
+
- `qodo review resolve --reply` drives the user's own `gh` with their own auth;
|
|
23
|
+
the reply text belongs to the caller, so the tool must not auto-append an agent
|
|
24
|
+
signature.
|
|
25
|
+
See best_practices.md at the repo root for the full conventions.
|
|
26
|
+
"""
|
|
@@ -5,6 +5,202 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
Format follows [Keep a Changelog](https://keepachangelog.com/). This project
|
|
6
6
|
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.9.0] - 2026-06-17
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **GitLab provider** for `qodo review` (via `glab`): find the open MR, list the
|
|
13
|
+
Qodo bot's notes across MR discussions (with the same parsed triage fields as
|
|
14
|
+
GitHub), reply, and resolve. GitLab's model is MR *discussions* (resolution is
|
|
15
|
+
at the discussion level — there is no `+1` marker, so resolving the discussion
|
|
16
|
+
*is* the acknowledgement). Implemented but **not live-tested** against a real
|
|
17
|
+
GitLab (we have none) — covered by mocked tests mirroring the GitHub ones, with
|
|
18
|
+
the `glab` REST shapes pinned in the citation ledger. (#10)
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- Generalized the provider gate: `require_provider` (supersedes the GitHub-only
|
|
23
|
+
`require_github` on the `review` surface) now allows **GitHub + GitLab**;
|
|
24
|
+
Azure/Bitbucket/Gerrit still error with a clear "not wired yet". `review`
|
|
25
|
+
dispatches find/fetch/resolve through a provider-aware seam
|
|
26
|
+
(`find_pr` / `fetch_comments` / `resolve` / `prefetch_threads`). (#10)
|
|
27
|
+
- Internal refactor to clear SonarCloud maintainability findings on the stack —
|
|
28
|
+
no behavior change: split the `config` render/validate/init handlers and
|
|
29
|
+
`review._select_targets` into focused helpers (cognitive complexity ≤ 15),
|
|
30
|
+
de-nested the validate mark ternary, extracted `_parse_thread_node`, and named
|
|
31
|
+
the shared resolve-action labels (`_ACT_RESOLVE_THREAD` /
|
|
32
|
+
`_ACT_LOOKUP_DISCUSSION`) to drop duplicated literals. (PR #12 review)
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
- **Self-hosted GitLab on a custom domain is now detected.** `resolve_provider`
|
|
37
|
+
gained a `glab_knows_host()` upgrade path mirroring the GHE `gh_knows_host()`
|
|
38
|
+
one: an `origin` whose host isn't `github.com`/`gitlab.com` is no longer
|
|
39
|
+
hard-failed as `unknown` when `glab auth status --hostname <host>` recognises
|
|
40
|
+
it — it resolves to `gitlab`. `gh` is consulted first (a host both CLIs know
|
|
41
|
+
resolves to `github`). Mocked-only, like the GHE path. (#10, PR #16 review)
|
|
42
|
+
- **Live smokes are now explicitly opt-in and skip (don't fail) when their
|
|
43
|
+
prerequisites are missing.** Both `test_contracts.py` smokes require a
|
|
44
|
+
deliberate `QODO_LIVE_SMOKE=1` switch, so a shell that merely exports
|
|
45
|
+
`QODO_API_KEY` for real `qodo rules` use no longer fires a network call during
|
|
46
|
+
a normal `pytest` run. The GHE smoke additionally gates on `gh` being present
|
|
47
|
+
and authenticated to the remote's host (`gh_knows_host`), so a `gh`-less or
|
|
48
|
+
unauthenticated box *skips* rather than failing on `resolve_provider → unknown`.
|
|
49
|
+
(#8, PR #15 review)
|
|
50
|
+
- **`qodo config init` is now symlink-safe.** It treats any existing path
|
|
51
|
+
(regular file, directory, FIFO, or a possibly-broken symlink) as occupied, and
|
|
52
|
+
under `--force` it refuses — with a structured `CliError` — to write *through* a
|
|
53
|
+
symlink (which could escape the repo root) or over a non-regular path (which
|
|
54
|
+
would crash). Targets are pre-scanned so a refusal aborts before any write,
|
|
55
|
+
never leaving a half-scaffold. (#7, PR #14 review)
|
|
56
|
+
- **`qodo config show`/`validate` degrade gracefully on an unreadable
|
|
57
|
+
`best_practices.md`.** `_inspect()` now guards the `best_practices.md` read
|
|
58
|
+
(`OSError`/`UnicodeDecodeError`) the same way the `.pr_agent.toml` read was
|
|
59
|
+
already guarded, so a permission/encoding problem reports a controlled
|
|
60
|
+
`readable: false` status instead of crashing the read-only verb with a generic
|
|
61
|
+
exit 1. (#7, PR #14 review)
|
|
62
|
+
- **Scope auto-detection is now truly non-raising.** `_origin_url()` wraps its
|
|
63
|
+
`subprocess.run(git …)` in `try/except OSError`, and `detect_scopes()` guards
|
|
64
|
+
`Path.cwd()` — so a git that vanishes mid-run or a deleted working directory
|
|
65
|
+
yields *no scope* (per the documented contract) instead of turning an optional
|
|
66
|
+
enhancement into a `qodo rules get` failure. (#9, PR #13 review)
|
|
67
|
+
- **`repo_slug()` no longer leaves `.git` in the slug for a trailing-slash
|
|
68
|
+
remote.** A URL like `https://host/org/repo.git/` now correctly yields
|
|
69
|
+
`org/repo` (the path is stripped of surrounding slashes *before* the `.git`
|
|
70
|
+
suffix), not `org/repo.git`. (#9, PR #13 review)
|
|
71
|
+
- **`review resolve`'s reaction-only fallback no longer flips the exit code.**
|
|
72
|
+
When no GitHub review thread maps to a comment, the `+1` reaction stands as the
|
|
73
|
+
acknowledgement marker; that documented fallback is now reported `ok=True` with
|
|
74
|
+
`fallback: true` (instead of `ok=False`), so `review resolve --all` exits 0 when
|
|
75
|
+
every actionable step succeeded. A genuine thread-resolve error still reports
|
|
76
|
+
`ok=False`. (GitLab is unchanged — it has no `+1` marker, so a missing discussion
|
|
77
|
+
is a real failure there.) (#3–#6, PR #12 review)
|
|
78
|
+
- **`review resolve --severity` rejects an invalid value instead of silently
|
|
79
|
+
resolving nothing.** A typo like `--severity HGIH` now fails at parse time with a
|
|
80
|
+
structured `error:`/`hint:` (exit 1) rather than matching no comments and exiting
|
|
81
|
+
0. Stays case-insensitive (`high` → `HIGH`). (#3–#6, PR #12 review)
|
|
82
|
+
|
|
83
|
+
## [0.8.1] - 2026-06-17
|
|
84
|
+
|
|
85
|
+
### Added
|
|
86
|
+
|
|
87
|
+
- `tests/test_contracts.py` + `tests/fixtures/rules_search_response.json` — an
|
|
88
|
+
**offline contract test** that pins the Qodo `/rules/search` response shape
|
|
89
|
+
(relevance order, the `{id, name, content, severity}` fields, severities within
|
|
90
|
+
the known set, unknown extra fields passing through), so the parser is verified
|
|
91
|
+
without a Qodo subscription in CI. (#8)
|
|
92
|
+
- **Opt-in live smokes** (skipped by default): `test_live_rules_search_smoke`
|
|
93
|
+
(runs when `QODO_API_KEY` is set) and `test_live_ghe_resolves_to_github` (runs
|
|
94
|
+
when `QODO_CLI_GHE_REMOTE` points at a real GitHub Enterprise origin). (#8)
|
|
95
|
+
- `docs/manual-verification.md` — a manual checklist for the paths that need a
|
|
96
|
+
real system to exercise (live `qodo rules`, GitHub Enterprise resolution, the
|
|
97
|
+
non-GitHub provider gate), cross-referenced from the citation ledger. (#8)
|
|
98
|
+
|
|
99
|
+
### Changed
|
|
100
|
+
|
|
101
|
+
### Fixed
|
|
102
|
+
|
|
103
|
+
## [0.8.0] - 2026-06-17
|
|
104
|
+
|
|
105
|
+
### Added
|
|
106
|
+
|
|
107
|
+
- `qodo config` — a new noun group to manage the **repo-level** Qodo reviewer
|
|
108
|
+
config (`.pr_agent.toml` + `best_practices.md`), distinct from the *client*
|
|
109
|
+
`~/.qodo/config.json` that `qodo rules` reads: (#7)
|
|
110
|
+
- `config show` — report presence, the parsed `.pr_agent.toml` sections, and
|
|
111
|
+
`best_practices.md` status (read-only).
|
|
112
|
+
- `config validate` — validate the config (valid TOML, a config present) and
|
|
113
|
+
exit 1 when invalid; warns (without failing) on a missing `[pr_reviewer]`
|
|
114
|
+
section or an empty `best_practices.md`. Emits the rubric-shaped
|
|
115
|
+
`{valid, checks: [...]}` in `--json`.
|
|
116
|
+
- `config init [--force]` — scaffold a minimal `.pr_agent.toml` +
|
|
117
|
+
`best_practices.md` when absent; never overwrites without `--force`.
|
|
118
|
+
- `config overview` — describe the noun (rubric-required).
|
|
119
|
+
|
|
120
|
+
### Changed
|
|
121
|
+
|
|
122
|
+
### Fixed
|
|
123
|
+
|
|
124
|
+
## [0.7.0] - 2026-06-17
|
|
125
|
+
|
|
126
|
+
### Added
|
|
127
|
+
|
|
128
|
+
- `qodo rules get` now **auto-detects the rules scope** when `--scope` is
|
|
129
|
+
omitted, mirroring `qodo-get-rules`: the `org/repo` slug from the git `origin`
|
|
130
|
+
(SSH `git@host:org/repo(.git)`, HTTPS, and `ssh://` forms; multi-level
|
|
131
|
+
namespaces such as GitLab subgroups preserved) plus the module name from a
|
|
132
|
+
`modules/<name>/` path. Detection is non-raising — no git / no origin yields no
|
|
133
|
+
scope, and `scopes` is omitted entirely (never sent empty). The detected scope
|
|
134
|
+
is surfaced in `--json` (`scopes`) and the text header. (#9)
|
|
135
|
+
- `qodo rules get --no-scope` forces scope omission (skips auto-detection);
|
|
136
|
+
`--scope` continues to override detection. `--scope` and `--no-scope` are
|
|
137
|
+
mutually exclusive. (#9)
|
|
138
|
+
|
|
139
|
+
### Changed
|
|
140
|
+
|
|
141
|
+
### Fixed
|
|
142
|
+
|
|
143
|
+
## [0.6.0] - 2026-06-17
|
|
144
|
+
|
|
145
|
+
### Added
|
|
146
|
+
|
|
147
|
+
- `qodo review list` now parses each Qodo comment body into structured triage
|
|
148
|
+
fields surfaced in `--json` and the text table: `severity` (from the badge —
|
|
149
|
+
`Action required → HIGH`, `Review recommended → MEDIUM`, other → `LOW`, none →
|
|
150
|
+
`null`), `type` and `categories` (the `<code>` chips), `description` (the
|
|
151
|
+
`<pre>` block, HTML-entity-decoded), and `agent_prompt` (the remediation
|
|
152
|
+
block). Parsing is best-effort — an unrecognised body degrades to title-only.
|
|
153
|
+
(#3)
|
|
154
|
+
- `qodo review list --kind {inline,summary,all}` filters by comment kind so the
|
|
155
|
+
non-actionable summary rollups can be excluded. (#3)
|
|
156
|
+
- `qodo review resolve` now resolves the GitHub review **thread** via the GraphQL
|
|
157
|
+
`resolveReviewThread` mutation by default (mapping the REST comment id to its
|
|
158
|
+
thread node id), with `--no-resolve-thread` to skip and a graceful fallback to
|
|
159
|
+
the `+1` reaction when no thread maps to the comment. (#4)
|
|
160
|
+
- `qodo review resolve --all` / `--severity <S>` and multiple positional ids
|
|
161
|
+
resolve several inline comments in one call. (#5)
|
|
162
|
+
- `qodo review resolve --reply "..." --sign` appends the `culture.yaml` nick
|
|
163
|
+
signature (`- <nick> (Claude)`) to the reply, at most once (duplicate-guarded);
|
|
164
|
+
default stays unsigned. (#6)
|
|
165
|
+
|
|
166
|
+
### Changed
|
|
167
|
+
|
|
168
|
+
- `qodo review resolve` is now **best-effort and per-action**: it reports each of
|
|
169
|
+
reply / acknowledge / resolve-thread per comment, so a posted reply whose
|
|
170
|
+
acknowledgement failed reads as partial success (exit 1) rather than a blanket
|
|
171
|
+
failure. The `resolve_comment()` return type changed from `list[str]` to
|
|
172
|
+
`list[{action, ok, detail}]`, and the `resolve --json` payload now carries a
|
|
173
|
+
`resolved` list with per-action results. (#5)
|
|
174
|
+
|
|
175
|
+
### Fixed
|
|
176
|
+
|
|
177
|
+
## [0.5.0] - 2026-06-17
|
|
178
|
+
|
|
179
|
+
### Added
|
|
180
|
+
|
|
181
|
+
- `.pr_agent.toml` + `best_practices.md` at the repo root — the Qodo Merge
|
|
182
|
+
reviewer config (cite, don't fork). They codify this repo's intentional
|
|
183
|
+
patterns (bare `return 0` handlers, `parser_class=type(p)` subparser nesting,
|
|
184
|
+
the mechanics-only `review resolve --reply`) so Qodo reviews accurately and
|
|
185
|
+
stops raising them as violations.
|
|
186
|
+
- `qodo doctor` now also checks **Qodo setup**, against the current git repo:
|
|
187
|
+
`.pr_agent.toml` present, `best_practices.md` present, and whether a usable
|
|
188
|
+
Qodo API key is resolvable for `qodo rules` — `QODO_API_KEY`, else a non-empty
|
|
189
|
+
`API_KEY` in `~/.qodo/config.json` (a present-but-keyless or malformed file
|
|
190
|
+
fails the check with guidance, and never throws). These are advisory and each
|
|
191
|
+
carries a `remediation` that guides an agent through setup. Runs in any repo
|
|
192
|
+
(not just a source checkout). (Addresses #7.)
|
|
193
|
+
|
|
194
|
+
### Changed
|
|
195
|
+
|
|
196
|
+
- `qodo doctor` `healthy` now depends on **error**-severity checks only;
|
|
197
|
+
`warning`/`info` checks surface guidance without flipping `healthy` or the
|
|
198
|
+
exit code. Fixes the `claude → CLAUDE.md` drift in the `doctor` explain entry
|
|
199
|
+
(this repo's backend is `colleague` → `AGENTS.colleague.md`).
|
|
200
|
+
- `learn` now describes `doctor` as "agent-identity invariants + Qodo setup" in
|
|
201
|
+
both its text and JSON payload, matching `overview` and the explain catalog
|
|
202
|
+
(self-description stays consistent across the introspection surfaces).
|
|
203
|
+
|
|
8
204
|
## [0.4.0] - 2026-06-17
|
|
9
205
|
|
|
10
206
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qodo-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.0
|
|
4
4
|
Summary: Community CLI and agent to manage Qodo — the AI code reviewer and Qodo's other agents (requires a Qodo subscription). Unofficial: not affiliated with, authorized, or endorsed by Qodo; the Qodo name and trademark belong to Qodo Ltd.
|
|
5
5
|
Project-URL: Homepage, https://github.com/agentculture/qodo-cli
|
|
6
6
|
Project-URL: Issues, https://github.com/agentculture/qodo-cli/issues
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Best practices for qodo-cli
|
|
2
|
+
|
|
3
|
+
Repository-specific coding standards for the Qodo reviewer — and for any agent
|
|
4
|
+
working in this repo. `qodo-cli` is an unofficial, community CLI to manage Qodo,
|
|
5
|
+
built as a **zero-runtime-dependency, stdlib-only** Python package.
|
|
6
|
+
|
|
7
|
+
These conventions are pinned by the test suite and the agent-first rubric
|
|
8
|
+
(`teken cli doctor . --strict`); please review against them rather than against
|
|
9
|
+
generic defaults.
|
|
10
|
+
|
|
11
|
+
## Dependencies
|
|
12
|
+
|
|
13
|
+
- Runtime dependencies must stay empty (`dependencies = []` in `pyproject.toml`).
|
|
14
|
+
Use only the Python standard library at runtime, and flag any new third-party
|
|
15
|
+
runtime import. `teken` and the lint/test tools are dev-only.
|
|
16
|
+
|
|
17
|
+
## Exit codes
|
|
18
|
+
|
|
19
|
+
- Command handlers return a bare `0` / `1` / `None` for their exit code (`0` is
|
|
20
|
+
success). The `EXIT_*` constants in `qodo/cli/_errors.py` are for `CliError`
|
|
21
|
+
codes on the failure path, **not** for handler return values. A bare
|
|
22
|
+
`return 0` in a handler is intentional and consistent across every command —
|
|
23
|
+
do not flag it as a magic number.
|
|
24
|
+
|
|
25
|
+
## Errors and output
|
|
26
|
+
|
|
27
|
+
- Every failure raises `CliError(code, message, remediation)`; no Python
|
|
28
|
+
traceback may leak to stderr. Text-mode errors render `error: <msg>` then
|
|
29
|
+
`hint: <remediation>` (the `hint:` prefix is required).
|
|
30
|
+
- Results go to stdout; errors and diagnostics go to stderr. Never mix the two,
|
|
31
|
+
in text or `--json` mode. Every command supports `--json`.
|
|
32
|
+
|
|
33
|
+
## argparse
|
|
34
|
+
|
|
35
|
+
- Build subparsers with the structured-error parser class. Nested subparsers
|
|
36
|
+
inherit it via `add_subparsers(parser_class=type(p))` (see
|
|
37
|
+
`qodo/cli/_commands/cli.py`); passing `type(p)` is the established idiom and is
|
|
38
|
+
equivalent to naming `_CliArgumentParser` directly — it is not a missing
|
|
39
|
+
`parser_class`.
|
|
40
|
+
- Add the standard `--json` flag with `add_json_flag()` from `qodo.cli._output`
|
|
41
|
+
rather than re-declaring the literal.
|
|
42
|
+
|
|
43
|
+
## The CLI is mechanics-only
|
|
44
|
+
|
|
45
|
+
- `qodo review resolve --reply` drives the user's own `gh` with their own auth;
|
|
46
|
+
the reply text belongs to the caller. The tool must not auto-append an agent
|
|
47
|
+
signature — that would mis-attribute human-authored replies. Signing is the
|
|
48
|
+
caller's responsibility (an opt-in flag may be added later).
|
|
49
|
+
|
|
50
|
+
## Cite, don't import
|
|
51
|
+
|
|
52
|
+
- Behavior derived from `qodo-ai/qodo-skills` and the vendored `.claude/skills/`
|
|
53
|
+
kit is cited as the source of truth, not forked or vendored into runtime code.
|
|
54
|
+
Keep `docs/qodo-skills-sources.md` in sync when the upstream contract changes.
|
|
55
|
+
|
|
56
|
+
## Keep the self-description in sync
|
|
57
|
+
|
|
58
|
+
- When adding a command, update `learn`, `overview`, and the explain catalog so
|
|
59
|
+
the rubric and the self-describing text stay consistent.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Manual verification checklist
|
|
2
|
+
|
|
3
|
+
Two `qodo-cli` paths are implemented and unit-tested with mocks, but cannot be
|
|
4
|
+
exercised against the real systems in CI (we have no GitHub Enterprise instance
|
|
5
|
+
and no Qodo subscription in the CI environment). This checklist is how to verify
|
|
6
|
+
them by hand when a real system *is* available, plus the offline contract test
|
|
7
|
+
that pins the response shape in the meantime.
|
|
8
|
+
|
|
9
|
+
See `docs/qodo-skills-sources.md` for the resolved contracts these verify.
|
|
10
|
+
|
|
11
|
+
## 1. Offline contract test (always runs)
|
|
12
|
+
|
|
13
|
+
`tests/test_contracts.py::test_rules_search_parses_recorded_response` asserts the
|
|
14
|
+
`/rules/search` parser against a recorded response fixture
|
|
15
|
+
(`tests/fixtures/rules_search_response.json`) — relevance order preserved, the
|
|
16
|
+
documented `{id, name, content, severity}` fields present, severities within the
|
|
17
|
+
known set, and unknown extra fields (e.g. `score`) passing through untouched.
|
|
18
|
+
|
|
19
|
+
If the Qodo API response shape ever changes, refresh the fixture from a real
|
|
20
|
+
response and update the contract test alongside the parser:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# with a real key, capture a response shape (redact ids/content as needed):
|
|
24
|
+
QODO_API_KEY=… qodo rules get "validate input" --json
|
|
25
|
+
# then update tests/fixtures/rules_search_response.json + the contract test.
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 2. `qodo rules` against the real Qodo API
|
|
29
|
+
|
|
30
|
+
Prerequisite: a Qodo subscription and an API key, either in
|
|
31
|
+
`~/.qodo/config.json` (`"API_KEY"`) or exported as `QODO_API_KEY`.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
qodo doctor # qodo_client_config_present should pass
|
|
35
|
+
qodo rules get "validate all user input at trust boundaries"
|
|
36
|
+
qodo rules get "sql safety" --json | jq '.rules[].severity'
|
|
37
|
+
qodo rules get "anything" --no-scope --json | jq '.scopes' # -> null
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Expected: relevance-ranked rules with `ERROR` / `WARNING` / `RECOMMENDATION`
|
|
41
|
+
severities; `--json` carries `scopes` (the auto-detected `org/repo`, or `null`
|
|
42
|
+
under `--no-scope`); a missing key exits `2` with a `hint:` and never prompts.
|
|
43
|
+
|
|
44
|
+
Opt-in smoke (runs only when explicitly enabled — `QODO_LIVE_SMOKE` gates it so a
|
|
45
|
+
shell that merely exports `QODO_API_KEY` for real `qodo rules` use never fires a
|
|
46
|
+
network call during a normal `pytest` run):
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
QODO_LIVE_SMOKE=1 QODO_API_KEY=… \
|
|
50
|
+
uv run pytest tests/test_contracts.py::test_live_rules_search_smoke -v
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 3. `qodo review` against a real GitHub Enterprise host
|
|
54
|
+
|
|
55
|
+
`resolve_provider()` upgrades an unknown host to `github` when `gh` is
|
|
56
|
+
authenticated to it (`gh auth status --hostname <host>`). This is covered by
|
|
57
|
+
mocked tests only — verify it against a real GHE instance like so:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
gh auth login --hostname ghe.your-company.com # one-time
|
|
61
|
+
cd /path/to/a/repo/whose/origin/is/that/GHE/host
|
|
62
|
+
qodo review list # should detect + list, not error
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Expected: the GHE remote resolves to `github` (no "not wired yet" / "could not
|
|
66
|
+
identify the git provider" error), and the Qodo bot's comments list as on
|
|
67
|
+
github.com. Then exercise resolution on a real PR:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
qodo review list --json | jq '.comments[] | {id, severity, type}'
|
|
71
|
+
qodo review resolve <comment-id> --reply "Verified." --sign
|
|
72
|
+
qodo review resolve --all --severity HIGH # batch
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Expected: the reply posts, the `+1` reaction lands, and the GitHub review thread
|
|
76
|
+
is marked resolved (via the GraphQL `resolveReviewThread` mutation); a comment
|
|
77
|
+
with no mappable thread falls back to reaction-only and is reported, not failed.
|
|
78
|
+
|
|
79
|
+
Opt-in smoke (runs only when opted in *and* `gh` is authenticated to the host —
|
|
80
|
+
otherwise it skips cleanly rather than failing on a `gh`-less / unauthenticated
|
|
81
|
+
box):
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
QODO_LIVE_SMOKE=1 QODO_CLI_GHE_REMOTE=git@ghe.your-company.com:org/repo.git \
|
|
85
|
+
uv run pytest tests/test_contracts.py::test_live_ghe_resolves_to_github -v
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## 4. `qodo review` against a self-hosted GitLab on a custom domain
|
|
89
|
+
|
|
90
|
+
`resolve_provider()` upgrades an unknown host to `gitlab` when `glab` is
|
|
91
|
+
authenticated to it (`glab auth status --hostname <host>`), mirroring the GHE
|
|
92
|
+
path above. `gitlab.com` is detected by hostname directly (no `glab` call);
|
|
93
|
+
`gh` is consulted before `glab`, so a host both CLIs know resolves to `github`.
|
|
94
|
+
Covered by mocked tests only — verify it against a real self-hosted instance:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
glab auth login --hostname gitlab.your-company.com # one-time
|
|
98
|
+
cd /path/to/a/repo/whose/origin/is/that/GitLab/host
|
|
99
|
+
qodo review list # should detect + list, not error
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Expected: the custom-domain remote resolves to `gitlab` (no "not wired yet" /
|
|
103
|
+
"could not identify the git provider" error), and the Qodo bot's notes list as
|
|
104
|
+
on gitlab.com. Resolution marks the note's MR *discussion* resolved (GitLab has
|
|
105
|
+
no `+1` marker).
|
|
106
|
+
|
|
107
|
+
## 5. Provider gate (still-unwired providers)
|
|
108
|
+
|
|
109
|
+
An Azure/Bitbucket/Gerrit remote should fail with a clear, actionable message
|
|
110
|
+
rather than misbehaving:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
cd /path/to/an/azure/devops/repo
|
|
114
|
+
qodo review list # exit 2, "provider 'azure' is not wired yet" + hint
|
|
115
|
+
```
|
|
@@ -30,8 +30,9 @@ calling agent — which keeps the CLI zero-dependency and model-agnostic.
|
|
|
30
30
|
generates (call `rules get` once per query and merge).
|
|
31
31
|
- **`qodo review`** — we own: detect the provider, find the open PR, fetch and
|
|
32
32
|
filter the Qodo bot's comments, dedup by stable comment identity (id/url),
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
parse each body into structured triage fields, reply, acknowledge, and resolve
|
|
34
|
+
the review thread. The agent owns: reading the flagged files, generating a fix,
|
|
35
|
+
editing, and committing.
|
|
35
36
|
|
|
36
37
|
## Resolved contract — `qodo-get-rules`
|
|
37
38
|
|
|
@@ -49,6 +50,14 @@ calling agent — which keeps the CLI zero-dependency and model-agnostic.
|
|
|
49
50
|
- **Request body:** `{"query": <str>, "top_k": <int>, "scopes": [<str>]}`.
|
|
50
51
|
`scopes` is omitted entirely when empty (never `null` / `[]`). `top_k`
|
|
51
52
|
defaults to `20`.
|
|
53
|
+
- **Scope auto-detection:** when `--scope` is omitted, the CLI mirrors the
|
|
54
|
+
skill — it derives the repository scope as the `org/repo` slug from
|
|
55
|
+
`git remote get-url origin` (SSH `git@host:org/repo(.git)`, HTTPS
|
|
56
|
+
`https://host/org/repo(.git)`, `ssh://…` forms; multi-level namespaces such as
|
|
57
|
+
GitLab subgroups are preserved) and a module scope `<name>` when the working
|
|
58
|
+
path contains `modules/<name>/`. Detection is non-raising: no git / no origin
|
|
59
|
+
yields no scope (omitted, not empty). `--scope` overrides detection;
|
|
60
|
+
`--no-scope` forces omission.
|
|
52
61
|
- **Response:** `{"rules": [{"id", "name", "content", "severity"}]}`, ranked by
|
|
53
62
|
relevance (most relevant first). Severity is one of `ERROR`, `WARNING`,
|
|
54
63
|
`RECOMMENDATION`.
|
|
@@ -79,15 +88,39 @@ calling agent — which keeps the CLI zero-dependency and model-agnostic.
|
|
|
79
88
|
- inline comments: `gh api repos/{owner}/{repo}/pulls/<pr>/comments --paginate`
|
|
80
89
|
- reply: `gh api repos/{owner}/{repo}/pulls/<pr>/comments/<id>/replies -X POST -f body=<text>`
|
|
81
90
|
- acknowledge: `gh api repos/{owner}/{repo}/pulls/comments/<id>/reactions -X POST -f content='+1'`
|
|
91
|
+
- resolve thread: map the comment's REST id to its review-thread node id via
|
|
92
|
+
`gh api graphql` (`repository.pullRequest.reviewThreads` → match
|
|
93
|
+
`comments.nodes.databaseId`), then `resolveReviewThread(input:{threadId})`.
|
|
94
|
+
|
|
95
|
+
- **Comment body structure (parsed by `qodo review list`):** a Qodo inline body
|
|
96
|
+
opens with a severity badge `<img ... alt="Action required">` (or
|
|
97
|
+
`"Review recommended"`); the title line carries `<code>` category chips
|
|
98
|
+
(e.g. `📘 Rule violation`, `≡ Correctness`); the `<pre>` block is the issue
|
|
99
|
+
description (HTML-entity-encoded); and a `<details><summary>Agent Prompt</summary>`
|
|
100
|
+
fenced block holds the remediation prompt. Severity map (the lever — extend as
|
|
101
|
+
Qodo adds badges): `Action required → HIGH`, `Review recommended → MEDIUM`,
|
|
102
|
+
any other badge → `LOW`, no badge → `null`. Parsing is best-effort; an
|
|
103
|
+
unrecognised body degrades to title-only with `null` fields.
|
|
104
|
+
|
|
105
|
+
- **GitLab (wired now), via `glab`:** GitLab's model is MR **discussions** (each
|
|
106
|
+
holds one or more **notes**); resolution is at the discussion level (no `+1`
|
|
107
|
+
marker — resolving the discussion *is* the acknowledgement). The project path
|
|
108
|
+
is the `namespace/repo` slug from `origin`, URL-encoded for the API.
|
|
109
|
+
- find MR: `glab api "projects/<proj>/merge_requests?source_branch=<branch>&state=opened"`
|
|
110
|
+
- notes: `glab api "projects/<proj>/merge_requests/<iid>/discussions?per_page=100" --paginate`
|
|
111
|
+
(keep notes whose `author.username` is a Qodo bot; skip `system` notes)
|
|
112
|
+
- reply: `glab api projects/<proj>/merge_requests/<iid>/discussions/<disc>/notes -X POST -f body=<text>`
|
|
113
|
+
- resolve: `glab api projects/<proj>/merge_requests/<iid>/discussions/<disc> -X PUT -f resolved=true`
|
|
114
|
+
- **Implemented but NOT live-tested** against a real GitLab (we have none);
|
|
115
|
+
covered by mocked tests mirroring the GitHub ones (the `glab` REST shapes
|
|
116
|
+
above are the contract). The provider gate (`require_provider`) now allows
|
|
117
|
+
`github` + `gitlab`.
|
|
82
118
|
|
|
83
119
|
### Follow-up providers (recognised, not yet wired)
|
|
84
120
|
|
|
85
121
|
These are captured from `resources/providers.md` so wiring them is a lookup, not
|
|
86
122
|
a re-investigation. Today the CLI raises a clear "not wired yet" error for them.
|
|
87
123
|
|
|
88
|
-
- **GitLab (`glab`):** find `glab mr list --source-branch <branch>`; fetch
|
|
89
|
-
`glab mr view <iid> --comments`; reply / resolve via
|
|
90
|
-
`glab api /projects/:id/merge_requests/<iid>/discussions/...`.
|
|
91
124
|
- **Azure DevOps (`az`):** find `az repos pr list --source-branch <branch> --status active`;
|
|
92
125
|
fetch / reply / resolve via `az devops invoke --resource pullRequestThreads`.
|
|
93
126
|
- **Bitbucket (`curl`):** REST under
|
|
@@ -96,8 +129,9 @@ a re-investigation. Today the CLI raises a clear "not wired yet" error for them.
|
|
|
96
129
|
`git push origin HEAD:refs/for/<branch>`.
|
|
97
130
|
|
|
98
131
|
True GitHub review-thread resolution (the GraphQL `resolveReviewThread`
|
|
99
|
-
mutation) is
|
|
100
|
-
|
|
132
|
+
mutation) is **now wired**: `resolve` posts the `+1` reaction the upstream skill
|
|
133
|
+
uses *and* resolves the GitHub review thread by default (`--no-resolve-thread`
|
|
134
|
+
to skip), falling back to reaction-only when no thread maps to the comment.
|
|
101
135
|
|
|
102
136
|
## Non-goals (enforced)
|
|
103
137
|
|
|
@@ -107,11 +141,22 @@ upstream skill uses as a lightweight acknowledgement.
|
|
|
107
141
|
- `qodo rules` does not implement an interactive login — it reuses existing
|
|
108
142
|
credentials and errors when they are absent.
|
|
109
143
|
|
|
144
|
+
## Verifying the contracts
|
|
145
|
+
|
|
146
|
+
The `/rules/search` response shape is pinned by an **offline contract test**
|
|
147
|
+
(`tests/test_contracts.py`) against a recorded fixture
|
|
148
|
+
(`tests/fixtures/rules_search_response.json`). Paths that need a real system to
|
|
149
|
+
exercise — `qodo rules` against the live API, and GitHub Enterprise provider
|
|
150
|
+
resolution — have **opt-in live smokes** (gated on `QODO_API_KEY` /
|
|
151
|
+
`QODO_CLI_GHE_REMOTE`, skipped by default) plus a manual checklist in
|
|
152
|
+
`docs/manual-verification.md`.
|
|
153
|
+
|
|
110
154
|
## Re-sync procedure
|
|
111
155
|
|
|
112
156
|
1. Re-fetch the upstream `SKILL.md` and the `references/` / `resources/` files
|
|
113
157
|
listed in the verb↔skill map above.
|
|
114
158
|
2. Diff the resolved contract in this file against them (endpoint, headers,
|
|
115
159
|
request/response schema, bot logins, provider commands).
|
|
116
|
-
3. Update `qodo/cli/_qodo_api.py` / `qodo/cli/_providers.py
|
|
160
|
+
3. Update `qodo/cli/_qodo_api.py` / `qodo/cli/_providers.py`, the contract
|
|
161
|
+
fixture (`tests/fixtures/rules_search_response.json`), and this ledger
|
|
117
162
|
together, then bump the version.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "qodo-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.9.0"
|
|
4
4
|
description = "Community CLI and agent to manage Qodo — the AI code reviewer and Qodo's other agents (requires a Qodo subscription). Unofficial: not affiliated with, authorized, or endorsed by Qodo; the Qodo name and trademark belong to Qodo Ltd."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -63,6 +63,7 @@ def _argv_has_json(argv: list[str] | None) -> bool:
|
|
|
63
63
|
|
|
64
64
|
def _build_parser() -> argparse.ArgumentParser:
|
|
65
65
|
from qodo.cli._commands import cli as _cli_group
|
|
66
|
+
from qodo.cli._commands import config as _config_group
|
|
66
67
|
from qodo.cli._commands import doctor as _doctor_cmd
|
|
67
68
|
from qodo.cli._commands import explain as _explain_cmd
|
|
68
69
|
from qodo.cli._commands import learn as _learn_cmd
|
|
@@ -87,6 +88,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
87
88
|
# Qodo domain noun groups (the real surface):
|
|
88
89
|
_rules_group.register(sub)
|
|
89
90
|
_review_group.register(sub)
|
|
91
|
+
_config_group.register(sub)
|
|
90
92
|
# Agent-first introspection verbs:
|
|
91
93
|
_whoami_cmd.register(sub)
|
|
92
94
|
_learn_cmd.register(sub)
|