143 lines
9.2 KiB
Markdown
143 lines
9.2 KiB
Markdown
---
|
||
description: Sync OpenProject work packages with current feature specs and tasks — creates milestones, phases, and child tasks as needed.
|
||
---
|
||
|
||
## User Input
|
||
|
||
```text
|
||
$ARGUMENTS
|
||
```
|
||
|
||
You **MUST** consider the user input before proceeding (if not empty).
|
||
|
||
## Outline
|
||
|
||
1. **Setup**:
|
||
- **Resolve remote URL**: Run `git remote get-url origin` to get the remote URL. All commit references in this skill MUST use `<remote-url>/commit/<hash>` format. Never use bare hashes.
|
||
- Run `.specify/scripts/powershell/check-prerequisites.ps1 -Json` from repo root and parse FEATURE_DIR, BRANCH, and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot").
|
||
- **If the script fails** (no feature branch, no specs directory, or prerequisites not met): proceed to step 2a (ad-hoc mode).
|
||
|
||
2. **Determine development stage**: Check which design artifacts exist in FEATURE_DIR:
|
||
- `spec.md` exists → at least "specify" stage
|
||
- `plan.md` exists → at least "plan" stage
|
||
- `tasks.md` exists → at least "tasks" stage
|
||
- Tasks with `[X]` checkboxes → "implement" stage (in progress)
|
||
- **No artifacts at all** → "none" stage (proceed to step 2a)
|
||
|
||
**2a. Ad-hoc mode** (no SpecKit artifacts available):
|
||
- This handles cases where:
|
||
- The branch is not a SpecKit feature branch (e.g., `main`, `fix/something`, `hotfix/urgent`)
|
||
- No `specs/` directory exists for this branch
|
||
- The user wants to log work to an existing WP without full SpecKit setup
|
||
- Ask the user: "No SpecKit feature detected for this branch. Which OpenProject work package should I update?"
|
||
- Accept one of:
|
||
- A WP ID (e.g., `#10423` or `10423`)
|
||
- A search term to find the WP (use `mcp__openproject__list_work_packages` with project ID 229 and present matching results)
|
||
- "new" to create a new work package
|
||
- "skip" to abort the OP update
|
||
- If the user provides a WP ID or selects from search results:
|
||
- Get the commits to be logged: `git log --oneline origin/HEAD..HEAD` (or from user input)
|
||
- Add a comment to the selected WP with commit links (`<remote-url>/commit/<hash>`) and summary
|
||
- Report what was logged and skip steps 3–8
|
||
- If the user says "new" or no search results match:
|
||
- Ask for a subject (suggest one based on the branch name or recent commit messages)
|
||
- Ask for a type (Task, Feature, Bug, etc.) — list available types via `mcp__openproject__list_types` if needed
|
||
- Optionally ask for description, priority, and assignee
|
||
- Create the WP via `mcp__openproject__create_work_package` with project ID 229
|
||
- Then log commits to the newly created WP (same as WP ID flow above)
|
||
- Report the new WP ID and what was logged, skip steps 3–8
|
||
- If the user says "skip": abort and return without error
|
||
|
||
3. **Load context**:
|
||
- Read `spec.md` to extract feature title and user stories
|
||
- If `tasks.md` exists: Read it to extract phases, task counts, OP WP IDs (from `— OP #NNNNN` in phase headers), and task details
|
||
- Read `CLAUDE.md` for the OpenProject Work Package IDs table and existing mappings
|
||
|
||
4. **Find or create the Milestone work package**:
|
||
- Extract the feature number and name from the branch name (e.g., `001-ai-etl-platform`)
|
||
- Search OpenProject for an existing Milestone WP matching this feature:
|
||
- Use `mcp__openproject__list_work_packages` with project ID 229 and filter by type "Milestone"
|
||
- Look for a WP whose subject contains the feature number or name
|
||
- **If found**: Display the milestone WP (ID, subject, status) and confirm with user
|
||
- **If NOT found**: Offer to create one:
|
||
- Propose title: `{feature-number} - {Feature Name from spec.md}` (e.g., "001 - Core ETL + Visual Designer (V1)")
|
||
- Propose description from spec.md summary
|
||
- Ask user for confirmation before creating via `mcp__openproject__create_work_package`
|
||
- Store the milestone WP ID for subsequent steps
|
||
|
||
5. **Stage: "tasks" — Sync Phases as Work Packages**:
|
||
- Skip this step if `tasks.md` does not exist
|
||
- Parse all phase headers from tasks.md: `## Phase N: Description — OP #NNNNN`
|
||
- For each phase:
|
||
- **If OP WP ID is present in the header**: Verify the WP exists via `mcp__openproject__get_work_package`
|
||
- If it exists: Compare the subject and update if the description has changed (use `mcp__openproject__update_work_package`)
|
||
- If it does NOT exist (stale ID): Flag it and offer to create a new WP
|
||
- **If NO OP WP ID in the header**: Create a new Phase WP:
|
||
- Type: "Phase" (or "Task" if Phase type unavailable — check `mcp__openproject__list_types` first)
|
||
- Subject: `Phase N: Description` (e.g., "Phase 3: US-1 — Manage Users and Roles")
|
||
- Description: Include the phase purpose, task count, checkpoint criteria, and user story goal
|
||
- After creation, update the tasks.md phase header to include `— OP #NewID`
|
||
- **Create milestone relations**: For each phase WP, create a `requires` relation from the phase to the milestone (if not already linked):
|
||
- Use `mcp__openproject__list_relations` on the phase WP to check existing relations
|
||
- If no `requires` relation to the milestone exists, create one via `mcp__openproject__create_relation`
|
||
- **Create inter-phase dependencies**: Parse the dependency graph from tasks.md (look for "Depends on: Phase N" notes and the dependency graph section):
|
||
- For each dependency, create a `follows` relation (phase X follows phase Y)
|
||
- Check existing relations first to avoid duplicates
|
||
- Report summary: phases found, created, updated, relations created
|
||
|
||
6. **Stage: "implement" — Sync Tasks as Child Work Packages**:
|
||
- Skip this step if NOT in "implement" stage (no `[X]` tasks) unless the user explicitly requests task sync
|
||
- For each phase in tasks.md:
|
||
- Get the phase WP ID from the header
|
||
- Use `mcp__openproject__list_work_packages` to find existing child WPs under this phase (filter by parent if supported, or list all project WPs and filter by subject prefix)
|
||
- Parse all tasks in the phase: `- [ ] T### [P?] [US?] Description`
|
||
- For each task:
|
||
- **If a matching child WP exists** (match by task ID in subject, e.g., "T042"):
|
||
- Compare status: if task is `[X]` in tasks.md but WP is not closed → update WP status
|
||
- Compare subject: if description changed → update WP subject
|
||
- **If NO matching child WP exists**: Create one:
|
||
- Type: "Task"
|
||
- Subject: `T### — Description` (e.g., "T042 — Implement refresh token denylist in backend/etl/.../TokenDenylistService.java")
|
||
- Set parent to the phase WP ID (use direct API PATCH with `_links.parent.href` since MCP update_work_package does not support parent — see CLAUDE.md constraints)
|
||
- **Batch creation**: Process tasks in batches to avoid rate limiting. Create up to 10 WPs at a time, then pause briefly.
|
||
- Update task completion status:
|
||
- For tasks marked `[X]` in tasks.md: Update the corresponding WP status to "Closed" (or appropriate status)
|
||
- For tasks marked `[ ]`: Ensure WP is in "New" or "In progress" status
|
||
- Report summary: tasks found, created, updated, status synced
|
||
|
||
7. **Update CLAUDE.md** (if new WP IDs were created):
|
||
- Update the OpenProject Work Package IDs table in CLAUDE.md with any new phase WP IDs
|
||
- Update task counts if they changed
|
||
- Add any new relation IDs
|
||
|
||
8. **Update tasks.md** (if new phase WP IDs were assigned):
|
||
- Update phase headers with newly assigned OP WP IDs: `## Phase N: Description — OP #NewID`
|
||
|
||
9. **Report**: Output a summary table:
|
||
|
||
```text
|
||
| Action | Count | Details |
|
||
|--------------|-------|----------------------------------|
|
||
| Milestone | 1 | #XXXXX (found/created) |
|
||
| Phases | N | M created, K updated, J existing |
|
||
| Tasks | N | M created, K updated |
|
||
| Relations | N | M requires, K follows |
|
||
| Files Updated| N | tasks.md, CLAUDE.md |
|
||
```
|
||
|
||
- List any errors or items that need manual attention
|
||
- Suggest next steps (e.g., "Run /speckit.implement to start implementation")
|
||
|
||
## Operating Rules
|
||
|
||
1. **Never delete work packages** — only create or update. If a WP seems orphaned, flag it for manual review.
|
||
2. **Always check before creating** — search for existing WPs before creating new ones to avoid duplicates.
|
||
3. **Preserve existing OP WP IDs** — if a phase header already has an OP ID, trust it unless the WP doesn't exist.
|
||
4. **Respect MCP limitations**:
|
||
- Relations are CRD only (no update) — to change a relation type, delete and recreate
|
||
- Parent-child cannot be set via `update_work_package` — use direct API PATCH with `_links.parent.href`
|
||
- Milestones cannot have children — use `requires` relations instead
|
||
5. **Batch operations** — when creating many WPs, process in batches of 10 to avoid overwhelming the API.
|
||
6. **Confirm destructive-ish actions** — ask user before bulk-creating WPs (e.g., "About to create 23 phase WPs. Proceed?").
|
||
7. **Log activity** — after creating or updating WPs, add a comment with context (e.g., "Synced from tasks.md phase header").
|