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,324 @@
|
|
|
1
|
+
"""Bootstrap bundled base Rai assets into a project.
|
|
2
|
+
|
|
3
|
+
Copies identity, patterns, and methodology from the raise_cli.rai_base
|
|
4
|
+
package to the project's .raise/rai/ directory during `raise init`.
|
|
5
|
+
|
|
6
|
+
Uses importlib.resources to read bundled files (Python 3.9+).
|
|
7
|
+
Per-file idempotency: existing files are never overwritten.
|
|
8
|
+
|
|
9
|
+
Example:
|
|
10
|
+
from raise_cli.onboarding.bootstrap import bootstrap_rai_base
|
|
11
|
+
|
|
12
|
+
result = bootstrap_rai_base(project_path)
|
|
13
|
+
if result.identity_copied:
|
|
14
|
+
print("Base identity installed")
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import logging
|
|
20
|
+
from importlib.resources import files
|
|
21
|
+
from importlib.resources.abc import Traversable
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
from pydantic import BaseModel, Field
|
|
25
|
+
|
|
26
|
+
from raise_cli.config.paths import (
|
|
27
|
+
get_framework_dir,
|
|
28
|
+
get_identity_dir,
|
|
29
|
+
get_memory_dir,
|
|
30
|
+
get_personal_dir,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
logger = logging.getLogger(__name__)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class BootstrapResult(BaseModel):
|
|
37
|
+
"""Result of base Rai bootstrap operation."""
|
|
38
|
+
|
|
39
|
+
identity_copied: bool = False
|
|
40
|
+
patterns_copied: bool = False
|
|
41
|
+
methodology_copied: bool = False
|
|
42
|
+
base_version: str = ""
|
|
43
|
+
already_existed: bool = False
|
|
44
|
+
files_copied: list[str] = Field(default_factory=list)
|
|
45
|
+
files_skipped: list[str] = Field(default_factory=list)
|
|
46
|
+
patterns_added: int = 0
|
|
47
|
+
patterns_updated: int = 0
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def bootstrap_rai_base(project_root: Path) -> BootstrapResult:
|
|
51
|
+
"""Copy bundled base Rai assets to project .raise/rai/ directory.
|
|
52
|
+
|
|
53
|
+
Copies identity files, base patterns, and methodology definition
|
|
54
|
+
from the installed raise_cli.rai_base package. Uses per-file
|
|
55
|
+
idempotency — existing files are never overwritten.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
project_root: Project root directory.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
BootstrapResult with details of what was copied or skipped.
|
|
62
|
+
"""
|
|
63
|
+
from raise_cli.rai_base import __version__ as base_version
|
|
64
|
+
|
|
65
|
+
base = files("raise_cli.rai_base")
|
|
66
|
+
result = BootstrapResult(base_version=base_version)
|
|
67
|
+
|
|
68
|
+
# Copy identity files
|
|
69
|
+
_copy_identity(base, project_root, result)
|
|
70
|
+
|
|
71
|
+
# Copy patterns
|
|
72
|
+
_copy_patterns(base, project_root, result)
|
|
73
|
+
|
|
74
|
+
# Copy methodology
|
|
75
|
+
_copy_methodology(base, project_root, result)
|
|
76
|
+
|
|
77
|
+
# Ensure personal directory exists with .gitkeep
|
|
78
|
+
_ensure_personal_dir(project_root)
|
|
79
|
+
|
|
80
|
+
# Ensure .gitignore has entries for personal/ephemeral paths
|
|
81
|
+
ensure_gitignore(project_root)
|
|
82
|
+
|
|
83
|
+
# Determine if everything already existed
|
|
84
|
+
result.already_existed = len(result.files_copied) == 0
|
|
85
|
+
|
|
86
|
+
return result
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _copy_identity(
|
|
90
|
+
base: Traversable, project_root: Path, result: BootstrapResult
|
|
91
|
+
) -> None:
|
|
92
|
+
"""Copy base identity files to .raise/rai/identity/.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
base: importlib.resources Traversable for rai_base package.
|
|
96
|
+
project_root: Project root directory.
|
|
97
|
+
result: BootstrapResult to update.
|
|
98
|
+
"""
|
|
99
|
+
identity_dir = get_identity_dir(project_root)
|
|
100
|
+
identity_base = base / "identity"
|
|
101
|
+
|
|
102
|
+
identity_files = ["core.md", "perspective.md"]
|
|
103
|
+
copied_any = False
|
|
104
|
+
|
|
105
|
+
for filename in identity_files:
|
|
106
|
+
dest = identity_dir / filename
|
|
107
|
+
if dest.exists():
|
|
108
|
+
result.files_skipped.append(str(dest))
|
|
109
|
+
logger.debug("Skipped (exists): %s", dest)
|
|
110
|
+
continue
|
|
111
|
+
|
|
112
|
+
content = (identity_base / filename).read_text(encoding="utf-8")
|
|
113
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
114
|
+
dest.write_text(content, encoding="utf-8")
|
|
115
|
+
result.files_copied.append(str(dest))
|
|
116
|
+
copied_any = True
|
|
117
|
+
logger.debug("Copied: %s", dest)
|
|
118
|
+
|
|
119
|
+
result.identity_copied = copied_any
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _copy_patterns(
|
|
123
|
+
base: Traversable, project_root: Path, result: BootstrapResult
|
|
124
|
+
) -> None:
|
|
125
|
+
"""Copy or merge base patterns to .raise/rai/memory/patterns.jsonl.
|
|
126
|
+
|
|
127
|
+
First init: copies all base patterns (fresh install).
|
|
128
|
+
Re-init: merges base patterns — adds new, updates versioned, preserves project patterns.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
base: importlib.resources Traversable for rai_base package.
|
|
132
|
+
project_root: Project root directory.
|
|
133
|
+
result: BootstrapResult to update.
|
|
134
|
+
"""
|
|
135
|
+
import json
|
|
136
|
+
import tempfile
|
|
137
|
+
|
|
138
|
+
memory_dir = get_memory_dir(project_root)
|
|
139
|
+
dest = memory_dir / "patterns.jsonl"
|
|
140
|
+
source = base / "memory" / "patterns-base.jsonl"
|
|
141
|
+
|
|
142
|
+
if not dest.exists():
|
|
143
|
+
# Fresh install: copy all base patterns
|
|
144
|
+
content = source.read_text(encoding="utf-8")
|
|
145
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
146
|
+
dest.write_text(content, encoding="utf-8")
|
|
147
|
+
result.files_copied.append(str(dest))
|
|
148
|
+
result.patterns_copied = True
|
|
149
|
+
logger.debug("Copied: %s", dest)
|
|
150
|
+
return
|
|
151
|
+
|
|
152
|
+
# Re-init: merge base patterns into existing file
|
|
153
|
+
existing_lines = dest.read_text(encoding="utf-8").strip().splitlines()
|
|
154
|
+
existing_patterns: list[dict[str, object]] = []
|
|
155
|
+
existing_by_id: dict[str, int] = {} # id -> index in existing_patterns
|
|
156
|
+
|
|
157
|
+
for line in existing_lines:
|
|
158
|
+
line = line.strip()
|
|
159
|
+
if not line:
|
|
160
|
+
continue
|
|
161
|
+
pattern = json.loads(line)
|
|
162
|
+
idx = len(existing_patterns)
|
|
163
|
+
existing_patterns.append(pattern)
|
|
164
|
+
pid = str(pattern.get("id", ""))
|
|
165
|
+
if pid:
|
|
166
|
+
existing_by_id[pid] = idx
|
|
167
|
+
|
|
168
|
+
# Read base patterns from package
|
|
169
|
+
base_lines = source.read_text(encoding="utf-8").strip().splitlines()
|
|
170
|
+
added = 0
|
|
171
|
+
updated = 0
|
|
172
|
+
|
|
173
|
+
for line in base_lines:
|
|
174
|
+
line = line.strip()
|
|
175
|
+
if not line:
|
|
176
|
+
continue
|
|
177
|
+
base_pattern = json.loads(line)
|
|
178
|
+
pid = str(base_pattern.get("id", ""))
|
|
179
|
+
if not pid:
|
|
180
|
+
continue
|
|
181
|
+
|
|
182
|
+
if pid not in existing_by_id:
|
|
183
|
+
# New base pattern — append
|
|
184
|
+
existing_patterns.append(base_pattern)
|
|
185
|
+
existing_by_id[pid] = len(existing_patterns) - 1
|
|
186
|
+
added += 1
|
|
187
|
+
logger.debug("Added base pattern: %s", pid)
|
|
188
|
+
else:
|
|
189
|
+
# Existing — check version for upgrade
|
|
190
|
+
idx = existing_by_id[pid]
|
|
191
|
+
existing_version = int(str(existing_patterns[idx].get("version", 0)))
|
|
192
|
+
package_version = int(str(base_pattern.get("version", 0)))
|
|
193
|
+
if package_version > existing_version:
|
|
194
|
+
existing_patterns[idx] = base_pattern
|
|
195
|
+
updated += 1
|
|
196
|
+
logger.debug("Updated base pattern: %s v%d → v%d", pid, existing_version, package_version)
|
|
197
|
+
|
|
198
|
+
result.patterns_added = added
|
|
199
|
+
result.patterns_updated = updated
|
|
200
|
+
|
|
201
|
+
if added > 0 or updated > 0:
|
|
202
|
+
# Write atomically: temp file + rename
|
|
203
|
+
merged_content = "\n".join(json.dumps(p) for p in existing_patterns) + "\n"
|
|
204
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
205
|
+
fd, tmp_path = tempfile.mkstemp(
|
|
206
|
+
dir=str(dest.parent), suffix=".tmp", prefix="patterns_"
|
|
207
|
+
)
|
|
208
|
+
try:
|
|
209
|
+
Path(tmp_path).write_text(merged_content, encoding="utf-8")
|
|
210
|
+
Path(tmp_path).replace(dest)
|
|
211
|
+
except Exception:
|
|
212
|
+
Path(tmp_path).unlink(missing_ok=True)
|
|
213
|
+
raise
|
|
214
|
+
finally:
|
|
215
|
+
import contextlib
|
|
216
|
+
import os
|
|
217
|
+
with contextlib.suppress(OSError):
|
|
218
|
+
os.close(fd)
|
|
219
|
+
result.files_copied.append(str(dest))
|
|
220
|
+
logger.debug("Merged base patterns into %s: %d added, %d updated", dest, added, updated)
|
|
221
|
+
else:
|
|
222
|
+
result.files_skipped.append(str(dest))
|
|
223
|
+
logger.debug("Base patterns already current: %s", dest)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def _copy_methodology(
|
|
227
|
+
base: Traversable, project_root: Path, result: BootstrapResult
|
|
228
|
+
) -> None:
|
|
229
|
+
"""Copy methodology.yaml to .raise/rai/framework/.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
base: importlib.resources Traversable for rai_base package.
|
|
233
|
+
project_root: Project root directory.
|
|
234
|
+
result: BootstrapResult to update.
|
|
235
|
+
"""
|
|
236
|
+
framework_dir = get_framework_dir(project_root)
|
|
237
|
+
dest = framework_dir / "methodology.yaml"
|
|
238
|
+
|
|
239
|
+
if dest.exists():
|
|
240
|
+
result.files_skipped.append(str(dest))
|
|
241
|
+
logger.debug("Skipped (exists): %s", dest)
|
|
242
|
+
return
|
|
243
|
+
|
|
244
|
+
source = base / "framework" / "methodology.yaml"
|
|
245
|
+
content = source.read_text(encoding="utf-8")
|
|
246
|
+
|
|
247
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
248
|
+
dest.write_text(content, encoding="utf-8")
|
|
249
|
+
result.files_copied.append(str(dest))
|
|
250
|
+
result.methodology_copied = True
|
|
251
|
+
logger.debug("Copied: %s", dest)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def ensure_gitignore(project_root: Path) -> bool:
|
|
255
|
+
"""Ensure .gitignore contains entries for RaiSE personal/ephemeral paths.
|
|
256
|
+
|
|
257
|
+
Appends a RaiSE-managed block to the project .gitignore if the entries
|
|
258
|
+
are not already present. Idempotent — running multiple times will not
|
|
259
|
+
create duplicate entries.
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
project_root: Project root directory.
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
True if entries were added, False if already present.
|
|
266
|
+
"""
|
|
267
|
+
gitignore_path = project_root / ".gitignore"
|
|
268
|
+
|
|
269
|
+
# Entries to ensure are present
|
|
270
|
+
entries = [
|
|
271
|
+
".raise/rai/personal/",
|
|
272
|
+
]
|
|
273
|
+
|
|
274
|
+
# Read existing content (if any)
|
|
275
|
+
existing_content = ""
|
|
276
|
+
if gitignore_path.exists():
|
|
277
|
+
existing_content = gitignore_path.read_text(encoding="utf-8")
|
|
278
|
+
|
|
279
|
+
# Check which entries are missing
|
|
280
|
+
existing_lines = {line.strip() for line in existing_content.splitlines()}
|
|
281
|
+
missing = [e for e in entries if e not in existing_lines]
|
|
282
|
+
|
|
283
|
+
if not missing:
|
|
284
|
+
logger.debug("All RaiSE gitignore entries already present")
|
|
285
|
+
return False
|
|
286
|
+
|
|
287
|
+
# Build block to append
|
|
288
|
+
block_lines = [
|
|
289
|
+
"",
|
|
290
|
+
"# RaiSE personal directory (per-developer, not shared)",
|
|
291
|
+
]
|
|
292
|
+
for entry in missing:
|
|
293
|
+
block_lines.append(entry)
|
|
294
|
+
block_lines.append("")
|
|
295
|
+
|
|
296
|
+
block = "\n".join(block_lines)
|
|
297
|
+
|
|
298
|
+
# Ensure file ends with newline before appending
|
|
299
|
+
if existing_content and not existing_content.endswith("\n"):
|
|
300
|
+
block = "\n" + block
|
|
301
|
+
|
|
302
|
+
with gitignore_path.open("a", encoding="utf-8") as f:
|
|
303
|
+
f.write(block)
|
|
304
|
+
|
|
305
|
+
logger.debug("Added RaiSE entries to .gitignore: %s", missing)
|
|
306
|
+
return True
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def _ensure_personal_dir(project_root: Path) -> None:
|
|
310
|
+
"""Ensure .raise/rai/personal/ exists with a .gitkeep file.
|
|
311
|
+
|
|
312
|
+
The personal directory is gitignored and stores per-developer data
|
|
313
|
+
(sessions, telemetry, calibration). The .gitkeep ensures the directory
|
|
314
|
+
structure exists after `rai init` before any subsystem creates files.
|
|
315
|
+
|
|
316
|
+
Args:
|
|
317
|
+
project_root: Project root directory.
|
|
318
|
+
"""
|
|
319
|
+
personal_dir = get_personal_dir(project_root)
|
|
320
|
+
personal_dir.mkdir(parents=True, exist_ok=True)
|
|
321
|
+
gitkeep = personal_dir / ".gitkeep"
|
|
322
|
+
if not gitkeep.exists():
|
|
323
|
+
gitkeep.touch()
|
|
324
|
+
logger.debug("Created: %s", gitkeep)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Backward-compatibility shim for claudemd module.
|
|
2
|
+
|
|
3
|
+
All types have moved to raise_cli.onboarding.instructions.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from raise_cli.onboarding.instructions import (
|
|
7
|
+
ClaudeMdGenerator as ClaudeMdGenerator,
|
|
8
|
+
)
|
|
9
|
+
from raise_cli.onboarding.instructions import (
|
|
10
|
+
InstructionsGenerator as InstructionsGenerator,
|
|
11
|
+
)
|
|
12
|
+
from raise_cli.onboarding.instructions import (
|
|
13
|
+
generate_claude_md as generate_claude_md,
|
|
14
|
+
)
|
|
15
|
+
from raise_cli.onboarding.instructions import (
|
|
16
|
+
generate_instructions as generate_instructions,
|
|
17
|
+
)
|