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,333 @@
|
|
|
1
|
+
"""CLI commands for backlog management via ProjectManagementAdapter.
|
|
2
|
+
|
|
3
|
+
Provides the ``rai backlog`` command group. All commands delegate to a
|
|
4
|
+
ProjectManagementAdapter discovered via entry points (Pattern B, D2).
|
|
5
|
+
The adapter is resolved automatically when exactly one is registered,
|
|
6
|
+
or selected explicitly via ``--adapter NAME`` (D3).
|
|
7
|
+
|
|
8
|
+
Query format in ``search`` is adapter-specific: JQL for Jira, etc. (AR5).
|
|
9
|
+
|
|
10
|
+
Architecture: E301 (Agent Tool Abstraction), ADR-033 (PM Adapter)
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import Annotated, Any
|
|
17
|
+
|
|
18
|
+
import typer
|
|
19
|
+
from rich.console import Console
|
|
20
|
+
|
|
21
|
+
from raise_cli.adapters.models import IssueSpec
|
|
22
|
+
from raise_cli.backlog.sync import sync_backlog
|
|
23
|
+
from raise_cli.cli.commands._resolve import resolve_adapter
|
|
24
|
+
|
|
25
|
+
backlog_app = typer.Typer(
|
|
26
|
+
name="backlog",
|
|
27
|
+
help="Manage backlog items via ProjectManagementAdapter",
|
|
28
|
+
no_args_is_help=True,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
console = Console()
|
|
32
|
+
|
|
33
|
+
_VALID_FORMATS = ("human", "agent")
|
|
34
|
+
|
|
35
|
+
# Common option for adapter override (D3)
|
|
36
|
+
AdapterOption = Annotated[
|
|
37
|
+
str | None,
|
|
38
|
+
typer.Option(
|
|
39
|
+
"--adapter", "-a", help="Adapter name override (auto-detect if omitted)"
|
|
40
|
+
),
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
# Output format option (S325.3: ACI)
|
|
44
|
+
FormatOption = Annotated[
|
|
45
|
+
str,
|
|
46
|
+
typer.Option("--format", "-f", help="Output format (human or agent)"),
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _sanitize_pipe(value: str) -> str:
|
|
51
|
+
"""Replace pipe characters in value to preserve agent format field boundaries."""
|
|
52
|
+
return value.replace("|", "¦")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _validate_format(format: str) -> None:
|
|
56
|
+
"""Validate format option, exit with error if invalid."""
|
|
57
|
+
if format not in _VALID_FORMATS:
|
|
58
|
+
console.print(f"[red]Error:[/red] Invalid format: {format}")
|
|
59
|
+
console.print(f"Valid formats: {', '.join(_VALID_FORMATS)}")
|
|
60
|
+
raise typer.Exit(1)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@backlog_app.command()
|
|
64
|
+
def create(
|
|
65
|
+
summary: Annotated[str, typer.Argument(help="Issue title")],
|
|
66
|
+
project: Annotated[
|
|
67
|
+
str, typer.Option("--project", "-p", help="Project key (e.g., RAISE)")
|
|
68
|
+
],
|
|
69
|
+
issue_type: Annotated[
|
|
70
|
+
str, typer.Option("--type", "-t", help="Issue type")
|
|
71
|
+
] = "Task",
|
|
72
|
+
labels: Annotated[
|
|
73
|
+
str | None, typer.Option("--labels", "-l", help="Comma-separated labels")
|
|
74
|
+
] = None,
|
|
75
|
+
parent: Annotated[
|
|
76
|
+
str | None, typer.Option("--parent", help="Parent issue key")
|
|
77
|
+
] = None,
|
|
78
|
+
description: Annotated[
|
|
79
|
+
str | None,
|
|
80
|
+
typer.Option("--description", "-d", help="Issue description (markdown)"),
|
|
81
|
+
] = None,
|
|
82
|
+
adapter: AdapterOption = None,
|
|
83
|
+
format: FormatOption = "human",
|
|
84
|
+
) -> None:
|
|
85
|
+
"""Create a new backlog item."""
|
|
86
|
+
_validate_format(format)
|
|
87
|
+
pm = resolve_adapter(adapter)
|
|
88
|
+
spec = IssueSpec(
|
|
89
|
+
summary=summary,
|
|
90
|
+
issue_type=issue_type,
|
|
91
|
+
description=description or "",
|
|
92
|
+
labels=labels.split(",") if labels else [],
|
|
93
|
+
metadata={"parent": parent} if parent else {},
|
|
94
|
+
)
|
|
95
|
+
ref = pm.create_issue(project, spec)
|
|
96
|
+
if format == "agent":
|
|
97
|
+
print(ref.key)
|
|
98
|
+
else:
|
|
99
|
+
console.print(f"Created: {ref.key}")
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@backlog_app.command()
|
|
103
|
+
def transition(
|
|
104
|
+
key: Annotated[str, typer.Argument(help="Issue key (e.g., RAISE-123)")],
|
|
105
|
+
status: Annotated[str, typer.Argument(help="Target status")],
|
|
106
|
+
adapter: AdapterOption = None,
|
|
107
|
+
) -> None:
|
|
108
|
+
"""Transition a backlog item to a new status."""
|
|
109
|
+
pm = resolve_adapter(adapter)
|
|
110
|
+
ref = pm.transition_issue(key, status)
|
|
111
|
+
console.print(f"{ref.key}: transitioned \u2192 {status}")
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@backlog_app.command()
|
|
115
|
+
def update(
|
|
116
|
+
key: Annotated[str, typer.Argument(help="Issue key (e.g., RAISE-123)")],
|
|
117
|
+
summary: Annotated[
|
|
118
|
+
str | None, typer.Option("--summary", "-s", help="New summary")
|
|
119
|
+
] = None,
|
|
120
|
+
labels: Annotated[
|
|
121
|
+
str | None, typer.Option("--labels", "-l", help="Comma-separated labels")
|
|
122
|
+
] = None,
|
|
123
|
+
priority: Annotated[
|
|
124
|
+
str | None, typer.Option("--priority", help="Priority name")
|
|
125
|
+
] = None,
|
|
126
|
+
assignee: Annotated[
|
|
127
|
+
str | None, typer.Option("--assignee", help="Assignee identifier")
|
|
128
|
+
] = None,
|
|
129
|
+
adapter: AdapterOption = None,
|
|
130
|
+
) -> None:
|
|
131
|
+
"""Update fields on a backlog item."""
|
|
132
|
+
pm = resolve_adapter(adapter)
|
|
133
|
+
fields: dict[str, Any] = {}
|
|
134
|
+
if summary is not None:
|
|
135
|
+
fields["summary"] = summary
|
|
136
|
+
if labels is not None:
|
|
137
|
+
fields["labels"] = labels.split(",")
|
|
138
|
+
if priority is not None:
|
|
139
|
+
fields["priority"] = priority
|
|
140
|
+
if assignee is not None:
|
|
141
|
+
fields["assignee"] = assignee
|
|
142
|
+
|
|
143
|
+
if not fields:
|
|
144
|
+
console.print("[yellow]Warning:[/yellow] No fields to update.")
|
|
145
|
+
raise typer.Exit(0)
|
|
146
|
+
|
|
147
|
+
ref = pm.update_issue(key, fields)
|
|
148
|
+
console.print(f"{ref.key}: updated")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@backlog_app.command()
|
|
152
|
+
def link(
|
|
153
|
+
source: Annotated[str, typer.Argument(help="Source issue key")],
|
|
154
|
+
target: Annotated[str, typer.Argument(help="Target issue key")],
|
|
155
|
+
link_type: Annotated[
|
|
156
|
+
str, typer.Argument(help="Link type (e.g., 'blocks', 'relates')")
|
|
157
|
+
],
|
|
158
|
+
adapter: AdapterOption = None,
|
|
159
|
+
) -> None:
|
|
160
|
+
"""Link two backlog items (AR4: uses link_issues only)."""
|
|
161
|
+
pm = resolve_adapter(adapter)
|
|
162
|
+
pm.link_issues(source, target, link_type)
|
|
163
|
+
console.print(f"{source} \u2192 {link_type} \u2192 {target}: linked")
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@backlog_app.command()
|
|
167
|
+
def comment(
|
|
168
|
+
key: Annotated[str, typer.Argument(help="Issue key (e.g., RAISE-123)")],
|
|
169
|
+
body: Annotated[str, typer.Argument(help="Comment text (markdown)")],
|
|
170
|
+
adapter: AdapterOption = None,
|
|
171
|
+
) -> None:
|
|
172
|
+
"""Add a comment to a backlog item."""
|
|
173
|
+
pm = resolve_adapter(adapter)
|
|
174
|
+
ref = pm.add_comment(key, body)
|
|
175
|
+
console.print(f"{key}: comment added ({ref.id})")
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@backlog_app.command()
|
|
179
|
+
def get(
|
|
180
|
+
key: Annotated[str, typer.Argument(help="Issue key (e.g., RAISE-123)")],
|
|
181
|
+
adapter: AdapterOption = None,
|
|
182
|
+
) -> None:
|
|
183
|
+
"""Retrieve details for a single backlog item."""
|
|
184
|
+
pm = resolve_adapter(adapter)
|
|
185
|
+
try:
|
|
186
|
+
detail = pm.get_issue(key)
|
|
187
|
+
except Exception as exc:
|
|
188
|
+
console.print(f"[red]Error:[/red] {exc}")
|
|
189
|
+
raise typer.Exit(1) from exc
|
|
190
|
+
|
|
191
|
+
# Header: key, status, type
|
|
192
|
+
console.print(f"{detail.key} {detail.status} {detail.issue_type}")
|
|
193
|
+
console.print(detail.summary)
|
|
194
|
+
|
|
195
|
+
# Optional fields — only show when non-empty
|
|
196
|
+
if detail.assignee:
|
|
197
|
+
console.print(f"Assignee: {detail.assignee}")
|
|
198
|
+
if detail.labels:
|
|
199
|
+
console.print(f"Labels: {', '.join(detail.labels)}")
|
|
200
|
+
if detail.parent_key:
|
|
201
|
+
console.print(f"Parent: {detail.parent_key}")
|
|
202
|
+
if detail.priority:
|
|
203
|
+
console.print(f"Priority: {detail.priority}")
|
|
204
|
+
if detail.created:
|
|
205
|
+
console.print(f"Created: {detail.created}")
|
|
206
|
+
|
|
207
|
+
# Description
|
|
208
|
+
if detail.description:
|
|
209
|
+
console.print()
|
|
210
|
+
desc = detail.description
|
|
211
|
+
if len(desc) > 500:
|
|
212
|
+
desc = desc[:500] + "..."
|
|
213
|
+
console.print(desc)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
@backlog_app.command("get-comments")
|
|
217
|
+
def get_comments(
|
|
218
|
+
key: Annotated[str, typer.Argument(help="Issue key (e.g., RAISE-123)")],
|
|
219
|
+
limit: Annotated[int, typer.Option("--limit", "-n", help="Max comments")] = 10,
|
|
220
|
+
adapter: AdapterOption = None,
|
|
221
|
+
) -> None:
|
|
222
|
+
"""Retrieve comments for a backlog item."""
|
|
223
|
+
pm = resolve_adapter(adapter)
|
|
224
|
+
try:
|
|
225
|
+
comments = pm.get_comments(key, limit=limit)
|
|
226
|
+
except Exception as exc:
|
|
227
|
+
console.print(f"[red]Error:[/red] {exc}")
|
|
228
|
+
raise typer.Exit(1) from exc
|
|
229
|
+
|
|
230
|
+
if not comments:
|
|
231
|
+
console.print("No comments.")
|
|
232
|
+
return
|
|
233
|
+
|
|
234
|
+
for c in comments:
|
|
235
|
+
# Truncate timestamp to date+time (drop timezone for compactness)
|
|
236
|
+
ts = c.created[:19].replace("T", " ") if c.created else ""
|
|
237
|
+
console.print(f"[{ts}] {c.author}:")
|
|
238
|
+
# Indent comment body
|
|
239
|
+
for line in c.body.splitlines():
|
|
240
|
+
console.print(f" {line}")
|
|
241
|
+
console.print()
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
@backlog_app.command()
|
|
245
|
+
def search(
|
|
246
|
+
query: Annotated[
|
|
247
|
+
str,
|
|
248
|
+
typer.Argument(
|
|
249
|
+
help="Search query (format depends on adapter, e.g., JQL for Jira)"
|
|
250
|
+
),
|
|
251
|
+
],
|
|
252
|
+
limit: Annotated[int, typer.Option("--limit", "-n", help="Max results")] = 50,
|
|
253
|
+
adapter: AdapterOption = None,
|
|
254
|
+
format: FormatOption = "human",
|
|
255
|
+
) -> None:
|
|
256
|
+
"""Search backlog items. Query format is adapter-specific (AR5)."""
|
|
257
|
+
_validate_format(format)
|
|
258
|
+
pm = resolve_adapter(adapter)
|
|
259
|
+
results = pm.search(query, limit=limit)
|
|
260
|
+
if not results:
|
|
261
|
+
if format != "agent":
|
|
262
|
+
console.print("No results.")
|
|
263
|
+
return
|
|
264
|
+
if format == "agent":
|
|
265
|
+
for issue in results:
|
|
266
|
+
print(
|
|
267
|
+
f"{issue.key}|{_sanitize_pipe(issue.status)}|{_sanitize_pipe(issue.summary)}"
|
|
268
|
+
)
|
|
269
|
+
else:
|
|
270
|
+
for issue in results:
|
|
271
|
+
console.print(f"{issue.key} {issue.status:<12} {issue.summary}")
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
@backlog_app.command("batch-transition")
|
|
275
|
+
def batch_transition(
|
|
276
|
+
keys: Annotated[
|
|
277
|
+
str, typer.Argument(help="Comma-separated issue keys (e.g., RAISE-1,RAISE-2)")
|
|
278
|
+
],
|
|
279
|
+
status: Annotated[str, typer.Argument(help="Target status")],
|
|
280
|
+
adapter: AdapterOption = None,
|
|
281
|
+
) -> None:
|
|
282
|
+
"""Transition multiple backlog items at once."""
|
|
283
|
+
pm = resolve_adapter(adapter)
|
|
284
|
+
key_list = [k.strip() for k in keys.split(",") if k.strip()]
|
|
285
|
+
if not key_list:
|
|
286
|
+
console.print("[red]Error:[/red] No valid keys provided.")
|
|
287
|
+
raise typer.Exit(1)
|
|
288
|
+
|
|
289
|
+
result = pm.batch_transition(key_list, status)
|
|
290
|
+
succeeded = len(result.succeeded)
|
|
291
|
+
failed = len(result.failed)
|
|
292
|
+
total = succeeded + failed
|
|
293
|
+
|
|
294
|
+
console.print(f"{succeeded}/{total} transitioned \u2192 {status}")
|
|
295
|
+
for failure in result.failed:
|
|
296
|
+
console.print(f" [red]\u2717[/red] {failure.key}: {failure.error}")
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
@backlog_app.command()
|
|
300
|
+
def sync(
|
|
301
|
+
project: Annotated[
|
|
302
|
+
str | None,
|
|
303
|
+
typer.Option("--project", "-p", help="Project key filter (e.g., RAISE)"),
|
|
304
|
+
] = None,
|
|
305
|
+
adapter: AdapterOption = None,
|
|
306
|
+
) -> None:
|
|
307
|
+
"""Regenerate governance/backlog.md from a remote adapter."""
|
|
308
|
+
pm = resolve_adapter(adapter)
|
|
309
|
+
|
|
310
|
+
# Derive adapter name for display
|
|
311
|
+
adapter_name = adapter or type(pm).__name__.lower().replace("pmadapter", "").replace("adapter", "") or "unknown"
|
|
312
|
+
|
|
313
|
+
output_path = Path.cwd() / "governance" / "backlog.md"
|
|
314
|
+
|
|
315
|
+
try:
|
|
316
|
+
result = sync_backlog(
|
|
317
|
+
pm,
|
|
318
|
+
adapter_name,
|
|
319
|
+
project_filter=project,
|
|
320
|
+
output_path=output_path,
|
|
321
|
+
)
|
|
322
|
+
except ValueError as exc:
|
|
323
|
+
# Filesystem adapter no-op
|
|
324
|
+
console.print(f"[yellow]{exc}[/yellow]")
|
|
325
|
+
raise typer.Exit(0) from exc
|
|
326
|
+
except RuntimeError as exc:
|
|
327
|
+
console.print(f"[red]Error:[/red] {exc}")
|
|
328
|
+
raise typer.Exit(1) from exc
|
|
329
|
+
|
|
330
|
+
console.print(
|
|
331
|
+
f"Synced {result.output_path} from {result.adapter_name} "
|
|
332
|
+
f"({result.epic_count} epics, {result.timestamp})"
|
|
333
|
+
)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Backward-compatible alias for the info command.
|
|
2
|
+
|
|
3
|
+
The `base show` command has been moved to `rai info` (RAISE-247/S5).
|
|
4
|
+
|
|
5
|
+
This alias prints a deprecation warning and delegates to the canonical command.
|
|
6
|
+
It will be removed in a future release (RAISE-247/S9).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import typer
|
|
12
|
+
from rich.console import Console
|
|
13
|
+
|
|
14
|
+
base_app = typer.Typer(
|
|
15
|
+
name="base",
|
|
16
|
+
help="View base Rai package info",
|
|
17
|
+
no_args_is_help=True,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
_stderr_console = Console(stderr=True)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@base_app.command()
|
|
24
|
+
def show() -> None:
|
|
25
|
+
"""Deprecated: use 'rai info'."""
|
|
26
|
+
_stderr_console.print(
|
|
27
|
+
"[yellow]DEPRECATED:[/yellow] 'rai base show' → use 'rai info' instead",
|
|
28
|
+
)
|
|
29
|
+
from raise_cli.cli.commands.info import info_command
|
|
30
|
+
|
|
31
|
+
info_command()
|