gitroster 0.2.0__py3-none-any.whl
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.
- gitroster/__init__.py +1 -0
- gitroster/__main__.py +4 -0
- gitroster/agent.py +157 -0
- gitroster/cli.py +43 -0
- gitroster/demo.py +140 -0
- gitroster/deps.py +207 -0
- gitroster/export.py +40 -0
- gitroster/opener.py +218 -0
- gitroster/pathscan.py +34 -0
- gitroster/procs.py +179 -0
- gitroster/repoinfo.py +228 -0
- gitroster/scanner.py +454 -0
- gitroster/server.py +234 -0
- gitroster/static/icon.svg +12 -0
- gitroster/static/index.html +833 -0
- gitroster/store.py +80 -0
- gitroster-0.2.0.dist-info/METADATA +138 -0
- gitroster-0.2.0.dist-info/RECORD +22 -0
- gitroster-0.2.0.dist-info/WHEEL +5 -0
- gitroster-0.2.0.dist-info/entry_points.txt +2 -0
- gitroster-0.2.0.dist-info/licenses/LICENSE +9 -0
- gitroster-0.2.0.dist-info/top_level.txt +1 -0
gitroster/store.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""Small JSON persistence: user notes/flags and the last scan."""
|
|
2
|
+
import hashlib
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
import threading
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _dir(kind):
|
|
11
|
+
"""Per-OS config/state folder: XDG on Linux, Application Support on macOS, AppData on Windows."""
|
|
12
|
+
home = Path.home()
|
|
13
|
+
if sys.platform == "win32":
|
|
14
|
+
base = os.environ.get("APPDATA" if kind == "config" else "LOCALAPPDATA") or str(home / "AppData" / ("Roaming" if kind == "config" else "Local"))
|
|
15
|
+
elif sys.platform == "darwin":
|
|
16
|
+
base = str(home / "Library" / "Application Support")
|
|
17
|
+
else:
|
|
18
|
+
base = os.environ.get("XDG_CONFIG_HOME" if kind == "config" else "XDG_STATE_HOME") or str(home / (".config" if kind == "config" else ".local/state"))
|
|
19
|
+
d = Path(base) / "gitroster"
|
|
20
|
+
if sys.platform in ("win32", "darwin") and kind == "state":
|
|
21
|
+
d = d / "state"
|
|
22
|
+
d.mkdir(parents=True, exist_ok=True)
|
|
23
|
+
return d
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Store:
|
|
27
|
+
def __init__(self, config_dir=None, state_dir=None):
|
|
28
|
+
self.config = Path(config_dir) if config_dir else _dir("config")
|
|
29
|
+
self.state = Path(state_dir) if state_dir else _dir("state")
|
|
30
|
+
self.config.mkdir(parents=True, exist_ok=True)
|
|
31
|
+
self.state.mkdir(parents=True, exist_ok=True)
|
|
32
|
+
self.lock = threading.Lock()
|
|
33
|
+
|
|
34
|
+
def _load(self, path):
|
|
35
|
+
try:
|
|
36
|
+
return json.loads(path.read_text())
|
|
37
|
+
except (OSError, ValueError):
|
|
38
|
+
return {}
|
|
39
|
+
|
|
40
|
+
def _save(self, path, data):
|
|
41
|
+
tmp = path.with_suffix(".tmp")
|
|
42
|
+
tmp.write_text(json.dumps(data))
|
|
43
|
+
tmp.replace(path)
|
|
44
|
+
|
|
45
|
+
def meta(self):
|
|
46
|
+
return self._load(self.config / "meta.json")
|
|
47
|
+
|
|
48
|
+
def update_meta(self, repo_path, **fields):
|
|
49
|
+
allowed = {"note", "pinned", "ignored", "summary"}
|
|
50
|
+
with self.lock:
|
|
51
|
+
data = self._load(self.config / "meta.json")
|
|
52
|
+
entry = data.setdefault(repo_path, {})
|
|
53
|
+
entry.update({k: v for k, v in fields.items() if k in allowed})
|
|
54
|
+
self._save(self.config / "meta.json", data)
|
|
55
|
+
return entry
|
|
56
|
+
|
|
57
|
+
def settings(self):
|
|
58
|
+
return self._load(self.config / "settings.json")
|
|
59
|
+
|
|
60
|
+
def update_settings(self, **fields):
|
|
61
|
+
allowed = {"editor", "editor_custom", "terminal", "theme", "agent", "agent_custom"}
|
|
62
|
+
with self.lock:
|
|
63
|
+
data = self._load(self.config / "settings.json")
|
|
64
|
+
data.update({k: v for k, v in fields.items() if k in allowed})
|
|
65
|
+
self._save(self.config / "settings.json", data)
|
|
66
|
+
return data
|
|
67
|
+
|
|
68
|
+
def cached_scan(self):
|
|
69
|
+
return self._load(self.state / "scan.json")
|
|
70
|
+
|
|
71
|
+
def save_scan(self, scan):
|
|
72
|
+
with self.lock:
|
|
73
|
+
self._save(self.state / "scan.json", scan)
|
|
74
|
+
|
|
75
|
+
def log_path(self, repo_path):
|
|
76
|
+
"""One log per repo folder; the hash keeps two repos with the same folder name apart."""
|
|
77
|
+
d = self.state / "logs"
|
|
78
|
+
d.mkdir(exist_ok=True)
|
|
79
|
+
key = hashlib.sha1(str(repo_path).encode()).hexdigest()[:8]
|
|
80
|
+
return d / f"{Path(repo_path).name}-{key}.log"
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gitroster
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Find the repos, virtual envs and open ports you forgot about, and how to run them.
|
|
5
|
+
Author: firatsahn
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/firatsahn/gitroster
|
|
8
|
+
Project-URL: Source, https://github.com/firatsahn/gitroster
|
|
9
|
+
Project-URL: Issues, https://github.com/firatsahn/gitroster/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/firatsahn/gitroster/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: developer-tools,git,ports,virtualenv,dashboard,local-first
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Web Environment
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Operating System :: MacOS
|
|
18
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Topic :: Software Development
|
|
21
|
+
Requires-Python: >=3.9
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
<p align="center">
|
|
27
|
+
<img src="https://raw.githubusercontent.com/firatsahn/gitroster/main/gitroster/static/icon.svg" width="72" alt="gitroster logo">
|
|
28
|
+
</p>
|
|
29
|
+
|
|
30
|
+
<h1 align="center">gitroster</h1>
|
|
31
|
+
|
|
32
|
+
<p align="center">
|
|
33
|
+
<b>A roster of every git repo on your machine: yours, forks and clones.<br>What each one is, what's running, and how to run it.</b>
|
|
34
|
+
</p>
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
<p align="center">
|
|
39
|
+
<img src="https://raw.githubusercontent.com/firatsahn/gitroster/main/docs/home-light.png" alt="gitroster: a list of repos with running ports, uncommitted work, an AI summary and a note" width="860">
|
|
40
|
+
</p>
|
|
41
|
+
|
|
42
|
+
You clone a lot of open source projects, fork some, and write your own. Months later you have no idea which ones are still on disk, which are running in the background, which port belongs to what, or how you started them. gitroster scans your folders and puts it all on one page.
|
|
43
|
+
|
|
44
|
+
## Quick start (web, recommended)
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install gitroster # or: pipx install gitroster
|
|
48
|
+
gitroster ~/projects # then open http://127.0.0.1:8765
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
From source, without installing:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
git clone https://github.com/firatsahn/gitroster && cd gitroster
|
|
55
|
+
python3 -m gitroster ~/projects
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Want to look around first? `gitroster --demo` shows sample repos and touches nothing on your machine. Running, stopping and opening are switched off in the demo.
|
|
59
|
+
|
|
60
|
+
### Desktop app (Electron)
|
|
61
|
+
|
|
62
|
+
Prefer a window over a browser tab? The same UI runs in an Electron shell on Windows, macOS and Linux:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
cd electron && npm install && npm start
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
It starts the local server on a free port and stops it when you close the window. It needs Python 3.9+ on the machine (set `GITROSTER_PYTHON` if it is not on your PATH). It scans `~/projects`, or your home folder if that does not exist; set `GITROSTER_ROOTS` to scan other folders. `npm run dist` builds an installer with electron-builder.
|
|
69
|
+
|
|
70
|
+
### Platforms
|
|
71
|
+
|
|
72
|
+
Linux, macOS and Windows are supported. Ports come from `ss` (Linux), `lsof` (macOS) or `netstat` (Windows). On Windows a process's working directory is not readable, so ports are matched to repos by the command line only.
|
|
73
|
+
|
|
74
|
+
Scan several folders at once with `gitroster ~/projects ~/tools`. Without arguments it scans your home folder. Use `gitroster --json` to print a scan for scripts.
|
|
75
|
+
|
|
76
|
+
## What you get
|
|
77
|
+
|
|
78
|
+
**Repos**
|
|
79
|
+
- Every git repo, with last commit, branch, size on disk and README summary
|
|
80
|
+
- Sorted by origin: **mine** (you authored commits), **fork** (has an `upstream` remote), **clone** (someone else's) and **local** (no remote)
|
|
81
|
+
- Flags for **uncommitted changes**, **unpushed commits**, **no remote** and **dormant** (no commit in 90+ days and nothing running)
|
|
82
|
+
- Notes, pin and ignore, kept in `~/.config/gitroster/` (`~/Library/Application Support/gitroster` on macOS, `%APPDATA%\gitroster` on Windows)
|
|
83
|
+
|
|
84
|
+
**Look inside any repo**
|
|
85
|
+
- A detail page per repo: overview (languages, contributors linked to GitHub, tags, most changed files, README), file browser with a viewer, commit history with a graph and per-commit diffs, branches, dependencies
|
|
86
|
+
- **Search** code, file names and commit messages across every repo at once (plain text or regex)
|
|
87
|
+
- Search also finds **packages**: which repo uses a package and at which version, flagged when versions differ between repos
|
|
88
|
+
- **Related repos**: copies of the same remote, and local repos that depend on each other
|
|
89
|
+
- Everything is read-only
|
|
90
|
+
|
|
91
|
+
**Work you might forget**
|
|
92
|
+
- Stashes, branches that exist only on this machine or are not merged yet, and extra worktrees, with filters for each
|
|
93
|
+
- A commit graph of every branch (click a branch to jump to it)
|
|
94
|
+
- Light, dark or system theme in Settings
|
|
95
|
+
- One-click open in your editor, terminal or file manager. Settings lists the editors (VS Code, Cursor, PyCharm, IntelliJ, Zed, Sublime and more) and terminals installed on your machine so you can pick one, or set a custom command
|
|
96
|
+
|
|
97
|
+
<p align="center">
|
|
98
|
+
<img src="https://raw.githubusercontent.com/firatsahn/gitroster/main/docs/detail.png" alt="Repo detail page with an AI summary, languages, contributors and most changed files" width="860">
|
|
99
|
+
</p>
|
|
100
|
+
|
|
101
|
+
**How to run it**
|
|
102
|
+
- Setup and run commands detected from `package.json` (npm, pnpm, yarn), `pyproject.toml`, `requirements.txt`, `manage.py`, `main.py`/`app.py`, `Cargo.toml`, `go.mod`, `pubspec.yaml`, `Makefile`, Docker Compose and Wrangler
|
|
103
|
+
- Commands use the repo's own virtual environment when one exists
|
|
104
|
+
- Commands and ports mentioned in the README
|
|
105
|
+
- **▶ Start** runs a detected command in the background with a log (after you confirm)
|
|
106
|
+
|
|
107
|
+
**Ports and processes**
|
|
108
|
+
- Every listening port you own, matched to a repo by the process working directory, then by the command line
|
|
109
|
+
- Ports open on all interfaces are flagged
|
|
110
|
+
- One click to open it in the browser, one to stop it
|
|
111
|
+
- Docker containers, matched to their compose folder
|
|
112
|
+
|
|
113
|
+
**AI summary (optional)**
|
|
114
|
+
- Press the sparkle button next to **Details** and an agent CLI you already have writes a short summary of the repo: what it is, stack, how to run it, what you were working on, gotchas. It is labelled *AI-generated, unverified*, shown on the card and on the repo's Overview, and marked when the repo has changed since.
|
|
115
|
+
- gitroster finds the agent CLIs installed on your machine (Claude Code, Codex CLI, Gemini CLI) and you pick one in Settings. There is no API key to enter and no model to host: it runs the CLI you are already signed in to, with its tools turned off, and nothing is executed.
|
|
116
|
+
- It sends that agent the README, a file list (secret-looking files are left out), dependency names, detected commands and recent commit titles. Where that goes depends on the agent: all three are cloud services.
|
|
117
|
+
- Prefer another tool? Use any command that reads a prompt on stdin: a custom command in Settings, `gitroster --agent-cmd "my-agent"` or `GITROSTER_AGENT`.
|
|
118
|
+
- Only Claude Code is tested here. The Codex and Gemini invocations follow their documented non-interactive modes but are untested.
|
|
119
|
+
|
|
120
|
+
## How it works
|
|
121
|
+
|
|
122
|
+
Detection is deterministic: file checks, `git`, `du`, `ss` and `/proc`. The AI part is opt-in and separate. See [SECURITY.md](SECURITY.md) for the safety model: loopback only, host and origin checks, and start/stop limited to things the scanner found.
|
|
123
|
+
|
|
124
|
+
## Limits
|
|
125
|
+
|
|
126
|
+
- Linux, macOS and Windows. On Windows a process's working directory is not readable, so ports are matched by command line only.
|
|
127
|
+
- Only processes owned by your user are visible.
|
|
128
|
+
- Hidden folders (`~/.nvm`), `node_modules` and anything deeper than 6 levels are skipped.
|
|
129
|
+
- A big first scan can take a while on slow disks or `/mnt/c`. The last result is shown instantly while a new scan runs.
|
|
130
|
+
- Run commands are guesses from well-known files. Treat them as a starting point.
|
|
131
|
+
|
|
132
|
+
## Contributing
|
|
133
|
+
|
|
134
|
+
Issues and PRs welcome, see [CONTRIBUTING.md](CONTRIBUTING.md). Run the tests with `python3 -m unittest discover -s tests`.
|
|
135
|
+
|
|
136
|
+
## License
|
|
137
|
+
|
|
138
|
+
MIT
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
gitroster/__init__.py,sha256=Zn1KFblwuFHiDRdRAiRnDBRkbPttWh44jKa5zG2ov0E,22
|
|
2
|
+
gitroster/__main__.py,sha256=xs0ncFDq0tEcmLfLq5Gtp9GeSVyV5Mht4fmq8rIFHTg,51
|
|
3
|
+
gitroster/agent.py,sha256=MK2adQh15OKYfL4xZssPWx-pwswTHFnz1CdukMuFQbY,6611
|
|
4
|
+
gitroster/cli.py,sha256=12Qt9jhTBIM-mJ42eVQGMkQmJ_AMmIuMr_TIQKzNFpQ,1641
|
|
5
|
+
gitroster/demo.py,sha256=8bZUpabF1SHwt50WGdLKahGv8lxv2sh35PxcyikA8zw,7321
|
|
6
|
+
gitroster/deps.py,sha256=IiRuLNK356CpsYm1fnjxJxTAdgU0kBp-sL1jiT_V13s,7095
|
|
7
|
+
gitroster/export.py,sha256=Bpvh0WbwLqRQzF4vPBctiOmMRYDt8RnN8ai1vGXbe2w,1844
|
|
8
|
+
gitroster/opener.py,sha256=cQZ_IpUCxe3Mr9Ij4N_JzVjH7VTI6sg0H0QCOxkSHjA,8121
|
|
9
|
+
gitroster/pathscan.py,sha256=k4IpL5Q6w-yoqZL4QGDtBwUScBzRO1mDW6jUslUaRzM,1140
|
|
10
|
+
gitroster/procs.py,sha256=-fWI4wgwcJQ91EJaUA8ba_I0RWqNLZrIN5MHk6hypoU,6337
|
|
11
|
+
gitroster/repoinfo.py,sha256=bykR3ALQqRMHCEEqTPNkQ1qfGZVOmOHuCR6LFO9LTRc,9860
|
|
12
|
+
gitroster/scanner.py,sha256=lENKEsOdwufuXX8TAjdgJvw0d65Ni0nFLtYLKpC3Df4,18783
|
|
13
|
+
gitroster/server.py,sha256=kX5BMjOgnjEplgCwfNorEREFN_Vb7AksO3fvRBHniEo,10867
|
|
14
|
+
gitroster/store.py,sha256=_BzCIJCq_yp7q_hacblDd3svt2IE3aZaKHYgp6-gCkw,3013
|
|
15
|
+
gitroster/static/icon.svg,sha256=d7a428MCnphLgCwBEmkKko0q3NoCm5rj2Jy1_fOl6xs,691
|
|
16
|
+
gitroster/static/index.html,sha256=iJ4xanPJ1a2mXmTm88XB1HVJd-HQXeLXcXU2u_axAoo,68118
|
|
17
|
+
gitroster-0.2.0.dist-info/licenses/LICENSE,sha256=cNk0zyV12h_cZTh6A31XoE-C3c1VyLFxWeKXvrg8-Fg,1079
|
|
18
|
+
gitroster-0.2.0.dist-info/METADATA,sha256=PCrySht3Bx5wfDeLKYgDsdVBH5hKI_CUO_n0OoDU9Zs,7867
|
|
19
|
+
gitroster-0.2.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
20
|
+
gitroster-0.2.0.dist-info/entry_points.txt,sha256=H2DSfJdK7RuGCnaPWnjgQj6-LTadTzh0EQn3ScOX44M,49
|
|
21
|
+
gitroster-0.2.0.dist-info/top_level.txt,sha256=vMWHHsRpxmWDzirxSTp6O56ifb1_NpRerm51q3NBEN4,10
|
|
22
|
+
gitroster-0.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 gitroster contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
gitroster
|