aidlc-kit 0.3.0__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.
Files changed (53) hide show
  1. aidlc_kit/__init__.py +3 -0
  2. aidlc_kit/cli.py +281 -0
  3. aidlc_kit/scaffold.py +1302 -0
  4. aidlc_kit/templates/base/README.md +60 -0
  5. aidlc_kit/templates/base/aidlc-state.md +44 -0
  6. aidlc_kit/templates/base/archive/.gitkeep +0 -0
  7. aidlc_kit/templates/base/audit/audit-log.md +40 -0
  8. aidlc_kit/templates/base/completion/bolt-completion-criteria.md +264 -0
  9. aidlc_kit/templates/base/completion/consistency-check-prompt.md +157 -0
  10. aidlc_kit/templates/base/completion/intent-consolidation-prompt.md +63 -0
  11. aidlc_kit/templates/base/decisions/decision-log.md +106 -0
  12. aidlc_kit/templates/base/egs_definition.md +514 -0
  13. aidlc_kit/templates/base/egs_variants/egs_definition_agnostic.md +515 -0
  14. aidlc_kit/templates/base/egs_variants/egs_definition_aws.md +515 -0
  15. aidlc_kit/templates/base/egs_variants/egs_definition_azure.md +515 -0
  16. aidlc_kit/templates/base/egs_variants/egs_definition_gcp.md +515 -0
  17. aidlc_kit/templates/base/egs_variants/egs_definition_onprem.md +515 -0
  18. aidlc_kit/templates/base/extensions/README.md +46 -0
  19. aidlc_kit/templates/base/extensions/security-extensions.md +234 -0
  20. aidlc_kit/templates/base/intent-summaries/.gitkeep +0 -0
  21. aidlc_kit/templates/base/intents/intent-primary.md +34 -0
  22. aidlc_kit/templates/base/overrides/guardrails_overrides.md +7 -0
  23. aidlc_kit/templates/base/plan-templates/mob_construction_plan.md +49 -0
  24. aidlc_kit/templates/base/retrospectives/session-retrospective.md +138 -0
  25. aidlc_kit/templates/base/standards/content-validation.md +79 -0
  26. aidlc_kit/templates/base/standards/error-handling.md +123 -0
  27. aidlc_kit/templates/base/standards/question-format.md +56 -0
  28. aidlc_kit/templates/base/welcome.md +18 -0
  29. aidlc_kit/templates/brownfield/code-elevation/dynamic_model.md +77 -0
  30. aidlc_kit/templates/brownfield/code-elevation/guardrails_gap_analysis.md +102 -0
  31. aidlc_kit/templates/brownfield/code-elevation/static_model.md +119 -0
  32. aidlc_kit/templates/brownfield/code-elevation/technical_debt.md +70 -0
  33. aidlc_kit/templates/brownfield/mob-construction/bolt-b1/.gitkeep +0 -0
  34. aidlc_kit/templates/brownfield/mob-construction/bolt-b2/.gitkeep +0 -0
  35. aidlc_kit/templates/brownfield/mob-construction/bolt-b3/.gitkeep +0 -0
  36. aidlc_kit/templates/brownfield/mob-elaboration/guardrails_compliance_matrix.md +73 -0
  37. aidlc_kit/templates/brownfield/plan-templates/code_elevation_plan.md +44 -0
  38. aidlc_kit/templates/brownfield/plan-templates/mob_elaboration_plan.md +51 -0
  39. aidlc_kit/templates/brownfield/prompts/code-elevation.md +359 -0
  40. aidlc_kit/templates/brownfield/prompts/mob-construction.md +499 -0
  41. aidlc_kit/templates/brownfield/prompts/mob-elaboration.md +406 -0
  42. aidlc_kit/templates/greenfield/mob-construction/bolt-1/.gitkeep +0 -0
  43. aidlc_kit/templates/greenfield/mob-construction/bolt-2/.gitkeep +0 -0
  44. aidlc_kit/templates/greenfield/mob-construction/bolt-3/.gitkeep +0 -0
  45. aidlc_kit/templates/greenfield/mob-elaboration/guardrails_compliance_matrix.md +73 -0
  46. aidlc_kit/templates/greenfield/plan-templates/mob_elaboration_plan.md +48 -0
  47. aidlc_kit/templates/greenfield/prompts/mob-construction.md +416 -0
  48. aidlc_kit/templates/greenfield/prompts/mob-elaboration.md +352 -0
  49. aidlc_kit-0.3.0.dist-info/METADATA +181 -0
  50. aidlc_kit-0.3.0.dist-info/RECORD +53 -0
  51. aidlc_kit-0.3.0.dist-info/WHEEL +4 -0
  52. aidlc_kit-0.3.0.dist-info/entry_points.txt +2 -0
  53. aidlc_kit-0.3.0.dist-info/licenses/LICENSE +97 -0
aidlc_kit/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ """aidlc-kit: Scaffold AI-DLC projects with enterprise guardrails."""
2
+
3
+ __version__ = "0.3.0"
aidlc_kit/cli.py ADDED
@@ -0,0 +1,281 @@
1
+ """CLI entry point for aidlc-kit."""
2
+
3
+ import shutil
4
+ from pathlib import Path
5
+
6
+ import click
7
+
8
+ from aidlc_kit import __version__
9
+ from aidlc_kit.scaffold import IDES, TIERS, archive_project, check_project, consistency_check, scaffold_project, status_project, update_project
10
+
11
+
12
+ @click.group()
13
+ @click.version_option(version=__version__)
14
+ def main():
15
+ """AI-DLC project scaffolding tool."""
16
+
17
+
18
+ def _parse_ides(raw: tuple[str, ...]) -> list[str] | None:
19
+ """Flatten comma-separated and repeated --ide values; validate each."""
20
+ if not raw:
21
+ return None
22
+ names: list[str] = []
23
+ for token in raw:
24
+ names.extend(t.strip().lower() for t in token.split(",") if t.strip())
25
+ if "all" in names:
26
+ return list(IDES)
27
+ invalid = [n for n in names if n not in IDES]
28
+ if invalid:
29
+ raise click.ClickException(
30
+ f"Unknown IDE(s): {', '.join(invalid)}. Choose from: {', '.join(IDES)}, or 'all'."
31
+ )
32
+ # deduplicate preserving order
33
+ seen: set[str] = set()
34
+ return [n for n in names if not (n in seen or seen.add(n))]
35
+
36
+
37
+ _IDE_HELP = (
38
+ "IDE router configs to generate. Repeat or comma-separate: "
39
+ "--ide kiro --ide cursor or --ide kiro,cursor. "
40
+ f"Use 'all' for every IDE. Supported: {', '.join(IDES)}."
41
+ )
42
+
43
+
44
+ _MODES = ["greenfield", "brownfield"]
45
+ _PLATFORMS = ["aws", "azure", "gcp", "onprem", "agnostic"]
46
+ _TIERS = ["enterprise", "standard"]
47
+
48
+
49
+ def _pick(label: str, options: list[str], descriptions: dict[str, str] | None = None) -> str:
50
+ """Numbered picker — returns chosen value."""
51
+ click.echo(f"\n{label}:")
52
+ for i, opt in enumerate(options, 1):
53
+ desc = f" — {descriptions[opt]}" if descriptions and opt in descriptions else ""
54
+ click.echo(f" {i}. {opt}{desc}")
55
+ while True:
56
+ raw = click.prompt(">", prompt_suffix=" ").strip().lower()
57
+ if raw in options:
58
+ return raw
59
+ if raw.isdigit() and 1 <= int(raw) <= len(options):
60
+ return options[int(raw) - 1]
61
+ click.echo(f" Invalid choice. Enter 1-{len(options)} or a name.")
62
+
63
+
64
+ def _pick_ides() -> list[str] | None:
65
+ """IDE picker — returns list, empty list for none, or full list for all."""
66
+ ide_list = list(IDES)
67
+ click.echo("\nIDE config (required — pick one or more, comma-separate for multiple):")
68
+ cols = 3
69
+ for i, name in enumerate(ide_list, 1):
70
+ end = "\n" if i % cols == 0 else ""
71
+ click.echo(f" {i:>2}. {name:<16}", nl=False)
72
+ if end:
73
+ click.echo()
74
+ if len(ide_list) % cols:
75
+ click.echo()
76
+ click.echo(f" a. all — every IDE")
77
+ click.echo(f" n. none — skip (add later with 'aidlc-kit update --ide')")
78
+ while True:
79
+ raw = click.prompt(">", prompt_suffix=" ").strip().lower()
80
+ if raw == "n" or raw == "none":
81
+ click.echo(" ℹ No IDE config generated. Run 'aidlc-kit update --ide <name>' to add later.")
82
+ return None
83
+ if raw == "a" or raw == "all":
84
+ return list(IDES)
85
+ tokens = [t.strip() for t in raw.replace(",", " ").split() if t.strip()]
86
+ resolved: list[str] = []
87
+ bad = False
88
+ for t in tokens:
89
+ if t in ide_list:
90
+ resolved.append(t)
91
+ elif t.isdigit() and 1 <= int(t) <= len(ide_list):
92
+ resolved.append(ide_list[int(t) - 1])
93
+ else:
94
+ click.echo(f" Unknown: '{t}'. Enter numbers, names, 'a', or 'n'.")
95
+ bad = True
96
+ break
97
+ if bad:
98
+ continue
99
+ if not resolved:
100
+ click.echo(" Pick at least one, 'a' for all, or 'n' for none.")
101
+ continue
102
+ seen: set[str] = set()
103
+ return [r for r in resolved if not (r in seen or seen.add(r))]
104
+
105
+
106
+ @main.command()
107
+ @click.argument("target", default=".")
108
+ @click.option("--mode", default=None,
109
+ help="Project mode: greenfield (new) or brownfield (existing codebase).")
110
+ @click.option("--platform", default=None,
111
+ help="Deployment platform: aws, azure, gcp, onprem, agnostic.")
112
+ @click.option("--name", default=None, help="Project name. Defaults to target directory name.")
113
+ @click.option("--force", is_flag=True, help="Overwrite existing aidlc-docs/ if present.")
114
+ @click.option("--ide", multiple=True, default=None,
115
+ help=_IDE_HELP)
116
+ @click.option("--tier", default=None,
117
+ help="Prompt tier: enterprise (with EGS guardrails) or standard (no guardrails). Default: standard.")
118
+ def init(target: str, mode: str | None, platform: str | None, name: str | None, force: bool, ide: tuple[str, ...], tier: str | None):
119
+ """Scaffold an AI-DLC project at TARGET directory.
120
+
121
+ TARGET defaults to the current directory (.).
122
+ """
123
+ # Validate if passed on CLI
124
+ if mode and mode.lower() not in _MODES:
125
+ raise click.ClickException(f"Invalid mode '{mode}'. Choose from: {', '.join(_MODES)}")
126
+ if platform and platform.lower() not in _PLATFORMS:
127
+ raise click.ClickException(f"Invalid platform '{platform}'. Choose from: {', '.join(_PLATFORMS)}")
128
+ if tier and tier.lower() not in _TIERS:
129
+ raise click.ClickException(f"Invalid tier '{tier}'. Choose from: {', '.join(_TIERS)}")
130
+ if mode:
131
+ mode = mode.lower()
132
+ if platform:
133
+ platform = platform.lower()
134
+ if tier:
135
+ tier = tier.lower()
136
+
137
+ wizard = mode is None or platform is None
138
+ if wizard:
139
+ click.echo("🔧 aidlc-kit init — project setup")
140
+ if mode is None:
141
+ mode = _pick("Mode (required)", _MODES, {
142
+ "greenfield": "new project, no existing code",
143
+ "brownfield": "existing codebase to improve",
144
+ })
145
+ if platform is None:
146
+ platform = _pick("Platform (required)", _PLATFORMS)
147
+ if tier is None and wizard:
148
+ pass # tier stays None, resolved to "standard" below
149
+ tier = tier or "standard"
150
+ ides = _parse_ides(ide)
151
+ if ides is None and wizard:
152
+ ides = _pick_ides()
153
+ scaffold_project(target, mode, name, force, platform, ides, tier)
154
+
155
+
156
+ @main.command()
157
+ @click.argument("target", default=".")
158
+ @click.option("--yes", "-y", is_flag=True, help="Skip confirmation prompt.")
159
+ @click.option(
160
+ "--platform",
161
+ type=click.Choice(["aws", "azure", "gcp", "onprem", "agnostic"], case_sensitive=False),
162
+ default=None,
163
+ help="Deployment platform. Auto-detected from README; required if README lacks Platform row.",
164
+ )
165
+ @click.option("--ide", multiple=True, default=None,
166
+ help=f"Regenerate {_IDE_HELP}")
167
+ @click.option("--tier", default=None,
168
+ help="Override tier: enterprise or standard. Auto-detected from README.")
169
+ def update(target: str, yes: bool, platform: str | None, ide: tuple[str, ...], tier: str | None):
170
+ """Update kit-owned templates in an existing AI-DLC project.
171
+
172
+ Overwrites prompts, blank templates, and completion criteria.
173
+ Preserves user content: intents, archive, and README.
174
+ """
175
+ ides = _parse_ides(ide)
176
+ update_project(target, yes, platform, ides, tier)
177
+
178
+
179
+ @main.command()
180
+ @click.argument("target", default=".")
181
+ @click.option("--name", default=None, help="Archive folder name. Defaults to intent name.")
182
+ @click.option("--yes", "-y", is_flag=True, help="Skip confirmation prompt.")
183
+ def archive(target: str, name: str | None, yes: bool):
184
+ """Archive completed intent and reset workspace for the next one.
185
+
186
+ Moves intents, elaboration, construction, decisions, and retrospectives
187
+ into archive/<name>-<date>/. Restores blank templates.
188
+ """
189
+ archive_project(target, name, yes)
190
+
191
+
192
+ @main.command()
193
+ @click.argument("target", default=".")
194
+ @click.option("--json", "output_json", is_flag=True, help="Output as JSON.")
195
+ def check(target: str, output_json: bool):
196
+ """Check health of an existing AI-DLC project.
197
+
198
+ Validates required files, customization status, plan progress,
199
+ and template drift.
200
+ """
201
+ check_project(target, as_json=output_json)
202
+
203
+
204
+ @main.command()
205
+ @click.argument("target", default=".")
206
+ @click.option("--json", "output_json", is_flag=True, help="Output as JSON.")
207
+ def status(target: str, output_json: bool):
208
+ """Show current project status dashboard."""
209
+ status_project(target, as_json=output_json)
210
+
211
+
212
+ @main.command()
213
+ @click.argument("target", default=".")
214
+ @click.option("--json", "output_json", is_flag=True, help="Output as JSON.")
215
+ def consistency(target: str, output_json: bool):
216
+ """Run structural consistency checks across project artifacts.
217
+
218
+ Checks stories↔bolts, dependencies, decision log, EGS structure,
219
+ retro action items, unit mapping, bolt plan completeness, and audit log.
220
+ """
221
+ consistency_check(target, as_json=output_json)
222
+
223
+
224
+ @main.command(name="export-egs")
225
+ @click.argument("target", default=".")
226
+ @click.argument("output", default="egs_definition.md")
227
+ def export_egs(target: str, output: str):
228
+ """Export the project's EGS definition to a file.
229
+
230
+ \b
231
+ Usage examples:
232
+ aidlc-kit export-egs myproject /tmp/shared-egs.md
233
+ aidlc-kit export-egs myproject # saves to ./egs_definition.md
234
+ """
235
+ src = Path(target).resolve() / "aidlc-docs" / "egs_definition.md"
236
+ if not src.exists():
237
+ raise click.ClickException(
238
+ f"No EGS found at {src}.\n\n"
239
+ "Usage: aidlc-kit export-egs <project-dir> [output-file]\n"
240
+ " Example: aidlc-kit export-egs myproject /tmp/shared-egs.md"
241
+ )
242
+ dst = Path(output).resolve()
243
+ shutil.copy2(src, dst)
244
+ click.echo(f"✓ EGS exported to {dst}")
245
+ click.echo(f"\nTo import into another project:")
246
+ click.echo(f" aidlc-kit import-egs {dst} /path/to/project")
247
+
248
+
249
+ @main.command(name="import-egs")
250
+ @click.argument("source", required=False, default=None)
251
+ @click.argument("target", default=".")
252
+ @click.option("--yes", "-y", is_flag=True, help="Skip confirmation prompt.")
253
+ def import_egs(source: str | None, target: str, yes: bool):
254
+ """Import an external EGS definition into the project.
255
+
256
+ \b
257
+ Usage examples:
258
+ aidlc-kit import-egs /tmp/shared-egs.md myproject
259
+ aidlc-kit import-egs /tmp/shared-egs.md # imports into current dir
260
+ """
261
+ if source is None:
262
+ raise click.ClickException(
263
+ "Missing SOURCE file.\n\n"
264
+ "Usage: aidlc-kit import-egs <egs-file> [project-dir]\n"
265
+ " Example: aidlc-kit import-egs /tmp/shared-egs.md myproject"
266
+ )
267
+ src = Path(source).resolve()
268
+ if not src.exists():
269
+ raise click.ClickException(f"Source file not found: {src}")
270
+ dst = Path(target).resolve() / "aidlc-docs" / "egs_definition.md"
271
+ if not dst.parent.is_dir():
272
+ raise click.ClickException(f"No aidlc-docs/ found at {dst.parent}. Run 'init' first.")
273
+ if dst.exists() and not yes:
274
+ text = dst.read_text(encoding="utf-8")
275
+ if "Generic Template" not in text:
276
+ click.confirm("EGS is already customized. Overwrite?", abort=True)
277
+ shutil.copy2(src, dst)
278
+ click.echo(f"✓ EGS imported from {src}")
279
+ click.echo(f"\nNext steps:")
280
+ click.echo(f" 1. Review {dst} and adjust org name, thresholds, and policies for this project")
281
+ click.echo(f" 2. Run 'aidlc-kit check {target}' to validate EGS structure")