ghud 0.1.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.
@@ -0,0 +1,28 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.10", "3.11", "3.12"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Set up Python
20
+ uses: actions/setup-python@v5
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+
24
+ - name: Install dependencies
25
+ run: pip install -e ".[dev]"
26
+
27
+ - name: Run tests
28
+ run: pytest -v --tb=short
@@ -0,0 +1,47 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ id-token: write
9
+
10
+ jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+
16
+ - name: Set up Python
17
+ uses: actions/setup-python@v5
18
+ with:
19
+ python-version: "3.12"
20
+
21
+ - name: Install build tools
22
+ run: pip install build
23
+
24
+ - name: Build package
25
+ run: python -m build
26
+
27
+ - name: Upload artifacts
28
+ uses: actions/upload-artifact@v4
29
+ with:
30
+ name: dist
31
+ path: dist/
32
+
33
+ publish:
34
+ needs: build
35
+ runs-on: ubuntu-latest
36
+ environment: pypi
37
+ permissions:
38
+ id-token: write
39
+ steps:
40
+ - name: Download artifacts
41
+ uses: actions/download-artifact@v4
42
+ with:
43
+ name: dist
44
+ path: dist/
45
+
46
+ - name: Publish to PyPI
47
+ uses: pypa/gh-action-pypi-publish@release/v1
ghud-0.1.0/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .pytest_cache/
7
+ docs/_build/
8
+ *.egg
9
+ .venv/
@@ -0,0 +1,16 @@
1
+ version: 2
2
+
3
+ build:
4
+ os: ubuntu-22.04
5
+ tools:
6
+ python: "3.12"
7
+
8
+ sphinx:
9
+ configuration: docs/conf.py
10
+
11
+ python:
12
+ install:
13
+ - method: pip
14
+ path: .
15
+ extra_requirements:
16
+ - docs
ghud-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Teague Sterling
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
ghud-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,118 @@
1
+ Metadata-Version: 2.4
2
+ Name: ghud
3
+ Version: 0.1.0
4
+ Summary: GitHub Heads-Up Display — terminal dashboard for your portfolio repos
5
+ Project-URL: Homepage, https://github.com/teaguesterling/ghud
6
+ Project-URL: Documentation, https://ghud.readthedocs.io
7
+ Project-URL: Repository, https://github.com/teaguesterling/ghud
8
+ Project-URL: Issues, https://github.com/teaguesterling/ghud/issues
9
+ Author-email: Teague Sterling <teague@teaguesterling.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: cli,dashboard,github,rich,terminal
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Software Development :: Version Control :: Git
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: rich>=13.0
24
+ Requires-Dist: ruamel-yaml>=0.18
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest-cov; extra == 'dev'
27
+ Requires-Dist: pytest>=8.0; extra == 'dev'
28
+ Provides-Extra: docs
29
+ Requires-Dist: myst-parser; extra == 'docs'
30
+ Requires-Dist: sphinx-rtd-theme; extra == 'docs'
31
+ Requires-Dist: sphinx>=7.0; extra == 'docs'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # ghud
35
+
36
+ **GitHub Heads-Up Display** — a terminal dashboard for your portfolio repos.
37
+
38
+ [![PyPI version](https://img.shields.io/pypi/v/ghud)](https://pypi.org/project/ghud/)
39
+ [![Documentation](https://readthedocs.org/projects/ghud/badge/?version=latest)](https://ghud.readthedocs.io)
40
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
41
+
42
+ ghud gives you a single-command overview of your GitHub activity:
43
+
44
+ - **Important notifications** — review requests, mentions, assignments
45
+ - **Your open PRs** — with age and comment counts
46
+ - **Recently merged PRs** — what shipped this week
47
+ - **Issues from others** — on your portfolio repos
48
+ - **Other activity** — repos outside your portfolio
49
+
50
+ Plus a `discover` command to find repos missing from your portfolio config.
51
+
52
+ ## Installation
53
+
54
+ ```bash
55
+ pip install ghud
56
+ ```
57
+
58
+ Requires the [GitHub CLI](https://cli.github.com/) (`gh`) to be installed and authenticated.
59
+
60
+ ## Quick Start
61
+
62
+ ```bash
63
+ # Show your dashboard
64
+ ghud
65
+
66
+ # Include low-priority notifications
67
+ ghud --all
68
+
69
+ # Extend merged-PR lookback to 30 days
70
+ ghud --days 30
71
+
72
+ # Find repos not yet in your portfolio config
73
+ ghud discover --dry-run
74
+ ```
75
+
76
+ ## Configuration
77
+
78
+ ghud reads a `projects.yaml` file that lists your portfolio repos. It checks these locations:
79
+
80
+ 1. `~/Projects/pages/src/_data/projects.yaml`
81
+ 2. `/mnt/aux-data/teague/Projects/pages/src/_data/projects.yaml`
82
+
83
+ The YAML uses a nested category/subcategory/project structure. Repos in the `ignored` category are excluded from the dashboard.
84
+
85
+ ## Features
86
+
87
+ ### Responsive Layout
88
+
89
+ On wide terminals (>=120 columns), ghud uses a two-column layout:
90
+ - **Left:** things needing your attention (notifications, issues from others)
91
+ - **Right:** your activity (open PRs, recently merged)
92
+
93
+ Narrow terminals get a single-column stack.
94
+
95
+ ### Notification Filtering
96
+
97
+ By default, ghud shows only important notifications: `review_requested`, `mention`, `assign`, `team_mention`, `security_alert`. Use `--all` to include subscribed/comment notifications.
98
+
99
+ ### Repo Discovery
100
+
101
+ `ghud discover` queries your GitHub account for all repos and compares against your `projects.yaml`. New repos are listed (with `--dry-run`) or added to an `uncategorized` section for you to organize.
102
+
103
+ ### Performance
104
+
105
+ ghud fetches all data in ~2 seconds using concurrent API calls and GraphQL batching for per-repo issue queries.
106
+
107
+ ## Development
108
+
109
+ ```bash
110
+ git clone https://github.com/teaguesterling/ghud.git
111
+ cd ghud
112
+ pip install -e ".[dev]"
113
+ pytest
114
+ ```
115
+
116
+ ## License
117
+
118
+ MIT
ghud-0.1.0/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # ghud
2
+
3
+ **GitHub Heads-Up Display** — a terminal dashboard for your portfolio repos.
4
+
5
+ [![PyPI version](https://img.shields.io/pypi/v/ghud)](https://pypi.org/project/ghud/)
6
+ [![Documentation](https://readthedocs.org/projects/ghud/badge/?version=latest)](https://ghud.readthedocs.io)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+
9
+ ghud gives you a single-command overview of your GitHub activity:
10
+
11
+ - **Important notifications** — review requests, mentions, assignments
12
+ - **Your open PRs** — with age and comment counts
13
+ - **Recently merged PRs** — what shipped this week
14
+ - **Issues from others** — on your portfolio repos
15
+ - **Other activity** — repos outside your portfolio
16
+
17
+ Plus a `discover` command to find repos missing from your portfolio config.
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ pip install ghud
23
+ ```
24
+
25
+ Requires the [GitHub CLI](https://cli.github.com/) (`gh`) to be installed and authenticated.
26
+
27
+ ## Quick Start
28
+
29
+ ```bash
30
+ # Show your dashboard
31
+ ghud
32
+
33
+ # Include low-priority notifications
34
+ ghud --all
35
+
36
+ # Extend merged-PR lookback to 30 days
37
+ ghud --days 30
38
+
39
+ # Find repos not yet in your portfolio config
40
+ ghud discover --dry-run
41
+ ```
42
+
43
+ ## Configuration
44
+
45
+ ghud reads a `projects.yaml` file that lists your portfolio repos. It checks these locations:
46
+
47
+ 1. `~/Projects/pages/src/_data/projects.yaml`
48
+ 2. `/mnt/aux-data/teague/Projects/pages/src/_data/projects.yaml`
49
+
50
+ The YAML uses a nested category/subcategory/project structure. Repos in the `ignored` category are excluded from the dashboard.
51
+
52
+ ## Features
53
+
54
+ ### Responsive Layout
55
+
56
+ On wide terminals (>=120 columns), ghud uses a two-column layout:
57
+ - **Left:** things needing your attention (notifications, issues from others)
58
+ - **Right:** your activity (open PRs, recently merged)
59
+
60
+ Narrow terminals get a single-column stack.
61
+
62
+ ### Notification Filtering
63
+
64
+ By default, ghud shows only important notifications: `review_requested`, `mention`, `assign`, `team_mention`, `security_alert`. Use `--all` to include subscribed/comment notifications.
65
+
66
+ ### Repo Discovery
67
+
68
+ `ghud discover` queries your GitHub account for all repos and compares against your `projects.yaml`. New repos are listed (with `--dry-run`) or added to an `uncategorized` section for you to organize.
69
+
70
+ ### Performance
71
+
72
+ ghud fetches all data in ~2 seconds using concurrent API calls and GraphQL batching for per-repo issue queries.
73
+
74
+ ## Development
75
+
76
+ ```bash
77
+ git clone https://github.com/teaguesterling/ghud.git
78
+ cd ghud
79
+ pip install -e ".[dev]"
80
+ pytest
81
+ ```
82
+
83
+ ## License
84
+
85
+ MIT
@@ -0,0 +1,17 @@
1
+ API Reference
2
+ =============
3
+
4
+ .. automodule:: ghud.config
5
+ :members:
6
+
7
+ .. automodule:: ghud.github
8
+ :members:
9
+
10
+ .. automodule:: ghud.dashboard
11
+ :members:
12
+
13
+ .. automodule:: ghud.discover
14
+ :members:
15
+
16
+ .. automodule:: ghud.cli
17
+ :members:
@@ -0,0 +1,21 @@
1
+ """Sphinx configuration for ghud documentation."""
2
+
3
+ project = "ghud"
4
+ copyright = "2026, Teague Sterling"
5
+ author = "Teague Sterling"
6
+ release = "0.1.0"
7
+
8
+ extensions = [
9
+ "myst_parser",
10
+ "sphinx.ext.autodoc",
11
+ "sphinx.ext.napoleon",
12
+ ]
13
+
14
+ templates_path = ["_templates"]
15
+ exclude_patterns = ["_build"]
16
+
17
+ html_theme = "sphinx_rtd_theme"
18
+
19
+ myst_enable_extensions = [
20
+ "colon_fence",
21
+ ]
@@ -0,0 +1,27 @@
1
+ ghud — GitHub Heads-Up Display
2
+ ==============================
3
+
4
+ .. toctree::
5
+ :maxdepth: 2
6
+ :caption: Contents:
7
+
8
+ installation
9
+ usage
10
+ api
11
+
12
+ ghud gives you a single-command overview of your GitHub activity across all your portfolio repos.
13
+
14
+ .. code-block:: bash
15
+
16
+ $ ghud
17
+
18
+ Features
19
+ --------
20
+
21
+ - Important notifications (review requests, mentions, assignments)
22
+ - Your open PRs with age and comment counts
23
+ - Recently merged PRs
24
+ - Issues from others on your portfolio repos
25
+ - Repo discovery to keep your portfolio config complete
26
+ - Responsive two-column layout on wide terminals
27
+ - Fast: ~2 seconds using GraphQL batching
@@ -0,0 +1,31 @@
1
+ Installation
2
+ ============
3
+
4
+ Requirements
5
+ ------------
6
+
7
+ - Python 3.10+
8
+ - `GitHub CLI <https://cli.github.com/>`_ (``gh``) installed and authenticated
9
+
10
+ From PyPI
11
+ ---------
12
+
13
+ .. code-block:: bash
14
+
15
+ pip install ghud
16
+
17
+ From Source
18
+ -----------
19
+
20
+ .. code-block:: bash
21
+
22
+ git clone https://github.com/teaguesterling/ghud.git
23
+ cd ghud
24
+ pip install -e ".[dev]"
25
+
26
+ Verify
27
+ ------
28
+
29
+ .. code-block:: bash
30
+
31
+ ghud --help
@@ -0,0 +1,54 @@
1
+ Usage
2
+ =====
3
+
4
+ Dashboard
5
+ ---------
6
+
7
+ .. code-block:: bash
8
+
9
+ # Show your dashboard (default)
10
+ ghud
11
+
12
+ # Include low-priority notifications (subscribed, comment, etc.)
13
+ ghud --all
14
+
15
+ # Extend merged-PR lookback to 30 days
16
+ ghud --days 30
17
+
18
+ The dashboard shows five sections (empty sections are hidden):
19
+
20
+ 1. **Important Notifications** — review_requested, mention, assign, team_mention, security_alert
21
+ 2. **New Issues From Others** — open issues on your portfolio repos, excluding your own
22
+ 3. **Your Open PRs** — PRs you authored, with age and comment counts
23
+ 4. **Recently Merged** — your PRs merged within the lookback window
24
+ 5. **Other Activity** — notifications from repos not in your portfolio
25
+
26
+ On wide terminals (>=120 columns), sections are arranged in two columns:
27
+ attention-needed on the left, your activity on the right.
28
+
29
+ Discover
30
+ --------
31
+
32
+ .. code-block:: bash
33
+
34
+ # See what repos are missing from your portfolio config
35
+ ghud discover --dry-run
36
+
37
+ # Add missing repos to the 'uncategorized' section
38
+ ghud discover
39
+
40
+ The discover command queries your GitHub account for all repos and compares
41
+ against your ``projects.yaml``. New repos are added to an ``uncategorized``
42
+ section for you to organize later.
43
+
44
+ Configuration
45
+ -------------
46
+
47
+ ghud reads a ``projects.yaml`` file that lists your portfolio repos.
48
+ It checks these locations in order:
49
+
50
+ 1. ``~/Projects/pages/src/_data/projects.yaml``
51
+ 2. ``/mnt/aux-data/teague/Projects/pages/src/_data/projects.yaml``
52
+
53
+ The YAML uses a nested ``categories -> subcategories -> projects`` structure.
54
+ Repos in the ``ignored`` category are excluded from the dashboard.
@@ -0,0 +1,57 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "ghud"
7
+ version = "0.1.0"
8
+ description = "GitHub Heads-Up Display — terminal dashboard for your portfolio repos"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ { name = "Teague Sterling", email = "teague@teaguesterling.com" },
14
+ ]
15
+ keywords = ["github", "dashboard", "terminal", "cli", "rich"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Environment :: Console",
19
+ "Intended Audience :: Developers",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Topic :: Software Development :: Version Control :: Git",
26
+ ]
27
+ dependencies = [
28
+ "rich>=13.0",
29
+ "ruamel.yaml>=0.18",
30
+ ]
31
+
32
+ [project.scripts]
33
+ ghud = "ghud.cli:main"
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/teaguesterling/ghud"
37
+ Documentation = "https://ghud.readthedocs.io"
38
+ Repository = "https://github.com/teaguesterling/ghud"
39
+ Issues = "https://github.com/teaguesterling/ghud/issues"
40
+
41
+ [project.optional-dependencies]
42
+ dev = [
43
+ "pytest>=8.0",
44
+ "pytest-cov",
45
+ ]
46
+ docs = [
47
+ "sphinx>=7.0",
48
+ "sphinx-rtd-theme",
49
+ "myst-parser",
50
+ ]
51
+
52
+ [tool.hatch.build.targets.wheel]
53
+ packages = ["src/ghud"]
54
+
55
+ [tool.pytest.ini_options]
56
+ testpaths = ["tests"]
57
+ pythonpath = ["src"]
@@ -0,0 +1,3 @@
1
+ """ghud — GitHub Heads-Up Display."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,110 @@
1
+ """CLI argument parsing and command dispatch."""
2
+
3
+ import argparse
4
+ import sys
5
+ from concurrent.futures import ThreadPoolExecutor
6
+
7
+ from ghud.config import find_yaml_path, load_repos_from_yaml
8
+ from ghud.github import (
9
+ get_username,
10
+ get_notifications,
11
+ get_open_prs,
12
+ get_merged_prs,
13
+ get_issues_for_repos_batch,
14
+ )
15
+ from ghud.dashboard import render_dashboard
16
+
17
+
18
+ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
19
+ parser = argparse.ArgumentParser(
20
+ prog="ghud",
21
+ description="GitHub Heads-Up Display — terminal dashboard for your portfolio repos",
22
+ )
23
+ parser.add_argument("--all", action="store_true", help="Include all notifications")
24
+ parser.add_argument("--days", type=int, default=7, help="Lookback days for merged PRs")
25
+
26
+ subparsers = parser.add_subparsers(dest="command")
27
+
28
+ discover_parser = subparsers.add_parser("discover", help="Discover new repos")
29
+ discover_parser.add_argument("--dry-run", action="store_true", help="Show changes without writing")
30
+
31
+ return parser.parse_args(argv)
32
+
33
+
34
+ def _collect_other_activity(
35
+ notifications: list[dict], portfolio_repos: set[str]
36
+ ) -> tuple[list[dict], list[dict]]:
37
+ """Split notifications into portfolio and other activity.
38
+
39
+ Returns (portfolio_notifications, other_activity_summary).
40
+ """
41
+ portfolio = []
42
+ other: dict[str, dict] = {}
43
+
44
+ for n in notifications:
45
+ repo = n.get("repository", {}).get("full_name", "")
46
+ if repo in portfolio_repos:
47
+ portfolio.append(n)
48
+ else:
49
+ if repo not in other:
50
+ other[repo] = {"repo": repo, "count": 0, "reason_set": set()}
51
+ other[repo]["count"] += 1
52
+ other[repo]["reason_set"].add(n.get("reason", "unknown"))
53
+
54
+ other_summary = [
55
+ {"repo": v["repo"], "count": v["count"], "reasons": ", ".join(sorted(v["reason_set"]))}
56
+ for v in sorted(other.values(), key=lambda x: x["count"], reverse=True)
57
+ ]
58
+ return portfolio, other_summary
59
+
60
+
61
+ def run_dashboard(args: argparse.Namespace) -> None:
62
+ yaml_path = find_yaml_path()
63
+ if not yaml_path:
64
+ print("Error: Could not find projects.yaml", file=sys.stderr)
65
+ sys.exit(1)
66
+
67
+ repos = load_repos_from_yaml(yaml_path)
68
+ portfolio_set = set(repos)
69
+ username = get_username()
70
+
71
+ if not username:
72
+ print("Error: Could not determine GitHub username. Run 'gh auth login'.", file=sys.stderr)
73
+ sys.exit(1)
74
+
75
+ # Fetch all data concurrently: notifications, PRs, merged PRs, and issues
76
+ with ThreadPoolExecutor(max_workers=4) as pool:
77
+ notif_future = pool.submit(get_notifications)
78
+ prs_future = pool.submit(get_open_prs, username)
79
+ merged_future = pool.submit(get_merged_prs, username, args.days)
80
+ issues_future = pool.submit(get_issues_for_repos_batch, repos, username)
81
+
82
+ all_notifications = notif_future.result()
83
+ open_prs = prs_future.result()
84
+ merged_prs = merged_future.result()
85
+ other_issues = issues_future.result()
86
+ other_issues.sort(key=lambda x: x.get("createdAt", ""), reverse=True)
87
+
88
+ portfolio_notifications, other_activity = _collect_other_activity(
89
+ all_notifications, portfolio_set
90
+ )
91
+
92
+ data = {
93
+ "notifications": portfolio_notifications,
94
+ "open_prs": open_prs,
95
+ "merged_prs": merged_prs,
96
+ "other_issues": other_issues,
97
+ "other_activity": other_activity,
98
+ }
99
+
100
+ render_dashboard(data, show_all=args.all)
101
+
102
+
103
+ def main(argv: list[str] | None = None) -> None:
104
+ args = parse_args(argv)
105
+
106
+ if args.command == "discover":
107
+ from ghud.discover import run_discover
108
+ run_discover(args)
109
+ else:
110
+ run_dashboard(args)