aicp-cli 0.3.0__tar.gz → 0.3.1__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.
Files changed (49) hide show
  1. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/CHANGELOG.md +16 -0
  2. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/PKG-INFO +14 -19
  3. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/README.md +13 -18
  4. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/pyproject.toml +1 -1
  5. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/src/aicp/menu.py +10 -1
  6. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/tests/test_menu.py +10 -0
  7. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/uv.lock +1 -1
  8. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/.github/workflows/ci.yml +0 -0
  9. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/.github/workflows/release.yml +0 -0
  10. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/.gitignore +0 -0
  11. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/LICENSE +0 -0
  12. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/TODO.md +0 -0
  13. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/config.example.json +0 -0
  14. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/docs/images/aicp-run.png +0 -0
  15. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/skills/commit.md +0 -0
  16. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/skills/safe-git-push/SKILL.md +0 -0
  17. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/skills/safe-git-push/scripts/safe_push.py +0 -0
  18. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/src/aicp/__init__.py +0 -0
  19. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/src/aicp/_keyreader.py +0 -0
  20. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/src/aicp/_utils.py +0 -0
  21. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/src/aicp/budget.py +0 -0
  22. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/src/aicp/cli.py +0 -0
  23. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/src/aicp/config.py +0 -0
  24. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/src/aicp/contracts.py +0 -0
  25. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/src/aicp/gitflow.py +0 -0
  26. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/src/aicp/i18n.py +0 -0
  27. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/src/aicp/notify.py +0 -0
  28. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/src/aicp/present.py +0 -0
  29. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/src/aicp/quota.py +0 -0
  30. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/src/aicp/runner.py +0 -0
  31. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/src/aicp/secrets.py +0 -0
  32. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/src/aicp/skills.py +0 -0
  33. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/src/aicp/timing.py +0 -0
  34. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/tests/conftest.py +0 -0
  35. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/tests/test_budget.py +0 -0
  36. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/tests/test_cli.py +0 -0
  37. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/tests/test_config.py +0 -0
  38. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/tests/test_cross_platform.py +0 -0
  39. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/tests/test_gitflow.py +0 -0
  40. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/tests/test_i18n.py +0 -0
  41. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/tests/test_menu_skills.py +0 -0
  42. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/tests/test_notify.py +0 -0
  43. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/tests/test_present.py +0 -0
  44. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/tests/test_quota.py +0 -0
  45. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/tests/test_runner.py +0 -0
  46. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/tests/test_secrets.py +0 -0
  47. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/tests/test_skills.py +0 -0
  48. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/tests/test_timing.py +0 -0
  49. {aicp_cli-0.3.0 → aicp_cli-0.3.1}/tests/test_undo.py +0 -0
@@ -1,3 +1,14 @@
1
+ ## [0.3.1] - 2026-09-14
2
+
3
+ ### 🐛 Bug Fixes
4
+
5
+ - **menu:** Stop config panel resizing on row selection
6
+
7
+ ### 📚 Documentation
8
+
9
+ - **readme:** Document releasing and the wheel version check
10
+ - Remove CI section from README.md
11
+ - Add uv requirement note to README.md
1
12
  ## [0.3.0] - 2026-09-14
2
13
 
3
14
  ### 🐛 Bug Fixes
@@ -16,8 +27,13 @@
16
27
 
17
28
  - **release:** Publish wheels to PyPI via trusted publishing
18
29
  - Assert the built wheel reports the right version
30
+ - **release:** V0.3.0
19
31
  ## [0.2.1] - 2026-09-13
20
32
 
33
+ ### 📚 Documentation
34
+
35
+ - **changelog:** Release v0.2.1
36
+
21
37
  ### ⚙️ Miscellaneous Tasks
22
38
 
23
39
  - Refresh uv lockfile for v0.2.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: aicp-cli
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Summary: AI commit + push, with a git-verified result summary
5
5
  Project-URL: Repository, https://github.com/weskao/aicp
6
6
  Project-URL: Issues, https://github.com/weskao/aicp/issues
@@ -36,6 +36,7 @@ push that never reached the remote.
36
36
  ## Requirements
37
37
 
38
38
  - Python 3.10 or newer
39
+ - [`uv`](https://docs.astral.sh/uv/) — the install path below
39
40
  - `git`
40
41
  - At least one of the six AI CLIs above on `PATH`
41
42
 
@@ -178,27 +179,21 @@ that, and even then the original is moved aside to `<name>.bak` (numbered
178
179
  `.bak.1`, `.bak.2`, … so a second forced install never clobbers the first
179
180
  backup) before aicp writes its own copy.
180
181
 
181
- ### This repo's own CI
182
+ ### Releasing
182
183
 
183
- `.github/workflows/ci.yml` runs the suite on **macOS, Linux, and Windows** in
184
- parallel (`fail-fast: false`, so one platform failing still tells you about the
185
- other two), then builds the wheel, installs it into a throwaway venv, and checks
186
- that the console script runs and the vendored skills survived packaging.
184
+ `.github/workflows/release.yml` runs on a `v*` tag. It repeats the full
185
+ lint/test/build pass, installs the wheel into a throwaway venv, and refuses to
186
+ upload unless that wheel reports the version being tagged — so a tag that
187
+ disagrees with `pyproject.toml` fails before anything reaches PyPI. It then
188
+ publishes with Trusted Publishing (OIDC — there is no API token stored in this
189
+ repo) and attaches the wheel, sdist and `SHA256SUMS` to the GitHub release.
187
190
 
188
- A failed run on a `push` also sends one Telegram message. Failure-only is
189
- deliberate: a notification on every green push is one nobody reads.
191
+ Checksums are generated *after* publishing on purpose: `uv publish` uploads
192
+ everything in `dist/`, and `SHA256SUMS` is not a distribution.
190
193
 
191
- The credentials are **repo secrets — never committed**. The workflow reads them
192
- through `${{ secrets.* }}` and skips quietly when they're unset, so a fork or a
193
- fresh clone gets no second red X on top of the real failure. To enable it:
194
-
195
- ```sh
196
- gh secret set TELEGRAM_BOT_TOKEN -R <owner>/<repo> # paste the bot token
197
- gh secret set TELEGRAM_CHAT_ID -R <owner>/<repo> # paste the chat id
198
- ```
199
-
200
- Verify with `gh secret list -R <owner>/<repo>` — GitHub shows the names and
201
- timestamps only; secret values can never be read back, by you or by CI logs.
194
+ A tag runs the workflow file **as it existed at that tag**, so a release that
195
+ failed to publish can't be repaired by re-running the old tag — the fix isn't
196
+ in that tree. Bump the version and tag again.
202
197
 
203
198
  ## Configuration
204
199
 
@@ -24,6 +24,7 @@ push that never reached the remote.
24
24
  ## Requirements
25
25
 
26
26
  - Python 3.10 or newer
27
+ - [`uv`](https://docs.astral.sh/uv/) — the install path below
27
28
  - `git`
28
29
  - At least one of the six AI CLIs above on `PATH`
29
30
 
@@ -166,27 +167,21 @@ that, and even then the original is moved aside to `<name>.bak` (numbered
166
167
  `.bak.1`, `.bak.2`, … so a second forced install never clobbers the first
167
168
  backup) before aicp writes its own copy.
168
169
 
169
- ### This repo's own CI
170
+ ### Releasing
170
171
 
171
- `.github/workflows/ci.yml` runs the suite on **macOS, Linux, and Windows** in
172
- parallel (`fail-fast: false`, so one platform failing still tells you about the
173
- other two), then builds the wheel, installs it into a throwaway venv, and checks
174
- that the console script runs and the vendored skills survived packaging.
172
+ `.github/workflows/release.yml` runs on a `v*` tag. It repeats the full
173
+ lint/test/build pass, installs the wheel into a throwaway venv, and refuses to
174
+ upload unless that wheel reports the version being tagged — so a tag that
175
+ disagrees with `pyproject.toml` fails before anything reaches PyPI. It then
176
+ publishes with Trusted Publishing (OIDC — there is no API token stored in this
177
+ repo) and attaches the wheel, sdist and `SHA256SUMS` to the GitHub release.
175
178
 
176
- A failed run on a `push` also sends one Telegram message. Failure-only is
177
- deliberate: a notification on every green push is one nobody reads.
179
+ Checksums are generated *after* publishing on purpose: `uv publish` uploads
180
+ everything in `dist/`, and `SHA256SUMS` is not a distribution.
178
181
 
179
- The credentials are **repo secrets — never committed**. The workflow reads them
180
- through `${{ secrets.* }}` and skips quietly when they're unset, so a fork or a
181
- fresh clone gets no second red X on top of the real failure. To enable it:
182
-
183
- ```sh
184
- gh secret set TELEGRAM_BOT_TOKEN -R <owner>/<repo> # paste the bot token
185
- gh secret set TELEGRAM_CHAT_ID -R <owner>/<repo> # paste the chat id
186
- ```
187
-
188
- Verify with `gh secret list -R <owner>/<repo>` — GitHub shows the names and
189
- timestamps only; secret values can never be read back, by you or by CI logs.
182
+ A tag runs the workflow file **as it existed at that tag**, so a release that
183
+ failed to publish can't be repaired by re-running the old tag — the fix isn't
184
+ in that tree. Bump the version and tag again.
190
185
 
191
186
  ## Configuration
192
187
 
@@ -2,7 +2,7 @@
2
2
  # PyPI distribution name only — the `aicp` name was taken in 2021 by an
3
3
  # unrelated project. The command, import path and repo stay `aicp`.
4
4
  name = "aicp-cli"
5
- version = "0.3.0"
5
+ version = "0.3.1"
6
6
  description = "AI commit + push, with a git-verified result summary"
7
7
  readme = "README.md"
8
8
  requires-python = ">=3.10"
@@ -653,8 +653,17 @@ def _panel(
653
653
  )
654
654
  title = f"{_t(state.lang, 'config_title', 'aicp config')} (v{__version__})"
655
655
  if selected is not None:
656
+ # Reserve the widest help line ANY row can show, not just the selected
657
+ # one's — otherwise the frame narrows and widens as the cursor moves
658
+ # across rows with shorter and longer help text (render_panel sizes
659
+ # its own width off the notes it is handed).
660
+ help_budget = frame_columns - 4
661
+ fitted_help = [_fit(_t(state.lang, *row.help), help_budget) for row in ROWS]
662
+ reserve = max(width(h) for h in fitted_help)
663
+ help_line = fitted_help[selected - 1]
664
+ help_line += " " * (reserve - width(help_line))
656
665
  texts = [
657
- _t(state.lang, *ROWS[selected - 1].help),
666
+ help_line,
658
667
  "",
659
668
  _t(state.lang, "config_keys_tui", "↑↓ select · ←→ change · ⏎ change/run · q/Ctrl-C quit · saves as you go"),
660
669
  ]
@@ -146,6 +146,16 @@ def test_cli_order_motion_runs_the_other_way_too():
146
146
  assert _plain(frames[-1]) == " → ".join(after)
147
147
 
148
148
 
149
+ def test_selecting_a_different_row_does_not_resize_the_panel():
150
+ """Rows carry help text of very different lengths — the box must be sized
151
+ for the longest one up front, not reflow as the cursor passes each row."""
152
+ state = MenuState(Path("menu.aicprc"), True, True, "en", list(ROSTER_NAMES))
153
+
154
+ widths = {width(_panel(state, selected=i)[0]) for i in range(1, len(ROWS) + 1)}
155
+
156
+ assert len(widths) == 1, "the frame width changed when a different row was selected"
157
+
158
+
149
159
  @pytest.mark.parametrize("columns, lines", [(80, 24), (100, 24), (60, 24), (100, 14)])
150
160
  def test_the_panel_fits_the_terminal_it_draws_on(columns, lines, monkeypatch):
151
161
  """Every line inside the terminal, in both languages.
@@ -4,7 +4,7 @@ requires-python = ">=3.10"
4
4
 
5
5
  [[package]]
6
6
  name = "aicp-cli"
7
- version = "0.3.0"
7
+ version = "0.3.1"
8
8
  source = { editable = "." }
9
9
 
10
10
  [package.dev-dependencies]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes