verkit 0.1.4__tar.gz → 0.2.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.
- {verkit-0.1.4 → verkit-0.2.1}/PKG-INFO +38 -2
- {verkit-0.1.4 → verkit-0.2.1}/README.md +36 -0
- {verkit-0.1.4 → verkit-0.2.1}/pyproject.toml +1 -1
- verkit-0.2.1/src/verkit/__init__.py +28 -0
- {verkit-0.1.4 → verkit-0.2.1}/src/verkit/cli.py +2 -5
- {verkit-0.1.4 → verkit-0.2.1}/src/verkit/inspector.py +52 -0
- {verkit-0.1.4 → verkit-0.2.1}/src/verkit/promoter.py +4 -2
- verkit-0.2.1/src/verkit/py.typed +0 -0
- verkit-0.2.1/src/verkit/theme.json +18 -0
- verkit-0.2.1/src/verkit/theme.py +55 -0
- verkit-0.2.1/tests/test_theme.py +38 -0
- {verkit-0.1.4 → verkit-0.2.1}/uv.lock +1 -1
- verkit-0.1.4/src/verkit/__init__.py +0 -14
- {verkit-0.1.4 → verkit-0.2.1}/.github/workflows/ci.yml +0 -0
- {verkit-0.1.4 → verkit-0.2.1}/.github/workflows/publish.yml +0 -0
- {verkit-0.1.4 → verkit-0.2.1}/.gitignore +0 -0
- {verkit-0.1.4 → verkit-0.2.1}/src/verkit/tagger.py +0 -0
- {verkit-0.1.4 → verkit-0.2.1}/tests/test_inspector.py +0 -0
- {verkit-0.1.4 → verkit-0.2.1}/tests/test_promoter.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: verkit
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Polyglot project version inspector, promoter, tagger, and release workflow engine
|
|
5
5
|
Author: Mark Stouffer
|
|
6
6
|
License: MIT
|
|
@@ -86,3 +86,39 @@ tag_name = verkit.tag_version(push=True)
|
|
|
86
86
|
# 4. Atomic release
|
|
87
87
|
verkit.release_version("patch", push=True)
|
|
88
88
|
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Shared Terminal Theme
|
|
93
|
+
|
|
94
|
+
`verkit` publishes the canonical Rich theme used across this developer's
|
|
95
|
+
CLIs (`task-agent`, `multi-agent-registry`, ...). It is **opt-in** — verkit
|
|
96
|
+
never applies the theme for you; consumers import it and apply it to their
|
|
97
|
+
own `Table`/`Panel` objects:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from rich.console import Console
|
|
101
|
+
from rich.table import Table
|
|
102
|
+
from verkit.theme import DEFAULT as theme
|
|
103
|
+
|
|
104
|
+
console = Console()
|
|
105
|
+
table = Table(
|
|
106
|
+
title="Portfolio",
|
|
107
|
+
box=theme.table_box, # borderless
|
|
108
|
+
header_style=theme.header_style, # "on grey23"
|
|
109
|
+
padding=theme.table_padding, # (0, 2, 0, 0)
|
|
110
|
+
)
|
|
111
|
+
console.print(table)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The theme is a frozen dataclass (`verkit.theme.Theme`); `DEFAULT` is the
|
|
115
|
+
canonical instance. Non-Python consumers (e.g. PowerShell scripts) read the
|
|
116
|
+
machine-readable mirror, which stays in sync via `tests/test_theme.py`:
|
|
117
|
+
|
|
118
|
+
```powershell
|
|
119
|
+
$theme = Invoke-RestMethod `
|
|
120
|
+
https://raw.githubusercontent.com/bizkite-co/verkit/main/src/verkit/theme.json
|
|
121
|
+
# $theme.theme.header_style -> "on grey23"
|
|
122
|
+
# $theme.theme.header_background_ansi -> ANSI 256 index 237 background escape
|
|
123
|
+
# $theme.theme.header_background_rgb_hex -> "#3a3a3a"
|
|
124
|
+
```
|
|
@@ -76,3 +76,39 @@ tag_name = verkit.tag_version(push=True)
|
|
|
76
76
|
# 4. Atomic release
|
|
77
77
|
verkit.release_version("patch", push=True)
|
|
78
78
|
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Shared Terminal Theme
|
|
83
|
+
|
|
84
|
+
`verkit` publishes the canonical Rich theme used across this developer's
|
|
85
|
+
CLIs (`task-agent`, `multi-agent-registry`, ...). It is **opt-in** — verkit
|
|
86
|
+
never applies the theme for you; consumers import it and apply it to their
|
|
87
|
+
own `Table`/`Panel` objects:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from rich.console import Console
|
|
91
|
+
from rich.table import Table
|
|
92
|
+
from verkit.theme import DEFAULT as theme
|
|
93
|
+
|
|
94
|
+
console = Console()
|
|
95
|
+
table = Table(
|
|
96
|
+
title="Portfolio",
|
|
97
|
+
box=theme.table_box, # borderless
|
|
98
|
+
header_style=theme.header_style, # "on grey23"
|
|
99
|
+
padding=theme.table_padding, # (0, 2, 0, 0)
|
|
100
|
+
)
|
|
101
|
+
console.print(table)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The theme is a frozen dataclass (`verkit.theme.Theme`); `DEFAULT` is the
|
|
105
|
+
canonical instance. Non-Python consumers (e.g. PowerShell scripts) read the
|
|
106
|
+
machine-readable mirror, which stays in sync via `tests/test_theme.py`:
|
|
107
|
+
|
|
108
|
+
```powershell
|
|
109
|
+
$theme = Invoke-RestMethod `
|
|
110
|
+
https://raw.githubusercontent.com/bizkite-co/verkit/main/src/verkit/theme.json
|
|
111
|
+
# $theme.theme.header_style -> "on grey23"
|
|
112
|
+
# $theme.theme.header_background_ansi -> ANSI 256 index 237 background escape
|
|
113
|
+
# $theme.theme.header_background_rgb_hex -> "#3a3a3a"
|
|
114
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Polyglot project version inspector, promoter, tagger, and release engine."""
|
|
2
|
+
|
|
3
|
+
from verkit.inspector import (
|
|
4
|
+
VersionInfo,
|
|
5
|
+
display_version_info,
|
|
6
|
+
get_installed_version,
|
|
7
|
+
get_latest_pypi_version,
|
|
8
|
+
inspect_committed,
|
|
9
|
+
inspect_project,
|
|
10
|
+
)
|
|
11
|
+
from verkit.promoter import promote_version
|
|
12
|
+
from verkit.tagger import release_version, tag_version
|
|
13
|
+
from verkit.theme import DEFAULT, Theme
|
|
14
|
+
|
|
15
|
+
__version__ = "0.2.0"
|
|
16
|
+
__all__ = [
|
|
17
|
+
"DEFAULT",
|
|
18
|
+
"Theme",
|
|
19
|
+
"VersionInfo",
|
|
20
|
+
"display_version_info",
|
|
21
|
+
"get_installed_version",
|
|
22
|
+
"get_latest_pypi_version",
|
|
23
|
+
"inspect_committed",
|
|
24
|
+
"inspect_project",
|
|
25
|
+
"promote_version",
|
|
26
|
+
"release_version",
|
|
27
|
+
"tag_version",
|
|
28
|
+
]
|
|
@@ -3,7 +3,7 @@ import sys
|
|
|
3
3
|
|
|
4
4
|
from rich.console import Console
|
|
5
5
|
|
|
6
|
-
from verkit.inspector import
|
|
6
|
+
from verkit.inspector import display_version_info
|
|
7
7
|
from verkit.promoter import promote_version
|
|
8
8
|
from verkit.tagger import release_version, tag_version
|
|
9
9
|
|
|
@@ -51,10 +51,7 @@ def main():
|
|
|
51
51
|
console = Console()
|
|
52
52
|
|
|
53
53
|
if not args.command or args.command == "inspect":
|
|
54
|
-
|
|
55
|
-
committed = inspect_committed()
|
|
56
|
-
console.print(f"[bold blue]Working version:[/bold blue] {info.version} (from {info.source or 'unknown'})")
|
|
57
|
-
console.print(f"[dim]Committed version (HEAD):[/dim] {committed.version}")
|
|
54
|
+
display_version_info(console, "verkit")
|
|
58
55
|
return
|
|
59
56
|
|
|
60
57
|
try:
|
|
@@ -1,11 +1,63 @@
|
|
|
1
|
+
import importlib.metadata
|
|
1
2
|
import json
|
|
2
3
|
import os
|
|
3
4
|
import re
|
|
4
5
|
import subprocess
|
|
6
|
+
import urllib.request
|
|
5
7
|
from dataclasses import dataclass
|
|
6
8
|
from pathlib import Path
|
|
7
9
|
from typing import Optional
|
|
8
10
|
|
|
11
|
+
from rich.console import Console
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_installed_version(package_name: str) -> str:
|
|
15
|
+
"""Read the installed package version via importlib.metadata."""
|
|
16
|
+
try:
|
|
17
|
+
return importlib.metadata.version(package_name)
|
|
18
|
+
except Exception:
|
|
19
|
+
return "unknown"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_latest_pypi_version(package_name: str, timeout: int = 4) -> Optional[str]:
|
|
23
|
+
"""Fetch the latest version of a package from PyPI."""
|
|
24
|
+
url = f"https://pypi.org/pypi/{package_name}/json"
|
|
25
|
+
try:
|
|
26
|
+
with urllib.request.urlopen(url, timeout=timeout) as response:
|
|
27
|
+
data = json.load(response)
|
|
28
|
+
return data["info"]["version"]
|
|
29
|
+
except Exception:
|
|
30
|
+
return None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def display_version_info(
|
|
34
|
+
console: Console,
|
|
35
|
+
package_name: str,
|
|
36
|
+
root: Optional[Path] = None,
|
|
37
|
+
upgrade_cmd: Optional[str] = None,
|
|
38
|
+
):
|
|
39
|
+
"""Display running, PyPI, and local project version information."""
|
|
40
|
+
tool_v = get_installed_version(package_name)
|
|
41
|
+
console.print(f"[bold blue]Running version:[/bold blue] {tool_v}")
|
|
42
|
+
|
|
43
|
+
latest_v = get_latest_pypi_version(package_name)
|
|
44
|
+
if latest_v:
|
|
45
|
+
if latest_v != tool_v:
|
|
46
|
+
console.print(f"[bold yellow]Latest PyPI version:[/bold yellow] {latest_v}")
|
|
47
|
+
if upgrade_cmd:
|
|
48
|
+
console.print(f"[dim]Run [bold]{upgrade_cmd}[/bold] to upgrade.[/dim]")
|
|
49
|
+
else:
|
|
50
|
+
console.print(f"[dim]Latest PyPI version:[/dim] {latest_v} (up to date)")
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
info = get_project_version(root)
|
|
54
|
+
if info.version != "unknown":
|
|
55
|
+
console.print(
|
|
56
|
+
f"[dim]Local project version:[/dim] {info.version} (from {info.source})"
|
|
57
|
+
)
|
|
58
|
+
except Exception:
|
|
59
|
+
pass
|
|
60
|
+
|
|
9
61
|
|
|
10
62
|
@dataclass
|
|
11
63
|
class VersionInfo:
|
|
@@ -235,7 +235,9 @@ def _commit_version_bump(
|
|
|
235
235
|
if msg_res.returncode == 0
|
|
236
236
|
else "chore: bump version"
|
|
237
237
|
)
|
|
238
|
-
commit_res = _git(
|
|
238
|
+
commit_res = _git(
|
|
239
|
+
"commit", "--no-verify", "--amend", "-m", existing_msg, cwd=git_root
|
|
240
|
+
)
|
|
239
241
|
if commit_res.returncode != 0:
|
|
240
242
|
err = (commit_res.stderr or commit_res.stdout or "").strip()
|
|
241
243
|
raise RuntimeError(f"Failed to amend version bump: {err}")
|
|
@@ -246,7 +248,7 @@ def _commit_version_bump(
|
|
|
246
248
|
|
|
247
249
|
if not amend:
|
|
248
250
|
msg = f"chore(release): v{new_v}"
|
|
249
|
-
commit_res = _git("commit", "-m", msg, cwd=git_root)
|
|
251
|
+
commit_res = _git("commit", "--no-verify", "-m", msg, cwd=git_root)
|
|
250
252
|
if commit_res.returncode != 0:
|
|
251
253
|
err = (commit_res.stderr or commit_res.stdout or "").strip()
|
|
252
254
|
if "nothing to commit" in err.lower():
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "verkit-grey",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"description": "Shared Rich terminal theme for tables and panels across this developer's Python CLIs (task-agent, multi-agent-registry, ...). Source of truth is src/verkit/theme.py (the Theme dataclass); this JSON mirrors Theme.DEFAULT for non-Python consumers and is kept in sync by tests/test_theme.py.",
|
|
5
|
+
"adoption": {
|
|
6
|
+
"python": "from verkit.theme import DEFAULT as theme",
|
|
7
|
+
"powershell": "$theme = Invoke-RestMethod '<raw URL of this file>'; $theme.theme",
|
|
8
|
+
"note": "Opt-in only: verkit publishes the theme but never applies it for you."
|
|
9
|
+
},
|
|
10
|
+
"theme": {
|
|
11
|
+
"table_box": null,
|
|
12
|
+
"panel_box": "MINIMAL",
|
|
13
|
+
"table_padding": [0, 2, 0, 0],
|
|
14
|
+
"header_style": "on grey23",
|
|
15
|
+
"header_background_ansi": "\u001b[48;5;237m",
|
|
16
|
+
"header_background_rgb_hex": "#3a3a3a"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Shared visual theme for Rich terminal output across client CLIs.
|
|
2
|
+
|
|
3
|
+
This module is a *convention carrier*, not a mandate. The theme is published
|
|
4
|
+
here so a client project can opt in with a one-line import instead of
|
|
5
|
+
maintaining its own copy; importing it is never forced on consumers.
|
|
6
|
+
|
|
7
|
+
Adoption hint (Python)::
|
|
8
|
+
|
|
9
|
+
from verkit.theme import DEFAULT as theme
|
|
10
|
+
|
|
11
|
+
table = Table(
|
|
12
|
+
title="...",
|
|
13
|
+
box=theme.table_box,
|
|
14
|
+
header_style=theme.header_style,
|
|
15
|
+
padding=theme.table_padding,
|
|
16
|
+
)
|
|
17
|
+
console.print(Panel(..., box=theme.panel_box))
|
|
18
|
+
|
|
19
|
+
Because ``Theme`` is a frozen dataclass, ``DEFAULT`` can be shared or
|
|
20
|
+
subclassed without risk of accidental mutation.
|
|
21
|
+
|
|
22
|
+
Non-Python consumers (e.g. PowerShell scripts) should read the machine
|
|
23
|
+
readable mirror at ``src/verkit/theme.json`` instead of re-deriving styles:
|
|
24
|
+
|
|
25
|
+
$theme = Invoke-RestMethod `
|
|
26
|
+
https://raw.githubusercontent.com/bizkite-co/verkit/main/src/verkit/theme.json
|
|
27
|
+
|
|
28
|
+
The JSON and this dataclass are kept in sync by ``tests/test_theme.py``.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from __future__ import annotations
|
|
32
|
+
|
|
33
|
+
from dataclasses import dataclass
|
|
34
|
+
|
|
35
|
+
from rich import box as rich_box
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass(frozen=True)
|
|
39
|
+
class Theme:
|
|
40
|
+
"""Visual theme for Rich terminal output (tables, panels).
|
|
41
|
+
|
|
42
|
+
Defaults render tables and panels in the compact report style shared
|
|
43
|
+
across this developer's CLIs: borderless tables, a minimal panel border,
|
|
44
|
+
and a subtle grey header band (ANSI 256 index 237).
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
table_box: rich_box.Box | None = None
|
|
48
|
+
panel_box: rich_box.Box = rich_box.MINIMAL
|
|
49
|
+
table_padding: tuple[int, int, int, int] = (0, 2, 0, 0)
|
|
50
|
+
header_style: str = "on grey23"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
#: The canonical theme. Client CLIs opt in with ``from verkit.theme import
|
|
54
|
+
#: DEFAULT``.
|
|
55
|
+
DEFAULT = Theme()
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from rich import box as rich_box
|
|
5
|
+
|
|
6
|
+
from verkit.theme import DEFAULT, Theme
|
|
7
|
+
|
|
8
|
+
THEME_JSON = Path(__file__).resolve().parent.parent / "src" / "verkit" / "theme.json"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_default_is_theme():
|
|
12
|
+
assert isinstance(DEFAULT, Theme)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_default_values():
|
|
16
|
+
assert DEFAULT.table_box is None
|
|
17
|
+
assert DEFAULT.panel_box is rich_box.MINIMAL
|
|
18
|
+
assert DEFAULT.table_padding == (0, 2, 0, 0)
|
|
19
|
+
assert DEFAULT.header_style == "on grey23"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_theme_json_matches_default():
|
|
23
|
+
data = json.loads(THEME_JSON.read_text(encoding="utf-8"))
|
|
24
|
+
theme = data["theme"]
|
|
25
|
+
assert theme["table_box"] is None
|
|
26
|
+
assert theme["panel_box"] == "MINIMAL"
|
|
27
|
+
assert tuple(theme["table_padding"]) == DEFAULT.table_padding
|
|
28
|
+
assert theme["header_style"] == DEFAULT.header_style
|
|
29
|
+
assert theme["header_background_ansi"] == "\x1b[48;5;237m"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_theme_is_frozen():
|
|
33
|
+
try:
|
|
34
|
+
DEFAULT.table_padding = (1, 1, 1, 1)
|
|
35
|
+
except AttributeError:
|
|
36
|
+
pass
|
|
37
|
+
else:
|
|
38
|
+
raise AssertionError("Theme should be immutable")
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
"""Polyglot project version inspector, promoter, tagger, and release engine."""
|
|
2
|
-
|
|
3
|
-
from verkit.inspector import VersionInfo, inspect_project, inspect_committed
|
|
4
|
-
from verkit.promoter import promote_version
|
|
5
|
-
from verkit.tagger import tag_version
|
|
6
|
-
|
|
7
|
-
__version__ = "0.1.0"
|
|
8
|
-
__all__ = [
|
|
9
|
-
"VersionInfo",
|
|
10
|
-
"inspect_project",
|
|
11
|
-
"inspect_committed",
|
|
12
|
-
"promote_version",
|
|
13
|
-
"tag_version",
|
|
14
|
-
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|