specweave 0.24.8 → 0.24.9
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/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +3 -1
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js +18 -2
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js.map +1 -1
- package/dist/src/core/repo-structure/git-error-handler.d.ts +1 -1
- package/dist/src/core/repo-structure/git-error-handler.d.ts.map +1 -1
- package/dist/src/core/repo-structure/git-provider.d.ts +1 -1
- package/dist/src/core/repo-structure/git-provider.d.ts.map +1 -1
- package/dist/src/core/repo-structure/platform-registry.d.ts.map +1 -1
- package/dist/src/core/repo-structure/platform-registry.js +20 -9
- package/dist/src/core/repo-structure/platform-registry.js.map +1 -1
- package/dist/src/core/repo-structure/prompt-consolidator.d.ts +13 -1
- package/dist/src/core/repo-structure/prompt-consolidator.d.ts.map +1 -1
- package/dist/src/core/repo-structure/prompt-consolidator.js +38 -5
- package/dist/src/core/repo-structure/prompt-consolidator.js.map +1 -1
- package/dist/src/core/repo-structure/providers/azure-devops-provider.d.ts +64 -0
- package/dist/src/core/repo-structure/providers/azure-devops-provider.d.ts.map +1 -0
- package/dist/src/core/repo-structure/providers/azure-devops-provider.js +263 -0
- package/dist/src/core/repo-structure/providers/azure-devops-provider.js.map +1 -0
- package/dist/src/core/repo-structure/providers/bitbucket-provider.d.ts +12 -11
- package/dist/src/core/repo-structure/providers/bitbucket-provider.d.ts.map +1 -1
- package/dist/src/core/repo-structure/providers/bitbucket-provider.js +164 -30
- package/dist/src/core/repo-structure/providers/bitbucket-provider.js.map +1 -1
- package/dist/src/core/repo-structure/providers/gitlab-provider.d.ts +10 -9
- package/dist/src/core/repo-structure/providers/gitlab-provider.d.ts.map +1 -1
- package/dist/src/core/repo-structure/providers/gitlab-provider.js +182 -28
- package/dist/src/core/repo-structure/providers/gitlab-provider.js.map +1 -1
- package/dist/src/core/repo-structure/providers/index.d.ts +3 -1
- package/dist/src/core/repo-structure/providers/index.d.ts.map +1 -1
- package/dist/src/core/repo-structure/providers/index.js +10 -2
- package/dist/src/core/repo-structure/providers/index.js.map +1 -1
- package/dist/src/core/repo-structure/providers/local-provider.d.ts +61 -0
- package/dist/src/core/repo-structure/providers/local-provider.d.ts.map +1 -0
- package/dist/src/core/repo-structure/providers/local-provider.js +148 -0
- package/dist/src/core/repo-structure/providers/local-provider.js.map +1 -0
- package/dist/src/core/repo-structure/repo-structure-manager.d.ts +11 -1
- package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.js +268 -84
- package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/agents/pm/AGENT.md.bak +1893 -0
- package/plugins/specweave/hooks/docs-changed.sh.backup +79 -0
- package/plugins/specweave/hooks/human-input-required.sh.backup +75 -0
- package/plugins/specweave/hooks/lib/migrate-increment-work.sh.bak +245 -0
- package/plugins/specweave/hooks/lib/sync-spec-content.sh.bak +149 -0
- package/plugins/specweave/hooks/lib/validate-spec-status.sh.bak +163 -0
- package/plugins/specweave/hooks/post-first-increment.sh.backup +61 -0
- package/plugins/specweave/hooks/post-first-increment.sh.bak +61 -0
- package/plugins/specweave/hooks/post-increment-change.sh.backup +98 -0
- package/plugins/specweave/hooks/post-increment-completion.sh.backup +231 -0
- package/plugins/specweave/hooks/post-increment-planning.sh.backup +1048 -0
- package/plugins/specweave/hooks/post-increment-status-change.sh.backup +147 -0
- package/plugins/specweave/hooks/post-spec-update.sh.backup +158 -0
- package/plugins/specweave/hooks/post-spec-update.sh.bak +158 -0
- package/plugins/specweave/hooks/post-task-completion.sh +69 -175
- package/plugins/specweave/hooks/post-user-story-complete.sh.backup +179 -0
- package/plugins/specweave/hooks/post-user-story-complete.sh.bak +179 -0
- package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +83 -0
- package/plugins/specweave/hooks/pre-command-deduplication.sh.bak +83 -0
- package/plugins/specweave/hooks/pre-implementation.sh.backup +67 -0
- package/plugins/specweave/hooks/pre-task-completion.sh.backup +194 -0
- package/plugins/specweave/hooks/pre-tool-use.sh.backup +133 -0
- package/plugins/specweave/hooks/user-prompt-submit.sh.backup +386 -0
- package/plugins/specweave/hooks/user-prompt-submit.sh.bak +386 -0
- package/plugins/specweave/lib/hooks/auto-transition.js.bak +50 -0
- package/plugins/specweave/lib/hooks/auto-transition.ts.bak +84 -0
- package/plugins/specweave/lib/hooks/consolidated-sync.js +183 -0
- package/plugins/specweave/lib/hooks/git-diff-analyzer.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/git-diff-analyzer.d.ts.bak +89 -0
- package/plugins/specweave/lib/hooks/git-diff-analyzer.js.bak +142 -0
- package/plugins/specweave/lib/hooks/git-diff-analyzer.ts.bak +269 -0
- package/plugins/specweave/lib/hooks/invoke-translator-skill.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/invoke-translator-skill.d.ts.bak +60 -0
- package/plugins/specweave/lib/hooks/invoke-translator-skill.js.bak +155 -0
- package/plugins/specweave/lib/hooks/invoke-translator-skill.ts.bak +264 -0
- package/plugins/specweave/lib/hooks/prepare-reflection-context.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/prepare-reflection-context.d.ts.bak +42 -0
- package/plugins/specweave/lib/hooks/prepare-reflection-context.js.bak +110 -0
- package/plugins/specweave/lib/hooks/prepare-reflection-context.ts.bak +178 -0
- package/plugins/specweave/lib/hooks/reflection-config-loader.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-config-loader.d.ts.bak +45 -0
- package/plugins/specweave/lib/hooks/reflection-config-loader.js.bak +92 -0
- package/plugins/specweave/lib/hooks/reflection-config-loader.ts.bak +156 -0
- package/plugins/specweave/lib/hooks/reflection-parser.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-parser.d.ts.bak +33 -0
- package/plugins/specweave/lib/hooks/reflection-parser.js.bak +301 -0
- package/plugins/specweave/lib/hooks/reflection-parser.ts.bak +484 -0
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.d.ts.bak +56 -0
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.js.bak +182 -0
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.ts.bak +306 -0
- package/plugins/specweave/lib/hooks/reflection-storage.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-storage.d.ts.bak +64 -0
- package/plugins/specweave/lib/hooks/reflection-storage.js.bak +231 -0
- package/plugins/specweave/lib/hooks/reflection-storage.ts.bak +369 -0
- package/plugins/specweave/lib/hooks/run-self-reflection.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/run-self-reflection.d.ts.bak +43 -0
- package/plugins/specweave/lib/hooks/run-self-reflection.js.bak +132 -0
- package/plugins/specweave/lib/hooks/run-self-reflection.ts.bak +258 -0
- package/plugins/specweave/lib/hooks/sync-cache.js.bak +294 -0
- package/plugins/specweave/lib/hooks/sync-living-docs.d.js.bak +1 -0
- package/plugins/specweave/lib/hooks/sync-living-docs.d.ts.bak +27 -0
- package/plugins/specweave/lib/hooks/sync-living-docs.js.bak +339 -0
- package/plugins/specweave/lib/hooks/sync-us-tasks.js.bak +476 -0
- package/plugins/specweave/lib/hooks/translate-file.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/translate-file.d.ts.bak +59 -0
- package/plugins/specweave/lib/hooks/translate-file.js.bak +289 -0
- package/plugins/specweave/lib/hooks/translate-file.ts.bak +428 -0
- package/plugins/specweave/lib/hooks/translate-living-docs.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/translate-living-docs.d.ts.bak +13 -0
- package/plugins/specweave/lib/hooks/translate-living-docs.js.bak +119 -0
- package/plugins/specweave/lib/hooks/translate-living-docs.ts.bak +224 -0
- package/plugins/specweave/lib/hooks/update-ac-status.js.bak +51 -0
- package/plugins/specweave/lib/hooks/update-ac-status.ts.bak +103 -0
- package/plugins/specweave/lib/hooks/update-tasks-md.d.js.bak +1 -0
- package/plugins/specweave/lib/hooks/update-tasks-md.d.ts.bak +29 -0
- package/plugins/specweave/lib/hooks/update-tasks-md.js.bak +296 -0
- package/plugins/specweave/lib/hooks/update-tasks-md.ts.bak +489 -0
- package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +353 -0
- package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +172 -0
- package/plugins/specweave-ado/lib/ado-multi-project-sync.js +1 -0
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +424 -0
- package/plugins/specweave-github/hooks/post-task-completion.sh.backup +258 -0
- package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +172 -0
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +540 -0
- package/plugins/specweave-release/hooks/post-task-completion.sh.backup +110 -0
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reflection Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses markdown output from reflective-reviewer agent
|
|
5
|
+
* Extracts structured data (issues, metrics, lessons learned, etc.)
|
|
6
|
+
*
|
|
7
|
+
* @module reflection-parser
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
ReflectionResult,
|
|
12
|
+
ReflectionIssue,
|
|
13
|
+
IssueSeverity,
|
|
14
|
+
IssueCategory,
|
|
15
|
+
LessonLearned,
|
|
16
|
+
ReflectionMetrics,
|
|
17
|
+
ReflectionModel
|
|
18
|
+
} from './types/reflection-types';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Extract section content by heading
|
|
22
|
+
* @param markdown Markdown content
|
|
23
|
+
* @param heading Section heading to find (e.g., "## What Was Accomplished")
|
|
24
|
+
* @returns Section content (text after heading until next heading or end)
|
|
25
|
+
*/
|
|
26
|
+
function extractSection(markdown: string, heading: string): string {
|
|
27
|
+
const headingRegex = new RegExp(`^${heading}\\s*$`, 'mi');
|
|
28
|
+
const match = markdown.match(headingRegex);
|
|
29
|
+
|
|
30
|
+
if (!match || match.index === undefined) {
|
|
31
|
+
return '';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const startIndex = match.index + match[0].length;
|
|
35
|
+
const afterHeading = markdown.slice(startIndex);
|
|
36
|
+
|
|
37
|
+
// Find next heading at same or higher level
|
|
38
|
+
const nextHeadingMatch = afterHeading.match(/^#{1,3}\s+/m);
|
|
39
|
+
const endIndex = nextHeadingMatch?.index ?? afterHeading.length;
|
|
40
|
+
|
|
41
|
+
return afterHeading.slice(0, endIndex).trim();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Parse accomplishments from "What Was Accomplished" section
|
|
46
|
+
* @param markdown Reflection markdown
|
|
47
|
+
* @returns Array of accomplishment strings
|
|
48
|
+
*/
|
|
49
|
+
function parseAccomplishments(markdown: string): string[] {
|
|
50
|
+
const section = extractSection(markdown, '## ✅ What Was Accomplished');
|
|
51
|
+
if (!section) return [];
|
|
52
|
+
|
|
53
|
+
// Extract bullet points and paragraphs
|
|
54
|
+
const lines = section.split('\n').filter(line => line.trim());
|
|
55
|
+
const accomplishments: string[] = [];
|
|
56
|
+
|
|
57
|
+
for (const line of lines) {
|
|
58
|
+
const trimmed = line.trim();
|
|
59
|
+
// Match bullet points (-, *, +) or numbered lists (1., 2.)
|
|
60
|
+
if (/^[-*+]\s+/.test(trimmed) || /^\d+\.\s+/.test(trimmed)) {
|
|
61
|
+
accomplishments.push(trimmed.replace(/^[-*+\d.]\s+/, '').trim());
|
|
62
|
+
} else if (trimmed.length > 10 && !trimmed.startsWith('#')) {
|
|
63
|
+
// Include non-heading paragraphs
|
|
64
|
+
accomplishments.push(trimmed);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return accomplishments;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Parse strengths from "Quality Assessment" section
|
|
73
|
+
* @param markdown Reflection markdown
|
|
74
|
+
* @returns Array of strength strings
|
|
75
|
+
*/
|
|
76
|
+
function parseStrengths(markdown: string): string[] {
|
|
77
|
+
const section = extractSection(markdown, '### ✅ Strengths');
|
|
78
|
+
if (!section) return [];
|
|
79
|
+
|
|
80
|
+
const lines = section.split('\n').filter(line => line.trim());
|
|
81
|
+
const strengths: string[] = [];
|
|
82
|
+
|
|
83
|
+
for (const line of lines) {
|
|
84
|
+
const trimmed = line.trim();
|
|
85
|
+
if (trimmed.startsWith('- ✅') || trimmed.startsWith('✅')) {
|
|
86
|
+
strengths.push(trimmed.replace(/^[-*+]?\s*✅\s*/, '').trim());
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return strengths;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Parse severity from issue description
|
|
95
|
+
* @param text Issue text (e.g., "**CRITICAL (SECURITY)**")
|
|
96
|
+
* @returns Issue severity enum or undefined
|
|
97
|
+
*/
|
|
98
|
+
function parseSeverity(text: string): IssueSeverity | undefined {
|
|
99
|
+
if (/CRITICAL/i.test(text)) return IssueSeverity.CRITICAL;
|
|
100
|
+
if (/HIGH/i.test(text)) return IssueSeverity.HIGH;
|
|
101
|
+
if (/MEDIUM/i.test(text)) return IssueSeverity.MEDIUM;
|
|
102
|
+
if (/LOW/i.test(text)) return IssueSeverity.LOW;
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Parse category from issue description
|
|
108
|
+
* @param text Issue text (e.g., "**CRITICAL (SECURITY)**")
|
|
109
|
+
* @returns Issue category enum or undefined
|
|
110
|
+
*/
|
|
111
|
+
function parseCategory(text: string): IssueCategory | undefined {
|
|
112
|
+
if (/SECURITY/i.test(text)) return IssueCategory.SECURITY;
|
|
113
|
+
if (/QUALITY/i.test(text)) return IssueCategory.QUALITY;
|
|
114
|
+
if (/TESTING/i.test(text)) return IssueCategory.TESTING;
|
|
115
|
+
if (/PERFORMANCE/i.test(text)) return IssueCategory.PERFORMANCE;
|
|
116
|
+
if (/TECHNICAL[_\s]DEBT/i.test(text)) return IssueCategory.TECHNICAL_DEBT;
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Parse location from issue text
|
|
122
|
+
* @param text Issue text (may contain **Location**: `path/to/file.ts:123`)
|
|
123
|
+
* @returns Location object or undefined
|
|
124
|
+
*/
|
|
125
|
+
function parseLocation(text: string): ReflectionIssue['location'] | undefined {
|
|
126
|
+
// Match: **Location**: `path/to/file.ts:123`
|
|
127
|
+
const locationMatch = text.match(/\*\*Location\*\*:\s*`([^`]+)`/i);
|
|
128
|
+
if (!locationMatch) return undefined;
|
|
129
|
+
|
|
130
|
+
const locationStr = locationMatch[1];
|
|
131
|
+
const [file, lineStr] = locationStr.split(':');
|
|
132
|
+
const line = lineStr ? parseInt(lineStr, 10) : undefined;
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
file: file.trim(),
|
|
136
|
+
line
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Parse issues from "Issues Identified" section
|
|
142
|
+
* @param markdown Reflection markdown
|
|
143
|
+
* @returns Array of ReflectionIssue objects
|
|
144
|
+
*/
|
|
145
|
+
function parseIssues(markdown: string): ReflectionIssue[] {
|
|
146
|
+
const section = extractSection(markdown, '### ⚠️ Issues Identified');
|
|
147
|
+
if (!section) return [];
|
|
148
|
+
|
|
149
|
+
const issues: ReflectionIssue[] = [];
|
|
150
|
+
const lines = section.split('\n');
|
|
151
|
+
|
|
152
|
+
let currentIssue: Partial<ReflectionIssue> | null = null;
|
|
153
|
+
let currentField: 'description' | 'impact' | 'recommendation' | null = null;
|
|
154
|
+
|
|
155
|
+
for (const line of lines) {
|
|
156
|
+
const trimmed = line.trim();
|
|
157
|
+
|
|
158
|
+
// Check for severity/category header (e.g., "**CRITICAL (SECURITY)**")
|
|
159
|
+
const headerMatch = trimmed.match(/^\*\*(CRITICAL|HIGH|MEDIUM|LOW)\s*\(([^)]+)\)\*\*/i);
|
|
160
|
+
if (headerMatch) {
|
|
161
|
+
// Save previous issue
|
|
162
|
+
if (currentIssue && currentIssue.severity && currentIssue.category && currentIssue.description) {
|
|
163
|
+
issues.push(currentIssue as ReflectionIssue);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Start new issue
|
|
167
|
+
currentIssue = {
|
|
168
|
+
severity: parseSeverity(headerMatch[1])!,
|
|
169
|
+
category: parseCategory(headerMatch[2])!,
|
|
170
|
+
description: '',
|
|
171
|
+
impact: '',
|
|
172
|
+
recommendation: ''
|
|
173
|
+
};
|
|
174
|
+
currentField = null;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Check for issue bullet point (❌ or ⚠️)
|
|
179
|
+
if ((trimmed.startsWith('- ❌') || trimmed.startsWith('❌') || trimmed.startsWith('- ⚠️')) && currentIssue) {
|
|
180
|
+
currentField = 'description';
|
|
181
|
+
const descText = trimmed.replace(/^[-*+]?\s*[❌⚠️]\s*/, '').trim();
|
|
182
|
+
currentIssue.description = descText;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Check for Impact field
|
|
187
|
+
if (trimmed.startsWith('- **Impact**:') || trimmed.startsWith('**Impact**:')) {
|
|
188
|
+
currentField = 'impact';
|
|
189
|
+
const impactText = trimmed.replace(/^[-*+]?\s*\*\*Impact\*\*:\s*/, '').trim();
|
|
190
|
+
if (currentIssue) currentIssue.impact = impactText;
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Check for Recommendation field
|
|
195
|
+
if (trimmed.startsWith('- **Recommendation**:') || trimmed.startsWith('**Recommendation**:')) {
|
|
196
|
+
currentField = 'recommendation';
|
|
197
|
+
const recText = trimmed.replace(/^[-*+]?\s*\*\*Recommendation\*\*:\s*/, '').trim();
|
|
198
|
+
if (currentIssue) currentIssue.recommendation = recText;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Check for Location field
|
|
203
|
+
if (trimmed.startsWith('- **Location**:') || trimmed.startsWith('**Location**:')) {
|
|
204
|
+
if (currentIssue) {
|
|
205
|
+
const location = parseLocation(trimmed);
|
|
206
|
+
if (location) currentIssue.location = location;
|
|
207
|
+
}
|
|
208
|
+
currentField = null;
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Append continuation lines to current field
|
|
213
|
+
if (currentField && currentIssue && trimmed && !trimmed.startsWith('#')) {
|
|
214
|
+
const fieldValue = currentIssue[currentField] || '';
|
|
215
|
+
currentIssue[currentField] = fieldValue + ' ' + trimmed;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Save last issue
|
|
220
|
+
if (currentIssue && currentIssue.severity && currentIssue.category && currentIssue.description) {
|
|
221
|
+
issues.push(currentIssue as ReflectionIssue);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return issues;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Parse recommended actions from "Recommended Follow-Up Actions" section
|
|
229
|
+
* @param markdown Reflection markdown
|
|
230
|
+
* @returns Recommended actions object with priority levels
|
|
231
|
+
*/
|
|
232
|
+
function parseRecommendedActions(markdown: string): ReflectionResult['recommendedActions'] {
|
|
233
|
+
const section = extractSection(markdown, '## 🔧 Recommended Follow-Up Actions');
|
|
234
|
+
|
|
235
|
+
const actions = {
|
|
236
|
+
priority1: [] as string[],
|
|
237
|
+
priority2: [] as string[],
|
|
238
|
+
priority3: [] as string[]
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
if (!section) return actions;
|
|
242
|
+
|
|
243
|
+
const lines = section.split('\n');
|
|
244
|
+
let currentPriority: 'priority1' | 'priority2' | 'priority3' | null = null;
|
|
245
|
+
|
|
246
|
+
for (const line of lines) {
|
|
247
|
+
const trimmed = line.trim();
|
|
248
|
+
|
|
249
|
+
// Check for priority headers
|
|
250
|
+
if (/Priority 1|MUST FIX/i.test(trimmed)) {
|
|
251
|
+
currentPriority = 'priority1';
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
if (/Priority 2|SHOULD FIX/i.test(trimmed)) {
|
|
255
|
+
currentPriority = 'priority2';
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
if (/Priority 3|NICE TO HAVE/i.test(trimmed)) {
|
|
259
|
+
currentPriority = 'priority3';
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Parse action items (numbered or bulleted)
|
|
264
|
+
if (currentPriority && (/^\d+\.\s/.test(trimmed) || /^[-*+]\s/.test(trimmed))) {
|
|
265
|
+
const actionText = trimmed.replace(/^(\d+\.|-|\*|\+)\s+/, '').trim();
|
|
266
|
+
if (actionText.length > 0) {
|
|
267
|
+
actions[currentPriority].push(actionText);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return actions;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Parse lessons learned from "Lessons Learned" section
|
|
277
|
+
* @param markdown Reflection markdown
|
|
278
|
+
* @returns LessonLearned object
|
|
279
|
+
*/
|
|
280
|
+
function parseLessonsLearned(markdown: string): LessonLearned {
|
|
281
|
+
const section = extractSection(markdown, '## 📚 Lessons Learned');
|
|
282
|
+
|
|
283
|
+
const lessons: LessonLearned = {
|
|
284
|
+
whatWentWell: [],
|
|
285
|
+
whatCouldImprove: [],
|
|
286
|
+
forNextTime: []
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
if (!section) return lessons;
|
|
290
|
+
|
|
291
|
+
const lines = section.split('\n');
|
|
292
|
+
let currentCategory: 'whatWentWell' | 'whatCouldImprove' | 'forNextTime' | null = null;
|
|
293
|
+
|
|
294
|
+
for (const line of lines) {
|
|
295
|
+
const trimmed = line.trim();
|
|
296
|
+
|
|
297
|
+
// Check for category headers
|
|
298
|
+
if (/What went well/i.test(trimmed)) {
|
|
299
|
+
currentCategory = 'whatWentWell';
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
if (/What could improve/i.test(trimmed)) {
|
|
303
|
+
currentCategory = 'whatCouldImprove';
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
if (/For next time/i.test(trimmed)) {
|
|
307
|
+
currentCategory = 'forNextTime';
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Parse bullet points
|
|
312
|
+
if (currentCategory && /^[-*+]\s/.test(trimmed)) {
|
|
313
|
+
const text = trimmed.replace(/^[-*+]\s+/, '').trim();
|
|
314
|
+
if (text.length > 0) {
|
|
315
|
+
lessons[currentCategory].push(text);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return lessons;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Parse metrics from "Metrics" section
|
|
325
|
+
* @param markdown Reflection markdown
|
|
326
|
+
* @returns ReflectionMetrics object
|
|
327
|
+
*/
|
|
328
|
+
function parseMetrics(markdown: string): ReflectionMetrics {
|
|
329
|
+
const section = extractSection(markdown, '## 📊 Metrics');
|
|
330
|
+
|
|
331
|
+
const metrics: ReflectionMetrics = {
|
|
332
|
+
codeQuality: 5,
|
|
333
|
+
security: 5,
|
|
334
|
+
testCoverage: undefined,
|
|
335
|
+
technicalDebt: 'MEDIUM',
|
|
336
|
+
performance: 'ACCEPTABLE'
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
if (!section) return metrics;
|
|
340
|
+
|
|
341
|
+
// Parse Code Quality (1-10)
|
|
342
|
+
const qualityMatch = section.match(/Code Quality.*?(\d+)/i);
|
|
343
|
+
if (qualityMatch) {
|
|
344
|
+
metrics.codeQuality = parseInt(qualityMatch[1], 10);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Parse Security (1-10)
|
|
348
|
+
const securityMatch = section.match(/Security.*?(\d+)/i);
|
|
349
|
+
if (securityMatch) {
|
|
350
|
+
metrics.security = parseInt(securityMatch[1], 10);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Parse Test Coverage (percentage)
|
|
354
|
+
const coverageMatch = section.match(/Test Coverage.*?(\d+)%/i);
|
|
355
|
+
if (coverageMatch) {
|
|
356
|
+
metrics.testCoverage = parseInt(coverageMatch[1], 10);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Parse Technical Debt (LOW/MEDIUM/HIGH)
|
|
360
|
+
const debtMatch = section.match(/Technical Debt.*?(LOW|MEDIUM|HIGH)/i);
|
|
361
|
+
if (debtMatch) {
|
|
362
|
+
metrics.technicalDebt = debtMatch[1].toUpperCase() as 'LOW' | 'MEDIUM' | 'HIGH';
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Parse Performance (GOOD/ACCEPTABLE/NEEDS WORK)
|
|
366
|
+
const perfMatch = section.match(/Performance.*?(GOOD|ACCEPTABLE|NEEDS[\s_]WORK)/i);
|
|
367
|
+
if (perfMatch) {
|
|
368
|
+
metrics.performance = perfMatch[1].toUpperCase().replace(/[\s_]/g, '_') as 'GOOD' | 'ACCEPTABLE' | 'NEEDS_WORK';
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return metrics;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Parse complete reflection result from markdown
|
|
376
|
+
* Main parsing function
|
|
377
|
+
*
|
|
378
|
+
* @param markdown Reflection markdown from reflective-reviewer agent
|
|
379
|
+
* @param taskName Task name for result
|
|
380
|
+
* @param model Model used for reflection
|
|
381
|
+
* @param reflectionTime Time taken in seconds
|
|
382
|
+
* @param estimatedCost Estimated cost in USD
|
|
383
|
+
* @returns Complete ReflectionResult object
|
|
384
|
+
*/
|
|
385
|
+
export function parseReflectionMarkdown(
|
|
386
|
+
markdown: string,
|
|
387
|
+
taskName: string,
|
|
388
|
+
model: ReflectionModel = ReflectionModel.HAIKU,
|
|
389
|
+
reflectionTime: number = 0,
|
|
390
|
+
estimatedCost: number = 0
|
|
391
|
+
): ReflectionResult {
|
|
392
|
+
const result: ReflectionResult = {
|
|
393
|
+
taskName,
|
|
394
|
+
completed: new Date().toISOString(),
|
|
395
|
+
duration: reflectionTime > 0 ? `${reflectionTime}s` : undefined,
|
|
396
|
+
filesModified: {
|
|
397
|
+
count: 0,
|
|
398
|
+
linesAdded: 0,
|
|
399
|
+
linesRemoved: 0
|
|
400
|
+
},
|
|
401
|
+
accomplishments: parseAccomplishments(markdown),
|
|
402
|
+
strengths: parseStrengths(markdown),
|
|
403
|
+
issues: parseIssues(markdown),
|
|
404
|
+
recommendedActions: parseRecommendedActions(markdown),
|
|
405
|
+
lessonsLearned: parseLessonsLearned(markdown),
|
|
406
|
+
metrics: parseMetrics(markdown),
|
|
407
|
+
metadata: {
|
|
408
|
+
model,
|
|
409
|
+
reflectionTime,
|
|
410
|
+
estimatedCost
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
// Extract file modification stats from markdown if present
|
|
415
|
+
const filesChangedMatch = markdown.match(/\*\*Files Modified\*\*:\s*(\d+)\s*files?,\s*\+(\d+)\s*-(\d+)/i);
|
|
416
|
+
if (filesChangedMatch) {
|
|
417
|
+
result.filesModified = {
|
|
418
|
+
count: parseInt(filesChangedMatch[1], 10),
|
|
419
|
+
linesAdded: parseInt(filesChangedMatch[2], 10),
|
|
420
|
+
linesRemoved: parseInt(filesChangedMatch[3], 10)
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return result;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Validate parsed reflection result
|
|
429
|
+
* Checks for required fields and data quality
|
|
430
|
+
*
|
|
431
|
+
* @param result Parsed reflection result
|
|
432
|
+
* @returns Validation result with errors
|
|
433
|
+
*/
|
|
434
|
+
export function validateReflectionResult(result: ReflectionResult): {
|
|
435
|
+
valid: boolean;
|
|
436
|
+
errors: string[];
|
|
437
|
+
} {
|
|
438
|
+
const errors: string[] = [];
|
|
439
|
+
|
|
440
|
+
// Check required fields
|
|
441
|
+
if (!result.taskName) {
|
|
442
|
+
errors.push('Missing task name');
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (!result.completed) {
|
|
446
|
+
errors.push('Missing completion timestamp');
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Check for meaningful content
|
|
450
|
+
if (result.accomplishments.length === 0 && result.strengths.length === 0) {
|
|
451
|
+
errors.push('No accomplishments or strengths identified (reflection too sparse)');
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Validate metrics
|
|
455
|
+
if (result.metrics.codeQuality < 1 || result.metrics.codeQuality > 10) {
|
|
456
|
+
errors.push('Code quality must be 1-10');
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
if (result.metrics.security < 1 || result.metrics.security > 10) {
|
|
460
|
+
errors.push('Security must be 1-10');
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (result.metrics.testCoverage !== undefined && (result.metrics.testCoverage < 0 || result.metrics.testCoverage > 100)) {
|
|
464
|
+
errors.push('Test coverage must be 0-100%');
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Validate issues have required fields
|
|
468
|
+
for (const issue of result.issues) {
|
|
469
|
+
if (!issue.description) {
|
|
470
|
+
errors.push('Issue missing description');
|
|
471
|
+
}
|
|
472
|
+
if (!issue.impact) {
|
|
473
|
+
errors.push('Issue missing impact explanation');
|
|
474
|
+
}
|
|
475
|
+
if (!issue.recommendation) {
|
|
476
|
+
errors.push('Issue missing recommendation');
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
return {
|
|
481
|
+
valid: errors.length === 0,
|
|
482
|
+
errors
|
|
483
|
+
};
|
|
484
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reflection Prompt Builder
|
|
3
|
+
*
|
|
4
|
+
* Builds comprehensive prompts for the reflective-reviewer agent
|
|
5
|
+
* Includes modified files context, configuration, task information
|
|
6
|
+
*
|
|
7
|
+
* @module reflection-prompt-builder
|
|
8
|
+
*/
|
|
9
|
+
import { ReflectionConfig, GitDiffInfo } from './types/reflection-types';
|
|
10
|
+
/**
|
|
11
|
+
* Build the complete reflection prompt
|
|
12
|
+
* Main function for creating agent prompts
|
|
13
|
+
*
|
|
14
|
+
* @param options Prompt options
|
|
15
|
+
* @returns Complete markdown-formatted prompt for reflective-reviewer agent
|
|
16
|
+
*/
|
|
17
|
+
export declare function buildReflectionPrompt(options: {
|
|
18
|
+
taskId: string;
|
|
19
|
+
taskName?: string;
|
|
20
|
+
modifiedFiles: GitDiffInfo[];
|
|
21
|
+
config: ReflectionConfig;
|
|
22
|
+
incrementId?: string;
|
|
23
|
+
includeFullDiff?: boolean;
|
|
24
|
+
}): string;
|
|
25
|
+
/**
|
|
26
|
+
* Estimate token count for prompt (rough approximation)
|
|
27
|
+
* Used for cost estimation
|
|
28
|
+
*
|
|
29
|
+
* @param prompt Reflection prompt
|
|
30
|
+
* @returns Estimated token count (1 token ≈ 4 characters)
|
|
31
|
+
*/
|
|
32
|
+
export declare function estimatePromptTokens(prompt: string): number;
|
|
33
|
+
/**
|
|
34
|
+
* Truncate large diffs to fit within token budget
|
|
35
|
+
* Preserves most recent changes (bottom of diff)
|
|
36
|
+
*
|
|
37
|
+
* @param modifiedFiles Array of modified files
|
|
38
|
+
* @param maxTokens Maximum tokens to use (default: 8000)
|
|
39
|
+
* @returns Truncated array of modified files
|
|
40
|
+
*/
|
|
41
|
+
export declare function truncateModifiedFiles(modifiedFiles: GitDiffInfo[], maxTokens?: number): GitDiffInfo[];
|
|
42
|
+
/**
|
|
43
|
+
* Build a simplified prompt for very large changes
|
|
44
|
+
* Used when full diff exceeds reasonable token budget
|
|
45
|
+
*
|
|
46
|
+
* @param options Prompt options (same as buildReflectionPrompt)
|
|
47
|
+
* @returns Simplified prompt with file list only (no diffs)
|
|
48
|
+
*/
|
|
49
|
+
export declare function buildSimplifiedPrompt(options: {
|
|
50
|
+
taskId: string;
|
|
51
|
+
taskName?: string;
|
|
52
|
+
modifiedFiles: GitDiffInfo[];
|
|
53
|
+
config: ReflectionConfig;
|
|
54
|
+
incrementId?: string;
|
|
55
|
+
}): string;
|
|
56
|
+
//# sourceMappingURL=reflection-prompt-builder.d.ts.map
|