specsmith 0.2.1.dev40__tar.gz → 0.2.1.dev41__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 (93) hide show
  1. {specsmith-0.2.1.dev40/src/specsmith.egg-info → specsmith-0.2.1.dev41}/PKG-INFO +1 -1
  2. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/pyproject.toml +1 -1
  3. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/auditor.py +9 -6
  4. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/cli.py +5 -4
  5. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/credit_analyzer.py +2 -4
  6. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/credits.py +8 -6
  7. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/importer.py +23 -7
  8. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/scaffolder.py +1 -3
  9. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/session.py +1 -2
  10. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/updater.py +5 -2
  11. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41/src/specsmith.egg-info}/PKG-INFO +1 -1
  12. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/tests/test_auditor.py +1 -0
  13. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/tests/test_cli.py +1 -0
  14. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/tests/test_integrations.py +1 -0
  15. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/tests/test_scaffolder.py +1 -0
  16. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/tests/test_smoke.py +1 -2
  17. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/tests/test_vcs.py +1 -0
  18. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/LICENSE +0 -0
  19. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/README.md +0 -0
  20. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/setup.cfg +0 -0
  21. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/__init__.py +0 -0
  22. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/__main__.py +0 -0
  23. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/architect.py +0 -0
  24. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/commands/__init__.py +0 -0
  25. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/compressor.py +0 -0
  26. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/config.py +0 -0
  27. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/differ.py +0 -0
  28. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/doctor.py +0 -0
  29. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/exporter.py +0 -0
  30. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/integrations/__init__.py +0 -0
  31. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/integrations/aider.py +0 -0
  32. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/integrations/base.py +0 -0
  33. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/integrations/claude_code.py +0 -0
  34. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/integrations/copilot.py +0 -0
  35. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/integrations/cursor.py +0 -0
  36. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/integrations/gemini.py +0 -0
  37. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/integrations/warp.py +0 -0
  38. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/integrations/windsurf.py +0 -0
  39. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/ledger.py +0 -0
  40. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/plugins.py +0 -0
  41. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/releaser.py +0 -0
  42. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/requirements.py +0 -0
  43. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/agents.md.j2 +0 -0
  44. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
  45. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
  46. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/community/contributing.md.j2 +0 -0
  47. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
  48. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
  49. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/community/license-MIT.j2 +0 -0
  50. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
  51. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/community/security.md.j2 +0 -0
  52. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
  53. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
  54. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
  55. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/docs/workflow.md.j2 +0 -0
  56. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/editorconfig.j2 +0 -0
  57. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/gitattributes.j2 +0 -0
  58. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/gitignore.j2 +0 -0
  59. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
  60. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
  61. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/governance/roles.md.j2 +0 -0
  62. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/governance/rules.md.j2 +0 -0
  63. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/governance/verification.md.j2 +0 -0
  64. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/governance/workflow.md.j2 +0 -0
  65. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/ledger.md.j2 +0 -0
  66. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/pyproject.toml.j2 +0 -0
  67. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/python/cli.py.j2 +0 -0
  68. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/python/init.py.j2 +0 -0
  69. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/readme.md.j2 +0 -0
  70. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
  71. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
  72. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
  73. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
  74. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
  75. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
  76. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/tools.py +0 -0
  77. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/upgrader.py +0 -0
  78. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/validator.py +0 -0
  79. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/vcs/__init__.py +0 -0
  80. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/vcs/base.py +0 -0
  81. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/vcs/bitbucket.py +0 -0
  82. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/vcs/github.py +0 -0
  83. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/vcs/gitlab.py +0 -0
  84. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith/vcs_commands.py +0 -0
  85. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith.egg-info/SOURCES.txt +0 -0
  86. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith.egg-info/dependency_links.txt +0 -0
  87. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith.egg-info/entry_points.txt +0 -0
  88. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith.egg-info/requires.txt +0 -0
  89. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/src/specsmith.egg-info/top_level.txt +0 -0
  90. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/tests/test_compressor.py +0 -0
  91. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/tests/test_importer.py +0 -0
  92. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/tests/test_tools.py +0 -0
  93. {specsmith-0.2.1.dev40 → specsmith-0.2.1.dev41}/tests/test_validator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specsmith
3
- Version: 0.2.1.dev40
3
+ Version: 0.2.1.dev41
4
4
  Summary: Forge governed project scaffolds from the Agentic AI Development Workflow Specification.
5
5
  Author: BitConcepts
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "specsmith"
7
- version = "0.2.1.dev40"
7
+ version = "0.2.1.dev41"
8
8
  description = "Forge governed project scaffolds from the Agentic AI Development Workflow Specification."
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -125,10 +125,14 @@ def check_governance_files(root: Path) -> list[AuditResult]:
125
125
  found = path.exists()
126
126
  # For architecture.md, also search subdirectories (e.g. docs/architecture/*.md)
127
127
  if not found and "architecture" in f:
128
- found = bool(
129
- list((root / "docs").glob("**/architecture*"))
130
- + list((root / "docs").glob("**/ARCHITECTURE*"))
131
- ) if (root / "docs").is_dir() else False
128
+ found = (
129
+ bool(
130
+ list((root / "docs").glob("**/architecture*"))
131
+ + list((root / "docs").glob("**/ARCHITECTURE*"))
132
+ )
133
+ if (root / "docs").is_dir()
134
+ else False
135
+ )
132
136
  results.append(
133
137
  AuditResult(
134
138
  name=f"recommended:{f}",
@@ -580,8 +584,7 @@ def run_auto_fix(root: Path, report: AuditReport) -> list[str]:
580
584
  path = root / "docs" / "ARCHITECTURE.md"
581
585
  path.parent.mkdir(parents=True, exist_ok=True)
582
586
  path.write_text(
583
- f"# Architecture — {root.name}\n\n"
584
- "[Run `specsmith architect` to populate]\n",
587
+ f"# Architecture — {root.name}\n\n[Run `specsmith architect` to populate]\n",
585
588
  encoding="utf-8",
586
589
  )
587
590
  fixed.append("Created stub docs/ARCHITECTURE.md")
@@ -703,9 +703,7 @@ def architect(project_dir: str, non_interactive: bool) -> None:
703
703
  f" [yellow]Note:[/yellow] Existing docs at {', '.join(existing)} "
704
704
  "are referenced but not merged. Review manually."
705
705
  )
706
- console.print(
707
- " [dim]Run \"specsmith audit --project-dir .\" to verify governance health.[/dim]"
708
- )
706
+ console.print(' [dim]Run "specsmith audit --project-dir ." to verify governance health.[/dim]')
709
707
 
710
708
 
711
709
  # ---------------------------------------------------------------------------
@@ -1463,7 +1461,10 @@ def credits_analyze(project_dir: str) -> None:
1463
1461
  "--watermarks", default=None, help="Comma-separated USD watermark alerts (e.g. 5,10,25,50)."
1464
1462
  )
1465
1463
  def credits_budget(
1466
- project_dir: str, cap: float | None, alert_pct: int | None, watermarks: str | None,
1464
+ project_dir: str,
1465
+ cap: float | None,
1466
+ alert_pct: int | None,
1467
+ watermarks: str | None,
1467
1468
  ) -> None:
1468
1469
  """View or set credit budget and alert thresholds."""
1469
1470
  from specsmith.credits import load_budget, save_budget
@@ -43,8 +43,7 @@ def analyze_spend(root: Path) -> AnalysisReport:
43
43
  severity="info",
44
44
  message="No credit data yet.",
45
45
  recommendation=(
46
- "Record usage with `specsmith credits record` "
47
- "or integrate with your AI agent."
46
+ "Record usage with `specsmith credits record` or integrate with your AI agent."
48
47
  ),
49
48
  )
50
49
  )
@@ -112,8 +111,7 @@ def analyze_spend(root: Path) -> AnalysisReport:
112
111
  category="governance",
113
112
  severity="info",
114
113
  message=(
115
- f"Governance files total {total_gov_lines} lines "
116
- f"across {len(gov_files)} files."
114
+ f"Governance files total {total_gov_lines} lines across {len(gov_files)} files."
117
115
  ),
118
116
  recommendation=(
119
117
  "Ensure agents lazy-load governance files. Only rules.md + workflow.md "
@@ -167,9 +167,9 @@ def record_usage(
167
167
  provider=provider,
168
168
  tokens_in=tokens_in,
169
169
  tokens_out=tokens_out,
170
- estimated_cost_usd=cost_usd if cost_usd is not None else estimate_cost(
171
- model, tokens_in, tokens_out
172
- ),
170
+ estimated_cost_usd=cost_usd
171
+ if cost_usd is not None
172
+ else estimate_cost(model, tokens_in, tokens_out),
173
173
  task=task,
174
174
  duration_seconds=duration_seconds,
175
175
  )
@@ -180,7 +180,10 @@ def record_usage(
180
180
 
181
181
 
182
182
  def get_summary(
183
- root: Path, *, since: str = "", month: str = "",
183
+ root: Path,
184
+ *,
185
+ since: str = "",
186
+ month: str = "",
184
187
  ) -> CreditSummary:
185
188
  """Get aggregate credit summary with budget alerts."""
186
189
  entries = _load_entries(root)
@@ -222,8 +225,7 @@ def get_summary(
222
225
  pct = (month_cost / budget.monthly_cap_usd) * 100 if budget.monthly_cap_usd else 0
223
226
  if pct >= 100:
224
227
  summary.alerts.append(
225
- f"BUDGET EXCEEDED: ${month_cost:.2f} / ${budget.monthly_cap_usd:.2f} "
226
- f"({pct:.0f}%)"
228
+ f"BUDGET EXCEEDED: ${month_cost:.2f} / ${budget.monthly_cap_usd:.2f} ({pct:.0f}%)"
227
229
  )
228
230
  elif pct >= budget.alert_threshold_pct:
229
231
  summary.alerts.append(
@@ -790,15 +790,31 @@ def _extract_governance_sections(root: Path) -> dict[str, str]:
790
790
  # Body-level content keywords for secondary classification.
791
791
  # Used when heading doesn't match — scan body text for strong signals.
792
792
  _BODY_ARCHITECTURE_KW = [
793
- "register map", "address offset", "0x0", "register name",
794
- "block diagram", "data flow", "interface spec",
795
- "directory layout", "src/", "repository structure",
796
- "milestone", "roadmap", "completion", "phase 2 target",
793
+ "register map",
794
+ "address offset",
795
+ "0x0",
796
+ "register name",
797
+ "block diagram",
798
+ "data flow",
799
+ "interface spec",
800
+ "directory layout",
801
+ "src/",
802
+ "repository structure",
803
+ "milestone",
804
+ "roadmap",
805
+ "completion",
806
+ "phase 2 target",
797
807
  ]
798
808
  _BODY_DRIFT_KW = [
799
- "subst v:", "path-length", "one-time setup", "per-machine",
800
- "environment variable", "install once", "bootstrap",
801
- "windows path", "ntfs",
809
+ "subst v:",
810
+ "path-length",
811
+ "one-time setup",
812
+ "per-machine",
813
+ "environment variable",
814
+ "install once",
815
+ "bootstrap",
816
+ "windows path",
817
+ "ntfs",
802
818
  ]
803
819
 
804
820
  for heading, body in sections.items():
@@ -406,9 +406,7 @@ def _build_community_files(config: ProjectConfig) -> list[tuple[str, str]]:
406
406
  files.append(("community/code_of_conduct.md.j2", "CODE_OF_CONDUCT.md"))
407
407
 
408
408
  if "pr-template" in cf and config.vcs_platform == "github":
409
- files.append(
410
- ("community/pull_request_template.md.j2", ".github/PULL_REQUEST_TEMPLATE.md")
411
- )
409
+ files.append(("community/pull_request_template.md.j2", ".github/PULL_REQUEST_TEMPLATE.md"))
412
410
 
413
411
  if "issue-templates" in cf and config.vcs_platform == "github":
414
412
  files.extend(
@@ -138,8 +138,7 @@ def run_session_end(root: Path) -> SessionReport:
138
138
  name="credits",
139
139
  status="ok",
140
140
  message=(
141
- f"Credits: ${cs.total_cost_usd:.4f} total, "
142
- f"{cs.session_count} session(s)"
141
+ f"Credits: ${cs.total_cost_usd:.4f} total, {cs.session_count} session(s)"
143
142
  ),
144
143
  )
145
144
  )
@@ -19,7 +19,8 @@ def get_update_channel() -> str:
19
19
 
20
20
 
21
21
  def check_latest_version(
22
- *, channel: str = "",
22
+ *,
23
+ channel: str = "",
23
24
  ) -> tuple[str, str, str]:
24
25
  """Check PyPI for the latest specsmith version.
25
26
 
@@ -60,7 +61,9 @@ def is_outdated() -> bool:
60
61
 
61
62
 
62
63
  def run_self_update(
63
- *, channel: str = "", target_version: str = "",
64
+ *,
65
+ channel: str = "",
66
+ target_version: str = "",
64
67
  ) -> tuple[bool, str]:
65
68
  """Update specsmith via pip.
66
69
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specsmith
3
- Version: 0.2.1.dev40
3
+ Version: 0.2.1.dev41
4
4
  Summary: Forge governed project scaffolds from the Agentic AI Development Workflow Specification.
5
5
  Author: BitConcepts
6
6
  License: MIT
@@ -7,6 +7,7 @@ from __future__ import annotations
7
7
  from pathlib import Path
8
8
 
9
9
  import pytest
10
+
10
11
  from specsmith.auditor import run_audit
11
12
 
12
13
 
@@ -8,6 +8,7 @@ from pathlib import Path
8
8
 
9
9
  import yaml
10
10
  from click.testing import CliRunner
11
+
11
12
  from specsmith.cli import main
12
13
  from specsmith.config import ProjectConfig, ProjectType
13
14
  from specsmith.scaffolder import scaffold_project
@@ -7,6 +7,7 @@ from __future__ import annotations
7
7
  from pathlib import Path
8
8
 
9
9
  import pytest
10
+
10
11
  from specsmith.config import ProjectConfig, ProjectType
11
12
  from specsmith.integrations import get_adapter, list_adapters
12
13
  from specsmith.integrations.claude_code import ClaudeCodeAdapter
@@ -7,6 +7,7 @@ from __future__ import annotations
7
7
  from pathlib import Path
8
8
 
9
9
  import pytest
10
+
10
11
  from specsmith.config import Platform, ProjectConfig, ProjectType
11
12
  from specsmith.scaffolder import scaffold_project
12
13
 
@@ -4,9 +4,8 @@
4
4
 
5
5
  from importlib.metadata import version as _pkg_version
6
6
 
7
- from specsmith.config import Platform, ProjectConfig, ProjectType
8
-
9
7
  from specsmith import __version__
8
+ from specsmith.config import Platform, ProjectConfig, ProjectType
10
9
 
11
10
 
12
11
  def test_version():
@@ -7,6 +7,7 @@ from __future__ import annotations
7
7
  from pathlib import Path
8
8
 
9
9
  import pytest
10
+
10
11
  from specsmith.config import Platform, ProjectConfig, ProjectType
11
12
  from specsmith.vcs import get_platform, list_platforms
12
13
  from specsmith.vcs.base import CommandResult
File without changes