raise-cli 2.2.1__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.
- raise_cli/__init__.py +38 -0
- raise_cli/__main__.py +30 -0
- raise_cli/adapters/__init__.py +91 -0
- raise_cli/adapters/declarative/__init__.py +26 -0
- raise_cli/adapters/declarative/adapter.py +267 -0
- raise_cli/adapters/declarative/discovery.py +94 -0
- raise_cli/adapters/declarative/expressions.py +150 -0
- raise_cli/adapters/declarative/reference/__init__.py +1 -0
- raise_cli/adapters/declarative/reference/github.yaml +143 -0
- raise_cli/adapters/declarative/schema.py +98 -0
- raise_cli/adapters/filesystem.py +299 -0
- raise_cli/adapters/mcp_bridge.py +10 -0
- raise_cli/adapters/mcp_confluence.py +246 -0
- raise_cli/adapters/mcp_jira.py +405 -0
- raise_cli/adapters/models.py +205 -0
- raise_cli/adapters/protocols.py +180 -0
- raise_cli/adapters/registry.py +90 -0
- raise_cli/adapters/sync.py +149 -0
- raise_cli/agents/__init__.py +14 -0
- raise_cli/agents/antigravity.yaml +8 -0
- raise_cli/agents/claude.yaml +8 -0
- raise_cli/agents/copilot.yaml +8 -0
- raise_cli/agents/copilot_plugin.py +124 -0
- raise_cli/agents/cursor.yaml +7 -0
- raise_cli/agents/roo.yaml +8 -0
- raise_cli/agents/windsurf.yaml +8 -0
- raise_cli/artifacts/__init__.py +30 -0
- raise_cli/artifacts/models.py +43 -0
- raise_cli/artifacts/reader.py +55 -0
- raise_cli/artifacts/renderer.py +104 -0
- raise_cli/artifacts/story_design.py +69 -0
- raise_cli/artifacts/writer.py +45 -0
- raise_cli/backlog/__init__.py +1 -0
- raise_cli/backlog/sync.py +115 -0
- raise_cli/cli/__init__.py +3 -0
- raise_cli/cli/commands/__init__.py +3 -0
- raise_cli/cli/commands/_resolve.py +153 -0
- raise_cli/cli/commands/adapters.py +362 -0
- raise_cli/cli/commands/artifact.py +137 -0
- raise_cli/cli/commands/backlog.py +333 -0
- raise_cli/cli/commands/base.py +31 -0
- raise_cli/cli/commands/discover.py +551 -0
- raise_cli/cli/commands/docs.py +130 -0
- raise_cli/cli/commands/doctor.py +177 -0
- raise_cli/cli/commands/gate.py +223 -0
- raise_cli/cli/commands/graph.py +1086 -0
- raise_cli/cli/commands/info.py +81 -0
- raise_cli/cli/commands/init.py +746 -0
- raise_cli/cli/commands/journal.py +167 -0
- raise_cli/cli/commands/mcp.py +524 -0
- raise_cli/cli/commands/memory.py +467 -0
- raise_cli/cli/commands/pattern.py +348 -0
- raise_cli/cli/commands/profile.py +59 -0
- raise_cli/cli/commands/publish.py +80 -0
- raise_cli/cli/commands/release.py +338 -0
- raise_cli/cli/commands/session.py +528 -0
- raise_cli/cli/commands/signal.py +410 -0
- raise_cli/cli/commands/skill.py +350 -0
- raise_cli/cli/commands/skill_set.py +145 -0
- raise_cli/cli/error_handler.py +158 -0
- raise_cli/cli/main.py +163 -0
- raise_cli/compat.py +66 -0
- raise_cli/config/__init__.py +41 -0
- raise_cli/config/agent_plugin.py +105 -0
- raise_cli/config/agent_registry.py +233 -0
- raise_cli/config/agents.py +120 -0
- raise_cli/config/ide.py +32 -0
- raise_cli/config/paths.py +379 -0
- raise_cli/config/settings.py +180 -0
- raise_cli/context/__init__.py +42 -0
- raise_cli/context/analyzers/__init__.py +16 -0
- raise_cli/context/analyzers/models.py +36 -0
- raise_cli/context/analyzers/protocol.py +43 -0
- raise_cli/context/analyzers/python.py +292 -0
- raise_cli/context/builder.py +1569 -0
- raise_cli/context/diff.py +213 -0
- raise_cli/context/extractors/__init__.py +13 -0
- raise_cli/context/extractors/skills.py +121 -0
- raise_cli/core/__init__.py +37 -0
- raise_cli/core/files.py +66 -0
- raise_cli/core/text.py +174 -0
- raise_cli/core/tools.py +441 -0
- raise_cli/discovery/__init__.py +50 -0
- raise_cli/discovery/analyzer.py +691 -0
- raise_cli/discovery/drift.py +355 -0
- raise_cli/discovery/scanner.py +1687 -0
- raise_cli/doctor/__init__.py +4 -0
- raise_cli/doctor/checks/__init__.py +1 -0
- raise_cli/doctor/checks/environment.py +110 -0
- raise_cli/doctor/checks/project.py +238 -0
- raise_cli/doctor/fix.py +80 -0
- raise_cli/doctor/models.py +56 -0
- raise_cli/doctor/protocol.py +43 -0
- raise_cli/doctor/registry.py +100 -0
- raise_cli/doctor/report.py +141 -0
- raise_cli/doctor/runner.py +95 -0
- raise_cli/engines/__init__.py +3 -0
- raise_cli/exceptions.py +215 -0
- raise_cli/gates/__init__.py +19 -0
- raise_cli/gates/builtin/__init__.py +1 -0
- raise_cli/gates/builtin/coverage.py +52 -0
- raise_cli/gates/builtin/lint.py +48 -0
- raise_cli/gates/builtin/tests.py +48 -0
- raise_cli/gates/builtin/types.py +48 -0
- raise_cli/gates/models.py +40 -0
- raise_cli/gates/protocol.py +41 -0
- raise_cli/gates/registry.py +141 -0
- raise_cli/governance/__init__.py +11 -0
- raise_cli/governance/extractor.py +412 -0
- raise_cli/governance/models.py +134 -0
- raise_cli/governance/parsers/__init__.py +35 -0
- raise_cli/governance/parsers/_convert.py +38 -0
- raise_cli/governance/parsers/adr.py +274 -0
- raise_cli/governance/parsers/backlog.py +356 -0
- raise_cli/governance/parsers/constitution.py +119 -0
- raise_cli/governance/parsers/epic.py +323 -0
- raise_cli/governance/parsers/glossary.py +316 -0
- raise_cli/governance/parsers/guardrails.py +345 -0
- raise_cli/governance/parsers/prd.py +112 -0
- raise_cli/governance/parsers/roadmap.py +118 -0
- raise_cli/governance/parsers/vision.py +116 -0
- raise_cli/graph/__init__.py +1 -0
- raise_cli/graph/backends/__init__.py +57 -0
- raise_cli/graph/backends/api.py +137 -0
- raise_cli/graph/backends/dual.py +139 -0
- raise_cli/graph/backends/pending.py +84 -0
- raise_cli/handlers/__init__.py +3 -0
- raise_cli/hooks/__init__.py +54 -0
- raise_cli/hooks/builtin/__init__.py +1 -0
- raise_cli/hooks/builtin/backlog.py +216 -0
- raise_cli/hooks/builtin/gate_bridge.py +83 -0
- raise_cli/hooks/builtin/jira_sync.py +127 -0
- raise_cli/hooks/builtin/memory.py +117 -0
- raise_cli/hooks/builtin/telemetry.py +72 -0
- raise_cli/hooks/emitter.py +184 -0
- raise_cli/hooks/events.py +262 -0
- raise_cli/hooks/protocol.py +38 -0
- raise_cli/hooks/registry.py +117 -0
- raise_cli/mcp/__init__.py +33 -0
- raise_cli/mcp/bridge.py +218 -0
- raise_cli/mcp/models.py +43 -0
- raise_cli/mcp/registry.py +77 -0
- raise_cli/mcp/schema.py +41 -0
- raise_cli/memory/__init__.py +58 -0
- raise_cli/memory/loader.py +247 -0
- raise_cli/memory/migration.py +241 -0
- raise_cli/memory/models.py +169 -0
- raise_cli/memory/writer.py +598 -0
- raise_cli/onboarding/__init__.py +103 -0
- raise_cli/onboarding/bootstrap.py +324 -0
- raise_cli/onboarding/claudemd.py +17 -0
- raise_cli/onboarding/conventions.py +742 -0
- raise_cli/onboarding/detection.py +374 -0
- raise_cli/onboarding/governance.py +443 -0
- raise_cli/onboarding/instructions.py +672 -0
- raise_cli/onboarding/manifest.py +201 -0
- raise_cli/onboarding/memory_md.py +399 -0
- raise_cli/onboarding/migration.py +207 -0
- raise_cli/onboarding/profile.py +624 -0
- raise_cli/onboarding/skill_conflict.py +100 -0
- raise_cli/onboarding/skill_manifest.py +176 -0
- raise_cli/onboarding/skills.py +437 -0
- raise_cli/onboarding/workflows.py +101 -0
- raise_cli/output/__init__.py +28 -0
- raise_cli/output/console.py +394 -0
- raise_cli/output/formatters/__init__.py +9 -0
- raise_cli/output/formatters/adapters.py +135 -0
- raise_cli/output/formatters/discover.py +439 -0
- raise_cli/output/formatters/skill.py +298 -0
- raise_cli/publish/__init__.py +3 -0
- raise_cli/publish/changelog.py +80 -0
- raise_cli/publish/check.py +179 -0
- raise_cli/publish/version.py +172 -0
- raise_cli/rai_base/__init__.py +22 -0
- raise_cli/rai_base/framework/__init__.py +7 -0
- raise_cli/rai_base/framework/methodology.yaml +233 -0
- raise_cli/rai_base/governance/__init__.py +1 -0
- raise_cli/rai_base/governance/architecture/__init__.py +1 -0
- raise_cli/rai_base/governance/architecture/domain-model.md +20 -0
- raise_cli/rai_base/governance/architecture/system-context.md +34 -0
- raise_cli/rai_base/governance/architecture/system-design.md +24 -0
- raise_cli/rai_base/governance/backlog.md +8 -0
- raise_cli/rai_base/governance/guardrails.md +17 -0
- raise_cli/rai_base/governance/prd.md +25 -0
- raise_cli/rai_base/governance/vision.md +16 -0
- raise_cli/rai_base/identity/__init__.py +8 -0
- raise_cli/rai_base/identity/core.md +119 -0
- raise_cli/rai_base/identity/perspective.md +119 -0
- raise_cli/rai_base/memory/__init__.py +7 -0
- raise_cli/rai_base/memory/patterns-base.jsonl +55 -0
- raise_cli/schemas/__init__.py +3 -0
- raise_cli/schemas/journal.py +49 -0
- raise_cli/schemas/session_state.py +117 -0
- raise_cli/session/__init__.py +5 -0
- raise_cli/session/bundle.py +820 -0
- raise_cli/session/close.py +268 -0
- raise_cli/session/journal.py +119 -0
- raise_cli/session/resolver.py +126 -0
- raise_cli/session/state.py +187 -0
- raise_cli/skills/__init__.py +44 -0
- raise_cli/skills/locator.py +141 -0
- raise_cli/skills/name_checker.py +199 -0
- raise_cli/skills/parser.py +145 -0
- raise_cli/skills/scaffold.py +212 -0
- raise_cli/skills/schema.py +132 -0
- raise_cli/skills/skillsets.py +195 -0
- raise_cli/skills/validator.py +197 -0
- raise_cli/skills_base/__init__.py +80 -0
- raise_cli/skills_base/contract-template.md +60 -0
- raise_cli/skills_base/preamble.md +37 -0
- raise_cli/skills_base/rai-architecture-review/SKILL.md +137 -0
- raise_cli/skills_base/rai-debug/SKILL.md +171 -0
- raise_cli/skills_base/rai-discover/SKILL.md +167 -0
- raise_cli/skills_base/rai-discover-document/SKILL.md +128 -0
- raise_cli/skills_base/rai-discover-scan/SKILL.md +147 -0
- raise_cli/skills_base/rai-discover-start/SKILL.md +145 -0
- raise_cli/skills_base/rai-discover-validate/SKILL.md +142 -0
- raise_cli/skills_base/rai-docs-update/SKILL.md +142 -0
- raise_cli/skills_base/rai-doctor/SKILL.md +120 -0
- raise_cli/skills_base/rai-epic-close/SKILL.md +165 -0
- raise_cli/skills_base/rai-epic-close/templates/retrospective.md +68 -0
- raise_cli/skills_base/rai-epic-design/SKILL.md +146 -0
- raise_cli/skills_base/rai-epic-design/templates/design.md +24 -0
- raise_cli/skills_base/rai-epic-design/templates/scope.md +76 -0
- raise_cli/skills_base/rai-epic-plan/SKILL.md +153 -0
- raise_cli/skills_base/rai-epic-plan/_references/sequencing-strategies.md +67 -0
- raise_cli/skills_base/rai-epic-plan/templates/plan-section.md +49 -0
- raise_cli/skills_base/rai-epic-run/SKILL.md +208 -0
- raise_cli/skills_base/rai-epic-start/SKILL.md +136 -0
- raise_cli/skills_base/rai-epic-start/templates/brief.md +34 -0
- raise_cli/skills_base/rai-mcp-add/SKILL.md +176 -0
- raise_cli/skills_base/rai-mcp-remove/SKILL.md +120 -0
- raise_cli/skills_base/rai-mcp-status/SKILL.md +147 -0
- raise_cli/skills_base/rai-problem-shape/SKILL.md +138 -0
- raise_cli/skills_base/rai-project-create/SKILL.md +144 -0
- raise_cli/skills_base/rai-project-onboard/SKILL.md +162 -0
- raise_cli/skills_base/rai-quality-review/SKILL.md +189 -0
- raise_cli/skills_base/rai-research/SKILL.md +143 -0
- raise_cli/skills_base/rai-research/references/research-prompt-template.md +317 -0
- raise_cli/skills_base/rai-session-close/SKILL.md +176 -0
- raise_cli/skills_base/rai-session-start/SKILL.md +110 -0
- raise_cli/skills_base/rai-story-close/SKILL.md +198 -0
- raise_cli/skills_base/rai-story-design/SKILL.md +203 -0
- raise_cli/skills_base/rai-story-design/references/tech-design-story-v2.md +293 -0
- raise_cli/skills_base/rai-story-implement/SKILL.md +115 -0
- raise_cli/skills_base/rai-story-plan/SKILL.md +135 -0
- raise_cli/skills_base/rai-story-review/SKILL.md +178 -0
- raise_cli/skills_base/rai-story-run/SKILL.md +282 -0
- raise_cli/skills_base/rai-story-start/SKILL.md +166 -0
- raise_cli/skills_base/rai-story-start/templates/story.md +38 -0
- raise_cli/skills_base/rai-welcome/SKILL.md +134 -0
- raise_cli/telemetry/__init__.py +42 -0
- raise_cli/telemetry/schemas.py +285 -0
- raise_cli/telemetry/writer.py +217 -0
- raise_cli/tier/__init__.py +0 -0
- raise_cli/tier/context.py +134 -0
- raise_cli/viz/__init__.py +7 -0
- raise_cli/viz/generator.py +406 -0
- raise_cli-2.2.1.dist-info/METADATA +433 -0
- raise_cli-2.2.1.dist-info/RECORD +264 -0
- raise_cli-2.2.1.dist-info/WHEEL +4 -0
- raise_cli-2.2.1.dist-info/entry_points.txt +40 -0
- raise_cli-2.2.1.dist-info/licenses/LICENSE +190 -0
- raise_cli-2.2.1.dist-info/licenses/NOTICE +4 -0
|
@@ -0,0 +1,746 @@
|
|
|
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
|
+
- Scaffolds skills, workflows, and governance for each target agent
|
|
8
|
+
- Supports multiple agents via --agent (repeatable) or --detect
|
|
9
|
+
|
|
10
|
+
Example:
|
|
11
|
+
$ raise init # defaults to claude
|
|
12
|
+
$ raise init --agent cursor # single agent
|
|
13
|
+
$ raise init --agent claude --agent cursor # multi-agent
|
|
14
|
+
$ raise init --detect # auto-detect installed agents
|
|
15
|
+
$ raise init --ide antigravity # (deprecated) alias for --agent
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import sys
|
|
19
|
+
from datetime import date
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import Annotated
|
|
22
|
+
|
|
23
|
+
import typer
|
|
24
|
+
from rich.console import Console
|
|
25
|
+
from rich.panel import Panel
|
|
26
|
+
|
|
27
|
+
from raise_cli.config.agent_registry import AgentRegistry, load_registry
|
|
28
|
+
from raise_cli.config.agents import AgentChoice, AgentConfig
|
|
29
|
+
from raise_cli.hooks.emitter import create_emitter
|
|
30
|
+
from raise_cli.hooks.events import InitCompleteEvent
|
|
31
|
+
from raise_cli.onboarding.bootstrap import BootstrapResult
|
|
32
|
+
from raise_cli.onboarding.conventions import detect_conventions
|
|
33
|
+
from raise_cli.onboarding.detection import ProjectType, detect_project_type
|
|
34
|
+
from raise_cli.onboarding.governance import (
|
|
35
|
+
GovernanceScaffoldResult,
|
|
36
|
+
generate_guardrails,
|
|
37
|
+
)
|
|
38
|
+
from raise_cli.onboarding.instructions import generate_instructions
|
|
39
|
+
from raise_cli.onboarding.manifest import (
|
|
40
|
+
AgentsManifest,
|
|
41
|
+
BranchConfig,
|
|
42
|
+
ProjectInfo,
|
|
43
|
+
ProjectManifest,
|
|
44
|
+
load_manifest,
|
|
45
|
+
save_manifest,
|
|
46
|
+
)
|
|
47
|
+
from raise_cli.onboarding.profile import (
|
|
48
|
+
DeveloperProfile,
|
|
49
|
+
ExperienceLevel,
|
|
50
|
+
load_developer_profile,
|
|
51
|
+
save_developer_profile,
|
|
52
|
+
)
|
|
53
|
+
from raise_cli.onboarding.skills import SkillScaffoldResult
|
|
54
|
+
|
|
55
|
+
console = Console()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _print_skill_sync_summary(result: SkillScaffoldResult) -> None:
|
|
59
|
+
"""Print a summary table of skill sync actions."""
|
|
60
|
+
from raise_cli.skills_base import __version__ as cli_version
|
|
61
|
+
|
|
62
|
+
console.print(f"\n[bold]Skill sync: raise-cli {cli_version}[/bold]\n")
|
|
63
|
+
|
|
64
|
+
rows: list[tuple[str, str, str]] = []
|
|
65
|
+
for name in result.skills_installed:
|
|
66
|
+
rows.append((name, "[green]new[/green]", "install"))
|
|
67
|
+
for name in result.skills_updated:
|
|
68
|
+
rows.append((name, "[cyan]updated[/cyan]", "auto-update"))
|
|
69
|
+
for name in result.skills_conflicted:
|
|
70
|
+
rows.append((name, "[yellow]conflict[/yellow]", "prompt"))
|
|
71
|
+
for name in result.skills_kept:
|
|
72
|
+
rows.append((name, "[yellow]kept[/yellow]", "user chose keep"))
|
|
73
|
+
for name in result.skills_overwritten:
|
|
74
|
+
rows.append((name, "[cyan]overwritten[/cyan]", "user chose overwrite"))
|
|
75
|
+
for name in result.skills_current:
|
|
76
|
+
rows.append((name, "current", "skip"))
|
|
77
|
+
|
|
78
|
+
rows.sort(key=lambda r: r[0])
|
|
79
|
+
|
|
80
|
+
from rich.table import Table
|
|
81
|
+
|
|
82
|
+
table = Table(show_header=True)
|
|
83
|
+
table.add_column("Skill", style="bold")
|
|
84
|
+
table.add_column("Status")
|
|
85
|
+
table.add_column("Action")
|
|
86
|
+
for name, status, action in rows:
|
|
87
|
+
table.add_row(name, status, action)
|
|
88
|
+
|
|
89
|
+
console.print(table)
|
|
90
|
+
|
|
91
|
+
n_install = len(result.skills_installed)
|
|
92
|
+
n_update = len(result.skills_updated)
|
|
93
|
+
n_conflict = len(result.skills_conflicted) + len(result.skills_kept)
|
|
94
|
+
n_current = len(result.skills_current) + len(result.skills_overwritten)
|
|
95
|
+
parts: list[str] = []
|
|
96
|
+
if n_install:
|
|
97
|
+
parts.append(f"{n_install} new")
|
|
98
|
+
if n_update:
|
|
99
|
+
parts.append(f"{n_update} auto-update")
|
|
100
|
+
if n_conflict:
|
|
101
|
+
parts.append(f"{n_conflict} conflict")
|
|
102
|
+
if n_current:
|
|
103
|
+
parts.append(f"{n_current} current")
|
|
104
|
+
console.print(f"\n Summary: {', '.join(parts)}\n")
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# Message templates for different experience levels
|
|
108
|
+
WELCOME_SHU = """[bold cyan]Welcome to RaiSE![/bold cyan]
|
|
109
|
+
|
|
110
|
+
I'm [bold]Rai[/bold] — your AI partner for reliable software engineering.
|
|
111
|
+
|
|
112
|
+
Together, we'll build software that's both fast AND reliable.
|
|
113
|
+
The RaiSE methodology guides our collaboration:
|
|
114
|
+
• [dim]You[/dim] bring intuition and judgment
|
|
115
|
+
• [dim]I[/dim] bring execution and memory
|
|
116
|
+
• [dim]Together[/dim]: reliable software at AI speed
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
WELCOME_BACK_RI = "[dim]Welcome back, {name}.[/dim]"
|
|
120
|
+
|
|
121
|
+
PROJECT_DETECTED_SHU = """
|
|
122
|
+
[bold]Project detected:[/bold] {project_type} ({file_count} code files)
|
|
123
|
+
{files_section}
|
|
124
|
+
|
|
125
|
+
[bold cyan]What's next?[/bold cyan]
|
|
126
|
+
|
|
127
|
+
[bold]1. Fill governance[/bold] (in Claude Code / AI editor):
|
|
128
|
+
Type [bold cyan]{skill_recommendation}[/bold cyan]
|
|
129
|
+
[dim]→ {skill_description}[/dim]
|
|
130
|
+
|
|
131
|
+
[bold]2. Start a session[/bold] (after governance is set up):
|
|
132
|
+
Type [bold cyan]/rai-session-start[/bold cyan]
|
|
133
|
+
[dim]→ Loads your context, remembers patterns, proposes focused work[/dim]
|
|
134
|
+
|
|
135
|
+
[bold]3. Explore the CLI[/bold] (in terminal):
|
|
136
|
+
[dim]raise --help[/dim] — see all commands
|
|
137
|
+
[dim]raise context[/dim] — query project context
|
|
138
|
+
[dim]raise memory[/dim] — query Rai's memory
|
|
139
|
+
|
|
140
|
+
[dim]Don't have Claude Code? https://claude.ai/download[/dim]
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
PROJECT_DETECTED_RI = """{project_type} project ({file_count} files). Created .raise/manifest.yaml
|
|
144
|
+
|
|
145
|
+
[dim]Next:[/dim] {skill_recommendation} [dim]Then:[/dim] /rai-session-start [dim]CLI:[/dim] raise --help [dim](claude.ai/download)[/dim]
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _get_welcome_message(profile: DeveloperProfile | None) -> str:
|
|
150
|
+
"""Get welcome message based on profile existence and level."""
|
|
151
|
+
if profile is None:
|
|
152
|
+
return WELCOME_SHU
|
|
153
|
+
|
|
154
|
+
if profile.experience_level == ExperienceLevel.RI:
|
|
155
|
+
return WELCOME_BACK_RI.format(name=profile.name)
|
|
156
|
+
elif profile.experience_level == ExperienceLevel.HA:
|
|
157
|
+
return f"[cyan]Welcome back, {profile.name}.[/cyan]\n"
|
|
158
|
+
else:
|
|
159
|
+
return WELCOME_SHU
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _get_skill_recommendation(project_type: str) -> tuple[str, str]:
|
|
163
|
+
"""Get recommended skill based on project type."""
|
|
164
|
+
if project_type == "brownfield":
|
|
165
|
+
return (
|
|
166
|
+
"/rai-project-onboard",
|
|
167
|
+
"Analyze codebase and fill governance from conversation",
|
|
168
|
+
)
|
|
169
|
+
return (
|
|
170
|
+
"/rai-project-create",
|
|
171
|
+
"Fill governance from conversation (new project)",
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _get_project_message(
|
|
176
|
+
project_type: str,
|
|
177
|
+
file_count: int,
|
|
178
|
+
profile: DeveloperProfile | None,
|
|
179
|
+
created_profile: bool,
|
|
180
|
+
bootstrap_result: BootstrapResult | None = None,
|
|
181
|
+
skills_result: SkillScaffoldResult | None = None,
|
|
182
|
+
governance_result: GovernanceScaffoldResult | None = None,
|
|
183
|
+
agent_config: AgentConfig | None = None,
|
|
184
|
+
) -> str:
|
|
185
|
+
"""Get project detection message based on experience level."""
|
|
186
|
+
skills_dir = agent_config.skills_dir if agent_config else ".claude/skills"
|
|
187
|
+
skill_cmd, skill_desc = _get_skill_recommendation(project_type)
|
|
188
|
+
|
|
189
|
+
if profile is None or profile.experience_level == ExperienceLevel.SHU:
|
|
190
|
+
lines = [
|
|
191
|
+
"[bold]Created:[/bold] .raise/manifest.yaml [dim]— project metadata[/dim]"
|
|
192
|
+
]
|
|
193
|
+
if created_profile:
|
|
194
|
+
lines.append(
|
|
195
|
+
"[bold]Created:[/bold] ~/.rai/developer.yaml "
|
|
196
|
+
"[dim]— your preferences (first time)[/dim]"
|
|
197
|
+
)
|
|
198
|
+
else:
|
|
199
|
+
lines.append(
|
|
200
|
+
"[bold]Loaded:[/bold] ~/.rai/developer.yaml [dim]— your preferences[/dim]"
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
if bootstrap_result is not None:
|
|
204
|
+
if bootstrap_result.already_existed:
|
|
205
|
+
# Check if base patterns were synced even though everything else existed
|
|
206
|
+
if bootstrap_result.patterns_added > 0 or bootstrap_result.patterns_updated > 0:
|
|
207
|
+
parts: list[str] = []
|
|
208
|
+
if bootstrap_result.patterns_added > 0:
|
|
209
|
+
parts.append(f"{bootstrap_result.patterns_added} new")
|
|
210
|
+
if bootstrap_result.patterns_updated > 0:
|
|
211
|
+
parts.append(f"{bootstrap_result.patterns_updated} updated")
|
|
212
|
+
lines.append(
|
|
213
|
+
"[bold]Synced:[/bold] .raise/rai/memory/ "
|
|
214
|
+
f"[dim]— {', '.join(parts)} base patterns[/dim]"
|
|
215
|
+
)
|
|
216
|
+
else:
|
|
217
|
+
lines.append(
|
|
218
|
+
"[bold]Loaded:[/bold] .raise/rai/ "
|
|
219
|
+
"[dim]— Rai base already present[/dim]"
|
|
220
|
+
)
|
|
221
|
+
else:
|
|
222
|
+
if bootstrap_result.identity_copied:
|
|
223
|
+
lines.append(
|
|
224
|
+
"[bold]Created:[/bold] .raise/rai/identity/ "
|
|
225
|
+
"[dim]— Rai's base identity[/dim]"
|
|
226
|
+
)
|
|
227
|
+
if bootstrap_result.patterns_copied:
|
|
228
|
+
from importlib.resources import files as _res_files
|
|
229
|
+
|
|
230
|
+
_base = _res_files("raise_cli.rai_base")
|
|
231
|
+
_src = _base / "memory" / "patterns-base.jsonl"
|
|
232
|
+
_count = len([
|
|
233
|
+
ln for ln in _src.read_text(encoding="utf-8").strip().splitlines()
|
|
234
|
+
if ln.strip()
|
|
235
|
+
])
|
|
236
|
+
lines.append(
|
|
237
|
+
"[bold]Created:[/bold] .raise/rai/memory/ "
|
|
238
|
+
f"[dim]— {_count} base patterns[/dim]"
|
|
239
|
+
)
|
|
240
|
+
if bootstrap_result.methodology_copied:
|
|
241
|
+
lines.append(
|
|
242
|
+
"[bold]Created:[/bold] .raise/rai/framework/ "
|
|
243
|
+
"[dim]— methodology definition[/dim]"
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
if skills_result is not None:
|
|
247
|
+
if skills_result.already_existed:
|
|
248
|
+
lines.append(
|
|
249
|
+
f"[bold]Loaded:[/bold] {skills_dir}/ "
|
|
250
|
+
"[dim]— skills already present[/dim]"
|
|
251
|
+
)
|
|
252
|
+
elif skills_result.skills_copied > 0:
|
|
253
|
+
lines.append(
|
|
254
|
+
f"[bold]Created:[/bold] {skills_dir}/ "
|
|
255
|
+
f"[dim]— {skills_result.skills_copied} onboarding skills[/dim]"
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
if governance_result is not None:
|
|
259
|
+
if governance_result.already_existed:
|
|
260
|
+
lines.append(
|
|
261
|
+
"[bold]Loaded:[/bold] governance/ "
|
|
262
|
+
"[dim]— governance templates already present[/dim]"
|
|
263
|
+
)
|
|
264
|
+
elif governance_result.files_created > 0:
|
|
265
|
+
lines.append(
|
|
266
|
+
f"[bold]Created:[/bold] governance/ "
|
|
267
|
+
f"[dim]— {governance_result.files_created} governance templates[/dim]"
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
files_section = "\n".join(lines)
|
|
271
|
+
|
|
272
|
+
return PROJECT_DETECTED_SHU.format(
|
|
273
|
+
project_type=project_type.capitalize(),
|
|
274
|
+
file_count=file_count,
|
|
275
|
+
files_section=files_section,
|
|
276
|
+
skill_recommendation=skill_cmd,
|
|
277
|
+
skill_description=skill_desc,
|
|
278
|
+
)
|
|
279
|
+
else:
|
|
280
|
+
bootstrap_msg = ""
|
|
281
|
+
if bootstrap_result is not None:
|
|
282
|
+
if not bootstrap_result.already_existed:
|
|
283
|
+
bootstrap_msg = (
|
|
284
|
+
f" Bootstrapped Rai base v{bootstrap_result.base_version}\n"
|
|
285
|
+
)
|
|
286
|
+
elif bootstrap_result.patterns_added > 0 or bootstrap_result.patterns_updated > 0:
|
|
287
|
+
parts_ri: list[str] = []
|
|
288
|
+
if bootstrap_result.patterns_added > 0:
|
|
289
|
+
parts_ri.append(f"{bootstrap_result.patterns_added} new")
|
|
290
|
+
if bootstrap_result.patterns_updated > 0:
|
|
291
|
+
parts_ri.append(f"{bootstrap_result.patterns_updated} updated")
|
|
292
|
+
bootstrap_msg = (
|
|
293
|
+
f" Synced base patterns: {', '.join(parts_ri)}\n"
|
|
294
|
+
)
|
|
295
|
+
skills_msg = ""
|
|
296
|
+
if skills_result is not None and not skills_result.already_existed:
|
|
297
|
+
skills_msg = (
|
|
298
|
+
f" Installed {skills_result.skills_copied} skills to {skills_dir}/\n"
|
|
299
|
+
)
|
|
300
|
+
governance_msg = ""
|
|
301
|
+
if governance_result is not None and not governance_result.already_existed:
|
|
302
|
+
governance_msg = f" Scaffolded governance/ ({governance_result.files_created} templates)\n"
|
|
303
|
+
return (
|
|
304
|
+
PROJECT_DETECTED_RI.format(
|
|
305
|
+
project_type=project_type.capitalize(),
|
|
306
|
+
file_count=file_count,
|
|
307
|
+
skill_recommendation=skill_cmd,
|
|
308
|
+
)
|
|
309
|
+
+ bootstrap_msg
|
|
310
|
+
+ skills_msg
|
|
311
|
+
+ governance_msg
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def _create_new_profile(project_path: Path) -> DeveloperProfile:
|
|
316
|
+
"""Create a new developer profile with defaults."""
|
|
317
|
+
today = date.today()
|
|
318
|
+
return DeveloperProfile(
|
|
319
|
+
name="Developer",
|
|
320
|
+
experience_level=ExperienceLevel.SHU,
|
|
321
|
+
first_session=today,
|
|
322
|
+
last_session=today,
|
|
323
|
+
projects=[str(project_path.resolve())],
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def _update_profile_with_project(
|
|
328
|
+
profile: DeveloperProfile, project_path: Path
|
|
329
|
+
) -> DeveloperProfile:
|
|
330
|
+
"""Update profile to include current project."""
|
|
331
|
+
project_str = str(project_path.resolve())
|
|
332
|
+
if project_str not in profile.projects:
|
|
333
|
+
profile.projects.append(project_str)
|
|
334
|
+
profile.last_session = date.today()
|
|
335
|
+
return profile
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def _resolve_agent_types(
|
|
339
|
+
agent: list[str] | None,
|
|
340
|
+
ide: AgentChoice | None,
|
|
341
|
+
detect: bool,
|
|
342
|
+
project_path: Path,
|
|
343
|
+
registry: AgentRegistry,
|
|
344
|
+
) -> list[str]:
|
|
345
|
+
"""Resolve the list of agent types to initialize for.
|
|
346
|
+
|
|
347
|
+
Priority: --agent > --ide (deprecated) > --detect > default ["claude"]
|
|
348
|
+
"""
|
|
349
|
+
if agent:
|
|
350
|
+
return list(agent)
|
|
351
|
+
if ide is not None:
|
|
352
|
+
return [ide.value]
|
|
353
|
+
if detect:
|
|
354
|
+
detected = registry.detect_agents(project_path)
|
|
355
|
+
return detected if detected else ["claude"]
|
|
356
|
+
return ["claude"]
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def _prompt_agent_selection(
|
|
360
|
+
detected: list[str],
|
|
361
|
+
registry: AgentRegistry,
|
|
362
|
+
) -> list[str]:
|
|
363
|
+
"""Show detected agents and prompt user to confirm or extend selection.
|
|
364
|
+
|
|
365
|
+
In non-interactive contexts (no TTY), prints the detected agents and
|
|
366
|
+
returns them without prompting.
|
|
367
|
+
|
|
368
|
+
Args:
|
|
369
|
+
detected: Agent types found by auto-detection.
|
|
370
|
+
registry: Registry used to list all available agents.
|
|
371
|
+
|
|
372
|
+
Returns:
|
|
373
|
+
Final list of agent types selected by the user.
|
|
374
|
+
"""
|
|
375
|
+
all_agents = registry.list_agents()
|
|
376
|
+
detected_label = ", ".join(detected) if detected else "none"
|
|
377
|
+
console.print(f"\n[bold]Detected agents:[/bold] {detected_label}")
|
|
378
|
+
|
|
379
|
+
if not sys.stdin.isatty():
|
|
380
|
+
return detected if detected else ["claude"]
|
|
381
|
+
|
|
382
|
+
console.print(f"[dim]Available:[/dim] {', '.join(all_agents)}")
|
|
383
|
+
default = ",".join(detected) if detected else "claude"
|
|
384
|
+
raw = typer.prompt(
|
|
385
|
+
"Configure agents (comma-separated)",
|
|
386
|
+
default=default,
|
|
387
|
+
)
|
|
388
|
+
return [a.strip() for a in raw.split(",") if a.strip()]
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def _generate_agents_md(
|
|
392
|
+
project_path: Path, agent_types: list[str], project_name: str
|
|
393
|
+
) -> None:
|
|
394
|
+
"""Generate AGENTS.md at project root — cross-tool instructions file.
|
|
395
|
+
|
|
396
|
+
AGENTS.md is supported by Cursor, Windsurf, Copilot, Codex CLI, Kilo Code,
|
|
397
|
+
OpenCode (60K+ repos use it as the universal agent instructions file).
|
|
398
|
+
|
|
399
|
+
Uses IDE-specific session start instructions when only one agent is
|
|
400
|
+
configured; uses generic instructions for multi-agent setups.
|
|
401
|
+
"""
|
|
402
|
+
agents_md_path = project_path / "AGENTS.md"
|
|
403
|
+
if agents_md_path.exists():
|
|
404
|
+
return
|
|
405
|
+
|
|
406
|
+
# Claude Code uses /skill-name syntax; other IDEs do not.
|
|
407
|
+
# Use the slash-command form only for single-claude setups.
|
|
408
|
+
if agent_types == ["claude"]:
|
|
409
|
+
session_instruction = "Run `/rai-session-start` to load full context."
|
|
410
|
+
else:
|
|
411
|
+
session_instruction = (
|
|
412
|
+
"Invoke the `rai-session-start` skill from your IDE to load full context."
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
content = (
|
|
416
|
+
f"# {project_name}\n\n"
|
|
417
|
+
f"> RaiSE-governed project. {session_instruction}\n\n"
|
|
418
|
+
f"## Active Agents\n\n" + "\n".join(f"- {a}" for a in agent_types) + "\n\n"
|
|
419
|
+
"## Process\n\n"
|
|
420
|
+
"This project follows the RaiSE methodology. "
|
|
421
|
+
"See `.raise/` for governance artifacts and `rai --help` for CLI.\n"
|
|
422
|
+
)
|
|
423
|
+
agents_md_path.write_text(content, encoding="utf-8")
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def init_command(
|
|
427
|
+
name: Annotated[
|
|
428
|
+
str | None,
|
|
429
|
+
typer.Option(
|
|
430
|
+
"--name",
|
|
431
|
+
"-n",
|
|
432
|
+
help="Project name (defaults to directory name)",
|
|
433
|
+
),
|
|
434
|
+
] = None,
|
|
435
|
+
path: Annotated[
|
|
436
|
+
Path | None,
|
|
437
|
+
typer.Option(
|
|
438
|
+
"--path",
|
|
439
|
+
"-p",
|
|
440
|
+
help="Project path (defaults to current directory)",
|
|
441
|
+
),
|
|
442
|
+
] = None,
|
|
443
|
+
detect: Annotated[
|
|
444
|
+
bool,
|
|
445
|
+
typer.Option(
|
|
446
|
+
"--detect",
|
|
447
|
+
"-d",
|
|
448
|
+
help="Auto-detect installed agents from project markers. Also generates AGENTS.md.",
|
|
449
|
+
),
|
|
450
|
+
] = False,
|
|
451
|
+
agent: Annotated[
|
|
452
|
+
list[str] | None,
|
|
453
|
+
typer.Option(
|
|
454
|
+
"--agent",
|
|
455
|
+
help="Target agent(s): claude, cursor, windsurf, copilot, antigravity. Repeatable.",
|
|
456
|
+
),
|
|
457
|
+
] = None,
|
|
458
|
+
ide: Annotated[
|
|
459
|
+
AgentChoice | None,
|
|
460
|
+
typer.Option(
|
|
461
|
+
"--ide",
|
|
462
|
+
help="[deprecated] Use --agent instead.",
|
|
463
|
+
hidden=False,
|
|
464
|
+
),
|
|
465
|
+
] = None,
|
|
466
|
+
dry_run: Annotated[
|
|
467
|
+
bool,
|
|
468
|
+
typer.Option(
|
|
469
|
+
"--dry-run",
|
|
470
|
+
help="Preview skill updates without writing files.",
|
|
471
|
+
),
|
|
472
|
+
] = False,
|
|
473
|
+
force: Annotated[
|
|
474
|
+
bool,
|
|
475
|
+
typer.Option(
|
|
476
|
+
"--force",
|
|
477
|
+
help="Overwrite all skill files without prompting.",
|
|
478
|
+
),
|
|
479
|
+
] = False,
|
|
480
|
+
skip_updates: Annotated[
|
|
481
|
+
bool,
|
|
482
|
+
typer.Option(
|
|
483
|
+
"--skip-updates",
|
|
484
|
+
help="Keep all existing skills, only install new ones.",
|
|
485
|
+
),
|
|
486
|
+
] = False,
|
|
487
|
+
skill_set: Annotated[
|
|
488
|
+
str | None,
|
|
489
|
+
typer.Option(
|
|
490
|
+
"--skill-set",
|
|
491
|
+
help="Overlay a skill set from .raise/skills/{name}/ on top of builtins.",
|
|
492
|
+
),
|
|
493
|
+
] = None,
|
|
494
|
+
) -> None:
|
|
495
|
+
"""Initialize a RaiSE project in the current directory.
|
|
496
|
+
|
|
497
|
+
Detects project type (greenfield/brownfield), creates .raise/manifest.yaml,
|
|
498
|
+
and scaffolds skills/workflows for each target agent.
|
|
499
|
+
|
|
500
|
+
Examples:
|
|
501
|
+
$ raise init # defaults to claude
|
|
502
|
+
$ raise init --agent cursor # single agent
|
|
503
|
+
$ raise init --agent claude --agent cursor # multi-agent
|
|
504
|
+
$ raise init --detect # auto-detect agents
|
|
505
|
+
$ raise init --ide antigravity # (deprecated) alias
|
|
506
|
+
"""
|
|
507
|
+
# Determine project path
|
|
508
|
+
project_path = path if path is not None else Path.cwd()
|
|
509
|
+
project_path = project_path.resolve()
|
|
510
|
+
|
|
511
|
+
# Determine project name
|
|
512
|
+
project_name = name if name is not None else project_path.name
|
|
513
|
+
|
|
514
|
+
# Load or create developer profile
|
|
515
|
+
profile = load_developer_profile()
|
|
516
|
+
created_profile = False
|
|
517
|
+
|
|
518
|
+
if profile is None:
|
|
519
|
+
profile = _create_new_profile(project_path)
|
|
520
|
+
save_developer_profile(profile)
|
|
521
|
+
created_profile = True
|
|
522
|
+
else:
|
|
523
|
+
profile = _update_profile_with_project(profile, project_path)
|
|
524
|
+
save_developer_profile(profile)
|
|
525
|
+
|
|
526
|
+
# Detect project type
|
|
527
|
+
detection = detect_project_type(project_path)
|
|
528
|
+
|
|
529
|
+
# Load agent registry (3-tier: built-in → .raise/agents/ → ~/.rai/agents/)
|
|
530
|
+
registry = load_registry(project_root=project_path)
|
|
531
|
+
|
|
532
|
+
# Resolve agent types from flags
|
|
533
|
+
agent_types = _resolve_agent_types(agent, ide, detect, project_path, registry)
|
|
534
|
+
|
|
535
|
+
# When --detect is used, confirm selection interactively
|
|
536
|
+
if detect and agent is None and ide is None:
|
|
537
|
+
agent_types = _prompt_agent_selection(agent_types, registry)
|
|
538
|
+
|
|
539
|
+
# Validate agent types are in registry; skip unknown with warning
|
|
540
|
+
valid_agent_types: list[str] = []
|
|
541
|
+
for at in agent_types:
|
|
542
|
+
try:
|
|
543
|
+
registry.get_config(at)
|
|
544
|
+
valid_agent_types.append(at)
|
|
545
|
+
except KeyError:
|
|
546
|
+
console.print(f"[yellow]Warning:[/yellow] Unknown agent '{at}' — skipped.")
|
|
547
|
+
if not valid_agent_types:
|
|
548
|
+
valid_agent_types = ["claude"]
|
|
549
|
+
|
|
550
|
+
# Create and save manifest with agent types, preserving existing config
|
|
551
|
+
existing_manifest = load_manifest(project_path)
|
|
552
|
+
|
|
553
|
+
project_info = ProjectInfo(
|
|
554
|
+
name=project_name,
|
|
555
|
+
project_type=detection.project_type,
|
|
556
|
+
code_file_count=detection.code_file_count,
|
|
557
|
+
language=detection.language,
|
|
558
|
+
test_command=detection.toolchain.test_command if detection.toolchain else None,
|
|
559
|
+
lint_command=detection.toolchain.lint_command if detection.toolchain else None,
|
|
560
|
+
type_check_command=(
|
|
561
|
+
detection.toolchain.type_check_command if detection.toolchain else None
|
|
562
|
+
),
|
|
563
|
+
)
|
|
564
|
+
manifest = ProjectManifest(
|
|
565
|
+
project=project_info,
|
|
566
|
+
agents=AgentsManifest(types=valid_agent_types),
|
|
567
|
+
branches=existing_manifest.branches if existing_manifest else BranchConfig(),
|
|
568
|
+
tier=existing_manifest.tier if existing_manifest else None,
|
|
569
|
+
)
|
|
570
|
+
save_manifest(manifest, project_path)
|
|
571
|
+
|
|
572
|
+
# Bootstrap Rai base assets (once, agent-agnostic)
|
|
573
|
+
from raise_cli.onboarding.bootstrap import bootstrap_rai_base
|
|
574
|
+
|
|
575
|
+
bootstrap_result = bootstrap_rai_base(project_path)
|
|
576
|
+
|
|
577
|
+
# Scaffold governance templates (once)
|
|
578
|
+
from raise_cli.onboarding.governance import scaffold_governance
|
|
579
|
+
|
|
580
|
+
governance_result = scaffold_governance(project_path, project_name)
|
|
581
|
+
|
|
582
|
+
# Generate MEMORY.md canonical copy
|
|
583
|
+
from raise_cli.config.paths import (
|
|
584
|
+
get_claude_memory_path,
|
|
585
|
+
get_framework_dir,
|
|
586
|
+
get_memory_dir,
|
|
587
|
+
)
|
|
588
|
+
from raise_cli.onboarding.memory_md import generate_memory_md
|
|
589
|
+
|
|
590
|
+
methodology_path = get_framework_dir(project_path) / "methodology.yaml"
|
|
591
|
+
patterns_path = get_memory_dir(project_path) / "patterns.jsonl"
|
|
592
|
+
memory_content = generate_memory_md(
|
|
593
|
+
methodology_path=methodology_path,
|
|
594
|
+
patterns_path=patterns_path,
|
|
595
|
+
project_name=project_name,
|
|
596
|
+
development_branch=manifest.branches.development,
|
|
597
|
+
)
|
|
598
|
+
canonical_memory = get_memory_dir(project_path) / "MEMORY.md"
|
|
599
|
+
canonical_memory.parent.mkdir(parents=True, exist_ok=True)
|
|
600
|
+
canonical_memory.write_text(memory_content, encoding="utf-8")
|
|
601
|
+
|
|
602
|
+
# Per-agent scaffolding
|
|
603
|
+
first_config = registry.get_config(valid_agent_types[0])
|
|
604
|
+
first_skills_result = None
|
|
605
|
+
|
|
606
|
+
from raise_cli.onboarding.skills import scaffold_skills
|
|
607
|
+
from raise_cli.onboarding.workflows import scaffold_workflows
|
|
608
|
+
|
|
609
|
+
for agent_type in valid_agent_types:
|
|
610
|
+
config = registry.get_config(agent_type)
|
|
611
|
+
plugin = registry.get_plugin(agent_type)
|
|
612
|
+
|
|
613
|
+
# Skills
|
|
614
|
+
skills_result = scaffold_skills(
|
|
615
|
+
project_path,
|
|
616
|
+
agent_config=config,
|
|
617
|
+
plugin=plugin,
|
|
618
|
+
force=force,
|
|
619
|
+
skip_updates=skip_updates,
|
|
620
|
+
dry_run=dry_run,
|
|
621
|
+
skill_set=skill_set,
|
|
622
|
+
)
|
|
623
|
+
if agent_type == valid_agent_types[0]:
|
|
624
|
+
first_skills_result = skills_result
|
|
625
|
+
|
|
626
|
+
# Workflows
|
|
627
|
+
scaffold_workflows(project_path, agent_config=config)
|
|
628
|
+
|
|
629
|
+
# Claude-specific: copy MEMORY.md to .claude/projects/
|
|
630
|
+
if config.agent_type == "claude":
|
|
631
|
+
claude_memory = get_claude_memory_path(project_path)
|
|
632
|
+
claude_memory.parent.mkdir(parents=True, exist_ok=True)
|
|
633
|
+
claude_memory.write_text(memory_content, encoding="utf-8")
|
|
634
|
+
|
|
635
|
+
# Plugin post_init hook
|
|
636
|
+
plugin.post_init(project_path, config)
|
|
637
|
+
|
|
638
|
+
# Dry-run: show skill sync summary and exit
|
|
639
|
+
if dry_run and first_skills_result is not None:
|
|
640
|
+
_print_skill_sync_summary(first_skills_result)
|
|
641
|
+
has_updates = bool(
|
|
642
|
+
first_skills_result.skills_updated
|
|
643
|
+
or first_skills_result.skills_installed
|
|
644
|
+
or first_skills_result.skills_conflicted
|
|
645
|
+
)
|
|
646
|
+
raise typer.Exit(code=0 if not has_updates else 1)
|
|
647
|
+
|
|
648
|
+
# Generate CLAUDE.md (or agent-specific instructions) for RaiSE projects
|
|
649
|
+
# This runs always (not just on --detect) so CLAUDE.md stays in sync with .raise/
|
|
650
|
+
if (project_path / ".raise").is_dir():
|
|
651
|
+
instructions_content = generate_instructions(
|
|
652
|
+
project_name=project_name,
|
|
653
|
+
detection=detection,
|
|
654
|
+
project_path=project_path,
|
|
655
|
+
)
|
|
656
|
+
instructions_path = project_path / first_config.instructions_file
|
|
657
|
+
instructions_path.parent.mkdir(parents=True, exist_ok=True)
|
|
658
|
+
instructions_path.write_text(instructions_content, encoding="utf-8")
|
|
659
|
+
|
|
660
|
+
# Emit init:complete event
|
|
661
|
+
emitter = create_emitter()
|
|
662
|
+
emitter.emit(
|
|
663
|
+
InitCompleteEvent(
|
|
664
|
+
project_path=project_path,
|
|
665
|
+
project_name=project_name,
|
|
666
|
+
)
|
|
667
|
+
)
|
|
668
|
+
|
|
669
|
+
# AGENTS.md on --detect
|
|
670
|
+
if detect:
|
|
671
|
+
_generate_agents_md(project_path, valid_agent_types, project_name)
|
|
672
|
+
|
|
673
|
+
# Output messages
|
|
674
|
+
welcome = _get_welcome_message(profile if not created_profile else None)
|
|
675
|
+
project_msg = _get_project_message(
|
|
676
|
+
project_type=detection.project_type.value,
|
|
677
|
+
file_count=detection.code_file_count,
|
|
678
|
+
profile=profile,
|
|
679
|
+
created_profile=created_profile,
|
|
680
|
+
bootstrap_result=bootstrap_result,
|
|
681
|
+
skills_result=first_skills_result,
|
|
682
|
+
governance_result=governance_result,
|
|
683
|
+
agent_config=first_config,
|
|
684
|
+
)
|
|
685
|
+
|
|
686
|
+
if profile.experience_level == ExperienceLevel.RI and not created_profile:
|
|
687
|
+
console.print(welcome)
|
|
688
|
+
console.print(project_msg)
|
|
689
|
+
else:
|
|
690
|
+
console.print(Panel(welcome.strip(), border_style="cyan"))
|
|
691
|
+
console.print(project_msg)
|
|
692
|
+
|
|
693
|
+
# Warn when brownfield governance was just scaffolded (docs are empty templates)
|
|
694
|
+
if (
|
|
695
|
+
detection.project_type == ProjectType.BROWNFIELD
|
|
696
|
+
and not governance_result.already_existed
|
|
697
|
+
and governance_result.files_created > 0
|
|
698
|
+
):
|
|
699
|
+
skill_cmd, _ = _get_skill_recommendation("brownfield")
|
|
700
|
+
if profile.experience_level == ExperienceLevel.RI:
|
|
701
|
+
console.print(
|
|
702
|
+
f"\n[yellow]⚠ Governance docs are empty templates.[/yellow] "
|
|
703
|
+
f"Run [bold cyan]{skill_cmd}[/bold cyan] to fill them."
|
|
704
|
+
)
|
|
705
|
+
else:
|
|
706
|
+
console.print(
|
|
707
|
+
Panel(
|
|
708
|
+
f"[bold yellow]Governance docs need your input[/bold yellow]\n\n"
|
|
709
|
+
f"[dim]vision.md, prd.md, backlog.md[/dim] were created as empty templates.\n"
|
|
710
|
+
f"Any agent that reads them now will get [bold]no context[/bold].\n\n"
|
|
711
|
+
f"Fill them before starting work:\n"
|
|
712
|
+
f" [bold cyan]{skill_cmd}[/bold cyan]",
|
|
713
|
+
border_style="yellow",
|
|
714
|
+
title="[yellow]⚠ Next step required[/yellow]",
|
|
715
|
+
)
|
|
716
|
+
)
|
|
717
|
+
|
|
718
|
+
# Convention detection and guardrails generation (--detect only)
|
|
719
|
+
instructions_path = project_path / first_config.instructions_file
|
|
720
|
+
if detect and detection.project_type == ProjectType.BROWNFIELD:
|
|
721
|
+
conventions = detect_conventions(project_path)
|
|
722
|
+
|
|
723
|
+
if conventions.files_analyzed > 0:
|
|
724
|
+
guardrails_content = generate_guardrails(
|
|
725
|
+
conventions, project_name=project_name
|
|
726
|
+
)
|
|
727
|
+
guardrails_dir = project_path / "governance"
|
|
728
|
+
guardrails_dir.mkdir(parents=True, exist_ok=True)
|
|
729
|
+
guardrails_path = guardrails_dir / "guardrails.md"
|
|
730
|
+
guardrails_path.write_text(guardrails_content, encoding="utf-8")
|
|
731
|
+
|
|
732
|
+
conf = conventions.overall_confidence.value.upper()
|
|
733
|
+
if profile.experience_level == ExperienceLevel.RI:
|
|
734
|
+
console.print(
|
|
735
|
+
f"\n[dim]Conventions detected ({conventions.files_analyzed} files, "
|
|
736
|
+
f"{conf} confidence). Generated guardrails.md and {first_config.instructions_file}[/dim]"
|
|
737
|
+
)
|
|
738
|
+
else:
|
|
739
|
+
console.print(
|
|
740
|
+
f"\n[bold cyan]Convention Detection[/bold cyan]\n"
|
|
741
|
+
f"Analyzed {conventions.files_analyzed} files with {conf} confidence.\n"
|
|
742
|
+
f"Generated:\n"
|
|
743
|
+
f" - [bold]{guardrails_path}[/bold] (code standards)\n"
|
|
744
|
+
f" - [bold]{instructions_path}[/bold] (project context)\n\n"
|
|
745
|
+
f"[dim]Review and adjust as needed.[/dim]"
|
|
746
|
+
)
|