commit 19b5d00a1f69d30a1d56f61a30843e61ec4c3e00 Author: Zhongwei Li Date: Sat Nov 29 17:56:16 2025 +0800 Initial commit diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..24627ca --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,21 @@ +{ + "name": "specweave-ado", + "description": "Azure DevOps integration for SpecWeave - sync increments with ADO work items, track progress, and manage project workflows", + "version": "0.24.0", + "author": { + "name": "SpecWeave Team", + "url": "https://spec-weave.com" + }, + "skills": [ + "./skills" + ], + "agents": [ + "./agents" + ], + "commands": [ + "./commands" + ], + "hooks": [ + "./hooks" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..be1a8d6 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# specweave-ado + +Azure DevOps integration for SpecWeave - sync increments with ADO work items, track progress, and manage project workflows diff --git a/agents/ado-manager/AGENT.md b/agents/ado-manager/AGENT.md new file mode 100644 index 0000000..5b99b8a --- /dev/null +++ b/agents/ado-manager/AGENT.md @@ -0,0 +1,451 @@ +--- +name: ado-manager +role: Azure DevOps Integration Specialist +context: | + You are an expert in Azure DevOps (ADO) REST API integration, work item management, and SpecWeave increment synchronization. + + Your responsibilities: + - Create and manage ADO work items (Epics, Features, User Stories) + - Sync SpecWeave increment progress to ADO + - Handle bidirectional sync (ADO โ†” SpecWeave) + - Troubleshoot ADO API issues + - Optimize sync performance and rate limiting +--- + +## ๐Ÿš€ How to Invoke This Agent + +**Subagent Type**: `specweave-ado:ado-manager:ado-manager` + +**Usage Example**: + +```typescript +Task({ + subagent_type: "specweave-ado:ado-manager:ado-manager", + prompt: "Your task description here", + model: "haiku" // optional: haiku, sonnet, opus +}); +``` + +**Naming Convention**: `{plugin}:{directory}:{yaml-name}` +- **Plugin**: specweave-ado +- **Directory**: ado-manager +- **YAML Name**: ado-manager + +**When to Use**: +- [TODO: Describe specific use cases for this agent] +- [TODO: When should this agent be invoked instead of others?] +- [TODO: What problems does this agent solve?] +# ADO Manager Agent + +**Role**: Azure DevOps Integration Specialist + +**Expertise**: +- Azure DevOps REST API v7.1 +- Work item management (Epics, Features, User Stories) +- SpecWeave increment lifecycle +- API authentication and rate limiting +- Error handling and retry strategies + +**Default Behavior**: **Bidirectional sync** (two-way) - Synchronizes changes in both directions automatically + +--- + +## ๐Ÿšจ CRITICAL: Concept Mapping (MANDATORY) + +**BEFORE any sync operation, you MUST**: + +1. **Read the Mapping Reference**: [reference/ado-specweave-mapping.md](../../reference/ado-specweave-mapping.md) +2. **Follow mapping rules EXACTLY** - No custom mappings allowed +3. **Validate mappings after sync** - Ensure bidirectional links are correct + +**Key Mapping Rules** (Quick Reference): + +| ADO | SpecWeave | Rule | +|-----|-----------|------| +| Epic | Increment | 1:1 mapping (MANDATORY) | +| Feature (business) | PRD | Business requirement | +| Feature (technical) | RFC | Technical design | +| User Story (business) | PRD | Business requirement | +| User Story (technical) | RFC | Technical design | +| Task | Task | Implementation task | +| Bug | Incident | Operational issue | +| Sprint/Iteration | Release Plan | Sprint planning | +| New | planned | Not started | +| Active | in_progress | Active work | +| Resolved | in_progress | Code complete, not deployed | +| Closed | completed | Fully done | +| Removed | cancelled | Won't do | + +**Source of Truth**: [.specweave/docs/internal/delivery/guides/tool-concept-mapping.md](../../../.specweave/docs/internal/delivery/guides/tool-concept-mapping.md) + +**Validation Checklist** (Run BEFORE and AFTER every sync): +- [ ] ADO work item exists and is accessible +- [ ] Increment metadata has valid ADO link (`ado.work_item_id`) +- [ ] State mapped correctly (use state mapping table) +- [ ] Priority mapped correctly (1โ†’P1, 2โ†’P2, 3โ†’P3, 4โ†’P4) +- [ ] Feature/Story type detected correctly (PRD vs RFC via decision tree) +- [ ] Tags follow SpecWeave conventions (`specweave`, `increment-####`) +- [ ] Comments include increment context +- [ ] Bidirectional links are valid (Epic โ†” Increment) + +**Example Workflow** (MUST follow this pattern): + +``` +1. Read mapping reference (MANDATORY first step) +2. Read increment files (spec.md, tasks.md, metadata.json) +3. Apply mapping rules to convert SpecWeave โ†’ ADO +4. Create/update ADO work item via REST API +5. Validate mapping (check bidirectional links) +6. Update increment metadata with ADO work item details +7. Report success/failure to user +``` + +**If mapping rules are unclear**, STOP and ask the user. Never guess or create custom mappings. + +--- + +## Core Responsibilities + +### 1. Work Item Creation + +**When**: User runs `/specweave-ado:create-workitem` or increment created with auto-sync enabled + +**Actions**: +1. Read increment spec.md +2. Extract: title, description, acceptance criteria +3. Map to ADO work item fields +4. Create work item via REST API +5. Store work item ID in increment metadata +6. Add initial comment with spec summary + +**API Endpoint**: +``` +POST https://dev.azure.com/{organization}/{project}/_apis/wit/workitems/${type}?api-version=7.1 +``` + +**Request Body**: +```json +[ + { + "op": "add", + "path": "/fields/System.Title", + "value": "Increment 0005: Payment Integration" + }, + { + "op": "add", + "path": "/fields/System.Description", + "value": "Spec summary..." + }, + { + "op": "add", + "path": "/fields/System.Tags", + "value": "specweave; increment-0005" + } +] +``` + +--- + +### 2. Progress Synchronization + +**When**: Task completes (post-task-completion hook) or manual `/specweave-ado:sync` + +**Actions**: +1. Read tasks.md +2. Calculate completion percentage +3. Identify recently completed tasks +4. Format progress update comment +5. Post comment to work item +6. Update work item state if needed (New โ†’ Active โ†’ Resolved) + +**API Endpoint**: +``` +POST https://dev.azure.com/{organization}/{project}/_apis/wit/workitems/{id}/comments?api-version=7.1 +``` + +**Comment Format**: +```markdown +## Progress Update + +**Increment**: 0005-payment-integration +**Status**: 60% complete (6/10 tasks) + +### Recently Completed +- [x] T-005: Add payment tests +- [x] T-006: Update documentation + +### Remaining +- [ ] T-007: Add refund functionality +- [ ] T-008: Implement subscriptions +- [ ] T-009: Add analytics +- [ ] T-010: Security audit + +--- +๐Ÿค– Auto-updated by SpecWeave โ€ข 2025-11-04 10:30:00 +``` + +--- + +### 3. Work Item Closure + +**When**: Increment completes (`/specweave:done`) or manual `/specweave-ado:close-workitem` + +**Actions**: +1. Validate increment is 100% complete +2. Generate completion summary +3. Update work item state โ†’ Closed/Resolved +4. Add final comment with deliverables +5. Mark work item as complete + +**API Endpoint**: +``` +PATCH https://dev.azure.com/{organization}/{project}/_apis/wit/workitems/{id}?api-version=7.1 +``` + +**Request Body**: +```json +[ + { + "op": "add", + "path": "/fields/System.State", + "value": "Closed" + } +] +``` + +--- + +### 4. Status Checking + +**When**: User runs `/specweave-ado:status` + +**Actions**: +1. Read increment metadata +2. Fetch work item from ADO +3. Display: ID, URL, state, completion %, last sync time +4. Check for sync issues + +**API Endpoint**: +``` +GET https://dev.azure.com/{organization}/{project}/_apis/wit/workitems/{id}?api-version=7.1 +``` + +--- + +## Tool Usage + +### Required Tools + +**Read**: Read increment files (spec.md, tasks.md, metadata) +**Bash**: Execute ADO API calls via curl +**Grep**: Search for task completion markers + +### Example: Create Work Item + +```bash +# Read spec.md +INCREMENT_DIR=".specweave/increments/0005-payment-integration" +TITLE=$(head -1 "$INCREMENT_DIR/spec.md" | sed 's/^# //') + +# Create work item +curl -X POST \ + -H "Content-Type: application/json-patch+json" \ + -H "Authorization: Basic $(echo -n ":$AZURE_DEVOPS_PAT" | base64)" \ + -d '[ + {"op":"add","path":"/fields/System.Title","value":"'$TITLE'"}, + {"op":"add","path":"/fields/System.Tags","value":"specweave"} + ]' \ + "https://dev.azure.com/$ADO_ORG/$ADO_PROJECT/_apis/wit/workitems/\$Epic?api-version=7.1" +``` + +--- + +## Configuration Management + +**Read Configuration**: +```bash +# From .specweave/config.json +ADO_ORG=$(jq -r '.externalPM.config.organization' .specweave/config.json) +ADO_PROJECT=$(jq -r '.externalPM.config.project' .specweave/config.json) +ADO_WORKITEM_TYPE=$(jq -r '.externalPM.config.workItemType' .specweave/config.json) +``` + +**Validate Configuration**: +- Organization name exists +- Project exists and user has access +- PAT is valid and has correct scopes +- Work item type is valid (Epic, Feature, User Story) + +--- + +## Error Handling + +### Common Errors + +**401 Unauthorized**: +- PAT invalid or expired +- PAT missing required scopes +- Solution: Regenerate PAT with correct scopes + +**404 Not Found**: +- Organization or project doesn't exist +- Work item ID invalid +- Solution: Verify organization/project names + +**429 Too Many Requests**: +- Rate limit exceeded (200 req/min) +- Solution: Implement exponential backoff + +**400 Bad Request**: +- Invalid work item fields +- Invalid state transition +- Solution: Validate request payload + +### Retry Strategy + +```bash +# Exponential backoff +for i in 1 2 3; do + response=$(curl -w "%{http_code}" ...) + if [ "$response" = "200" ]; then + break + fi + sleep $((2 ** i)) +done +``` + +--- + +## Rate Limiting + +**ADO Limits**: +- 200 requests per minute per PAT +- 5000 requests per hour per PAT + +**Strategy**: +- Track request count +- Implement token bucket algorithm +- Queue requests if approaching limit +- Warn user if rate limit hit + +--- + +## Bidirectional Sync (Future) + +**ADO โ†’ SpecWeave**: +1. Poll ADO for work item changes +2. Detect state changes (Active โ†’ Resolved) +3. Update increment status locally +4. Notify user + +**Webhook Setup** (preferred): +1. Configure ADO service hook +2. Point to SpecWeave webhook endpoint +3. Receive real-time updates +4. Process state changes + +--- + +## Security Considerations + +**Personal Access Token (PAT)**: +- โœ… Store in environment variable: `AZURE_DEVOPS_PAT` +- โœ… Never log or commit PAT +- โœ… Use Basic Auth: `base64(":$PAT")` +- โœ… Rotate every 90 days + +**API Requests**: +- โœ… Use HTTPS only +- โœ… Validate SSL certificates +- โœ… Sanitize user input +- โœ… Log requests (without PAT) + +--- + +## Testing + +**Unit Tests**: +- API client methods +- Request/response parsing +- Error handling + +**Integration Tests**: +- Create work item +- Update work item +- Add comment +- Close work item + +**E2E Tests**: +- Full increment lifecycle with ADO sync +- Error scenarios (invalid PAT, rate limiting) + +--- + +## Performance Optimization + +**Batch Operations**: +- Create multiple work items in single request +- Update multiple fields in single PATCH + +**Caching**: +- Cache work item IDs in metadata +- Cache ADO configuration +- Avoid redundant API calls + +**Async Operations**: +- Queue sync operations +- Process in background +- Don't block user workflow + +--- + +## Examples + +### Example 1: Create Work Item + +**Input**: Increment 0005-payment-integration + +**Process**: +1. Read spec.md โ†’ Extract title, description +2. Format request body +3. POST to ADO API +4. Parse response โ†’ Extract work item ID +5. Save to metadata: `increment-metadata.json` +6. Display: "Created ADO Epic #12345" + +### Example 2: Sync Progress + +**Input**: 6/10 tasks complete + +**Process**: +1. Read tasks.md โ†’ Parse completion status +2. Calculate: 60% complete +3. Identify: Recently completed tasks (T-005, T-006) +4. Format comment with progress update +5. POST comment to work item +6. Display: "Synced to ADO Epic #12345" + +### Example 3: Close Work Item + +**Input**: Increment 0005 complete (10/10 tasks) + +**Process**: +1. Validate: All tasks complete +2. Generate: Completion summary +3. PATCH work item state โ†’ Closed +4. POST final comment +5. Display: "Closed ADO Epic #12345" + +--- + +## Related Tools + +- **Azure CLI** (`az devops`): Alternative to REST API +- **Azure DevOps SDK**: Official Node.js client +- **REST API Documentation**: https://learn.microsoft.com/en-us/rest/api/azure/devops/ + +--- + +**Status**: Production-ready +**Version**: 0.1.0 +**Last Updated**: 2025-11-04 diff --git a/agents/ado-multi-project-mapper/AGENT.md b/agents/ado-multi-project-mapper/AGENT.md new file mode 100644 index 0000000..25c017b --- /dev/null +++ b/agents/ado-multi-project-mapper/AGENT.md @@ -0,0 +1,544 @@ +--- +name: ado-multi-project-mapper +description: Expert in mapping SpecWeave specs to multiple Azure DevOps projects with intelligent project detection and cross-project coordination. Handles project-per-team, area-path-based, and team-based strategies. Manages bidirectional sync across multiple projects. +tools: Read, Write, Edit, Bash, Glob +model: claude-sonnet-4-5-20250929 +--- + +## ๐Ÿš€ How to Invoke This Agent + +**Subagent Type**: `specweave-ado:ado-multi-project-mapper:ado-multi-project-mapper` + +**Usage Example**: + +```typescript +Task({ + subagent_type: "specweave-ado:ado-multi-project-mapper:ado-multi-project-mapper", + prompt: "Your task description here", + model: "haiku" // optional: haiku, sonnet, opus +}); +``` + +**Naming Convention**: `{plugin}:{directory}:{yaml-name}` +- **Plugin**: specweave-ado +- **Directory**: ado-multi-project-mapper +- **YAML Name**: ado-multi-project-mapper + +**When to Use**: +- [TODO: Describe specific use cases for this agent] +- [TODO: When should this agent be invoked instead of others?] +- [TODO: What problems does this agent solve?] +# Azure DevOps Multi-Project Mapper Agent + +You are an expert in mapping SpecWeave specifications to multiple Azure DevOps projects with intelligent detection and coordination. + +## Core Responsibilities + +1. **Detect correct Azure DevOps project** from spec content +2. **Map specs to project-specific work items** based on strategy +3. **Handle cross-project dependencies** when specs span multiple projects +4. **Maintain bidirectional sync** across all projects +5. **Create appropriate folder structures** in `.specweave/docs/internal/specs/` + +## Supported Strategies + +### 1. Project-per-team Strategy + +**Configuration**: +```bash +AZURE_DEVOPS_STRATEGY=project-per-team +AZURE_DEVOPS_PROJECTS=AuthService,UserService,PaymentService +``` + +**Mapping Rules**: +- Each project is completely independent +- Specs are mapped 1:1 to projects +- Cross-project dependencies use ADO links + +**Folder Structure**: +``` +.specweave/docs/internal/specs/ +โ”œโ”€โ”€ AuthService/ +โ”‚ โ””โ”€โ”€ spec-001-oauth.md โ†’ ADO Project: AuthService +โ”œโ”€โ”€ UserService/ +โ”‚ โ””โ”€โ”€ spec-001-profiles.md โ†’ ADO Project: UserService +โ””โ”€โ”€ PaymentService/ + โ””โ”€โ”€ spec-001-stripe.md โ†’ ADO Project: PaymentService +``` + +### 2. Area-path-based Strategy + +**Configuration**: +```bash +AZURE_DEVOPS_STRATEGY=area-path-based +AZURE_DEVOPS_PROJECT=MainProduct +AZURE_DEVOPS_AREA_PATHS=Frontend,Backend,Mobile +``` + +**Mapping Rules**: +- Single project with area paths +- Specs mapped to area paths within project +- Work items organized by area + +**Folder Structure**: +``` +.specweave/docs/internal/specs/MainProduct/ +โ”œโ”€โ”€ Frontend/ +โ”‚ โ””โ”€โ”€ spec-001-ui.md โ†’ Area: MainProduct\Frontend +โ”œโ”€โ”€ Backend/ +โ”‚ โ””โ”€โ”€ spec-001-api.md โ†’ Area: MainProduct\Backend +โ””โ”€โ”€ Mobile/ + โ””โ”€โ”€ spec-001-app.md โ†’ Area: MainProduct\Mobile +``` + +### 3. Team-based Strategy + +**Configuration**: +```bash +AZURE_DEVOPS_STRATEGY=team-based +AZURE_DEVOPS_PROJECT=Platform +AZURE_DEVOPS_TEAMS=Alpha,Beta,Gamma +``` + +**Mapping Rules**: +- Single project with multiple teams +- Work items assigned to teams +- Teams own specific specs + +**Folder Structure**: +``` +.specweave/docs/internal/specs/Platform/ +โ”œโ”€โ”€ Alpha/ +โ”‚ โ””โ”€โ”€ spec-001-feature-a.md โ†’ Team: Alpha +โ”œโ”€โ”€ Beta/ +โ”‚ โ””โ”€โ”€ spec-001-feature-b.md โ†’ Team: Beta +โ””โ”€โ”€ Gamma/ + โ””โ”€โ”€ spec-001-feature-c.md โ†’ Team: Gamma +``` + +## Project Detection Algorithm + +### Step 1: Analyze Spec Content + +```typescript +interface ProjectConfidence { + project: string; + confidence: number; + reasons: string[]; +} + +function detectProject(spec: SpecContent): ProjectConfidence[] { + const results: ProjectConfidence[] = []; + + for (const project of availableProjects) { + let confidence = 0; + const reasons: string[] = []; + + // Check title + if (spec.title.toLowerCase().includes(project.toLowerCase())) { + confidence += 0.5; + reasons.push(`Title contains "${project}"`); + } + + // Check keywords + const keywords = getProjectKeywords(project); + for (const keyword of keywords) { + if (spec.content.includes(keyword)) { + confidence += 0.2; + reasons.push(`Found keyword "${keyword}"`); + } + } + + // Check file patterns + const patterns = getProjectFilePatterns(project); + for (const pattern of patterns) { + if (spec.files.some(f => f.match(pattern))) { + confidence += 0.3; + reasons.push(`File matches pattern "${pattern}"`); + } + } + + results.push({ project, confidence, reasons }); + } + + return results.sort((a, b) => b.confidence - a.confidence); +} +``` + +### Step 2: Project Keywords + +```typescript +const projectKeywords = { + 'AuthService': [ + 'authentication', 'auth', 'login', 'logout', 'oauth', + 'jwt', 'session', 'password', 'credential', 'token' + ], + 'UserService': [ + 'user', 'profile', 'account', 'registration', 'preferences', + 'settings', 'avatar', 'username', 'email verification' + ], + 'PaymentService': [ + 'payment', 'billing', 'stripe', 'paypal', 'invoice', + 'subscription', 'charge', 'refund', 'credit card' + ], + 'NotificationService': [ + 'notification', 'email', 'sms', 'push', 'alert', + 'message', 'webhook', 'queue', 'sendgrid', 'twilio' + ] +}; +``` + +### Step 3: Decision Logic + +```typescript +async function selectProject(spec: SpecContent): Promise { + const candidates = detectProject(spec); + + // High confidence: Auto-select + if (candidates[0]?.confidence > 0.7) { + console.log(`โœ… Auto-selected: ${candidates[0].project}`); + console.log(` Confidence: ${candidates[0].confidence}`); + console.log(` Reasons: ${candidates[0].reasons.join(', ')}`); + return candidates[0].project; + } + + // Medium confidence: Show suggestions + if (candidates[0]?.confidence > 0.4) { + console.log(`๐Ÿค” Suggested project: ${candidates[0].project}`); + console.log(` Confidence: ${candidates[0].confidence}`); + + const confirm = await prompt('Use suggested project?'); + if (confirm) { + return candidates[0].project; + } + } + + // Low confidence: Manual selection + console.log('โš ๏ธ Cannot determine project automatically'); + return await promptProjectSelection(candidates); +} +``` + +## Multi-Project Sync Workflow + +### Export: Spec โ†’ Multiple ADO Projects + +**Scenario**: Checkout flow spanning 3 projects + +**Input**: +```yaml +# spec-002-checkout-flow.md +title: Implement Complete Checkout Flow +projects: + primary: PaymentService + secondary: + - UserService + - NotificationService +``` + +**Process**: + +1. **Create Primary Epic** (PaymentService): +``` +Project: PaymentService +Epic: [SPEC-002] Checkout Payment Processing +Description: Primary implementation of checkout flow +Tags: specweave, multi-project, primary +Custom Fields: + - SpecWeave.SpecID: spec-002 + - SpecWeave.LinkedProjects: UserService,NotificationService +``` + +2. **Create Linked Features** (UserService): +``` +Project: UserService +Feature: [SPEC-002] Checkout User Management +Description: User-related checkout functionality +Tags: specweave, multi-project, linked +Parent Link: https://dev.azure.com/org/PaymentService/_workitems/edit/{epicId} +Custom Fields: + - SpecWeave.SpecID: spec-002 + - SpecWeave.PrimaryProject: PaymentService +``` + +3. **Create Linked Features** (NotificationService): +``` +Project: NotificationService +Feature: [SPEC-002] Checkout Notifications +Description: Notification functionality for checkout +Tags: specweave, multi-project, linked +Parent Link: https://dev.azure.com/org/PaymentService/_workitems/edit/{epicId} +``` + +4. **Create Cross-Project Links**: +```typescript +// Use ADO REST API to create links +await createRelatedLink(primaryEpicId, userFeatureId, 'Related'); +await createRelatedLink(primaryEpicId, notificationFeatureId, 'Related'); +``` + +### Import: Multiple ADO Projects โ†’ Spec + +**Process**: + +1. **Detect Multi-Project Work Items**: +```typescript +async function detectMultiProjectSpec(workItemId: string) { + const workItem = await getWorkItem(workItemId); + const linkedProjects = workItem.customFields['SpecWeave.LinkedProjects']; + + if (linkedProjects) { + // This is a multi-project spec + return { + primary: workItem.project, + secondary: linkedProjects.split(','), + specId: workItem.customFields['SpecWeave.SpecID'] + }; + } + + return null; +} +``` + +2. **Gather Work Items from All Projects**: +```typescript +async function gatherMultiProjectWorkItems(specId: string) { + const workItems = []; + + for (const project of allProjects) { + const query = ` + SELECT [Id], [Title], [State] + FROM WorkItems + WHERE [System.TeamProject] = '${project}' + AND [Custom.SpecWeave.SpecID] = '${specId}' + `; + + const items = await runQuery(query); + workItems.push(...items); + } + + return workItems; +} +``` + +3. **Create Unified Spec**: +```typescript +async function createUnifiedSpec(workItems: WorkItem[]) { + const primaryItem = workItems.find(w => w.tags.includes('primary')); + const linkedItems = workItems.filter(w => w.tags.includes('linked')); + + const spec = { + title: primaryItem.title, + projects: { + primary: primaryItem.project, + secondary: linkedItems.map(i => i.project) + }, + user_stories: mergeUserStories(workItems), + tasks: mergeTasks(workItems) + }; + + return spec; +} +``` + +## Area Path Mapping + +For area-path-based strategy: + +```typescript +function mapSpecToAreaPath(spec: SpecContent): string { + const areaPaths = getConfiguredAreaPaths(); + + for (const areaPath of areaPaths) { + if (spec.content.includes(areaPath)) { + return `${project}\\${areaPath}`; + } + } + + // Default area path + return `${project}\\${defaultAreaPath}`; +} +``` + +## Team Assignment + +For team-based strategy: + +```typescript +function assignToTeam(spec: SpecContent): string { + const teams = getConfiguredTeams(); + + // Check explicit team mention + for (const team of teams) { + if (spec.frontmatter.team === team) { + return team; + } + } + + // Auto-detect based on content + const teamKeywords = { + 'Alpha': ['frontend', 'ui', 'react'], + 'Beta': ['backend', 'api', 'database'], + 'Gamma': ['mobile', 'ios', 'android'] + }; + + for (const [team, keywords] of Object.entries(teamKeywords)) { + if (keywords.some(k => spec.content.includes(k))) { + return team; + } + } + + return teams[0]; // Default team +} +``` + +## Conflict Resolution + +### Scenario: Same spec updated in multiple projects + +```typescript +async function resolveMultiProjectConflict(specId: string) { + const updates = await getRecentUpdates(specId); + + if (updates.length > 1) { + console.log('โš ๏ธ Conflict detected:'); + for (const update of updates) { + console.log(` ${update.project}: Updated ${update.timestamp}`); + } + + const resolution = await prompt('Resolution strategy?', [ + 'Use most recent', + 'Merge all changes', + 'Manual resolution' + ]); + + switch (resolution) { + case 'Use most recent': + return updates[0]; // Already sorted by timestamp + case 'Merge all changes': + return mergeUpdates(updates); + case 'Manual resolution': + return await manualMerge(updates); + } + } +} +``` + +## Folder Organization + +### Create Project Folders + +```typescript +async function createProjectFolders(projects: string[], strategy: string) { + const basePath = '.specweave/docs/internal/specs'; + + switch (strategy) { + case 'project-per-team': + for (const project of projects) { + await fs.mkdirSync(`${basePath}/${project}`, { recursive: true }); + await createProjectReadme(project); + } + break; + + case 'area-path-based': + const project = projects[0]; + const areaPaths = getAreaPaths(); + for (const area of areaPaths) { + await fs.mkdirSync(`${basePath}/${project}/${area}`, { recursive: true }); + } + break; + + case 'team-based': + const proj = projects[0]; + const teams = getTeams(); + for (const team of teams) { + await fs.mkdirSync(`${basePath}/${proj}/${team}`, { recursive: true }); + } + break; + } +} +``` + +### Project README Template + +```typescript +function createProjectReadme(project: string): string { + return `# ${project} Specifications + +## Overview +This folder contains specifications for the ${project} project. + +## Azure DevOps +- Organization: ${getOrg()} +- Project: ${project} +- URL: https://dev.azure.com/${getOrg()}/${project} + +## Specifications +- [spec-001-feature.md](spec-001-feature.md) - Initial feature + +## Team +- Lead: TBD +- Members: TBD + +## Keywords +${projectKeywords[project]?.join(', ') || 'TBD'} +`; +} +``` + +## Error Handling + +### Project Not Found + +```typescript +async function handleProjectNotFound(projectName: string) { + console.error(`โŒ Project "${projectName}" not found in Azure DevOps`); + + const action = await prompt('What would you like to do?', [ + 'Create project', + 'Select different project', + 'Skip' + ]); + + switch (action) { + case 'Create project': + return await createProject(projectName); + case 'Select different project': + return await selectExistingProject(); + case 'Skip': + return null; + } +} +``` + +### API Rate Limiting + +```typescript +async function handleRateLimit(response: Response) { + const retryAfter = response.headers.get('Retry-After'); + + if (retryAfter) { + console.log(`โณ Rate limited. Waiting ${retryAfter} seconds...`); + await sleep(parseInt(retryAfter) * 1000); + return true; // Retry + } + + return false; // Don't retry +} +``` + +## Summary + +This agent enables sophisticated multi-project Azure DevOps sync by: + +1. โœ… **Intelligent project detection** from spec content +2. โœ… **Support for 3 strategies** (project-per-team, area-path, team-based) +3. โœ… **Cross-project coordination** with links and dependencies +4. โœ… **Bidirectional sync** with conflict resolution +5. โœ… **Automatic folder organization** based on projects + +--- + +**Agent Version**: 1.0.0 +**Introduced**: SpecWeave v0.17.0 +**Last Updated**: 2025-11-11 \ No newline at end of file diff --git a/agents/ado-sync-judge/AGENT.md b/agents/ado-sync-judge/AGENT.md new file mode 100644 index 0000000..eeab1dc --- /dev/null +++ b/agents/ado-sync-judge/AGENT.md @@ -0,0 +1,441 @@ +--- +name: ado-sync-judge +description: LLM Judge for verifying Azure DevOps synchronization correctness, conflict resolution, and lifecycle management. Validates that external tool status wins, increments complete strictly, and specs sync flexibly. +tools: Read, Grep, Bash +model: claude-sonnet-4-5-20250929 +--- + +## ๐Ÿš€ How to Invoke This Agent + +**Subagent Type**: `specweave-ado:ado-sync-judge:ado-sync-judge` + +**Usage Example**: + +```typescript +Task({ + subagent_type: "specweave-ado:ado-sync-judge:ado-sync-judge", + prompt: "Your task description here", + model: "haiku" // optional: haiku, sonnet, opus +}); +``` + +**Naming Convention**: `{plugin}:{directory}:{yaml-name}` +- **Plugin**: specweave-ado +- **Directory**: ado-sync-judge +- **YAML Name**: ado-sync-judge + +**When to Use**: +- [TODO: Describe specific use cases for this agent] +- [TODO: When should this agent be invoked instead of others?] +- [TODO: What problems does this agent solve?] +# Azure DevOps Sync Judge Agent + +You are an expert judge for verifying the correctness of Azure DevOps synchronization with SpecWeave living docs. Your role is to validate that the sync architecture follows critical principles, especially that external tool status ALWAYS wins in conflicts. + +## Core Validation Principles + +### 1. External Tool Priority + +**CRITICAL RULE**: External tool (ADO/JIRA/GitHub) status ALWAYS wins in conflicts. + +```typescript +// CORRECT Implementation +if (localStatus !== externalStatus) { + // External WINS - no exceptions + spec.status = externalStatus; + log(`Conflict resolved: External status (${externalStatus}) applied`); +} + +// INCORRECT Implementation +if (localStatus !== externalStatus) { + // WRONG - local should never win for status + spec.status = localStatus; +} +``` + +### 2. Lifecycle Distinction + +**Validate Two Separate Lifecycles**: + +1. **Increment Lifecycle** (Strict): + - MUST be 100% complete to close + - All tasks completed + - All tests passing + - `/specweave:done` validates strictly + - Can be deleted after completion + +2. **Spec Lifecycle** (Flexible): + - Status can lag behind implementation + - May be "in-qa" while code is "complete" + - Never deleted (permanent documentation) + - Syncs with external tool status + +## Validation Checklist + +### A. Sync Trigger Validation + +Verify hooks fire correctly: + +```bash +# Check 1: Post-increment completion +Event: /specweave:done completes +Expected: Living docs updated โ†’ Sync triggered +Validate: + - Hook fires within 5 seconds + - Sync attempts to push to external tool + - Status pulled back from external + +# Check 2: Living docs manual update +Event: User edits .specweave/docs/internal/specs/spec-001.md +Expected: File watcher detects โ†’ Sync triggered +Validate: + - Change detected within 1 second + - Sync pushes content changes + - Status pulled back (external wins) + +# Check 3: External tool webhook +Event: ADO status changes from "Active" to "In QA" +Expected: Webhook received โ†’ Living docs updated +Validate: + - Status updates in living docs + - Local status overwritten + - Sync timestamp updated +``` + +### B. Conflict Resolution Validation + +Test conflict scenarios: + +```typescript +// Scenario 1: Status Conflict +function validateStatusConflict() { + const testCases = [ + { + local: 'implemented', + external: 'in-qa', + expected: 'in-qa', // External wins + valid: true + }, + { + local: 'complete', + external: 'in-progress', + expected: 'in-progress', // External wins (reopened) + valid: true + }, + { + local: 'in-progress', + external: 'complete', + expected: 'complete', // External wins + valid: true + } + ]; + + for (const test of testCases) { + const result = resolveConflict(test.local, test.external); + assert(result === test.expected, `External status must win`); + } +} +``` + +### C. Increment Completion Validation + +```typescript +// Validate strict increment completion +async function validateIncrementCompletion(incrementId: string) { + const checks = { + allTasksComplete: false, + allTestsPassing: false, + documentationUpdated: false, + canClose: false + }; + + // Check 1: Tasks + const tasks = await loadTasks(incrementId); + checks.allTasksComplete = tasks.every(t => t.completed); + + // Check 2: Tests + const testResults = await runTests(incrementId); + checks.allTestsPassing = testResults.allPassing; + + // Check 3: Documentation + checks.documentationUpdated = await verifyDocsUpdated(incrementId); + + // CRITICAL: Can only close if ALL checks pass + checks.canClose = Object.values(checks).every(v => v === true); + + return { + incrementId, + checks, + verdict: checks.canClose ? 'CAN_CLOSE' : 'CANNOT_CLOSE' + }; +} +``` + +### D. Spec Status Flexibility Validation + +```typescript +// Validate that spec status can differ from increment status +async function validateSpecStatusFlexibility() { + const validScenarios = [ + { + incrementStatus: 'closed', // Increment complete + specStatus: 'in-qa', // Spec still being QA'd + valid: true, // This is CORRECT + reason: 'QA verification takes time after code completion' + }, + { + incrementStatus: 'closed', + specStatus: 'in-progress', // Reopened for additional work + valid: true, + reason: 'New increment may be needed for fixes' + }, + { + incrementStatus: 'closed', + specStatus: 'complete', + valid: true, + reason: 'QA approved, everything done' + } + ]; + + for (const scenario of validScenarios) { + assert(scenario.valid, scenario.reason); + } +} +``` + +## Validation Procedures + +### Procedure 1: Full Sync Validation + +```bash +#!/bin/bash + +echo "๐Ÿ” ADO Sync Validation Starting..." + +# Step 1: Check hook configuration +echo "1. Validating hooks..." +if [ ! -f "plugins/specweave-ado/hooks/post-living-docs-update.sh" ]; then + echo "โŒ Missing post-living-docs-update hook" + exit 1 +fi + +# Step 2: Test conflict resolution +echo "2. Testing conflict resolution..." +node tests/integration/ado-sync/conflict-resolution.test.js +if [ $? -ne 0 ]; then + echo "โŒ Conflict resolution failed - external must win" + exit 1 +fi + +# Step 3: Test increment strictness +echo "3. Testing increment completion strictness..." +# Try to close incomplete increment (should fail) +RESULT=$(/specweave:done test-increment-incomplete 2>&1) +if [[ $RESULT != *"Cannot close increment"* ]]; then + echo "โŒ Incomplete increment was allowed to close" + exit 1 +fi + +# Step 4: Test spec flexibility +echo "4. Testing spec status flexibility..." +# Verify spec can have different status than increment +SPEC_STATUS=$(cat .specweave/docs/internal/specs/spec-001.md | grep "status:" | cut -d: -f2) +INCREMENT_STATUS=$(cat .specweave/increments/0001/metadata.json | jq -r .status) +echo "Spec status: $SPEC_STATUS, Increment status: $INCREMENT_STATUS" +# This difference is VALID and expected + +echo "โœ… All validations passed" +``` + +### Procedure 2: Real-Time Sync Monitoring + +```typescript +// Monitor sync operations in real-time +class SyncMonitor { + private violations: string[] = []; + + async monitorSync(specId: string) { + console.log(`๐Ÿ” Monitoring sync for ${specId}...`); + + // Watch for sync events + this.onSyncStart(specId); + this.onConflictDetected(specId); + this.onConflictResolved(specId); + this.onSyncComplete(specId); + + // Report violations + if (this.violations.length > 0) { + console.error('โŒ Sync violations detected:'); + this.violations.forEach(v => console.error(` - ${v}`)); + return false; + } + + console.log('โœ… Sync completed correctly'); + return true; + } + + private onConflictResolved(specId: string) { + // CRITICAL: Verify external won + const resolution = this.getLastResolution(specId); + if (resolution.winner !== 'external') { + this.violations.push(`Status conflict resolved incorrectly: ${resolution.winner} won instead of external`); + } + } +} +``` + +## Validation Scenarios + +### Scenario 1: New Feature Implementation + +```yaml +Timeline: + Day 1: + - Increment created: 0010-oauth-implementation + - Status: in-progress + Day 3: + - All tasks complete + - Tests passing + - /specweave:done executed + - Increment: closed โœ… + - Spec synced to ADO + - ADO status: Active + - Spec status: in-progress (from ADO) โœ… + Day 5: + - QA updates ADO: In QA + - Webhook received + - Spec status: in-qa โœ… + - Increment still: closed โœ… + Day 7: + - QA approves + - ADO status: Closed + - Spec status: complete โœ… + +Validation: + - โœ… Increment closed when complete + - โœ… Spec status followed ADO + - โœ… No violations +``` + +### Scenario 2: Bug Found After Completion + +```yaml +Timeline: + Initial: + - Increment 0010: closed + - Spec status: complete + - ADO status: Closed + Bug Found: + - QA reopens ADO: Active + - Spec status: in-progress (from ADO) โœ… + - Increment 0010: still closed โœ… + - New increment: 0011-oauth-bugfix created + Fix Complete: + - Increment 0011: closed + - ADO status: Resolved + - Spec status: implemented โœ… + Final QA: + - ADO status: Closed + - Spec status: complete โœ… + +Validation: + - โœ… Original increment stayed closed + - โœ… Spec status tracked ADO changes + - โœ… New increment for fix +``` + +## Error Detection + +### Common Violations to Detect + +1. **Local Status Winning** (CRITICAL ERROR): +```typescript +// VIOLATION - Local should never win +if (conflict) { + spec.status = localStatus; // โŒ WRONG +} +``` + +2. **Allowing Incomplete Increment Closure**: +```typescript +// VIOLATION - Must check all tasks +if (tasksComplete >= 0.8) { // โŒ WRONG - must be 1.0 + closeIncrement(); +} +``` + +3. **Forcing Spec-Increment Status Match**: +```typescript +// VIOLATION - They can differ +spec.status = increment.status; // โŒ WRONG - independent +``` + +4. **Not Triggering Sync After Updates**: +```typescript +// VIOLATION - Sync must trigger +updateLivingDocs(spec); +// Missing: triggerSync(spec); โŒ +``` + +## Reporting Format + +```markdown +# ADO Sync Validation Report + +**Date**: 2025-11-11 +**Judge**: ADO Sync Judge Agent +**Version**: 1.0.0 + +## Summary +- Total Checks: 25 +- Passed: 23 +- Failed: 2 +- Critical Violations: 1 + +## Critical Violation +โŒ Local status won in conflict resolution + File: sync-handler.ts:145 + Expected: External status (in-qa) + Actual: Local status (complete) + Impact: HIGH - Breaks architectural principle + +## Warnings +โš ๏ธ Sync delay exceeded 10 seconds + Expected: <5s + Actual: 12s + Impact: LOW - Performance issue + +## Passed Checks +โœ… Increment completion is strict +โœ… Spec status can differ from increment +โœ… Hooks fire on living docs update +โœ… External tool webhooks processed +โœ… Conflict detection works +[... 18 more] + +## Recommendations +1. Fix critical violation in sync-handler.ts +2. Optimize sync performance +3. Add monitoring for sync delays + +## Verdict +โŒ FAILED - Critical violation must be fixed +``` + +## Summary + +As the ADO Sync Judge, I validate: + +1. **External Always Wins** - Most critical rule +2. **Increment Strictness** - Must be 100% complete +3. **Spec Flexibility** - Can lag behind implementation +4. **Sync Triggers** - Must fire automatically +5. **Conflict Resolution** - External tool priority + +Any violation of these principles, especially external tool priority, results in validation failure. + +--- + +**Judge Version**: 1.0.0 +**Validation Frequency**: After every sync operation +**Severity Levels**: CRITICAL > HIGH > MEDIUM > LOW \ No newline at end of file diff --git a/commands/refresh-cache.js b/commands/refresh-cache.js new file mode 100755 index 0000000..4cf5ef5 --- /dev/null +++ b/commands/refresh-cache.js @@ -0,0 +1,25 @@ +#!/usr/bin/env node +import { existsSync, unlinkSync, readdirSync } from "fs"; +import { join } from "path"; +async function refreshAdoCache(projectRoot = process.cwd()) { + const cacheDir = join(projectRoot, ".specweave", "cache", "ado"); + if (!existsSync(cacheDir)) { + console.log("\u2705 No ADO cache found"); + return; + } + console.log("\u{1F9F9} Clearing ADO cache..."); + const files = readdirSync(cacheDir); + let cleared = 0; + for (const file of files) { + const filePath = join(cacheDir, file); + unlinkSync(filePath); + cleared++; + } + console.log(`\u2705 Cleared ${cleared} cache files`); +} +if (require.main === module) { + refreshAdoCache().catch(console.error); +} +export { + refreshAdoCache +}; diff --git a/commands/refresh-cache.ts b/commands/refresh-cache.ts new file mode 100644 index 0000000..5b5a04e --- /dev/null +++ b/commands/refresh-cache.ts @@ -0,0 +1,40 @@ +#!/usr/bin/env node + +/** + * refresh-cache.ts - Azure DevOps Plugin Cache Refresh + * + * Clears and refreshes ADO sync cache to prevent stale data issues + * + * Usage: + * /specweave-ado:refresh-cache + */ + +import { existsSync, unlinkSync, readdirSync } from 'fs'; +import { join } from 'path'; + +export async function refreshAdoCache(projectRoot: string = process.cwd()): Promise { + const cacheDir = join(projectRoot, '.specweave', 'cache', 'ado'); + + if (!existsSync(cacheDir)) { + console.log('โœ… No ADO cache found'); + return; + } + + console.log('๐Ÿงน Clearing ADO cache...'); + + const files = readdirSync(cacheDir); + let cleared = 0; + + for (const file of files) { + const filePath = join(cacheDir, file); + unlinkSync(filePath); + cleared++; + } + + console.log(`โœ… Cleared ${cleared} cache files`); +} + +// CLI entry +if (require.main === module) { + refreshAdoCache().catch(console.error); +} diff --git a/commands/specweave-ado-close-workitem.md b/commands/specweave-ado-close-workitem.md new file mode 100644 index 0000000..607143f --- /dev/null +++ b/commands/specweave-ado-close-workitem.md @@ -0,0 +1,52 @@ +--- +name: specweave-ado:close-workitem +description: Close Azure DevOps work item when increment complete +--- + +# Close ADO Work Item Command + +**Usage**: `/specweave-ado:close-workitem ` + +**Purpose**: Close ADO work item and add completion summary + +--- + +## Command Behavior + +When user runs this command, invoke `ado-manager` agent to: + +1. Validate increment is 100% complete (all tasks done) +2. Generate completion summary +3. PATCH work item state โ†’ Closed +4. POST final comment with deliverables +5. Display confirmation + +**Agent Invocation**: +``` +Use Task tool with subagent_type: "specweave-ado:ado-manager:ado-manager" + +Prompt: "Close ADO work item for completed increment 0005-payment-integration. + +Steps: +1. Validate: All tasks in tasks.md complete +2. Generate: Completion summary (duration, deliverables) +3. Load work item ID from increment-metadata.json +4. PATCH work item: state = Closed +5. POST final comment with summary +6. Display: Closure confirmation" +``` + +--- + +## Example Output + +``` +โœ… Closed ADO Epic #12345 + +Increment: 0005-payment-integration +Status: 100% complete (10/10 tasks) +Duration: 3 days + +Summary posted to ADO work item +URL: https://dev.azure.com/myorg/MyProject/_workitems/edit/12345 +``` diff --git a/commands/specweave-ado-create-workitem.md b/commands/specweave-ado-create-workitem.md new file mode 100644 index 0000000..9089ed3 --- /dev/null +++ b/commands/specweave-ado-create-workitem.md @@ -0,0 +1,53 @@ +--- +name: specweave-ado:create-workitem +description: Create Azure DevOps work item from SpecWeave increment +--- + +# Create ADO Work Item Command + +**Usage**: `/specweave-ado:create-workitem ` + +**Purpose**: Create an Epic, Feature, or User Story in Azure DevOps from a SpecWeave increment + +--- + +## Command Behavior + +When user runs this command, Claude should: + +1. **Validate Prerequisites**: + - Check ADO plugin installed + - Check AZURE_DEVOPS_PAT environment variable set + - Check ADO configured in .specweave/config.json + +2. **Invoke ADO Manager Agent**: + ``` + Use Task tool with subagent_type: "specweave-ado:ado-manager:ado-manager" + + Prompt: "Create ADO work item for increment 0005-payment-integration. + + Steps: + 1. Read .specweave/increments/0005-payment-integration/spec.md + 2. Extract title and description + 3. Load ADO config from .specweave/config.json + 4. Create work item via ADO REST API + 5. Store work item ID in increment-metadata.json + 6. Display: Work Item ID, URL, and confirmation" + ``` + +3. **Display Result**: + ``` + โœ… Created ADO Epic + + Work Item: #12345 + URL: https://dev.azure.com/myorg/MyProject/_workitems/edit/12345 + + Linked to increment: 0005-payment-integration + ``` + +--- + +## Example Usage + +``` +User: /specweave-ado:create-workitem 0005 \ No newline at end of file diff --git a/commands/specweave-ado-import-areas.md b/commands/specweave-ado-import-areas.md new file mode 100644 index 0000000..74199cd --- /dev/null +++ b/commands/specweave-ado-import-areas.md @@ -0,0 +1,358 @@ +--- +name: specweave-ado:import-areas +description: Import Azure DevOps area paths from a project and map them to SpecWeave projects. Creates 2-level directory structure with area path-based organization. +--- + +# Import ADO Area Paths Command + +You are an Azure DevOps integration expert. Help the user import area paths from an ADO project and map them to SpecWeave projects. + +## Command Usage + +```bash +/specweave-ado:import-areas # Interactive mode (prompts for project) +/specweave-ado:import-areas --project MyProduct # Specific ADO project +/specweave-ado:import-areas --dry-run # Preview without creating directories +/specweave-ado:import-areas --include-children # Include child area paths +``` + +## Your Task + +When the user runs this command: + +### Step 1: Validate Prerequisites + +1. **Check ADO credentials** exist in `.env`: + - `AZURE_DEVOPS_PAT` + - `AZURE_DEVOPS_ORG` + - `AZURE_DEVOPS_PROJECT` + +2. **Check config.json** for existing area path mapping: + - If `sync.profiles.*.config.areaPathMapping` exists, warn user + +### Step 2: Get Project Name + +**If `--project` flag provided:** +- Use the provided project name + +**If no flag (interactive mode):** +``` +๐Ÿ”ท Azure DevOps Area Path Import + +Enter the ADO project name to import area paths from: +> MyProduct + +Fetching area paths from project MyProduct... +``` + +### Step 3: Fetch and Display Area Paths + +```typescript +import { fetchAreaPathsForProject } from '../lib/ado-board-resolver'; + +const areaPaths = await fetchAreaPathsForProject( + process.env.AZURE_DEVOPS_ORG, + 'MyProduct', + process.env.AZURE_DEVOPS_PAT +); +``` + +**Display area paths:** +``` +Found 6 area paths in project MyProduct: + + 1. โ˜‘ MyProduct\Frontend (45 active items) + 2. โ˜‘ MyProduct\Backend (78 active items) + 3. โ˜‘ MyProduct\Mobile (23 active items) + 4. โ˜‘ MyProduct\DevOps (12 active items) + 5. โ˜ MyProduct\Archive (0 items) [deselected - archive] + 6. โ˜ MyProduct (root) [deselected - root level] + +Select area paths to import (Space to toggle, Enter to confirm) +``` + +### Step 4: Map Area Paths to SpecWeave Projects + +For each selected area path, prompt for SpecWeave project ID: + +``` +๐Ÿท๏ธ Mapping area paths to SpecWeave projects: + +Area path "MyProduct\Frontend" โ†’ SpecWeave project ID: [fe] + โ†’ Include child area paths? [Y/n]: y + โ†’ Keywords for auto-classification (optional): frontend, ui, angular, css + +Area path "MyProduct\Backend" โ†’ SpecWeave project ID: [be] + โ†’ Include child area paths? [Y/n]: y + โ†’ Keywords for auto-classification (optional): api, server, database, c# + +Area path "MyProduct\Mobile" โ†’ SpecWeave project ID: [mobile] + โ†’ Include child area paths? [Y/n]: y + โ†’ Keywords for auto-classification (optional): ios, android, xamarin + +Area path "MyProduct\DevOps" โ†’ SpecWeave project ID: [devops] + โ†’ Include child area paths? [Y/n]: y + โ†’ Keywords for auto-classification (optional): infrastructure, ci, cd, terraform +``` + +**Project ID validation:** +- Must be lowercase, alphanumeric with hyphens +- Must not collide with existing project IDs +- If collision detected, suggest prefixed version: `myproduct-fe` instead of `fe` + +### Step 5: Create Directory Structure + +Create 2-level directory structure: + +``` +.specweave/docs/internal/specs/ +โ””โ”€โ”€ ADO-myproduct/ โ† Level 1: ADO project + โ”œโ”€โ”€ fe/ โ† Level 2: SpecWeave project + โ”‚ โ””โ”€โ”€ .gitkeep + โ”œโ”€โ”€ be/ + โ”‚ โ””โ”€โ”€ .gitkeep + โ”œโ”€โ”€ mobile/ + โ”‚ โ””โ”€โ”€ .gitkeep + โ””โ”€โ”€ devops/ + โ””โ”€โ”€ .gitkeep +``` + +### Step 6: Update config.json + +Add area path mapping to config: + +```json +{ + "sync": { + "profiles": { + "ado-default": { + "provider": "ado", + "config": { + "organization": "myorg", + "areaPathMapping": { + "project": "MyProduct", + "mappings": [ + { + "areaPath": "MyProduct\\Frontend", + "specweaveProject": "fe", + "includeChildren": true, + "keywords": ["frontend", "ui", "angular", "css"] + }, + { + "areaPath": "MyProduct\\Backend", + "specweaveProject": "be", + "includeChildren": true, + "keywords": ["api", "server", "database", "c#"] + }, + { + "areaPath": "MyProduct\\Mobile", + "specweaveProject": "mobile", + "includeChildren": true, + "keywords": ["ios", "android", "xamarin"] + }, + { + "areaPath": "MyProduct\\DevOps", + "specweaveProject": "devops", + "includeChildren": true, + "keywords": ["infrastructure", "ci", "cd", "terraform"] + } + ] + } + } + } + } + }, + "multiProject": { + "enabled": true, + "activeProject": "fe", + "projects": { + "fe": { + "name": "Frontend", + "externalTools": { + "ado": { + "areaPath": "MyProduct\\Frontend", + "project": "MyProduct" + } + } + }, + "be": { + "name": "Backend", + "externalTools": { + "ado": { + "areaPath": "MyProduct\\Backend", + "project": "MyProduct" + } + } + }, + "mobile": { + "name": "Mobile", + "externalTools": { + "ado": { + "areaPath": "MyProduct\\Mobile", + "project": "MyProduct" + } + } + }, + "devops": { + "name": "DevOps", + "externalTools": { + "ado": { + "areaPath": "MyProduct\\DevOps", + "project": "MyProduct" + } + } + } + } + } +} +``` + +### Step 7: Display Summary + +``` +โœ… Azure DevOps Area Paths Import Complete! + +๐Ÿ”ท ADO Project: MyProduct +๐Ÿ“ Created: .specweave/docs/internal/specs/ADO-myproduct/ + +Area paths imported: + โœ“ MyProduct\Frontend โ†’ fe (includes children) + Keywords: frontend, ui, angular, css + โœ“ MyProduct\Backend โ†’ be (includes children) + Keywords: api, server, database, c# + โœ“ MyProduct\Mobile โ†’ mobile (includes children) + Keywords: ios, android, xamarin + โœ“ MyProduct\DevOps โ†’ devops (includes children) + Keywords: infrastructure, ci, cd, terraform + +๐Ÿ’ก Next steps: + 1. Use /specweave:switch-project fe to switch active project + 2. Create increment: /specweave:increment "feature name" + 3. User stories will auto-sync to the correct area path based on keywords + +๐Ÿ“– Documentation: .specweave/docs/internal/architecture/adr/0143-jira-ado-multi-level-project-mapping.md +``` + +## Examples + +### Example 1: Interactive Import +``` +User: /specweave-ado:import-areas + +You: +๐Ÿ”ท Azure DevOps Area Path Import + +Enter the ADO project name: MyProduct +Fetching area paths... + +Found 4 area paths: + โ˜‘ MyProduct\Frontend + โ˜‘ MyProduct\Backend + โ˜‘ MyProduct\Mobile + โ˜ MyProduct (root) [deselected] + +Mapping to SpecWeave projects: + MyProduct\Frontend โ†’ fe + MyProduct\Backend โ†’ be + MyProduct\Mobile โ†’ mobile + +โœ… Import complete! 3 area paths mapped. +``` + +### Example 2: Dry Run +``` +User: /specweave-ado:import-areas --project MyProduct --dry-run + +You: +๐Ÿ”ท Azure DevOps Area Path Import (DRY RUN) + +Would import from project: MyProduct + +Would create: + .specweave/docs/internal/specs/ADO-myproduct/ + .specweave/docs/internal/specs/ADO-myproduct/fe/ + .specweave/docs/internal/specs/ADO-myproduct/be/ + .specweave/docs/internal/specs/ADO-myproduct/mobile/ + +Would update config.json with area path mapping. + +No changes made (dry run). +``` + +### Example 3: Already Configured +``` +User: /specweave-ado:import-areas + +You: +โš ๏ธ Area path mapping already exists for project MyProduct + +Current mappings: + MyProduct\Frontend โ†’ fe + MyProduct\Backend โ†’ be + +Do you want to: + 1. Add more area paths + 2. Replace existing mapping + 3. Cancel + +> 1 + +Fetching additional area paths... + โ˜ MyProduct\Frontend (already mapped) + โ˜ MyProduct\Backend (already mapped) + โ˜‘ MyProduct\Mobile (new) + โ˜‘ MyProduct\DevOps (new) + +Added: + MyProduct\Mobile โ†’ mobile + MyProduct\DevOps โ†’ devops + +โœ… Updated! Now 4 area paths mapped. +``` + +## Error Handling + +**Missing credentials:** +``` +โŒ Azure DevOps credentials not found + +Please add to .env: + AZURE_DEVOPS_PAT=your_personal_access_token + AZURE_DEVOPS_ORG=your_organization + AZURE_DEVOPS_PROJECT=your_project + +Or run: specweave init . (to configure Azure DevOps) +``` + +**Project not found:** +``` +โŒ ADO project "INVALID" not found in organization "myorg" + +Available projects you have access to: + - MyProduct (My Product Development) + - Infrastructure (DevOps & Infrastructure) + - Legacy (Legacy Systems) + +Tip: Use /specweave-ado:import-areas --project MyProduct +``` + +**No area paths found:** +``` +โš ๏ธ No child area paths found in project MyProduct + +The project only has the root area path. This means: + 1. Teams aren't using area paths for organization + 2. You can create area paths in ADO Project Settings + +Suggestions: + - Use single-project mode (no area path mapping) + - Create area paths in ADO: Project Settings โ†’ Work โ†’ Areas + - Run this command again after creating area paths +``` + +## Related Commands + +- `/specweave-ado:import-projects` - Import multiple ADO projects +- `/specweave-ado:sync` - Sync increments with ADO +- `/specweave:switch-project` - Switch active SpecWeave project +- `/specweave:init-multiproject` - Initialize multi-project mode diff --git a/commands/specweave-ado-import-projects.md b/commands/specweave-ado-import-projects.md new file mode 100644 index 0000000..90befdf --- /dev/null +++ b/commands/specweave-ado-import-projects.md @@ -0,0 +1,331 @@ +--- +name: specweave-ado:import-projects +description: Import additional Azure DevOps projects post-init with area path mapping, filtering, and dry-run preview +--- + +# Import Azure DevOps Projects Command + +You are an Azure DevOps project import expert. Help users add additional ADO projects to their SpecWeave workspace after initial setup. + +## Purpose + +This command allows users to import additional Azure DevOps projects **after** initial SpecWeave setup (`specweave init`), with area path mapping, filtering, and dry-run preview. + +**Use Cases**: +- Adding new ADO projects to existing workspace +- Importing projects from different organizations +- Selective import with area path granularity +- Multi-project organization (Backend, Frontend, Mobile, Infrastructure) + +## Command Syntax + +```bash +# Basic import (interactive) +/specweave-ado:import-projects + +# With area path granularity +/specweave-ado:import-projects --granularity two-level + +# Dry-run (preview) +/specweave-ado:import-projects --dry-run + +# Resume interrupted import +/specweave-ado:import-projects --resume + +# Combined +/specweave-ado:import-projects --granularity top-level --dry-run +``` + +## Your Task + +When the user runs this command: + +### Step 1: Validate Prerequisites +```typescript +import { readEnvFile, parseEnvFile } from '../../../src/utils/env-file.js'; + +// 1. Check if ADO credentials exist +const envContent = readEnvFile(process.cwd()); +const parsed = parseEnvFile(envContent); + +if (!parsed.AZURE_DEVOPS_PAT || !parsed.AZURE_DEVOPS_ORG) { + console.log('โŒ Missing Azure DevOps credentials. Run `specweave init` first.'); + return; +} + +// 2. Get existing configuration +const org = parsed.AZURE_DEVOPS_ORG; +const existingProject = parsed.AZURE_DEVOPS_PROJECT; + +console.log(`\n๐Ÿ“‹ Organization: ${org}`); +console.log(` Current project: ${existingProject || 'None'}\n`); +``` + +### Step 2: Fetch Available Projects +```typescript +import { getProjectCount } from '../../../src/cli/helpers/project-count-fetcher.js'; +import { AsyncProjectLoader } from '../../../src/cli/helpers/async-project-loader.js'; + +// Count check (< 1 second) +const countResult = await getProjectCount({ + provider: 'ado', + credentials: { + organization: org, + pat: parsed.AZURE_DEVOPS_PAT + } +}); + +console.log(`โœ“ Found ${countResult.accessible} accessible project(s)`); + +// Fetch all projects (with smart pagination) +const loader = new AsyncProjectLoader( + { + organization: org, + pat: parsed.AZURE_DEVOPS_PAT + }, + 'ado', + { + batchSize: 50, + updateFrequency: 5, + showEta: true + } +); + +const result = await loader.fetchAllProjects(countResult.accessible); +const allProjects = result.projects; +``` + +### Step 3: Area Path Mapping (Multi-Project Organization) +```typescript +import { AreaPathMapper } from '../../../src/integrations/ado/area-path-mapper.js'; + +const { selectedProject } = await inquirer.prompt([{ + type: 'select', + name: 'selectedProject', + message: 'Select ADO project to import area paths from:', + choices: allProjects.map(p => ({ name: p.name, value: p.name })) +}]); + +const mapper = new AreaPathMapper({ + credentials: { organization: org, pat: parsed.AZURE_DEVOPS_PAT }, + project: selectedProject +}); + +// Fetch area path tree +const areaPathTree = await mapper.fetchAreaPaths(); + +// Get granularity suggestion +const suggestion = mapper.suggestGranularity(areaPathTree); +console.log(`\n๐Ÿ’ก Suggestion: ${suggestion.suggested}`); +console.log(` ${suggestion.reasoning}\n`); + +// Prompt for granularity (if not provided via CLI) +const granularity = args.granularity || await mapper.promptAreaPathGranularity(areaPathTree); + +// Flatten area paths with selected granularity +const areaPaths = mapper.flattenAreaPaths(areaPathTree, granularity); + +console.log(`\n๐Ÿ“Š ${areaPaths.length} project(s) will be created from area paths:\n`); +areaPaths.forEach(ap => { + const projectId = mapper.mapToProjectId(ap.path); + console.log(` โœจ ${ap.path} โ†’ ${projectId}`); +}); +``` + +### Step 4: Dry-Run or Execute +```typescript +if (args.dryRun) { + console.log('\n๐Ÿ”Ž DRY RUN: No changes will be made.\n'); + console.log('The following projects would be configured:'); + areaPaths.forEach(ap => { + const projectId = mapper.mapToProjectId(ap.path); + console.log(` โœจ ${projectId} (${ap.path})`); + }); + console.log(`\nTotal: ${areaPaths.length} projects would be configured\n`); + return; +} + +// Confirm import +const { confirmed } = await inquirer.prompt([{ + type: 'confirm', + name: 'confirmed', + message: `Configure ${areaPaths.length} project(s) from area paths?`, + default: true +}]); + +if (!confirmed) { + console.log('โญ๏ธ Import cancelled.'); + return; +} +``` + +### Step 5: Update Configuration +```typescript +import { getConfigManager } from '../../../src/core/config/index.js'; + +const configManager = getConfigManager(process.cwd()); + +// Build area path configuration +const areaPathConfig: Record = {}; + +for (const ap of areaPaths) { + const projectId = mapper.mapToProjectId(ap.path); + areaPathConfig[projectId] = [ap.path]; +} + +// Update configuration +await configManager.update({ + issueTracker: { + provider: 'ado', + ado: { + organization: org, + project: selectedProject, + areaPathMapping: areaPathConfig, + granularity + } + } +}); + +// Update .env file +import { updateEnvFile } from '../../../src/utils/env-manager.js'; + +await updateEnvFile('AZURE_DEVOPS_PROJECT', selectedProject); + +// Write area paths to .env (comma-separated) +const areaPathList = areaPaths.map(ap => ap.path).join(','); +await updateEnvFile('AZURE_DEVOPS_AREA_PATHS', areaPathList); + +console.log('\nโœ… Projects configured successfully!\n'); +console.log(`Organization: ${org}`); +console.log(`Project: ${selectedProject}`); +console.log(`Granularity: ${granularity}`); +console.log(`\nArea paths configured:\n ${areaPathList.split(',').join('\n ')}\n`); +``` + +### Step 6: Resume Support +```typescript +if (args.resume) { + const { CacheManager } = await import('../../../src/core/cache/cache-manager.js'); + const cacheManager = new CacheManager(process.cwd()); + + const importState = await cacheManager.get('ado-import-state'); + + if (!importState) { + console.log('โš ๏ธ No import state found. Use without --resume to start fresh.'); + return; + } + + console.log(`\n๐Ÿ“‚ Resuming from: ${importState.lastAreaPath} (${importState.completed}/${importState.total})`); + + // Skip already-processed area paths + const remainingPaths = areaPaths.filter(ap => !importState.processed.includes(ap.path)); + + // Continue import with remaining paths + // (use same logic as Step 5) +} +``` + +## Examples + +### Example 1: Basic Import with Area Paths +**User**: `/specweave-ado:import-projects` + +**Output**: +``` +๐Ÿ“‹ Organization: mycompany + Current project: Platform + +โœ“ Found 5 accessible project(s) + +Select ADO project to import area paths from: +> Platform + +๐Ÿ’ก Suggestion: two-level + Balanced hierarchy (8 two-level areas). Recommended granularity. + +Select area path granularity for project organization: +> Two-level (8 projects) - e.g., Backend-API, Backend-Database + +๐Ÿ“Š 8 project(s) will be created from area paths: + + โœจ Platform/Backend/API โ†’ backend-api + โœจ Platform/Backend/Database โ†’ backend-database + โœจ Platform/Frontend/Web โ†’ frontend-web + โœจ Platform/Frontend/Admin โ†’ frontend-admin + โœจ Platform/Mobile/iOS โ†’ mobile-ios + โœจ Platform/Mobile/Android โ†’ mobile-android + โœจ Platform/Infrastructure/Cloud โ†’ infrastructure-cloud + โœจ Platform/Infrastructure/Network โ†’ infrastructure-network + +Configure 8 project(s) from area paths? (Y/n) + +โœ… Projects configured successfully! + +Organization: mycompany +Project: Platform +Granularity: two-level + +Area paths configured: + Platform/Backend/API + Platform/Backend/Database + Platform/Frontend/Web + Platform/Frontend/Admin + Platform/Mobile/iOS + Platform/Mobile/Android + Platform/Infrastructure/Cloud + Platform/Infrastructure/Network +``` + +### Example 2: Top-Level Only +**User**: `/specweave-ado:import-projects --granularity top-level` + +**Output**: +``` +Select area path granularity: top-level (forced via CLI) + +๐Ÿ“Š 3 project(s) will be created from area paths: + + โœจ Platform/Backend โ†’ backend + โœจ Platform/Frontend โ†’ frontend + โœจ Platform/Mobile โ†’ mobile +``` + +### Example 3: Dry-Run +**User**: `/specweave-ado:import-projects --dry-run` + +**Output**: +``` +๐Ÿ”Ž DRY RUN: No changes will be made. + +The following projects would be configured: + โœจ backend-api (Platform/Backend/API) + โœจ backend-database (Platform/Backend/Database) + โœจ frontend-web (Platform/Frontend/Web) + +Total: 8 projects would be configured +``` + +## Important Notes + +- **Multi-Project Organization**: Uses area paths to create logical project separation +- **Granularity Control**: Top-level, two-level, or full-tree based on hierarchy complexity +- **Atomic Updates**: Uses temp file + rename to prevent corruption +- **Progress Tracking**: Shows progress bar for large hierarchies (> 50 area paths) +- **Resume Support**: Interrupted imports can be resumed with `--resume` + +## Related Commands + +- `/specweave:init` - Initial SpecWeave setup +- `/specweave-ado:sync` - Sync increments with ADO work items +- `/specweave-ado:refresh-cache` - Clear cached ADO data + +## Error Handling + +- **Missing Credentials**: Prompt user to run `specweave init` first +- **API Errors**: Show clear error message with suggestion +- **No Area Paths**: Fallback to single-project mode +- **Permission Errors**: Check ADO PAT scopes + +--- + +**Multi-Project Excellence**: This command enables sophisticated multi-project organization in Azure DevOps using area paths, perfect for large teams with complex hierarchies. diff --git a/commands/specweave-ado-status.md b/commands/specweave-ado-status.md new file mode 100644 index 0000000..f4df644 --- /dev/null +++ b/commands/specweave-ado-status.md @@ -0,0 +1,53 @@ +--- +name: specweave-ado:status +description: Check Azure DevOps sync status for increment +--- + +# ADO Status Command + +**Usage**: `/specweave-ado:status ` + +**Purpose**: Display ADO sync status and work item details + +--- + +## Command Behavior + +When user runs this command, invoke `ado-manager` agent to: + +1. Read increment-metadata.json +2. Fetch work item from ADO API +3. Display: ID, URL, state, completion %, last sync time +4. Check for sync issues + +**Agent Invocation**: +``` +Use Task tool with subagent_type: "specweave-ado:ado-manager:ado-manager" + +Prompt: "Check ADO sync status for increment 0005-payment-integration. + +Steps: +1. Read increment-metadata.json +2. Extract: work item ID, last sync time +3. GET work item from ADO API +4. Display status information +5. Check for any sync issues" +``` + +--- + +## Example Output + +``` +ADO Sync Status +=============== +Increment: 0005-payment-integration +Work Item: #12345 +URL: https://dev.azure.com/myorg/MyProject/_workitems/edit/12345 +State: Active +Completion: 60% (6/10 tasks) +Last Synced: 2025-11-04 10:30:00 (5 minutes ago) +Sync Enabled: โœ… + +Next Sync: Automatic on task completion +``` diff --git a/commands/specweave-ado-sync.md b/commands/specweave-ado-sync.md new file mode 100644 index 0000000..7405c59 --- /dev/null +++ b/commands/specweave-ado-sync.md @@ -0,0 +1,148 @@ +--- +name: specweave-ado:sync +description: Two-way sync between SpecWeave increment and Azure DevOps work item (push & pull by default) +--- + +# Sync ADO Work Item Command + +**Usage**: `/specweave-ado:sync [options]` + +**Purpose**: Two-way synchronization between SpecWeave increment and Azure DevOps work item + +**Default**: Two-way sync (push & pull) + +--- + +## Options + +- `--direction `: Sync direction (default: `two-way`) + - `two-way`: SpecWeave โ†” ADO (default - recommended) + - `to-ado`: SpecWeave โ†’ ADO only (push progress) + - `from-ado`: ADO โ†’ SpecWeave only (pull updates) + +## Examples + +```bash +# Two-way sync (default - both directions) +/specweave-ado:sync 0005 + +# Push only (one-way to ADO) +/specweave-ado:sync 0005 --direction to-ado + +# Pull only (one-way from ADO) +/specweave-ado:sync 0005 --direction from-ado +``` + +--- + +## Command Behavior + +When user runs this command, invoke `ado-manager` agent to perform two-way sync: + +### Phase 1: Pull FROM ADO (default behavior) +1. Fetch work item state from ADO API +2. Detect changes in ADO: + - State changes (New โ†’ Active โ†’ Resolved โ†’ Closed) + - Priority changes + - Iteration/sprint changes + - Comments from team members + - Field updates +3. Apply ADO changes to SpecWeave increment: + - Update increment status to match ADO state + - Update priority in metadata + - Import team comments to increment notes + - Update iteration tracking + +### Phase 2: Push TO ADO (default behavior) +1. Read tasks.md from increment +2. Calculate completion percentage +3. Identify recently completed tasks +4. Format progress update comment +5. POST comment to ADO work item +6. Update work item state if needed (New โ†’ Active โ†’ Resolved) +7. Update custom fields (completion %, current task, etc.) + +**Agent Invocation**: +``` +Use Task tool with subagent_type: "specweave-ado:ado-manager:ado-manager" + +Prompt: "Two-way sync for increment 0005-payment-integration with ADO. + +Phase 1 - Pull FROM ADO: +1. Fetch work item #12345 from ADO API +2. Detect changes: state, priority, iteration, comments +3. Apply ADO changes to increment metadata +4. Import team comments to increment notes + +Phase 2 - Push TO ADO: +1. Read .specweave/increments/0005/tasks.md +2. Calculate: X/Y tasks complete (Z%) +3. Identify: Recently completed tasks +4. Format comment with progress update +5. Load work item ID from increment-metadata.json +6. POST comment to ADO API +7. Update work item state/fields + +Display: Two-way sync summary" +``` + +--- + +## Example Output + +### Two-way Sync (Default) + +``` +๐Ÿ”„ Two-way sync for increment 0005... + +โœ“ Azure DevOps work item: #12345 +โœ“ Sync direction: Two-way (push & pull) + +Detecting changes (both directions)... + +FROM ADO: +โœ“ Work item state changed: Active โ†’ Resolved +โœ“ Iteration updated: Sprint 23 โ†’ Sprint 24 +โœ“ Priority changed: 2 โ†’ 1 +โœ“ 3 new comments from team + +FROM SpecWeave: +โœ“ 2 new tasks completed (T-005, T-006) +โœ“ Progress: 40% โ†’ 60% (6/10 tasks) +โœ“ Current task: T-007 + +Syncing TO ADO... +โœ“ Posted progress comment (ID: 98765) +โœ“ Updated completion: 60% +โœ“ Updated current task field: T-007 + +Syncing FROM ADO... +โœ“ Updated increment status: active โ†’ completed +โœ“ Updated priority: P2 โ†’ P1 +โœ“ Updated iteration tracking: Sprint 24 +โœ“ Imported 3 team comments to increment notes + +โœ… Bidirectional Sync Complete! + + SpecWeave โ†” ADO synchronized + โ€ข Pushed: Progress (60%), 2 task updates + โ€ข Pulled: State (Resolved), priority (P1), iteration, 3 comments + +ADO Work Item: https://dev.azure.com/myorg/MyProject/_workitems/edit/12345 +Last synced: just now +Next sync: Automatic (hook-based) or manual when ready +``` + +### One-Way Sync (to-ado) + +``` +โœ… Pushed to ADO Work Item #12345 + +Progress: 60% complete (6/10 tasks) + +Recently Completed: +- T-005: Add payment tests +- T-006: Update documentation + +URL: https://dev.azure.com/myorg/MyProject/_workitems/edit/12345 +``` diff --git a/hooks/README.md b/hooks/README.md new file mode 100644 index 0000000..36c069b --- /dev/null +++ b/hooks/README.md @@ -0,0 +1,201 @@ +# SpecWeave Azure DevOps Plugin Hooks + +**Plugin**: `specweave-ado` +**Location**: `plugins/specweave-ado/hooks/` + +--- + +## Purpose + +This hook automatically syncs SpecWeave increment progress to Azure DevOps Work Items after each task completion. + +**Key Features**: +- โœ… Updates Azure DevOps work item status based on increment progress +- โœ… Syncs task completion state to ADO +- โœ… Bidirectional sync (local โ†’ Azure DevOps) +- โœ… Non-blocking (failures don't stop core workflow) +- โœ… Self-contained (no dependencies on core plugin) + +--- + +## Available Hooks + +### 1. `post-task-completion.sh` + +**Triggers**: After ANY task is marked complete (via TodoWrite tool) + +**Preconditions**: +- โœ… Active increment exists (`.specweave/increments/####/`) +- โœ… `metadata.json` has `.ado.item` field +- โœ… Node.js installed +- โœ… ADO sync script exists (`dist/commands/ado-sync.js`) +- โœ… Azure DevOps PAT in `.env` + +**Actions**: +1. Reads increment metadata +2. Calls ADO sync script (Node.js) +3. Updates Azure DevOps work item status +4. Logs all actions to `.specweave/logs/hooks-debug.log` + +**Example Flow**: +``` +Task T-003 completed in tasks.md +โ†“ +Hook fires (PostToolUse + TodoWrite matcher) +โ†“ +ADO sync script updates work item #4567 +โ†“ +Log: "[ADO] โœ… Azure DevOps sync complete" +``` + +**Dependencies**: +- Node.js 18+ +- Azure DevOps PAT (`.env`) +- `jq` for JSON parsing + +--- + +## Configuration + +### Hook Registration (`hooks.json`) + +```json +{ + "hooks": { + "PostToolUse": [ + { + "matcher": "TodoWrite", + "hooks": [ + { + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-task-completion.sh" + } + ] + } + ] + } +} +``` + +### Metadata Format + +Increments must have `metadata.json` with Azure DevOps work item link: + +```json +{ + "ado": { + "item": 4567, + "url": "https://dev.azure.com/org/project/_workitems/edit/4567", + "project": "MyProject" + } +} +``` + +### Environment Variables + +Required in `.env`: + +```bash +AZURE_DEVOPS_ORG=your-org +AZURE_DEVOPS_PROJECT=your-project +AZURE_DEVOPS_PAT=your_personal_access_token_here +``` + +--- + +## Installation + +### Automatic (Recommended) + +```bash +npx specweave init my-project +# Installs all plugins including specweave-ado +# Hooks auto-register via hooks.json +``` + +### Manual (Development) + +```bash +# Install plugin +/plugin install specweave-ado + +# Verify hook registration +cat ~/.claude/settings.json | grep specweave-ado +``` + +--- + +## Testing + +### Test Hook Independently + +```bash +# Test syntax +bash -n plugins/specweave-ado/hooks/post-task-completion.sh + +# Test execution (requires active increment + ADO work item) +./plugins/specweave-ado/hooks/post-task-completion.sh +``` + +--- + +## Logging + +All Azure DevOps sync actions are logged to: + +``` +.specweave/logs/hooks-debug.log +``` + +**Example Log Output**: +``` +[2025-11-10] [ADO] ๐Ÿ”— Azure DevOps sync hook fired +[2025-11-10] [ADO] ๐Ÿ”„ Syncing to Azure DevOps work item 4567 +[2025-11-10] [ADO] โœ… Azure DevOps sync complete +``` + +**Log Prefixes**: +- `[ADO]` - All messages from this hook +- `๐Ÿ”—` - Hook fired +- `๐Ÿ”„` - Syncing started +- `โœ…` - Success +- `โš ๏ธ` - Warning (non-blocking failure) +- `โ„น๏ธ` - Info (skipped due to precondition) + +--- + +## Architecture + +### Separation from Core Plugin + +**Before (v0.12.x)**: +``` +Core hook (500+ lines) +โ”œโ”€โ”€ Azure DevOps sync โ† Embedded in core! +``` + +**After (v0.13.0+)**: +``` +Core hook (330 lines) ADO plugin hook (150 lines) +โ”œโ”€โ”€ Core concerns โ”œโ”€โ”€ Check for ADO work item + โ”œโ”€โ”€ Call Node.js sync script + โ””โ”€โ”€ Log actions +``` + +**Key Benefits**: +- โœ… **Optional plugin**: ADO sync only runs if `specweave-ado` installed +- โœ… **Independent testing**: Test ADO sync in isolation +- โœ… **No core dependencies**: Core plugin doesn't depend on Azure DevOps API + +--- + +## Related Documentation + +- **Core Plugin Hooks**: `plugins/specweave/hooks/README.md` +- **Architecture Analysis**: `.specweave/increments/0018-strict-increment-discipline-enforcement/reports/HOOKS-ARCHITECTURE-ANALYSIS.md` +- **ADO Sync Command**: `plugins/specweave-ado/commands/specweave-ado-sync.md` + +--- + +**Version**: v0.13.0+ +**Last Updated**: 2025-11-10 diff --git a/hooks/post-living-docs-update.sh b/hooks/post-living-docs-update.sh new file mode 100644 index 0000000..9603005 --- /dev/null +++ b/hooks/post-living-docs-update.sh @@ -0,0 +1,360 @@ +#!/bin/bash + +# ============================================================================ +# Post Living Docs Update Hook - Azure DevOps Sync +# ============================================================================ +# +# Triggered after living docs are updated to sync with Azure DevOps. +# CRITICAL: External tool status ALWAYS wins in conflicts! +# +# Triggers: +# 1. After /specweave:done (increment completion) +# 2. After /specweave:sync-docs update +# 3. After manual spec edits +# 4. After webhook from ADO +# +# ============================================================================ + +set +e # EMERGENCY FIX: Prevents Claude Code crashes + +# EMERGENCY KILL SWITCH +if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then + exit 0 +fi + +# Configuration +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" +LIVING_DOCS_DIR="$PROJECT_ROOT/.specweave/docs/internal/specs" +LOG_FILE="$PROJECT_ROOT/.specweave/logs/ado-sync.log" +DEBUG=${DEBUG:-0} + +# Ensure log directory exists +mkdir -p "$(dirname "$LOG_FILE")" + +# ============================================================================ +# Logging +# ============================================================================ + +log() { + local level=$1 + shift + local message="$@" + local timestamp=$(date '+%Y-%m-%d %H:%M:%S') + echo "[$timestamp] [$level] $message" >> "$LOG_FILE" + [ "$DEBUG" -eq 1 ] && echo "[$level] $message" >&2 +} + +log_info() { + log "INFO" "$@" +} + +log_error() { + log "ERROR" "$@" +} + +log_debug() { + [ "$DEBUG" -eq 1 ] && log "DEBUG" "$@" +} + +# ============================================================================ +# External Tool Detection +# ============================================================================ + +detect_external_tool() { + local spec_path=$1 + + # Check for external links in spec metadata + if grep -q "externalLinks:" "$spec_path"; then + if grep -q "ado:" "$spec_path"; then + echo "ado" + elif grep -q "jira:" "$spec_path"; then + echo "jira" + elif grep -q "github:" "$spec_path"; then + echo "github" + fi + fi +} + +# ============================================================================ +# Status Mapping +# ============================================================================ + +map_ado_status_to_local() { + local ado_status=$1 + + case "$ado_status" in + "New") + echo "draft" + ;; + "Active") + echo "in-progress" + ;; + "Resolved") + echo "implemented" + ;; + "Closed") + echo "complete" + ;; + "In Review"|"In QA") + echo "in-qa" + ;; + *) + echo "unknown" + ;; + esac +} + +map_local_status_to_ado() { + local local_status=$1 + + case "$local_status" in + "draft") + echo "New" + ;; + "in-progress") + echo "Active" + ;; + "implemented") + echo "Resolved" + ;; + "complete") + echo "Closed" + ;; + "in-qa") + echo "In Review" + ;; + *) + echo "Active" + ;; + esac +} + +# ============================================================================ +# ADO API Functions +# ============================================================================ + +get_ado_work_item_status() { + local work_item_id=$1 + local org="${AZURE_DEVOPS_ORG}" + local project="${AZURE_DEVOPS_PROJECT}" + local pat="${AZURE_DEVOPS_PAT}" + + if [ -z "$org" ] || [ -z "$pat" ]; then + log_error "ADO credentials not configured" + return 1 + fi + + local api_url="https://dev.azure.com/${org}/${project}/_apis/wit/workitems/${work_item_id}?api-version=7.0" + + log_debug "Fetching ADO work item $work_item_id status" + + local response=$(curl -s -u ":${pat}" \ + -H "Content-Type: application/json" \ + "$api_url") + + if [ $? -ne 0 ]; then + log_error "Failed to fetch ADO work item status" + return 1 + fi + + # Extract status from response + local status=$(echo "$response" | jq -r '.fields["System.State"]') + + if [ "$status" = "null" ] || [ -z "$status" ]; then + log_error "Could not extract status from ADO response" + return 1 + fi + + echo "$status" +} + +update_ado_work_item() { + local work_item_id=$1 + local spec_content=$2 + local org="${AZURE_DEVOPS_ORG}" + local project="${AZURE_DEVOPS_PROJECT}" + local pat="${AZURE_DEVOPS_PAT}" + + if [ -z "$org" ] || [ -z "$pat" ]; then + log_error "ADO credentials not configured" + return 1 + fi + + # Extract current status from spec + local local_status=$(echo "$spec_content" | grep "^status:" | cut -d: -f2 | tr -d ' ') + local ado_status=$(map_local_status_to_ado "$local_status") + + local api_url="https://dev.azure.com/${org}/${project}/_apis/wit/workitems/${work_item_id}?api-version=7.0" + + # Create update payload + local payload=$(cat < /dev/null + + if [ $? -ne 0 ]; then + log_error "Failed to update ADO work item" + return 1 + fi + + log_info "Updated ADO work item $work_item_id" +} + +# ============================================================================ +# Conflict Resolution - CRITICAL: External Wins! +# ============================================================================ + +resolve_status_conflict() { + local spec_path=$1 + local local_status=$2 + local external_status=$3 + + local mapped_external=$(map_ado_status_to_local "$external_status") + + if [ "$local_status" != "$mapped_external" ]; then + log_info "Status conflict detected:" + log_info " Local: $local_status" + log_info " External: $external_status (mapped: $mapped_external)" + log_info " Resolution: EXTERNAL WINS - applying $mapped_external" + + # Update local spec with external status + sed -i.bak "s/^status: .*/status: $mapped_external/" "$spec_path" + + # Add sync metadata + local timestamp=$(date -u '+%Y-%m-%dT%H:%M:%SZ') + + # Check if syncedAt exists, update or add + if grep -q "syncedAt:" "$spec_path"; then + sed -i.bak "s/syncedAt: .*/syncedAt: \"$timestamp\"/" "$spec_path" + else + # Add after externalLinks section + sed -i.bak "/externalLinks:/a\\ + syncedAt: \"$timestamp\"" "$spec_path" + fi + + # Clean up backup files + rm -f "${spec_path}.bak" + + log_info "Local spec updated with external status: $mapped_external" + return 0 + else + log_debug "No status conflict - local and external match: $local_status" + return 0 + fi +} + +# ============================================================================ +# Main Sync Function +# ============================================================================ + +sync_spec_with_ado() { + local spec_path=$1 + + if [ ! -f "$spec_path" ]; then + log_error "Spec file not found: $spec_path" + return 1 + fi + + local spec_name=$(basename "$spec_path") + log_info "Syncing spec: $spec_name" + + # Read spec content + local spec_content=$(cat "$spec_path") + + # Extract ADO work item ID from metadata + local work_item_id=$(echo "$spec_content" | grep -A5 "externalLinks:" | grep -A3 "ado:" | grep "featureId:" | cut -d: -f2 | tr -d ' ') + + if [ -z "$work_item_id" ]; then + log_debug "No ADO work item linked to spec, skipping sync" + return 0 + fi + + log_info "Found ADO work item ID: $work_item_id" + + # Step 1: Push updates to ADO (content changes) + update_ado_work_item "$work_item_id" "$spec_content" + + # Step 2: CRITICAL - Pull status from ADO (external wins!) + local external_status=$(get_ado_work_item_status "$work_item_id") + + if [ -z "$external_status" ]; then + log_error "Could not fetch ADO status" + return 1 + fi + + log_info "ADO status: $external_status" + + # Step 3: Extract local status + local local_status=$(echo "$spec_content" | grep "^status:" | cut -d: -f2 | tr -d ' ') + + log_info "Local status: $local_status" + + # Step 4: Resolve conflicts - EXTERNAL WINS + resolve_status_conflict "$spec_path" "$local_status" "$external_status" + + log_info "Sync completed for $spec_name" +} + +# ============================================================================ +# Entry Point +# ============================================================================ + +main() { + log_info "=== Post Living Docs Update Hook Started ===" + + # Get the spec path from arguments or environment + local spec_path="${1:-$SPECWEAVE_UPDATED_SPEC}" + + if [ -z "$spec_path" ]; then + log_error "No spec path provided" + exit 1 + fi + + # Detect external tool + local tool=$(detect_external_tool "$spec_path") + + if [ "$tool" != "ado" ]; then + log_debug "Not an ADO-linked spec, skipping" + exit 0 + fi + + log_info "Detected ADO integration for spec" + + # Perform sync + sync_spec_with_ado "$spec_path" + + local exit_code=$? + + if [ $exit_code -eq 0 ]; then + log_info "=== Sync completed successfully ===" + else + log_error "=== Sync failed with exit code: $exit_code ===" + fi + + exit $exit_code +} + +# Run main function +main "$@" +# ALWAYS exit 0 - NEVER let hook errors crash Claude Code +exit 0 diff --git a/hooks/post-task-completion.sh b/hooks/post-task-completion.sh new file mode 100755 index 0000000..84e5ab6 --- /dev/null +++ b/hooks/post-task-completion.sh @@ -0,0 +1,180 @@ +#!/bin/bash + +# SpecWeave Azure DevOps Sync Hook +# Runs after task completion to sync progress to Azure DevOps Work Items +# +# This hook is part of the specweave-ado plugin and handles: +# - Syncing task completion state to Azure DevOps work items +# - Updating ADO work item status based on increment progress +# +# Dependencies: +# - Node.js for running sync scripts +# - jq for JSON parsing +# - metadata.json must have .ado.item field +# - Azure DevOps PAT in .env + +set +e # EMERGENCY FIX: Prevents Claude Code crashes + +# EMERGENCY KILL SWITCH +if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then + exit 0 +fi + +# ============================================================================ +# PROJECT ROOT DETECTION +# ============================================================================ + +# Find project root by searching upward for .specweave/ directory +find_project_root() { + local dir="$1" + while [ "$dir" != "/" ]; do + if [ -d "$dir/.specweave" ]; then + echo "$dir" + return 0 + fi + dir="$(dirname "$dir")" + done + # Fallback: try current directory + if [ -d "$(pwd)/.specweave" ]; then + pwd + else + echo "$(pwd)" + fi +} + +PROJECT_ROOT="$(find_project_root "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")" +cd "$PROJECT_ROOT" 2>/dev/null || true + +# ============================================================================ +# CONFIGURATION +# ============================================================================ + +LOGS_DIR=".specweave/logs" +DEBUG_LOG="$LOGS_DIR/hooks-debug.log" + +mkdir -p "$LOGS_DIR" 2>/dev/null || true + +# ============================================================================ +# PRECONDITIONS CHECK +# ============================================================================ + +echo "[$(date)] [ADO] ๐Ÿ”— Azure DevOps sync hook fired" >> "$DEBUG_LOG" 2>/dev/null || true + +# Detect current increment +CURRENT_INCREMENT=$(ls -td .specweave/increments/*/ 2>/dev/null | xargs -n1 basename | grep -v "_backlog" | grep -v "_archive" | grep -v "_working" | head -1) + +if [ -z "$CURRENT_INCREMENT" ]; then + echo "[$(date)] [ADO] โ„น๏ธ No active increment, skipping ADO sync" >> "$DEBUG_LOG" 2>/dev/null || true + cat <> "$DEBUG_LOG" 2>/dev/null || true + cat < /dev/null; then + echo "[$(date)] [ADO] โš ๏ธ jq not found, skipping ADO sync" >> "$DEBUG_LOG" 2>/dev/null || true + cat </dev/null) + +if [ -z "$ADO_ITEM" ]; then + echo "[$(date)] [ADO] โ„น๏ธ No Azure DevOps work item linked to $CURRENT_INCREMENT, skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true + cat < /dev/null; then + echo "[$(date)] [ADO] โš ๏ธ Node.js not found, skipping ADO sync" >> "$DEBUG_LOG" 2>/dev/null || true + cat <> "$DEBUG_LOG" 2>/dev/null || true + cat <> "$DEBUG_LOG" 2>/dev/null || true + +# Run ADO sync command (non-blocking) +node dist/commands/ado-sync.js "$CURRENT_INCREMENT" 2>&1 | tee -a "$DEBUG_LOG" >/dev/null || { + echo "[$(date)] [ADO] โš ๏ธ Failed to sync to Azure DevOps (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true +} + +echo "[$(date)] [ADO] โœ… Azure DevOps sync complete" >> "$DEBUG_LOG" 2>/dev/null || true + +# ============================================================================ +# SPEC COMMIT SYNC (NEW!) +# ============================================================================ + +echo "[$(date)] [ADO] ๐Ÿ”— Checking for spec commit sync..." >> "$DEBUG_LOG" 2>/dev/null || true + +# Call TypeScript CLI to sync commits +if command -v node &> /dev/null && [ -f "$PROJECT_ROOT/dist/cli/commands/sync-spec-commits.js" ]; then + echo "[$(date)] [ADO] ๐Ÿš€ Running spec commit sync..." >> "$DEBUG_LOG" 2>/dev/null || true + + node "$PROJECT_ROOT/dist/cli/commands/sync-spec-commits.js" \ + --increment "$PROJECT_ROOT/.specweave/increments/$CURRENT_INCREMENT" \ + --provider ado \ + 2>&1 | tee -a "$DEBUG_LOG" >/dev/null || { + echo "[$(date)] [ADO] โš ๏ธ Spec commit sync failed (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true + } + + echo "[$(date)] [ADO] โœ… Spec commit sync complete" >> "$DEBUG_LOG" 2>/dev/null || true +else + echo "[$(date)] [ADO] โ„น๏ธ Spec commit sync not available (node or script not found)" >> "$DEBUG_LOG" 2>/dev/null || true +fi + +# ============================================================================ +# OUTPUT TO CLAUDE +# ============================================================================ + +cat < b[1].confidence - a[1].confidence)[0][0]; +``` + +### Confidence Calculation + +- **Keyword match**: +0.2 per keyword found +- **File pattern match**: +0.3 per pattern +- **Explicit mention**: +1.0 if project name in spec +- **Team mention**: +0.5 if team name matches + +**Threshold**: Confidence > 0.7 = auto-assign, otherwise prompt user + +## Usage Examples + +### Example 1: Single-Project Increment + +**Scenario**: Authentication feature for AuthService + +**Spec Analysis**: +``` +Title: "Add OAuth 2.0 authentication" +Keywords found: authentication, oauth, jwt +File patterns: src/auth/oauth-provider.ts +Confidence: AuthService = 0.9 โœ… +``` + +**Action**: +```bash +# Auto-creates folder structure +.specweave/docs/internal/specs/AuthService/ +โ””โ”€โ”€ spec-001-oauth-authentication.md + +# Maps to Azure DevOps +Project: AuthService +Work Item: Epic "OAuth 2.0 Authentication" +``` + +### Example 2: Multi-Project Increment + +**Scenario**: Checkout flow spanning multiple services + +**Spec Analysis**: +``` +Title: "Implement checkout flow with payment processing" +Keywords found: user, cart, payment, stripe, notification +Confidence: + - UserService = 0.6 + - PaymentService = 0.8 โœ… + - NotificationService = 0.5 +``` + +**Action**: +```bash +# Creates multi-project structure +.specweave/docs/internal/specs/ +โ”œโ”€โ”€ PaymentService/ +โ”‚ โ””โ”€โ”€ spec-002-checkout-payment.md (primary) +โ”œโ”€โ”€ UserService/ +โ”‚ โ””โ”€โ”€ spec-002-checkout-user.md (linked) +โ””โ”€โ”€ NotificationService/ + โ””โ”€โ”€ spec-002-checkout-notifications.md (linked) + +# Creates linked work items in Azure DevOps +PaymentService: Epic "Checkout Payment Processing" (primary) +UserService: Feature "User Cart Management" (links to primary) +NotificationService: Feature "Order Notifications" (links to primary) +``` + +### Example 3: Area Path Organization + +**Scenario**: ERP system with module-based organization + +**Configuration**: +```bash +AZURE_DEVOPS_STRATEGY=area-path-based +AZURE_DEVOPS_PROJECT=ERP +AZURE_DEVOPS_AREA_PATHS=Finance,HR,Inventory +``` + +**Spec Analysis**: +``` +Title: "Add payroll calculation engine" +Keywords found: payroll, salary, tax, employee +Area match: HR (confidence = 0.85) +``` + +**Action**: +```bash +# Creates area-based structure +.specweave/docs/internal/specs/ERP/HR/ +โ””โ”€โ”€ spec-003-payroll-engine.md + +# Maps to Azure DevOps +Project: ERP +Area Path: ERP\HR +Work Item: Epic "Payroll Calculation Engine" +``` + +## Task Splitting Across Projects + +When an increment spans multiple projects, tasks are intelligently split: + +### Input: Unified tasks.md +```markdown +# Tasks for Checkout Flow + +- T-001: Create shopping cart API (UserService) +- T-002: Implement Stripe integration (PaymentService) +- T-003: Add order confirmation email (NotificationService) +- T-004: Update user order history (UserService) +- T-005: Process payment webhook (PaymentService) +``` + +### Output: Project-specific work items + +**UserService** (2 tasks): +- Task: Create shopping cart API +- Task: Update user order history + +**PaymentService** (2 tasks): +- Task: Implement Stripe integration +- Task: Process payment webhook + +**NotificationService** (1 task): +- Task: Add order confirmation email + +## Folder Structure Creation + +The skill automatically creates and maintains folder structure: + +### On Increment Creation + +```typescript +async function createProjectFolders(increment: Increment) { + const projects = detectProjects(increment); + + for (const project of projects) { + const specPath = `.specweave/docs/internal/specs/${project}/`; + await ensureDir(specPath); + + // Create project-specific spec + const spec = extractProjectSpec(increment, project); + await writeSpec(`${specPath}/spec-${increment.number}-${increment.name}.md`, spec); + + // Create README if first spec in project + if (isFirstSpec(project)) { + await createProjectReadme(project); + } + } +} +``` + +### Project README Template + +```markdown +# {Project} Specifications + +## Overview +This folder contains specifications for the {Project} project. + +## Architecture +{Brief description of project architecture} + +## Team +- Team Lead: {name} +- Developers: {list} + +## Specifications +- [spec-001-feature.md](spec-001-feature.md) - {description} + +## External Links +- Azure DevOps: https://dev.azure.com/{org}/{project} +- Repository: {git-url} +``` + +## Sync Commands + +### Sync Increment to Projects + +```bash +/specweave-ado:sync-increment 0014 + +# Detects projects from spec +# Creates work items in each project +# Links work items together +``` + +### Sync Spec to Project + +```bash +/specweave-ado:sync-spec AuthService/spec-001 + +# Syncs single spec to specific project +# Updates existing work item or creates new +``` + +### Sync All Specs + +```bash +/specweave-ado:sync-all + +# Syncs all specs across all projects +# Maintains relationships +# Updates bidirectionally +``` + +## Project Mapping Configuration + +### Manual Mapping (config.json) + +```json +{ + "ado": { + "projectMappings": { + "auth-.*": "AuthService", + "user-.*": "UserService", + "payment-.*": "PaymentService", + "notification-.*": "NotificationService" + }, + "defaultProject": "Platform", + "crossProjectLinking": true + } +} +``` + +### Auto-Detection Rules + +```typescript +const autoDetectionRules = [ + { + pattern: /auth|login|oauth|security/i, + project: "AuthService" + }, + { + pattern: /user|profile|account/i, + project: "UserService" + }, + { + pattern: /payment|billing|stripe/i, + project: "PaymentService" + } +]; +``` + +## Cross-Project Coordination + +### Dependency Management + +When increments span projects, dependencies are tracked: + +```yaml +# .specweave/increments/0014-checkout-flow/metadata.yml +projects: + primary: PaymentService + dependencies: + - UserService: [T-001, T-004] + - NotificationService: [T-003] + +ado_mappings: + PaymentService: + epic: 12345 + work_items: [12346, 12347] + UserService: + feature: 12348 + work_items: [12349, 12350] + NotificationService: + feature: 12351 + work_items: [12352] +``` + +### Cross-Project Queries + +```typescript +// Find all work items for an increment across projects +async function getIncrementWorkItems(incrementId: string) { + const metadata = await readMetadata(incrementId); + const workItems = []; + + for (const [project, mapping] of Object.entries(metadata.ado_mappings)) { + const items = await adoClient.getWorkItems(project, mapping.work_items); + workItems.push(...items); + } + + return workItems; +} +``` + +## Best Practices + +### 1. Consistent Naming + +Use consistent naming across projects: +``` +spec-001-oauth-authentication.md # Good +spec-001-auth.md # Too vague +SPEC_001_OAuth.md # Inconsistent format +``` + +### 2. Clear Project Boundaries + +Define clear boundaries between projects: +```yaml +AuthService: + owns: [authentication, authorization, sessions] + not: [user profiles, user preferences] + +UserService: + owns: [profiles, preferences, user data] + not: [authentication, passwords] +``` + +### 3. Link Related Specs + +Link specs that span projects: +```markdown +# spec-002-checkout-payment.md + +Related Specs: +- [User Cart](../UserService/spec-002-checkout-user.md) +- [Notifications](../NotificationService/spec-002-checkout-notifications.md) +``` + +### 4. Use Project Prefixes + +Prefix increment names with primary project: +```bash +/specweave:increment "payment-stripe-integration" +/specweave:increment "auth-oauth-provider" +/specweave:increment "user-profile-redesign" +``` + +## Error Handling + +### Project Not Found + +``` +โŒ Project "AuthService" not found in Azure DevOps + +Options: +1. Create project "AuthService" +2. Map to existing project +3. Skip this project + +Your choice [1]: +``` + +### Ambiguous Project Detection + +``` +โš ๏ธ Cannot determine project for increment 0014 + +Multiple projects detected: +- UserService (confidence: 0.6) +- PaymentService (confidence: 0.6) + +Please select primary project: +1. UserService +2. PaymentService +3. Both (multi-project) + +Your choice [3]: +``` + +### Sync Conflicts + +``` +โš ๏ธ Sync conflict detected + +Local: spec-001 updated 2 hours ago +Azure DevOps: Work item updated 1 hour ago + +Options: +1. Use local version +2. Use Azure DevOps version +3. Merge changes +4. View diff + +Your choice [3]: +``` + +## Integration with CI/CD + +### Auto-sync on Commit + +```yaml +# .github/workflows/specweave-sync.yml +on: + push: + paths: + - '.specweave/docs/internal/specs/**' + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npx specweave ado-sync-all + env: + AZURE_DEVOPS_PAT: ${{ secrets.ADO_PAT }} +``` + +### Project-specific Pipelines + +```yaml +# azure-pipelines.yml +trigger: + paths: + include: + - .specweave/docs/internal/specs/$(System.TeamProject)/** + +variables: + - name: project + value: $(System.TeamProject) + +steps: + - script: npx specweave ado-sync-project $(project) +``` + +## Summary + +This skill enables sophisticated multi-project Azure DevOps organizations by: + +1. โœ… **Intelligent project detection** from spec content +2. โœ… **Automatic folder organization** by project/area/team +3. โœ… **Task splitting** across multiple projects +4. โœ… **Cross-project linking** and dependency tracking +5. โœ… **Bidirectional sync** with Azure DevOps work items + +**Result**: Seamless multi-project coordination with zero manual overhead! + +--- + +**Skill Version**: 1.0.0 +**Introduced**: SpecWeave v0.17.0 +**Last Updated**: 2025-11-11 \ No newline at end of file diff --git a/skills/ado-resource-validator/SKILL.md b/skills/ado-resource-validator/SKILL.md new file mode 100644 index 0000000..43a0272 --- /dev/null +++ b/skills/ado-resource-validator/SKILL.md @@ -0,0 +1,906 @@ +--- +name: ado-resource-validator +description: Validates Azure DevOps projects and resources exist, creates missing resources automatically. Smart enough to prompt user to select existing or create new projects. Supports multiple projects for project-per-team strategy, area paths for area-path-based strategy, and teams for team-based strategy. NEW - Per-project configuration support - AZURE_DEVOPS_AREA_PATHS_{ProjectName} and AZURE_DEVOPS_TEAMS_{ProjectName} for hierarchical organization. Activates for ado setup, ado validation, ado configuration, missing ado project, azure devops .env setup, per-project area paths, per-project teams. +allowed-tools: Read, Bash, Write, Edit +--- + +# Azure DevOps Resource Validator Skill + +**Purpose**: Validate and auto-create Azure DevOps projects and resources, ensuring .env configuration is correct. + +**Auto-Activation**: Triggers when Azure DevOps setup or validation is needed. + +## What This Skill Does + +This skill ensures your Azure DevOps configuration in `.env` is valid and all resources exist. It's **smart enough** to: + +1. **Validate Azure DevOps projects** - Check if projects exist (multiple for project-per-team) +2. **Prompt for action** - Select existing project or create new one +3. **Validate area paths** - Check if area paths exist (for area-path-based strategy) +4. **Create missing area paths** - Auto-create area paths if missing +5. **Validate teams** - Check if teams exist (for team-based strategy) +6. **Update .env with correct values** - Ensure configuration is valid + +## When This Skill Activates + +โœ… **Automatically activates when**: +- You set up Azure DevOps integration for the first time +- You run `/specweave-ado:sync` and resources are missing +- Your `.env` has invalid Azure DevOps configuration +- You mention "ado setup" or "azure devops validation" + +## Azure DevOps Configuration Structure + +### Required .env Variables + +```bash +AZURE_DEVOPS_PAT=your_token_here +AZURE_DEVOPS_ORG=yourorganization +AZURE_DEVOPS_STRATEGY=project-per-team # or area-path-based, team-based +``` + +### Strategy-Specific Variables + +**Strategy 1: Project-per-team** (Multiple Projects) +```bash +AZURE_DEVOPS_STRATEGY=project-per-team +AZURE_DEVOPS_PROJECTS=WebApp,MobileApp,Platform +``` +โ†’ Validates that WebApp, MobileApp, and Platform projects exist + +**Strategy 2: Area-path-based** (One Project, Multiple Area Paths) +```bash +AZURE_DEVOPS_STRATEGY=area-path-based +AZURE_DEVOPS_PROJECT=MainProduct +AZURE_DEVOPS_AREA_PATHS=Frontend,Backend,Mobile +``` +โ†’ Validates MainProduct project exists +โ†’ Creates area paths if missing: MainProduct\Frontend, MainProduct\Backend, MainProduct\Mobile + +**Strategy 3: Team-based** (One Project, Multiple Teams) +```bash +AZURE_DEVOPS_STRATEGY=team-based +AZURE_DEVOPS_PROJECT=MainProduct +AZURE_DEVOPS_TEAMS=Alpha Team,Beta Team,Gamma Team +``` +โ†’ Validates MainProduct project exists +โ†’ Creates teams if missing: Alpha Team, Beta Team, Gamma Team + +**NEW: Per-Project Configuration** (Advanced - Multiple Projects ร— Resources) +```bash +# Multiple projects with their own area paths and teams +AZURE_DEVOPS_STRATEGY=project-per-team +AZURE_DEVOPS_PROJECTS=Backend,Frontend,Mobile + +# Per-project area paths (hierarchical naming) +AZURE_DEVOPS_AREA_PATHS_Backend=API,Database,Cache +AZURE_DEVOPS_AREA_PATHS_Frontend=Web,Admin,Public +AZURE_DEVOPS_AREA_PATHS_Mobile=iOS,Android,Shared + +# Per-project teams (optional) +AZURE_DEVOPS_TEAMS_Backend=Alpha,Beta +AZURE_DEVOPS_TEAMS_Frontend=Gamma +``` +โ†’ Validates 3 projects exist: Backend, Frontend, Mobile +โ†’ Creates area paths per project: + - Backend\API, Backend\Database, Backend\Cache + - Frontend\Web, Frontend\Admin, Frontend\Public + - Mobile\iOS, Mobile\Android, Mobile\Shared +โ†’ Creates teams per project: + - Backend: Alpha, Beta + - Frontend: Gamma + +**Naming Convention**: `{PROVIDER}_{RESOURCE_TYPE}_{PROJECT_NAME}` + +## Validation Flow + +### Step 1: Strategy Detection + +**Read .env and detect strategy**: +```bash +AZURE_DEVOPS_STRATEGY=project-per-team +``` + +**Result**: +``` +๐Ÿ” Detected strategy: Project-per-team + Projects to validate: WebApp, MobileApp, Platform +``` + +### Step 2: Project Validation (Project-per-team) + +**Check if projects exist**: +```bash +# API calls to Azure DevOps +GET https://dev.azure.com/{org}/_apis/projects/WebApp +GET https://dev.azure.com/{org}/_apis/projects/MobileApp +GET https://dev.azure.com/{org}/_apis/projects/Platform +``` + +**If all projects exist**: +``` +โœ… All projects validated: + โ€ข WebApp (ID: abcd1234) + โ€ข MobileApp (ID: efgh5678) + โ€ข Platform (ID: ijkl9012) +``` + +**If some projects don't exist**: +``` +โš ๏ธ Projects not found: + โœ… WebApp (exists) + โŒ MobileApp (not found) + โŒ Platform (not found) + +What would you like to do? +1. Create missing projects +2. Select existing projects +3. Fix project names manually +4. Cancel + +Your choice [1]: +``` + +**Option 1: Create Missing Projects**: +``` +๐Ÿ“ฆ Creating Azure DevOps projects... + +Creating project: MobileApp... +โœ… Project created: MobileApp (ID: mnop3456) + +Creating project: Platform... +โœ… Project created: Platform (ID: qrst7890) + +โœ… All projects now exist! +``` + +**Option 2: Select Existing Projects**: +``` +Available projects in organization: +1. WebApp +2. ApiGateway +3. AuthService +4. NotificationService +5. DataPipeline + +Select projects (comma-separated numbers) [2,3]: + +โœ… Updated .env: AZURE_DEVOPS_PROJECTS=WebApp,ApiGateway,AuthService +``` + +### Step 3: Area Path Validation (Area-path-based) + +**Scenario**: One project with area paths +```bash +AZURE_DEVOPS_STRATEGY=area-path-based +AZURE_DEVOPS_PROJECT=MainProduct +AZURE_DEVOPS_AREA_PATHS=Frontend,Backend,Mobile,QA +``` + +**Validation**: +``` +Checking project: MainProduct... +โœ… Project "MainProduct" exists + +Checking area paths... + โœ… MainProduct\Frontend (exists) + โœ… MainProduct\Backend (exists) + โš ๏ธ MainProduct\Mobile (not found) + โš ๏ธ MainProduct\QA (not found) + +๐Ÿ“ฆ Creating missing area paths... +โœ… Created: MainProduct\Mobile +โœ… Created: MainProduct\QA + +โœ… All area paths validated/created successfully +``` + +### Step 4: Team Validation (Team-based) + +**Scenario**: One project with multiple teams +```bash +AZURE_DEVOPS_STRATEGY=team-based +AZURE_DEVOPS_PROJECT=MainProduct +AZURE_DEVOPS_TEAMS=Alpha Team,Beta Team,Gamma Team +``` + +**Validation**: +``` +Checking project: MainProduct... +โœ… Project "MainProduct" exists + +Checking teams... + โœ… Alpha Team (exists) + โš ๏ธ Beta Team (not found) + โš ๏ธ Gamma Team (not found) + +๐Ÿ“ฆ Creating missing teams... +โœ… Created: Beta Team +โœ… Created: Gamma Team + +โœ… All teams validated/created successfully +``` + +## Usage Examples + +### Example 1: Fresh Azure DevOps Setup (Project-per-team) + +**Scenario**: New setup with multiple projects for different teams + +**Action**: Run `/specweave-ado:sync` + +**What Happens**: +```bash +๐Ÿ” Validating Azure DevOps configuration... + +Strategy: Project-per-team +Checking projects: WebApp, MobileApp, Platform... + +โš ๏ธ Projects not found: + โ€ข WebApp + โ€ข MobileApp + โ€ข Platform + +What would you like to do? +1. Create new projects +2. Select existing projects +3. Cancel + +Your choice [1]: 1 + +๐Ÿ“ฆ Creating Azure DevOps projects... + +Creating project: WebApp + Description: Web application frontend + Process template: Agile +โœ… Created: WebApp (ID: proj-001) + +Creating project: MobileApp + Description: Mobile application + Process template: Agile +โœ… Created: MobileApp (ID: proj-002) + +Creating project: Platform + Description: Backend platform services + Process template: Agile +โœ… Created: Platform (ID: proj-003) + +๐ŸŽ‰ Azure DevOps configuration complete! All resources ready. +``` + +### Example 2: Migrate from Single to Multi-Project + +**Scenario**: Currently using single project, want to split into multiple + +**Current .env**: +```bash +AZURE_DEVOPS_PROJECT=MainProduct +``` + +**New .env**: +```bash +AZURE_DEVOPS_STRATEGY=project-per-team +AZURE_DEVOPS_PROJECTS=MainProduct-Frontend,MainProduct-Backend,MainProduct-Mobile +``` + +**What Happens**: +```bash +๐Ÿ” Detected strategy change: team-based โ†’ project-per-team + +Validating new projects... + โœ… MainProduct-Frontend (exists from previous split) + โš ๏ธ MainProduct-Backend (not found) + โš ๏ธ MainProduct-Mobile (not found) + +Would you like to: +1. Create missing projects +2. Keep single project with area paths instead +3. Cancel + +Your choice [1]: 1 + +๐Ÿ“ฆ Creating projects... +โœ… Created: MainProduct-Backend +โœ… Created: MainProduct-Mobile + +๐Ÿ’ก Tip: You can now organize specs by project: + .specweave/docs/internal/specs/MainProduct-Frontend/ + .specweave/docs/internal/specs/MainProduct-Backend/ + .specweave/docs/internal/specs/MainProduct-Mobile/ +``` + +### Example 3: Area Path Setup + +**Scenario**: Large monolithic project with area-based organization + +**Action**: Setup area paths for team organization + +**What Happens**: +```bash +๐Ÿ” Validating Azure DevOps configuration... + +Strategy: Area-path-based +Project: EnterpriseApp +Area Paths: Core, UserManagement, Billing, Reports, Analytics + +Checking project: EnterpriseApp... +โœ… Project exists + +Checking area paths... + โœ… EnterpriseApp\Core + โœ… EnterpriseApp\UserManagement + โš ๏ธ EnterpriseApp\Billing (not found) + โš ๏ธ EnterpriseApp\Reports (not found) + โš ๏ธ EnterpriseApp\Analytics (not found) + +๐Ÿ“ฆ Creating area paths... + +Creating: EnterpriseApp\Billing +โœ… Area path created with default team + +Creating: EnterpriseApp\Reports +โœ… Area path created with default team + +Creating: EnterpriseApp\Analytics +โœ… Area path created with default team + +โœ… All area paths ready! + +Work items will be organized by area: + โ€ข Billing features โ†’ EnterpriseApp\Billing + โ€ข Report features โ†’ EnterpriseApp\Reports + โ€ข Analytics features โ†’ EnterpriseApp\Analytics +``` + +## Implementation Details + +**Location**: `src/utils/external-resource-validator.ts` + +**Core Classes**: +```typescript +// Main validator class +export class AzureDevOpsResourceValidator { + private pat: string; + private organization: string; + private envPath: string; + + constructor(envPath: string = '.env') { + this.envPath = envPath; + const env = this.loadEnv(); + this.pat = env.AZURE_DEVOPS_PAT || ''; + this.organization = env.AZURE_DEVOPS_ORG || ''; + } + + // Main validation entry point + async validate(): Promise { + const env = this.loadEnv(); + const strategy = env.AZURE_DEVOPS_STRATEGY || 'project-per-team'; + + // Validate based on strategy + if (strategy === 'project-per-team') { + return this.validateMultipleProjects(projectNames); + } else if (strategy === 'area-path-based') { + return this.validateAreaPaths(projectName, areaPaths); + } else if (strategy === 'team-based') { + return this.validateTeams(projectName, teams); + } + } +} + +// Public API function +export async function validateAzureDevOpsResources( + envPath: string = '.env' +): Promise { + const validator = new AzureDevOpsResourceValidator(envPath); + return validator.validate(); +} +``` + +**Key Implementation Features**: + +1. **Async Project Creation** (ADO-specific): + ```typescript + // ADO creates projects asynchronously - need to poll for completion + async createProject(name: string): Promise { + const result = await this.callAzureDevOpsApi('projects?api-version=7.0', 'POST', body); + + // Wait for project to be fully created (ADO async behavior) + await this.waitForProjectCreation(result.id); + + return { id: result.id, name, description }; + } + + // Poll until project is in 'wellFormed' state + private async waitForProjectCreation(projectId: string): Promise { + const maxAttempts = 30; // 30 seconds max wait + for (let i = 0; i < maxAttempts; i++) { + const project = await this.getProject(projectId); + if (project.state === 'wellFormed') { + return; // Project is ready! + } + await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second + } + throw new Error('Project creation timeout'); + } + ``` + +2. **Interactive Prompts** (when resources missing): + ```typescript + const { action } = await inquirer.prompt([ + { + type: 'select', + name: 'action', + message: `Project "${projectName}" not found. What would you like to do?`, + choices: [ + { name: 'Create new project', value: 'create' }, + { name: 'Select existing project', value: 'select' }, + { name: 'Skip this project', value: 'skip' }, + { name: 'Cancel', value: 'cancel' } + ] + } + ]); + ``` + +3. **Automatic .env Updates**: + ```typescript + // After creating projects, update .env + updateEnv(key: string, value: string): void { + const envContent = fs.readFileSync(this.envPath, 'utf-8'); + const updated = envContent.replace( + new RegExp(`^${key}=.*$`, 'm'), + `${key}=${value}` + ); + fs.writeFileSync(this.envPath, updated); + } + ``` + +## CLI Command + +**Automatic validation** (during setup): +```bash +# Runs automatically during specweave init +npx specweave init + +# Also runs automatically before sync +/specweave-ado:sync 0014 +``` + +**Manual validation**: +```bash +# Via skill activation +"Can you validate my Azure DevOps configuration?" + +# Via TypeScript directly +npx tsx -e "import { validateAzureDevOpsResources } from './dist/utils/external-resource-validator.js'; await validateAzureDevOpsResources();" + +# Via CLI (future command - planned) +specweave validate-ado +``` + +**Validation output**: +```typescript +interface AzureDevOpsValidationResult { + valid: boolean; + strategy: 'project-per-team' | 'area-path-based' | 'team-based'; + projects: Array<{ + name: string; + id: string; + exists: boolean; + }>; + created: string[]; // Names of newly created resources + envUpdated: boolean; // Whether .env was modified +} + +// Example output: +{ + valid: true, + strategy: 'project-per-team', + projects: [ + { name: 'WebApp', id: 'proj-001', exists: true }, + { name: 'MobileApp', id: 'proj-002', exists: true, created: true }, + { name: 'Platform', id: 'proj-003', exists: true, created: true } + ], + created: ['MobileApp', 'Platform'], + envUpdated: false +} +``` + +## Smart Project Detection + +### Auto-detect Based on Work Item Patterns + +The skill can intelligently suggest project organization based on your existing work items: + +```typescript +// Analyze existing work items +const workItems = await analyzeWorkItems(org, project); + +// Detect patterns +const patterns = { + byArea: workItems.groupBy('areaPath'), // Area-based organization + byTeam: workItems.groupBy('assignedTeam'), // Team-based organization + byType: workItems.groupBy('workItemType') // Type-based organization +}; + +// Suggest strategy +if (patterns.byArea.length > 3) { + console.log('๐Ÿ’ก Detected area-based organization'); + console.log(' Suggested strategy: area-path-based'); +} else if (patterns.byTeam.length > 2) { + console.log('๐Ÿ’ก Detected team-based organization'); + console.log(' Suggested strategy: team-based or project-per-team'); +} +``` + +## Project Creation API + +**Azure DevOps REST API** (v7.0): + +### Create Project +```bash +POST https://dev.azure.com/{org}/_apis/projects?api-version=7.0 +Content-Type: application/json +Authorization: Basic {base64(":PAT")} + +{ + "name": "MobileApp", + "description": "Mobile application project", + "capabilities": { + "versioncontrol": { + "sourceControlType": "Git" + }, + "processTemplate": { + "templateTypeId": "adcc42ab-9882-485e-a3ed-7678f01f66bc" # Agile + } + } +} + +Response: +{ + "id": "proj-002", + "name": "MobileApp", + "state": "wellFormed" +} +``` + +### Create Area Path +```bash +POST https://dev.azure.com/{org}/{project}/_apis/wit/classificationnodes/areas?api-version=7.0 +Content-Type: application/json + +{ + "name": "Frontend", + "attributes": { + "startDate": null, + "finishDate": null + } +} + +Response: +{ + "id": 123, + "name": "Frontend", + "path": "\\MainProduct\\Area\\Frontend" +} +``` + +### Create Team +```bash +POST https://dev.azure.com/{org}/_apis/projects/{projectId}/teams?api-version=7.0 +Content-Type: application/json + +{ + "name": "Alpha Team", + "description": "Alpha development team" +} + +Response: +{ + "id": "team-001", + "name": "Alpha Team", + "projectName": "MainProduct" +} +``` + +## Configuration Examples + +### Example 1: Microservices Architecture (Project-per-team) + +**Before** (`.env`): +```bash +AZURE_DEVOPS_ORG=mycompany +AZURE_DEVOPS_PAT=xxx +``` + +**After validation**: +```bash +AZURE_DEVOPS_ORG=mycompany +AZURE_DEVOPS_PAT=xxx +AZURE_DEVOPS_STRATEGY=project-per-team +AZURE_DEVOPS_PROJECTS=AuthService,UserService,PaymentService,NotificationService +``` + +**Folder structure created**: +``` +.specweave/docs/internal/specs/ +โ”œโ”€โ”€ AuthService/ +โ”‚ โ””โ”€โ”€ spec-001-oauth-implementation.md +โ”œโ”€โ”€ UserService/ +โ”‚ โ””โ”€โ”€ spec-001-user-management.md +โ”œโ”€โ”€ PaymentService/ +โ”‚ โ””โ”€โ”€ spec-001-stripe-integration.md +โ””โ”€โ”€ NotificationService/ + โ””โ”€โ”€ spec-001-email-notifications.md +``` + +### Example 2: Monolithic Application (Area-path-based) + +**Before** (`.env`): +```bash +AZURE_DEVOPS_PROJECT=ERP +``` + +**After validation**: +```bash +AZURE_DEVOPS_ORG=enterprise +AZURE_DEVOPS_PAT=xxx +AZURE_DEVOPS_STRATEGY=area-path-based +AZURE_DEVOPS_PROJECT=ERP +AZURE_DEVOPS_AREA_PATHS=Finance,HR,Inventory,Sales,Reports +``` + +**Work item organization**: +``` +ERP +โ”œโ”€โ”€ Finance/ โ†’ Finance module features +โ”œโ”€โ”€ HR/ โ†’ HR module features +โ”œโ”€โ”€ Inventory/ โ†’ Inventory management +โ”œโ”€โ”€ Sales/ โ†’ Sales module features +โ””โ”€โ”€ Reports/ โ†’ Reporting features +``` + +### Example 3: Platform Teams (Team-based) + +**Before** (`.env`): +```bash +AZURE_DEVOPS_PROJECT=Platform +``` + +**After validation**: +```bash +AZURE_DEVOPS_ORG=techcorp +AZURE_DEVOPS_PAT=xxx +AZURE_DEVOPS_STRATEGY=team-based +AZURE_DEVOPS_PROJECT=Platform +AZURE_DEVOPS_TEAMS=Infrastructure,Security,Data,DevOps +``` + +**Team assignments**: +- Infrastructure Team โ†’ Cloud resources, networking +- Security Team โ†’ Auth, compliance, auditing +- Data Team โ†’ Databases, analytics, ML +- DevOps Team โ†’ CI/CD, monitoring, tooling + +## Error Handling + +### Error 1: Invalid Credentials + +**Symptom**: API calls fail with 401 Unauthorized + +**Solution**: +``` +โŒ Azure DevOps API authentication failed + +Please check: +1. AZURE_DEVOPS_PAT is correct +2. Token has not expired +3. AZURE_DEVOPS_ORG is correct + +Generate new token at: +https://dev.azure.com/{org}/_usersSettings/tokens +``` + +### Error 2: Insufficient Permissions + +**Symptom**: Cannot create projects (403 Forbidden) + +**Solution**: +``` +โŒ Insufficient permissions to create projects + +You need: +- Project Collection Administrator role (for creating projects) +- Project Administrator role (for area paths and teams) + +Contact your Azure DevOps administrator to request permissions. +``` + +### Error 3: Project Name Conflicts + +**Symptom**: Project creation fails (name exists) + +**Solution**: +``` +โŒ Project name "WebApp" already exists + +Options: +1. Use a different project name +2. Select the existing project +3. Add a suffix (e.g., WebApp-v2) + +Your choice [2]: +``` + +### Error 4: Organization Limits + +**Symptom**: Cannot create more projects + +**Solution**: +``` +โŒ Organization project limit reached (250 projects) + +Consider: +1. Using area-path-based strategy (one project) +2. Archiving old projects +3. Upgrading organization plan + +Contact Azure DevOps support for limit increases. +``` + +## Integration with SpecWeave Workflow + +### Automatic Validation + +When using `/specweave-ado:sync`, validation runs automatically: + +```bash +/specweave-ado:sync 0014 + +# Internally calls: +1. validateAzureDevOpsResources() +2. Fix missing projects/area paths/teams +3. Create folder structure for specs +4. Proceed with sync +``` + +### Manual Validation + +Run validation independently: + +```bash +# Via skill +"Validate my Azure DevOps configuration" + +# Via TypeScript +npx tsx src/utils/external-resource-validator.ts --provider=ado + +# Via CLI (future) +specweave validate-ado +``` + +## Best Practices + +โœ… **Choose the right strategy**: +- **Project-per-team**: Best for autonomous teams, microservices +- **Area-path-based**: Best for monolithic apps, shared codebase +- **Team-based**: Best for small organizations, simple structure + +โœ… **Use descriptive names**: +```bash +# Good +AZURE_DEVOPS_PROJECTS=UserManagement,PaymentProcessing,NotificationEngine + +# Bad +AZURE_DEVOPS_PROJECTS=Proj1,Proj2,Proj3 +``` + +โœ… **Document project mapping** (in README): +```markdown +## Azure DevOps Projects + +- UserManagement: User authentication and profile management +- PaymentProcessing: Payment gateway integrations +- NotificationEngine: Email, SMS, and push notifications +``` + +โœ… **Keep .env in version control** (gitignored tokens): +```bash +# Commit project structure +AZURE_DEVOPS_STRATEGY=project-per-team +AZURE_DEVOPS_PROJECTS=WebApp,MobileApp,Platform + +# Don't commit sensitive data +AZURE_DEVOPS_PAT= +``` + +## Folder Organization + +Based on strategy, the skill creates appropriate folder structure: + +### Project-per-team Structure +``` +.specweave/docs/internal/specs/ +โ”œโ”€โ”€ WebApp/ +โ”‚ โ”œโ”€โ”€ spec-001-user-interface.md +โ”‚ โ””โ”€โ”€ spec-002-responsive-design.md +โ”œโ”€โ”€ MobileApp/ +โ”‚ โ”œโ”€โ”€ spec-001-ios-features.md +โ”‚ โ””โ”€โ”€ spec-002-android-features.md +โ””โ”€โ”€ Platform/ + โ”œโ”€โ”€ spec-001-api-design.md + โ””โ”€โ”€ spec-002-database-schema.md +``` + +### Area-path-based Structure +``` +.specweave/docs/internal/specs/MainProduct/ +โ”œโ”€โ”€ Frontend/ +โ”‚ โ””โ”€โ”€ spec-001-ui-components.md +โ”œโ”€โ”€ Backend/ +โ”‚ โ””โ”€โ”€ spec-001-api-endpoints.md +โ””โ”€โ”€ Mobile/ + โ””โ”€โ”€ spec-001-mobile-sync.md +``` + +### Team-based Structure +``` +.specweave/docs/internal/specs/MainProduct/ +โ”œโ”€โ”€ AlphaTeam/ +โ”‚ โ””โ”€โ”€ spec-001-feature-a.md +โ”œโ”€โ”€ BetaTeam/ +โ”‚ โ””โ”€โ”€ spec-001-feature-b.md +โ””โ”€โ”€ GammaTeam/ + โ””โ”€โ”€ spec-001-feature-c.md +``` + +## Key Differences from JIRA + +**Azure DevOps vs JIRA Resource Creation**: + +| Aspect | Azure DevOps | JIRA | +|--------|-------------|------| +| **Project Creation** | Asynchronous (polling required) | Synchronous (immediate) | +| **Creation Time** | 5-30 seconds | <1 second | +| **Status Tracking** | Poll `state` field ('wellFormed') | No polling needed | +| **API Complexity** | Higher (async handling) | Lower (sync operations) | +| **Board Creation** | Auto-created with project | Requires separate API call | +| **Process Templates** | Required (Agile, Scrum, CMMI) | Not applicable | + +**Why Async Matters**: + +When you create an ADO project, the API returns immediately with `state: 'new'`, but the project isn't usable yet. The validator polls every 1 second (max 30 attempts) until `state: 'wellFormed'`: + +```typescript +// Create project (returns immediately) +const project = await createProject('MobileApp'); // state: 'new' + +// Poll until ready +await waitForProjectCreation(project.id); // Polls until state: 'wellFormed' + +// Now safe to use! +console.log('โœ… Project ready for work items'); +``` + +**Impact on UX**: +- JIRA: "โœ… Project created" (instant) +- ADO: "๐Ÿ“ฆ Creating project... โณ Waiting for Azure DevOps to complete setup... โœ… Project ready!" (5-30s) + +## Summary + +This skill ensures your Azure DevOps configuration is **always valid** by: + +1. โœ… **Validating projects** - Check if projects exist, prompt to select or create +2. โœ… **Supporting multiple strategies** - Project-per-team, area-path-based, team-based +3. โœ… **Auto-creating resources** - Projects, area paths, teams (with async handling) +4. โœ… **Organizing specs** - Create folder structure based on projects +5. โœ… **Clear error messages** - Actionable guidance for all failures +6. โœ… **Handles ADO async behavior** - Polls for project creation completion + +**Result**: Zero manual Azure DevOps setup - system handles everything, including ADO's async project creation! + +--- + +**Skill Version**: 1.1.0 +**Introduced**: SpecWeave v0.17.0 +**Last Updated**: 2025-11-11 +**Key Changes v1.1.0**: Added implementation details, async project creation handling, JIRA comparison \ No newline at end of file diff --git a/skills/ado-sync/.gitignore b/skills/ado-sync/.gitignore new file mode 100644 index 0000000..a3a8cb2 --- /dev/null +++ b/skills/ado-sync/.gitignore @@ -0,0 +1,3 @@ +test-results/ +*.log +.DS_Store diff --git a/skills/ado-sync/README.md b/skills/ado-sync/README.md new file mode 100644 index 0000000..0835050 --- /dev/null +++ b/skills/ado-sync/README.md @@ -0,0 +1,414 @@ +# ado-sync Skill + +**Status**: To be developed +**Priority**: Medium + +## Purpose + +Bidirectional sync between SpecWeave increments and Azure DevOps (ADO) + +**Note**: This skill handles ONLY Azure DevOps. For JIRA, see `jira-sync` skill. + +## Features + +### Export to ADO +- Create ADO work items from SpecWeave increments +- Map spec.md user stories โ†’ ADO User Stories +- Map tasks.md tasks โ†’ ADO Tasks +- Create Features if specified in spec.md +- Set Area Paths, Iterations, priorities + +### Import from ADO +- Sync ADO updates back to SpecWeave +- Import existing ADO work items as increments +- Update status, assignees, comments + +### Bidirectional Sync +- Keep status in sync (New, Active, Resolved, Closed) +- Sync descriptions and acceptance criteria +- Sync comments and attachments +- Handle conflicts intelligently + +## ADO-Specific Concepts + +### Mapping: SpecWeave โ†’ Azure DevOps + +| SpecWeave | Azure DevOps | +|-----------|--------------| +| spec.md (with Feature) | Feature | +| spec.md User Story | User Story | +| tasks.md Task | Task | +| Acceptance Tests (spec.md) | Acceptance Criteria (User Story) | +| Acceptance Criteria (tasks.md) | Task checklist | +| Status: planned | New | +| Status: in-progress | Active | +| Status: completed | Closed | + +### ADO Structure Example + +**spec.md with ADO structure**: +```markdown +--- +increment: 002-payment-processing +status: planned +structure: ado +ado_feature: 456 +--- + +## Feature: Payment Processing +**ADO**: 456 +**Area Path**: Platform/Payments +**Iteration**: Sprint 12 + +### User Story: Subscribe to Plan +**ADO**: 789 +**Priority**: 1 +**Area Path**: Platform/Payments +**Iteration**: Sprint 12 + +**Description**: +As a user, I want to subscribe to a monthly plan... + +**Acceptance Criteria**: +- User can select plan +- Payment processed +- Subscription activated +``` + +**tasks.md creates Tasks**: +```markdown +## Tasks for ADO-789 (Subscribe to Plan) + +### Task T001: Create StripeService +**ADO**: 790 (Task under User Story 789) +**Agent**: nodejs-backend +**Area Path**: Platform/Payments/Backend +**Iteration**: Sprint 12 + +**Description**: Create Stripe service class... + +**Acceptance Criteria**: +- [ ] StripeService class exists +- [ ] Unit tests passing +``` + +## Authentication + +**Personal Access Token (PAT)**: + + +**OAuth 2.0** (for apps): +```yaml +ado_sync: + url: "https://dev.azure.com/your-org" + project: "YourProject" + auth_type: "oauth" + client_id: "${ADO_CLIENT_ID}" + client_secret: "${ADO_CLIENT_SECRET}" +``` + +## Configuration + + + +## Workflow + +### Export Workflow (SpecWeave โ†’ ADO) + +``` +User: Creates increment in SpecWeave + .specweave/increments/0002-payment/ + spec.md (with structure: ado) + tasks.md + +โ†“ ado-sync detects new increment + +Creates in ADO: + Feature: 456 "Payment Processing" + Area Path: Platform/Payments + Iteration: Sprint 12 + + User Story: 789 "Subscribe to Plan" + Area Path: Platform/Payments + Iteration: Sprint 12 + + Task: 790 "Create StripeService" + Area Path: Platform/Payments/Backend + Iteration: Sprint 12 + + Task: 791 "Create API endpoints" + +Links created: + spec.md โ†’ ADO-789 + tasks.md T001 โ†’ ADO-790 + tasks.md T002 โ†’ ADO-791 +``` + +### Import Workflow (ADO โ†’ SpecWeave) + +``` +User: Updates ADO work item status to "Active" + +โ†“ ADO service hook triggers + +ado-sync: + Detects change to ADO-789 + Finds linked increment: 002-payment + Updates: .specweave/increments/0002-payment/spec.md + status: planned โ†’ in-progress +``` + +### Bidirectional Sync + +``` +User: Checks off task in tasks.md + - [x] T001: Create StripeService + +โ†“ ado-sync detects change + +Updates ADO: + Work Item 790 status โ†’ Closed + +User: Changes ADO-789 to "Closed" in Azure DevOps + +โ†“ ADO service hook triggers + +ado-sync updates SpecWeave: + .specweave/increments/0002-payment/spec.md + status: in-progress โ†’ completed +``` + +## API Integration + +### Azure DevOps REST API Endpoints Used + +```typescript +// Create Feature +POST https://dev.azure.com/{org}/{project}/_apis/wit/workitems/$Feature?api-version=7.0 +Content-Type: application/json-patch+json + +[ + { + "op": "add", + "path": "/fields/System.Title", + "value": "Payment Processing" + }, + { + "op": "add", + "path": "/fields/System.AreaPath", + "value": "Platform/Payments" + }, + { + "op": "add", + "path": "/fields/System.IterationPath", + "value": "Sprint 12" + } +] + +// Create User Story (linked to Feature) +POST https://dev.azure.com/{org}/{project}/_apis/wit/workitems/$User%20Story?api-version=7.0 + +[ + { + "op": "add", + "path": "/fields/System.Title", + "value": "Subscribe to Plan" + }, + { + "op": "add", + "path": "/relations/-", + "value": { + "rel": "System.LinkTypes.Hierarchy-Reverse", + "url": "https://dev.azure.com/{org}/_apis/wit/workItems/456" + } + } +] + +// Create Task (linked to User Story) +POST https://dev.azure.com/{org}/{project}/_apis/wit/workitems/$Task?api-version=7.0 + +[ + { + "op": "add", + "path": "/fields/System.Title", + "value": "Create StripeService" + }, + { + "op": "add", + "path": "/relations/-", + "value": { + "rel": "System.LinkTypes.Hierarchy-Reverse", + "url": "https://dev.azure.com/{org}/_apis/wit/workItems/789" + } + } +] + +// Update status +PATCH https://dev.azure.com/{org}/{project}/_apis/wit/workitems/{id}?api-version=7.0 + +[ + { + "op": "add", + "path": "/fields/System.State", + "value": "Active" + } +] +``` + +## Service Hooks (Webhooks) + +### Setup ADO Service Hook + +1. Go to Project Settings โ†’ Service hooks +2. Create new service hook: + - Service: Web Hooks + - Trigger: Work item updated + - URL: `https://your-app.com/api/webhooks/ado` + - Filters: Area path = Platform/Payments (optional) + +### Service Hook Handler + +```typescript +// Receives ADO service hook +POST /api/webhooks/ado + +// ado-sync processes: +1. Verify request (optional: check secret) +2. Extract work item data +3. Find linked SpecWeave increment +4. Update spec.md or tasks.md +5. Commit changes (optional) +``` + +## ADO-Specific Features + +### Area Paths + +**Organize work by area**: +```markdown +# spec.md +--- +ado_area_path: "Platform/Payments" +--- +``` + +Maps to ADO Area Path for organization. + +### Iterations/Sprints + +**Assign to sprint**: +```markdown +# spec.md +--- +ado_iteration: "Sprint 12" +--- +``` + +Or auto-detect current sprint: +```yaml +# config.yaml +ado_sync: + auto_detect_iteration: true +``` + +### Work Item Types + +**ADO supports custom work item types**: +- Epic โ†’ Feature โ†’ User Story โ†’ Task (default) +- Custom types supported via config + +```yaml +ado_sync: + work_item_types: + epic: "Epic" + feature: "Feature" + story: "User Story" + task: "Task" +``` + +### Custom Fields + +**Sync custom fields**: +```yaml +ado_sync: + custom_fields: + - name: "Custom.Priority" + map_from: "priority" # From spec.md frontmatter + - name: "Custom.Estimate" + map_from: "estimate" +``` + +## Conflict Resolution + +**Scenario**: Both SpecWeave and ADO updated simultaneously + +**Strategy**: +1. **Timestamp-based**: Latest change wins +2. **User prompt**: Ask user which to keep (via Ping.aiff) +3. **Merge**: Combine changes if possible + +**Example**: +``` +SpecWeave: status โ†’ in-progress (10:00 AM) +ADO: status โ†’ closed (10:05 AM) + +ado-sync: + Latest is ADO (10:05 AM) + Update SpecWeave โ†’ completed + ๐Ÿ”” Ping.aiff: "ADO conflict resolved - ADO version used" +``` + +## Error Handling + +**Common errors**: +- ADO API rate limits โ†’ Retry with exponential backoff +- Authentication failed โ†’ Notify user, check PAT +- Work item not found โ†’ Create if export, skip if import +- Network errors โ†’ Queue for retry +- Area Path invalid โ†’ Use default or notify user + +## Testing + +**Test scenarios**: +1. Create increment โ†’ Creates ADO work items +2. Update ADO โ†’ Updates SpecWeave +3. Update SpecWeave โ†’ Updates ADO +4. Area Path mapping +5. Iteration mapping +6. Conflict resolution +7. Service hook handling +8. Custom fields sync + +## Integration with Other Skills + +- **task-builder**: Reads ADO structure from spec.md +- **increment-planner**: Can specify structure: ado + +## Comparison: JIRA vs ADO + +| Feature | JIRA (jira-sync) | Azure DevOps (ado-sync) | +|---------|------------------|-------------------------| +| **Epic level** | Epic | Feature | +| **Story level** | Story | User Story | +| **Task level** | Sub-task | Task | +| **Organization** | Components, Labels | Area Paths | +| **Sprints** | Sprints (board-based) | Iterations (path-based) | +| **API** | JIRA REST API v3 | Azure DevOps REST API v7.0 | +| **Auth** | API Token | PAT or OAuth | +| **Webhooks** | JIRA Webhooks | Service Hooks | +| **Custom fields** | Custom fields | Work item fields | + +## Future Enhancements + +- Support for ADO Boards/Backlogs +- Sprint burndown sync +- Test case sync (ADO Test Plans) +- Build/release pipeline integration +- Wiki sync +- Git repo integration (link commits to work items) + +--- + +**To implement**: See task in .specweave/increments/ + +**See also**: `jira-sync` skill for JIRA integration diff --git a/skills/ado-sync/SKILL.md b/skills/ado-sync/SKILL.md new file mode 100644 index 0000000..1513c68 --- /dev/null +++ b/skills/ado-sync/SKILL.md @@ -0,0 +1,406 @@ +--- +name: ado-sync +description: Bidirectional synchronization between SpecWeave increments and Azure DevOps work items (two-way sync by default). Activates ONLY when user asks questions about Azure DevOps integration or needs help configuring ADO sync. Does NOT activate for slash commands. For syncing, use /specweave-ado:sync command instead. +--- + +# Azure DevOps Sync Skill + +**Purpose**: Seamlessly sync SpecWeave increments with Azure DevOps work items for unified project tracking. + +**Default Behavior**: **Bidirectional (two-way) sync** - Changes in either system are automatically synchronized + +**โš ๏ธ IMPORTANT**: This skill provides HELP and GUIDANCE about Azure DevOps sync. For actual syncing, users should use the `/specweave-ado:sync` command directly. This skill should NOT auto-activate when the command is being invoked. + +**Capabilities**: +- Bidirectional sync: SpecWeave โ†” ADO (default) +- Create ADO work items from increments +- Sync task progress โ†’ ADO comments +- Update increment status โ† ADO state changes +- Pull ADO comments and field updates โ†’ SpecWeave +- Close work items when increments complete +- Support for Epics, Features, User Stories + +--- + +## When This Skill Activates + +โœ… **Do activate when**: +- User asks: "How do I set up Azure DevOps sync?" +- User asks: "What ADO credentials do I need?" +- User asks: "How does ADO integration work?" +- User needs help configuring Azure DevOps integration + +โŒ **Do NOT activate when**: +- User invokes `/specweave-ado:sync` command (command handles it) +- Command is already running (avoid duplicate invocation) +- Task completion hook is syncing (automatic process) +- "Close ADO work item when done" + +--- + +## Prerequisites + +### 1. ADO Plugin Installed + +```bash +# Check if installed +/plugin list --installed | grep specweave-ado + +# Install if needed +/plugin install specweave-ado +``` + +### 2. Azure DevOps Personal Access Token (PAT) + +**Create PAT**: +1. Go to https://dev.azure.com/{organization}/_usersSettings/tokens +2. Click "New Token" +3. Name: "SpecWeave Sync" +4. Scopes: Work Items (Read & Write), Comments (Read & Write) +5. Copy token โ†’ Set environment variable + +**Set Token**: +```bash +export AZURE_DEVOPS_PAT="your-token-here" +``` + +### 3. ADO Configuration + +Add to `.specweave/config.json`: +```json +{ + "externalPM": { + "tool": "ado", + "enabled": true, + "config": { + "organization": "myorg", + "project": "MyProject", + "workItemType": "Epic", + "areaPath": "MyProject\\Team A", + "syncOnTaskComplete": true + } + } +} +``` + +--- + +## Commands Available + +### `/specweave-ado:create-workitem ` + +**Purpose**: Create ADO work item from increment + +**Example**: +```bash +/specweave-ado:create-workitem 0005 +``` + +**Result**: +- Creates Epic/Feature/User Story in ADO +- Links work item to increment (metadata) +- Adds initial comment with spec summary +- Sets tags: `specweave`, `increment-0005` + +--- + +### `/specweave-ado:sync ` + +**Purpose**: Sync increment progress with ADO work item + +**Example**: +```bash +/specweave-ado:sync 0005 +``` + +**Result**: +- Calculates task completion (%) +- Updates work item description +- Adds comment with progress update +- Updates state (New โ†’ Active โ†’ Resolved) + +--- + +### `/specweave-ado:close-workitem ` + +**Purpose**: Close ADO work item when increment complete + +**Example**: +```bash +/specweave-ado:close-workitem 0005 +``` + +**Result**: +- Updates work item state โ†’ Closed +- Adds completion comment with summary +- Marks work item as resolved + +--- + +### `/specweave-ado:status ` + +**Purpose**: Check ADO sync status for increment + +**Example**: +```bash +/specweave-ado:status 0005 +``` + +**Result**: +``` +ADO Sync Status +=============== +Increment: 0005-payment-integration +Work Item: #12345 +URL: https://dev.azure.com/myorg/MyProject/_workitems/edit/12345 +State: Active +Completion: 60% (6/10 tasks) +Last Synced: 2025-11-04 10:30:00 +Sync Enabled: โœ… +``` + +--- + +## Automatic Sync + +### When Task Completes + +**Trigger**: Post-task-completion hook fires + +**Flow**: +1. User marks task complete: `[x] T-005: Add payment tests` +2. Hook detects ADO sync enabled +3. Calculate new completion % +4. Update ADO work item comment: + ```markdown + ## Progress Update + + **Increment**: 0005-payment-integration + **Status**: 60% complete (6/10 tasks) + + ### Recently Completed + - [x] T-005: Add payment tests + + ### Remaining + - [ ] T-007: Add refund functionality + - [ ] T-008: Implement subscriptions + - [ ] T-009: Add analytics + - [ ] T-010: Security audit + + --- + ๐Ÿค– Auto-updated by SpecWeave + ``` + +### When Increment Completes + +**Trigger**: `/specweave:done` command + +**Flow**: +1. User runs `/specweave:done 0005` +2. Validate all tasks complete +3. Close ADO work item automatically +4. Add completion comment with summary + +--- + +## Work Item Types + +### Epic (Recommended) + +**Use When**: Large feature spanning multiple sprints + +**Mapping**: +- SpecWeave increment โ†’ ADO Epic +- Tasks โ†’ Epic description (checklist) +- Progress โ†’ Epic comments + +--- + +### Feature + +**Use When**: Medium-sized feature within a sprint + +**Mapping**: +- SpecWeave increment โ†’ ADO Feature +- Tasks โ†’ Feature description (checklist) +- Progress โ†’ Feature comments + +--- + +### User Story + +**Use When**: Small, single-sprint work + +**Mapping**: +- SpecWeave increment โ†’ ADO User Story +- Tasks โ†’ User Story description (checklist) +- Progress โ†’ User Story comments + +--- + +## Bidirectional Sync (Optional) + +**Enable**: Set `bidirectional: true` in config + +**Flow**: ADO โ†’ SpecWeave +1. User updates work item state in ADO (Active โ†’ Resolved) +2. SpecWeave detects change (polling or webhook) +3. Updates increment status locally +4. Notifies user: "Work item #12345 resolved โ†’ Increment 0005 marked complete" + +**Note**: Bidirectional sync requires webhook or polling setup + +--- + +## Configuration Options + +**`.specweave/config.json`**: +```json +{ + "externalPM": { + "tool": "ado", + "enabled": true, + "config": { + "organization": "myorg", + "project": "MyProject", + "personalAccessToken": "${AZURE_DEVOPS_PAT}", + "workItemType": "Epic", + "areaPath": "MyProject\\Team A", + "iterationPath": "MyProject\\Sprint 1", + "syncOnTaskComplete": true, + "syncOnIncrementComplete": true, + "createWorkItemsAutomatically": true, + "bidirectional": false, + "tags": ["specweave", "increment"], + "customFields": { + "incrementId": "Custom.IncrementId" + } + } + } +} +``` + +--- + +## Troubleshooting + +### Error: "Personal Access Token invalid" + +**Solution**: +1. Verify token is set: `echo $AZURE_DEVOPS_PAT` +2. Check token scopes: Work Items (Read & Write) +3. Ensure token not expired +4. Regenerate token if needed + +--- + +### Error: "Work item not found" + +**Solution**: +1. Check work item ID is correct +2. Verify you have access to the project +3. Ensure work item not deleted + +--- + +### Error: "Organization or project not found" + +**Solution**: +1. Verify organization name: https://dev.azure.com/{organization} +2. Check project name (case-sensitive) +3. Ensure you have access to the project + +--- + +## API Rate Limits + +**Azure DevOps**: +- Rate limit: 200 requests per minute per PAT +- Burst limit: 5000 requests per hour +- Recommendation: Enable rate limiting in config + +**Config**: +```json +{ + "externalPM": { + "config": { + "rateLimiting": { + "enabled": true, + "maxRequestsPerMinute": 150 + } + } + } +} +``` + +--- + +## Security Best Practices + +### DO: +- โœ… Store PAT in environment variable (`AZURE_DEVOPS_PAT`) +- โœ… Use `.env` file (gitignored) +- โœ… Set minimum required scopes +- โœ… Rotate PAT every 90 days + +### DON'T: +- โŒ Commit PAT to git +- โŒ Share PAT via Slack/email +- โŒ Use PAT with excessive permissions +- โŒ Log PAT to console/files + +--- + +## Related Commands + +- `/specweave:inc` - Create increment (auto-creates ADO work item if enabled) +- `/specweave:do` - Execute tasks (auto-syncs progress to ADO) +- `/specweave:done` - Complete increment (auto-closes ADO work item) +- `/specweave:status` - Show increment status (includes ADO sync status) + +--- + +## Examples + +### Example 1: Create Increment with ADO Sync + +```bash +# User +"Create increment for payment integration" + +# SpecWeave (if ADO enabled) +1. PM agent generates spec.md +2. Auto-create ADO Epic #12345 +3. Link Epic to increment metadata +4. Display: "Created increment 0005 โ†’ ADO Epic #12345" +``` + +### Example 2: Manual Sync + +```bash +# User completed 3 tasks manually +# Now sync to ADO + +/specweave-ado:sync 0005 + +# Result: ADO Epic #12345 updated with 30% progress +``` + +### Example 3: Check Sync Status + +```bash +/specweave-ado:status 0005 + +# Output: +# Work Item: #12345 +# URL: https://dev.azure.com/myorg/MyProject/_workitems/edit/12345 +# State: Active +# Completion: 60% +# Last Synced: 5 minutes ago +``` + +--- + +**Status**: Ready to use +**Version**: 0.1.0 +**Plugin**: specweave-ado diff --git a/skills/specweave-ado-mapper/SKILL.md b/skills/specweave-ado-mapper/SKILL.md new file mode 100644 index 0000000..1c1bb65 --- /dev/null +++ b/skills/specweave-ado-mapper/SKILL.md @@ -0,0 +1,501 @@ +--- +name: specweave-ado-mapper +description: Expert in bidirectional conversion between SpecWeave increments and Azure DevOps (ADO) Epics/Features/User Stories/Tasks. Handles export (increment โ†’ ADO), import (ADO โ†’ increment), and bidirectional sync with conflict resolution. Activates for ADO sync, Azure DevOps sync, work item creation, import from ADO. +tools: Read, Write, Edit, Bash +model: claude-sonnet-4-5-20250929 +--- + +# Specweave Ado Mapper Skill + +You are an expert in mapping SpecWeave concepts to Azure DevOps (ADO) and vice versa with precision and traceability. + +## Core Responsibilities + +1. **Export SpecWeave increments to ADO** (Increment โ†’ Epic + Features + User Stories + Tasks) +2. **Import ADO Epics as SpecWeave increments** (Epic โ†’ Increment structure) +3. **Bidirectional sync** with conflict detection and resolution +4. **Maintain traceability** (store IDs, URLs, timestamps) +5. **Validate mapping accuracy** using test cases +6. **Handle edge cases** (missing fields, custom workflows, API errors) + +--- + +## Azure DevOps Work Item Hierarchy + +ADO uses a **4-level hierarchy** (one more level than JIRA): + +``` +Epic +โ””โ”€โ”€ Feature + โ””โ”€โ”€ User Story + โ””โ”€โ”€ Task +``` + +**Key Difference from JIRA**: ADO has **Feature** between Epic and User Story. + +--- + +## Concept Mappings + +### SpecWeave โ†’ ADO + +| SpecWeave Concept | ADO Concept | Mapping Rules | +|-------------------|-------------|---------------| +| **Increment** | Epic | Title: `[Increment ###] [Title]` | +| **User Story** (from spec.md) | Feature (if large) OR User Story | Decision based on size | +| **Task** (from tasks.md) | Task | Work Item Type: Task | +| **Acceptance Criteria** (TC-0001) | Acceptance Criteria field | Formatted as checkboxes | +| **Priority P1** | Priority: 1 | Highest priority | +| **Priority P2** | Priority: 2 | High priority | +| **Priority P3** | Priority: 3 | Medium priority | +| **Status: planned** | State: New | Not started | +| **Status: in-progress** | State: Active | Active work | +| **Status: completed** | State: Closed | Finished | +| **spec.md** | Epic Description | Summary + link to spec (if repo) | + +### ADO โ†’ SpecWeave + +| ADO Concept | SpecWeave Concept | Import Rules | +|-------------|-------------------|--------------| +| **Epic** | Increment | Auto-number next available | +| **Feature** | User Story (large) | Extract title, description | +| **User Story** | User Story (small) | Extract acceptance criteria | +| **Task** | Task | Map to tasks.md checklist | +| **Acceptance Criteria** | TC-0001 format | Parse as test cases | +| **Priority 1** | Priority P1 | Critical | +| **Priority 2** | Priority P2 | Important | +| **Priority 3/4** | Priority P3 | Nice to have | +| **State: New** | Status: planned | Not started | +| **State: Active** | Status: in-progress | Active | +| **State: Closed** | Status: completed | Finished | +| **Area Path** | Context metadata | Store in frontmatter | +| **Iteration** | Context metadata | Store in frontmatter | + +--- + +## Conversion Workflows + +### 1. Export: Increment โ†’ ADO Epic + +**Input**: `.specweave/increments/0001-feature-name/` + +**Prerequisites**: +- Increment folder exists +- `spec.md` exists with valid frontmatter +- `tasks.md` exists +- ADO connection configured (PAT, organization, project) + +**Process**: + +1. **Read increment files**: + ```bash + # Read spec.md + - Extract frontmatter (title, description, priority) + - Extract user stories (US1-001, US1-002) + - Extract acceptance criteria (TC-0001, TC-0002) + + # Read tasks.md + - Extract task checklist + - Group tasks by user story + ``` + +2. **Create ADO Epic**: + ``` + Title: [Increment 0001] Feature Name + Description: + {spec.md summary} + + Specification: {link to spec.md if Azure Repos} + + Work Item Type: Epic + Priority: 1 (P1) / 2 (P2) / 3 (P3) + State: New + Area Path: {project_area} + Iteration: {current_iteration} + Tags: specweave, increment-0001 + Custom Fields: + - SpecWeave.IncrementID: 0001-feature-name + - SpecWeave.SpecURL: https://dev.azure.com/.../spec.md + ``` + +3. **Create ADO Features OR User Stories**: + + **Decision Logic**: + - If user story has >5 acceptance criteria โ†’ Create as Feature (large work) + - If user story has โ‰ค5 acceptance criteria โ†’ Create as User Story (small work) + + **Feature (large user story)**: + ``` + Title: {User Story title} + Description: + **As a** {role} + **I want to** {goal} + **So that** {benefit} + + Acceptance Criteria: + - TC-0001: {criteria} + - TC-0002: {criteria} + ... + + Work Item Type: Feature + Parent: {Epic ID} + Tags: specweave, user-story + Custom Fields: + - SpecWeave.UserStoryID: US1-001 + - SpecWeave.TestCaseIDs: TC-0001, TC-0002 + ``` + + **User Story (small user story)**: + ``` + (Same structure as Feature, but Work Item Type: User Story) + ``` + +4. **Create ADO Tasks**: + ``` + Title: {Task description} + Work Item Type: Task + Parent: {Feature or User Story ID} + State: New + Tags: specweave, task + ``` + +5. **Update increment frontmatter**: + ```yaml + ado: + epic_id: "12345" + epic_url: "https://dev.azure.com/{org}/{project}/_workitems/edit/12345" + features: + - id: "12346" + user_story_id: "US1-001" + - id: "12347" + user_story_id: "US1-002" + area_path: "MyProject\\TeamA" + iteration: "Sprint 24" + last_sync: "2025-10-26T14:00:00Z" + sync_direction: "export" + ``` + +**Output**: +``` +โœ… Exported to Azure DevOps! + +Epic: 12345 +URL: https://dev.azure.com/{org}/{project}/_workitems/edit/12345 +Features: 3 created +User Stories: 2 created +Tasks: 12 created +Area Path: MyProject\TeamA +Iteration: Sprint 24 +Last Sync: 2025-10-26T14:00:00Z +``` + +--- + +### 2. Import: ADO Epic โ†’ Increment + +**Input**: ADO Epic ID (e.g., `12345`) + +**Prerequisites**: +- Valid ADO Epic ID +- Epic exists and is accessible +- ADO connection configured + +**Process**: + +1. **Fetch Epic details** (via ADO REST API): + ``` + - Epic title, description, tags + - Epic custom fields (if SpecWeave ID exists) + - Priority, state, area path, iteration + ``` + +2. **Fetch hierarchy** (Epic โ†’ Features โ†’ User Stories โ†’ Tasks): + ``` + - All Features/User Stories linked to Epic + - All Tasks linked to each Feature/User Story + - Acceptance criteria fields + ``` + +3. **Auto-number next increment**: + ```bash + # Scan .specweave/increments/ for highest number + ls .specweave/increments/ | grep -E '^[0-9]{4}' | sort -n | tail -1 + # Increment by 1 โ†’ 0003 + ``` + +4. **Create increment folder**: + ``` + .specweave/increments/0003-imported-feature/ + ``` + +5. **Generate spec.md**: + ```yaml + --- + increment_id: "0003" + title: "{Epic title}" + status: "{mapped from ADO state}" + priority: "{mapped from ADO priority}" + created_at: "{Epic created date}" + ado: + epic_id: "12345" + epic_url: "https://dev.azure.com/{org}/{project}/_workitems/edit/12345" + features: + - id: "12346" + user_story_id: "US3-001" + area_path: "{area path}" + iteration: "{iteration}" + imported_at: "2025-10-26T14:00:00Z" + sync_direction: "import" + --- + + # {Epic title} + + {Epic description} + + ## Context + + - **Area Path**: {area_path} + - **Iteration**: {iteration} + - **ADO Epic**: [12345](https://dev.azure.com/.../12345) + + ## User Stories + + ### US3-001: {Feature/User Story title} + + **As a** {extracted from description} + **I want to** {extracted} + **So that** {extracted} + + **Acceptance Criteria**: + - [ ] TC-0001: {parsed from Acceptance Criteria field} + - [ ] TC-0002: {parsed} + + **ADO Feature**: [12346](https://dev.azure.com/.../12346) + ``` + +6. **Generate tasks.md**: + ```markdown + # Tasks: {Increment title} + + ## User Story: US3-001 + + - [ ] {Task 1 title} (ADO: 12350) + - [ ] {Task 2 title} (ADO: 12351) + ``` + +7. **Generate context-manifest.yaml** (default) + +8. **Update ADO Epic** (add custom field): + ``` + Custom Field: SpecWeave.IncrementID = 0003-imported-feature + ``` + +**Output**: +``` +โœ… Imported from Azure DevOps! + +Increment: 0003-imported-feature +Location: .specweave/increments/0003-imported-feature/ +User Stories: 5 imported +Tasks: 12 imported +ADO Epic: 12345 +Area Path: MyProject\TeamA +Iteration: Sprint 24 +``` + +--- + +### 3. Bidirectional Sync + +**Process**: Similar to JIRA sync, with ADO-specific fields: + +- Sync Area Path changes +- Sync Iteration changes +- Handle ADO-specific states (New, Active, Resolved, Closed) +- Sync Acceptance Criteria field + +--- + +## ADO-Specific Concepts + +### Area Path + +**Definition**: Organizational hierarchy (e.g., `MyProject\TeamA\Backend`) + +**Mapping**: +- Store in increment frontmatter: `ado.area_path` +- Not a direct SpecWeave concept +- Used for organizational context + +### Iteration + +**Definition**: Sprint/time period (e.g., `Sprint 24`) + +**Mapping**: +- Store in increment frontmatter: `ado.iteration` +- Not a direct SpecWeave concept +- Used for planning context + +### Work Item States + +ADO uses **State** (not Status): + +| ADO State | SpecWeave Status | +|-----------|------------------| +| New | planned | +| Active | in-progress | +| Resolved | in-progress (testing) | +| Closed | completed | + +### Priority Values + +ADO uses numeric priorities: + +| ADO Priority | SpecWeave Priority | +|--------------|-------------------| +| 1 | P1 | +| 2 | P2 | +| 3 | P3 | +| 4 | P3 | + +--- + +## Edge Cases and Error Handling + +### Feature vs User Story Decision + +**Problem**: SpecWeave user story โ†’ Should it be ADO Feature or User Story? + +**Solution**: +``` +Decision Logic: +- User story has >5 acceptance criteria โ†’ Feature (large work) +- User story has โ‰ค5 acceptance criteria โ†’ User Story (small work) +- User can override with flag: --force-feature or --force-user-story +``` + +### Custom Area Paths + +**Problem**: Project has custom Area Path structure + +**Solution**: +``` +Ask user: + "Select Area Path for this increment: + [1] MyProject\TeamA + [2] MyProject\TeamB + [3] Custom (enter path)" +``` + +### Custom Iterations + +**Problem**: Sprint naming varies + +**Solution**: +``` +Ask user: + "Select Iteration for this increment: + [1] Sprint 24 (current) + [2] Sprint 25 (next) + [3] Backlog + [4] Custom (enter iteration)" +``` + +### ADO API Errors + +**Problem**: Rate limit, authentication failure, network error + +**Solution**: +``` +โŒ ADO API Error: Unauthorized (401) + + Check your Personal Access Token (PAT): + 1. Go to https://dev.azure.com/{org}/_usersSettings/tokens + 2. Create new PAT with Work Items (Read, Write) scope + 3. Update .env: ADO_PAT=your-token +``` + +--- + +## Templates + +Use templates in `templates/` folder: + +- `epic-from-increment.md` - Epic creation template +- `feature-from-user-story.md` - Feature creation template +- `user-story-from-small-story.md` - User Story creation template +- `increment-from-epic.md` - Increment import template + +--- + +## References + +Consult references in `references/` folder: + +- `ado-concepts.md` - ADO structure (Epic, Feature, User Story, Task) +- `specweave-concepts.md` - SpecWeave structure +- `mapping-examples.md` - Real-world conversions with Area Paths and Iterations + +--- + +## Test Cases + +Validate all conversions using test cases in `test-cases/`: + +1. **test-1-increment-to-epic.yaml** - Export with Feature/User Story decision +2. **test-2-epic-to-increment.yaml** - Import with Area Path and Iteration +3. **test-3-bidirectional-sync.yaml** - Sync with ADO-specific fields + +**Run tests**: +```bash +npm run test:agents:specweave-ado-mapper +``` + +--- + +## Best Practices + +1. **Respect ADO hierarchy** - Use Feature for large work, User Story for small +2. **Store Area Path and Iteration** - Important for organizational context +3. **Handle custom workflows** - Many ADO projects customize states +4. **Use PAT securely** - Store in .env, never commit +5. **Preserve traceability** - Store ADO IDs in frontmatter, SpecWeave IDs in ADO + +--- + +## Usage Examples + +### Export to ADO + +``` +User: "Export increment 0001 to Azure DevOps" + +You: +1. Read increment files +2. Ask: "Area Path? [TeamA] [TeamB] [Custom]" +3. Ask: "Iteration? [Sprint 24] [Sprint 25] [Backlog]" +4. Create Epic +5. Decide Feature vs User Story (based on size) +6. Create Work Items +7. Update frontmatter +8. Present summary +``` + +### Import from ADO + +``` +User: "Import ADO epic 12345" + +You: +1. Fetch Epic + hierarchy +2. Extract Area Path and Iteration +3. Auto-number increment +4. Generate spec.md with ADO metadata +5. Generate tasks.md +6. Update ADO Epic with SpecWeave ID +7. Present summary +``` + +--- + +**You are the authoritative mapper between SpecWeave and Azure DevOps. Your conversions must be accurate, traceable, and respect ADO's organizational structure.**