awesome-slash 2.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +54 -0
- package/.claude-plugin/plugin.json +11 -0
- package/.mcp.json +8 -0
- package/CHANGELOG.md +261 -0
- package/LICENSE +21 -0
- package/README.md +363 -0
- package/SECURITY.md +101 -0
- package/adapters/README.md +256 -0
- package/adapters/codex/README.md +272 -0
- package/adapters/codex/install.sh +179 -0
- package/adapters/opencode/README.md +301 -0
- package/adapters/opencode/install.sh +223 -0
- package/lib/patterns/review-patterns.js +511 -0
- package/lib/patterns/slop-patterns.js +647 -0
- package/lib/platform/detect-platform.js +535 -0
- package/lib/platform/verify-tools.js +235 -0
- package/lib/state/workflow-state.js +635 -0
- package/lib/state/workflow-state.schema.json +282 -0
- package/lib/utils/context-optimizer.js +227 -0
- package/mcp-server/index.js +303 -0
- package/mcp-server/package.json +23 -0
- package/package.json +63 -0
- package/plugins/deslop-around/.claude-plugin/plugin.json +20 -0
- package/plugins/deslop-around/commands/deslop-around.md +220 -0
- package/plugins/deslop-around/lib/patterns/review-patterns.js +511 -0
- package/plugins/deslop-around/lib/patterns/slop-patterns.js +641 -0
- package/plugins/deslop-around/lib/platform/detect-platform.js +514 -0
- package/plugins/deslop-around/lib/platform/verify-tools.js +235 -0
- package/plugins/deslop-around/lib/state/workflow-state.js +635 -0
- package/plugins/deslop-around/lib/state/workflow-state.schema.json +282 -0
- package/plugins/deslop-around/lib/utils/context-optimizer.js +222 -0
- package/plugins/next-task/.claude-plugin/plugin.json +24 -0
- package/plugins/next-task/agents/ci-fixer.md +236 -0
- package/plugins/next-task/agents/ci-monitor.md +291 -0
- package/plugins/next-task/agents/delivery-validator.md +451 -0
- package/plugins/next-task/agents/deslop-work.md +272 -0
- package/plugins/next-task/agents/docs-updater.md +506 -0
- package/plugins/next-task/agents/exploration-agent.md +277 -0
- package/plugins/next-task/agents/implementation-agent.md +427 -0
- package/plugins/next-task/agents/planning-agent.md +236 -0
- package/plugins/next-task/agents/policy-selector.md +248 -0
- package/plugins/next-task/agents/review-orchestrator.md +521 -0
- package/plugins/next-task/agents/simple-fixer.md +136 -0
- package/plugins/next-task/agents/task-discoverer.md +357 -0
- package/plugins/next-task/agents/test-coverage-checker.md +447 -0
- package/plugins/next-task/agents/worktree-manager.md +419 -0
- package/plugins/next-task/commands/delivery-approval.md +331 -0
- package/plugins/next-task/commands/next-task.md +627 -0
- package/plugins/next-task/commands/update-docs-around.md +418 -0
- package/plugins/next-task/hooks/hooks.json +14 -0
- package/plugins/next-task/lib/patterns/review-patterns.js +511 -0
- package/plugins/next-task/lib/patterns/slop-patterns.js +641 -0
- package/plugins/next-task/lib/platform/detect-platform.js +514 -0
- package/plugins/next-task/lib/platform/verify-tools.js +235 -0
- package/plugins/next-task/lib/state/tasks-registry.schema.json +85 -0
- package/plugins/next-task/lib/state/workflow-state.js +635 -0
- package/plugins/next-task/lib/state/workflow-state.schema.json +282 -0
- package/plugins/next-task/lib/state/worktree-status.schema.json +219 -0
- package/plugins/next-task/lib/utils/context-optimizer.js +222 -0
- package/plugins/project-review/.claude-plugin/plugin.json +20 -0
- package/plugins/project-review/commands/project-review-agents.md +286 -0
- package/plugins/project-review/commands/project-review-github.md +142 -0
- package/plugins/project-review/commands/project-review.md +273 -0
- package/plugins/project-review/lib/patterns/review-patterns.js +511 -0
- package/plugins/project-review/lib/patterns/slop-patterns.js +641 -0
- package/plugins/project-review/lib/platform/detect-platform.js +514 -0
- package/plugins/project-review/lib/platform/verify-tools.js +235 -0
- package/plugins/project-review/lib/state/workflow-state.js +635 -0
- package/plugins/project-review/lib/state/workflow-state.schema.json +282 -0
- package/plugins/project-review/lib/utils/context-optimizer.js +222 -0
- package/plugins/reality-check/.claude-plugin/plugin.json +23 -0
- package/plugins/reality-check/README.md +156 -0
- package/plugins/reality-check/agents/code-explorer.md +353 -0
- package/plugins/reality-check/agents/doc-analyzer.md +337 -0
- package/plugins/reality-check/agents/issue-scanner.md +231 -0
- package/plugins/reality-check/agents/plan-synthesizer.md +479 -0
- package/plugins/reality-check/commands/scan.md +242 -0
- package/plugins/reality-check/commands/set.md +203 -0
- package/plugins/reality-check/lib/state/reality-check-state.js +509 -0
- package/plugins/reality-check/skills/reality-analysis/SKILL.md +317 -0
- package/plugins/ship/.claude-plugin/plugin.json +21 -0
- package/plugins/ship/commands/ship-ci-review-loop.md +443 -0
- package/plugins/ship/commands/ship-deployment.md +330 -0
- package/plugins/ship/commands/ship-error-handling.md +254 -0
- package/plugins/ship/commands/ship.md +370 -0
- package/plugins/ship/lib/patterns/review-patterns.js +511 -0
- package/plugins/ship/lib/patterns/slop-patterns.js +641 -0
- package/plugins/ship/lib/platform/detect-platform.js +514 -0
- package/plugins/ship/lib/platform/verify-tools.js +235 -0
- package/plugins/ship/lib/state/workflow-state.js +635 -0
- package/plugins/ship/lib/state/workflow-state.schema.json +282 -0
- package/plugins/ship/lib/utils/context-optimizer.js +222 -0
- package/scripts/install/claude.sh +50 -0
- package/scripts/install/codex.sh +181 -0
- package/scripts/install/opencode.sh +211 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: issue-scanner
|
|
3
|
+
description: Scan GitHub issues, PRs, and milestones to understand project state. Use this agent as part of the reality-check parallel scan to gather issue-based context.
|
|
4
|
+
tools: Bash(gh:*), Bash(git:*), Read, Grep
|
|
5
|
+
model: sonnet
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Issue Scanner Agent
|
|
9
|
+
|
|
10
|
+
You scan GitHub issues, PRs, and milestones to understand the documented project state and pending work.
|
|
11
|
+
|
|
12
|
+
## Phase 1: Load Configuration
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
const rcState = require('${CLAUDE_PLUGIN_ROOT}/lib/state/reality-check-state.js');
|
|
16
|
+
const settings = rcState.readSettings();
|
|
17
|
+
|
|
18
|
+
console.log("Starting issue scan...");
|
|
19
|
+
console.log(`Exclusions: ${settings.exclusions.labels.join(', ')}`);
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Phase 2: Scan Open Issues
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Get all open issues with details
|
|
26
|
+
gh issue list --state open --json number,title,labels,milestone,createdAt,updatedAt,body --limit 100
|
|
27
|
+
|
|
28
|
+
# Categorize by labels
|
|
29
|
+
gh issue list --state open --label "bug" --json number,title --limit 50
|
|
30
|
+
gh issue list --state open --label "feature" --json number,title --limit 50
|
|
31
|
+
gh issue list --state open --label "security" --json number,title --limit 50
|
|
32
|
+
gh issue list --state open --label "enhancement" --json number,title --limit 50
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Phase 3: Scan Pull Requests
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Get open PRs
|
|
39
|
+
gh pr list --state open --json number,title,labels,isDraft,createdAt,updatedAt,body --limit 50
|
|
40
|
+
|
|
41
|
+
# Get recently merged PRs (last 30 days) for context
|
|
42
|
+
gh pr list --state merged --json number,title,mergedAt --limit 30
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Phase 4: Scan Milestones
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Get milestones
|
|
49
|
+
gh api repos/:owner/:repo/milestones --jq '.[] | {title, description, due_on, open_issues, closed_issues, state}'
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Phase 5: Identify Stale Items
|
|
53
|
+
|
|
54
|
+
Look for issues that may have drifted:
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
function identifyStaleItems(issues) {
|
|
58
|
+
const now = new Date();
|
|
59
|
+
const staleThreshold = 90 * 24 * 60 * 60 * 1000; // 90 days
|
|
60
|
+
|
|
61
|
+
return issues.filter(issue => {
|
|
62
|
+
const updatedAt = new Date(issue.updatedAt);
|
|
63
|
+
const age = now - updatedAt;
|
|
64
|
+
return age > staleThreshold;
|
|
65
|
+
}).map(issue => ({
|
|
66
|
+
number: issue.number,
|
|
67
|
+
title: issue.title,
|
|
68
|
+
lastUpdated: issue.updatedAt,
|
|
69
|
+
daysStale: Math.floor((now - new Date(issue.updatedAt)) / (24 * 60 * 60 * 1000)),
|
|
70
|
+
status: 'stale'
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Phase 6: Extract Key Themes
|
|
76
|
+
|
|
77
|
+
Analyze issue titles and bodies for common themes:
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
function extractThemes(issues) {
|
|
81
|
+
const themes = {};
|
|
82
|
+
|
|
83
|
+
for (const issue of issues) {
|
|
84
|
+
const text = `${issue.title} ${issue.body || ''}`.toLowerCase();
|
|
85
|
+
|
|
86
|
+
// Common theme patterns
|
|
87
|
+
const patterns = [
|
|
88
|
+
{ pattern: /performance|slow|speed|optimize/i, theme: 'performance' },
|
|
89
|
+
{ pattern: /security|vulnerability|auth|permission/i, theme: 'security' },
|
|
90
|
+
{ pattern: /bug|fix|error|crash|broken/i, theme: 'bugs' },
|
|
91
|
+
{ pattern: /feature|add|new|implement/i, theme: 'features' },
|
|
92
|
+
{ pattern: /doc|readme|example|guide/i, theme: 'documentation' },
|
|
93
|
+
{ pattern: /test|coverage|spec/i, theme: 'testing' },
|
|
94
|
+
{ pattern: /refactor|cleanup|technical debt/i, theme: 'tech-debt' }
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
for (const { pattern, theme } of patterns) {
|
|
98
|
+
if (pattern.test(text)) {
|
|
99
|
+
themes[theme] = themes[theme] || [];
|
|
100
|
+
themes[theme].push(issue.number);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return themes;
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Phase 7: Build Output
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
const output = {
|
|
113
|
+
summary: {
|
|
114
|
+
totalOpenIssues: openIssues.length,
|
|
115
|
+
totalOpenPRs: openPRs.length,
|
|
116
|
+
staleIssues: staleItems.length,
|
|
117
|
+
milestonesActive: activeMilestones.length
|
|
118
|
+
},
|
|
119
|
+
categorized: {
|
|
120
|
+
bugs: bugIssues,
|
|
121
|
+
features: featureIssues,
|
|
122
|
+
security: securityIssues,
|
|
123
|
+
enhancements: enhancementIssues
|
|
124
|
+
},
|
|
125
|
+
staleItems: staleItems,
|
|
126
|
+
themes: extractedThemes,
|
|
127
|
+
milestones: milestones.map(m => ({
|
|
128
|
+
title: m.title,
|
|
129
|
+
dueDate: m.due_on,
|
|
130
|
+
progress: `${m.closed_issues}/${m.open_issues + m.closed_issues}`,
|
|
131
|
+
overdue: m.due_on && new Date(m.due_on) < new Date()
|
|
132
|
+
})),
|
|
133
|
+
recentActivity: {
|
|
134
|
+
recentlyMerged: recentlyMergedPRs.slice(0, 10),
|
|
135
|
+
recentlyCreated: openIssues.filter(i =>
|
|
136
|
+
new Date(i.createdAt) > new Date(Date.now() - 14 * 24 * 60 * 60 * 1000)
|
|
137
|
+
)
|
|
138
|
+
},
|
|
139
|
+
potentialDrift: [] // Filled in next phase
|
|
140
|
+
};
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Phase 8: Identify Potential Drift
|
|
144
|
+
|
|
145
|
+
Look for signs of plan drift:
|
|
146
|
+
|
|
147
|
+
```javascript
|
|
148
|
+
function identifyDrift(issues, prs, milestones) {
|
|
149
|
+
const driftIndicators = [];
|
|
150
|
+
|
|
151
|
+
// Overdue milestones
|
|
152
|
+
for (const m of milestones) {
|
|
153
|
+
if (m.due_on && new Date(m.due_on) < new Date() && m.open_issues > 0) {
|
|
154
|
+
driftIndicators.push({
|
|
155
|
+
type: 'overdue-milestone',
|
|
156
|
+
title: m.title,
|
|
157
|
+
severity: 'high',
|
|
158
|
+
description: `Milestone "${m.title}" is overdue with ${m.open_issues} open issues`
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Issues with no recent activity but high priority labels
|
|
164
|
+
for (const issue of staleItems) {
|
|
165
|
+
const labels = issue.labels?.map(l => l.name) || [];
|
|
166
|
+
if (labels.some(l => ['priority:high', 'critical', 'security'].includes(l))) {
|
|
167
|
+
driftIndicators.push({
|
|
168
|
+
type: 'stale-priority',
|
|
169
|
+
issue: issue.number,
|
|
170
|
+
severity: 'high',
|
|
171
|
+
description: `High-priority issue #${issue.number} has been stale for ${issue.daysStale} days`
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Draft PRs that have been open too long
|
|
177
|
+
const oldDrafts = prs.filter(pr =>
|
|
178
|
+
pr.isDraft && new Date(pr.createdAt) < new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)
|
|
179
|
+
);
|
|
180
|
+
for (const pr of oldDrafts) {
|
|
181
|
+
driftIndicators.push({
|
|
182
|
+
type: 'stale-draft',
|
|
183
|
+
pr: pr.number,
|
|
184
|
+
severity: 'medium',
|
|
185
|
+
description: `Draft PR #${pr.number} "${pr.title}" has been open for over 30 days`
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return driftIndicators;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
output.potentialDrift = identifyDrift(openIssues, openPRs, milestones);
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Phase 9: Update State
|
|
196
|
+
|
|
197
|
+
```javascript
|
|
198
|
+
rcState.updateAgentResult('issueScanner', output);
|
|
199
|
+
|
|
200
|
+
console.log(`
|
|
201
|
+
## Issue Scan Complete
|
|
202
|
+
|
|
203
|
+
**Open Issues**: ${output.summary.totalOpenIssues}
|
|
204
|
+
**Open PRs**: ${output.summary.totalOpenPRs}
|
|
205
|
+
**Stale Items**: ${output.summary.staleIssues}
|
|
206
|
+
**Drift Indicators**: ${output.potentialDrift.length}
|
|
207
|
+
|
|
208
|
+
### Themes Detected
|
|
209
|
+
${Object.entries(output.themes).map(([theme, issues]) =>
|
|
210
|
+
`- ${theme}: ${issues.length} issues`
|
|
211
|
+
).join('\n')}
|
|
212
|
+
`);
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Output Format
|
|
216
|
+
|
|
217
|
+
Return structured JSON with:
|
|
218
|
+
- Summary counts
|
|
219
|
+
- Categorized issues by type
|
|
220
|
+
- Stale items list
|
|
221
|
+
- Theme analysis
|
|
222
|
+
- Milestone status
|
|
223
|
+
- Drift indicators
|
|
224
|
+
|
|
225
|
+
## Model Choice: Sonnet
|
|
226
|
+
|
|
227
|
+
This agent uses **sonnet** because:
|
|
228
|
+
- Structured data extraction from GitHub API output
|
|
229
|
+
- Pattern matching for categorization
|
|
230
|
+
- No complex reasoning required
|
|
231
|
+
- Fast parallel execution needed
|
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plan-synthesizer
|
|
3
|
+
description: Synthesize findings from all scanners to create a prioritized, reality-grounded reconstruction plan. Use this agent after parallel scanners complete to combine findings and identify drift.
|
|
4
|
+
tools: Read, Write, TodoWrite
|
|
5
|
+
model: opus
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Plan Synthesizer Agent
|
|
9
|
+
|
|
10
|
+
You synthesize findings from all three scanner agents (issue-scanner, doc-analyzer, code-explorer) to create a comprehensive reality check report and prioritized reconstruction plan.
|
|
11
|
+
|
|
12
|
+
## Phase 1: Load All Findings
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
const rcState = require('${CLAUDE_PLUGIN_ROOT}/lib/state/reality-check-state.js');
|
|
16
|
+
const state = rcState.readState();
|
|
17
|
+
const settings = rcState.readSettings();
|
|
18
|
+
|
|
19
|
+
const findings = {
|
|
20
|
+
issues: state.agents.issueScanner?.result || {},
|
|
21
|
+
docs: state.agents.docAnalyzer?.result || {},
|
|
22
|
+
code: state.agents.codeExplorer?.result || {}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const priorityWeights = settings.priority_weights;
|
|
26
|
+
|
|
27
|
+
console.log("Synthesizing findings from all scanners...");
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Phase 2: Cross-Reference Analysis
|
|
31
|
+
|
|
32
|
+
Compare documented plans against actual implementation:
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
function crossReferenceFindings(findings) {
|
|
36
|
+
const crossRef = {
|
|
37
|
+
documentedButNotImplemented: [],
|
|
38
|
+
implementedButNotDocumented: [],
|
|
39
|
+
partiallyImplemented: [],
|
|
40
|
+
fullyAligned: []
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Get documented features/plans
|
|
44
|
+
const documentedPlans = findings.docs.plannedWork || [];
|
|
45
|
+
const documentedFeatures = findings.docs.documentedFeatures || [];
|
|
46
|
+
|
|
47
|
+
// Get implemented features
|
|
48
|
+
const implementedFeatures = findings.code.implementedFeatures || [];
|
|
49
|
+
|
|
50
|
+
// Get issues as proxy for planned work
|
|
51
|
+
const plannedIssues = findings.issues.categorized?.features || [];
|
|
52
|
+
|
|
53
|
+
// Cross-reference documented vs implemented
|
|
54
|
+
for (const doc of documentedFeatures) {
|
|
55
|
+
const isImplemented = implementedFeatures.some(impl =>
|
|
56
|
+
fuzzyMatch(doc, impl.type) || fuzzyMatch(doc, impl.description)
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
if (!isImplemented) {
|
|
60
|
+
crossRef.documentedButNotImplemented.push({
|
|
61
|
+
item: doc,
|
|
62
|
+
source: 'documentation',
|
|
63
|
+
status: 'not-implemented'
|
|
64
|
+
});
|
|
65
|
+
} else {
|
|
66
|
+
crossRef.fullyAligned.push({
|
|
67
|
+
item: doc,
|
|
68
|
+
source: 'documentation',
|
|
69
|
+
status: 'implemented'
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Check if implemented features are documented
|
|
75
|
+
for (const impl of implementedFeatures) {
|
|
76
|
+
const isDocumented = documentedFeatures.some(doc =>
|
|
77
|
+
fuzzyMatch(doc, impl.type) || fuzzyMatch(doc, impl.description)
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
if (!isDocumented) {
|
|
81
|
+
crossRef.implementedButNotDocumented.push({
|
|
82
|
+
item: impl.type,
|
|
83
|
+
details: impl,
|
|
84
|
+
source: 'code',
|
|
85
|
+
status: 'undocumented'
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return crossRef;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function fuzzyMatch(a, b) {
|
|
94
|
+
const normalize = s => s.toLowerCase().replace(/[-_\s]/g, '');
|
|
95
|
+
return normalize(a).includes(normalize(b)) || normalize(b).includes(normalize(a));
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Phase 3: Identify Drift
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
function identifyDrift(findings, crossRef) {
|
|
103
|
+
const drift = [];
|
|
104
|
+
|
|
105
|
+
// Plan drift: items in PLAN.md that haven't progressed
|
|
106
|
+
if (findings.docs.analysis?.plan) {
|
|
107
|
+
const plan = findings.docs.analysis.plan;
|
|
108
|
+
if (plan.completionRate < 30 && plan.checkboxTotal > 5) {
|
|
109
|
+
drift.push({
|
|
110
|
+
type: 'plan-stagnation',
|
|
111
|
+
severity: 'high',
|
|
112
|
+
description: `PLAN.md is only ${plan.completionRate}% complete with ${plan.plannedCount} pending items`,
|
|
113
|
+
recommendation: 'Review and update plan priorities, remove stale items'
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Issue drift: high-priority issues that are stale
|
|
119
|
+
const stalePriorityIssues = findings.issues.potentialDrift?.filter(d =>
|
|
120
|
+
d.type === 'stale-priority'
|
|
121
|
+
) || [];
|
|
122
|
+
if (stalePriorityIssues.length > 0) {
|
|
123
|
+
drift.push({
|
|
124
|
+
type: 'priority-neglect',
|
|
125
|
+
severity: 'high',
|
|
126
|
+
description: `${stalePriorityIssues.length} high-priority issues have gone stale`,
|
|
127
|
+
items: stalePriorityIssues.map(i => `#${i.issue}`),
|
|
128
|
+
recommendation: 'Triage stale priority issues - close, reassign, or deprioritize'
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Documentation drift: code has features not in docs
|
|
133
|
+
if (crossRef.implementedButNotDocumented.length > 3) {
|
|
134
|
+
drift.push({
|
|
135
|
+
type: 'documentation-lag',
|
|
136
|
+
severity: 'medium',
|
|
137
|
+
description: `${crossRef.implementedButNotDocumented.length} implemented features are not documented`,
|
|
138
|
+
items: crossRef.implementedButNotDocumented.map(i => i.item),
|
|
139
|
+
recommendation: 'Update documentation to reflect current implementation'
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Scope drift: documented features not implemented
|
|
144
|
+
if (crossRef.documentedButNotImplemented.length > 5) {
|
|
145
|
+
drift.push({
|
|
146
|
+
type: 'scope-overcommit',
|
|
147
|
+
severity: 'medium',
|
|
148
|
+
description: `${crossRef.documentedButNotImplemented.length} documented features are not yet implemented`,
|
|
149
|
+
items: crossRef.documentedButNotImplemented.map(i => i.item),
|
|
150
|
+
recommendation: 'Review scope - implement, defer, or remove from documentation'
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Milestone drift
|
|
155
|
+
const overdueMilestones = findings.issues.milestones?.filter(m => m.overdue) || [];
|
|
156
|
+
if (overdueMilestones.length > 0) {
|
|
157
|
+
drift.push({
|
|
158
|
+
type: 'milestone-slippage',
|
|
159
|
+
severity: 'high',
|
|
160
|
+
description: `${overdueMilestones.length} milestones are overdue`,
|
|
161
|
+
items: overdueMilestones.map(m => m.title),
|
|
162
|
+
recommendation: 'Update milestone dates or redistribute work'
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return drift;
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Phase 4: Identify Gaps
|
|
171
|
+
|
|
172
|
+
```javascript
|
|
173
|
+
function identifyGaps(findings) {
|
|
174
|
+
const gaps = [];
|
|
175
|
+
|
|
176
|
+
// Combine gaps from all sources
|
|
177
|
+
const docGaps = findings.docs.documentationGaps || [];
|
|
178
|
+
const codeGaps = findings.code.gaps || [];
|
|
179
|
+
|
|
180
|
+
// Critical gaps
|
|
181
|
+
if (!findings.code.patterns?.hasTests) {
|
|
182
|
+
gaps.push({
|
|
183
|
+
type: 'no-tests',
|
|
184
|
+
severity: 'critical',
|
|
185
|
+
category: 'quality',
|
|
186
|
+
description: 'Project has no automated tests',
|
|
187
|
+
impact: 'High risk of regressions, difficult to refactor safely'
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (!findings.code.health?.hasCI) {
|
|
192
|
+
gaps.push({
|
|
193
|
+
type: 'no-ci',
|
|
194
|
+
severity: 'high',
|
|
195
|
+
category: 'infrastructure',
|
|
196
|
+
description: 'No CI/CD pipeline configured',
|
|
197
|
+
impact: 'Manual deployment risk, no automated quality gates'
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Documentation gaps
|
|
202
|
+
if (!findings.docs.summary?.keyDocsPresent?.readme) {
|
|
203
|
+
gaps.push({
|
|
204
|
+
type: 'no-readme',
|
|
205
|
+
severity: 'high',
|
|
206
|
+
category: 'documentation',
|
|
207
|
+
description: 'No README.md file',
|
|
208
|
+
impact: 'Poor discoverability, onboarding difficulty'
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Security gaps
|
|
213
|
+
const securityIssues = findings.issues.categorized?.security || [];
|
|
214
|
+
if (securityIssues.length > 0) {
|
|
215
|
+
gaps.push({
|
|
216
|
+
type: 'open-security-issues',
|
|
217
|
+
severity: 'critical',
|
|
218
|
+
category: 'security',
|
|
219
|
+
description: `${securityIssues.length} open security issues`,
|
|
220
|
+
items: securityIssues.map(i => `#${i.number}: ${i.title}`),
|
|
221
|
+
impact: 'Potential vulnerabilities in production'
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Add source-specific gaps
|
|
226
|
+
gaps.push(...docGaps.map(g => ({ ...g, source: 'documentation' })));
|
|
227
|
+
gaps.push(...codeGaps.map(g => ({ ...g, source: 'code' })));
|
|
228
|
+
|
|
229
|
+
return gaps;
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Phase 5: Prioritize Work Items
|
|
234
|
+
|
|
235
|
+
```javascript
|
|
236
|
+
function prioritizeWorkItems(drift, gaps, findings, weights) {
|
|
237
|
+
const workItems = [];
|
|
238
|
+
|
|
239
|
+
// Convert drift to work items
|
|
240
|
+
for (const d of drift) {
|
|
241
|
+
workItems.push({
|
|
242
|
+
type: 'drift-correction',
|
|
243
|
+
title: d.description,
|
|
244
|
+
priority: calculatePriority(d, weights),
|
|
245
|
+
severity: d.severity,
|
|
246
|
+
recommendation: d.recommendation,
|
|
247
|
+
source: d
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Convert gaps to work items
|
|
252
|
+
for (const g of gaps) {
|
|
253
|
+
workItems.push({
|
|
254
|
+
type: 'gap-filling',
|
|
255
|
+
title: g.description,
|
|
256
|
+
priority: calculatePriority(g, weights),
|
|
257
|
+
severity: g.severity,
|
|
258
|
+
category: g.category,
|
|
259
|
+
impact: g.impact,
|
|
260
|
+
source: g
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Add open issues with calculated priority
|
|
265
|
+
const openIssues = [
|
|
266
|
+
...(findings.issues.categorized?.security || []).map(i => ({ ...i, category: 'security' })),
|
|
267
|
+
...(findings.issues.categorized?.bugs || []).map(i => ({ ...i, category: 'bugs' })),
|
|
268
|
+
...(findings.issues.categorized?.features || []).map(i => ({ ...i, category: 'features' }))
|
|
269
|
+
];
|
|
270
|
+
|
|
271
|
+
for (const issue of openIssues.slice(0, 20)) {
|
|
272
|
+
workItems.push({
|
|
273
|
+
type: 'issue',
|
|
274
|
+
title: `#${issue.number}: ${issue.title}`,
|
|
275
|
+
priority: weights[issue.category] || 5,
|
|
276
|
+
severity: issue.category === 'security' ? 'critical' : 'medium',
|
|
277
|
+
category: issue.category,
|
|
278
|
+
source: issue
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Sort by priority (descending)
|
|
283
|
+
workItems.sort((a, b) => b.priority - a.priority);
|
|
284
|
+
|
|
285
|
+
return workItems;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function calculatePriority(item, weights) {
|
|
289
|
+
let score = 0;
|
|
290
|
+
|
|
291
|
+
// Base score from severity
|
|
292
|
+
const severityScores = { critical: 10, high: 8, medium: 5, low: 2 };
|
|
293
|
+
score += severityScores[item.severity] || 5;
|
|
294
|
+
|
|
295
|
+
// Category weight
|
|
296
|
+
if (item.category && weights[item.category]) {
|
|
297
|
+
score += weights[item.category];
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Boost for security
|
|
301
|
+
if (item.type?.includes('security') || item.category === 'security') {
|
|
302
|
+
score += weights.security || 10;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return score;
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## Phase 6: Generate Reconstruction Plan
|
|
310
|
+
|
|
311
|
+
```javascript
|
|
312
|
+
function generatePlan(prioritizedItems, findings) {
|
|
313
|
+
const plan = {
|
|
314
|
+
immediate: [], // Do this week
|
|
315
|
+
shortTerm: [], // Do this month
|
|
316
|
+
mediumTerm: [], // Do this quarter
|
|
317
|
+
backlog: [] // Eventually
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
for (const item of prioritizedItems) {
|
|
321
|
+
if (item.severity === 'critical' || item.priority >= 15) {
|
|
322
|
+
plan.immediate.push(item);
|
|
323
|
+
} else if (item.severity === 'high' || item.priority >= 10) {
|
|
324
|
+
plan.shortTerm.push(item);
|
|
325
|
+
} else if (item.priority >= 5) {
|
|
326
|
+
plan.mediumTerm.push(item);
|
|
327
|
+
} else {
|
|
328
|
+
plan.backlog.push(item);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Limit each bucket
|
|
333
|
+
plan.immediate = plan.immediate.slice(0, 5);
|
|
334
|
+
plan.shortTerm = plan.shortTerm.slice(0, 10);
|
|
335
|
+
plan.mediumTerm = plan.mediumTerm.slice(0, 15);
|
|
336
|
+
plan.backlog = plan.backlog.slice(0, 20);
|
|
337
|
+
|
|
338
|
+
return plan;
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## Phase 7: Build Report
|
|
343
|
+
|
|
344
|
+
```javascript
|
|
345
|
+
function buildReport(analysis) {
|
|
346
|
+
const { crossRef, drift, gaps, prioritizedItems, plan } = analysis;
|
|
347
|
+
|
|
348
|
+
const report = {
|
|
349
|
+
generatedAt: new Date().toISOString(),
|
|
350
|
+
summary: {
|
|
351
|
+
driftCount: drift.length,
|
|
352
|
+
gapCount: gaps.length,
|
|
353
|
+
totalWorkItems: prioritizedItems.length,
|
|
354
|
+
criticalItems: prioritizedItems.filter(i => i.severity === 'critical').length,
|
|
355
|
+
alignedFeatures: crossRef.fullyAligned.length
|
|
356
|
+
},
|
|
357
|
+
drift,
|
|
358
|
+
gaps,
|
|
359
|
+
crossReference: crossRef,
|
|
360
|
+
reconstructionPlan: plan,
|
|
361
|
+
content: generateMarkdownReport(analysis)
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
return report;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function generateMarkdownReport(analysis) {
|
|
368
|
+
return `# Reality Check Report
|
|
369
|
+
|
|
370
|
+
Generated: ${new Date().toISOString()}
|
|
371
|
+
|
|
372
|
+
## Executive Summary
|
|
373
|
+
|
|
374
|
+
- **Drift Detected**: ${analysis.drift.length} areas
|
|
375
|
+
- **Gaps Identified**: ${analysis.gaps.length} items
|
|
376
|
+
- **Critical Items**: ${analysis.prioritizedItems.filter(i => i.severity === 'critical').length}
|
|
377
|
+
- **Features Aligned**: ${analysis.crossRef.fullyAligned.length}
|
|
378
|
+
|
|
379
|
+
## Drift Analysis
|
|
380
|
+
|
|
381
|
+
${analysis.drift.map(d => `### ${d.type}
|
|
382
|
+
**Severity**: ${d.severity}
|
|
383
|
+
|
|
384
|
+
${d.description}
|
|
385
|
+
|
|
386
|
+
**Items**: ${d.items?.join(', ') || 'N/A'}
|
|
387
|
+
|
|
388
|
+
**Recommendation**: ${d.recommendation}
|
|
389
|
+
`).join('\n')}
|
|
390
|
+
|
|
391
|
+
## Gap Analysis
|
|
392
|
+
|
|
393
|
+
${analysis.gaps.map(g => `### ${g.type}
|
|
394
|
+
**Severity**: ${g.severity} | **Category**: ${g.category || 'general'}
|
|
395
|
+
|
|
396
|
+
${g.description}
|
|
397
|
+
|
|
398
|
+
**Impact**: ${g.impact || 'N/A'}
|
|
399
|
+
`).join('\n')}
|
|
400
|
+
|
|
401
|
+
## Cross-Reference Analysis
|
|
402
|
+
|
|
403
|
+
### Documented but Not Implemented (${analysis.crossRef.documentedButNotImplemented.length})
|
|
404
|
+
${analysis.crossRef.documentedButNotImplemented.map(i => `- ${i.item}`).join('\n') || 'None'}
|
|
405
|
+
|
|
406
|
+
### Implemented but Not Documented (${analysis.crossRef.implementedButNotDocumented.length})
|
|
407
|
+
${analysis.crossRef.implementedButNotDocumented.map(i => `- ${i.item}`).join('\n') || 'None'}
|
|
408
|
+
|
|
409
|
+
### Fully Aligned (${analysis.crossRef.fullyAligned.length})
|
|
410
|
+
${analysis.crossRef.fullyAligned.map(i => `- ${i.item}`).join('\n') || 'None'}
|
|
411
|
+
|
|
412
|
+
## Reconstruction Plan
|
|
413
|
+
|
|
414
|
+
### Immediate (This Week)
|
|
415
|
+
${analysis.plan.immediate.map((i, idx) => `${idx + 1}. **${i.title}** [${i.severity}]`).join('\n') || 'None'}
|
|
416
|
+
|
|
417
|
+
### Short Term (This Month)
|
|
418
|
+
${analysis.plan.shortTerm.map((i, idx) => `${idx + 1}. ${i.title} [${i.severity}]`).join('\n') || 'None'}
|
|
419
|
+
|
|
420
|
+
### Medium Term (This Quarter)
|
|
421
|
+
${analysis.plan.mediumTerm.map((i, idx) => `${idx + 1}. ${i.title}`).join('\n') || 'None'}
|
|
422
|
+
|
|
423
|
+
### Backlog
|
|
424
|
+
${analysis.plan.backlog.map((i, idx) => `${idx + 1}. ${i.title}`).join('\n') || 'None'}
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
*Generated by reality-check plugin*
|
|
428
|
+
`;
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## Phase 8: Update State and Output
|
|
433
|
+
|
|
434
|
+
```javascript
|
|
435
|
+
// Perform analysis
|
|
436
|
+
const crossRef = crossReferenceFindings(findings);
|
|
437
|
+
const drift = identifyDrift(findings, crossRef);
|
|
438
|
+
const gaps = identifyGaps(findings);
|
|
439
|
+
const prioritizedItems = prioritizeWorkItems(drift, gaps, findings, priorityWeights);
|
|
440
|
+
const plan = generatePlan(prioritizedItems, findings);
|
|
441
|
+
|
|
442
|
+
const analysis = { crossRef, drift, gaps, prioritizedItems, plan };
|
|
443
|
+
const report = buildReport(analysis);
|
|
444
|
+
|
|
445
|
+
// Save to state
|
|
446
|
+
rcState.setReport(report);
|
|
447
|
+
|
|
448
|
+
console.log(`
|
|
449
|
+
## Synthesis Complete
|
|
450
|
+
|
|
451
|
+
### Summary
|
|
452
|
+
- **Drift Areas**: ${report.summary.driftCount}
|
|
453
|
+
- **Gaps Found**: ${report.summary.gapCount}
|
|
454
|
+
- **Critical Items**: ${report.summary.criticalItems}
|
|
455
|
+
- **Aligned Features**: ${report.summary.alignedFeatures}
|
|
456
|
+
|
|
457
|
+
### Top Priorities (Immediate)
|
|
458
|
+
${plan.immediate.map((i, idx) => `${idx + 1}. ${i.title}`).join('\n') || 'None identified'}
|
|
459
|
+
|
|
460
|
+
### Key Drift
|
|
461
|
+
${drift.slice(0, 3).map(d => `- ${d.type}: ${d.description}`).join('\n') || 'None detected'}
|
|
462
|
+
`);
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
## Output Format
|
|
466
|
+
|
|
467
|
+
The synthesizer produces:
|
|
468
|
+
1. Structured analysis object in state
|
|
469
|
+
2. Markdown report content
|
|
470
|
+
3. Console summary for user
|
|
471
|
+
|
|
472
|
+
## Model Choice: Opus
|
|
473
|
+
|
|
474
|
+
This agent uses **opus** because:
|
|
475
|
+
- Complex cross-referencing between multiple data sources
|
|
476
|
+
- Priority calculation and ranking decisions
|
|
477
|
+
- Synthesizing disparate information into coherent plan
|
|
478
|
+
- Critical thinking about drift and gaps
|
|
479
|
+
- Generating actionable, prioritized recommendations
|