lib-cli-exit-tools 2.2.4__tar.gz → 2.3.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.
Files changed (84) hide show
  1. lib_cli_exit_tools-2.3.0/.claude/commands/tfbp.md +84 -0
  2. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/.codacy/cli.sh +27 -25
  3. lib_cli_exit_tools-2.3.0/.data_arch_violations.json +38 -0
  4. lib_cli_exit_tools-2.3.0/.github/actions/extract-metadata/action.yml +92 -0
  5. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/.github/workflows/default_cicd_public.yml +37 -57
  6. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/.github/workflows/default_release_public.yml +1 -1
  7. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/.gitignore +1 -0
  8. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/CHANGELOG.md +17 -0
  9. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/CLAUDE.md +3 -3
  10. lib_cli_exit_tools-2.3.0/Makefile +235 -0
  11. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/PKG-INFO +7 -7
  12. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/pyproject.toml +12 -7
  13. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/src/lib_cli_exit_tools/__init__.py +1 -0
  14. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/src/lib_cli_exit_tools/__init__conf__.py +1 -1
  15. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/src/lib_cli_exit_tools/application/runner.py +20 -28
  16. lib_cli_exit_tools-2.3.0/src/lib_cli_exit_tools/cli/__init__.py +27 -0
  17. lib_cli_exit_tools-2.3.0/src/lib_cli_exit_tools/cli/commands.py +69 -0
  18. lib_cli_exit_tools-2.3.0/src/lib_cli_exit_tools/cli/group.py +123 -0
  19. lib_cli_exit_tools-2.3.0/src/lib_cli_exit_tools/cli/styling.py +111 -0
  20. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/src/lib_cli_exit_tools/core/configuration.py +20 -4
  21. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/src/lib_cli_exit_tools/core/exit_codes.py +2 -2
  22. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/src/lib_cli_exit_tools/lib_cli_exit_tools.py +2 -1
  23. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/tests/conftest.py +2 -1
  24. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/tests/test_cli.py +27 -19
  25. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/tests/test_core_configuration.py +5 -4
  26. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/tests/test_core_exit_codes.py +2 -1
  27. lib_cli_exit_tools-2.2.4/.github/workflows/ci.yml_backup +0 -208
  28. lib_cli_exit_tools-2.2.4/.github/workflows/release.yml_backup +0 -50
  29. lib_cli_exit_tools-2.2.4/Makefile +0 -60
  30. lib_cli_exit_tools-2.2.4/scripts/__init__.py +0 -3
  31. lib_cli_exit_tools-2.2.4/scripts/__main__.py +0 -7
  32. lib_cli_exit_tools-2.2.4/scripts/_utils.py +0 -768
  33. lib_cli_exit_tools-2.2.4/scripts/build.py +0 -52
  34. lib_cli_exit_tools-2.2.4/scripts/bump.py +0 -32
  35. lib_cli_exit_tools-2.2.4/scripts/bump_major.py +0 -20
  36. lib_cli_exit_tools-2.2.4/scripts/bump_minor.py +0 -20
  37. lib_cli_exit_tools-2.2.4/scripts/bump_patch.py +0 -20
  38. lib_cli_exit_tools-2.2.4/scripts/bump_version.py +0 -80
  39. lib_cli_exit_tools-2.2.4/scripts/clean.py +0 -75
  40. lib_cli_exit_tools-2.2.4/scripts/cli.py +0 -232
  41. lib_cli_exit_tools-2.2.4/scripts/dependencies.py +0 -590
  42. lib_cli_exit_tools-2.2.4/scripts/dev.py +0 -19
  43. lib_cli_exit_tools-2.2.4/scripts/help.py +0 -41
  44. lib_cli_exit_tools-2.2.4/scripts/install.py +0 -19
  45. lib_cli_exit_tools-2.2.4/scripts/menu.py +0 -582
  46. lib_cli_exit_tools-2.2.4/scripts/push.py +0 -309
  47. lib_cli_exit_tools-2.2.4/scripts/release.py +0 -92
  48. lib_cli_exit_tools-2.2.4/scripts/run_cli.py +0 -154
  49. lib_cli_exit_tools-2.2.4/scripts/target_metadata.py +0 -202
  50. lib_cli_exit_tools-2.2.4/scripts/test.py +0 -1004
  51. lib_cli_exit_tools-2.2.4/scripts/toml_config.py +0 -433
  52. lib_cli_exit_tools-2.2.4/scripts/version_current.py +0 -20
  53. lib_cli_exit_tools-2.2.4/src/lib_cli_exit_tools/cli.py +0 -261
  54. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/.codacy/cli-config.yaml +0 -0
  55. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/.codacy/codacy.yaml +0 -0
  56. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/.codacy/tools-configs/lizard.yaml +0 -0
  57. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/.codacy/tools-configs/trivy.yaml +0 -0
  58. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/.devcontainer/devcontainer.json +0 -0
  59. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/.devcontainer/settings.json +0 -0
  60. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/.env.example +0 -0
  61. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/.github/dependabot.yml +0 -0
  62. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/.github/workflows/codeql.yml +0 -0
  63. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/.qlty/qlty.toml +0 -0
  64. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/.snyk +0 -0
  65. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/CONTRIBUTING.md +0 -0
  66. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/DEVELOPMENT.md +0 -0
  67. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/INSTALL.md +0 -0
  68. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/LICENSE +0 -0
  69. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/README.md +0 -0
  70. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/codecov.yml +0 -0
  71. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/docs/system-design/module_reference.md +0 -0
  72. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/notebooks/Quickstart.ipynb +0 -0
  73. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/src/lib_cli_exit_tools/__main__.py +0 -0
  74. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/src/lib_cli_exit_tools/adapters/__init__.py +0 -0
  75. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/src/lib_cli_exit_tools/adapters/signals.py +0 -0
  76. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/src/lib_cli_exit_tools/application/__init__.py +0 -0
  77. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/src/lib_cli_exit_tools/core/__init__.py +0 -0
  78. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/src/lib_cli_exit_tools/py.typed +0 -0
  79. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/tests/test_adapters_signals.py +0 -0
  80. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/tests/test_application_runner.py +0 -0
  81. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/tests/test_behaviors.py +0 -0
  82. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/tests/test_metadata.py +0 -0
  83. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/tests/test_module_entry.py +0 -0
  84. {lib_cli_exit_tools-2.2.4 → lib_cli_exit_tools-2.3.0}/tests/test_signals_integration.py +0 -0
@@ -0,0 +1,84 @@
1
+ Test, Fix, Bump, Push — full release pipeline.
2
+
3
+ Execute the following steps sequentially. Do NOT skip steps. Stop and ask the user if any decision requires human judgement.
4
+
5
+ ---
6
+
7
+ ## Step 1 — Run Tests
8
+
9
+ Run `make test` and capture the full output.
10
+
11
+ ## Step 2 — Fix All Errors
12
+
13
+ If `make test` failed:
14
+ - Analyze every error in the output (lint, type-check, unit tests, shellcheck, etc.).
15
+ - Fix all errors in the source code.
16
+ - Re-run `make test` to confirm all errors are resolved.
17
+ - Repeat until `make test` passes with zero failures.
18
+
19
+ If `make test` passed, proceed to the next step.
20
+
21
+ ## Step 3 — Determine Semver Bump Level
22
+
23
+ Analyze all changes since the last released version:
24
+ - Run `git log $(git describe --tags --abbrev=0)..HEAD --oneline` to list commits since the last tag.
25
+ - Run `git diff $(git describe --tags --abbrev=0)..HEAD --stat` to see which files changed.
26
+ - Apply semver rules:
27
+ - **major** — breaking API changes, removed public functions/classes, changed signatures
28
+ - **minor** — new features, new public API, new modules, backward-compatible additions
29
+ - **patch** — bug fixes, documentation, internal refactors, dependency updates, CI/CD changes
30
+ - Present your reasoning and recommended bump level to the user for confirmation before proceeding.
31
+
32
+ ## Step 4 — Bump Version
33
+
34
+ Run the appropriate command based on the confirmed semver level:
35
+ - `make bump-patch` for patch
36
+ - `make bump-minor` for minor
37
+ - `make bump-major` for major
38
+
39
+ ## Step 5 — Update Changelog
40
+
41
+ Update `CHANGELOG.md` with the important changes since the last version:
42
+ - Group changes under the new version heading with the current date.
43
+ - Categorize entries (Added, Changed, Fixed, Removed, etc.) following Keep a Changelog format.
44
+ - Be concise but cover all user-visible and developer-visible changes.
45
+
46
+ ## Step 6 — Create Commit Message
47
+
48
+ Compose a meaningful commit message that:
49
+ - Summarizes the version bump and key changes.
50
+ - References the new version number.
51
+ - Follows conventional commit style if the project uses it.
52
+
53
+ Present the commit message to the user for approval.
54
+
55
+ ## Step 7 — Push
56
+
57
+ Run `make push <approved commit message>` to run tests, commit, and push to the remote.
58
+
59
+ ## Step 8 — Monitor GitHub CI
60
+
61
+ After pushing:
62
+ - Run `gh run list --limit 1` to find the latest workflow run.
63
+ - Run `gh run watch <run-id>` to monitor it until completion.
64
+ - If the run **succeeds**, proceed to Step 9.
65
+ - If the run **fails**:
66
+ - Run `gh run view <run-id> --log-failed` to get failure details.
67
+ - Fix all errors in the source code.
68
+ - Go back to **Step 5** (update changelog if the fix is meaningful, re-commit, re-push).
69
+
70
+ ## Step 9 — Release
71
+
72
+ Once GitHub CI is green:
73
+ - Run `make release` to create the version tag and GitHub release.
74
+
75
+ ## Step 10 — Monitor Release CI
76
+
77
+ After releasing:
78
+ - Run `gh run list --limit 1` to find the release workflow run.
79
+ - Run `gh run watch <run-id>` to monitor it until completion.
80
+ - If the run **succeeds**, report the release URL and confirm completion.
81
+ - If the run **fails**:
82
+ - Run `gh run view <run-id> --log-failed` to get failure details.
83
+ - Fix all errors in the source code.
84
+ - Go back to **Step 5** (update changelog, re-commit, re-push, re-release).
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
-
4
3
  set -e +o pipefail
5
4
 
6
5
  # Set up paths first
@@ -11,15 +10,15 @@ os_name=$(uname)
11
10
  arch=$(uname -m)
12
11
 
13
12
  case "$arch" in
14
- "x86_64")
15
- arch="amd64"
16
- ;;
17
- "x86")
18
- arch="386"
19
- ;;
20
- "aarch64"|"arm64")
21
- arch="arm64"
22
- ;;
13
+ "x86_64")
14
+ arch="amd64"
15
+ ;;
16
+ "x86")
17
+ arch="386"
18
+ ;;
19
+ "aarch64" | "arm64")
20
+ arch="arm64"
21
+ ;;
23
22
  esac
24
23
 
25
24
  if [ -z "$CODACY_CLI_V2_TMP_FOLDER" ]; then
@@ -34,10 +33,10 @@ fi
34
33
 
35
34
  version_file="$CODACY_CLI_V2_TMP_FOLDER/version.yaml"
36
35
 
37
-
38
36
  get_version_from_yaml() {
39
37
  if [ -f "$version_file" ]; then
40
- local version=$(grep -o 'version: *"[^"]*"' "$version_file" | cut -d'"' -f2)
38
+ local version
39
+ version=$(grep -o 'version: *"[^"]*"' "$version_file" | cut -d'"' -f2)
41
40
  if [ -n "$version" ]; then
42
41
  echo "$version"
43
42
  return 0
@@ -49,20 +48,24 @@ get_version_from_yaml() {
49
48
  get_latest_version() {
50
49
  local response
51
50
  if [ -n "$GH_TOKEN" ]; then
52
- response=$(curl -Lq --header "Authorization: Bearer $GH_TOKEN" "https://api.github.com/repos/codacy/codacy-cli-v2/releases/latest" 2>/dev/null)
51
+ response=$(curl -Lq \
52
+ --header "Authorization: Bearer $GH_TOKEN" \
53
+ "https://api.github.com/repos/codacy/codacy-cli-v2/releases/latest" 2>/dev/null)
53
54
  else
54
- response=$(curl -Lq "https://api.github.com/repos/codacy/codacy-cli-v2/releases/latest" 2>/dev/null)
55
+ response=$(curl -Lq \
56
+ "https://api.github.com/repos/codacy/codacy-cli-v2/releases/latest" 2>/dev/null)
55
57
  fi
56
58
 
57
59
  handle_rate_limit "$response"
58
- local version=$(echo "$response" | grep -m 1 tag_name | cut -d'"' -f4)
60
+ local version
61
+ version=$(echo "$response" | grep -m 1 tag_name | cut -d'"' -f4)
59
62
  echo "$version"
60
63
  }
61
64
 
62
65
  handle_rate_limit() {
63
66
  local response="$1"
64
67
  if echo "$response" | grep -q "API rate limit exceeded"; then
65
- fatal "Error: GitHub API rate limit exceeded. Please try again later"
68
+ fatal "Error: GitHub API rate limit exceeded. Please try again later"
66
69
  fi
67
70
  }
68
71
 
@@ -70,9 +73,9 @@ download_file() {
70
73
  local url="$1"
71
74
 
72
75
  echo "Downloading from URL: ${url}"
73
- if command -v curl > /dev/null 2>&1; then
76
+ if command -v curl >/dev/null 2>&1; then
74
77
  curl -# -LS "$url" -O
75
- elif command -v wget > /dev/null 2>&1; then
78
+ elif command -v wget >/dev/null 2>&1; then
76
79
  wget "$url"
77
80
  else
78
81
  fatal "Error: Could not find curl or wget, please install one."
@@ -83,7 +86,7 @@ download() {
83
86
  local url="$1"
84
87
  local output_folder="$2"
85
88
 
86
- ( cd "$output_folder" && download_file "$url" )
89
+ (cd "$output_folder" && download_file "$url")
87
90
  }
88
91
 
89
92
  download_cli() {
@@ -95,7 +98,7 @@ download_cli() {
95
98
  local version="$3"
96
99
 
97
100
  if [ ! -f "$bin_path" ]; then
98
- echo "📥 Downloading CLI version $version..."
101
+ echo "Downloading CLI version $version..."
99
102
 
100
103
  remote_file="codacy-cli-v2_${version}_${suffix}_${arch}.tar.gz"
101
104
  url="https://github.com/codacy/codacy-cli-v2/releases/download/${version}/${remote_file}"
@@ -107,16 +110,16 @@ download_cli() {
107
110
 
108
111
  # Warn if CODACY_CLI_V2_VERSION is set and update is requested
109
112
  if [ -n "$CODACY_CLI_V2_VERSION" ] && [ "$1" = "update" ]; then
110
- echo "⚠️ Warning: Performing update with forced version $CODACY_CLI_V2_VERSION"
113
+ echo "Warning: Performing update with forced version $CODACY_CLI_V2_VERSION"
111
114
  echo " Unset CODACY_CLI_V2_VERSION to use the latest version"
112
115
  fi
113
116
 
114
117
  # Ensure version.yaml exists and is up to date
115
118
  if [ ! -f "$version_file" ] || [ "$1" = "update" ]; then
116
- echo "ℹ️ Fetching latest version..."
119
+ echo "Fetching latest version..."
117
120
  version=$(get_latest_version)
118
121
  mkdir -p "$CODACY_CLI_V2_TMP_FOLDER"
119
- echo "version: \"$version\"" > "$version_file"
122
+ echo "version: \"$version\"" >"$version_file"
120
123
  fi
121
124
 
122
125
  # Set the version to use
@@ -126,7 +129,6 @@ else
126
129
  version=$(get_version_from_yaml)
127
130
  fi
128
131
 
129
-
130
132
  # Set up version-specific paths
131
133
  bin_folder="${CODACY_CLI_V2_TMP_FOLDER}/${version}"
132
134
 
@@ -146,4 +148,4 @@ if [ "$#" -eq 1 ] && [ "$1" = "download" ]; then
146
148
  echo "Codacy cli v2 download succeeded"
147
149
  else
148
150
  eval "$run_command $*"
149
- fi
151
+ fi
@@ -0,0 +1,38 @@
1
+ {
2
+ "pass": 1,
3
+ "total_violations": 0,
4
+ "files": {
5
+ "src/lib_cli_exit_tools/core/configuration.py": {
6
+ "violations": [],
7
+ "status": "clean"
8
+ },
9
+ "src/lib_cli_exit_tools/core/exit_codes.py": {
10
+ "violations": [],
11
+ "status": "clean"
12
+ },
13
+ "src/lib_cli_exit_tools/application/runner.py": {
14
+ "violations": [],
15
+ "status": "clean"
16
+ },
17
+ "src/lib_cli_exit_tools/__init__.py": {
18
+ "violations": [],
19
+ "status": "clean"
20
+ },
21
+ "src/lib_cli_exit_tools/__init__conf__.py": {
22
+ "violations": [],
23
+ "status": "clean"
24
+ },
25
+ "src/lib_cli_exit_tools/cli.py": {
26
+ "violations": [],
27
+ "status": "clean"
28
+ },
29
+ "src/lib_cli_exit_tools/lib_cli_exit_tools.py": {
30
+ "violations": [],
31
+ "status": "clean"
32
+ },
33
+ "src/lib_cli_exit_tools/adapters/signals.py": {
34
+ "violations": [],
35
+ "status": "clean"
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,92 @@
1
+ name: Extract project metadata
2
+ description: >-
3
+ Parse pyproject.toml and expose project metadata as step outputs.
4
+ Requires Python to be available in the runner environment.
5
+ Auto-installs rtoml if not already present.
6
+
7
+ outputs:
8
+ PACKAGE_MODULE:
9
+ description: Python-importable module name (underscored)
10
+ value: ${{ steps.meta.outputs.PACKAGE_MODULE }}
11
+ PROJECT_NAME:
12
+ description: Project name from pyproject.toml
13
+ value: ${{ steps.meta.outputs.PROJECT_NAME }}
14
+ CLI_BIN:
15
+ description: CLI entry-point binary name
16
+ value: ${{ steps.meta.outputs.CLI_BIN }}
17
+ SRC_PATH:
18
+ description: Source directory path (e.g. "src")
19
+ value: ${{ steps.meta.outputs.SRC_PATH }}
20
+ COV_FAIL_UNDER:
21
+ description: Minimum coverage percentage from tool.coverage.report.fail_under
22
+ value: ${{ steps.meta.outputs.COV_FAIL_UNDER }}
23
+ COV_REPORT_FILE:
24
+ description: Coverage report filename (e.g. "coverage.xml")
25
+ value: ${{ steps.meta.outputs.COV_REPORT_FILE }}
26
+ PYTEST_VERBOSITY:
27
+ description: Pytest verbosity flag (e.g. "-vv")
28
+ value: ${{ steps.meta.outputs.PYTEST_VERBOSITY }}
29
+ BANDIT_SKIP_FLAG:
30
+ description: Bandit skip flag string (e.g. "-s B101,B601") or empty
31
+ value: ${{ steps.meta.outputs.BANDIT_SKIP_FLAG }}
32
+
33
+ runs:
34
+ using: composite
35
+ steps:
36
+ - name: Extract project metadata from pyproject.toml
37
+ id: meta
38
+ shell: python
39
+ run: |
40
+ import os, subprocess, sys
41
+ try:
42
+ import rtoml
43
+ except ModuleNotFoundError:
44
+ subprocess.check_call([sys.executable, "-m", "pip", "install", "rtoml", "-q"])
45
+ import rtoml
46
+
47
+ from pathlib import Path
48
+ data = rtoml.load(Path('pyproject.toml'))
49
+
50
+ # --- [project] section ---
51
+ project = data['project']['name']
52
+ module = project.replace('-', '_')
53
+ dash = project.replace('_', '-')
54
+ scripts = list(data['project'].get('scripts', {}).keys())
55
+ cli_bin = scripts[0] if scripts else dash
56
+
57
+ # --- [tool.scripts.test] section ---
58
+ scripts_test = data.get('tool', {}).get('scripts', {}).get('test', {})
59
+ src_path = scripts_test.get('src-path', 'src')
60
+ pytest_verbosity = scripts_test.get('pytest-verbosity', '-vv')
61
+ cov_report_file = scripts_test.get('coverage-report-file', 'coverage.xml')
62
+
63
+ # --- [tool.coverage.report] section ---
64
+ cov_fail_under = (
65
+ data.get('tool', {}).get('coverage', {}).get('report', {}).get('fail_under', 90)
66
+ )
67
+
68
+ # --- [tool.bandit] section ---
69
+ bandit_skips = data.get('tool', {}).get('bandit', {}).get('skips', [])
70
+ bandit_skip_flag = f"-s {','.join(bandit_skips)}" if bandit_skips else ""
71
+
72
+ # Write to GITHUB_OUTPUT for composite action outputs
73
+ with open(os.environ['GITHUB_OUTPUT'], 'a', encoding='utf-8') as out:
74
+ out.write(f"PROJECT_NAME={project}\n")
75
+ out.write(f"PACKAGE_MODULE={module}\n")
76
+ out.write(f"CLI_BIN={cli_bin}\n")
77
+ out.write(f"SRC_PATH={src_path}\n")
78
+ out.write(f"PYTEST_VERBOSITY={pytest_verbosity}\n")
79
+ out.write(f"COV_REPORT_FILE={cov_report_file}\n")
80
+ out.write(f"COV_FAIL_UNDER={cov_fail_under}\n")
81
+ out.write(f"BANDIT_SKIP_FLAG={bandit_skip_flag}\n")
82
+
83
+ # Also write to GITHUB_ENV so subsequent steps can use ${{ env.VAR }}
84
+ with open(os.environ['GITHUB_ENV'], 'a', encoding='utf-8') as env:
85
+ env.write(f"PROJECT_NAME={project}\n")
86
+ env.write(f"PACKAGE_MODULE={module}\n")
87
+ env.write(f"CLI_BIN={cli_bin}\n")
88
+ env.write(f"SRC_PATH={src_path}\n")
89
+ env.write(f"PYTEST_VERBOSITY={pytest_verbosity}\n")
90
+ env.write(f"COV_REPORT_FILE={cov_report_file}\n")
91
+ env.write(f"COV_FAIL_UNDER={cov_fail_under}\n")
92
+ env.write(f"BANDIT_SKIP_FLAG={bandit_skip_flag}\n")
@@ -23,6 +23,7 @@ jobs:
23
23
  PYO3_USE_ABI3_FORWARD_COMPATIBILITY: "1"
24
24
  PYTHONIOENCODING: "utf-8"
25
25
  UV_LINK_MODE: "copy"
26
+ UV_BREAK_SYSTEM_PACKAGES: "1"
26
27
  steps:
27
28
  - uses: actions/checkout@v6
28
29
  - uses: actions/setup-python@v6
@@ -34,31 +35,15 @@ jobs:
34
35
  enable-cache: true
35
36
  prune-cache: false
36
37
 
37
- - name: Install tomli (Python < 3.11)
38
- shell: bash
39
- run: python -c "import tomllib" 2>/dev/null || uv pip install tomli --system
38
+ - name: Install bash 4+ on macOS
39
+ if: runner.os == 'macOS'
40
+ run: |
41
+ brew install bash
42
+ echo "$(brew --prefix)/bin" >> "$GITHUB_PATH"
40
43
 
41
44
  - name: Extract project metadata
42
- shell: python
43
- run: |
44
- import os
45
- try:
46
- import tomllib
47
- except ModuleNotFoundError:
48
- import tomli as tomllib
49
-
50
- with open('pyproject.toml', 'rb') as f:
51
- data = tomllib.load(f)
52
- project = data['project']['name']
53
- module = project.replace('-', '_')
54
- dash = project.replace('_', '-')
55
- scripts = list(data['project'].get('scripts', {}).keys())
56
- cli_bin = scripts[0] if scripts else dash
57
-
58
- with open(os.environ['GITHUB_ENV'], 'a', encoding='utf-8') as env:
59
- env.write(f"PROJECT_NAME={project}\n")
60
- env.write(f"PACKAGE_MODULE={module}\n")
61
- env.write(f"CLI_BIN={cli_bin}\n")
45
+ id: metadata
46
+ uses: ./.github/actions/extract-metadata
62
47
 
63
48
  - name: Install journald prerequisites
64
49
  if: runner.os == 'Linux'
@@ -93,8 +78,8 @@ jobs:
93
78
  continue-on-error: true
94
79
  shell: bash
95
80
  run: |
96
- ruff check src tests notebooks
97
- ruff format --check src tests notebooks
81
+ ruff check .
82
+ ruff format --check .
98
83
 
99
84
  - name: Run pyright (type check)
100
85
  id: pyright
@@ -108,7 +93,27 @@ jobs:
108
93
  shell: bash
109
94
  env:
110
95
  TEST_VERBOSE: "1"
111
- run: pytest --cov=src --cov-report=term-missing --cov-report=xml
96
+ # Write coverage SQLite database to local disk — network mounts
97
+ # and stale journal files cause "database is locked" errors.
98
+ COVERAGE_FILE: "${{ runner.temp }}/.coverage"
99
+ run: >-
100
+ pytest -m "not local_only"
101
+ --cov=${{ env.SRC_PATH }}/${{ env.PACKAGE_MODULE }}
102
+ --cov-report=term-missing
103
+ --cov-report=xml:${{ env.COV_REPORT_FILE }}
104
+ --cov-fail-under=${{ env.COV_FAIL_UNDER }}
105
+ ${{ env.PYTEST_VERBOSITY }}
106
+
107
+ - name: Upload coverage to Codecov
108
+ if: >-
109
+ always()
110
+ && steps.pytest.outcome == 'success'
111
+ && matrix.os == 'ubuntu-latest'
112
+ && matrix.python == '3.13'
113
+ uses: codecov/codecov-action@v5
114
+ with:
115
+ files: ${{ env.COV_REPORT_FILE }}
116
+ fail_ci_if_error: false
112
117
 
113
118
  - name: Run import-linter (architecture)
114
119
  id: importlinter
@@ -120,7 +125,7 @@ jobs:
120
125
  id: bandit
121
126
  continue-on-error: true
122
127
  shell: bash
123
- run: bandit -q -r src/${{ env.PACKAGE_MODULE }}
128
+ run: bandit -q -r ${{ env.SRC_PATH }}/${{ env.PACKAGE_MODULE }} ${{ env.BANDIT_SKIP_FLAG }}
124
129
 
125
130
  - name: Run pip-audit (vulnerability scan)
126
131
  id: pipaudit
@@ -128,12 +133,9 @@ jobs:
128
133
  shell: python
129
134
  run: |
130
135
  import subprocess, sys
131
- try:
132
- import tomllib
133
- except ModuleNotFoundError:
134
- import tomli as tomllib
135
- with open("pyproject.toml", "rb") as f:
136
- data = tomllib.load(f)
136
+ import rtoml
137
+ from pathlib import Path
138
+ data = rtoml.load(Path("pyproject.toml"))
137
139
  vulns = data.get("tool", {}).get("pip-audit", {}).get("ignore-vulns", [])
138
140
  cmd = ["pip-audit", "--skip-editable"]
139
141
  for v in vulns:
@@ -208,31 +210,9 @@ jobs:
208
210
  enable-cache: true
209
211
  prune-cache: false
210
212
 
211
- - name: Install tomli (Python < 3.11)
212
- shell: bash
213
- run: python -c "import tomllib" 2>/dev/null || uv pip install tomli --system
214
-
215
213
  - name: Extract project metadata
216
- shell: python
217
- run: |
218
- import os
219
- try:
220
- import tomllib
221
- except ModuleNotFoundError:
222
- import tomli as tomllib
223
-
224
- with open('pyproject.toml', 'rb') as f:
225
- data = tomllib.load(f)
226
- project = data['project']['name']
227
- module = project.replace('-', '_')
228
- dash = project.replace('_', '-')
229
- scripts = list(data['project'].get('scripts', {}).keys())
230
- cli_bin = scripts[0] if scripts else dash
231
-
232
- with open(os.environ['GITHUB_ENV'], 'a', encoding='utf-8') as env:
233
- env.write(f"PROJECT_NAME={project}\n")
234
- env.write(f"PACKAGE_MODULE={module}\n")
235
- env.write(f"CLI_BIN={cli_bin}\n")
214
+ id: metadata
215
+ uses: ./.github/actions/extract-metadata
236
216
 
237
217
  - name: Build wheel
238
218
  run: uv build
@@ -56,7 +56,7 @@ jobs:
56
56
  fi
57
57
 
58
58
  - name: Download artifacts
59
- uses: actions/download-artifact@v6
59
+ uses: actions/download-artifact@v7
60
60
  with:
61
61
  name: dist
62
62
  path: dist/
@@ -179,3 +179,4 @@ poetry.lock
179
179
  pdm.lock
180
180
  uv.lock
181
181
  /.github_bak/
182
+ prompts.md
@@ -2,12 +2,29 @@
2
2
 
3
3
  All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
4
4
 
5
+ ## [Unreleased]
6
+
7
+ ## [2.3.0] - 2026-02-13
8
+
9
+ ### Added
10
+ - `ExitCodeStyle` enum (`str, Enum`) replacing `Literal["errno", "sysexits"]` string literals, re-exported through the public API facade.
11
+ - New `cli/` package structure splitting the monolithic `cli.py` into `group.py`, `commands.py`, and `styling.py` with backward-compatible re-exports.
12
+
13
+ ### Changed
14
+ - Replaced `Mapping[str, object]` with typed `SessionOverrides` in `cli_session` and internal helpers for stricter type safety.
15
+ - Removed `_CONFIG_TRACEBACK` / `_CONFIG_TRACEBACK_FORCE_COLOR` string constants in favour of direct `SessionOverrides` key access.
16
+ - Migrated `scripts/` to external submodule; build automation now uses `uvx bmk`.
17
+ - Updated GitHub Actions CI/CD workflows and removed legacy backup workflow files.
18
+
19
+ ### Security
20
+ - Added CVE-2026-1703, CVE-2026-25990, and CVE-2026-26007 to pip-audit ignore list (transitive dev dependencies, not runtime).
5
21
 
6
22
  ## [2.2.4] - 2026-01-26
7
23
 
8
24
  ### Changed
9
25
  - Updated dependencies.
10
26
  - Excluded `scripts/` from pyright, pytest, and CI/CD test collection.
27
+ - Ctrl-C in scripts now exits with code 130 (POSIX SIGINT convention) instead of Click's default exit code 1.
11
28
 
12
29
  ## [2.2.3] - 2025-12-17
13
30
 
@@ -18,10 +18,10 @@ When working with Bash scripts:
18
18
  When working with Python code:
19
19
  - `core_programming_solid.md`
20
20
  - `python_solid_architecture_enforcer.md`
21
- - `python_clean_architecture.md`
21
+ - use skill `bx-python-clean-architecture`
22
22
  - `python_clean_code.md`
23
23
  - `python_small_functions_style.md`
24
- - `python_libraries_to_use.md`
24
+ - use skill `bx-python-libraries-to-use`
25
25
  - `python_data_architecture_enforcement.md`
26
26
 
27
27
  ### Additional Guidelines
@@ -136,7 +136,7 @@ Import rules (enforced by import-linter):
136
136
  - `core` cannot import from `application`, `adapters`, or `cli`
137
137
  - `application` cannot import from `cli`
138
138
 
139
- Apply principles from `python_clean_architecture.md` when designing and implementing features.
139
+ Apply principles using skill `bx-python-clean-architecture` when designing and implementing features.
140
140
 
141
141
  ## Security & Configuration
142
142