gitglimpse 0.1.4__tar.gz → 0.1.6__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.
- gitglimpse-0.1.6/PKG-INFO +69 -0
- gitglimpse-0.1.6/PYPI_README.md +44 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/pyproject.toml +5 -4
- gitglimpse-0.1.6/src/gitglimpse/__init__.py +1 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/cli.py +50 -1
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/providers/claude.py +13 -4
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/providers/gemini.py +13 -4
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/providers/local.py +14 -2
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/providers/openai.py +13 -4
- gitglimpse-0.1.4/PKG-INFO +0 -391
- gitglimpse-0.1.4/README.md +0 -366
- gitglimpse-0.1.4/src/gitglimpse/__init__.py +0 -1
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/.gitignore +0 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/LICENSE +0 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/commands/__init__.py +0 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/commands/pr.md +0 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/commands/report.md +0 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/commands/standup.md +0 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/commands/week.md +0 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/config.py +0 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/estimation.py +0 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/formatters/__init__.py +0 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/formatters/json.py +0 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/formatters/markdown.py +0 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/formatters/pr.py +0 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/formatters/template.py +0 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/git.py +0 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/grouping.py +0 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/onboarding.py +0 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/providers/__init__.py +0 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/providers/base.py +0 -0
- {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/py.typed +0 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gitglimpse
|
|
3
|
+
Version: 0.1.6
|
|
4
|
+
Summary: Extract structured context from your git history — PR descriptions, standups, weekly reports, and LLM-ready JSON.
|
|
5
|
+
Project-URL: Homepage, https://github.com/dino/gitglimpse
|
|
6
|
+
Project-URL: Repository, https://github.com/dino/gitglimpse
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/dino/gitglimpse/issues
|
|
8
|
+
Author: Dino
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: cli,developer-tools,git,standup
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Requires-Python: >=3.11
|
|
17
|
+
Requires-Dist: inquirerpy>=0.3.4
|
|
18
|
+
Requires-Dist: platformdirs>=4.0
|
|
19
|
+
Requires-Dist: rich>=13.0
|
|
20
|
+
Requires-Dist: tomli-w>=1.2
|
|
21
|
+
Requires-Dist: typer[all]>=0.9.0
|
|
22
|
+
Provides-Extra: llm
|
|
23
|
+
Requires-Dist: httpx>=0.27; extra == 'llm'
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# gitglimpse
|
|
27
|
+
|
|
28
|
+
Extract structured context from your git history — PR descriptions, standups, weekly reports, and LLM-ready JSON.
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install gitglimpse
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## What it does
|
|
37
|
+
|
|
38
|
+
gitglimpse reads your git log, groups commits into logical tasks, filters noise, extracts ticket IDs from branch names, and outputs structured context — as formatted text or clean JSON.
|
|
39
|
+
|
|
40
|
+
## Commands
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
glimpse pr # PR summary from current branch
|
|
44
|
+
glimpse standup # daily context from recent commits
|
|
45
|
+
glimpse week # weekly summary grouped by day
|
|
46
|
+
glimpse report # markdown report with file details
|
|
47
|
+
glimpse init # generate Claude Code / Cursor slash commands
|
|
48
|
+
glimpse config setup # interactive configuration
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Features
|
|
52
|
+
|
|
53
|
+
- **Noise filtering** — merge commits, lock files, and formatting changes excluded by default
|
|
54
|
+
- **Ticket detection** — branch names like `feature/PROJ-123` are parsed automatically
|
|
55
|
+
- **Multi-project** — run from a parent directory to aggregate across repos
|
|
56
|
+
- **LLM-optional** — works instantly without AI, or connect Ollama / OpenAI / Anthropic / Gemini for richer output
|
|
57
|
+
- **Editor integration** — slash commands for Claude Code and Cursor
|
|
58
|
+
- **GitHub Action** — auto-generate PR context on every pull request
|
|
59
|
+
- **JSON output** — every command supports `--json` for pipelines and LLM workflows
|
|
60
|
+
|
|
61
|
+
## Links
|
|
62
|
+
|
|
63
|
+
- **Website:** [gitglimpse.com](https://gitglimpse.com)
|
|
64
|
+
- **GitHub:** [github.com/dino-zecevic/gitglimpse](https://github.com/dino-zecevic/gitglimpse)
|
|
65
|
+
- **Documentation:** [README on GitHub](https://github.com/dino-zecevic/gitglimpse#readme)
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
|
|
69
|
+
MIT
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# gitglimpse
|
|
2
|
+
|
|
3
|
+
Extract structured context from your git history — PR descriptions, standups, weekly reports, and LLM-ready JSON.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install gitglimpse
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## What it does
|
|
12
|
+
|
|
13
|
+
gitglimpse reads your git log, groups commits into logical tasks, filters noise, extracts ticket IDs from branch names, and outputs structured context — as formatted text or clean JSON.
|
|
14
|
+
|
|
15
|
+
## Commands
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
glimpse pr # PR summary from current branch
|
|
19
|
+
glimpse standup # daily context from recent commits
|
|
20
|
+
glimpse week # weekly summary grouped by day
|
|
21
|
+
glimpse report # markdown report with file details
|
|
22
|
+
glimpse init # generate Claude Code / Cursor slash commands
|
|
23
|
+
glimpse config setup # interactive configuration
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Features
|
|
27
|
+
|
|
28
|
+
- **Noise filtering** — merge commits, lock files, and formatting changes excluded by default
|
|
29
|
+
- **Ticket detection** — branch names like `feature/PROJ-123` are parsed automatically
|
|
30
|
+
- **Multi-project** — run from a parent directory to aggregate across repos
|
|
31
|
+
- **LLM-optional** — works instantly without AI, or connect Ollama / OpenAI / Anthropic / Gemini for richer output
|
|
32
|
+
- **Editor integration** — slash commands for Claude Code and Cursor
|
|
33
|
+
- **GitHub Action** — auto-generate PR context on every pull request
|
|
34
|
+
- **JSON output** — every command supports `--json` for pipelines and LLM workflows
|
|
35
|
+
|
|
36
|
+
## Links
|
|
37
|
+
|
|
38
|
+
- **Website:** [gitglimpse.com](https://gitglimpse.com)
|
|
39
|
+
- **GitHub:** [github.com/dino-zecevic/gitglimpse](https://github.com/dino-zecevic/gitglimpse)
|
|
40
|
+
- **Documentation:** [README on GitHub](https://github.com/dino-zecevic/gitglimpse#readme)
|
|
41
|
+
|
|
42
|
+
## License
|
|
43
|
+
|
|
44
|
+
MIT
|
|
@@ -4,9 +4,9 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "gitglimpse"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.6"
|
|
8
8
|
description = "Extract structured context from your git history — PR descriptions, standups, weekly reports, and LLM-ready JSON."
|
|
9
|
-
readme = "
|
|
9
|
+
readme = "PYPI_README.md"
|
|
10
10
|
authors = [{ name = "Dino" }]
|
|
11
11
|
license = { text = "MIT" }
|
|
12
12
|
requires-python = ">=3.11"
|
|
@@ -25,13 +25,14 @@ dependencies = [
|
|
|
25
25
|
"InquirerPy>=0.3.4",
|
|
26
26
|
]
|
|
27
27
|
|
|
28
|
+
[project.optional-dependencies]
|
|
29
|
+
llm = ["httpx>=0.27"]
|
|
30
|
+
|
|
28
31
|
[project.urls]
|
|
29
32
|
Homepage = "https://github.com/dino/gitglimpse"
|
|
30
33
|
Repository = "https://github.com/dino/gitglimpse"
|
|
31
34
|
"Bug Tracker" = "https://github.com/dino/gitglimpse/issues"
|
|
32
35
|
|
|
33
|
-
[project.optional-dependencies]
|
|
34
|
-
llm = ["httpx>=0.27"]
|
|
35
36
|
|
|
36
37
|
[project.scripts]
|
|
37
38
|
glimpse = "gitglimpse.cli:app"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.6"
|
|
@@ -18,7 +18,6 @@ from gitglimpse.formatters.template import format_standup, format_week_template
|
|
|
18
18
|
from gitglimpse.git import GitError, get_branch_commits, get_commit_diff, get_commits, get_current_branch_name
|
|
19
19
|
from gitglimpse.grouping import filter_noise_commits, group_commits_into_tasks, is_vague_message
|
|
20
20
|
from gitglimpse.providers import get_provider
|
|
21
|
-
from gitglimpse.providers.local import LocalProvider
|
|
22
21
|
|
|
23
22
|
app = typer.Typer(
|
|
24
23
|
name="glimpse",
|
|
@@ -276,6 +275,7 @@ def _print_status_line(
|
|
|
276
275
|
ctx_mode: str = "commits",
|
|
277
276
|
) -> None:
|
|
278
277
|
"""Print a one-line dim status showing author, context, and active model."""
|
|
278
|
+
from gitglimpse.providers.local import LocalProvider
|
|
279
279
|
from gitglimpse.providers.openai import OpenAIProvider
|
|
280
280
|
from gitglimpse.providers.claude import ClaudeProvider
|
|
281
281
|
from gitglimpse.providers.gemini import GeminiProvider
|
|
@@ -301,6 +301,35 @@ def _print_status_line(
|
|
|
301
301
|
console.print("[dim]" + " · ".join(parts) + "[/dim]", highlight=False)
|
|
302
302
|
|
|
303
303
|
|
|
304
|
+
_PROVIDER_DEFAULTS: dict[str, dict[str, str]] = {
|
|
305
|
+
"openai": {"api_key_env": "OPENAI_API_KEY", "model": "gpt-4o-mini", "mode": "api"},
|
|
306
|
+
"anthropic": {"api_key_env": "ANTHROPIC_API_KEY", "model": "claude-sonnet-4-20250514", "mode": "api"},
|
|
307
|
+
"gemini": {"api_key_env": "GEMINI_API_KEY", "model": "gemini-2.5-flash", "mode": "api"},
|
|
308
|
+
"local": {"api_key_env": "", "model": "qwen2.5-coder:latest", "mode": "local-llm"},
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def _apply_provider_override(
|
|
313
|
+
cfg: Config,
|
|
314
|
+
provider_name: Optional[str],
|
|
315
|
+
model_override: Optional[str],
|
|
316
|
+
) -> None:
|
|
317
|
+
"""Mutate *cfg* in-place when --provider is passed on the CLI."""
|
|
318
|
+
if not provider_name:
|
|
319
|
+
return
|
|
320
|
+
defaults = _PROVIDER_DEFAULTS.get(provider_name)
|
|
321
|
+
if defaults is None:
|
|
322
|
+
_stderr_console.print(
|
|
323
|
+
f"[bold red]Error:[/bold red] Unknown provider '{provider_name}'. "
|
|
324
|
+
f"Choose from: {', '.join(_PROVIDER_DEFAULTS)}"
|
|
325
|
+
)
|
|
326
|
+
raise typer.Exit(1)
|
|
327
|
+
cfg.default_mode = defaults["mode"]
|
|
328
|
+
cfg.llm_provider = provider_name if provider_name != "local" else None
|
|
329
|
+
cfg.api_key_env = defaults["api_key_env"] or None
|
|
330
|
+
cfg.llm_model = model_override or defaults["model"]
|
|
331
|
+
|
|
332
|
+
|
|
304
333
|
def _resolve_provider(
|
|
305
334
|
cfg: Config,
|
|
306
335
|
use_local: bool,
|
|
@@ -315,6 +344,8 @@ def _resolve_provider(
|
|
|
315
344
|
2. config default_mode == local-llm / api → get_provider()
|
|
316
345
|
3. anything else → None (template fallback)
|
|
317
346
|
"""
|
|
347
|
+
from gitglimpse.providers.local import LocalProvider
|
|
348
|
+
|
|
318
349
|
if use_local:
|
|
319
350
|
url = local_url_override or cfg.local_llm_url
|
|
320
351
|
model = model_override or cfg.llm_model or None
|
|
@@ -379,6 +410,10 @@ def standup(
|
|
|
379
410
|
Optional[str],
|
|
380
411
|
typer.Option("--output", "-o", help="Save output to file instead of printing."),
|
|
381
412
|
] = None,
|
|
413
|
+
provider: Annotated[
|
|
414
|
+
Optional[str],
|
|
415
|
+
typer.Option("--provider", help="LLM provider override: openai, anthropic, gemini, local.", hidden=True),
|
|
416
|
+
] = None,
|
|
382
417
|
skip_setup: Annotated[
|
|
383
418
|
bool,
|
|
384
419
|
typer.Option("--skip-setup", help="Skip first-run onboarding.", hidden=True),
|
|
@@ -395,6 +430,7 @@ def standup(
|
|
|
395
430
|
glimpse standup --repos "api,frontend,landing"
|
|
396
431
|
"""
|
|
397
432
|
cfg = _load_or_onboard(skip_setup)
|
|
433
|
+
_apply_provider_override(cfg, provider, model)
|
|
398
434
|
effective = _effective_since(since, cfg.default_since)
|
|
399
435
|
ctx_mode = context or cfg.context_mode
|
|
400
436
|
resolved_author = _resolve_author(author, cfg.author_email)
|
|
@@ -457,6 +493,7 @@ def standup(
|
|
|
457
493
|
active_provider: object | None = None
|
|
458
494
|
llm_output: str | None = None
|
|
459
495
|
if not no_llm:
|
|
496
|
+
from gitglimpse.providers.local import LocalProvider
|
|
460
497
|
provider = _resolve_provider(cfg, local_llm, local_llm_url, model, context_mode=ctx_mode)
|
|
461
498
|
if provider is not None:
|
|
462
499
|
if isinstance(provider, LocalProvider) and not provider.is_available():
|
|
@@ -536,6 +573,10 @@ def week(
|
|
|
536
573
|
typer.Option("--filter-noise/--no-filter-noise",
|
|
537
574
|
help="Filter out noise commits (merges, formatting, lock files)."),
|
|
538
575
|
] = None,
|
|
576
|
+
provider: Annotated[
|
|
577
|
+
Optional[str],
|
|
578
|
+
typer.Option("--provider", help="LLM provider override: openai, anthropic, gemini, local.", hidden=True),
|
|
579
|
+
] = None,
|
|
539
580
|
skip_setup: Annotated[
|
|
540
581
|
bool,
|
|
541
582
|
typer.Option("--skip-setup", help="Skip first-run onboarding.", hidden=True),
|
|
@@ -550,6 +591,7 @@ def week(
|
|
|
550
591
|
glimpse week --json
|
|
551
592
|
"""
|
|
552
593
|
cfg = _load_or_onboard(skip_setup)
|
|
594
|
+
_apply_provider_override(cfg, provider, model)
|
|
553
595
|
ctx_mode = context or cfg.context_mode
|
|
554
596
|
resolved_author = _resolve_author(author, cfg.author_email)
|
|
555
597
|
do_filter = filter_noise if filter_noise is not None else cfg.filter_noise
|
|
@@ -602,6 +644,7 @@ def week(
|
|
|
602
644
|
active_provider: object | None = None
|
|
603
645
|
llm_output: str | None = None
|
|
604
646
|
if not no_llm:
|
|
647
|
+
from gitglimpse.providers.local import LocalProvider
|
|
605
648
|
provider = _resolve_provider(cfg, local_llm, local_llm_url, model, context_mode=ctx_mode)
|
|
606
649
|
if provider is not None:
|
|
607
650
|
if isinstance(provider, LocalProvider) and not provider.is_available():
|
|
@@ -657,6 +700,10 @@ def pr(
|
|
|
657
700
|
typer.Option("--filter-noise/--no-filter-noise",
|
|
658
701
|
help="Filter out noise commits (merges, formatting, lock files)."),
|
|
659
702
|
] = None,
|
|
703
|
+
provider: Annotated[
|
|
704
|
+
Optional[str],
|
|
705
|
+
typer.Option("--provider", help="LLM provider override: openai, anthropic, gemini, local.", hidden=True),
|
|
706
|
+
] = None,
|
|
660
707
|
skip_setup: Annotated[
|
|
661
708
|
bool,
|
|
662
709
|
typer.Option("--skip-setup", help="Skip first-run onboarding.", hidden=True),
|
|
@@ -672,6 +719,7 @@ def pr(
|
|
|
672
719
|
glimpse pr --context diffs
|
|
673
720
|
"""
|
|
674
721
|
cfg = _load_or_onboard(skip_setup)
|
|
722
|
+
_apply_provider_override(cfg, provider, model)
|
|
675
723
|
# PR defaults to "both" context for richer output, unless explicitly overridden.
|
|
676
724
|
ctx_mode = context or "both"
|
|
677
725
|
do_filter = filter_noise if filter_noise is not None else cfg.filter_noise
|
|
@@ -733,6 +781,7 @@ def pr(
|
|
|
733
781
|
active_provider: object | None = None
|
|
734
782
|
llm_output: str | None = None
|
|
735
783
|
if not no_llm:
|
|
784
|
+
from gitglimpse.providers.local import LocalProvider
|
|
736
785
|
provider = _resolve_provider(cfg, local_llm, local_llm_url, model, context_mode=ctx_mode)
|
|
737
786
|
if provider is not None:
|
|
738
787
|
if isinstance(provider, LocalProvider) and not provider.is_available():
|
|
@@ -5,8 +5,6 @@ from __future__ import annotations
|
|
|
5
5
|
from datetime import date
|
|
6
6
|
from typing import TYPE_CHECKING
|
|
7
7
|
|
|
8
|
-
import httpx
|
|
9
|
-
|
|
10
8
|
from gitglimpse.providers.base import BaseLLMProvider, _warn, validate_llm_output
|
|
11
9
|
|
|
12
10
|
if TYPE_CHECKING:
|
|
@@ -14,9 +12,18 @@ if TYPE_CHECKING:
|
|
|
14
12
|
|
|
15
13
|
_API_URL = "https://api.anthropic.com/v1/messages"
|
|
16
14
|
_ANTHROPIC_VERSION = "2023-06-01"
|
|
17
|
-
_TIMEOUT = httpx.Timeout(connect=30.0, read=120.0, write=30.0, pool=30.0)
|
|
18
15
|
_MAX_TOKENS = 1024
|
|
19
16
|
|
|
17
|
+
_HTTPX_INSTALL_HINT = "httpx is required for LLM features. Install with: pip install 'gitglimpse[llm]'"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _import_httpx():
|
|
21
|
+
try:
|
|
22
|
+
import httpx
|
|
23
|
+
return httpx
|
|
24
|
+
except ImportError:
|
|
25
|
+
raise ImportError(_HTTPX_INSTALL_HINT)
|
|
26
|
+
|
|
20
27
|
|
|
21
28
|
class ClaudeProvider(BaseLLMProvider):
|
|
22
29
|
"""Anthropic Claude messages provider."""
|
|
@@ -27,6 +34,7 @@ class ClaudeProvider(BaseLLMProvider):
|
|
|
27
34
|
self.context_mode = context_mode
|
|
28
35
|
|
|
29
36
|
def _chat(self, user_message: str, system_prompt: str | None = None) -> str | None:
|
|
37
|
+
httpx = _import_httpx()
|
|
30
38
|
if system_prompt is None:
|
|
31
39
|
system_prompt = self.get_system_prompt()
|
|
32
40
|
headers = {
|
|
@@ -40,9 +48,10 @@ class ClaudeProvider(BaseLLMProvider):
|
|
|
40
48
|
"system": system_prompt,
|
|
41
49
|
"messages": [{"role": "user", "content": user_message}],
|
|
42
50
|
}
|
|
51
|
+
_timeout = httpx.Timeout(connect=30.0, read=120.0, write=30.0, pool=30.0)
|
|
43
52
|
try:
|
|
44
53
|
with _warn.status(f"[dim]Generating with {self.model}...[/dim]"):
|
|
45
|
-
resp = httpx.post(_API_URL, json=payload, headers=headers, timeout=
|
|
54
|
+
resp = httpx.post(_API_URL, json=payload, headers=headers, timeout=_timeout)
|
|
46
55
|
if resp.status_code == 401:
|
|
47
56
|
_warn.print("[yellow]⚠ Claude: invalid API key.[/yellow]")
|
|
48
57
|
return None
|
|
@@ -5,15 +5,22 @@ from __future__ import annotations
|
|
|
5
5
|
from datetime import date
|
|
6
6
|
from typing import TYPE_CHECKING
|
|
7
7
|
|
|
8
|
-
import httpx
|
|
9
|
-
|
|
10
8
|
from gitglimpse.providers.base import BaseLLMProvider, _warn, validate_llm_output
|
|
11
9
|
|
|
12
10
|
if TYPE_CHECKING:
|
|
13
11
|
from gitglimpse.grouping import Task
|
|
14
12
|
|
|
15
13
|
_API_BASE = "https://generativelanguage.googleapis.com/v1beta/models"
|
|
16
|
-
|
|
14
|
+
|
|
15
|
+
_HTTPX_INSTALL_HINT = "httpx is required for LLM features. Install with: pip install 'gitglimpse[llm]'"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _import_httpx():
|
|
19
|
+
try:
|
|
20
|
+
import httpx
|
|
21
|
+
return httpx
|
|
22
|
+
except ImportError:
|
|
23
|
+
raise ImportError(_HTTPX_INSTALL_HINT)
|
|
17
24
|
|
|
18
25
|
|
|
19
26
|
class GeminiProvider(BaseLLMProvider):
|
|
@@ -25,6 +32,7 @@ class GeminiProvider(BaseLLMProvider):
|
|
|
25
32
|
self.context_mode = context_mode
|
|
26
33
|
|
|
27
34
|
def _chat(self, user_message: str, system_prompt: str | None = None) -> str | None:
|
|
35
|
+
httpx = _import_httpx()
|
|
28
36
|
if system_prompt is None:
|
|
29
37
|
system_prompt = self.get_system_prompt()
|
|
30
38
|
url = f"{_API_BASE}/{self.model}:generateContent?key={self.api_key}"
|
|
@@ -36,9 +44,10 @@ class GeminiProvider(BaseLLMProvider):
|
|
|
36
44
|
{"parts": [{"text": user_message}]}
|
|
37
45
|
],
|
|
38
46
|
}
|
|
47
|
+
_timeout = httpx.Timeout(connect=30.0, read=120.0, write=30.0, pool=30.0)
|
|
39
48
|
try:
|
|
40
49
|
with _warn.status(f"[dim]Generating with {self.model}...[/dim]"):
|
|
41
|
-
resp = httpx.post(url, json=payload, timeout=
|
|
50
|
+
resp = httpx.post(url, json=payload, timeout=_timeout)
|
|
42
51
|
if resp.status_code == 400:
|
|
43
52
|
_warn.print("[yellow]⚠ Gemini: bad request (check API key or model name).[/yellow]")
|
|
44
53
|
return None
|
|
@@ -5,8 +5,6 @@ from __future__ import annotations
|
|
|
5
5
|
from datetime import date
|
|
6
6
|
from typing import TYPE_CHECKING
|
|
7
7
|
|
|
8
|
-
import httpx
|
|
9
|
-
|
|
10
8
|
from gitglimpse.providers.base import BaseLLMProvider, _warn, validate_llm_output
|
|
11
9
|
|
|
12
10
|
if TYPE_CHECKING:
|
|
@@ -17,6 +15,16 @@ _READ_TIMEOUT = 240.0
|
|
|
17
15
|
_AVAILABILITY_TIMEOUT = 3.0
|
|
18
16
|
_DEFAULT_MODEL = "qwen2.5-coder:latest"
|
|
19
17
|
|
|
18
|
+
_HTTPX_INSTALL_HINT = "httpx is required for LLM features. Install with: pip install 'gitglimpse[llm]'"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _import_httpx():
|
|
22
|
+
try:
|
|
23
|
+
import httpx
|
|
24
|
+
return httpx
|
|
25
|
+
except ImportError:
|
|
26
|
+
raise ImportError(_HTTPX_INSTALL_HINT)
|
|
27
|
+
|
|
20
28
|
|
|
21
29
|
class LocalProvider(BaseLLMProvider):
|
|
22
30
|
"""OpenAI-compatible local LLM (Ollama, LM Studio, etc.)."""
|
|
@@ -27,6 +35,7 @@ class LocalProvider(BaseLLMProvider):
|
|
|
27
35
|
model: str | None = None,
|
|
28
36
|
context_mode: str = "commits",
|
|
29
37
|
) -> None:
|
|
38
|
+
httpx = _import_httpx()
|
|
30
39
|
self.base_url = base_url.rstrip("/")
|
|
31
40
|
self._explicit_model = model
|
|
32
41
|
self._model_resolved = bool(model)
|
|
@@ -41,6 +50,7 @@ class LocalProvider(BaseLLMProvider):
|
|
|
41
50
|
|
|
42
51
|
def is_available(self) -> bool:
|
|
43
52
|
"""Return True if the local server responds to a quick probe."""
|
|
53
|
+
httpx = _import_httpx()
|
|
44
54
|
try:
|
|
45
55
|
resp = httpx.get(
|
|
46
56
|
f"{self.base_url}/models",
|
|
@@ -55,6 +65,7 @@ class LocalProvider(BaseLLMProvider):
|
|
|
55
65
|
if self._model_resolved:
|
|
56
66
|
return
|
|
57
67
|
self._model_resolved = True
|
|
68
|
+
httpx = _import_httpx()
|
|
58
69
|
try:
|
|
59
70
|
resp = httpx.get(
|
|
60
71
|
f"{self.base_url}/models",
|
|
@@ -68,6 +79,7 @@ class LocalProvider(BaseLLMProvider):
|
|
|
68
79
|
pass # keep the default
|
|
69
80
|
|
|
70
81
|
def _chat(self, user_message: str, system_prompt: str | None = None) -> str | None:
|
|
82
|
+
httpx = _import_httpx()
|
|
71
83
|
self._auto_detect_model()
|
|
72
84
|
url = f"{self.base_url}/chat/completions"
|
|
73
85
|
if system_prompt is None:
|
|
@@ -5,15 +5,22 @@ from __future__ import annotations
|
|
|
5
5
|
from datetime import date
|
|
6
6
|
from typing import TYPE_CHECKING
|
|
7
7
|
|
|
8
|
-
import httpx
|
|
9
|
-
|
|
10
8
|
from gitglimpse.providers.base import BaseLLMProvider, _warn, validate_llm_output
|
|
11
9
|
|
|
12
10
|
if TYPE_CHECKING:
|
|
13
11
|
from gitglimpse.grouping import Task
|
|
14
12
|
|
|
15
13
|
_API_URL = "https://api.openai.com/v1/chat/completions"
|
|
16
|
-
|
|
14
|
+
|
|
15
|
+
_HTTPX_INSTALL_HINT = "httpx is required for LLM features. Install with: pip install 'gitglimpse[llm]'"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _import_httpx():
|
|
19
|
+
try:
|
|
20
|
+
import httpx
|
|
21
|
+
return httpx
|
|
22
|
+
except ImportError:
|
|
23
|
+
raise ImportError(_HTTPX_INSTALL_HINT)
|
|
17
24
|
|
|
18
25
|
|
|
19
26
|
class OpenAIProvider(BaseLLMProvider):
|
|
@@ -25,6 +32,7 @@ class OpenAIProvider(BaseLLMProvider):
|
|
|
25
32
|
self.context_mode = context_mode
|
|
26
33
|
|
|
27
34
|
def _chat(self, user_message: str, system_prompt: str | None = None) -> str | None:
|
|
35
|
+
httpx = _import_httpx()
|
|
28
36
|
if system_prompt is None:
|
|
29
37
|
system_prompt = self.get_system_prompt()
|
|
30
38
|
headers = {
|
|
@@ -38,9 +46,10 @@ class OpenAIProvider(BaseLLMProvider):
|
|
|
38
46
|
{"role": "user", "content": user_message},
|
|
39
47
|
],
|
|
40
48
|
}
|
|
49
|
+
_timeout = httpx.Timeout(connect=30.0, read=120.0, write=30.0, pool=30.0)
|
|
41
50
|
try:
|
|
42
51
|
with _warn.status(f"[dim]Generating with {self.model}...[/dim]"):
|
|
43
|
-
resp = httpx.post(_API_URL, json=payload, headers=headers, timeout=
|
|
52
|
+
resp = httpx.post(_API_URL, json=payload, headers=headers, timeout=_timeout)
|
|
44
53
|
if resp.status_code == 401:
|
|
45
54
|
_warn.print("[yellow]⚠ OpenAI: invalid API key.[/yellow]")
|
|
46
55
|
return None
|
gitglimpse-0.1.4/PKG-INFO
DELETED
|
@@ -1,391 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: gitglimpse
|
|
3
|
-
Version: 0.1.4
|
|
4
|
-
Summary: Extract structured context from your git history — PR descriptions, standups, weekly reports, and LLM-ready JSON.
|
|
5
|
-
Project-URL: Homepage, https://github.com/dino/gitglimpse
|
|
6
|
-
Project-URL: Repository, https://github.com/dino/gitglimpse
|
|
7
|
-
Project-URL: Bug Tracker, https://github.com/dino/gitglimpse/issues
|
|
8
|
-
Author: Dino
|
|
9
|
-
License: MIT
|
|
10
|
-
License-File: LICENSE
|
|
11
|
-
Keywords: cli,developer-tools,git,standup
|
|
12
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
-
Requires-Python: >=3.11
|
|
17
|
-
Requires-Dist: inquirerpy>=0.3.4
|
|
18
|
-
Requires-Dist: platformdirs>=4.0
|
|
19
|
-
Requires-Dist: rich>=13.0
|
|
20
|
-
Requires-Dist: tomli-w>=1.2
|
|
21
|
-
Requires-Dist: typer[all]>=0.9.0
|
|
22
|
-
Provides-Extra: llm
|
|
23
|
-
Requires-Dist: httpx>=0.27; extra == 'llm'
|
|
24
|
-
Description-Content-Type: text/markdown
|
|
25
|
-
|
|
26
|
-
<div align="center">
|
|
27
|
-
|
|
28
|
-
<img src="docs/gitglimpse.png" alt="gitglimpse" width="120">
|
|
29
|
-
|
|
30
|
-
# gitglimpse
|
|
31
|
-
|
|
32
|
-
**Extract structured context from your git history. Standups, PR descriptions, weekly reports, and LLM-ready JSON — from one command.**
|
|
33
|
-
|
|
34
|
-
50KB of raw diffs → 1KB of structured signal. Less noise, fewer tokens, better output.
|
|
35
|
-
|
|
36
|
-
[](https://python.org)
|
|
37
|
-
[](LICENSE)
|
|
38
|
-
[](CONTRIBUTING.md)
|
|
39
|
-
|
|
40
|
-
<br>
|
|
41
|
-
|
|
42
|
-
</div>
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
## Why gitglimpse?
|
|
47
|
-
|
|
48
|
-
Modern development (especially with AI) creates **more changes across more files than ever**.
|
|
49
|
-
|
|
50
|
-
Git tracks *what changed* — but not in a way that's easy to understand quickly.
|
|
51
|
-
|
|
52
|
-
gitglimpse bridges that gap.
|
|
53
|
-
|
|
54
|
-
It turns raw git history into:
|
|
55
|
-
|
|
56
|
-
- 🧠 **Structured context (JSON)** for LLMs and tools
|
|
57
|
-
- 📝 **Standups & reports** for humans
|
|
58
|
-
- 🔍 **Clean summaries** without opening diffs or PRs
|
|
59
|
-
|
|
60
|
-
> Think of it as a **context extraction layer for your codebase**.
|
|
61
|
-
|
|
62
|
-
---
|
|
63
|
-
|
|
64
|
-
## ✨ Demo
|
|
65
|
-
|
|
66
|
-
<!-- TODO: Replace with real GIF -->
|
|
67
|
-

|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## Quick Start
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
pip install gitglimpse
|
|
75
|
-
cd your-project
|
|
76
|
-
glimpse standup
|
|
77
|
-
````
|
|
78
|
-
|
|
79
|
-
That’s it. No API keys, no setup required.
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## Core Idea
|
|
84
|
-
|
|
85
|
-
gitglimpse is not just a “standup generator”.
|
|
86
|
-
|
|
87
|
-
It’s a **Git → Structured Context engine**.
|
|
88
|
-
|
|
89
|
-
```bash
|
|
90
|
-
glimpse standup --json | your-llm
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
Instead of dumping raw diffs into an LLM, you give it:
|
|
94
|
-
|
|
95
|
-
* grouped tasks
|
|
96
|
-
* extracted tickets
|
|
97
|
-
* filtered noise
|
|
98
|
-
* optional diffs
|
|
99
|
-
* structured JSON
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
## 🚀 Commands
|
|
104
|
-
|
|
105
|
-
### `glimpse pr`
|
|
106
|
-
|
|
107
|
-
Generate PR summaries from your branch.
|
|
108
|
-
|
|
109
|
-
```bash
|
|
110
|
-
glimpse pr
|
|
111
|
-
glimpse pr --json
|
|
112
|
-
glimpse pr --base develop
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
---
|
|
116
|
-
|
|
117
|
-
### `glimpse standup`
|
|
118
|
-
|
|
119
|
-
Generate a daily summary or structured context.
|
|
120
|
-
|
|
121
|
-
```bash
|
|
122
|
-
glimpse standup
|
|
123
|
-
glimpse standup --json
|
|
124
|
-
glimpse standup --since "3 days ago"
|
|
125
|
-
glimpse standup --format markdown
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
Example:
|
|
129
|
-
|
|
130
|
-
```
|
|
131
|
-
Yesterday:
|
|
132
|
-
• Add rate limiting middleware (AUTH-42, ~1.5h)
|
|
133
|
-
• Fix pagination bug (BUG-87, ~1h)
|
|
134
|
-
|
|
135
|
-
Estimated effort: 2.5h
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
---
|
|
139
|
-
|
|
140
|
-
### `glimpse week`
|
|
141
|
-
|
|
142
|
-
Weekly breakdown grouped by day.
|
|
143
|
-
|
|
144
|
-
```bash
|
|
145
|
-
glimpse week
|
|
146
|
-
glimpse week --json
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
---
|
|
150
|
-
|
|
151
|
-
### `glimpse init`
|
|
152
|
-
|
|
153
|
-
Install Claude Code / Cursor slash commands.
|
|
154
|
-
|
|
155
|
-
```bash
|
|
156
|
-
glimpse init
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
Then in your editor:
|
|
160
|
-
|
|
161
|
-
```
|
|
162
|
-
/standup
|
|
163
|
-
/pr
|
|
164
|
-
/week
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
---
|
|
168
|
-
|
|
169
|
-
### `glimpse config`
|
|
170
|
-
|
|
171
|
-
View or edit configuration.
|
|
172
|
-
|
|
173
|
-
```bash
|
|
174
|
-
glimpse config show
|
|
175
|
-
glimpse config setup
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
## 🧩 Output Modes
|
|
181
|
-
|
|
182
|
-
| Mode | Description |
|
|
183
|
-
| ------------- | ------------------------------- |
|
|
184
|
-
| **Template** | Fast, deterministic, no LLM |
|
|
185
|
-
| **Local LLM** | Uses Ollama (privacy-first) |
|
|
186
|
-
| **Cloud API** | OpenAI / Anthropic / Gemini |
|
|
187
|
-
| **JSON** | Structured output for pipelines |
|
|
188
|
-
|
|
189
|
-
---
|
|
190
|
-
|
|
191
|
-
## 🔥 What Makes It Different
|
|
192
|
-
|
|
193
|
-
### 1. Noise Filtering (by default)
|
|
194
|
-
|
|
195
|
-
Removes:
|
|
196
|
-
|
|
197
|
-
* merge commits
|
|
198
|
-
* lock files
|
|
199
|
-
* formatting changes
|
|
200
|
-
|
|
201
|
-
So you only see meaningful work.
|
|
202
|
-
|
|
203
|
-
---
|
|
204
|
-
|
|
205
|
-
### 2. Task Grouping
|
|
206
|
-
|
|
207
|
-
Commits → grouped into **real tasks**:
|
|
208
|
-
|
|
209
|
-
```
|
|
210
|
-
3 commits → 1 task
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
---
|
|
214
|
-
|
|
215
|
-
### 3. Ticket Extraction
|
|
216
|
-
|
|
217
|
-
Automatically parses:
|
|
218
|
-
|
|
219
|
-
```
|
|
220
|
-
feature/AUTH-42-login → AUTH-42
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
---
|
|
224
|
-
|
|
225
|
-
### 4. Works Without LLMs
|
|
226
|
-
|
|
227
|
-
No AI required.
|
|
228
|
-
|
|
229
|
-
* Good commits → good summaries
|
|
230
|
-
* Bad commits → fallback heuristics
|
|
231
|
-
* LLM → optional enhancement
|
|
232
|
-
|
|
233
|
-
---
|
|
234
|
-
|
|
235
|
-
### 5. Built for LLM Workflows
|
|
236
|
-
|
|
237
|
-
Instead of:
|
|
238
|
-
|
|
239
|
-
```bash
|
|
240
|
-
git diff | llm
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
You do:
|
|
244
|
-
|
|
245
|
-
```bash
|
|
246
|
-
glimpse standup --json | llm
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
Cleaner input → better output.
|
|
250
|
-
|
|
251
|
-
---
|
|
252
|
-
|
|
253
|
-
## 🤖 Claude Code Integration
|
|
254
|
-
|
|
255
|
-
<!-- TODO: Add GIF showing /standup usage -->
|
|
256
|
-
|
|
257
|
-
```bash
|
|
258
|
-
glimpse init
|
|
259
|
-
git add .claude/commands/
|
|
260
|
-
git commit -m "add glimpse commands"
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
Now every dev on your team gets:
|
|
264
|
-
|
|
265
|
-
```
|
|
266
|
-
/standup
|
|
267
|
-
/pr
|
|
268
|
-
/week
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
📌 The repo becomes the distribution channel.
|
|
272
|
-
|
|
273
|
-
---
|
|
274
|
-
|
|
275
|
-
## GitHub Action
|
|
276
|
-
|
|
277
|
-
Add automatic PR context to your repository:
|
|
278
|
-
|
|
279
|
-
```yaml
|
|
280
|
-
- uses: dino-zecevic/gitglimpse@main
|
|
281
|
-
with:
|
|
282
|
-
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
Every pull request gets a structured summary with changes, ticket IDs, and effort estimates. The comment updates on each push.
|
|
286
|
-
|
|
287
|
-
See [action/README.md](action/README.md) for full configuration options.
|
|
288
|
-
|
|
289
|
-
---
|
|
290
|
-
|
|
291
|
-
## 🧠 Multi-Project Mode
|
|
292
|
-
|
|
293
|
-
Run from a parent folder:
|
|
294
|
-
|
|
295
|
-
```bash
|
|
296
|
-
cd ~/projects
|
|
297
|
-
glimpse standup
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
gitglimpse will:
|
|
301
|
-
|
|
302
|
-
* detect repos automatically
|
|
303
|
-
* merge timelines
|
|
304
|
-
* group by project or task
|
|
305
|
-
|
|
306
|
-
<!-- TODO: Add multi-project GIF -->
|
|
307
|
-
|
|
308
|
-
---
|
|
309
|
-
|
|
310
|
-
## ⚙️ Configuration
|
|
311
|
-
|
|
312
|
-
```bash
|
|
313
|
-
glimpse config setup
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
Stored in:
|
|
317
|
-
|
|
318
|
-
```
|
|
319
|
-
~/.config/gitglimpse/config.toml
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
Supports:
|
|
323
|
-
|
|
324
|
-
* local models (Ollama)
|
|
325
|
-
* cloud APIs
|
|
326
|
-
* context modes (`commits`, `diffs`, `both`)
|
|
327
|
-
|
|
328
|
-
---
|
|
329
|
-
|
|
330
|
-
## Philosophy
|
|
331
|
-
|
|
332
|
-
* **Privacy-first** — works fully offline
|
|
333
|
-
* **LLM-optional** — useful without AI
|
|
334
|
-
* **Developer-first** — not a manager tool
|
|
335
|
-
* **Composable** — JSON output for pipelines
|
|
336
|
-
* **Honest** — no fake precision (effort is approximate)
|
|
337
|
-
|
|
338
|
-
---
|
|
339
|
-
|
|
340
|
-
## When It’s Actually Useful
|
|
341
|
-
|
|
342
|
-
* Weekly summaries across repos
|
|
343
|
-
* PR descriptions
|
|
344
|
-
* Feeding context into coding agents
|
|
345
|
-
* Remembering what you did yesterday
|
|
346
|
-
|
|
347
|
-
---
|
|
348
|
-
|
|
349
|
-
## ⚠️ Limitations
|
|
350
|
-
|
|
351
|
-
* Only sees **code changes** (not meetings, docs, etc.)
|
|
352
|
-
* Effort estimation is **heuristic, not accurate**
|
|
353
|
-
* Depends on git history quality
|
|
354
|
-
|
|
355
|
-
---
|
|
356
|
-
|
|
357
|
-
## Installation
|
|
358
|
-
|
|
359
|
-
```bash
|
|
360
|
-
pip install gitglimpse
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
Requirements:
|
|
364
|
-
|
|
365
|
-
* Python 3.11+
|
|
366
|
-
* git
|
|
367
|
-
* (optional) Ollama or API key
|
|
368
|
-
|
|
369
|
-
---
|
|
370
|
-
|
|
371
|
-
## Contributing
|
|
372
|
-
|
|
373
|
-
PRs welcome — especially for:
|
|
374
|
-
|
|
375
|
-
* better effort estimation
|
|
376
|
-
* smarter task grouping
|
|
377
|
-
* improved noise filtering
|
|
378
|
-
|
|
379
|
-
---
|
|
380
|
-
|
|
381
|
-
## License
|
|
382
|
-
|
|
383
|
-
MIT
|
|
384
|
-
|
|
385
|
-
---
|
|
386
|
-
|
|
387
|
-
<div align="center">
|
|
388
|
-
|
|
389
|
-
Built by Dino
|
|
390
|
-
|
|
391
|
-
</div>
|
gitglimpse-0.1.4/README.md
DELETED
|
@@ -1,366 +0,0 @@
|
|
|
1
|
-
<div align="center">
|
|
2
|
-
|
|
3
|
-
<img src="docs/gitglimpse.png" alt="gitglimpse" width="120">
|
|
4
|
-
|
|
5
|
-
# gitglimpse
|
|
6
|
-
|
|
7
|
-
**Extract structured context from your git history. Standups, PR descriptions, weekly reports, and LLM-ready JSON — from one command.**
|
|
8
|
-
|
|
9
|
-
50KB of raw diffs → 1KB of structured signal. Less noise, fewer tokens, better output.
|
|
10
|
-
|
|
11
|
-
[](https://python.org)
|
|
12
|
-
[](LICENSE)
|
|
13
|
-
[](CONTRIBUTING.md)
|
|
14
|
-
|
|
15
|
-
<br>
|
|
16
|
-
|
|
17
|
-
</div>
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## Why gitglimpse?
|
|
22
|
-
|
|
23
|
-
Modern development (especially with AI) creates **more changes across more files than ever**.
|
|
24
|
-
|
|
25
|
-
Git tracks *what changed* — but not in a way that's easy to understand quickly.
|
|
26
|
-
|
|
27
|
-
gitglimpse bridges that gap.
|
|
28
|
-
|
|
29
|
-
It turns raw git history into:
|
|
30
|
-
|
|
31
|
-
- 🧠 **Structured context (JSON)** for LLMs and tools
|
|
32
|
-
- 📝 **Standups & reports** for humans
|
|
33
|
-
- 🔍 **Clean summaries** without opening diffs or PRs
|
|
34
|
-
|
|
35
|
-
> Think of it as a **context extraction layer for your codebase**.
|
|
36
|
-
|
|
37
|
-
---
|
|
38
|
-
|
|
39
|
-
## ✨ Demo
|
|
40
|
-
|
|
41
|
-
<!-- TODO: Replace with real GIF -->
|
|
42
|
-

|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
## Quick Start
|
|
47
|
-
|
|
48
|
-
```bash
|
|
49
|
-
pip install gitglimpse
|
|
50
|
-
cd your-project
|
|
51
|
-
glimpse standup
|
|
52
|
-
````
|
|
53
|
-
|
|
54
|
-
That’s it. No API keys, no setup required.
|
|
55
|
-
|
|
56
|
-
---
|
|
57
|
-
|
|
58
|
-
## Core Idea
|
|
59
|
-
|
|
60
|
-
gitglimpse is not just a “standup generator”.
|
|
61
|
-
|
|
62
|
-
It’s a **Git → Structured Context engine**.
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
glimpse standup --json | your-llm
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
Instead of dumping raw diffs into an LLM, you give it:
|
|
69
|
-
|
|
70
|
-
* grouped tasks
|
|
71
|
-
* extracted tickets
|
|
72
|
-
* filtered noise
|
|
73
|
-
* optional diffs
|
|
74
|
-
* structured JSON
|
|
75
|
-
|
|
76
|
-
---
|
|
77
|
-
|
|
78
|
-
## 🚀 Commands
|
|
79
|
-
|
|
80
|
-
### `glimpse pr`
|
|
81
|
-
|
|
82
|
-
Generate PR summaries from your branch.
|
|
83
|
-
|
|
84
|
-
```bash
|
|
85
|
-
glimpse pr
|
|
86
|
-
glimpse pr --json
|
|
87
|
-
glimpse pr --base develop
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
---
|
|
91
|
-
|
|
92
|
-
### `glimpse standup`
|
|
93
|
-
|
|
94
|
-
Generate a daily summary or structured context.
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
glimpse standup
|
|
98
|
-
glimpse standup --json
|
|
99
|
-
glimpse standup --since "3 days ago"
|
|
100
|
-
glimpse standup --format markdown
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
Example:
|
|
104
|
-
|
|
105
|
-
```
|
|
106
|
-
Yesterday:
|
|
107
|
-
• Add rate limiting middleware (AUTH-42, ~1.5h)
|
|
108
|
-
• Fix pagination bug (BUG-87, ~1h)
|
|
109
|
-
|
|
110
|
-
Estimated effort: 2.5h
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
---
|
|
114
|
-
|
|
115
|
-
### `glimpse week`
|
|
116
|
-
|
|
117
|
-
Weekly breakdown grouped by day.
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
glimpse week
|
|
121
|
-
glimpse week --json
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
### `glimpse init`
|
|
127
|
-
|
|
128
|
-
Install Claude Code / Cursor slash commands.
|
|
129
|
-
|
|
130
|
-
```bash
|
|
131
|
-
glimpse init
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
Then in your editor:
|
|
135
|
-
|
|
136
|
-
```
|
|
137
|
-
/standup
|
|
138
|
-
/pr
|
|
139
|
-
/week
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
---
|
|
143
|
-
|
|
144
|
-
### `glimpse config`
|
|
145
|
-
|
|
146
|
-
View or edit configuration.
|
|
147
|
-
|
|
148
|
-
```bash
|
|
149
|
-
glimpse config show
|
|
150
|
-
glimpse config setup
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
---
|
|
154
|
-
|
|
155
|
-
## 🧩 Output Modes
|
|
156
|
-
|
|
157
|
-
| Mode | Description |
|
|
158
|
-
| ------------- | ------------------------------- |
|
|
159
|
-
| **Template** | Fast, deterministic, no LLM |
|
|
160
|
-
| **Local LLM** | Uses Ollama (privacy-first) |
|
|
161
|
-
| **Cloud API** | OpenAI / Anthropic / Gemini |
|
|
162
|
-
| **JSON** | Structured output for pipelines |
|
|
163
|
-
|
|
164
|
-
---
|
|
165
|
-
|
|
166
|
-
## 🔥 What Makes It Different
|
|
167
|
-
|
|
168
|
-
### 1. Noise Filtering (by default)
|
|
169
|
-
|
|
170
|
-
Removes:
|
|
171
|
-
|
|
172
|
-
* merge commits
|
|
173
|
-
* lock files
|
|
174
|
-
* formatting changes
|
|
175
|
-
|
|
176
|
-
So you only see meaningful work.
|
|
177
|
-
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
### 2. Task Grouping
|
|
181
|
-
|
|
182
|
-
Commits → grouped into **real tasks**:
|
|
183
|
-
|
|
184
|
-
```
|
|
185
|
-
3 commits → 1 task
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
---
|
|
189
|
-
|
|
190
|
-
### 3. Ticket Extraction
|
|
191
|
-
|
|
192
|
-
Automatically parses:
|
|
193
|
-
|
|
194
|
-
```
|
|
195
|
-
feature/AUTH-42-login → AUTH-42
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
---
|
|
199
|
-
|
|
200
|
-
### 4. Works Without LLMs
|
|
201
|
-
|
|
202
|
-
No AI required.
|
|
203
|
-
|
|
204
|
-
* Good commits → good summaries
|
|
205
|
-
* Bad commits → fallback heuristics
|
|
206
|
-
* LLM → optional enhancement
|
|
207
|
-
|
|
208
|
-
---
|
|
209
|
-
|
|
210
|
-
### 5. Built for LLM Workflows
|
|
211
|
-
|
|
212
|
-
Instead of:
|
|
213
|
-
|
|
214
|
-
```bash
|
|
215
|
-
git diff | llm
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
You do:
|
|
219
|
-
|
|
220
|
-
```bash
|
|
221
|
-
glimpse standup --json | llm
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
Cleaner input → better output.
|
|
225
|
-
|
|
226
|
-
---
|
|
227
|
-
|
|
228
|
-
## 🤖 Claude Code Integration
|
|
229
|
-
|
|
230
|
-
<!-- TODO: Add GIF showing /standup usage -->
|
|
231
|
-
|
|
232
|
-
```bash
|
|
233
|
-
glimpse init
|
|
234
|
-
git add .claude/commands/
|
|
235
|
-
git commit -m "add glimpse commands"
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
Now every dev on your team gets:
|
|
239
|
-
|
|
240
|
-
```
|
|
241
|
-
/standup
|
|
242
|
-
/pr
|
|
243
|
-
/week
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
📌 The repo becomes the distribution channel.
|
|
247
|
-
|
|
248
|
-
---
|
|
249
|
-
|
|
250
|
-
## GitHub Action
|
|
251
|
-
|
|
252
|
-
Add automatic PR context to your repository:
|
|
253
|
-
|
|
254
|
-
```yaml
|
|
255
|
-
- uses: dino-zecevic/gitglimpse@main
|
|
256
|
-
with:
|
|
257
|
-
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
Every pull request gets a structured summary with changes, ticket IDs, and effort estimates. The comment updates on each push.
|
|
261
|
-
|
|
262
|
-
See [action/README.md](action/README.md) for full configuration options.
|
|
263
|
-
|
|
264
|
-
---
|
|
265
|
-
|
|
266
|
-
## 🧠 Multi-Project Mode
|
|
267
|
-
|
|
268
|
-
Run from a parent folder:
|
|
269
|
-
|
|
270
|
-
```bash
|
|
271
|
-
cd ~/projects
|
|
272
|
-
glimpse standup
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
gitglimpse will:
|
|
276
|
-
|
|
277
|
-
* detect repos automatically
|
|
278
|
-
* merge timelines
|
|
279
|
-
* group by project or task
|
|
280
|
-
|
|
281
|
-
<!-- TODO: Add multi-project GIF -->
|
|
282
|
-
|
|
283
|
-
---
|
|
284
|
-
|
|
285
|
-
## ⚙️ Configuration
|
|
286
|
-
|
|
287
|
-
```bash
|
|
288
|
-
glimpse config setup
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
Stored in:
|
|
292
|
-
|
|
293
|
-
```
|
|
294
|
-
~/.config/gitglimpse/config.toml
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
Supports:
|
|
298
|
-
|
|
299
|
-
* local models (Ollama)
|
|
300
|
-
* cloud APIs
|
|
301
|
-
* context modes (`commits`, `diffs`, `both`)
|
|
302
|
-
|
|
303
|
-
---
|
|
304
|
-
|
|
305
|
-
## Philosophy
|
|
306
|
-
|
|
307
|
-
* **Privacy-first** — works fully offline
|
|
308
|
-
* **LLM-optional** — useful without AI
|
|
309
|
-
* **Developer-first** — not a manager tool
|
|
310
|
-
* **Composable** — JSON output for pipelines
|
|
311
|
-
* **Honest** — no fake precision (effort is approximate)
|
|
312
|
-
|
|
313
|
-
---
|
|
314
|
-
|
|
315
|
-
## When It’s Actually Useful
|
|
316
|
-
|
|
317
|
-
* Weekly summaries across repos
|
|
318
|
-
* PR descriptions
|
|
319
|
-
* Feeding context into coding agents
|
|
320
|
-
* Remembering what you did yesterday
|
|
321
|
-
|
|
322
|
-
---
|
|
323
|
-
|
|
324
|
-
## ⚠️ Limitations
|
|
325
|
-
|
|
326
|
-
* Only sees **code changes** (not meetings, docs, etc.)
|
|
327
|
-
* Effort estimation is **heuristic, not accurate**
|
|
328
|
-
* Depends on git history quality
|
|
329
|
-
|
|
330
|
-
---
|
|
331
|
-
|
|
332
|
-
## Installation
|
|
333
|
-
|
|
334
|
-
```bash
|
|
335
|
-
pip install gitglimpse
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
Requirements:
|
|
339
|
-
|
|
340
|
-
* Python 3.11+
|
|
341
|
-
* git
|
|
342
|
-
* (optional) Ollama or API key
|
|
343
|
-
|
|
344
|
-
---
|
|
345
|
-
|
|
346
|
-
## Contributing
|
|
347
|
-
|
|
348
|
-
PRs welcome — especially for:
|
|
349
|
-
|
|
350
|
-
* better effort estimation
|
|
351
|
-
* smarter task grouping
|
|
352
|
-
* improved noise filtering
|
|
353
|
-
|
|
354
|
-
---
|
|
355
|
-
|
|
356
|
-
## License
|
|
357
|
-
|
|
358
|
-
MIT
|
|
359
|
-
|
|
360
|
-
---
|
|
361
|
-
|
|
362
|
-
<div align="center">
|
|
363
|
-
|
|
364
|
-
Built by Dino
|
|
365
|
-
|
|
366
|
-
</div>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.1.4"
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|