specweave 1.0.255 → 1.0.256

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 (92) hide show
  1. package/CLAUDE.md +24 -24
  2. package/README.md +138 -203
  3. package/dist/src/core/ac-checkbox-formatter.d.ts +24 -0
  4. package/dist/src/core/ac-checkbox-formatter.d.ts.map +1 -0
  5. package/dist/src/core/ac-checkbox-formatter.js +35 -0
  6. package/dist/src/core/ac-checkbox-formatter.js.map +1 -0
  7. package/dist/src/core/ac-progress-sync.d.ts +116 -0
  8. package/dist/src/core/ac-progress-sync.d.ts.map +1 -0
  9. package/dist/src/core/ac-progress-sync.js +272 -0
  10. package/dist/src/core/ac-progress-sync.js.map +1 -0
  11. package/dist/src/core/fabric/registry-schema.d.ts +79 -0
  12. package/dist/src/core/fabric/registry-schema.d.ts.map +1 -0
  13. package/dist/src/core/fabric/registry-schema.js +6 -0
  14. package/dist/src/core/fabric/registry-schema.js.map +1 -0
  15. package/dist/src/core/fabric/security-scanner.d.ts +12 -0
  16. package/dist/src/core/fabric/security-scanner.d.ts.map +1 -0
  17. package/dist/src/core/fabric/security-scanner.js +219 -0
  18. package/dist/src/core/fabric/security-scanner.js.map +1 -0
  19. package/dist/src/core/types/sync-profile.d.ts +44 -0
  20. package/dist/src/core/types/sync-profile.d.ts.map +1 -1
  21. package/dist/src/core/types/sync-profile.js.map +1 -1
  22. package/package.json +1 -1
  23. package/plugins/specweave/hooks/v2/dispatchers/post-tool-use.sh +4 -4
  24. package/plugins/{specweave-github/hooks/github-ac-sync-handler.sh → specweave/hooks/v2/handlers/ac-sync-dispatcher.sh} +96 -92
  25. package/plugins/specweave/skills/architect/SKILL.md +1 -1
  26. package/plugins/specweave/skills/auto/SKILL.md +1 -1
  27. package/plugins/specweave/skills/cancel-auto/SKILL.md +1 -1
  28. package/plugins/specweave/skills/code-simplifier/SKILL.md +1 -1
  29. package/plugins/specweave/skills/do/SKILL.md +1 -1
  30. package/plugins/specweave/skills/docs/SKILL.md +1 -1
  31. package/plugins/specweave/skills/docs-updater/SKILL.md +1 -1
  32. package/plugins/specweave/skills/done/SKILL.md +13 -70
  33. package/plugins/specweave/skills/framework/SKILL.md +1 -1
  34. package/plugins/specweave/skills/grill/SKILL.md +1 -1
  35. package/plugins/specweave/skills/increment/SKILL.md +1 -1
  36. package/plugins/specweave/skills/increment-planner/SKILL.md +1 -1
  37. package/plugins/specweave/skills/lsp/SKILL.md +1 -1
  38. package/plugins/specweave/skills/pm/SKILL.md +1 -1
  39. package/plugins/specweave/skills/progress/SKILL.md +1 -1
  40. package/plugins/specweave/skills/save/SKILL.md +1 -1
  41. package/plugins/specweave/skills/security/SKILL.md +1 -1
  42. package/plugins/specweave/skills/security-patterns/SKILL.md +1 -1
  43. package/plugins/specweave/skills/tdd-cycle/SKILL.md +1 -1
  44. package/plugins/specweave/skills/tdd-green/SKILL.md +1 -1
  45. package/plugins/specweave/skills/tdd-orchestrator/SKILL.md +1 -1
  46. package/plugins/specweave/skills/tdd-red/SKILL.md +1 -1
  47. package/plugins/specweave/skills/validate/SKILL.md +1 -1
  48. package/plugins/specweave-github/commands/sync.md +1 -22
  49. package/dist/plugins/specweave-github/lib/ThreeLayerSyncManager.d.ts +0 -205
  50. package/dist/plugins/specweave-github/lib/ThreeLayerSyncManager.d.ts.map +0 -1
  51. package/dist/plugins/specweave-github/lib/ThreeLayerSyncManager.js +0 -685
  52. package/dist/plugins/specweave-github/lib/ThreeLayerSyncManager.js.map +0 -1
  53. package/dist/plugins/specweave-github/lib/cli-sync-increment-changes.d.ts +0 -12
  54. package/dist/plugins/specweave-github/lib/cli-sync-increment-changes.d.ts.map +0 -1
  55. package/dist/plugins/specweave-github/lib/cli-sync-increment-changes.js +0 -28
  56. package/dist/plugins/specweave-github/lib/cli-sync-increment-changes.js.map +0 -1
  57. package/dist/plugins/specweave-github/lib/github-increment-sync-cli.d.ts +0 -21
  58. package/dist/plugins/specweave-github/lib/github-increment-sync-cli.d.ts.map +0 -1
  59. package/dist/plugins/specweave-github/lib/github-increment-sync-cli.js +0 -471
  60. package/dist/plugins/specweave-github/lib/github-increment-sync-cli.js.map +0 -1
  61. package/dist/plugins/specweave-github/lib/github-status-sync.d.ts +0 -53
  62. package/dist/plugins/specweave-github/lib/github-status-sync.d.ts.map +0 -1
  63. package/dist/plugins/specweave-github/lib/github-status-sync.js +0 -120
  64. package/dist/plugins/specweave-github/lib/github-status-sync.js.map +0 -1
  65. package/dist/plugins/specweave-github/lib/github-sync-increment-changes.d.ts +0 -18
  66. package/dist/plugins/specweave-github/lib/github-sync-increment-changes.d.ts.map +0 -1
  67. package/dist/plugins/specweave-github/lib/github-sync-increment-changes.js +0 -297
  68. package/dist/plugins/specweave-github/lib/github-sync-increment-changes.js.map +0 -1
  69. package/dist/plugins/specweave-github/lib/increment-issue-builder.d.ts +0 -94
  70. package/dist/plugins/specweave-github/lib/increment-issue-builder.d.ts.map +0 -1
  71. package/dist/plugins/specweave-github/lib/increment-issue-builder.js +0 -385
  72. package/dist/plugins/specweave-github/lib/increment-issue-builder.js.map +0 -1
  73. package/plugins/specweave-github/lib/ThreeLayerSyncManager.js +0 -611
  74. package/plugins/specweave-github/lib/ThreeLayerSyncManager.ts +0 -909
  75. package/plugins/specweave-github/lib/cli-sync-increment-changes.d.js +0 -1
  76. package/plugins/specweave-github/lib/cli-sync-increment-changes.d.ts +0 -12
  77. package/plugins/specweave-github/lib/cli-sync-increment-changes.d.ts.map +0 -1
  78. package/plugins/specweave-github/lib/cli-sync-increment-changes.js +0 -17
  79. package/plugins/specweave-github/lib/cli-sync-increment-changes.js.map +0 -1
  80. package/plugins/specweave-github/lib/cli-sync-increment-changes.ts +0 -33
  81. package/plugins/specweave-github/lib/github-increment-sync-cli.js +0 -474
  82. package/plugins/specweave-github/lib/github-increment-sync-cli.ts +0 -616
  83. package/plugins/specweave-github/lib/github-status-sync.js +0 -107
  84. package/plugins/specweave-github/lib/github-status-sync.ts +0 -163
  85. package/plugins/specweave-github/lib/github-sync-increment-changes.d.js +0 -0
  86. package/plugins/specweave-github/lib/github-sync-increment-changes.d.ts +0 -18
  87. package/plugins/specweave-github/lib/github-sync-increment-changes.d.ts.map +0 -1
  88. package/plugins/specweave-github/lib/github-sync-increment-changes.js +0 -253
  89. package/plugins/specweave-github/lib/github-sync-increment-changes.js.map +0 -1
  90. package/plugins/specweave-github/lib/github-sync-increment-changes.ts +0 -391
  91. package/plugins/specweave-github/lib/increment-issue-builder.js +0 -402
  92. package/plugins/specweave-github/lib/increment-issue-builder.ts +0 -520
@@ -1,402 +0,0 @@
1
- import { readFile } from "fs/promises";
2
- import { existsSync } from "fs";
3
- import * as path from "path";
4
- import * as yaml from "yaml";
5
- class IncrementIssueBuilder {
6
- constructor(incrementPath, projectRoot) {
7
- this.incrementPath = incrementPath;
8
- this.projectRoot = projectRoot;
9
- }
10
- /**
11
- * Parse increment spec.md and extract all data
12
- */
13
- async parse() {
14
- const specPath = path.join(this.incrementPath, "spec.md");
15
- if (!existsSync(specPath)) {
16
- throw new Error(`spec.md not found at ${specPath}`);
17
- }
18
- const content = await readFile(specPath, "utf-8");
19
- const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
20
- if (!frontmatterMatch) {
21
- throw new Error("spec.md missing YAML frontmatter");
22
- }
23
- const frontmatter = yaml.parse(frontmatterMatch[1]);
24
- const bodyContent = content.slice(frontmatterMatch[0].length).trim();
25
- const titleMatch = bodyContent.match(/^#\s+(.+)$/m);
26
- const title = titleMatch ? titleMatch[1].trim() : frontmatter.increment;
27
- const problemStatement = this.extractSection(bodyContent, "Problem Statement");
28
- const userStories = this.extractUserStories(bodyContent);
29
- const outOfScopeSection = this.extractSection(bodyContent, "Out of Scope");
30
- const outOfScope = outOfScopeSection.split("\n").filter((line) => line.startsWith("-")).map((line) => line.replace(/^-\s*/, "").trim());
31
- const tasks = await this.extractTasks();
32
- return {
33
- frontmatter,
34
- title,
35
- problemStatement,
36
- userStories,
37
- tasks,
38
- outOfScope
39
- };
40
- }
41
- /**
42
- * Extract tasks from tasks.md
43
- */
44
- async extractTasks() {
45
- const tasksPath = path.join(this.incrementPath, "tasks.md");
46
- if (!existsSync(tasksPath)) {
47
- return [];
48
- }
49
- try {
50
- const content = await readFile(tasksPath, "utf-8");
51
- const tasks = [];
52
- const taskBlocks = content.split(/(?=###\s+T-\d+)/);
53
- for (const block of taskBlocks) {
54
- const headerMatch = block.match(/###\s+(T-\d+):\s*(.+)/);
55
- if (!headerMatch) continue;
56
- const id = headerMatch[1];
57
- const title = headerMatch[2].trim();
58
- const statusMatch = block.match(/\*\*Status\*\*:\s*\[([x\s])\]/i);
59
- const completed = statusMatch ? statusMatch[1].toLowerCase() === "x" : false;
60
- const userStoryMatch = block.match(/\*\*User Story\*\*:\s*([^\n]+)/i);
61
- const satisfiesMatch = block.match(/\*\*Satisfies ACs?\*\*:\s*([^\n]+)/i);
62
- let userStories = [];
63
- if (userStoryMatch) {
64
- userStories = userStoryMatch[1].split(",").map((s) => s.trim());
65
- } else if (satisfiesMatch) {
66
- const acIds = satisfiesMatch[1].split(",").map((s) => s.trim());
67
- const usIds = /* @__PURE__ */ new Set();
68
- for (const ac of acIds) {
69
- const usMatch = ac.match(/AC-(US\d+)-/i);
70
- if (usMatch) {
71
- usIds.add(usMatch[1]);
72
- }
73
- }
74
- userStories = Array.from(usIds);
75
- }
76
- const priorityMatch = block.match(/\*\*Priority\*\*:\s*(P\d)/i);
77
- const priority = priorityMatch ? priorityMatch[1] : void 0;
78
- tasks.push({
79
- id,
80
- title,
81
- completed,
82
- userStories,
83
- priority
84
- });
85
- }
86
- return tasks;
87
- } catch {
88
- return [];
89
- }
90
- }
91
- /**
92
- * Extract a section by heading
93
- */
94
- extractSection(content, heading) {
95
- const regex = new RegExp(`##\\s+${heading}\\s*\\n([\\s\\S]*?)(?=\\n##\\s|$)`, "i");
96
- const match = content.match(regex);
97
- return match ? match[1].trim() : "";
98
- }
99
- /**
100
- * Extract user stories from spec.md
101
- */
102
- extractUserStories(content) {
103
- const stories = [];
104
- const userStoriesSection = this.extractSection(content, "User Stories");
105
- if (!userStoriesSection) {
106
- return stories;
107
- }
108
- const storyBlocks = userStoriesSection.split(/(?=###\s+US-\d+)/);
109
- for (const block of storyBlocks) {
110
- const headerMatch = block.match(/###\s+(US-\d+):\s*(.+)/);
111
- if (!headerMatch) continue;
112
- const id = headerMatch[1];
113
- const title = headerMatch[2].trim();
114
- const asAMatch = block.match(/\*\*As a\*\*\s+([^\n]+)/i);
115
- const iWantMatch = block.match(/\*\*I want\*\*\s+([^\n]+)/i);
116
- const soThatMatch = block.match(/\*\*So that\*\*\s+([^\n]+)/i);
117
- const acceptanceCriteria = this.extractAcceptanceCriteria(block, id);
118
- stories.push({
119
- id,
120
- title,
121
- asA: asAMatch ? asAMatch[1].trim().replace(/,$/, "") : "",
122
- iWant: iWantMatch ? iWantMatch[1].trim().replace(/,$/, "") : "",
123
- soThat: soThatMatch ? soThatMatch[1].trim().replace(/\.$/, "") : "",
124
- acceptanceCriteria
125
- });
126
- }
127
- return stories;
128
- }
129
- /**
130
- * Extract acceptance criteria from a user story block
131
- */
132
- extractAcceptanceCriteria(block, userStoryId) {
133
- const criteria = [];
134
- const acPattern = /-\s*\[([ x])\]\s*\*\*AC-(US\d+)-(\d+)\*\*:\s*(.+)/gi;
135
- let match;
136
- while ((match = acPattern.exec(block)) !== null) {
137
- const completed = match[1].toLowerCase() === "x";
138
- const usNum = match[2];
139
- const acNum = match[3];
140
- const description = match[4].trim();
141
- criteria.push({
142
- id: `AC-${usNum}-${acNum}`,
143
- description,
144
- completed
145
- });
146
- }
147
- return criteria;
148
- }
149
- /**
150
- * Build GitHub issue for a single user story
151
- */
152
- buildUserStoryIssue(story, incrementData, githubRepo) {
153
- const featureId = incrementData.frontmatter.feature_id || this.generateFeatureId(incrementData);
154
- const incrementId = incrementData.frontmatter.increment;
155
- const title = `[${featureId}][${story.id}] ${story.title}`;
156
- let body = "";
157
- const completedACs = story.acceptanceCriteria.filter((ac) => ac.completed).length;
158
- const totalACs = story.acceptanceCriteria.length;
159
- const storyTasks = incrementData.tasks.filter(
160
- (t) => t.userStories.includes(story.id) || t.userStories.some((us) => us.toUpperCase() === story.id.toUpperCase())
161
- );
162
- const completedTasks = storyTasks.filter((t) => t.completed).length;
163
- const totalTasks = storyTasks.length;
164
- const overallPercentage = totalACs + totalTasks > 0 ? Math.round((completedACs + completedTasks) / (totalACs + totalTasks) * 100) : 0;
165
- body += `## Progress
166
-
167
- `;
168
- body += `**Acceptance Criteria**: ${completedACs}/${totalACs} (${totalACs > 0 ? Math.round(completedACs / totalACs * 100) : 0}%)
169
- `;
170
- body += `**Tasks**: ${completedTasks}/${totalTasks} (${totalTasks > 0 ? Math.round(completedTasks / totalTasks * 100) : 0}%)
171
- `;
172
- body += `**Overall**: ${overallPercentage}%
173
-
174
- `;
175
- const filledBlocks = Math.floor(overallPercentage / 5);
176
- const emptyBlocks = 20 - filledBlocks;
177
- body += `${"\u2588".repeat(filledBlocks)}${"\u2591".repeat(emptyBlocks)} ${overallPercentage}%
178
-
179
- `;
180
- body += `---
181
-
182
- `;
183
- body += `## User Story
184
-
185
- `;
186
- if (story.asA && story.iWant && story.soThat) {
187
- body += `**As a** ${story.asA}
188
- `;
189
- body += `**I want** ${story.iWant}
190
- `;
191
- body += `**So that** ${story.soThat}
192
-
193
- `;
194
- } else {
195
- body += `${story.title}
196
-
197
- `;
198
- }
199
- body += `---
200
-
201
- `;
202
- body += `## Acceptance Criteria
203
-
204
- `;
205
- if (story.acceptanceCriteria.length > 0) {
206
- const completed = story.acceptanceCriteria.filter((ac) => ac.completed).length;
207
- const total = story.acceptanceCriteria.length;
208
- const percentage = total > 0 ? Math.round(completed / total * 100) : 0;
209
- body += `Progress: ${completed}/${total} criteria met (${percentage}%)
210
-
211
- `;
212
- for (const ac of story.acceptanceCriteria) {
213
- const checkbox = ac.completed ? "[x]" : "[ ]";
214
- body += `- ${checkbox} **${ac.id}**: ${ac.description}
215
- `;
216
- }
217
- body += "\n";
218
- } else {
219
- body += `*No acceptance criteria defined*
220
-
221
- `;
222
- }
223
- body += `---
224
-
225
- `;
226
- if (storyTasks.length > 0) {
227
- body += `## Tasks
228
-
229
- `;
230
- const completedTasks2 = storyTasks.filter((t) => t.completed).length;
231
- body += `Progress: ${completedTasks2}/${storyTasks.length} tasks
232
-
233
- `;
234
- for (const task of storyTasks) {
235
- const checkbox = task.completed ? "[x]" : "[ ]";
236
- body += `- ${checkbox} **${task.id}**: ${task.title}
237
- `;
238
- }
239
- body += "\n---\n\n";
240
- }
241
- body += `## Implementation
242
-
243
- `;
244
- if (githubRepo) {
245
- body += `**Increment**: [${incrementId}](https://github.com/${githubRepo}/tree/develop/.specweave/increments/${incrementId})
246
-
247
- `;
248
- } else {
249
- body += `**Increment**: ${incrementId}
250
-
251
- `;
252
- }
253
- body += `---
254
-
255
- `;
256
- body += `\u{1F916} Auto-synced by SpecWeave Increment Sync`;
257
- const labels = ["specweave", "user-story"];
258
- if (incrementData.frontmatter.type) {
259
- labels.push(incrementData.frontmatter.type.toLowerCase());
260
- }
261
- const priority = story.priority?.toLowerCase() || incrementData.frontmatter.priority?.toLowerCase() || "p2";
262
- labels.push(priority);
263
- return { title, body, labels };
264
- }
265
- /**
266
- * Build GitHub issue for the entire increment (epic-style)
267
- */
268
- buildIncrementIssue(incrementData, githubRepo) {
269
- const featureId = incrementData.frontmatter.feature_id || this.generateFeatureId(incrementData);
270
- const incrementId = incrementData.frontmatter.increment;
271
- const title = `[${featureId}] ${incrementData.title}`;
272
- let body = "";
273
- body += `**Increment**: ${incrementId}
274
- `;
275
- body += `**Status**: ${incrementData.frontmatter.status || "planning"}
276
- `;
277
- body += `**Priority**: P0 (Critical)
278
- `;
279
- const totalACs = incrementData.userStories.reduce((sum, us) => sum + us.acceptanceCriteria.length, 0);
280
- const completedACs = incrementData.userStories.reduce(
281
- (sum, us) => sum + us.acceptanceCriteria.filter((ac) => ac.completed).length,
282
- 0
283
- );
284
- const percentage = totalACs > 0 ? Math.round(completedACs / totalACs * 100) : 0;
285
- body += `**Progress**: ${completedACs}/${totalACs} ACs (${percentage}%)
286
- `;
287
- body += `
288
- ---
289
-
290
- `;
291
- body += `## Overview
292
-
293
- `;
294
- body += incrementData.problemStatement || incrementData.title;
295
- body += `
296
-
297
- ---
298
-
299
- `;
300
- body += `## User Stories
301
-
302
- `;
303
- for (const story of incrementData.userStories) {
304
- const usCompleted = story.acceptanceCriteria.filter((ac) => ac.completed).length;
305
- const usTotal = story.acceptanceCriteria.length;
306
- const usCheckbox = usCompleted === usTotal && usTotal > 0 ? "[x]" : "[ ]";
307
- body += `### ${usCheckbox} ${story.id}: ${story.title}
308
-
309
- `;
310
- if (story.asA && story.iWant && story.soThat) {
311
- body += `> **As a** ${story.asA}, **I want** ${story.iWant}, **So that** ${story.soThat}
312
-
313
- `;
314
- }
315
- body += `**Acceptance Criteria:**
316
- `;
317
- for (const ac of story.acceptanceCriteria) {
318
- const checkbox = ac.completed ? "[x]" : "[ ]";
319
- body += `- ${checkbox} **${ac.id}**: ${ac.description}
320
- `;
321
- }
322
- body += "\n";
323
- }
324
- body += `---
325
-
326
- `;
327
- if (incrementData.tasks.length > 0) {
328
- body += `## Tasks
329
-
330
- `;
331
- const completedTasks = incrementData.tasks.filter((t) => t.completed).length;
332
- const totalTasks = incrementData.tasks.length;
333
- const taskPercentage = totalTasks > 0 ? Math.round(completedTasks / totalTasks * 100) : 0;
334
- body += `Progress: ${completedTasks}/${totalTasks} tasks (${taskPercentage}%)
335
-
336
- `;
337
- for (const task of incrementData.tasks) {
338
- const checkbox = task.completed ? "[x]" : "[ ]";
339
- body += `- ${checkbox} **${task.id}**: ${task.title}
340
- `;
341
- if (task.priority || task.userStories.length > 0) {
342
- const parts = [];
343
- if (task.priority) parts.push(`Priority: ${task.priority}`);
344
- if (task.userStories.length > 0) parts.push(`User ${task.userStories.length === 1 ? "Story" : "Stories"}: ${task.userStories.join(", ")}`);
345
- body += ` - ${parts.join(" | ")}
346
- `;
347
- }
348
- }
349
- body += "\n---\n\n";
350
- }
351
- body += `## SpecWeave Increment
352
-
353
- `;
354
- if (githubRepo) {
355
- body += `- **Spec**: [\`spec.md\`](https://github.com/${githubRepo}/blob/develop/.specweave/increments/${incrementId}/spec.md)
356
- `;
357
- body += `- **Plan**: [\`plan.md\`](https://github.com/${githubRepo}/blob/develop/.specweave/increments/${incrementId}/plan.md)
358
- `;
359
- body += `- **Tasks**: [\`tasks.md\`](https://github.com/${githubRepo}/blob/develop/.specweave/increments/${incrementId}/tasks.md)
360
- `;
361
- } else {
362
- body += `- **Spec**: \`spec.md\`
363
- `;
364
- body += `- **Plan**: \`plan.md\`
365
- `;
366
- body += `- **Tasks**: \`tasks.md\`
367
- `;
368
- }
369
- body += `
370
- ---
371
-
372
- `;
373
- body += `\u{1F916} Auto-synced by SpecWeave Increment Sync`;
374
- const labels = ["specweave", "increment"];
375
- const typeLabel = incrementData.frontmatter.type?.toLowerCase() || "enhancement";
376
- labels.push(typeLabel);
377
- const priority = incrementData.frontmatter.priority?.toLowerCase() || "p2";
378
- labels.push(priority);
379
- return { title, body, labels };
380
- }
381
- /**
382
- * Generate a feature ID if not present in frontmatter
383
- * Uses date-based format: FS-YY-MM-DD
384
- */
385
- generateFeatureId(incrementData) {
386
- const incrementNum = incrementData.frontmatter.increment.match(/^(\d+)/)?.[1];
387
- if (incrementNum) {
388
- return `FS-${incrementNum.padStart(3, "0")}`;
389
- }
390
- const created = incrementData.frontmatter.created;
391
- if (created) {
392
- const match = created.match(/^(\d{4})-(\d{2})-(\d{2})/);
393
- if (match) {
394
- return `FS-${match[1].slice(2)}-${match[2]}-${match[3]}`;
395
- }
396
- }
397
- return "FS-UNKNOWN";
398
- }
399
- }
400
- export {
401
- IncrementIssueBuilder
402
- };