verkit 0.2.1__tar.gz → 0.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.
verkit-0.3.0/AGENTS.md ADDED
@@ -0,0 +1,21 @@
1
+ # AGENTS.md
2
+
3
+ verkit: polyglot version inspector/promoter/tagger, plus shared Rich theme and
4
+ Textual key conventions used by the author's other TUIs.
5
+
6
+ ## Commands
7
+ - Setup: `uv sync`
8
+ - Test: `uv run pytest`
9
+ - Lint: `uv run ruff check .`
10
+ - Release: `verkit release <major|minor|patch>` (do not hand-edit versions)
11
+
12
+ ## Layout
13
+ - `src/verkit/agent_guide.md`: canonical agent conventions (shipped in wheel;
14
+ printed by `verkit conventions`). Edit here, not in consumers.
15
+ - `src/verkit/keys.py`: `VIM_BINDINGS`. `src/verkit/theme.py` + `theme.json`: theme
16
+ (kept in sync by `tests/test_theme.py`).
17
+ - `src/verkit/agent.py`: `conventions` / `init-agent` implementation.
18
+
19
+ ## Rules
20
+ - No Textual import in verkit; keep `keys.py` pure data.
21
+ - Changing a convention means updating `agent_guide.md`, `llms.txt`, README, and tests.
verkit-0.3.0/CLAUDE.md ADDED
@@ -0,0 +1 @@
1
+ @AGENTS.md
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: verkit
3
- Version: 0.2.1
3
+ Version: 0.3.0
4
4
  Summary: Polyglot project version inspector, promoter, tagger, and release workflow engine
5
5
  Author: Mark Stouffer
6
6
  License: MIT
@@ -122,3 +122,18 @@ $theme = Invoke-RestMethod `
122
122
  # $theme.theme.header_background_ansi -> ANSI 256 index 237 background escape
123
123
  # $theme.theme.header_background_rgb_hex -> "#3a3a3a"
124
124
  ```
125
+
126
+ ---
127
+
128
+ ## For AI Agents
129
+
130
+ Projects that depend on `verkit` should follow its conventions: vim-style
131
+ navigation (`from verkit.keys import VIM_BINDINGS`), the shared theme, and a
132
+ `mise`-only local dev override (PyPI release everywhere else).
133
+
134
+ ```bash
135
+ verkit conventions # print the guide (add --json for structured output)
136
+ verkit init-agent --mise # add pointer to AGENTS.md and a mise.toml template
137
+ ```
138
+
139
+ See also `AGENTS.md` and `llms.txt` in this repo.
@@ -112,3 +112,18 @@ $theme = Invoke-RestMethod `
112
112
  # $theme.theme.header_background_ansi -> ANSI 256 index 237 background escape
113
113
  # $theme.theme.header_background_rgb_hex -> "#3a3a3a"
114
114
  ```
115
+
116
+ ---
117
+
118
+ ## For AI Agents
119
+
120
+ Projects that depend on `verkit` should follow its conventions: vim-style
121
+ navigation (`from verkit.keys import VIM_BINDINGS`), the shared theme, and a
122
+ `mise`-only local dev override (PyPI release everywhere else).
123
+
124
+ ```bash
125
+ verkit conventions # print the guide (add --json for structured output)
126
+ verkit init-agent --mise # add pointer to AGENTS.md and a mise.toml template
127
+ ```
128
+
129
+ See also `AGENTS.md` and `llms.txt` in this repo.
verkit-0.3.0/llms.txt ADDED
@@ -0,0 +1,15 @@
1
+ # verkit
2
+
3
+ > Polyglot project version inspector, promoter, tagger and release CLI, plus the shared Rich theme and vim-style Textual key conventions for the author's Python TUIs. If your project depends on verkit, read the conventions guide first.
4
+
5
+ ## Agent guidance
6
+ - [Conventions guide](https://raw.githubusercontent.com/bizkite-co/verkit/main/src/verkit/agent_guide.md): vim navigation, theme, mise dev-vs-PyPI rule. Also `verkit conventions [--json]`.
7
+ - [AGENTS.md](https://raw.githubusercontent.com/bizkite-co/verkit/main/AGENTS.md): working on verkit itself.
8
+
9
+ ## Code
10
+ - [keys.py](https://raw.githubusercontent.com/bizkite-co/verkit/main/src/verkit/keys.py): `VIM_BINDINGS` for Textual `BINDINGS`.
11
+ - [theme.py](https://raw.githubusercontent.com/bizkite-co/verkit/main/src/verkit/theme.py): shared Rich theme.
12
+ - [theme.json](https://raw.githubusercontent.com/bizkite-co/verkit/main/src/verkit/theme.json): theme for non-Python consumers.
13
+
14
+ ## Optional
15
+ - [README](https://raw.githubusercontent.com/bizkite-co/verkit/main/README.md): CLI and API usage.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "verkit"
7
- version = "0.2.1"
7
+ version = "0.3.0"
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,75 @@
1
+ """Agent-facing commands: print conventions and wire them into a project."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from importlib import resources
7
+ from pathlib import Path
8
+
9
+ from verkit.keys import VIM_BINDINGS
10
+
11
+ MARKER = "<!-- verkit:agent-guide -->"
12
+
13
+ SNIPPET = f"""{MARKER}
14
+ ## verkit conventions
15
+
16
+ This project depends on `verkit`. Before touching TUI, theme, or dev-setup
17
+ code, run `verkit conventions` (or read `verkit/agent_guide.md` in the
18
+ installed package). Key rules: vim-style navigation via
19
+ `verkit.keys.VIM_BINDINGS`, shared theme via `verkit.theme`, and local verkit
20
+ dev override through `mise` only (never in `pyproject.toml`).
21
+ """
22
+
23
+ MISE_TEMPLATE = """# Generated by `verkit init-agent --mise`.
24
+ # Local checkout of verkit is used when it exists; CI/Docker/users get PyPI.
25
+ [env]
26
+ VERKIT_DEV = "{{ env.HOME }}/repos/verkit"
27
+ UV_NO_SYNC = "1" # keep uv from replacing the editable install with PyPI's
28
+
29
+ [tasks.install]
30
+ run = '''
31
+ uv sync
32
+ if [ -d "$VERKIT_DEV" ]; then uv pip install -e "$VERKIT_DEV"; fi
33
+ '''
34
+ """
35
+
36
+
37
+ def guide_text() -> str:
38
+ return resources.files("verkit").joinpath("agent_guide.md").read_text(encoding="utf-8")
39
+
40
+
41
+ def conventions_json() -> str:
42
+ return json.dumps(
43
+ {
44
+ "vim_bindings": [
45
+ {"key": k, "action": a, "description": d} for k, a, d in VIM_BINDINGS
46
+ ],
47
+ "import": "from verkit.keys import VIM_BINDINGS",
48
+ "theme_import": "from verkit.theme import DEFAULT as theme",
49
+ "dev_override": "mise.toml only; never pyproject.toml",
50
+ "guide": guide_text(),
51
+ },
52
+ indent=2,
53
+ )
54
+
55
+
56
+ def init_agent(directory: Path, mise: bool = False) -> list[str]:
57
+ """Idempotently add the pointer to AGENTS.md (and mise.toml if asked)."""
58
+ changed: list[str] = []
59
+ agents = directory / "AGENTS.md"
60
+ existing = agents.read_text(encoding="utf-8") if agents.exists() else ""
61
+ if MARKER not in existing:
62
+ sep = "\n" if existing and not existing.endswith("\n\n") else ""
63
+ agents.write_text(existing + sep + SNIPPET, encoding="utf-8")
64
+ changed.append(str(agents))
65
+ if mise:
66
+ target = directory / "mise.toml"
67
+ present = [f for f in (target, directory / "mise.verkit.toml") if f.exists()]
68
+ if any("VERKIT_DEV" in f.read_text(encoding="utf-8") for f in present):
69
+ return changed
70
+ if target.exists():
71
+ target = directory / "mise.verkit.toml" # never clobber; merge by hand
72
+ if not target.exists():
73
+ target.write_text(MISE_TEMPLATE, encoding="utf-8")
74
+ changed.append(str(target))
75
+ return changed
@@ -0,0 +1,63 @@
1
+ # verkit conventions for AI agents
2
+
3
+ verkit is the shared foundation for this developer's Python Textual/Rich TUIs
4
+ and CLIs. If the project you are working in depends on `verkit`, follow these
5
+ conventions. Print this guide any time with `verkit conventions`.
6
+
7
+ ## 1. Vim-style navigation (required for every TUI)
8
+
9
+ Every Textual TUI must support vim-style navigation **in addition to** the
10
+ arrow keys, never instead of them.
11
+
12
+ | Key | Action | Textual action |
13
+ | :-- | :-- | :-- |
14
+ | `j` / `k` | move down / up | `cursor_down` / `cursor_up` |
15
+ | `h` / `l` | move left / right | `cursor_left` / `cursor_right` |
16
+ | `g` / `G` | jump to top / bottom | `scroll_home` / `scroll_end` |
17
+ | `ctrl+d` / `ctrl+u` | half-page down / up | `page_down` / `page_up` |
18
+ | `/` | search / filter | app-specific |
19
+ | `escape` | go back / close | app-specific |
20
+ | `q` | quit | `quit` |
21
+
22
+ Do not hand-write these. Import them:
23
+
24
+ ```python
25
+ from verkit.keys import VIM_BINDINGS
26
+
27
+ class MyApp(App):
28
+ BINDINGS = [*VIM_BINDINGS, ("f", "filter", "Filter")]
29
+ ```
30
+
31
+ Show bindings in the `Footer`. Do not reassign these keys to other meanings.
32
+
33
+ ## 2. Theme
34
+
35
+ Use the shared Rich theme; never copy-paste style constants:
36
+
37
+ ```python
38
+ from verkit.theme import DEFAULT as theme
39
+ ```
40
+
41
+ Machine-readable mirror for non-Python consumers: `theme.json` in the package.
42
+
43
+ ## 3. Dev vs. released verkit (mise)
44
+
45
+ Rule: **in the local checkout, run the local verkit source; everywhere else
46
+ (CI, Docker, end users) install the latest release from PyPI.**
47
+
48
+ - `pyproject.toml` declares a plain dependency (`"verkit"`). Never add a
49
+ `path`/`editable` source there: it would leak to CI and to PyPI consumers.
50
+ - Local override lives only in the consumer's `mise.toml`, and is a no-op when
51
+ the local verkit checkout does not exist. Generate it with
52
+ `verkit init-agent --mise`. It sets `VERKIT_DEV` (default
53
+ `~/repos/verkit`) and installs it editable after `uv sync`.
54
+ - Use `mise run install` (not bare `uv sync`), and run tools with
55
+ `UV_NO_SYNC=1` (set by the mise template) so uv does not replace the
56
+ editable install with the PyPI release.
57
+
58
+ ## 4. Agent-friendly CLI
59
+
60
+ - `verkit conventions [--json]` prints this guide (or structured JSON).
61
+ - `verkit init-agent [--mise] [--dir PATH]` adds a pointer to this guide in the
62
+ project's `AGENTS.md` (idempotent) and, with `--mise`, writes the mise template.
63
+ - Errors exit non-zero, so agents can rely on exit codes.
@@ -1,8 +1,10 @@
1
1
  import argparse
2
2
  import sys
3
+ from pathlib import Path
3
4
 
4
5
  from rich.console import Console
5
6
 
7
+ from verkit.agent import conventions_json, guide_text, init_agent
6
8
  from verkit.inspector import display_version_info
7
9
  from verkit.promoter import promote_version
8
10
  from verkit.tagger import release_version, tag_version
@@ -47,6 +49,15 @@ def main():
47
49
  help="Promote and tag locally only",
48
50
  )
49
51
 
52
+ # verkit conventions [--json]
53
+ conv_p = subparsers.add_parser("conventions", help="Print conventions for AI agents")
54
+ conv_p.add_argument("--json", action="store_true", help="Structured output")
55
+
56
+ # verkit init-agent
57
+ init_p = subparsers.add_parser("init-agent", help="Add verkit guidance to a project")
58
+ init_p.add_argument("--dir", default=".", help="Project directory")
59
+ init_p.add_argument("--mise", action="store_true", help="Also write mise.toml template")
60
+
50
61
  args = parser.parse_args()
51
62
  console = Console()
52
63
 
@@ -55,7 +66,12 @@ def main():
55
66
  return
56
67
 
57
68
  try:
58
- if args.command == "promote":
69
+ if args.command == "conventions":
70
+ print(conventions_json() if args.json else guide_text())
71
+ elif args.command == "init-agent":
72
+ changed = init_agent(Path(args.dir), mise=args.mise)
73
+ console.print("\n".join(f"updated {c}" for c in changed) or "already up to date")
74
+ elif args.command == "promote":
59
75
  promote_version(args.part, console=console, allow_amend=getattr(args, "allow_amend", True))
60
76
  elif args.command == "tag":
61
77
  tag_version(console=console, push=getattr(args, "push", True))
@@ -0,0 +1,29 @@
1
+ """Canonical vim-style key bindings for Textual TUIs.
2
+
3
+ Pure data with no Textual import, so verkit does not depend on Textual.
4
+ Entries are ``(key, action, description)`` tuples, which is what Textual's
5
+ ``BINDINGS`` accepts directly::
6
+
7
+ from verkit.keys import VIM_BINDINGS
8
+
9
+ class MyApp(App):
10
+ BINDINGS = [*VIM_BINDINGS, ("f", "filter", "Filter")]
11
+
12
+ Arrow keys keep working through Textual's defaults; these add the vim keys.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ VIM_BINDINGS: list[tuple[str, str, str]] = [
18
+ ("j", "cursor_down", "Down"),
19
+ ("k", "cursor_up", "Up"),
20
+ ("h", "cursor_left", "Left"),
21
+ ("l", "cursor_right", "Right"),
22
+ ("g", "scroll_home", "Top"),
23
+ ("G", "scroll_end", "Bottom"),
24
+ ("ctrl+d", "page_down", "Page down"),
25
+ ("ctrl+u", "page_up", "Page up"),
26
+ ("q", "quit", "Quit"),
27
+ ]
28
+
29
+ __all__ = ["VIM_BINDINGS"]
@@ -0,0 +1,30 @@
1
+ import json
2
+
3
+ from verkit.agent import MARKER, conventions_json, guide_text, init_agent
4
+ from verkit.keys import VIM_BINDINGS
5
+
6
+
7
+ def test_guide_mentions_bindings_and_mise():
8
+ g = guide_text()
9
+ assert "VIM_BINDINGS" in g and "mise" in g
10
+
11
+
12
+ def test_bindings_shape_and_vim_keys():
13
+ assert all(len(b) == 3 for b in VIM_BINDINGS)
14
+ assert {"j", "k", "h", "l"} <= {b[0] for b in VIM_BINDINGS}
15
+
16
+
17
+ def test_json_output():
18
+ data = json.loads(conventions_json())
19
+ assert data["vim_bindings"][0]["key"] == "j"
20
+
21
+
22
+ def test_init_agent_idempotent_and_no_clobber(tmp_path):
23
+ (tmp_path / "AGENTS.md").write_text("# Mine\n")
24
+ assert init_agent(tmp_path, mise=True)
25
+ assert init_agent(tmp_path, mise=True) == []
26
+ text = (tmp_path / "AGENTS.md").read_text()
27
+ assert text.startswith("# Mine") and text.count(MARKER) == 1
28
+ (tmp_path / "mise.toml").write_text("[tools]\n")
29
+ init_agent(tmp_path, mise=True)
30
+ assert (tmp_path / "mise.toml").read_text() == "[tools]\n"
@@ -70,7 +70,7 @@ wheels = [
70
70
 
71
71
  [[package]]
72
72
  name = "verkit"
73
- version = "0.2.1"
73
+ version = "0.3.0"
74
74
  source = { editable = "." }
75
75
  dependencies = [
76
76
  { name = "rich" },
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