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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: verkit
3
- Version: 0.1.4
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
+ ```
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "verkit"
7
- version = "0.1.4"
7
+ version = "0.2.1"
8
8
  description = "Polyglot project version inspector, promoter, tagger, and release workflow engine"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -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 inspect_committed, inspect_project
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
- info = inspect_project()
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("commit", "--amend", "-m", existing_msg, cwd=git_root)
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")
@@ -70,7 +70,7 @@ wheels = [
70
70
 
71
71
  [[package]]
72
72
  name = "verkit"
73
- version = "0.1.4"
73
+ version = "0.2.1"
74
74
  source = { editable = "." }
75
75
  dependencies = [
76
76
  { name = "rich" },
@@ -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