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.
Files changed (32) hide show
  1. gitglimpse-0.1.6/PKG-INFO +69 -0
  2. gitglimpse-0.1.6/PYPI_README.md +44 -0
  3. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/pyproject.toml +5 -4
  4. gitglimpse-0.1.6/src/gitglimpse/__init__.py +1 -0
  5. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/cli.py +50 -1
  6. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/providers/claude.py +13 -4
  7. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/providers/gemini.py +13 -4
  8. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/providers/local.py +14 -2
  9. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/providers/openai.py +13 -4
  10. gitglimpse-0.1.4/PKG-INFO +0 -391
  11. gitglimpse-0.1.4/README.md +0 -366
  12. gitglimpse-0.1.4/src/gitglimpse/__init__.py +0 -1
  13. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/.gitignore +0 -0
  14. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/LICENSE +0 -0
  15. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/commands/__init__.py +0 -0
  16. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/commands/pr.md +0 -0
  17. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/commands/report.md +0 -0
  18. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/commands/standup.md +0 -0
  19. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/commands/week.md +0 -0
  20. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/config.py +0 -0
  21. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/estimation.py +0 -0
  22. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/formatters/__init__.py +0 -0
  23. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/formatters/json.py +0 -0
  24. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/formatters/markdown.py +0 -0
  25. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/formatters/pr.py +0 -0
  26. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/formatters/template.py +0 -0
  27. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/git.py +0 -0
  28. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/grouping.py +0 -0
  29. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/onboarding.py +0 -0
  30. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/providers/__init__.py +0 -0
  31. {gitglimpse-0.1.4 → gitglimpse-0.1.6}/src/gitglimpse/providers/base.py +0 -0
  32. {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.4"
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 = "README.md"
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=_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
- _TIMEOUT = httpx.Timeout(connect=30.0, read=120.0, write=30.0, pool=30.0)
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=_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
- _TIMEOUT = httpx.Timeout(connect=30.0, read=120.0, write=30.0, pool=30.0)
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=_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
- [![Python 3.11+](https://img.shields.io/badge/python-3.11+-3776AB?logo=python&logoColor=white)](https://python.org)
37
- [![License: MIT](https://img.shields.io/badge/license-MIT-F59E0B)](LICENSE)
38
- [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen)](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
- ![Standup Demo](docs/demo-standup.gif)
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>
@@ -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
- [![Python 3.11+](https://img.shields.io/badge/python-3.11+-3776AB?logo=python&logoColor=white)](https://python.org)
12
- [![License: MIT](https://img.shields.io/badge/license-MIT-F59E0B)](LICENSE)
13
- [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen)](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
- ![Standup Demo](docs/demo-standup.gif)
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