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.
Files changed (264) hide show
  1. raise_cli/__init__.py +38 -0
  2. raise_cli/__main__.py +30 -0
  3. raise_cli/adapters/__init__.py +91 -0
  4. raise_cli/adapters/declarative/__init__.py +26 -0
  5. raise_cli/adapters/declarative/adapter.py +267 -0
  6. raise_cli/adapters/declarative/discovery.py +94 -0
  7. raise_cli/adapters/declarative/expressions.py +150 -0
  8. raise_cli/adapters/declarative/reference/__init__.py +1 -0
  9. raise_cli/adapters/declarative/reference/github.yaml +143 -0
  10. raise_cli/adapters/declarative/schema.py +98 -0
  11. raise_cli/adapters/filesystem.py +299 -0
  12. raise_cli/adapters/mcp_bridge.py +10 -0
  13. raise_cli/adapters/mcp_confluence.py +246 -0
  14. raise_cli/adapters/mcp_jira.py +405 -0
  15. raise_cli/adapters/models.py +205 -0
  16. raise_cli/adapters/protocols.py +180 -0
  17. raise_cli/adapters/registry.py +90 -0
  18. raise_cli/adapters/sync.py +149 -0
  19. raise_cli/agents/__init__.py +14 -0
  20. raise_cli/agents/antigravity.yaml +8 -0
  21. raise_cli/agents/claude.yaml +8 -0
  22. raise_cli/agents/copilot.yaml +8 -0
  23. raise_cli/agents/copilot_plugin.py +124 -0
  24. raise_cli/agents/cursor.yaml +7 -0
  25. raise_cli/agents/roo.yaml +8 -0
  26. raise_cli/agents/windsurf.yaml +8 -0
  27. raise_cli/artifacts/__init__.py +30 -0
  28. raise_cli/artifacts/models.py +43 -0
  29. raise_cli/artifacts/reader.py +55 -0
  30. raise_cli/artifacts/renderer.py +104 -0
  31. raise_cli/artifacts/story_design.py +69 -0
  32. raise_cli/artifacts/writer.py +45 -0
  33. raise_cli/backlog/__init__.py +1 -0
  34. raise_cli/backlog/sync.py +115 -0
  35. raise_cli/cli/__init__.py +3 -0
  36. raise_cli/cli/commands/__init__.py +3 -0
  37. raise_cli/cli/commands/_resolve.py +153 -0
  38. raise_cli/cli/commands/adapters.py +362 -0
  39. raise_cli/cli/commands/artifact.py +137 -0
  40. raise_cli/cli/commands/backlog.py +333 -0
  41. raise_cli/cli/commands/base.py +31 -0
  42. raise_cli/cli/commands/discover.py +551 -0
  43. raise_cli/cli/commands/docs.py +130 -0
  44. raise_cli/cli/commands/doctor.py +177 -0
  45. raise_cli/cli/commands/gate.py +223 -0
  46. raise_cli/cli/commands/graph.py +1086 -0
  47. raise_cli/cli/commands/info.py +81 -0
  48. raise_cli/cli/commands/init.py +746 -0
  49. raise_cli/cli/commands/journal.py +167 -0
  50. raise_cli/cli/commands/mcp.py +524 -0
  51. raise_cli/cli/commands/memory.py +467 -0
  52. raise_cli/cli/commands/pattern.py +348 -0
  53. raise_cli/cli/commands/profile.py +59 -0
  54. raise_cli/cli/commands/publish.py +80 -0
  55. raise_cli/cli/commands/release.py +338 -0
  56. raise_cli/cli/commands/session.py +528 -0
  57. raise_cli/cli/commands/signal.py +410 -0
  58. raise_cli/cli/commands/skill.py +350 -0
  59. raise_cli/cli/commands/skill_set.py +145 -0
  60. raise_cli/cli/error_handler.py +158 -0
  61. raise_cli/cli/main.py +163 -0
  62. raise_cli/compat.py +66 -0
  63. raise_cli/config/__init__.py +41 -0
  64. raise_cli/config/agent_plugin.py +105 -0
  65. raise_cli/config/agent_registry.py +233 -0
  66. raise_cli/config/agents.py +120 -0
  67. raise_cli/config/ide.py +32 -0
  68. raise_cli/config/paths.py +379 -0
  69. raise_cli/config/settings.py +180 -0
  70. raise_cli/context/__init__.py +42 -0
  71. raise_cli/context/analyzers/__init__.py +16 -0
  72. raise_cli/context/analyzers/models.py +36 -0
  73. raise_cli/context/analyzers/protocol.py +43 -0
  74. raise_cli/context/analyzers/python.py +292 -0
  75. raise_cli/context/builder.py +1569 -0
  76. raise_cli/context/diff.py +213 -0
  77. raise_cli/context/extractors/__init__.py +13 -0
  78. raise_cli/context/extractors/skills.py +121 -0
  79. raise_cli/core/__init__.py +37 -0
  80. raise_cli/core/files.py +66 -0
  81. raise_cli/core/text.py +174 -0
  82. raise_cli/core/tools.py +441 -0
  83. raise_cli/discovery/__init__.py +50 -0
  84. raise_cli/discovery/analyzer.py +691 -0
  85. raise_cli/discovery/drift.py +355 -0
  86. raise_cli/discovery/scanner.py +1687 -0
  87. raise_cli/doctor/__init__.py +4 -0
  88. raise_cli/doctor/checks/__init__.py +1 -0
  89. raise_cli/doctor/checks/environment.py +110 -0
  90. raise_cli/doctor/checks/project.py +238 -0
  91. raise_cli/doctor/fix.py +80 -0
  92. raise_cli/doctor/models.py +56 -0
  93. raise_cli/doctor/protocol.py +43 -0
  94. raise_cli/doctor/registry.py +100 -0
  95. raise_cli/doctor/report.py +141 -0
  96. raise_cli/doctor/runner.py +95 -0
  97. raise_cli/engines/__init__.py +3 -0
  98. raise_cli/exceptions.py +215 -0
  99. raise_cli/gates/__init__.py +19 -0
  100. raise_cli/gates/builtin/__init__.py +1 -0
  101. raise_cli/gates/builtin/coverage.py +52 -0
  102. raise_cli/gates/builtin/lint.py +48 -0
  103. raise_cli/gates/builtin/tests.py +48 -0
  104. raise_cli/gates/builtin/types.py +48 -0
  105. raise_cli/gates/models.py +40 -0
  106. raise_cli/gates/protocol.py +41 -0
  107. raise_cli/gates/registry.py +141 -0
  108. raise_cli/governance/__init__.py +11 -0
  109. raise_cli/governance/extractor.py +412 -0
  110. raise_cli/governance/models.py +134 -0
  111. raise_cli/governance/parsers/__init__.py +35 -0
  112. raise_cli/governance/parsers/_convert.py +38 -0
  113. raise_cli/governance/parsers/adr.py +274 -0
  114. raise_cli/governance/parsers/backlog.py +356 -0
  115. raise_cli/governance/parsers/constitution.py +119 -0
  116. raise_cli/governance/parsers/epic.py +323 -0
  117. raise_cli/governance/parsers/glossary.py +316 -0
  118. raise_cli/governance/parsers/guardrails.py +345 -0
  119. raise_cli/governance/parsers/prd.py +112 -0
  120. raise_cli/governance/parsers/roadmap.py +118 -0
  121. raise_cli/governance/parsers/vision.py +116 -0
  122. raise_cli/graph/__init__.py +1 -0
  123. raise_cli/graph/backends/__init__.py +57 -0
  124. raise_cli/graph/backends/api.py +137 -0
  125. raise_cli/graph/backends/dual.py +139 -0
  126. raise_cli/graph/backends/pending.py +84 -0
  127. raise_cli/handlers/__init__.py +3 -0
  128. raise_cli/hooks/__init__.py +54 -0
  129. raise_cli/hooks/builtin/__init__.py +1 -0
  130. raise_cli/hooks/builtin/backlog.py +216 -0
  131. raise_cli/hooks/builtin/gate_bridge.py +83 -0
  132. raise_cli/hooks/builtin/jira_sync.py +127 -0
  133. raise_cli/hooks/builtin/memory.py +117 -0
  134. raise_cli/hooks/builtin/telemetry.py +72 -0
  135. raise_cli/hooks/emitter.py +184 -0
  136. raise_cli/hooks/events.py +262 -0
  137. raise_cli/hooks/protocol.py +38 -0
  138. raise_cli/hooks/registry.py +117 -0
  139. raise_cli/mcp/__init__.py +33 -0
  140. raise_cli/mcp/bridge.py +218 -0
  141. raise_cli/mcp/models.py +43 -0
  142. raise_cli/mcp/registry.py +77 -0
  143. raise_cli/mcp/schema.py +41 -0
  144. raise_cli/memory/__init__.py +58 -0
  145. raise_cli/memory/loader.py +247 -0
  146. raise_cli/memory/migration.py +241 -0
  147. raise_cli/memory/models.py +169 -0
  148. raise_cli/memory/writer.py +598 -0
  149. raise_cli/onboarding/__init__.py +103 -0
  150. raise_cli/onboarding/bootstrap.py +324 -0
  151. raise_cli/onboarding/claudemd.py +17 -0
  152. raise_cli/onboarding/conventions.py +742 -0
  153. raise_cli/onboarding/detection.py +374 -0
  154. raise_cli/onboarding/governance.py +443 -0
  155. raise_cli/onboarding/instructions.py +672 -0
  156. raise_cli/onboarding/manifest.py +201 -0
  157. raise_cli/onboarding/memory_md.py +399 -0
  158. raise_cli/onboarding/migration.py +207 -0
  159. raise_cli/onboarding/profile.py +624 -0
  160. raise_cli/onboarding/skill_conflict.py +100 -0
  161. raise_cli/onboarding/skill_manifest.py +176 -0
  162. raise_cli/onboarding/skills.py +437 -0
  163. raise_cli/onboarding/workflows.py +101 -0
  164. raise_cli/output/__init__.py +28 -0
  165. raise_cli/output/console.py +394 -0
  166. raise_cli/output/formatters/__init__.py +9 -0
  167. raise_cli/output/formatters/adapters.py +135 -0
  168. raise_cli/output/formatters/discover.py +439 -0
  169. raise_cli/output/formatters/skill.py +298 -0
  170. raise_cli/publish/__init__.py +3 -0
  171. raise_cli/publish/changelog.py +80 -0
  172. raise_cli/publish/check.py +179 -0
  173. raise_cli/publish/version.py +172 -0
  174. raise_cli/rai_base/__init__.py +22 -0
  175. raise_cli/rai_base/framework/__init__.py +7 -0
  176. raise_cli/rai_base/framework/methodology.yaml +233 -0
  177. raise_cli/rai_base/governance/__init__.py +1 -0
  178. raise_cli/rai_base/governance/architecture/__init__.py +1 -0
  179. raise_cli/rai_base/governance/architecture/domain-model.md +20 -0
  180. raise_cli/rai_base/governance/architecture/system-context.md +34 -0
  181. raise_cli/rai_base/governance/architecture/system-design.md +24 -0
  182. raise_cli/rai_base/governance/backlog.md +8 -0
  183. raise_cli/rai_base/governance/guardrails.md +17 -0
  184. raise_cli/rai_base/governance/prd.md +25 -0
  185. raise_cli/rai_base/governance/vision.md +16 -0
  186. raise_cli/rai_base/identity/__init__.py +8 -0
  187. raise_cli/rai_base/identity/core.md +119 -0
  188. raise_cli/rai_base/identity/perspective.md +119 -0
  189. raise_cli/rai_base/memory/__init__.py +7 -0
  190. raise_cli/rai_base/memory/patterns-base.jsonl +55 -0
  191. raise_cli/schemas/__init__.py +3 -0
  192. raise_cli/schemas/journal.py +49 -0
  193. raise_cli/schemas/session_state.py +117 -0
  194. raise_cli/session/__init__.py +5 -0
  195. raise_cli/session/bundle.py +820 -0
  196. raise_cli/session/close.py +268 -0
  197. raise_cli/session/journal.py +119 -0
  198. raise_cli/session/resolver.py +126 -0
  199. raise_cli/session/state.py +187 -0
  200. raise_cli/skills/__init__.py +44 -0
  201. raise_cli/skills/locator.py +141 -0
  202. raise_cli/skills/name_checker.py +199 -0
  203. raise_cli/skills/parser.py +145 -0
  204. raise_cli/skills/scaffold.py +212 -0
  205. raise_cli/skills/schema.py +132 -0
  206. raise_cli/skills/skillsets.py +195 -0
  207. raise_cli/skills/validator.py +197 -0
  208. raise_cli/skills_base/__init__.py +80 -0
  209. raise_cli/skills_base/contract-template.md +60 -0
  210. raise_cli/skills_base/preamble.md +37 -0
  211. raise_cli/skills_base/rai-architecture-review/SKILL.md +137 -0
  212. raise_cli/skills_base/rai-debug/SKILL.md +171 -0
  213. raise_cli/skills_base/rai-discover/SKILL.md +167 -0
  214. raise_cli/skills_base/rai-discover-document/SKILL.md +128 -0
  215. raise_cli/skills_base/rai-discover-scan/SKILL.md +147 -0
  216. raise_cli/skills_base/rai-discover-start/SKILL.md +145 -0
  217. raise_cli/skills_base/rai-discover-validate/SKILL.md +142 -0
  218. raise_cli/skills_base/rai-docs-update/SKILL.md +142 -0
  219. raise_cli/skills_base/rai-doctor/SKILL.md +120 -0
  220. raise_cli/skills_base/rai-epic-close/SKILL.md +165 -0
  221. raise_cli/skills_base/rai-epic-close/templates/retrospective.md +68 -0
  222. raise_cli/skills_base/rai-epic-design/SKILL.md +146 -0
  223. raise_cli/skills_base/rai-epic-design/templates/design.md +24 -0
  224. raise_cli/skills_base/rai-epic-design/templates/scope.md +76 -0
  225. raise_cli/skills_base/rai-epic-plan/SKILL.md +153 -0
  226. raise_cli/skills_base/rai-epic-plan/_references/sequencing-strategies.md +67 -0
  227. raise_cli/skills_base/rai-epic-plan/templates/plan-section.md +49 -0
  228. raise_cli/skills_base/rai-epic-run/SKILL.md +208 -0
  229. raise_cli/skills_base/rai-epic-start/SKILL.md +136 -0
  230. raise_cli/skills_base/rai-epic-start/templates/brief.md +34 -0
  231. raise_cli/skills_base/rai-mcp-add/SKILL.md +176 -0
  232. raise_cli/skills_base/rai-mcp-remove/SKILL.md +120 -0
  233. raise_cli/skills_base/rai-mcp-status/SKILL.md +147 -0
  234. raise_cli/skills_base/rai-problem-shape/SKILL.md +138 -0
  235. raise_cli/skills_base/rai-project-create/SKILL.md +144 -0
  236. raise_cli/skills_base/rai-project-onboard/SKILL.md +162 -0
  237. raise_cli/skills_base/rai-quality-review/SKILL.md +189 -0
  238. raise_cli/skills_base/rai-research/SKILL.md +143 -0
  239. raise_cli/skills_base/rai-research/references/research-prompt-template.md +317 -0
  240. raise_cli/skills_base/rai-session-close/SKILL.md +176 -0
  241. raise_cli/skills_base/rai-session-start/SKILL.md +110 -0
  242. raise_cli/skills_base/rai-story-close/SKILL.md +198 -0
  243. raise_cli/skills_base/rai-story-design/SKILL.md +203 -0
  244. raise_cli/skills_base/rai-story-design/references/tech-design-story-v2.md +293 -0
  245. raise_cli/skills_base/rai-story-implement/SKILL.md +115 -0
  246. raise_cli/skills_base/rai-story-plan/SKILL.md +135 -0
  247. raise_cli/skills_base/rai-story-review/SKILL.md +178 -0
  248. raise_cli/skills_base/rai-story-run/SKILL.md +282 -0
  249. raise_cli/skills_base/rai-story-start/SKILL.md +166 -0
  250. raise_cli/skills_base/rai-story-start/templates/story.md +38 -0
  251. raise_cli/skills_base/rai-welcome/SKILL.md +134 -0
  252. raise_cli/telemetry/__init__.py +42 -0
  253. raise_cli/telemetry/schemas.py +285 -0
  254. raise_cli/telemetry/writer.py +217 -0
  255. raise_cli/tier/__init__.py +0 -0
  256. raise_cli/tier/context.py +134 -0
  257. raise_cli/viz/__init__.py +7 -0
  258. raise_cli/viz/generator.py +406 -0
  259. raise_cli-2.2.1.dist-info/METADATA +433 -0
  260. raise_cli-2.2.1.dist-info/RECORD +264 -0
  261. raise_cli-2.2.1.dist-info/WHEEL +4 -0
  262. raise_cli-2.2.1.dist-info/entry_points.txt +40 -0
  263. raise_cli-2.2.1.dist-info/licenses/LICENSE +190 -0
  264. raise_cli-2.2.1.dist-info/licenses/NOTICE +4 -0
@@ -0,0 +1,205 @@
1
+ """Pydantic models for adapter boundaries.
2
+
3
+ Shared data types consumed by adapter Protocols. These models define
4
+ the contracts at integration boundaries — what goes in and comes out
5
+ of adapters regardless of their concrete implementation.
6
+
7
+ Architecture: ADR-033 (Open-core adapter architecture), ADR-034 (Governance extensibility)
8
+ """
9
+
10
+
11
+ from enum import StrEnum
12
+ from typing import Any
13
+
14
+ from pydantic import BaseModel, Field
15
+
16
+
17
+ class CoreArtifactType(StrEnum):
18
+ """Core governance artifact types.
19
+
20
+ Protocols accept ``str`` — plugins are not restricted to this enum.
21
+ Use these constants for built-in artifact types.
22
+ """
23
+
24
+ BACKLOG = "backlog"
25
+ ADR = "adr"
26
+ CONSTITUTION = "constitution"
27
+ PRD = "prd"
28
+ VISION = "vision"
29
+ GUARDRAILS = "guardrails"
30
+ GLOSSARY = "glossary"
31
+ ROADMAP = "roadmap"
32
+ EPIC_SCOPE = "epic_scope"
33
+
34
+
35
+ class ArtifactLocator(BaseModel):
36
+ """Points to a governance artifact for parsing."""
37
+
38
+ path: str = Field(..., description="Relative path from project root")
39
+ artifact_type: str = Field(
40
+ ..., description="Artifact type (CoreArtifactType or custom str)"
41
+ )
42
+ metadata: dict[str, Any] = Field(
43
+ default_factory=dict, description="Type-specific context"
44
+ )
45
+
46
+
47
+ class IssueSpec(BaseModel):
48
+ """Specification for creating a PM issue."""
49
+
50
+ summary: str = Field(..., description="Issue title")
51
+ description: str = Field(default="", description="Issue body (markdown)")
52
+ issue_type: str = Field(default="Task", description="Issue type name")
53
+ labels: list[str] = Field(default_factory=list)
54
+ metadata: dict[str, Any] = Field(
55
+ default_factory=dict, description="PM-specific fields"
56
+ )
57
+
58
+
59
+ class IssueRef(BaseModel):
60
+ """Reference to an existing PM issue."""
61
+
62
+ key: str = Field(..., description="Issue key (e.g., 'PROJ-123')")
63
+ url: str = Field(default="", description="Web URL to the issue")
64
+ metadata: dict[str, Any] = Field(default_factory=dict)
65
+
66
+
67
+ class PublishResult(BaseModel):
68
+ """Result of publishing documentation."""
69
+
70
+ success: bool = Field(..., description="Whether publish succeeded")
71
+ url: str = Field(default="", description="URL of published content")
72
+ message: str = Field(default="", description="Status or error message")
73
+
74
+
75
+ class IssueDetail(IssueRef):
76
+ """Full issue details — extends IssueRef (inherits key, url, metadata).
77
+
78
+ Timestamps use ISO 8601 format (e.g. ``2026-02-27T10:30:00Z``).
79
+ Empty string means timestamp not available.
80
+ """
81
+
82
+ summary: str = Field(..., description="Issue title")
83
+ description: str = Field(default="", description="Issue body (markdown)")
84
+ status: str = Field(..., description="Current status name")
85
+ issue_type: str = Field(..., description="Issue type (e.g., 'Story', 'Bug')")
86
+ parent_key: str | None = Field(default=None, description="Parent issue key")
87
+ labels: list[str] = Field(default_factory=list)
88
+ assignee: str | None = Field(default=None, description="Assignee identifier")
89
+ priority: str | None = Field(default=None, description="Priority name")
90
+ created: str = Field(default="", description="ISO 8601 creation timestamp")
91
+ updated: str = Field(default="", description="ISO 8601 last update timestamp")
92
+
93
+
94
+ class IssueSummary(BaseModel):
95
+ """Compact issue for search results and listings."""
96
+
97
+ key: str = Field(..., description="Issue key (e.g., 'PROJ-123')")
98
+ summary: str = Field(..., description="Issue title")
99
+ status: str = Field(..., description="Current status name")
100
+ issue_type: str = Field(..., description="Issue type name")
101
+ parent_key: str | None = Field(default=None, description="Parent issue key")
102
+
103
+
104
+ class Comment(BaseModel):
105
+ """Issue comment. Timestamps use ISO 8601 format."""
106
+
107
+ id: str = Field(..., description="Comment ID")
108
+ body: str = Field(..., description="Comment body (markdown)")
109
+ author: str = Field(..., description="Author identifier")
110
+ created: str = Field(..., description="ISO 8601 creation timestamp")
111
+
112
+
113
+ class CommentRef(BaseModel):
114
+ """Reference to a created comment."""
115
+
116
+ id: str = Field(..., description="Comment ID")
117
+ url: str = Field(default="", description="Web URL to the comment")
118
+
119
+
120
+ class FailureDetail(BaseModel):
121
+ """A single failure in a batch operation."""
122
+
123
+ key: str = Field(..., description="Issue key that failed")
124
+ error: str = Field(..., description="Error description")
125
+
126
+
127
+ class BatchResult(BaseModel):
128
+ """Result of a batch operation."""
129
+
130
+ succeeded: list[IssueRef] = Field(default_factory=lambda: list[IssueRef]())
131
+ failed: list[FailureDetail] = Field(default_factory=lambda: list[FailureDetail]())
132
+
133
+
134
+ class PageContent(BaseModel):
135
+ """Full page content from documentation target."""
136
+
137
+ id: str = Field(..., description="Page ID")
138
+ title: str = Field(..., description="Page title")
139
+ content: str = Field(..., description="Page content (markdown)")
140
+ url: str = Field(default="", description="Web URL to the page")
141
+ space_key: str = Field(default="", description="Space key (e.g., 'DEV')")
142
+ version: int = Field(default=1, description="Page version number")
143
+
144
+
145
+ class PageSummary(BaseModel):
146
+ """Compact page for search results. Timestamps use ISO 8601 format."""
147
+
148
+ id: str = Field(..., description="Page ID")
149
+ title: str = Field(..., description="Page title")
150
+ url: str = Field(default="", description="Web URL to the page")
151
+ space_key: str = Field(default="", description="Space key")
152
+ updated: str = Field(default="", description="ISO 8601 last update timestamp")
153
+
154
+
155
+ class AdapterHealth(BaseModel):
156
+ """Health check result for an adapter."""
157
+
158
+ name: str = Field(..., description="Adapter name (e.g., 'jira')")
159
+ healthy: bool = Field(..., description="Whether the adapter is healthy")
160
+ message: str = Field(default="", description="Status or error message")
161
+ latency_ms: int | None = Field(
162
+ default=None, description="Response latency in milliseconds"
163
+ )
164
+
165
+
166
+ # ---------------------------------------------------------------------------
167
+ # YAML store models (S347.2 — FileAdapter parity)
168
+ # ---------------------------------------------------------------------------
169
+
170
+
171
+ class BacklogLink(BaseModel):
172
+ """Link from one backlog item to another."""
173
+
174
+ target: str = Field(..., description="Target issue key")
175
+ link_type: str = Field(..., description="Relationship type (blocks, depends_on, relates_to)")
176
+
177
+
178
+ class BacklogComment(BaseModel):
179
+ """Comment embedded in a backlog item YAML file."""
180
+
181
+ id: str = Field(..., description="Comment ID ({KEY}-{N})")
182
+ body: str = Field(..., description="Comment body text")
183
+ author: str = Field(..., description="Author identifier")
184
+ created: str = Field(..., description="ISO 8601 creation timestamp")
185
+
186
+
187
+ class BacklogItem(BaseModel):
188
+ """Single backlog item stored as .raise/backlog/items/{KEY}.yaml."""
189
+
190
+ key: str = Field(..., description="Issue key (E1, S1.1, etc.)")
191
+ summary: str = Field(..., description="Issue title")
192
+ issue_type: str = Field(..., description="Epic, Story, Task")
193
+ status: str = Field(..., description="pending, in_progress, complete")
194
+ parent: str | None = Field(default=None, description="Parent issue key")
195
+ description: str = Field(default="", description="Issue description")
196
+ labels: list[str] = Field(default_factory=list)
197
+ priority: str | None = Field(default=None, description="Priority level")
198
+ assignee: str | None = Field(default=None, description="Assignee identifier")
199
+ comments: list[BacklogComment] = Field(default_factory=list) # pyright: ignore[reportUnknownVariableType]
200
+ links: list[BacklogLink] = Field(default_factory=list) # pyright: ignore[reportUnknownVariableType]
201
+ created: str = Field(default="", description="ISO 8601 creation timestamp")
202
+ updated: str = Field(default="", description="ISO 8601 last update timestamp")
203
+
204
+
205
+ # BackendHealth moved to raise_core.graph.backends.models (E275)
@@ -0,0 +1,180 @@
1
+ """Protocol contracts for raise-cli adapters.
2
+
3
+ Defines the typed interfaces that adapter implementations must satisfy.
4
+ All Protocols are ``@runtime_checkable`` for isinstance() checks.
5
+
6
+ **Sync vs Async:**
7
+ - ``AsyncProjectManagementAdapter`` / ``AsyncDocumentationTarget`` are the primary
8
+ protocols. Concrete adapters (JiraAdapter, ConfluenceTarget) implement these.
9
+ - ``ProjectManagementAdapter`` / ``DocumentationTarget`` are the sync facades.
10
+ CLI commands consume these. Use ``SyncPMAdapter`` / ``SyncDocsAdapter`` wrappers
11
+ (from ``adapters.sync``) to bridge async adapters to sync consumption.
12
+
13
+ Architecture: ADR-033 (PM), ADR-034 (Governance)
14
+ Note: KnowledgeGraphBackend moved to raise_core.graph.backends.protocol (E275)
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ from typing import Any, Protocol, runtime_checkable
20
+
21
+ from raise_cli.adapters.models import (
22
+ AdapterHealth,
23
+ ArtifactLocator,
24
+ BatchResult,
25
+ Comment,
26
+ CommentRef,
27
+ IssueDetail,
28
+ IssueRef,
29
+ IssueSpec,
30
+ IssueSummary,
31
+ PageContent,
32
+ PageSummary,
33
+ PublishResult,
34
+ )
35
+ from raise_core.graph.models import GraphNode
36
+
37
+ # ---------------------------------------------------------------------------
38
+ # Sync protocols (CLI consumption)
39
+ # ---------------------------------------------------------------------------
40
+
41
+
42
+ @runtime_checkable
43
+ class ProjectManagementAdapter(Protocol):
44
+ """Sync PM adapter contract. CLI commands consume this.
45
+
46
+ For concrete adapters, implement ``AsyncProjectManagementAdapter`` and wrap
47
+ with ``SyncPMAdapter`` for CLI consumption.
48
+ """
49
+
50
+ # CRUD
51
+ def create_issue(self, project_key: str, issue: IssueSpec) -> IssueRef: ...
52
+
53
+ def get_issue(self, key: str) -> IssueDetail: ...
54
+
55
+ def update_issue(self, key: str, fields: dict[str, Any]) -> IssueRef: ...
56
+
57
+ def transition_issue(self, key: str, status: str) -> IssueRef: ...
58
+
59
+ # Batch
60
+ def batch_transition(self, keys: list[str], status: str) -> BatchResult: ...
61
+
62
+ # Relationships
63
+ def link_to_parent(self, child_key: str, parent_key: str) -> None: ...
64
+
65
+ def link_issues(self, source: str, target: str, link_type: str) -> None: ...
66
+
67
+ # Comments
68
+ def add_comment(self, key: str, body: str) -> CommentRef: ...
69
+
70
+ def get_comments(self, key: str, limit: int = 10) -> list[Comment]: ...
71
+
72
+ # Query — query is adapter-specific (JQL for Jira, etc.)
73
+ def search(self, query: str, limit: int = 50) -> list[IssueSummary]: ...
74
+
75
+ # Health
76
+ def health(self) -> AdapterHealth: ...
77
+
78
+
79
+ @runtime_checkable
80
+ class GovernanceSchemaProvider(Protocol):
81
+ """ADR-034: Declares what artifact types exist and where to find them.
82
+
83
+ Implementations: RaiSEDefaultSchema (built-in), OrgSchema (raise-pro).
84
+ """
85
+
86
+ def list_artifact_types(self) -> list[str]: ...
87
+
88
+ def locate(self, artifact_type: str) -> list[ArtifactLocator]: ...
89
+
90
+
91
+ @runtime_checkable
92
+ class GovernanceParser(Protocol):
93
+ """ADR-034: Parses a governance artifact into graph nodes.
94
+
95
+ Implementations: BacklogParser, AdrParser, etc. (S211.3 wraps existing).
96
+ """
97
+
98
+ def can_parse(self, locator: ArtifactLocator) -> bool: ...
99
+
100
+ def parse(self, locator: ArtifactLocator) -> list[GraphNode]: ...
101
+
102
+
103
+ @runtime_checkable
104
+ class DocumentationTarget(Protocol):
105
+ """Sync docs target contract. CLI commands consume this.
106
+
107
+ For concrete targets, implement ``AsyncDocumentationTarget`` and wrap
108
+ with ``SyncDocsAdapter`` for CLI consumption.
109
+ """
110
+
111
+ def can_publish(self, doc_type: str, metadata: dict[str, Any]) -> bool: ...
112
+
113
+ def publish(
114
+ self, doc_type: str, content: str, metadata: dict[str, Any]
115
+ ) -> PublishResult: ...
116
+
117
+ def get_page(self, identifier: str) -> PageContent: ...
118
+
119
+ def search(self, query: str, limit: int = 10) -> list[PageSummary]: ...
120
+
121
+ def health(self) -> AdapterHealth: ...
122
+
123
+
124
+ # ---------------------------------------------------------------------------
125
+ # Async protocols (adapter implementation target)
126
+ # ---------------------------------------------------------------------------
127
+
128
+
129
+ @runtime_checkable
130
+ class AsyncProjectManagementAdapter(Protocol):
131
+ """Async PM adapter contract. Concrete adapters implement this.
132
+
133
+ Consumed directly by async contexts (rai-server) or via ``SyncPMAdapter``
134
+ wrapper for CLI.
135
+ """
136
+
137
+ # CRUD
138
+ async def create_issue(self, project_key: str, issue: IssueSpec) -> IssueRef: ...
139
+
140
+ async def get_issue(self, key: str) -> IssueDetail: ...
141
+
142
+ async def update_issue(self, key: str, fields: dict[str, Any]) -> IssueRef: ...
143
+
144
+ async def transition_issue(self, key: str, status: str) -> IssueRef: ...
145
+
146
+ # Batch
147
+ async def batch_transition(self, keys: list[str], status: str) -> BatchResult: ...
148
+
149
+ # Relationships
150
+ async def link_to_parent(self, child_key: str, parent_key: str) -> None: ...
151
+
152
+ async def link_issues(self, source: str, target: str, link_type: str) -> None: ...
153
+
154
+ # Comments
155
+ async def add_comment(self, key: str, body: str) -> CommentRef: ...
156
+
157
+ async def get_comments(self, key: str, limit: int = 10) -> list[Comment]: ...
158
+
159
+ # Query — query is adapter-specific (JQL for Jira, etc.)
160
+ async def search(self, query: str, limit: int = 50) -> list[IssueSummary]: ...
161
+
162
+ # Health
163
+ async def health(self) -> AdapterHealth: ...
164
+
165
+
166
+ @runtime_checkable
167
+ class AsyncDocumentationTarget(Protocol):
168
+ """Async docs target contract. Concrete targets implement this."""
169
+
170
+ async def can_publish(self, doc_type: str, metadata: dict[str, Any]) -> bool: ...
171
+
172
+ async def publish(
173
+ self, doc_type: str, content: str, metadata: dict[str, Any]
174
+ ) -> PublishResult: ...
175
+
176
+ async def get_page(self, identifier: str) -> PageContent: ...
177
+
178
+ async def search(self, query: str, limit: int = 10) -> list[PageSummary]: ...
179
+
180
+ async def health(self) -> AdapterHealth: ...
@@ -0,0 +1,90 @@
1
+ """Entry point registry for adapter discovery.
2
+
3
+ Discovers adapter implementations registered via Python entry points
4
+ (``[project.entry-points]`` in pyproject.toml). Each group maps to a
5
+ Protocol contract from ``raise_cli.adapters.protocols``.
6
+
7
+ Trust model: entry point loading inherits the ``pip install`` trust boundary.
8
+ If a package is installed in the environment, its entry points are trusted.
9
+ There is no allowlist or sandboxing — this is consistent with how pytest,
10
+ stevedore, and the broader Python ecosystem handle plugin discovery.
11
+
12
+ Architecture: ADR-033 (PM), ADR-034 (Governance), ADR-036 (Graph Backend)
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import inspect
18
+ import logging
19
+ from importlib.metadata import entry_points
20
+ from typing import Any
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+ # Entry point group names — stable contract for external packages.
25
+ EP_PM_ADAPTERS: str = "rai.adapters.pm"
26
+ EP_GOVERNANCE_SCHEMAS: str = "rai.governance.schemas"
27
+ EP_GOVERNANCE_PARSERS: str = "rai.governance.parsers"
28
+ EP_DOC_TARGETS: str = "rai.docs.targets"
29
+ EP_GRAPH_BACKENDS: str = "rai.graph.backends"
30
+
31
+
32
+ def _dist_name(ep: Any) -> str:
33
+ """Best-effort extraction of the distribution name that provides an entry point."""
34
+ try:
35
+ return ep.dist.name # type: ignore[union-attr]
36
+ except AttributeError:
37
+ return "unknown"
38
+
39
+
40
+ def _discover(group: str) -> dict[str, type]:
41
+ """Load all entry points for a group. Skips broken or non-class ones with warning."""
42
+ result: dict[str, type] = {}
43
+ for ep in entry_points(group=group):
44
+ try:
45
+ loaded: Any = ep.load()
46
+ except Exception as exc: # noqa: BLE001
47
+ logger.warning(
48
+ "Skipping entry point '%s' from '%s' in group '%s': %s",
49
+ ep.name,
50
+ _dist_name(ep),
51
+ group,
52
+ exc,
53
+ )
54
+ continue
55
+ if not inspect.isclass(loaded):
56
+ logger.warning(
57
+ "Skipping entry point '%s' from '%s' in group '%s': expected a class, got %s",
58
+ ep.name,
59
+ _dist_name(ep),
60
+ group,
61
+ type(loaded).__name__,
62
+ )
63
+ continue
64
+ result[ep.name] = loaded
65
+ return result
66
+
67
+
68
+ def get_pm_adapters() -> dict[str, type]:
69
+ """Discover ProjectManagementAdapter implementations."""
70
+ return _discover(EP_PM_ADAPTERS)
71
+
72
+
73
+ def get_governance_schemas() -> dict[str, type]:
74
+ """Discover GovernanceSchemaProvider implementations."""
75
+ return _discover(EP_GOVERNANCE_SCHEMAS)
76
+
77
+
78
+ def get_governance_parsers() -> dict[str, type]:
79
+ """Discover GovernanceParser implementations."""
80
+ return _discover(EP_GOVERNANCE_PARSERS)
81
+
82
+
83
+ def get_doc_targets() -> dict[str, type]:
84
+ """Discover DocumentationTarget implementations."""
85
+ return _discover(EP_DOC_TARGETS)
86
+
87
+
88
+ def get_graph_backends() -> dict[str, type]:
89
+ """Discover KnowledgeGraphBackend implementations."""
90
+ return _discover(EP_GRAPH_BACKENDS)
@@ -0,0 +1,149 @@
1
+ """Sync wrappers for async adapter protocols.
2
+
3
+ Bridges async adapters to sync consumption. Safe to call from both sync
4
+ contexts (CLI) and async contexts (hooks, server) — uses a thread-based
5
+ fallback when an event loop is already running.
6
+
7
+ Usage::
8
+
9
+ from raise_cli.adapters.sync import SyncPMAdapter
10
+
11
+ async_adapter = JiraAdapter(config)
12
+ sync_adapter = SyncPMAdapter(async_adapter)
13
+ issue = sync_adapter.get_issue("RAISE-301") # sync call
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import asyncio
19
+ import concurrent.futures
20
+ from collections.abc import Coroutine
21
+ from typing import Any
22
+
23
+ from raise_cli.adapters.models import (
24
+ AdapterHealth,
25
+ BatchResult,
26
+ Comment,
27
+ CommentRef,
28
+ IssueDetail,
29
+ IssueRef,
30
+ IssueSpec,
31
+ IssueSummary,
32
+ PageContent,
33
+ PageSummary,
34
+ PublishResult,
35
+ )
36
+ from raise_cli.adapters.protocols import (
37
+ AsyncDocumentationTarget,
38
+ AsyncProjectManagementAdapter,
39
+ )
40
+
41
+
42
+ def _run_sync[T](coro: Coroutine[Any, Any, T], closeable: Any = None) -> T:
43
+ """Run a coroutine synchronously, safe from both sync and async contexts.
44
+
45
+ - **No running loop:** uses ``asyncio.run()`` directly.
46
+ - **Loop already running:** runs ``asyncio.run()`` in a separate thread
47
+ so each thread gets its own event loop, avoiding the
48
+ ``RuntimeError: asyncio.run() cannot be called from a running event loop``.
49
+
50
+ Args:
51
+ coro: The coroutine to run.
52
+ closeable: Optional object with ``aclose()`` method. Called in a
53
+ ``finally`` block within the same event loop to prevent
54
+ asyncgen finalizer tracebacks (RAISE-324).
55
+ """
56
+
57
+ async def _wrapped() -> T:
58
+ try:
59
+ return await coro
60
+ finally:
61
+ if closeable is not None:
62
+ aclose = getattr(closeable, "aclose", None)
63
+ if aclose:
64
+ await aclose()
65
+
66
+ try:
67
+ asyncio.get_running_loop()
68
+ except RuntimeError:
69
+ # No loop running — safe to use asyncio.run()
70
+ return asyncio.run(_wrapped())
71
+ else:
72
+ # Loop already running — delegate to a thread with its own loop
73
+ with concurrent.futures.ThreadPoolExecutor(max_workers=1) as pool:
74
+ future = pool.submit(asyncio.run, _wrapped())
75
+ return future.result()
76
+
77
+
78
+ class SyncPMAdapter:
79
+ """Wraps ``AsyncProjectManagementAdapter`` for sync CLI consumption.
80
+
81
+ Satisfies ``ProjectManagementAdapter`` protocol via structural typing.
82
+ Each method delegates to the async adapter via ``_run_sync()``.
83
+ """
84
+
85
+ def __init__(self, async_adapter: AsyncProjectManagementAdapter) -> None:
86
+ self._adapter = async_adapter
87
+
88
+ def create_issue(self, project_key: str, issue: IssueSpec) -> IssueRef:
89
+ return _run_sync(self._adapter.create_issue(project_key, issue), self._adapter)
90
+
91
+ def get_issue(self, key: str) -> IssueDetail:
92
+ return _run_sync(self._adapter.get_issue(key), self._adapter)
93
+
94
+ def update_issue(self, key: str, fields: dict[str, Any]) -> IssueRef:
95
+ return _run_sync(self._adapter.update_issue(key, fields), self._adapter)
96
+
97
+ def transition_issue(self, key: str, status: str) -> IssueRef:
98
+ return _run_sync(self._adapter.transition_issue(key, status), self._adapter)
99
+
100
+ def batch_transition(self, keys: list[str], status: str) -> BatchResult:
101
+ return _run_sync(self._adapter.batch_transition(keys, status), self._adapter)
102
+
103
+ def link_to_parent(self, child_key: str, parent_key: str) -> None:
104
+ _run_sync(self._adapter.link_to_parent(child_key, parent_key), self._adapter)
105
+
106
+ def link_issues(self, source: str, target: str, link_type: str) -> None:
107
+ _run_sync(self._adapter.link_issues(source, target, link_type), self._adapter)
108
+
109
+ def add_comment(self, key: str, body: str) -> CommentRef:
110
+ return _run_sync(self._adapter.add_comment(key, body), self._adapter)
111
+
112
+ def get_comments(self, key: str, limit: int = 10) -> list[Comment]:
113
+ return _run_sync(self._adapter.get_comments(key, limit), self._adapter)
114
+
115
+ def search(self, query: str, limit: int = 50) -> list[IssueSummary]:
116
+ return _run_sync(self._adapter.search(query, limit), self._adapter)
117
+
118
+ def health(self) -> AdapterHealth:
119
+ return _run_sync(self._adapter.health(), self._adapter)
120
+
121
+
122
+ class SyncDocsAdapter:
123
+ """Wraps ``AsyncDocumentationTarget`` for sync CLI consumption.
124
+
125
+ Satisfies ``DocumentationTarget`` protocol via structural typing.
126
+ Each method delegates to the async target via ``_run_sync()``.
127
+ """
128
+
129
+ def __init__(self, async_target: AsyncDocumentationTarget) -> None:
130
+ self._target = async_target
131
+
132
+ def can_publish(self, doc_type: str, metadata: dict[str, Any]) -> bool:
133
+ return _run_sync(self._target.can_publish(doc_type, metadata), self._target)
134
+
135
+ def publish(
136
+ self, doc_type: str, content: str, metadata: dict[str, Any]
137
+ ) -> PublishResult:
138
+ return _run_sync(
139
+ self._target.publish(doc_type, content, metadata), self._target
140
+ )
141
+
142
+ def get_page(self, identifier: str) -> PageContent:
143
+ return _run_sync(self._target.get_page(identifier), self._target)
144
+
145
+ def search(self, query: str, limit: int = 10) -> list[PageSummary]:
146
+ return _run_sync(self._target.search(query, limit), self._target)
147
+
148
+ def health(self) -> AdapterHealth:
149
+ return _run_sync(self._target.health(), self._target)
@@ -0,0 +1,14 @@
1
+ """Built-in agent configuration package.
2
+
3
+ Contains YAML config files for the 5 Tier-1 built-in agents:
4
+ - claude.yaml (Claude Code)
5
+ - cursor.yaml (Cursor 2.4+)
6
+ - windsurf.yaml (Windsurf)
7
+ - copilot.yaml (GitHub Copilot — has CopilotPlugin)
8
+ - antigravity.yaml (Antigravity)
9
+
10
+ Usage:
11
+ from importlib.resources import files
12
+ agents_pkg = files("raise_cli.agents")
13
+ claude_yaml = (agents_pkg / "claude.yaml").read_text(encoding="utf-8")
14
+ """
@@ -0,0 +1,8 @@
1
+ name: Antigravity
2
+ agent_type: antigravity
3
+ instructions_file: .agent/rules/raise.md
4
+ skills_dir: .agent/skills
5
+ workflows_dir: .agent/workflows
6
+ detection_markers:
7
+ - .agent/rules
8
+ - .agent
@@ -0,0 +1,8 @@
1
+ name: Claude Code
2
+ agent_type: claude
3
+ instructions_file: CLAUDE.md
4
+ skills_dir: .claude/skills
5
+ detection_markers:
6
+ - CLAUDE.md
7
+ - .claude
8
+ - ~/.claude
@@ -0,0 +1,8 @@
1
+ name: GitHub Copilot
2
+ agent_type: copilot
3
+ instructions_file: .github/copilot-instructions.md
4
+ skills_dir: .github/agents
5
+ workflows_dir: .github/prompts
6
+ detection_markers:
7
+ - .github/copilot-instructions.md
8
+ plugin: raise_cli.agents.copilot_plugin