devgen-cli 0.2.7__py3-none-any.whl → 0.2.8__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.
devgen/cli/setup.py CHANGED
@@ -85,14 +85,14 @@ def setup_config() -> None:
85
85
  raise typer.Exit(code=130)
86
86
  ollama_host = ollama_host_input.strip() or ollama_host
87
87
 
88
- # Save Config
89
- new_config = {
88
+ # Save Config — merge with existing to preserve extra keys
89
+ new_config = {**current_config, **{
90
90
  "provider": provider,
91
91
  "model": model,
92
92
  "api_key": api_key,
93
93
  "emoji": emoji,
94
94
  "ollama_host": ollama_host,
95
- }
95
+ }}
96
96
 
97
97
  try:
98
98
  with config_path.open("w", encoding="utf-8") as f:
@@ -145,7 +145,7 @@ class ChangelogGenerator:
145
145
  old = path.read_text(encoding="utf-8")
146
146
  if old.strip().startswith("# CHANGELOG"):
147
147
  header, _, rest = old.partition("\n")
148
- new_content = f"{header}\n\n{md_content}\n{rest.lstrip()}"
148
+ new_content = f"{header}\n\n{md_content}\n{rest}"
149
149
  else:
150
150
  new_content = f"# CHANGELOG\n\n{md_content}\n\n{old}"
151
151
  else:
@@ -48,6 +48,7 @@ class CacheManager:
48
48
 
49
49
  def __init__(self, path: Path, max_age_minutes: int = 120) -> None:
50
50
  self.path = path
51
+ self.max_age_minutes = max_age_minutes
51
52
 
52
53
  def init_dry_run(self) -> None:
53
54
  self.path.parent.mkdir(parents=True, exist_ok=True)
@@ -59,7 +60,7 @@ class CacheManager:
59
60
  if dry_run:
60
61
  self.init_dry_run()
61
62
  return {}
62
- if not force_rebuild and is_file_recent(self.path):
63
+ if not force_rebuild and is_file_recent(self.path, self.max_age_minutes):
63
64
  return extract_commit_messages(self.path)
64
65
  return {}
65
66
 
@@ -70,7 +70,7 @@ class DiffBuilder:
70
70
  def _partition(self, files: List[str]) -> tuple[list[str], list[str]]:
71
71
  summary, to_diff = [], []
72
72
  for f in files:
73
- if any(p in f for p in IGNORED_DIFF_PATTERNS):
73
+ if Path(f).name in IGNORED_DIFF_PATTERNS:
74
74
  summary.append(f"[METADATA UPDATED] {f}")
75
75
  else:
76
76
  to_diff.append(f)
@@ -128,7 +128,11 @@ class FileGrouper:
128
128
  deepest = max(candidates, key=lambda p: len(Path(p).parts))
129
129
  parent_path = str(Path(deepest).parent)
130
130
  new_key = "root" if parent_path == "." else parent_path
131
- groups.setdefault(new_key, []).extend(groups.pop(deepest))
131
+ files = groups.pop(deepest)
132
+ if new_key in groups:
133
+ groups[new_key].extend(files)
134
+ else:
135
+ groups["root"].extend(files)
132
136
  return groups
133
137
 
134
138
 
devgen/modules/git_ops.py CHANGED
@@ -115,8 +115,11 @@ class GitOperator:
115
115
  self._run(["git", "add", *existing])
116
116
  if deleted:
117
117
  self._run(["git", "rm", *deleted])
118
- except GitError as e:
119
- raise GitError(f"Could not stage files: {e}") from e
118
+ except GitError:
119
+ # Fallback: file state may have changed between check and command.
120
+ # Try a single git add --all for the whole set; git will handle
121
+ # both additions and removals correctly.
122
+ self._run(["git", "add", "--all", "--", *files])
120
123
 
121
124
  def commit(self, message: str) -> None:
122
125
  """``git commit -m`` with the given message."""
@@ -16,4 +16,4 @@ class AnthropicProvider(BaseProvider):
16
16
  max_tokens=1024,
17
17
  messages=[{"role": "user", "content": prompt}],
18
18
  )
19
- return message.content[0].text
19
+ return message.content[0].text or ""
devgen/providers/base.py CHANGED
@@ -53,7 +53,8 @@ class BaseProvider(ABC):
53
53
  )
54
54
  chosen_model = model or self.DEFAULT_MODEL
55
55
  try:
56
- return self._generate(prompt, api_key, chosen_model, **kwargs).strip()
56
+ text = self._generate(prompt, api_key, chosen_model, **kwargs)
57
+ return (text or "").strip()
57
58
  except Exception as e:
58
59
  self._handle_error(e)
59
60
 
@@ -30,7 +30,7 @@ class GeminiProvider(BaseProvider):
30
30
  max_output_tokens=kwargs.get("max_output_tokens", 2048),
31
31
  ),
32
32
  )
33
- return response.text
33
+ return response.text or ""
34
34
  except Exception as e:
35
35
  if is_token_limit_error(e):
36
36
  raise # base class handles with friendly message
@@ -36,7 +36,7 @@ class OllamaProvider(BaseProvider):
36
36
  f"Ollama returned no choices for model {model!r}. "
37
37
  "The model may not be installed locally."
38
38
  )
39
- return response.choices[0].message.content
39
+ return response.choices[0].message.content or ""
40
40
 
41
41
  def _handle_error(self, error):
42
42
  """Override default wrapping — Ollama has no API key to check."""
@@ -17,4 +17,4 @@ class OpenaiProvider(BaseProvider):
17
17
  messages=[{"role": "user", "content": prompt}],
18
18
  **kwargs,
19
19
  )
20
- return response.choices[0].message.content
20
+ return response.choices[0].message.content or ""
devgen/utils.py CHANGED
@@ -209,6 +209,11 @@ def delete_file(filepath: Path | str) -> bool:
209
209
 
210
210
  def load_template_env(sub_dir: str) -> Environment:
211
211
  template_dir = Path(__file__).parent / "templates" / sub_dir
212
+ if not template_dir.is_dir():
213
+ raise RuntimeError(
214
+ f"Template directory not found: {template_dir}. "
215
+ "The installation may be corrupted."
216
+ )
212
217
  return Environment(loader=FileSystemLoader(template_dir))
213
218
 
214
219
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devgen-cli
3
- Version: 0.2.7
3
+ Version: 0.2.8
4
4
  Summary: A collection of developer tools
5
5
  Home-page: https://github.com/S4NKALP/devgen
6
6
  Author: Sankalp Tharu
@@ -1,6 +1,6 @@
1
1
  devgen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  devgen/ai.py,sha256=dUzAYTsYCa4p8c4mXGc1bkOYN9RznaFzDSif9BCjfx8,1821
3
- devgen/utils.py,sha256=-Qcr0eddNa8iissjHxcxG_ziE4-KGwZcszuhPN7a71k,10291
3
+ devgen/utils.py,sha256=UPmlzsjtNTJVEND76rhwSw3TencUowcOzvaweAkXoDI,10474
4
4
  devgen/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  devgen/cli/changelog.py,sha256=V8HhhzsIcI0CZQnJeUv06Zns4oCVS51ndFsnQC78HZ8,960
6
6
  devgen/cli/commit.py,sha256=MuK1VxJIRatKteeV1T9Pgzd29DCyNJZbld-NULKHj4s,4150
@@ -9,23 +9,23 @@ devgen/cli/gitignore.py,sha256=Nl7t_EZDhsOs5y-YkbOiuFLxHuAw48QTpw4_m9qJR2w,4446
9
9
  devgen/cli/license.py,sha256=LAwro2Mwf7PEQWORMFqwp__Mn0Kx3BPhqZR-ttuKAbk,2830
10
10
  devgen/cli/main.py,sha256=LBMZxMI7djpO2beccpRZWZ2DWS3tSblp3cmxAtTzu5c,3667
11
11
  devgen/cli/release.py,sha256=X0PfH7Vx__-CraiCNoMvxXWDmcmKdCdX16TYNubteV4,864
12
- devgen/cli/setup.py,sha256=KvNcSoJox6FVEyk5k_8g-yGghWExgKD719I63TNAywo,3008
12
+ devgen/cli/setup.py,sha256=aSEAf3Ny3ox3fynx5Go53AgqRwOVf0s4jTnnfQ_QcuQ,3077
13
13
  devgen/modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- devgen/modules/changelog_generator.py,sha256=xtIfJbHQaFf2mfumshQezb2s_4pQVxDcqWy-p-w9_z8,5725
14
+ devgen/modules/changelog_generator.py,sha256=7n4KM9VCkhke0NVYelJfBu1CVLnVT39pvZbvZ6RybYg,5716
15
15
  devgen/modules/changelog_sections.py,sha256=MuBGRZW3PBFRFbN4075BYHs0G1wWHEdPi2ekjMxSbvo,2414
16
- devgen/modules/commit_generator.py,sha256=hpop2bNTkkzCrCSgtM_EHRhykxtxYi_oYyYN9P0jfJU,12730
17
- devgen/modules/diff_builder.py,sha256=KUMiVITfwfPZ7jF-dZWtkMGGwSr-W9K8m-FhrZCufME,7325
18
- devgen/modules/git_ops.py,sha256=D4wS4cfn-FAgaogmOq25Fpig7TZE5DvtAe_qABoSyGA,5344
16
+ devgen/modules/commit_generator.py,sha256=6WhOCmWYelgr_-lMVDvgWmqoadfnDARAq8zrR74l1OM,12799
17
+ devgen/modules/diff_builder.py,sha256=Wj6ahAdbau5-LNmRJNO2nzx9MMkxX4WzQbinhFUU0O4,7432
18
+ devgen/modules/git_ops.py,sha256=SB-ptIVsgvhQyrpGUKq-E1RxFEvbMBTPdSL0RQdKhY4,5543
19
19
  devgen/modules/gitignore_generator.py,sha256=DpHAOrKIwSDklv7CLelYro478MQGJ4EcMAFi5E--348,4379
20
20
  devgen/modules/license_generator.py,sha256=YU25lNsD6_7zneuv9NpsT1sy_u5_FiC__0Qeou2O1kY,2634
21
21
  devgen/modules/release_note_generator.py,sha256=4FOi0rk9PWvECL84_uM5cPTZAFLvWfDGVRPuqsyCaQk,2267
22
22
  devgen/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
- devgen/providers/anthropic.py,sha256=OhExEt951Y94A0Q1jOye0LJqhvcFqNrquxz3eeGOX48,563
24
- devgen/providers/base.py,sha256=000kK4DCwwNmkEvWY8jDvcuVWVt3LxmlPYOZV26wXPc,3244
25
- devgen/providers/gemini.py,sha256=mhPtpGn4RU9TLa0o05wrvPMnq-WH0PUdsnWRp079Fp8,2717
23
+ devgen/providers/anthropic.py,sha256=Fu6PcfIvL_Ey-t7VQ7V6OlhoXaMukC3RmIl9Jx5dSsg,569
24
+ devgen/providers/base.py,sha256=1pJJzrEX8HZ0F9B9Xv766fRpNJkUVdaSY-Dmey29P1U,3276
25
+ devgen/providers/gemini.py,sha256=503wne2XX2mkE-l-3vWa8K0q6C6NSn-bEAo8Kk2iUNw,2723
26
26
  devgen/providers/huggingface.py,sha256=TgTDCGOOwDdKaHgZJVMrXFn5fYJ8W5YiF7uki3XSOf0,2242
27
- devgen/providers/ollama.py,sha256=NZqglIJBdPn94W_2oXqCCPFprRJghi0XDp7VEniz99A,1895
28
- devgen/providers/openai.py,sha256=km8cUkMdc_41OOXFozy5DIDvu8BYumviOFNA9rGRcMY,589
27
+ devgen/providers/ollama.py,sha256=667cGxtbi2GtyBvi6aeaRhRMzXZWWTvn2qSBB6dHTPU,1901
28
+ devgen/providers/openai.py,sha256=MfPW4-tdLJ682i3Qqz9z9pPhX161eWfACqgeO_Jl0xY,595
29
29
  devgen/providers/openrouter.py,sha256=4-5SgUMNnY4nuTtlCtdbrDJIAQo5hFTciIFttELI_Bs,839
30
30
  devgen/templates/commit/commit_message.tpl,sha256=vj9dUP_d1--TWiE0NMP3-EEBHmdJLdb2tQCDMdaPoAk,435
31
31
  devgen/templates/licenses/agpl-3.0.json,sha256=lYJObhc3-nBQQD2L3cw9C-Q9ceiV26qkzp6b1H7NnZ4,35832
@@ -41,9 +41,9 @@ devgen/templates/licenses/lgpl-2.1.json,sha256=M1uxVajrZBccW3gX5cYwMdZ0DyBLbxnmP
41
41
  devgen/templates/licenses/mit.json,sha256=NfRzL86O8TZOY2ZRdelQFEVX0t1o3bUJtqmib-pXM0s,1426
42
42
  devgen/templates/licenses/mpl-2.0.json,sha256=Fq-oj2-z5TZS2Qr9bQHea-Nm_baC2_7DQtuSKT476Yk,17729
43
43
  devgen/templates/licenses/unlicense.json,sha256=uWl_NnBn_Daqu-0df7y4E5H0q7KUdDby3TK1IHBDr4Y,1553
44
- devgen_cli-0.2.7.dist-info/licenses/LICENSE,sha256=-JHhLXXB2RRUeojKiRRTDHyJ1QiOCtrDfwbahUOb6Yc,35150
45
- devgen_cli-0.2.7.dist-info/METADATA,sha256=eQikHq_pImn0Zil0Nihs4kxGWOXVO-Z7YGdSL_W3dS8,8772
46
- devgen_cli-0.2.7.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
47
- devgen_cli-0.2.7.dist-info/entry_points.txt,sha256=NdqXSz3M3_0x0I3tFrXEF7r0mwCDmMfUNZbh2HDZSCg,47
48
- devgen_cli-0.2.7.dist-info/top_level.txt,sha256=u-4SzOUkP7II9PqLZ4PCpIAsxv4tuxuJ4gtdApYG4Bw,7
49
- devgen_cli-0.2.7.dist-info/RECORD,,
44
+ devgen_cli-0.2.8.dist-info/licenses/LICENSE,sha256=-JHhLXXB2RRUeojKiRRTDHyJ1QiOCtrDfwbahUOb6Yc,35150
45
+ devgen_cli-0.2.8.dist-info/METADATA,sha256=Gi-fskrat61KX5RVzSUzfllrOzk29p11ACsHo606G4k,8772
46
+ devgen_cli-0.2.8.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
47
+ devgen_cli-0.2.8.dist-info/entry_points.txt,sha256=NdqXSz3M3_0x0I3tFrXEF7r0mwCDmMfUNZbh2HDZSCg,47
48
+ devgen_cli-0.2.8.dist-info/top_level.txt,sha256=u-4SzOUkP7II9PqLZ4PCpIAsxv4tuxuJ4gtdApYG4Bw,7
49
+ devgen_cli-0.2.8.dist-info/RECORD,,