rai-cli 2.0.0a1__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.
- rai_cli/__init__.py +38 -0
- rai_cli/__main__.py +30 -0
- rai_cli/cli/__init__.py +3 -0
- rai_cli/cli/commands/__init__.py +3 -0
- rai_cli/cli/commands/base.py +101 -0
- rai_cli/cli/commands/discover.py +547 -0
- rai_cli/cli/commands/init.py +460 -0
- rai_cli/cli/commands/memory.py +1626 -0
- rai_cli/cli/commands/profile.py +51 -0
- rai_cli/cli/commands/session.py +264 -0
- rai_cli/cli/commands/skill.py +226 -0
- rai_cli/cli/error_handler.py +158 -0
- rai_cli/cli/main.py +137 -0
- rai_cli/config/__init__.py +11 -0
- rai_cli/config/paths.py +309 -0
- rai_cli/config/settings.py +180 -0
- rai_cli/context/__init__.py +42 -0
- rai_cli/context/analyzers/__init__.py +16 -0
- rai_cli/context/analyzers/models.py +36 -0
- rai_cli/context/analyzers/protocol.py +43 -0
- rai_cli/context/analyzers/python.py +291 -0
- rai_cli/context/builder.py +1566 -0
- rai_cli/context/diff.py +213 -0
- rai_cli/context/extractors/__init__.py +13 -0
- rai_cli/context/extractors/skills.py +121 -0
- rai_cli/context/graph.py +300 -0
- rai_cli/context/models.py +134 -0
- rai_cli/context/query.py +507 -0
- rai_cli/core/__init__.py +37 -0
- rai_cli/core/files.py +66 -0
- rai_cli/core/text.py +174 -0
- rai_cli/core/tools.py +441 -0
- rai_cli/discovery/__init__.py +50 -0
- rai_cli/discovery/analyzer.py +601 -0
- rai_cli/discovery/drift.py +355 -0
- rai_cli/discovery/scanner.py +1200 -0
- rai_cli/engines/__init__.py +3 -0
- rai_cli/exceptions.py +200 -0
- rai_cli/governance/__init__.py +11 -0
- rai_cli/governance/extractor.py +311 -0
- rai_cli/governance/models.py +132 -0
- rai_cli/governance/parsers/__init__.py +35 -0
- rai_cli/governance/parsers/adr.py +255 -0
- rai_cli/governance/parsers/backlog.py +302 -0
- rai_cli/governance/parsers/constitution.py +100 -0
- rai_cli/governance/parsers/epic.py +299 -0
- rai_cli/governance/parsers/glossary.py +297 -0
- rai_cli/governance/parsers/guardrails.py +326 -0
- rai_cli/governance/parsers/prd.py +93 -0
- rai_cli/governance/parsers/vision.py +97 -0
- rai_cli/handlers/__init__.py +3 -0
- rai_cli/memory/__init__.py +58 -0
- rai_cli/memory/loader.py +247 -0
- rai_cli/memory/migration.py +247 -0
- rai_cli/memory/models.py +169 -0
- rai_cli/memory/writer.py +485 -0
- rai_cli/onboarding/__init__.py +96 -0
- rai_cli/onboarding/bootstrap.py +164 -0
- rai_cli/onboarding/claudemd.py +209 -0
- rai_cli/onboarding/conventions.py +742 -0
- rai_cli/onboarding/detection.py +155 -0
- rai_cli/onboarding/governance.py +443 -0
- rai_cli/onboarding/manifest.py +101 -0
- rai_cli/onboarding/memory_md.py +387 -0
- rai_cli/onboarding/migration.py +207 -0
- rai_cli/onboarding/profile.py +457 -0
- rai_cli/onboarding/skills.py +114 -0
- rai_cli/output/__init__.py +28 -0
- rai_cli/output/console.py +394 -0
- rai_cli/output/formatters/__init__.py +9 -0
- rai_cli/output/formatters/discover.py +442 -0
- rai_cli/output/formatters/skill.py +293 -0
- rai_cli/rai_base/__init__.py +22 -0
- rai_cli/rai_base/framework/__init__.py +7 -0
- rai_cli/rai_base/framework/methodology.yaml +235 -0
- rai_cli/rai_base/governance/__init__.py +1 -0
- rai_cli/rai_base/governance/architecture/__init__.py +1 -0
- rai_cli/rai_base/governance/architecture/domain-model.md +20 -0
- rai_cli/rai_base/governance/architecture/system-context.md +34 -0
- rai_cli/rai_base/governance/architecture/system-design.md +24 -0
- rai_cli/rai_base/governance/backlog.md +8 -0
- rai_cli/rai_base/governance/guardrails.md +18 -0
- rai_cli/rai_base/governance/prd.md +25 -0
- rai_cli/rai_base/governance/vision.md +16 -0
- rai_cli/rai_base/identity/__init__.py +8 -0
- rai_cli/rai_base/identity/core.md +119 -0
- rai_cli/rai_base/identity/perspective.md +119 -0
- rai_cli/rai_base/memory/__init__.py +7 -0
- rai_cli/rai_base/memory/patterns-base.jsonl +20 -0
- rai_cli/schemas/__init__.py +3 -0
- rai_cli/schemas/session_state.py +106 -0
- rai_cli/session/__init__.py +5 -0
- rai_cli/session/bundle.py +389 -0
- rai_cli/session/close.py +255 -0
- rai_cli/session/state.py +108 -0
- rai_cli/skills/__init__.py +44 -0
- rai_cli/skills/locator.py +129 -0
- rai_cli/skills/name_checker.py +203 -0
- rai_cli/skills/parser.py +145 -0
- rai_cli/skills/scaffold.py +185 -0
- rai_cli/skills/schema.py +130 -0
- rai_cli/skills/validator.py +172 -0
- rai_cli/skills_base/__init__.py +59 -0
- rai_cli/skills_base/rai-debug/SKILL.md +296 -0
- rai_cli/skills_base/rai-discover-document/SKILL.md +292 -0
- rai_cli/skills_base/rai-discover-scan/SKILL.md +325 -0
- rai_cli/skills_base/rai-discover-start/SKILL.md +213 -0
- rai_cli/skills_base/rai-discover-validate/SKILL.md +310 -0
- rai_cli/skills_base/rai-epic-close/SKILL.md +369 -0
- rai_cli/skills_base/rai-epic-design/SKILL.md +622 -0
- rai_cli/skills_base/rai-epic-plan/SKILL.md +672 -0
- rai_cli/skills_base/rai-epic-plan/_references/sequencing-strategies.md +67 -0
- rai_cli/skills_base/rai-epic-start/SKILL.md +217 -0
- rai_cli/skills_base/rai-project-create/SKILL.md +455 -0
- rai_cli/skills_base/rai-project-onboard/SKILL.md +503 -0
- rai_cli/skills_base/rai-research/SKILL.md +264 -0
- rai_cli/skills_base/rai-research/references/research-prompt-template.md +317 -0
- rai_cli/skills_base/rai-session-close/SKILL.md +151 -0
- rai_cli/skills_base/rai-session-start/SKILL.md +110 -0
- rai_cli/skills_base/rai-story-close/SKILL.md +367 -0
- rai_cli/skills_base/rai-story-design/SKILL.md +339 -0
- rai_cli/skills_base/rai-story-design/references/tech-design-story-v2.md +293 -0
- rai_cli/skills_base/rai-story-implement/SKILL.md +256 -0
- rai_cli/skills_base/rai-story-plan/SKILL.md +307 -0
- rai_cli/skills_base/rai-story-review/SKILL.md +276 -0
- rai_cli/skills_base/rai-story-start/SKILL.md +288 -0
- rai_cli/telemetry/__init__.py +42 -0
- rai_cli/telemetry/schemas.py +285 -0
- rai_cli/telemetry/writer.py +210 -0
- rai_cli/viz/__init__.py +7 -0
- rai_cli/viz/generator.py +404 -0
- rai_cli-2.0.0a1.dist-info/METADATA +289 -0
- rai_cli-2.0.0a1.dist-info/RECORD +137 -0
- rai_cli-2.0.0a1.dist-info/WHEEL +4 -0
- rai_cli-2.0.0a1.dist-info/entry_points.txt +2 -0
- rai_cli-2.0.0a1.dist-info/licenses/LICENSE +190 -0
- rai_cli-2.0.0a1.dist-info/licenses/NOTICE +4 -0
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
"""Init CLI command for RaiSE project initialization.
|
|
2
|
+
|
|
3
|
+
This module provides the `raise init` command that:
|
|
4
|
+
- Detects if the project is greenfield or brownfield
|
|
5
|
+
- Creates .raise/manifest.yaml with project metadata
|
|
6
|
+
- Loads or creates ~/.rai/developer.yaml for personal profile
|
|
7
|
+
- Outputs adaptive messages based on experience level
|
|
8
|
+
- Optionally detects conventions and generates guardrails (--detect)
|
|
9
|
+
|
|
10
|
+
Example:
|
|
11
|
+
$ raise init
|
|
12
|
+
$ raise init --name my-custom-name
|
|
13
|
+
$ raise init --detect # Detect conventions and generate guardrails
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from datetime import date
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import TYPE_CHECKING, Annotated
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from rai_cli.onboarding.bootstrap import BootstrapResult
|
|
24
|
+
from rai_cli.onboarding.governance import GovernanceScaffoldResult
|
|
25
|
+
from rai_cli.onboarding.skills import SkillScaffoldResult
|
|
26
|
+
|
|
27
|
+
import typer
|
|
28
|
+
from rich.console import Console
|
|
29
|
+
from rich.panel import Panel
|
|
30
|
+
|
|
31
|
+
from rai_cli.onboarding.claudemd import generate_claude_md
|
|
32
|
+
from rai_cli.onboarding.conventions import detect_conventions
|
|
33
|
+
from rai_cli.onboarding.detection import ProjectType, detect_project_type
|
|
34
|
+
from rai_cli.onboarding.governance import generate_guardrails
|
|
35
|
+
from rai_cli.onboarding.manifest import ProjectInfo, ProjectManifest, save_manifest
|
|
36
|
+
from rai_cli.onboarding.profile import (
|
|
37
|
+
DeveloperProfile,
|
|
38
|
+
ExperienceLevel,
|
|
39
|
+
load_developer_profile,
|
|
40
|
+
save_developer_profile,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
console = Console()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# Message templates for different experience levels
|
|
47
|
+
WELCOME_SHU = """[bold cyan]Welcome to RaiSE![/bold cyan]
|
|
48
|
+
|
|
49
|
+
I'm [bold]Rai[/bold] — your AI partner for reliable software engineering.
|
|
50
|
+
|
|
51
|
+
Together, we'll build software that's both fast AND reliable.
|
|
52
|
+
The RaiSE methodology guides our collaboration:
|
|
53
|
+
• [dim]You[/dim] bring intuition and judgment
|
|
54
|
+
• [dim]I[/dim] bring execution and memory
|
|
55
|
+
• [dim]Together[/dim]: reliable software at AI speed
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
WELCOME_BACK_RI = "[dim]Welcome back, {name}.[/dim]"
|
|
59
|
+
|
|
60
|
+
PROJECT_DETECTED_SHU = """
|
|
61
|
+
[bold]Project detected:[/bold] {project_type} ({file_count} code files)
|
|
62
|
+
{files_section}
|
|
63
|
+
|
|
64
|
+
[bold cyan]What's next?[/bold cyan]
|
|
65
|
+
|
|
66
|
+
[bold]1. Fill governance[/bold] (in Claude Code / AI editor):
|
|
67
|
+
Type [bold cyan]{skill_recommendation}[/bold cyan]
|
|
68
|
+
[dim]→ {skill_description}[/dim]
|
|
69
|
+
|
|
70
|
+
[bold]2. Start a session[/bold] (after governance is set up):
|
|
71
|
+
Type [bold cyan]/rai-session-start[/bold cyan]
|
|
72
|
+
[dim]→ Loads your context, remembers patterns, proposes focused work[/dim]
|
|
73
|
+
|
|
74
|
+
[bold]3. Explore the CLI[/bold] (in terminal):
|
|
75
|
+
[dim]raise --help[/dim] — see all commands
|
|
76
|
+
[dim]raise context[/dim] — query project context
|
|
77
|
+
[dim]raise memory[/dim] — query Rai's memory
|
|
78
|
+
|
|
79
|
+
[dim]Don't have Claude Code? https://claude.ai/download[/dim]
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
PROJECT_DETECTED_RI = """{project_type} project ({file_count} files). Created .raise/manifest.yaml
|
|
83
|
+
|
|
84
|
+
[dim]Next:[/dim] {skill_recommendation} [dim]Then:[/dim] /rai-session-start [dim]CLI:[/dim] raise --help [dim](claude.ai/download)[/dim]
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _get_welcome_message(profile: DeveloperProfile | None) -> str:
|
|
89
|
+
"""Get welcome message based on profile existence and level."""
|
|
90
|
+
if profile is None:
|
|
91
|
+
return WELCOME_SHU
|
|
92
|
+
|
|
93
|
+
if profile.experience_level == ExperienceLevel.RI:
|
|
94
|
+
return WELCOME_BACK_RI.format(name=profile.name)
|
|
95
|
+
elif profile.experience_level == ExperienceLevel.HA:
|
|
96
|
+
return f"[cyan]Welcome back, {profile.name}.[/cyan]\n"
|
|
97
|
+
else:
|
|
98
|
+
return WELCOME_SHU
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _get_skill_recommendation(project_type: str) -> tuple[str, str]:
|
|
102
|
+
"""Get recommended skill based on project type.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
project_type: Detected project type (greenfield/brownfield).
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
Tuple of (skill_command, description).
|
|
109
|
+
"""
|
|
110
|
+
if project_type == "brownfield":
|
|
111
|
+
return (
|
|
112
|
+
"/rai-project-onboard",
|
|
113
|
+
"Analyze codebase and fill governance from conversation",
|
|
114
|
+
)
|
|
115
|
+
return (
|
|
116
|
+
"/rai-project-create",
|
|
117
|
+
"Fill governance from conversation (new project)",
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _get_project_message(
|
|
122
|
+
project_type: str,
|
|
123
|
+
file_count: int,
|
|
124
|
+
profile: DeveloperProfile | None,
|
|
125
|
+
created_profile: bool,
|
|
126
|
+
bootstrap_result: BootstrapResult | None = None,
|
|
127
|
+
skills_result: SkillScaffoldResult | None = None,
|
|
128
|
+
governance_result: GovernanceScaffoldResult | None = None,
|
|
129
|
+
) -> str:
|
|
130
|
+
"""Get project detection message based on experience level.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
project_type: Detected project type (greenfield/brownfield).
|
|
134
|
+
file_count: Number of code files detected.
|
|
135
|
+
profile: Developer profile (None for new users).
|
|
136
|
+
created_profile: Whether profile was just created.
|
|
137
|
+
bootstrap_result: Result of base Rai bootstrap (None if not run).
|
|
138
|
+
skills_result: Result of skill scaffolding (None if not run).
|
|
139
|
+
governance_result: Result of governance scaffolding (None if not run).
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Formatted message string for console output.
|
|
143
|
+
"""
|
|
144
|
+
skill_cmd, skill_desc = _get_skill_recommendation(project_type)
|
|
145
|
+
|
|
146
|
+
if profile is None or profile.experience_level == ExperienceLevel.SHU:
|
|
147
|
+
# Build files section with descriptions
|
|
148
|
+
lines = [
|
|
149
|
+
"[bold]Created:[/bold] .raise/manifest.yaml [dim]— project metadata[/dim]"
|
|
150
|
+
]
|
|
151
|
+
if created_profile:
|
|
152
|
+
lines.append(
|
|
153
|
+
"[bold]Created:[/bold] ~/.rai/developer.yaml "
|
|
154
|
+
"[dim]— your preferences (first time)[/dim]"
|
|
155
|
+
)
|
|
156
|
+
else:
|
|
157
|
+
lines.append(
|
|
158
|
+
"[bold]Loaded:[/bold] ~/.rai/developer.yaml [dim]— your preferences[/dim]"
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# Bootstrap info
|
|
162
|
+
if bootstrap_result is not None:
|
|
163
|
+
if bootstrap_result.already_existed:
|
|
164
|
+
lines.append(
|
|
165
|
+
"[bold]Loaded:[/bold] .raise/rai/ "
|
|
166
|
+
"[dim]— Rai base already present[/dim]"
|
|
167
|
+
)
|
|
168
|
+
else:
|
|
169
|
+
if bootstrap_result.identity_copied:
|
|
170
|
+
lines.append(
|
|
171
|
+
"[bold]Created:[/bold] .raise/rai/identity/ "
|
|
172
|
+
"[dim]— Rai's base identity[/dim]"
|
|
173
|
+
)
|
|
174
|
+
if bootstrap_result.patterns_copied:
|
|
175
|
+
lines.append(
|
|
176
|
+
"[bold]Created:[/bold] .raise/rai/memory/ "
|
|
177
|
+
"[dim]— 20 universal patterns[/dim]"
|
|
178
|
+
)
|
|
179
|
+
if bootstrap_result.methodology_copied:
|
|
180
|
+
lines.append(
|
|
181
|
+
"[bold]Created:[/bold] .raise/rai/framework/ "
|
|
182
|
+
"[dim]— methodology definition[/dim]"
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# Skills info
|
|
186
|
+
if skills_result is not None:
|
|
187
|
+
if skills_result.already_existed:
|
|
188
|
+
lines.append(
|
|
189
|
+
"[bold]Loaded:[/bold] .claude/skills/ "
|
|
190
|
+
"[dim]— skills already present[/dim]"
|
|
191
|
+
)
|
|
192
|
+
elif skills_result.skills_copied > 0:
|
|
193
|
+
lines.append(
|
|
194
|
+
f"[bold]Created:[/bold] .claude/skills/ "
|
|
195
|
+
f"[dim]— {skills_result.skills_copied} onboarding skills[/dim]"
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# Governance info
|
|
199
|
+
if governance_result is not None:
|
|
200
|
+
if governance_result.already_existed:
|
|
201
|
+
lines.append(
|
|
202
|
+
"[bold]Loaded:[/bold] governance/ "
|
|
203
|
+
"[dim]— governance templates already present[/dim]"
|
|
204
|
+
)
|
|
205
|
+
elif governance_result.files_created > 0:
|
|
206
|
+
lines.append(
|
|
207
|
+
f"[bold]Created:[/bold] governance/ "
|
|
208
|
+
f"[dim]— {governance_result.files_created} governance templates[/dim]"
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
files_section = "\n".join(lines)
|
|
212
|
+
|
|
213
|
+
return PROJECT_DETECTED_SHU.format(
|
|
214
|
+
project_type=project_type.capitalize(),
|
|
215
|
+
file_count=file_count,
|
|
216
|
+
files_section=files_section,
|
|
217
|
+
skill_recommendation=skill_cmd,
|
|
218
|
+
skill_description=skill_desc,
|
|
219
|
+
)
|
|
220
|
+
else:
|
|
221
|
+
bootstrap_msg = ""
|
|
222
|
+
if bootstrap_result is not None and not bootstrap_result.already_existed:
|
|
223
|
+
bootstrap_msg = (
|
|
224
|
+
f" Bootstrapped Rai base v{bootstrap_result.base_version}\n"
|
|
225
|
+
)
|
|
226
|
+
skills_msg = ""
|
|
227
|
+
if skills_result is not None and not skills_result.already_existed:
|
|
228
|
+
skills_msg = (
|
|
229
|
+
f" Installed {skills_result.skills_copied} skills"
|
|
230
|
+
f" to .claude/skills/\n"
|
|
231
|
+
)
|
|
232
|
+
governance_msg = ""
|
|
233
|
+
if governance_result is not None and not governance_result.already_existed:
|
|
234
|
+
governance_msg = (
|
|
235
|
+
f" Scaffolded governance/ ({governance_result.files_created} templates)\n"
|
|
236
|
+
)
|
|
237
|
+
return (
|
|
238
|
+
PROJECT_DETECTED_RI.format(
|
|
239
|
+
project_type=project_type.capitalize(),
|
|
240
|
+
file_count=file_count,
|
|
241
|
+
skill_recommendation=skill_cmd,
|
|
242
|
+
)
|
|
243
|
+
+ bootstrap_msg
|
|
244
|
+
+ skills_msg
|
|
245
|
+
+ governance_msg
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def _create_new_profile(project_path: Path) -> DeveloperProfile:
|
|
250
|
+
"""Create a new developer profile with defaults."""
|
|
251
|
+
today = date.today()
|
|
252
|
+
return DeveloperProfile(
|
|
253
|
+
name="Developer", # Will be personalized later
|
|
254
|
+
experience_level=ExperienceLevel.SHU,
|
|
255
|
+
first_session=today,
|
|
256
|
+
last_session=today,
|
|
257
|
+
projects=[str(project_path.resolve())],
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def _update_profile_with_project(
|
|
262
|
+
profile: DeveloperProfile, project_path: Path
|
|
263
|
+
) -> DeveloperProfile:
|
|
264
|
+
"""Update profile to include current project."""
|
|
265
|
+
project_str = str(project_path.resolve())
|
|
266
|
+
if project_str not in profile.projects:
|
|
267
|
+
profile.projects.append(project_str)
|
|
268
|
+
profile.last_session = date.today()
|
|
269
|
+
return profile
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def init_command(
|
|
273
|
+
name: Annotated[
|
|
274
|
+
str | None,
|
|
275
|
+
typer.Option(
|
|
276
|
+
"--name",
|
|
277
|
+
"-n",
|
|
278
|
+
help="Project name (defaults to directory name)",
|
|
279
|
+
),
|
|
280
|
+
] = None,
|
|
281
|
+
path: Annotated[
|
|
282
|
+
Path | None,
|
|
283
|
+
typer.Option(
|
|
284
|
+
"--path",
|
|
285
|
+
"-p",
|
|
286
|
+
help="Project path (defaults to current directory)",
|
|
287
|
+
),
|
|
288
|
+
] = None,
|
|
289
|
+
detect: Annotated[
|
|
290
|
+
bool,
|
|
291
|
+
typer.Option(
|
|
292
|
+
"--detect",
|
|
293
|
+
"-d",
|
|
294
|
+
help="Detect conventions and generate guardrails.md",
|
|
295
|
+
),
|
|
296
|
+
] = False,
|
|
297
|
+
) -> None:
|
|
298
|
+
"""Initialize a RaiSE project in the current directory.
|
|
299
|
+
|
|
300
|
+
Detects project type (greenfield/brownfield), creates .raise/manifest.yaml,
|
|
301
|
+
and sets up developer profile for personalized interaction.
|
|
302
|
+
|
|
303
|
+
With --detect, also analyzes code conventions and generates guardrails.
|
|
304
|
+
|
|
305
|
+
Examples:
|
|
306
|
+
$ raise init
|
|
307
|
+
$ raise init --name my-api
|
|
308
|
+
$ raise init --path /path/to/project
|
|
309
|
+
$ raise init --detect # Detect conventions and generate guardrails
|
|
310
|
+
"""
|
|
311
|
+
# Determine project path
|
|
312
|
+
project_path = path if path is not None else Path.cwd()
|
|
313
|
+
project_path = project_path.resolve()
|
|
314
|
+
|
|
315
|
+
# Determine project name
|
|
316
|
+
project_name = name if name is not None else project_path.name
|
|
317
|
+
|
|
318
|
+
# Load or create developer profile
|
|
319
|
+
profile = load_developer_profile()
|
|
320
|
+
created_profile = False
|
|
321
|
+
|
|
322
|
+
if profile is None:
|
|
323
|
+
profile = _create_new_profile(project_path)
|
|
324
|
+
save_developer_profile(profile)
|
|
325
|
+
created_profile = True
|
|
326
|
+
else:
|
|
327
|
+
profile = _update_profile_with_project(profile, project_path)
|
|
328
|
+
save_developer_profile(profile)
|
|
329
|
+
|
|
330
|
+
# Detect project type
|
|
331
|
+
detection = detect_project_type(project_path)
|
|
332
|
+
|
|
333
|
+
# Create and save manifest
|
|
334
|
+
project_info = ProjectInfo(
|
|
335
|
+
name=project_name,
|
|
336
|
+
project_type=detection.project_type,
|
|
337
|
+
code_file_count=detection.code_file_count,
|
|
338
|
+
)
|
|
339
|
+
manifest = ProjectManifest(project=project_info)
|
|
340
|
+
save_manifest(manifest, project_path)
|
|
341
|
+
|
|
342
|
+
# Bootstrap Rai base assets
|
|
343
|
+
from rai_cli.onboarding.bootstrap import bootstrap_rai_base
|
|
344
|
+
|
|
345
|
+
bootstrap_result = bootstrap_rai_base(project_path)
|
|
346
|
+
|
|
347
|
+
# Scaffold onboarding skills
|
|
348
|
+
from rai_cli.onboarding.skills import scaffold_skills
|
|
349
|
+
|
|
350
|
+
skills_result = scaffold_skills(project_path)
|
|
351
|
+
|
|
352
|
+
# Scaffold governance templates
|
|
353
|
+
from rai_cli.onboarding.governance import scaffold_governance
|
|
354
|
+
|
|
355
|
+
governance_result = scaffold_governance(project_path, project_name)
|
|
356
|
+
|
|
357
|
+
# Generate MEMORY.md (canonical + Claude Code)
|
|
358
|
+
from rai_cli.config.paths import (
|
|
359
|
+
get_claude_memory_path,
|
|
360
|
+
get_framework_dir,
|
|
361
|
+
get_memory_dir,
|
|
362
|
+
)
|
|
363
|
+
from rai_cli.onboarding.memory_md import generate_memory_md
|
|
364
|
+
|
|
365
|
+
methodology_path = get_framework_dir(project_path) / "methodology.yaml"
|
|
366
|
+
patterns_path = get_memory_dir(project_path) / "patterns.jsonl"
|
|
367
|
+
|
|
368
|
+
memory_content = generate_memory_md(
|
|
369
|
+
methodology_path=methodology_path,
|
|
370
|
+
patterns_path=patterns_path,
|
|
371
|
+
project_name=project_name,
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
# Write canonical copy
|
|
375
|
+
canonical_memory = get_memory_dir(project_path) / "MEMORY.md"
|
|
376
|
+
canonical_memory.parent.mkdir(parents=True, exist_ok=True)
|
|
377
|
+
canonical_memory.write_text(memory_content)
|
|
378
|
+
|
|
379
|
+
# Write Claude Code copy
|
|
380
|
+
claude_memory = get_claude_memory_path(project_path)
|
|
381
|
+
claude_memory.parent.mkdir(parents=True, exist_ok=True)
|
|
382
|
+
claude_memory.write_text(memory_content)
|
|
383
|
+
|
|
384
|
+
# Output messages based on experience level
|
|
385
|
+
welcome = _get_welcome_message(profile if not created_profile else None)
|
|
386
|
+
project_msg = _get_project_message(
|
|
387
|
+
project_type=detection.project_type.value,
|
|
388
|
+
file_count=detection.code_file_count,
|
|
389
|
+
profile=profile,
|
|
390
|
+
created_profile=created_profile,
|
|
391
|
+
bootstrap_result=bootstrap_result,
|
|
392
|
+
skills_result=skills_result,
|
|
393
|
+
governance_result=governance_result,
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
if profile.experience_level == ExperienceLevel.RI and not created_profile:
|
|
397
|
+
# Concise output for experienced users
|
|
398
|
+
console.print(welcome)
|
|
399
|
+
console.print(project_msg)
|
|
400
|
+
else:
|
|
401
|
+
# Rich output for new/learning users
|
|
402
|
+
console.print(Panel(welcome.strip(), border_style="cyan"))
|
|
403
|
+
console.print(project_msg)
|
|
404
|
+
|
|
405
|
+
# Convention detection, guardrails, and CLAUDE.md generation
|
|
406
|
+
if detect and detection.project_type == ProjectType.BROWNFIELD:
|
|
407
|
+
conventions = detect_conventions(project_path)
|
|
408
|
+
|
|
409
|
+
if conventions.files_analyzed > 0:
|
|
410
|
+
# Generate guardrails markdown
|
|
411
|
+
guardrails_content = generate_guardrails(
|
|
412
|
+
conventions, project_name=project_name
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
# Write to governance/guardrails.md
|
|
416
|
+
guardrails_dir = project_path / "governance"
|
|
417
|
+
guardrails_dir.mkdir(parents=True, exist_ok=True)
|
|
418
|
+
guardrails_path = guardrails_dir / "guardrails.md"
|
|
419
|
+
guardrails_path.write_text(guardrails_content)
|
|
420
|
+
|
|
421
|
+
# Generate CLAUDE.md
|
|
422
|
+
claude_md_content = generate_claude_md(
|
|
423
|
+
project_name=project_name,
|
|
424
|
+
detection=detection,
|
|
425
|
+
conventions=conventions,
|
|
426
|
+
)
|
|
427
|
+
claude_md_path = project_path / "CLAUDE.md"
|
|
428
|
+
claude_md_path.write_text(claude_md_content)
|
|
429
|
+
|
|
430
|
+
# Output summary
|
|
431
|
+
conf = conventions.overall_confidence.value.upper()
|
|
432
|
+
if profile.experience_level == ExperienceLevel.RI:
|
|
433
|
+
console.print(
|
|
434
|
+
f"\n[dim]Conventions detected ({conventions.files_analyzed} files, "
|
|
435
|
+
f"{conf} confidence). Generated guardrails.md and CLAUDE.md[/dim]"
|
|
436
|
+
)
|
|
437
|
+
else:
|
|
438
|
+
console.print(
|
|
439
|
+
f"\n[bold cyan]Convention Detection[/bold cyan]\n"
|
|
440
|
+
f"Analyzed {conventions.files_analyzed} files with {conf} confidence.\n"
|
|
441
|
+
f"Generated:\n"
|
|
442
|
+
f" - [bold]{guardrails_path}[/bold] (code standards)\n"
|
|
443
|
+
f" - [bold]{claude_md_path}[/bold] (project context)\n\n"
|
|
444
|
+
f"[dim]Review and adjust as needed.[/dim]"
|
|
445
|
+
)
|
|
446
|
+
elif detect and detection.project_type == ProjectType.GREENFIELD:
|
|
447
|
+
# Generate minimal CLAUDE.md for greenfield
|
|
448
|
+
claude_md_content = generate_claude_md(
|
|
449
|
+
project_name=project_name,
|
|
450
|
+
detection=detection,
|
|
451
|
+
conventions=None,
|
|
452
|
+
)
|
|
453
|
+
claude_md_path = project_path / "CLAUDE.md"
|
|
454
|
+
claude_md_path.write_text(claude_md_content)
|
|
455
|
+
|
|
456
|
+
if profile.experience_level != ExperienceLevel.RI:
|
|
457
|
+
console.print(
|
|
458
|
+
f"\n[dim]Created {claude_md_path}. No code to analyze yet — "
|
|
459
|
+
"guardrails will be generated when conventions are established.[/dim]"
|
|
460
|
+
)
|