specweave 0.23.0 → 0.23.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.
Files changed (76) hide show
  1. package/.claude-plugin/marketplace.json +0 -88
  2. package/CLAUDE.md +100 -0
  3. package/bin/fix-marketplace-errors.sh +8 -8
  4. package/dist/src/cli/helpers/issue-tracker/index.d.ts.map +1 -1
  5. package/dist/src/cli/helpers/issue-tracker/index.js +5 -17
  6. package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
  7. package/dist/src/core/repo-structure/repo-id-generator.d.ts +20 -0
  8. package/dist/src/core/repo-structure/repo-id-generator.d.ts.map +1 -1
  9. package/dist/src/core/repo-structure/repo-id-generator.js +44 -0
  10. package/dist/src/core/repo-structure/repo-id-generator.js.map +1 -1
  11. package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
  12. package/dist/src/core/repo-structure/repo-structure-manager.js +5 -2
  13. package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
  14. package/package.json +1 -1
  15. package/plugins/specweave/.claude-plugin/plugin.json +10 -0
  16. package/plugins/specweave/commands/specweave-archive.md +51 -15
  17. package/plugins/specweave/hooks/post-edit-spec.sh +62 -9
  18. package/plugins/specweave/hooks/post-metadata-change.sh +160 -0
  19. package/plugins/specweave/hooks/post-write-spec.sh +62 -8
  20. package/plugins/specweave/lib/hooks/auto-transition.js.bak +50 -0
  21. package/plugins/specweave/lib/hooks/auto-transition.ts.bak +84 -0
  22. package/plugins/specweave/lib/hooks/git-diff-analyzer.d.js.bak +0 -0
  23. package/plugins/specweave/lib/hooks/git-diff-analyzer.d.ts.bak +89 -0
  24. package/plugins/specweave/lib/hooks/git-diff-analyzer.js.bak +142 -0
  25. package/plugins/specweave/lib/hooks/git-diff-analyzer.ts.bak +269 -0
  26. package/plugins/specweave/lib/hooks/invoke-translator-skill.d.js.bak +0 -0
  27. package/plugins/specweave/lib/hooks/invoke-translator-skill.d.ts.bak +60 -0
  28. package/plugins/specweave/lib/hooks/invoke-translator-skill.js.bak +155 -0
  29. package/plugins/specweave/lib/hooks/invoke-translator-skill.ts.bak +264 -0
  30. package/plugins/specweave/lib/hooks/prepare-reflection-context.d.js.bak +0 -0
  31. package/plugins/specweave/lib/hooks/prepare-reflection-context.d.ts.bak +42 -0
  32. package/plugins/specweave/lib/hooks/prepare-reflection-context.js.bak +110 -0
  33. package/plugins/specweave/lib/hooks/prepare-reflection-context.ts.bak +178 -0
  34. package/plugins/specweave/lib/hooks/reflection-config-loader.d.js.bak +0 -0
  35. package/plugins/specweave/lib/hooks/reflection-config-loader.d.ts.bak +45 -0
  36. package/plugins/specweave/lib/hooks/reflection-config-loader.js.bak +92 -0
  37. package/plugins/specweave/lib/hooks/reflection-config-loader.ts.bak +156 -0
  38. package/plugins/specweave/lib/hooks/reflection-parser.d.js.bak +0 -0
  39. package/plugins/specweave/lib/hooks/reflection-parser.d.ts.bak +33 -0
  40. package/plugins/specweave/lib/hooks/reflection-parser.js.bak +301 -0
  41. package/plugins/specweave/lib/hooks/reflection-parser.ts.bak +484 -0
  42. package/plugins/specweave/lib/hooks/reflection-prompt-builder.d.js.bak +0 -0
  43. package/plugins/specweave/lib/hooks/reflection-prompt-builder.d.ts.bak +56 -0
  44. package/plugins/specweave/lib/hooks/reflection-prompt-builder.js.bak +182 -0
  45. package/plugins/specweave/lib/hooks/reflection-prompt-builder.ts.bak +306 -0
  46. package/plugins/specweave/lib/hooks/reflection-storage.d.js.bak +0 -0
  47. package/plugins/specweave/lib/hooks/reflection-storage.d.ts.bak +64 -0
  48. package/plugins/specweave/lib/hooks/reflection-storage.js.bak +231 -0
  49. package/plugins/specweave/lib/hooks/reflection-storage.ts.bak +369 -0
  50. package/plugins/specweave/lib/hooks/run-self-reflection.d.js.bak +0 -0
  51. package/plugins/specweave/lib/hooks/run-self-reflection.d.ts.bak +43 -0
  52. package/plugins/specweave/lib/hooks/run-self-reflection.js.bak +132 -0
  53. package/plugins/specweave/lib/hooks/run-self-reflection.ts.bak +258 -0
  54. package/plugins/specweave/lib/hooks/sync-cache.js.bak +294 -0
  55. package/plugins/specweave/lib/hooks/sync-living-docs.d.js.bak +1 -0
  56. package/plugins/specweave/lib/hooks/sync-living-docs.d.ts.bak +27 -0
  57. package/plugins/specweave/lib/hooks/sync-living-docs.js.bak +339 -0
  58. package/plugins/specweave/lib/hooks/sync-us-tasks.js.bak +476 -0
  59. package/plugins/specweave/lib/hooks/translate-file.d.js.bak +0 -0
  60. package/plugins/specweave/lib/hooks/translate-file.d.ts.bak +59 -0
  61. package/plugins/specweave/lib/hooks/translate-file.js.bak +289 -0
  62. package/plugins/specweave/lib/hooks/translate-file.ts.bak +428 -0
  63. package/plugins/specweave/lib/hooks/translate-living-docs.d.js.bak +0 -0
  64. package/plugins/specweave/lib/hooks/translate-living-docs.d.ts.bak +13 -0
  65. package/plugins/specweave/lib/hooks/translate-living-docs.js.bak +119 -0
  66. package/plugins/specweave/lib/hooks/translate-living-docs.ts.bak +224 -0
  67. package/plugins/specweave/lib/hooks/update-ac-status.js.bak +51 -0
  68. package/plugins/specweave/lib/hooks/update-ac-status.ts.bak +103 -0
  69. package/plugins/specweave/lib/hooks/update-tasks-md.d.js.bak +1 -0
  70. package/plugins/specweave/lib/hooks/update-tasks-md.d.ts.bak +29 -0
  71. package/plugins/specweave/lib/hooks/update-tasks-md.js.bak +296 -0
  72. package/plugins/specweave/lib/hooks/update-tasks-md.ts.bak +489 -0
  73. package/plugins/specweave-ado/lib/ado-multi-project-sync.js +1 -0
  74. package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
  75. package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
  76. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +6225 -0
@@ -0,0 +1,301 @@
1
+ import {
2
+ IssueSeverity,
3
+ IssueCategory,
4
+ ReflectionModel
5
+ } from "./types/reflection-types";
6
+ function extractSection(markdown, heading) {
7
+ const headingRegex = new RegExp(`^${heading}\\s*$`, "mi");
8
+ const match = markdown.match(headingRegex);
9
+ if (!match || match.index === void 0) {
10
+ return "";
11
+ }
12
+ const startIndex = match.index + match[0].length;
13
+ const afterHeading = markdown.slice(startIndex);
14
+ const nextHeadingMatch = afterHeading.match(/^#{1,3}\s+/m);
15
+ const endIndex = nextHeadingMatch?.index ?? afterHeading.length;
16
+ return afterHeading.slice(0, endIndex).trim();
17
+ }
18
+ function parseAccomplishments(markdown) {
19
+ const section = extractSection(markdown, "## \u2705 What Was Accomplished");
20
+ if (!section) return [];
21
+ const lines = section.split("\n").filter((line) => line.trim());
22
+ const accomplishments = [];
23
+ for (const line of lines) {
24
+ const trimmed = line.trim();
25
+ if (/^[-*+]\s+/.test(trimmed) || /^\d+\.\s+/.test(trimmed)) {
26
+ accomplishments.push(trimmed.replace(/^[-*+\d.]\s+/, "").trim());
27
+ } else if (trimmed.length > 10 && !trimmed.startsWith("#")) {
28
+ accomplishments.push(trimmed);
29
+ }
30
+ }
31
+ return accomplishments;
32
+ }
33
+ function parseStrengths(markdown) {
34
+ const section = extractSection(markdown, "### \u2705 Strengths");
35
+ if (!section) return [];
36
+ const lines = section.split("\n").filter((line) => line.trim());
37
+ const strengths = [];
38
+ for (const line of lines) {
39
+ const trimmed = line.trim();
40
+ if (trimmed.startsWith("- \u2705") || trimmed.startsWith("\u2705")) {
41
+ strengths.push(trimmed.replace(/^[-*+]?\s*✅\s*/, "").trim());
42
+ }
43
+ }
44
+ return strengths;
45
+ }
46
+ function parseSeverity(text) {
47
+ if (/CRITICAL/i.test(text)) return IssueSeverity.CRITICAL;
48
+ if (/HIGH/i.test(text)) return IssueSeverity.HIGH;
49
+ if (/MEDIUM/i.test(text)) return IssueSeverity.MEDIUM;
50
+ if (/LOW/i.test(text)) return IssueSeverity.LOW;
51
+ return void 0;
52
+ }
53
+ function parseCategory(text) {
54
+ if (/SECURITY/i.test(text)) return IssueCategory.SECURITY;
55
+ if (/QUALITY/i.test(text)) return IssueCategory.QUALITY;
56
+ if (/TESTING/i.test(text)) return IssueCategory.TESTING;
57
+ if (/PERFORMANCE/i.test(text)) return IssueCategory.PERFORMANCE;
58
+ if (/TECHNICAL[_\s]DEBT/i.test(text)) return IssueCategory.TECHNICAL_DEBT;
59
+ return void 0;
60
+ }
61
+ function parseLocation(text) {
62
+ const locationMatch = text.match(/\*\*Location\*\*:\s*`([^`]+)`/i);
63
+ if (!locationMatch) return void 0;
64
+ const locationStr = locationMatch[1];
65
+ const [file, lineStr] = locationStr.split(":");
66
+ const line = lineStr ? parseInt(lineStr, 10) : void 0;
67
+ return {
68
+ file: file.trim(),
69
+ line
70
+ };
71
+ }
72
+ function parseIssues(markdown) {
73
+ const section = extractSection(markdown, "### \u26A0\uFE0F Issues Identified");
74
+ if (!section) return [];
75
+ const issues = [];
76
+ const lines = section.split("\n");
77
+ let currentIssue = null;
78
+ let currentField = null;
79
+ for (const line of lines) {
80
+ const trimmed = line.trim();
81
+ const headerMatch = trimmed.match(/^\*\*(CRITICAL|HIGH|MEDIUM|LOW)\s*\(([^)]+)\)\*\*/i);
82
+ if (headerMatch) {
83
+ if (currentIssue && currentIssue.severity && currentIssue.category && currentIssue.description) {
84
+ issues.push(currentIssue);
85
+ }
86
+ currentIssue = {
87
+ severity: parseSeverity(headerMatch[1]),
88
+ category: parseCategory(headerMatch[2]),
89
+ description: "",
90
+ impact: "",
91
+ recommendation: ""
92
+ };
93
+ currentField = null;
94
+ continue;
95
+ }
96
+ if ((trimmed.startsWith("- \u274C") || trimmed.startsWith("\u274C") || trimmed.startsWith("- \u26A0\uFE0F")) && currentIssue) {
97
+ currentField = "description";
98
+ const descText = trimmed.replace(/^[-*+]?\s*[❌⚠️]\s*/, "").trim();
99
+ currentIssue.description = descText;
100
+ continue;
101
+ }
102
+ if (trimmed.startsWith("- **Impact**:") || trimmed.startsWith("**Impact**:")) {
103
+ currentField = "impact";
104
+ const impactText = trimmed.replace(/^[-*+]?\s*\*\*Impact\*\*:\s*/, "").trim();
105
+ if (currentIssue) currentIssue.impact = impactText;
106
+ continue;
107
+ }
108
+ if (trimmed.startsWith("- **Recommendation**:") || trimmed.startsWith("**Recommendation**:")) {
109
+ currentField = "recommendation";
110
+ const recText = trimmed.replace(/^[-*+]?\s*\*\*Recommendation\*\*:\s*/, "").trim();
111
+ if (currentIssue) currentIssue.recommendation = recText;
112
+ continue;
113
+ }
114
+ if (trimmed.startsWith("- **Location**:") || trimmed.startsWith("**Location**:")) {
115
+ if (currentIssue) {
116
+ const location = parseLocation(trimmed);
117
+ if (location) currentIssue.location = location;
118
+ }
119
+ currentField = null;
120
+ continue;
121
+ }
122
+ if (currentField && currentIssue && trimmed && !trimmed.startsWith("#")) {
123
+ const fieldValue = currentIssue[currentField] || "";
124
+ currentIssue[currentField] = fieldValue + " " + trimmed;
125
+ }
126
+ }
127
+ if (currentIssue && currentIssue.severity && currentIssue.category && currentIssue.description) {
128
+ issues.push(currentIssue);
129
+ }
130
+ return issues;
131
+ }
132
+ function parseRecommendedActions(markdown) {
133
+ const section = extractSection(markdown, "## \u{1F527} Recommended Follow-Up Actions");
134
+ const actions = {
135
+ priority1: [],
136
+ priority2: [],
137
+ priority3: []
138
+ };
139
+ if (!section) return actions;
140
+ const lines = section.split("\n");
141
+ let currentPriority = null;
142
+ for (const line of lines) {
143
+ const trimmed = line.trim();
144
+ if (/Priority 1|MUST FIX/i.test(trimmed)) {
145
+ currentPriority = "priority1";
146
+ continue;
147
+ }
148
+ if (/Priority 2|SHOULD FIX/i.test(trimmed)) {
149
+ currentPriority = "priority2";
150
+ continue;
151
+ }
152
+ if (/Priority 3|NICE TO HAVE/i.test(trimmed)) {
153
+ currentPriority = "priority3";
154
+ continue;
155
+ }
156
+ if (currentPriority && (/^\d+\.\s/.test(trimmed) || /^[-*+]\s/.test(trimmed))) {
157
+ const actionText = trimmed.replace(/^(\d+\.|-|\*|\+)\s+/, "").trim();
158
+ if (actionText.length > 0) {
159
+ actions[currentPriority].push(actionText);
160
+ }
161
+ }
162
+ }
163
+ return actions;
164
+ }
165
+ function parseLessonsLearned(markdown) {
166
+ const section = extractSection(markdown, "## \u{1F4DA} Lessons Learned");
167
+ const lessons = {
168
+ whatWentWell: [],
169
+ whatCouldImprove: [],
170
+ forNextTime: []
171
+ };
172
+ if (!section) return lessons;
173
+ const lines = section.split("\n");
174
+ let currentCategory = null;
175
+ for (const line of lines) {
176
+ const trimmed = line.trim();
177
+ if (/What went well/i.test(trimmed)) {
178
+ currentCategory = "whatWentWell";
179
+ continue;
180
+ }
181
+ if (/What could improve/i.test(trimmed)) {
182
+ currentCategory = "whatCouldImprove";
183
+ continue;
184
+ }
185
+ if (/For next time/i.test(trimmed)) {
186
+ currentCategory = "forNextTime";
187
+ continue;
188
+ }
189
+ if (currentCategory && /^[-*+]\s/.test(trimmed)) {
190
+ const text = trimmed.replace(/^[-*+]\s+/, "").trim();
191
+ if (text.length > 0) {
192
+ lessons[currentCategory].push(text);
193
+ }
194
+ }
195
+ }
196
+ return lessons;
197
+ }
198
+ function parseMetrics(markdown) {
199
+ const section = extractSection(markdown, "## \u{1F4CA} Metrics");
200
+ const metrics = {
201
+ codeQuality: 5,
202
+ security: 5,
203
+ testCoverage: void 0,
204
+ technicalDebt: "MEDIUM",
205
+ performance: "ACCEPTABLE"
206
+ };
207
+ if (!section) return metrics;
208
+ const qualityMatch = section.match(/Code Quality.*?(\d+)/i);
209
+ if (qualityMatch) {
210
+ metrics.codeQuality = parseInt(qualityMatch[1], 10);
211
+ }
212
+ const securityMatch = section.match(/Security.*?(\d+)/i);
213
+ if (securityMatch) {
214
+ metrics.security = parseInt(securityMatch[1], 10);
215
+ }
216
+ const coverageMatch = section.match(/Test Coverage.*?(\d+)%/i);
217
+ if (coverageMatch) {
218
+ metrics.testCoverage = parseInt(coverageMatch[1], 10);
219
+ }
220
+ const debtMatch = section.match(/Technical Debt.*?(LOW|MEDIUM|HIGH)/i);
221
+ if (debtMatch) {
222
+ metrics.technicalDebt = debtMatch[1].toUpperCase();
223
+ }
224
+ const perfMatch = section.match(/Performance.*?(GOOD|ACCEPTABLE|NEEDS[\s_]WORK)/i);
225
+ if (perfMatch) {
226
+ metrics.performance = perfMatch[1].toUpperCase().replace(/[\s_]/g, "_");
227
+ }
228
+ return metrics;
229
+ }
230
+ function parseReflectionMarkdown(markdown, taskName, model = ReflectionModel.HAIKU, reflectionTime = 0, estimatedCost = 0) {
231
+ const result = {
232
+ taskName,
233
+ completed: (/* @__PURE__ */ new Date()).toISOString(),
234
+ duration: reflectionTime > 0 ? `${reflectionTime}s` : void 0,
235
+ filesModified: {
236
+ count: 0,
237
+ linesAdded: 0,
238
+ linesRemoved: 0
239
+ },
240
+ accomplishments: parseAccomplishments(markdown),
241
+ strengths: parseStrengths(markdown),
242
+ issues: parseIssues(markdown),
243
+ recommendedActions: parseRecommendedActions(markdown),
244
+ lessonsLearned: parseLessonsLearned(markdown),
245
+ metrics: parseMetrics(markdown),
246
+ metadata: {
247
+ model,
248
+ reflectionTime,
249
+ estimatedCost
250
+ }
251
+ };
252
+ const filesChangedMatch = markdown.match(/\*\*Files Modified\*\*:\s*(\d+)\s*files?,\s*\+(\d+)\s*-(\d+)/i);
253
+ if (filesChangedMatch) {
254
+ result.filesModified = {
255
+ count: parseInt(filesChangedMatch[1], 10),
256
+ linesAdded: parseInt(filesChangedMatch[2], 10),
257
+ linesRemoved: parseInt(filesChangedMatch[3], 10)
258
+ };
259
+ }
260
+ return result;
261
+ }
262
+ function validateReflectionResult(result) {
263
+ const errors = [];
264
+ if (!result.taskName) {
265
+ errors.push("Missing task name");
266
+ }
267
+ if (!result.completed) {
268
+ errors.push("Missing completion timestamp");
269
+ }
270
+ if (result.accomplishments.length === 0 && result.strengths.length === 0) {
271
+ errors.push("No accomplishments or strengths identified (reflection too sparse)");
272
+ }
273
+ if (result.metrics.codeQuality < 1 || result.metrics.codeQuality > 10) {
274
+ errors.push("Code quality must be 1-10");
275
+ }
276
+ if (result.metrics.security < 1 || result.metrics.security > 10) {
277
+ errors.push("Security must be 1-10");
278
+ }
279
+ if (result.metrics.testCoverage !== void 0 && (result.metrics.testCoverage < 0 || result.metrics.testCoverage > 100)) {
280
+ errors.push("Test coverage must be 0-100%");
281
+ }
282
+ for (const issue of result.issues) {
283
+ if (!issue.description) {
284
+ errors.push("Issue missing description");
285
+ }
286
+ if (!issue.impact) {
287
+ errors.push("Issue missing impact explanation");
288
+ }
289
+ if (!issue.recommendation) {
290
+ errors.push("Issue missing recommendation");
291
+ }
292
+ }
293
+ return {
294
+ valid: errors.length === 0,
295
+ errors
296
+ };
297
+ }
298
+ export {
299
+ parseReflectionMarkdown,
300
+ validateReflectionResult
301
+ };