Compare commits
2 Commits
d27c440631
...
v5.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 74198743ab | |||
| d57bff184e |
@@ -53,7 +53,6 @@ class GiteaClient:
|
|||||||
self,
|
self,
|
||||||
state: str = 'open',
|
state: str = 'open',
|
||||||
labels: Optional[List[str]] = None,
|
labels: Optional[List[str]] = None,
|
||||||
milestone: Optional[str] = None,
|
|
||||||
repo: Optional[str] = None
|
repo: Optional[str] = None
|
||||||
) -> List[Dict]:
|
) -> List[Dict]:
|
||||||
"""
|
"""
|
||||||
@@ -62,7 +61,6 @@ class GiteaClient:
|
|||||||
Args:
|
Args:
|
||||||
state: Issue state (open, closed, all)
|
state: Issue state (open, closed, all)
|
||||||
labels: Filter by labels
|
labels: Filter by labels
|
||||||
milestone: Filter by milestone title (exact match)
|
|
||||||
repo: Repository in 'owner/repo' format
|
repo: Repository in 'owner/repo' format
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -73,8 +71,6 @@ class GiteaClient:
|
|||||||
params = {'state': state}
|
params = {'state': state}
|
||||||
if labels:
|
if labels:
|
||||||
params['labels'] = ','.join(labels)
|
params['labels'] = ','.join(labels)
|
||||||
if milestone:
|
|
||||||
params['milestones'] = milestone
|
|
||||||
logger.info(f"Listing issues from {owner}/{target_repo} with state={state}")
|
logger.info(f"Listing issues from {owner}/{target_repo} with state={state}")
|
||||||
response = self.session.get(url, params=params)
|
response = self.session.get(url, params=params)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
|
|||||||
@@ -26,44 +26,6 @@ logging.getLogger("mcp").setLevel(logging.ERROR)
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def _coerce_types(arguments: dict) -> dict:
|
|
||||||
"""
|
|
||||||
Coerce argument types to handle MCP serialization quirks.
|
|
||||||
|
|
||||||
MCP sometimes passes integers as strings and arrays as JSON strings.
|
|
||||||
This function normalizes them to the expected Python types.
|
|
||||||
"""
|
|
||||||
coerced = {}
|
|
||||||
for key, value in arguments.items():
|
|
||||||
if value is None:
|
|
||||||
coerced[key] = value
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Coerce integer fields
|
|
||||||
int_fields = {'issue_number', 'milestone_id', 'pr_number', 'depends_on', 'milestone', 'limit'}
|
|
||||||
if key in int_fields and isinstance(value, str):
|
|
||||||
try:
|
|
||||||
coerced[key] = int(value)
|
|
||||||
continue
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Coerce array fields that might be JSON strings
|
|
||||||
array_fields = {'labels', 'tags', 'issue_numbers', 'comments'}
|
|
||||||
if key in array_fields and isinstance(value, str):
|
|
||||||
try:
|
|
||||||
parsed = json.loads(value)
|
|
||||||
if isinstance(parsed, list):
|
|
||||||
coerced[key] = parsed
|
|
||||||
continue
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
coerced[key] = value
|
|
||||||
|
|
||||||
return coerced
|
|
||||||
|
|
||||||
|
|
||||||
class GiteaMCPServer:
|
class GiteaMCPServer:
|
||||||
"""MCP Server for Gitea integration"""
|
"""MCP Server for Gitea integration"""
|
||||||
|
|
||||||
@@ -126,10 +88,6 @@ class GiteaMCPServer:
|
|||||||
"items": {"type": "string"},
|
"items": {"type": "string"},
|
||||||
"description": "Filter by labels"
|
"description": "Filter by labels"
|
||||||
},
|
},
|
||||||
"milestone": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Filter by milestone title (exact match)"
|
|
||||||
},
|
|
||||||
"repo": {
|
"repo": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Repository name (for PMO mode)"
|
"description": "Repository name (for PMO mode)"
|
||||||
@@ -941,9 +899,6 @@ class GiteaMCPServer:
|
|||||||
List of TextContent with results
|
List of TextContent with results
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Coerce types to handle MCP serialization quirks
|
|
||||||
arguments = _coerce_types(arguments)
|
|
||||||
|
|
||||||
# Route to appropriate tool handler
|
# Route to appropriate tool handler
|
||||||
if name == "list_issues":
|
if name == "list_issues":
|
||||||
result = await self.issue_tools.list_issues(**arguments)
|
result = await self.issue_tools.list_issues(**arguments)
|
||||||
|
|||||||
@@ -98,7 +98,6 @@ class IssueTools:
|
|||||||
self,
|
self,
|
||||||
state: str = 'open',
|
state: str = 'open',
|
||||||
labels: Optional[List[str]] = None,
|
labels: Optional[List[str]] = None,
|
||||||
milestone: Optional[str] = None,
|
|
||||||
repo: Optional[str] = None
|
repo: Optional[str] = None
|
||||||
) -> List[Dict]:
|
) -> List[Dict]:
|
||||||
"""
|
"""
|
||||||
@@ -107,7 +106,6 @@ class IssueTools:
|
|||||||
Args:
|
Args:
|
||||||
state: Issue state (open, closed, all)
|
state: Issue state (open, closed, all)
|
||||||
labels: Filter by labels
|
labels: Filter by labels
|
||||||
milestone: Filter by milestone title (exact match)
|
|
||||||
repo: Override configured repo (for PMO multi-repo)
|
repo: Override configured repo (for PMO multi-repo)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -126,7 +124,7 @@ class IssueTools:
|
|||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
return await loop.run_in_executor(
|
return await loop.run_in_executor(
|
||||||
None,
|
None,
|
||||||
lambda: self.gitea.list_issues(state, labels, milestone, repo)
|
lambda: self.gitea.list_issues(state, labels, repo)
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_issue(
|
async def get_issue(
|
||||||
|
|||||||
@@ -54,32 +54,23 @@ The orchestrator agent will guide you through:
|
|||||||
- If partial: Keep status as "In Progress", note completed implementations
|
- If partial: Keep status as "In Progress", note completed implementations
|
||||||
- Add summary of what was accomplished
|
- Add summary of what was accomplished
|
||||||
|
|
||||||
7. **New Command Verification** (if applicable)
|
7. **Update CHANGELOG** (MANDATORY)
|
||||||
- Check if this sprint added new commands or skills
|
|
||||||
- **IMPORTANT:** New commands are NOT discoverable until session restart
|
|
||||||
- If new commands were added:
|
|
||||||
- List them in sprint close notes
|
|
||||||
- Remind user: "New commands require session restart to test"
|
|
||||||
- Create verification task in next sprint or backlog
|
|
||||||
- **WHY:** Claude Code discovers skills at session start; commands added during a session won't work until restart
|
|
||||||
|
|
||||||
8. **Update CHANGELOG** (MANDATORY)
|
|
||||||
- Add all sprint changes to `[Unreleased]` section in CHANGELOG.md
|
- Add all sprint changes to `[Unreleased]` section in CHANGELOG.md
|
||||||
- Categorize: Added, Changed, Fixed, Removed, Deprecated
|
- Categorize: Added, Changed, Fixed, Removed, Deprecated
|
||||||
- Include plugin prefix (e.g., `- **projman:** New feature`)
|
- Include plugin prefix (e.g., `- **projman:** New feature`)
|
||||||
|
|
||||||
9. **Version Check**
|
8. **Version Check**
|
||||||
- Run `/suggest-version` to analyze changes and recommend version bump
|
- Run `/suggest-version` to analyze changes and recommend version bump
|
||||||
- If release warranted: run `./scripts/release.sh X.Y.Z`
|
- If release warranted: run `./scripts/release.sh X.Y.Z`
|
||||||
- Ensures version numbers stay in sync across files
|
- Ensures version numbers stay in sync across files
|
||||||
|
|
||||||
10. **Git Operations**
|
9. **Git Operations**
|
||||||
- Commit any remaining work (including CHANGELOG updates)
|
- Commit any remaining work (including CHANGELOG updates)
|
||||||
- Merge feature branches if needed
|
- Merge feature branches if needed
|
||||||
- Clean up merged branches
|
- Clean up merged branches
|
||||||
- Tag sprint completion (if release created)
|
- Tag sprint completion (if release created)
|
||||||
|
|
||||||
11. **Close Milestone**
|
10. **Close Milestone**
|
||||||
- Use `update_milestone` to close the sprint milestone
|
- Use `update_milestone` to close the sprint milestone
|
||||||
- Document final completion status
|
- Document final completion status
|
||||||
|
|
||||||
|
|||||||
@@ -6,13 +6,9 @@ description: Begin sprint execution with relevant lessons learned from previous
|
|||||||
|
|
||||||
You are initiating sprint execution. The orchestrator agent will coordinate the work, analyze dependencies for parallel execution, search for relevant lessons learned, and guide you through the implementation process.
|
You are initiating sprint execution. The orchestrator agent will coordinate the work, analyze dependencies for parallel execution, search for relevant lessons learned, and guide you through the implementation process.
|
||||||
|
|
||||||
## Sprint Approval Verification (Recommended)
|
## Sprint Approval Verification
|
||||||
|
|
||||||
**RECOMMENDED: Sprint should be approved before execution.**
|
**CRITICAL: Sprint must be approved before execution.**
|
||||||
|
|
||||||
> **Note:** This is a recommended workflow practice, not code-enforced. The orchestrator
|
|
||||||
> SHOULD check for approval, but execution will proceed if approval is missing. For
|
|
||||||
> critical projects, consider making approval mandatory in your workflow.
|
|
||||||
|
|
||||||
The orchestrator checks for approval in the milestone description:
|
The orchestrator checks for approval in the milestone description:
|
||||||
|
|
||||||
@@ -23,15 +19,16 @@ get_milestone(milestone_id=17)
|
|||||||
|
|
||||||
**If Approval Missing:**
|
**If Approval Missing:**
|
||||||
```
|
```
|
||||||
⚠️ SPRINT APPROVAL NOT FOUND (Warning)
|
⚠️ SPRINT NOT APPROVED
|
||||||
|
|
||||||
Sprint 17 milestone does not contain an approval record.
|
Sprint 17 has not been approved for execution.
|
||||||
|
The milestone description does not contain an approval record.
|
||||||
|
|
||||||
Recommended: Run /sprint-plan first to:
|
Please run /sprint-plan to:
|
||||||
1. Review the sprint scope
|
1. Review the sprint scope
|
||||||
2. Document the approved execution plan
|
2. Approve the execution plan
|
||||||
|
|
||||||
Proceeding anyway - consider adding approval for audit trail.
|
Then run /sprint-start again.
|
||||||
```
|
```
|
||||||
|
|
||||||
**If Approval Found:**
|
**If Approval Found:**
|
||||||
@@ -45,10 +42,10 @@ Proceeding anyway - consider adding approval for audit trail.
|
|||||||
Proceeding with execution within approved scope...
|
Proceeding with execution within approved scope...
|
||||||
```
|
```
|
||||||
|
|
||||||
**Scope Enforcement (when approval exists):**
|
**Scope Enforcement:**
|
||||||
- Agents SHOULD only create branches matching approved patterns
|
- Agents can ONLY create branches matching approved patterns
|
||||||
- Agents SHOULD only modify files within approved paths
|
- Agents can ONLY modify files within approved paths
|
||||||
- Operations outside scope should trigger re-approval via `/sprint-plan`
|
- Operations outside scope require re-approval via `/sprint-plan`
|
||||||
|
|
||||||
## Branch Detection
|
## Branch Detection
|
||||||
|
|
||||||
@@ -69,11 +66,11 @@ If you are on a production or staging branch, you MUST stop and ask the user to
|
|||||||
|
|
||||||
The orchestrator agent will:
|
The orchestrator agent will:
|
||||||
|
|
||||||
1. **Verify Sprint Approval** (Recommended)
|
1. **Verify Sprint Approval**
|
||||||
- Check milestone description for `## Sprint Approval` section
|
- Check milestone description for `## Sprint Approval` section
|
||||||
- If no approval found, WARN user and suggest `/sprint-plan` first
|
- If no approval found, STOP and direct user to `/sprint-plan`
|
||||||
- If approval found, extract scope (branches, files)
|
- If approval found, extract scope (branches, files)
|
||||||
- Agents SHOULD operate within approved scope when available
|
- Agents operate ONLY within approved scope
|
||||||
|
|
||||||
2. **Detect Checkpoints (Resume Support)**
|
2. **Detect Checkpoints (Resume Support)**
|
||||||
- Check each open issue for `## Checkpoint` comments
|
- Check each open issue for `## Checkpoint` comments
|
||||||
|
|||||||
Reference in New Issue
Block a user