specsmith 0.1.4.dev26__tar.gz → 0.1.4.dev30__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.
- {specsmith-0.1.4.dev26/src/specsmith.egg-info → specsmith-0.1.4.dev30}/PKG-INFO +1 -1
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/pyproject.toml +1 -1
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/auditor.py +54 -10
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/importer.py +134 -14
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/scaffolder.py +1 -0
- specsmith-0.1.4.dev30/src/specsmith/templates/editorconfig.j2 +93 -0
- specsmith-0.1.4.dev30/src/specsmith/templates/gitattributes.j2 +146 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/gitignore.j2 +71 -1
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/tools.py +22 -3
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30/src/specsmith.egg-info}/PKG-INFO +1 -1
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith.egg-info/SOURCES.txt +1 -0
- specsmith-0.1.4.dev26/src/specsmith/templates/gitattributes.j2 +0 -15
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/LICENSE +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/README.md +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/setup.cfg +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/__init__.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/__main__.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/cli.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/commands/__init__.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/compressor.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/config.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/differ.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/doctor.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/exporter.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/integrations/__init__.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/integrations/aider.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/integrations/base.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/integrations/claude_code.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/integrations/copilot.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/integrations/cursor.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/integrations/gemini.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/integrations/warp.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/integrations/windsurf.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/ledger.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/plugins.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/releaser.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/requirements.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/session.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/agents.md.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/docs/workflow.md.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/governance/roles.md.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/governance/rules.md.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/governance/verification.md.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/governance/workflow.md.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/ledger.md.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/pyproject.toml.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/python/cli.py.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/python/init.py.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/readme.md.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/updater.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/upgrader.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/validator.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/vcs/__init__.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/vcs/base.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/vcs/bitbucket.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/vcs/github.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/vcs/gitlab.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/vcs_commands.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith.egg-info/dependency_links.txt +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith.egg-info/entry_points.txt +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith.egg-info/requires.txt +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith.egg-info/top_level.txt +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/tests/test_auditor.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/tests/test_cli.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/tests/test_compressor.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/tests/test_importer.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/tests/test_integrations.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/tests/test_scaffolder.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/tests/test_smoke.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/tests/test_tools.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/tests/test_validator.py +0 -0
- {specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/tests/test_vcs.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "specsmith"
|
|
7
|
-
version = "0.1.4.
|
|
7
|
+
version = "0.1.4.dev30"
|
|
8
8
|
description = "Forge governed project scaffolds from the Agentic AI Development Workflow Specification."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -283,18 +283,62 @@ def check_ledger_health(root: Path) -> list[AuditResult]:
|
|
|
283
283
|
# ---------------------------------------------------------------------------
|
|
284
284
|
|
|
285
285
|
|
|
286
|
+
# Default thresholds (used when no project type is detected)
|
|
287
|
+
_DEFAULT_THRESHOLDS: dict[str, int] = {
|
|
288
|
+
"AGENTS.md": 200,
|
|
289
|
+
"docs/governance/rules.md": 800,
|
|
290
|
+
"docs/governance/workflow.md": 400,
|
|
291
|
+
"docs/governance/roles.md": 300,
|
|
292
|
+
"docs/governance/context-budget.md": 300,
|
|
293
|
+
"docs/governance/verification.md": 400,
|
|
294
|
+
"docs/governance/drift-metrics.md": 300,
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
# Type-specific overrides — hardware/embedded projects have denser rules.
|
|
298
|
+
_TYPE_THRESHOLD_OVERRIDES: dict[str, dict[str, int]] = {
|
|
299
|
+
"fpga-rtl": {
|
|
300
|
+
"docs/governance/rules.md": 1000,
|
|
301
|
+
"docs/governance/workflow.md": 500,
|
|
302
|
+
"docs/governance/verification.md": 600,
|
|
303
|
+
},
|
|
304
|
+
"yocto-bsp": {
|
|
305
|
+
"docs/governance/rules.md": 1000,
|
|
306
|
+
"docs/governance/workflow.md": 500,
|
|
307
|
+
"docs/governance/verification.md": 500,
|
|
308
|
+
},
|
|
309
|
+
"embedded-hardware": {
|
|
310
|
+
"docs/governance/rules.md": 1000,
|
|
311
|
+
"docs/governance/verification.md": 500,
|
|
312
|
+
},
|
|
313
|
+
"pcb-hardware": {
|
|
314
|
+
"docs/governance/rules.md": 900,
|
|
315
|
+
"docs/governance/verification.md": 500,
|
|
316
|
+
},
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def _get_thresholds(root: Path) -> dict[str, int]:
|
|
321
|
+
"""Get governance size thresholds, scaled by project type if available."""
|
|
322
|
+
thresholds = dict(_DEFAULT_THRESHOLDS)
|
|
323
|
+
scaffold_path = root / "scaffold.yml"
|
|
324
|
+
if scaffold_path.exists():
|
|
325
|
+
try:
|
|
326
|
+
import yaml
|
|
327
|
+
|
|
328
|
+
with open(scaffold_path) as f:
|
|
329
|
+
raw = yaml.safe_load(f) or {}
|
|
330
|
+
ptype = raw.get("type", "")
|
|
331
|
+
overrides = _TYPE_THRESHOLD_OVERRIDES.get(ptype, {})
|
|
332
|
+
thresholds.update(overrides)
|
|
333
|
+
except Exception: # noqa: BLE001
|
|
334
|
+
pass # Use defaults on any error
|
|
335
|
+
return thresholds
|
|
336
|
+
|
|
337
|
+
|
|
286
338
|
def check_context_size(root: Path) -> list[AuditResult]:
|
|
287
|
-
"""Check governance file sizes against thresholds."""
|
|
339
|
+
"""Check governance file sizes against type-aware thresholds."""
|
|
288
340
|
results: list[AuditResult] = []
|
|
289
|
-
thresholds =
|
|
290
|
-
"AGENTS.md": 200,
|
|
291
|
-
"docs/governance/rules.md": 300,
|
|
292
|
-
"docs/governance/workflow.md": 300,
|
|
293
|
-
"docs/governance/roles.md": 200,
|
|
294
|
-
"docs/governance/context-budget.md": 200,
|
|
295
|
-
"docs/governance/verification.md": 200,
|
|
296
|
-
"docs/governance/drift-metrics.md": 200,
|
|
297
|
-
}
|
|
341
|
+
thresholds = _get_thresholds(root)
|
|
298
342
|
|
|
299
343
|
for rel_path, max_lines in thresholds.items():
|
|
300
344
|
path = root / rel_path
|
|
@@ -38,6 +38,10 @@ _EXT_LANG: dict[str, str] = {
|
|
|
38
38
|
".yaml": "yaml",
|
|
39
39
|
".bb": "bitbake",
|
|
40
40
|
".bbappend": "bitbake",
|
|
41
|
+
".bbclass": "bitbake",
|
|
42
|
+
".inc": "bitbake",
|
|
43
|
+
".dts": "devicetree",
|
|
44
|
+
".dtsi": "devicetree",
|
|
41
45
|
".proto": "protobuf",
|
|
42
46
|
".graphql": "graphql",
|
|
43
47
|
".gql": "graphql",
|
|
@@ -64,6 +68,7 @@ _BUILD_SYSTEMS: dict[str, str] = {
|
|
|
64
68
|
"build.gradle.kts": "gradle",
|
|
65
69
|
"meson.build": "meson",
|
|
66
70
|
"bitbake": "bitbake",
|
|
71
|
+
"kas.yml": "kas",
|
|
67
72
|
"west.yml": "west",
|
|
68
73
|
"pubspec.yaml": "flutter",
|
|
69
74
|
"*.csproj": "dotnet",
|
|
@@ -629,11 +634,75 @@ _DRIFT_KW: list[str] = [
|
|
|
629
634
|
]
|
|
630
635
|
|
|
631
636
|
|
|
637
|
+
def _clean_diff_markers(text: str) -> str:
|
|
638
|
+
"""Strip git diff/merge conflict artifacts from text.
|
|
639
|
+
|
|
640
|
+
Removes leading |-, |+, || prefixes and <<<<<<< / >>>>>>> markers.
|
|
641
|
+
"""
|
|
642
|
+
import re
|
|
643
|
+
|
|
644
|
+
cleaned_lines: list[str] = []
|
|
645
|
+
skip_block = False
|
|
646
|
+
for line in text.splitlines():
|
|
647
|
+
# Skip merge conflict markers entirely
|
|
648
|
+
if line.startswith(("<<<<<<", ">>>>>>", "======")):
|
|
649
|
+
skip_block = not skip_block if line.startswith("<<<<<<") else skip_block
|
|
650
|
+
if line.startswith(">>>>>>>"):
|
|
651
|
+
skip_block = False
|
|
652
|
+
continue
|
|
653
|
+
if skip_block:
|
|
654
|
+
continue
|
|
655
|
+
# Strip diff marker prefixes: |-, |+, ||, leading +, leading -
|
|
656
|
+
stripped = re.sub(r"^\|{1,2}[-+]\s?", "", line)
|
|
657
|
+
stripped = re.sub(r"^[-+]\s(?=[A-Z])", "", stripped) # +/- before prose
|
|
658
|
+
cleaned_lines.append(stripped)
|
|
659
|
+
return "\n".join(cleaned_lines)
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
def _detect_content_issues(text: str) -> list[str]:
|
|
663
|
+
"""Detect quality issues in source text. Returns list of warnings."""
|
|
664
|
+
import re
|
|
665
|
+
|
|
666
|
+
warnings: list[str] = []
|
|
667
|
+
lines = text.splitlines()
|
|
668
|
+
diff_marker_count = 0
|
|
669
|
+
for i, line in enumerate(lines, 1):
|
|
670
|
+
# Diff markers
|
|
671
|
+
if re.match(r"^\|{1,2}[-+]", line):
|
|
672
|
+
diff_marker_count += 1
|
|
673
|
+
# Merge conflict markers
|
|
674
|
+
if line.startswith(("<<<<<<", ">>>>>>")):
|
|
675
|
+
warnings.append(f" Line {i}: unresolved merge conflict marker")
|
|
676
|
+
if diff_marker_count > 0:
|
|
677
|
+
warnings.append(
|
|
678
|
+
f" {diff_marker_count} line(s) with git diff markers (|-, |+) — auto-stripped"
|
|
679
|
+
)
|
|
680
|
+
return warnings
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
def _deduplicate_paragraphs(text: str) -> str:
|
|
684
|
+
"""Remove duplicate paragraphs within a text block."""
|
|
685
|
+
paragraphs = text.split("\n\n")
|
|
686
|
+
seen: set[str] = set()
|
|
687
|
+
unique: list[str] = []
|
|
688
|
+
for para in paragraphs:
|
|
689
|
+
normalized = para.strip()
|
|
690
|
+
if not normalized:
|
|
691
|
+
continue
|
|
692
|
+
# Use first 200 chars as dedup key (handles minor formatting diffs)
|
|
693
|
+
key = normalized[:200].lower()
|
|
694
|
+
if key not in seen:
|
|
695
|
+
seen.add(key)
|
|
696
|
+
unique.append(para)
|
|
697
|
+
return "\n\n".join(unique)
|
|
698
|
+
|
|
699
|
+
|
|
632
700
|
def _extract_governance_sections(root: Path) -> dict[str, str]:
|
|
633
701
|
"""Extract modular governance content from existing AGENTS.md.
|
|
634
702
|
|
|
635
703
|
If AGENTS.md exists and is large, extract sections into modular files.
|
|
636
704
|
Unmatched sections are collected into rules.md so nothing is lost.
|
|
705
|
+
Diff markers are stripped and duplicate paragraphs are removed.
|
|
637
706
|
"""
|
|
638
707
|
defaults = {
|
|
639
708
|
"rules": (
|
|
@@ -663,10 +732,21 @@ def _extract_governance_sections(root: Path) -> dict[str, str]:
|
|
|
663
732
|
if not agents_path.exists():
|
|
664
733
|
return defaults
|
|
665
734
|
|
|
666
|
-
|
|
667
|
-
if len(
|
|
735
|
+
raw_content = agents_path.read_text(encoding="utf-8")
|
|
736
|
+
if len(raw_content.splitlines()) < 50:
|
|
668
737
|
return defaults # Too short to extract from
|
|
669
738
|
|
|
739
|
+
# P0: Detect and report content issues, then clean diff markers
|
|
740
|
+
issues = _detect_content_issues(raw_content)
|
|
741
|
+
if issues:
|
|
742
|
+
import sys
|
|
743
|
+
|
|
744
|
+
print("\n[specsmith] Content quality warnings in AGENTS.md:", file=sys.stderr) # noqa: T201
|
|
745
|
+
for w in issues:
|
|
746
|
+
print(w, file=sys.stderr) # noqa: T201
|
|
747
|
+
|
|
748
|
+
content = _clean_diff_markers(raw_content)
|
|
749
|
+
|
|
670
750
|
# Parse AGENTS.md into sections by ## headings
|
|
671
751
|
sections: dict[str, str] = {}
|
|
672
752
|
current_heading = ""
|
|
@@ -706,6 +786,20 @@ def _extract_governance_sections(root: Path) -> dict[str, str]:
|
|
|
706
786
|
}
|
|
707
787
|
unmatched: list[tuple[str, str]] = []
|
|
708
788
|
|
|
789
|
+
# Body-level content keywords for secondary classification.
|
|
790
|
+
# Used when heading doesn't match — scan body text for strong signals.
|
|
791
|
+
_BODY_ARCHITECTURE_KW = [
|
|
792
|
+
"register map", "address offset", "0x0", "register name",
|
|
793
|
+
"block diagram", "data flow", "interface spec",
|
|
794
|
+
"directory layout", "src/", "repository structure",
|
|
795
|
+
"milestone", "roadmap", "completion", "phase 2 target",
|
|
796
|
+
]
|
|
797
|
+
_BODY_DRIFT_KW = [
|
|
798
|
+
"subst v:", "path-length", "one-time setup", "per-machine",
|
|
799
|
+
"environment variable", "install once", "bootstrap",
|
|
800
|
+
"windows path", "ntfs",
|
|
801
|
+
]
|
|
802
|
+
|
|
709
803
|
for heading, body in sections.items():
|
|
710
804
|
key_lower = heading.lower()
|
|
711
805
|
matched = False
|
|
@@ -715,7 +809,14 @@ def _extract_governance_sections(root: Path) -> dict[str, str]:
|
|
|
715
809
|
matched = True
|
|
716
810
|
break # First match wins
|
|
717
811
|
if not matched:
|
|
718
|
-
|
|
812
|
+
# Secondary pass: scan body content for strong topic signals
|
|
813
|
+
body_lower = body[:2000].lower() # Cap scan for performance
|
|
814
|
+
if any(kw in body_lower for kw in _BODY_ARCHITECTURE_KW):
|
|
815
|
+
buckets["verification"].append((heading, body)) # technical reference
|
|
816
|
+
elif any(kw in body_lower for kw in _BODY_DRIFT_KW):
|
|
817
|
+
buckets["drift-metrics"].append((heading, body))
|
|
818
|
+
else:
|
|
819
|
+
unmatched.append((heading, body))
|
|
719
820
|
|
|
720
821
|
# Unmatched sections go to rules.md as project-specific rules
|
|
721
822
|
if unmatched:
|
|
@@ -739,7 +840,8 @@ def _extract_governance_sections(root: Path) -> dict[str, str]:
|
|
|
739
840
|
parts.append(f"## {heading}\n")
|
|
740
841
|
parts.append(body)
|
|
741
842
|
parts.append("")
|
|
742
|
-
|
|
843
|
+
# P1: Deduplicate paragraphs within each governance file
|
|
844
|
+
result[category] = _deduplicate_paragraphs("\n".join(parts)) + "\n"
|
|
743
845
|
|
|
744
846
|
return result
|
|
745
847
|
|
|
@@ -752,7 +854,7 @@ def _infer_type(result: DetectionResult) -> ProjectType:
|
|
|
752
854
|
# Hardware types
|
|
753
855
|
if lang in ("vhdl", "verilog", "systemverilog"):
|
|
754
856
|
return ProjectType.FPGA_RTL
|
|
755
|
-
if lang == "bitbake" or build
|
|
857
|
+
if lang == "bitbake" or build in ("bitbake", "kas"):
|
|
756
858
|
return ProjectType.YOCTO_BSP
|
|
757
859
|
|
|
758
860
|
# Language-specific
|
|
@@ -891,8 +993,14 @@ def generate_overlay(
|
|
|
891
993
|
f"- Build system: {result.build_system}\n",
|
|
892
994
|
)
|
|
893
995
|
|
|
894
|
-
# docs/REQUIREMENTS.md
|
|
895
|
-
|
|
996
|
+
# docs/REQUIREMENTS.md — skip if project already has one (anywhere under docs/)
|
|
997
|
+
existing_reqs = list(target.glob("docs/**/REQUIREMENTS*")) + list(
|
|
998
|
+
target.glob("docs/**/requirements*")
|
|
999
|
+
)
|
|
1000
|
+
if existing_reqs and not force:
|
|
1001
|
+
pass # Preserve existing requirements doc
|
|
1002
|
+
else:
|
|
1003
|
+
reqs = "# Requirements\n\nRequirements auto-generated from project detection.\n\n"
|
|
896
1004
|
for module in result.modules:
|
|
897
1005
|
mu = module.upper().replace(" ", "-")
|
|
898
1006
|
reqs += (
|
|
@@ -908,10 +1016,16 @@ def generate_overlay(
|
|
|
908
1016
|
"- **Status**: Draft\n"
|
|
909
1017
|
f"- **Description**: Project builds successfully with {result.build_system}\n\n"
|
|
910
1018
|
)
|
|
911
|
-
|
|
1019
|
+
_write("docs/REQUIREMENTS.md", reqs)
|
|
912
1020
|
|
|
913
|
-
# docs/TEST_SPEC.md
|
|
914
|
-
|
|
1021
|
+
# docs/TEST_SPEC.md — skip if project already has one
|
|
1022
|
+
existing_tests = list(target.glob("docs/**/TEST_SPEC*")) + list(
|
|
1023
|
+
target.glob("docs/**/test_spec*")
|
|
1024
|
+
)
|
|
1025
|
+
if existing_tests and not force:
|
|
1026
|
+
pass # Preserve existing test spec
|
|
1027
|
+
else:
|
|
1028
|
+
tests = "# Test Specification\n\nTests auto-generated from project detection.\n\n"
|
|
915
1029
|
for i, test_file in enumerate(result.test_files[:20], 1):
|
|
916
1030
|
tests += f"## TEST-{i:03d}\n- **File**: {test_file}\n- **Status**: Detected\n"
|
|
917
1031
|
for module in result.modules:
|
|
@@ -919,10 +1033,16 @@ def generate_overlay(
|
|
|
919
1033
|
tests += f"- **Requirement**: REQ-{module.upper()}-001\n"
|
|
920
1034
|
break
|
|
921
1035
|
tests += "\n"
|
|
922
|
-
|
|
1036
|
+
_write("docs/TEST_SPEC.md", tests)
|
|
923
1037
|
|
|
924
|
-
# docs/architecture.md
|
|
925
|
-
|
|
1038
|
+
# docs/architecture.md — skip if project has architecture doc anywhere under docs/
|
|
1039
|
+
existing_arch = list(target.glob("docs/**/architecture*")) + list(
|
|
1040
|
+
target.glob("docs/**/ARCHITECTURE*")
|
|
1041
|
+
)
|
|
1042
|
+
if existing_arch and not force:
|
|
1043
|
+
pass # Preserve existing architecture doc
|
|
1044
|
+
else:
|
|
1045
|
+
arch = (
|
|
926
1046
|
f"# Architecture — {name}\n\n"
|
|
927
1047
|
"Architecture auto-generated from project detection.\n\n"
|
|
928
1048
|
"## Overview\n"
|
|
@@ -944,7 +1064,7 @@ def generate_overlay(
|
|
|
944
1064
|
arch += "## Language Distribution\n"
|
|
945
1065
|
for lang_name, count in sorted(result.languages.items(), key=lambda x: -x[1]):
|
|
946
1066
|
arch += f"- {lang_name}: {count} files\n"
|
|
947
|
-
|
|
1067
|
+
_write("docs/architecture.md", arch)
|
|
948
1068
|
|
|
949
1069
|
# --- Modular governance files ---
|
|
950
1070
|
# If AGENTS.md exists and is rich, extract sections from it.
|
|
@@ -100,6 +100,7 @@ def _build_file_map(config: ProjectConfig) -> list[tuple[str, str]]:
|
|
|
100
100
|
("readme.md.j2", "README.md"),
|
|
101
101
|
("gitignore.j2", ".gitignore"),
|
|
102
102
|
("gitattributes.j2", ".gitattributes"),
|
|
103
|
+
("editorconfig.j2", ".editorconfig"),
|
|
103
104
|
# Modular governance
|
|
104
105
|
("governance/rules.md.j2", "docs/governance/rules.md"),
|
|
105
106
|
("governance/workflow.md.j2", "docs/governance/workflow.md"),
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# EditorConfig — https://editorconfig.org
|
|
2
|
+
root = true
|
|
3
|
+
|
|
4
|
+
[*]
|
|
5
|
+
charset = utf-8
|
|
6
|
+
end_of_line = lf
|
|
7
|
+
insert_final_newline = true
|
|
8
|
+
trim_trailing_whitespace = true
|
|
9
|
+
indent_style = space
|
|
10
|
+
indent_size = 4
|
|
11
|
+
{% if project.type.value in ('cli-python', 'library-python', 'backend-frontend', 'backend-frontend-tray', 'data-ml') %}
|
|
12
|
+
|
|
13
|
+
[*.py]
|
|
14
|
+
indent_size = 4
|
|
15
|
+
max_line_length = 100
|
|
16
|
+
{% endif %}
|
|
17
|
+
{% if project.type.value in ('cli-rust', 'library-rust') %}
|
|
18
|
+
|
|
19
|
+
[*.rs]
|
|
20
|
+
indent_size = 4
|
|
21
|
+
max_line_length = 100
|
|
22
|
+
{% endif %}
|
|
23
|
+
{% if project.type.value in ('cli-go',) %}
|
|
24
|
+
|
|
25
|
+
[*.go]
|
|
26
|
+
indent_style = tab
|
|
27
|
+
indent_size = 4
|
|
28
|
+
{% endif %}
|
|
29
|
+
{% if project.type.value in ('cli-c', 'library-c', 'embedded-hardware') %}
|
|
30
|
+
|
|
31
|
+
[*.{c,h,cpp,hpp}]
|
|
32
|
+
indent_size = 4
|
|
33
|
+
{% endif %}
|
|
34
|
+
{% if project.type.value in ('web-frontend', 'fullstack-js', 'browser-extension', 'monorepo') %}
|
|
35
|
+
|
|
36
|
+
[*.{js,ts,jsx,tsx,css,scss,html}]
|
|
37
|
+
indent_size = 2
|
|
38
|
+
|
|
39
|
+
[*.json]
|
|
40
|
+
indent_size = 2
|
|
41
|
+
{% endif %}
|
|
42
|
+
{% if project.type.value == 'dotnet-app' %}
|
|
43
|
+
|
|
44
|
+
[*.cs]
|
|
45
|
+
indent_size = 4
|
|
46
|
+
|
|
47
|
+
[*.csproj]
|
|
48
|
+
indent_size = 2
|
|
49
|
+
{% endif %}
|
|
50
|
+
{% if project.type.value == 'fpga-rtl' %}
|
|
51
|
+
|
|
52
|
+
[*.{vhd,vhdl}]
|
|
53
|
+
indent_size = 2
|
|
54
|
+
|
|
55
|
+
[*.{v,sv}]
|
|
56
|
+
indent_size = 2
|
|
57
|
+
|
|
58
|
+
[*.{xdc,sdc,tcl}]
|
|
59
|
+
indent_size = 2
|
|
60
|
+
{% endif %}
|
|
61
|
+
{% if project.type.value in ('yocto-bsp',) %}
|
|
62
|
+
|
|
63
|
+
[*.{bb,bbappend,bbclass,conf}]
|
|
64
|
+
indent_size = 4
|
|
65
|
+
|
|
66
|
+
[*.{dts,dtsi}]
|
|
67
|
+
indent_size = 4
|
|
68
|
+
{% endif %}
|
|
69
|
+
{% if project.type.value in ('research-paper',) %}
|
|
70
|
+
|
|
71
|
+
[*.{tex,bib}]
|
|
72
|
+
indent_size = 2
|
|
73
|
+
{% endif %}
|
|
74
|
+
{% if project.type.value in ('devops-iac',) %}
|
|
75
|
+
|
|
76
|
+
[*.{tf,hcl,tfvars}]
|
|
77
|
+
indent_size = 2
|
|
78
|
+
{% endif %}
|
|
79
|
+
|
|
80
|
+
[*.{yml,yaml}]
|
|
81
|
+
indent_size = 2
|
|
82
|
+
|
|
83
|
+
[*.md]
|
|
84
|
+
trim_trailing_whitespace = false
|
|
85
|
+
|
|
86
|
+
[Makefile]
|
|
87
|
+
indent_style = tab
|
|
88
|
+
|
|
89
|
+
[*.{cmd,bat}]
|
|
90
|
+
end_of_line = crlf
|
|
91
|
+
|
|
92
|
+
[*.{ps1,psm1}]
|
|
93
|
+
end_of_line = crlf
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Auto-detect text files and normalize line endings
|
|
2
|
+
* text=auto
|
|
3
|
+
|
|
4
|
+
# Common text files
|
|
5
|
+
*.md text eol=lf
|
|
6
|
+
*.txt text eol=lf
|
|
7
|
+
*.yml text eol=lf
|
|
8
|
+
*.yaml text eol=lf
|
|
9
|
+
*.json text eol=lf
|
|
10
|
+
*.toml text eol=lf
|
|
11
|
+
*.cfg text eol=lf
|
|
12
|
+
*.ini text eol=lf
|
|
13
|
+
*.xml text eol=lf
|
|
14
|
+
.gitignore text eol=lf
|
|
15
|
+
.gitattributes text eol=lf
|
|
16
|
+
.editorconfig text eol=lf
|
|
17
|
+
|
|
18
|
+
# Shell scripts
|
|
19
|
+
*.sh text eol=lf
|
|
20
|
+
*.bash text eol=lf
|
|
21
|
+
*.cmd text eol=crlf
|
|
22
|
+
*.bat text eol=crlf
|
|
23
|
+
*.ps1 text eol=crlf
|
|
24
|
+
*.psm1 text eol=crlf
|
|
25
|
+
{% if project.type.value in ('cli-python', 'library-python', 'backend-frontend', 'backend-frontend-tray', 'data-ml') %}
|
|
26
|
+
|
|
27
|
+
# Python
|
|
28
|
+
*.py text eol=lf
|
|
29
|
+
*.pyi text eol=lf
|
|
30
|
+
*.pyx text eol=lf
|
|
31
|
+
{% endif %}
|
|
32
|
+
{% if project.type.value in ('cli-rust', 'library-rust') %}
|
|
33
|
+
|
|
34
|
+
# Rust
|
|
35
|
+
*.rs text eol=lf
|
|
36
|
+
Cargo.lock text -diff linguist-generated
|
|
37
|
+
{% endif %}
|
|
38
|
+
{% if project.type.value in ('cli-go',) %}
|
|
39
|
+
|
|
40
|
+
# Go
|
|
41
|
+
*.go text eol=lf
|
|
42
|
+
go.sum text -diff linguist-generated
|
|
43
|
+
{% endif %}
|
|
44
|
+
{% if project.type.value in ('cli-c', 'library-c', 'embedded-hardware') %}
|
|
45
|
+
|
|
46
|
+
# C / C++
|
|
47
|
+
*.c text eol=lf
|
|
48
|
+
*.h text eol=lf
|
|
49
|
+
*.cpp text eol=lf
|
|
50
|
+
*.hpp text eol=lf
|
|
51
|
+
*.o binary
|
|
52
|
+
*.a binary
|
|
53
|
+
*.so binary
|
|
54
|
+
*.dll binary
|
|
55
|
+
{% endif %}
|
|
56
|
+
{% if project.type.value in ('web-frontend', 'fullstack-js', 'browser-extension', 'monorepo') %}
|
|
57
|
+
|
|
58
|
+
# JavaScript / TypeScript
|
|
59
|
+
*.js text eol=lf
|
|
60
|
+
*.ts text eol=lf
|
|
61
|
+
*.jsx text eol=lf
|
|
62
|
+
*.tsx text eol=lf
|
|
63
|
+
*.css text eol=lf
|
|
64
|
+
*.scss text eol=lf
|
|
65
|
+
*.html text eol=lf
|
|
66
|
+
package-lock.json text -diff linguist-generated
|
|
67
|
+
yarn.lock text -diff linguist-generated
|
|
68
|
+
pnpm-lock.yaml text -diff linguist-generated
|
|
69
|
+
{% endif %}
|
|
70
|
+
{% if project.type.value == 'dotnet-app' %}
|
|
71
|
+
|
|
72
|
+
# .NET
|
|
73
|
+
*.cs text eol=lf
|
|
74
|
+
*.csproj text eol=lf
|
|
75
|
+
*.sln text eol=crlf
|
|
76
|
+
*.dll binary
|
|
77
|
+
*.exe binary
|
|
78
|
+
{% endif %}
|
|
79
|
+
{% if project.type.value == 'fpga-rtl' %}
|
|
80
|
+
|
|
81
|
+
# FPGA / RTL
|
|
82
|
+
*.vhd text eol=lf
|
|
83
|
+
*.vhdl text eol=lf
|
|
84
|
+
*.v text eol=lf
|
|
85
|
+
*.sv text eol=lf
|
|
86
|
+
*.xdc text eol=lf
|
|
87
|
+
*.sdc text eol=lf
|
|
88
|
+
*.tcl text eol=lf
|
|
89
|
+
*.bit binary
|
|
90
|
+
*.bin binary
|
|
91
|
+
*.xsa binary
|
|
92
|
+
*.ltx binary
|
|
93
|
+
*.mmi binary
|
|
94
|
+
{% endif %}
|
|
95
|
+
{% if project.type.value in ('yocto-bsp',) %}
|
|
96
|
+
|
|
97
|
+
# Yocto / BitBake
|
|
98
|
+
*.bb text eol=lf
|
|
99
|
+
*.bbappend text eol=lf
|
|
100
|
+
*.bbclass text eol=lf
|
|
101
|
+
*.conf text eol=lf
|
|
102
|
+
*.dts text eol=lf
|
|
103
|
+
*.dtsi text eol=lf
|
|
104
|
+
{% endif %}
|
|
105
|
+
{% if project.type.value == 'pcb-hardware' %}
|
|
106
|
+
|
|
107
|
+
# KiCad / PCB
|
|
108
|
+
*.kicad_pcb binary diff
|
|
109
|
+
*.kicad_sch binary diff
|
|
110
|
+
*.kicad_pro text eol=lf
|
|
111
|
+
*.step binary
|
|
112
|
+
*.wrl binary
|
|
113
|
+
{% endif %}
|
|
114
|
+
{% if project.type.value == 'research-paper' %}
|
|
115
|
+
|
|
116
|
+
# LaTeX
|
|
117
|
+
*.tex text eol=lf
|
|
118
|
+
*.bib text eol=lf
|
|
119
|
+
*.cls text eol=lf
|
|
120
|
+
*.sty text eol=lf
|
|
121
|
+
*.pdf binary
|
|
122
|
+
*.eps binary
|
|
123
|
+
{% endif %}
|
|
124
|
+
{% if project.type.value == 'api-specification' %}
|
|
125
|
+
|
|
126
|
+
# API / Protobuf
|
|
127
|
+
*.proto text eol=lf
|
|
128
|
+
*.graphql text eol=lf
|
|
129
|
+
{% endif %}
|
|
130
|
+
{% if project.type.value == 'mobile-app' %}
|
|
131
|
+
|
|
132
|
+
# Mobile
|
|
133
|
+
*.swift text eol=lf
|
|
134
|
+
*.kt text eol=lf
|
|
135
|
+
*.dart text eol=lf
|
|
136
|
+
*.apk binary
|
|
137
|
+
*.aab binary
|
|
138
|
+
*.ipa binary
|
|
139
|
+
{% endif %}
|
|
140
|
+
{% if project.type.value == 'devops-iac' %}
|
|
141
|
+
|
|
142
|
+
# Terraform / IaC
|
|
143
|
+
*.tf text eol=lf
|
|
144
|
+
*.tfvars text eol=lf
|
|
145
|
+
*.hcl text eol=lf
|
|
146
|
+
{% endif %}
|
|
@@ -86,16 +86,32 @@ fp-info-cache
|
|
|
86
86
|
# FPGA
|
|
87
87
|
*.jou
|
|
88
88
|
*.str
|
|
89
|
+
*.bit
|
|
90
|
+
*.bin
|
|
91
|
+
*.xsa
|
|
92
|
+
*.ltx
|
|
93
|
+
*.mmi
|
|
89
94
|
work/
|
|
90
95
|
xsim.dir/
|
|
96
|
+
.Xil/
|
|
97
|
+
dfx_runtime.txt
|
|
98
|
+
*.backup.log
|
|
99
|
+
*.backup.jou
|
|
91
100
|
{% endif %}
|
|
92
101
|
{% if project.type.value in ('yocto-bsp', 'embedded-hardware') %}
|
|
93
102
|
|
|
94
|
-
# Embedded
|
|
103
|
+
# Yocto / Embedded
|
|
95
104
|
twister-out/
|
|
96
105
|
sstate-cache/
|
|
97
106
|
downloads/
|
|
98
107
|
tmp/
|
|
108
|
+
*.wic
|
|
109
|
+
*.wic.xz
|
|
110
|
+
*.wic.bmap
|
|
111
|
+
*.ext4
|
|
112
|
+
*.manifest
|
|
113
|
+
*.tar.gz
|
|
114
|
+
cache/
|
|
99
115
|
{% endif %}
|
|
100
116
|
{% if project.type.value == 'research-paper' %}
|
|
101
117
|
|
|
@@ -117,3 +133,57 @@ tmp/
|
|
|
117
133
|
*.tfstate.backup
|
|
118
134
|
*.tfvars
|
|
119
135
|
{% endif %}
|
|
136
|
+
{% if project.type.value == 'data-ml' %}
|
|
137
|
+
|
|
138
|
+
# Data / ML
|
|
139
|
+
.ipynb_checkpoints/
|
|
140
|
+
mlruns/
|
|
141
|
+
wandb/
|
|
142
|
+
data/raw/
|
|
143
|
+
models/*.pkl
|
|
144
|
+
models/*.h5
|
|
145
|
+
models/*.pt
|
|
146
|
+
*.onnx
|
|
147
|
+
{% endif %}
|
|
148
|
+
{% if project.type.value == 'microservices' %}
|
|
149
|
+
|
|
150
|
+
# Microservices
|
|
151
|
+
.env
|
|
152
|
+
.env.*
|
|
153
|
+
!.env.example
|
|
154
|
+
docker-compose.override.yml
|
|
155
|
+
{% endif %}
|
|
156
|
+
{% if project.type.value in ('monorepo',) %}
|
|
157
|
+
|
|
158
|
+
# Monorepo
|
|
159
|
+
.turbo/
|
|
160
|
+
.nx/
|
|
161
|
+
{% endif %}
|
|
162
|
+
{% if project.type.value == 'browser-extension' %}
|
|
163
|
+
|
|
164
|
+
# Browser Extension
|
|
165
|
+
web-ext-artifacts/
|
|
166
|
+
*.crx
|
|
167
|
+
*.xpi
|
|
168
|
+
{% endif %}
|
|
169
|
+
{% if project.type.value in ('spec-document', 'user-manual') %}
|
|
170
|
+
|
|
171
|
+
# Documentation builds
|
|
172
|
+
_site/
|
|
173
|
+
site/
|
|
174
|
+
_build/
|
|
175
|
+
.cache/
|
|
176
|
+
public/
|
|
177
|
+
{% endif %}
|
|
178
|
+
{% if project.type.value in ('business-plan', 'legal-compliance', 'patent-application') %}
|
|
179
|
+
|
|
180
|
+
# Office / Documents
|
|
181
|
+
~$*
|
|
182
|
+
*.tmp
|
|
183
|
+
*.bak
|
|
184
|
+
{% endif %}
|
|
185
|
+
{% if project.type.value == 'api-specification' %}
|
|
186
|
+
|
|
187
|
+
# API / Generated
|
|
188
|
+
generated/
|
|
189
|
+
{% endif %}
|
|
@@ -66,9 +66,10 @@ _TOOL_REGISTRY: dict[ProjectType, ToolSet] = {
|
|
|
66
66
|
),
|
|
67
67
|
ProjectType.YOCTO_BSP: ToolSet(
|
|
68
68
|
lint=["oelint-adv"],
|
|
69
|
-
test=["bitbake"],
|
|
69
|
+
test=["bitbake -c testimage"],
|
|
70
70
|
build=["kas build", "bitbake"],
|
|
71
71
|
security=[],
|
|
72
|
+
compliance=["yocto-check-layer"],
|
|
72
73
|
),
|
|
73
74
|
ProjectType.PCB_HARDWARE: ToolSet(
|
|
74
75
|
lint=[],
|
|
@@ -362,10 +363,28 @@ LANG_CI_META: dict[str, dict[str, str]] = {
|
|
|
362
363
|
"docker_image": "verilator/verilator:latest",
|
|
363
364
|
"install": "",
|
|
364
365
|
},
|
|
365
|
-
"
|
|
366
|
+
"systemverilog": {
|
|
367
|
+
"gh_setup": "",
|
|
368
|
+
"docker_image": "verilator/verilator:latest",
|
|
369
|
+
"install": "",
|
|
370
|
+
},
|
|
371
|
+
"bitbake": {
|
|
372
|
+
"gh_setup": "",
|
|
373
|
+
"docker_image": "crops/poky:latest",
|
|
374
|
+
"install": "pip install oelint-adv",
|
|
375
|
+
},
|
|
376
|
+
"devicetree": {
|
|
366
377
|
"gh_setup": "",
|
|
378
|
+
"docker_image": "gcc:latest",
|
|
379
|
+
"install": "",
|
|
380
|
+
},
|
|
381
|
+
"markdown": {
|
|
382
|
+
"gh_setup": (
|
|
383
|
+
" - uses: actions/setup-python@v6\n"
|
|
384
|
+
' with:\n python-version: "3.12"\n'
|
|
385
|
+
),
|
|
367
386
|
"docker_image": "pandoc/core:latest",
|
|
368
|
-
"install": "pip install vale mkdocs",
|
|
387
|
+
"install": "pip install vale mkdocs markdownlint-cli2 cspell",
|
|
369
388
|
},
|
|
370
389
|
"latex": {
|
|
371
390
|
"gh_setup": "",
|
|
@@ -39,6 +39,7 @@ src/specsmith/integrations/gemini.py
|
|
|
39
39
|
src/specsmith/integrations/warp.py
|
|
40
40
|
src/specsmith/integrations/windsurf.py
|
|
41
41
|
src/specsmith/templates/agents.md.j2
|
|
42
|
+
src/specsmith/templates/editorconfig.j2
|
|
42
43
|
src/specsmith/templates/gitattributes.j2
|
|
43
44
|
src/specsmith/templates/gitignore.j2
|
|
44
45
|
src/specsmith/templates/ledger.md.j2
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
* text=auto
|
|
2
|
-
*.py text eol=lf
|
|
3
|
-
*.pyi text eol=lf
|
|
4
|
-
*.sh text eol=lf
|
|
5
|
-
*.bash text eol=lf
|
|
6
|
-
*.ps1 text eol=crlf
|
|
7
|
-
*.psm1 text eol=crlf
|
|
8
|
-
*.toml text eol=lf
|
|
9
|
-
*.cfg text eol=lf
|
|
10
|
-
*.yml text eol=lf
|
|
11
|
-
*.yaml text eol=lf
|
|
12
|
-
*.json text eol=lf
|
|
13
|
-
*.md text eol=lf
|
|
14
|
-
.gitignore text eol=lf
|
|
15
|
-
.gitattributes text eol=lf
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/docs/architecture.md.j2
RENAMED
|
File without changes
|
{specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/docs/requirements.md.j2
RENAMED
|
File without changes
|
{specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/docs/test-spec.md.j2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/governance/roles.md.j2
RENAMED
|
File without changes
|
{specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/governance/rules.md.j2
RENAMED
|
File without changes
|
|
File without changes
|
{specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/governance/workflow.md.j2
RENAMED
|
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
|
{specsmith-0.1.4.dev26 → specsmith-0.1.4.dev30}/src/specsmith/templates/scripts/setup.cmd.j2
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|