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/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,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ gitroster = gitroster.cli:main
@@ -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