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.
- aidlc_kit/__init__.py +3 -0
- aidlc_kit/cli.py +281 -0
- aidlc_kit/scaffold.py +1302 -0
- aidlc_kit/templates/base/README.md +60 -0
- aidlc_kit/templates/base/aidlc-state.md +44 -0
- aidlc_kit/templates/base/archive/.gitkeep +0 -0
- aidlc_kit/templates/base/audit/audit-log.md +40 -0
- aidlc_kit/templates/base/completion/bolt-completion-criteria.md +264 -0
- aidlc_kit/templates/base/completion/consistency-check-prompt.md +157 -0
- aidlc_kit/templates/base/completion/intent-consolidation-prompt.md +63 -0
- aidlc_kit/templates/base/decisions/decision-log.md +106 -0
- aidlc_kit/templates/base/egs_definition.md +514 -0
- aidlc_kit/templates/base/egs_variants/egs_definition_agnostic.md +515 -0
- aidlc_kit/templates/base/egs_variants/egs_definition_aws.md +515 -0
- aidlc_kit/templates/base/egs_variants/egs_definition_azure.md +515 -0
- aidlc_kit/templates/base/egs_variants/egs_definition_gcp.md +515 -0
- aidlc_kit/templates/base/egs_variants/egs_definition_onprem.md +515 -0
- aidlc_kit/templates/base/extensions/README.md +46 -0
- aidlc_kit/templates/base/extensions/security-extensions.md +234 -0
- aidlc_kit/templates/base/intent-summaries/.gitkeep +0 -0
- aidlc_kit/templates/base/intents/intent-primary.md +34 -0
- aidlc_kit/templates/base/overrides/guardrails_overrides.md +7 -0
- aidlc_kit/templates/base/plan-templates/mob_construction_plan.md +49 -0
- aidlc_kit/templates/base/retrospectives/session-retrospective.md +138 -0
- aidlc_kit/templates/base/standards/content-validation.md +79 -0
- aidlc_kit/templates/base/standards/error-handling.md +123 -0
- aidlc_kit/templates/base/standards/question-format.md +56 -0
- aidlc_kit/templates/base/welcome.md +18 -0
- aidlc_kit/templates/brownfield/code-elevation/dynamic_model.md +77 -0
- aidlc_kit/templates/brownfield/code-elevation/guardrails_gap_analysis.md +102 -0
- aidlc_kit/templates/brownfield/code-elevation/static_model.md +119 -0
- aidlc_kit/templates/brownfield/code-elevation/technical_debt.md +70 -0
- aidlc_kit/templates/brownfield/mob-construction/bolt-b1/.gitkeep +0 -0
- aidlc_kit/templates/brownfield/mob-construction/bolt-b2/.gitkeep +0 -0
- aidlc_kit/templates/brownfield/mob-construction/bolt-b3/.gitkeep +0 -0
- aidlc_kit/templates/brownfield/mob-elaboration/guardrails_compliance_matrix.md +73 -0
- aidlc_kit/templates/brownfield/plan-templates/code_elevation_plan.md +44 -0
- aidlc_kit/templates/brownfield/plan-templates/mob_elaboration_plan.md +51 -0
- aidlc_kit/templates/brownfield/prompts/code-elevation.md +359 -0
- aidlc_kit/templates/brownfield/prompts/mob-construction.md +499 -0
- aidlc_kit/templates/brownfield/prompts/mob-elaboration.md +406 -0
- aidlc_kit/templates/greenfield/mob-construction/bolt-1/.gitkeep +0 -0
- aidlc_kit/templates/greenfield/mob-construction/bolt-2/.gitkeep +0 -0
- aidlc_kit/templates/greenfield/mob-construction/bolt-3/.gitkeep +0 -0
- aidlc_kit/templates/greenfield/mob-elaboration/guardrails_compliance_matrix.md +73 -0
- aidlc_kit/templates/greenfield/plan-templates/mob_elaboration_plan.md +48 -0
- aidlc_kit/templates/greenfield/prompts/mob-construction.md +416 -0
- aidlc_kit/templates/greenfield/prompts/mob-elaboration.md +352 -0
- aidlc_kit-0.3.0.dist-info/METADATA +181 -0
- aidlc_kit-0.3.0.dist-info/RECORD +53 -0
- aidlc_kit-0.3.0.dist-info/WHEEL +4 -0
- aidlc_kit-0.3.0.dist-info/entry_points.txt +2 -0
- aidlc_kit-0.3.0.dist-info/licenses/LICENSE +97 -0
aidlc_kit/__init__.py
ADDED
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")
|