specweave 0.26.11 → 0.26.14

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 (83) hide show
  1. package/dist/plugins/specweave-github/lib/completion-calculator.d.ts +4 -1
  2. package/dist/plugins/specweave-github/lib/completion-calculator.d.ts.map +1 -1
  3. package/dist/plugins/specweave-github/lib/completion-calculator.js +49 -29
  4. package/dist/plugins/specweave-github/lib/completion-calculator.js.map +1 -1
  5. package/dist/plugins/specweave-jira/lib/setup-wizard.js +1 -1
  6. package/dist/plugins/specweave-jira/lib/setup-wizard.js.map +1 -1
  7. package/dist/src/cli/commands/import-docs.js +2 -2
  8. package/dist/src/cli/commands/import-docs.js.map +1 -1
  9. package/dist/src/cli/commands/init.js +8 -8
  10. package/dist/src/cli/commands/init.js.map +1 -1
  11. package/dist/src/cli/commands/install.js +2 -2
  12. package/dist/src/cli/commands/install.js.map +1 -1
  13. package/dist/src/cli/helpers/ado-area-path-mapper.js +3 -3
  14. package/dist/src/cli/helpers/ado-area-path-mapper.js.map +1 -1
  15. package/dist/src/cli/helpers/github/profile-manager.js +1 -1
  16. package/dist/src/cli/helpers/github/profile-manager.js.map +1 -1
  17. package/dist/src/cli/helpers/github-repo-selector.js +3 -3
  18. package/dist/src/cli/helpers/github-repo-selector.js.map +1 -1
  19. package/dist/src/cli/helpers/import-strategy-prompter.js +1 -1
  20. package/dist/src/cli/helpers/import-strategy-prompter.js.map +1 -1
  21. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js +1 -1
  22. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js.map +1 -1
  23. package/dist/src/cli/helpers/issue-tracker/github.js +3 -3
  24. package/dist/src/cli/helpers/issue-tracker/github.js.map +1 -1
  25. package/dist/src/cli/helpers/issue-tracker/index.js +1 -1
  26. package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
  27. package/dist/src/cli/helpers/issue-tracker/jira.js +1 -1
  28. package/dist/src/cli/helpers/issue-tracker/jira.js.map +1 -1
  29. package/dist/src/cli/helpers/smart-filter.js +1 -1
  30. package/dist/src/cli/helpers/smart-filter.js.map +1 -1
  31. package/dist/src/core/increment/increment-archiver.d.ts +3 -0
  32. package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
  33. package/dist/src/core/increment/increment-archiver.js +35 -4
  34. package/dist/src/core/increment/increment-archiver.js.map +1 -1
  35. package/dist/src/core/living-docs/feature-archiver.d.ts +5 -0
  36. package/dist/src/core/living-docs/feature-archiver.d.ts.map +1 -1
  37. package/dist/src/core/living-docs/feature-archiver.js +66 -18
  38. package/dist/src/core/living-docs/feature-archiver.js.map +1 -1
  39. package/dist/src/core/repo-structure/repo-bulk-discovery.js +2 -2
  40. package/dist/src/core/repo-structure/repo-bulk-discovery.js.map +1 -1
  41. package/dist/src/core/repo-structure/repo-structure-manager.js +10 -10
  42. package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
  43. package/dist/src/core/sync/bidirectional-engine.js +1 -1
  44. package/dist/src/core/sync/bidirectional-engine.js.map +1 -1
  45. package/dist/src/init/InitFlow.js +1 -1
  46. package/dist/src/init/InitFlow.js.map +1 -1
  47. package/dist/src/integrations/ado/area-path-mapper.js +1 -1
  48. package/dist/src/integrations/ado/area-path-mapper.js.map +1 -1
  49. package/dist/src/utils/external-resource-validator.js +4 -4
  50. package/dist/src/utils/external-resource-validator.js.map +1 -1
  51. package/package.json +1 -1
  52. package/plugins/PLUGINS-INDEX.md +120 -0
  53. package/plugins/specweave/commands/specweave-archive.md +10 -1
  54. package/plugins/specweave/commands/specweave-increment.md +1 -1
  55. package/plugins/specweave/commands/specweave-update-scope.md +2 -2
  56. package/plugins/specweave/hooks/hooks.json +10 -0
  57. package/plugins/specweave/hooks/lib/update-active-increment.sh +96 -0
  58. package/plugins/specweave/hooks/lib/update-status-line.sh +153 -189
  59. package/plugins/specweave/hooks/post-edit-write-consolidated.sh +6 -0
  60. package/plugins/specweave/hooks/post-metadata-change.sh +9 -0
  61. package/plugins/specweave/hooks/post-task-completion.sh +8 -0
  62. package/plugins/specweave/hooks/post-task-edit.sh +37 -0
  63. package/plugins/specweave/hooks/post-user-story-complete.sh +86 -35
  64. package/plugins/specweave/hooks/pre-command-deduplication.sh +43 -53
  65. package/plugins/specweave/hooks/pre-tool-use.sh +5 -0
  66. package/plugins/specweave/hooks/user-prompt-submit.sh +143 -289
  67. package/plugins/specweave/lib/hooks/us-completion-orchestrator.js +62 -1
  68. package/plugins/specweave/lib/hooks/us-completion-orchestrator.ts +106 -3
  69. package/plugins/specweave/skills/SKILLS-INDEX.md +69 -225
  70. package/plugins/specweave-ado/commands/specweave-ado-import-projects.md +1 -1
  71. package/plugins/specweave-ado/lib/project-selector.js +1 -1
  72. package/plugins/specweave-ado/lib/project-selector.ts +1 -1
  73. package/plugins/specweave-ado/skills/ado-resource-validator/SKILL.md +1 -1
  74. package/plugins/specweave-github/lib/completion-calculator.js +34 -16
  75. package/plugins/specweave-github/lib/completion-calculator.ts +54 -32
  76. package/plugins/specweave-github/lib/repo-selector.js +1 -1
  77. package/plugins/specweave-github/lib/repo-selector.ts +1 -1
  78. package/plugins/specweave-jira/lib/project-selector.js +1 -1
  79. package/plugins/specweave-jira/lib/project-selector.ts +1 -1
  80. package/plugins/specweave-jira/lib/setup-wizard.js +1 -1
  81. package/plugins/specweave-jira/lib/setup-wizard.ts +1 -1
  82. package/src/templates/AGENTS.md.template +301 -2452
  83. package/src/templates/CLAUDE.md.template +99 -667
@@ -212,8 +212,11 @@ export class CompletionCalculator {
212
212
  * Process:
213
213
  * 1. Find increment link in user story's "Implementation" section
214
214
  * 2. Read increment's tasks.md
215
- * 3. Filter tasks that reference this user story's ACs
215
+ * 3. Filter tasks that reference this user story (via **User Story** field OR AC-IDs)
216
216
  * 4. Extract completion status from **Status**: [x] or [ ]
217
+ *
218
+ * IMPORTANT: Checks **User Story** field FIRST (handles multi-story tasks like "US-001, US-002"),
219
+ * then falls back to AC-based filtering. Also handles "Satisfies ACs: All" correctly.
217
220
  */
218
221
  private async extractTasks(userStoryContent: string, userStoryId: string): Promise<Task[]> {
219
222
  const tasks: Task[] = [];
@@ -252,12 +255,20 @@ export class CompletionCalculator {
252
255
 
253
256
  const tasksContent = await readFile(tasksPath, 'utf-8');
254
257
 
255
- // Extract tasks that reference this User Story via AC-IDs
258
+ // Normalize the current user story ID for comparison
259
+ // Handles: "US-001", "US-1", "US001", "001"
260
+ const normalizeUsId = (id: string): string => {
261
+ const num = id.replace(/^US-?0*/, ''); // Remove "US-", "US", and leading zeros
262
+ return `US-${num.padStart(3, '0')}`; // Normalize to "US-001" format
263
+ };
264
+ const normalizedCurrentUs = normalizeUsId(userStoryId);
265
+
266
+ // Extract tasks that reference this User Story
256
267
  // Pattern:
257
268
  // ### T-001: Task Title
258
- // **User Story**: ...
259
- // **Status**: [x] (100% - Completed) or [ ] (0% - Not started)
260
- // **AC**: AC-US1-01, AC-US1-02
269
+ // **User Story**: US-001, US-002 ← Check this FIRST!
270
+ // **Satisfies ACs**: AC-US1-01, AC-US1-02 (or "All")
271
+ // **Status**: [x] completed
261
272
  const taskPattern = /###?\s+(T-\d+):\s*([^\n]+)\n([\s\S]*?)(?=\n###?\s+T-\d+:|$)/g;
262
273
  let match;
263
274
 
@@ -266,34 +277,41 @@ export class CompletionCalculator {
266
277
  const taskTitle = match[2].trim();
267
278
  const taskBody = match[3];
268
279
 
269
- // Extract AC list (support both old and new field names)
270
- const acMatch = taskBody.match(/\*\*(?:Satisfies ACs?|AC)\*\*:\s*([^\n]+)/);
271
- if (!acMatch) {
272
- continue; // Skip tasks without AC field
280
+ // PRIORITY 1: Check **User Story** field directly (handles multi-story tasks!)
281
+ // Pattern: **User Story**: US-001, US-002, US-003
282
+ const userStoryFieldMatch = taskBody.match(/\*\*User Story\*\*:\s*([^\n]+)/);
283
+ let belongsToThisUS = false;
284
+
285
+ if (userStoryFieldMatch) {
286
+ const userStoryList = userStoryFieldMatch[1].trim();
287
+ // Split by comma and check if any matches current user story
288
+ const userStoryIds = userStoryList.split(',').map((us) => us.trim());
289
+ belongsToThisUS = userStoryIds.some((usId) => {
290
+ return normalizeUsId(usId) === normalizedCurrentUs;
291
+ });
292
+ }
293
+
294
+ // PRIORITY 2: Fall back to AC-based filtering (legacy support)
295
+ if (!belongsToThisUS) {
296
+ const acMatch = taskBody.match(/\*\*(?:Satisfies ACs?|AC)\*\*:\s*([^\n]+)/);
297
+ if (acMatch) {
298
+ const acList = acMatch[1].trim();
299
+
300
+ // Handle special "All" case - if "All", include task if User Story field matched
301
+ // (already handled above), otherwise skip AC-based check for "All"
302
+ if (acList.toLowerCase() !== 'all') {
303
+ const acIds = acList.split(',').map((ac) => ac.trim());
304
+ belongsToThisUS = acIds.some((acId) => {
305
+ // Extract US ID from AC-ID: AC-US1-01 → US-001
306
+ const usMatch = acId.match(/AC-([A-Z]+\d+)-/);
307
+ if (!usMatch) return false;
308
+
309
+ const extractedUsId = usMatch[1]; // e.g., "US1" or "US001"
310
+ return normalizeUsId(extractedUsId) === normalizedCurrentUs;
311
+ });
312
+ }
313
+ }
273
314
  }
274
- const acList = acMatch[1].trim();
275
-
276
- // Check if any AC in this task belongs to current User Story
277
- // AC-US1-01 → US-001
278
- // AC-US001-01 → US-001
279
- const acIds = acList.split(',').map((ac) => ac.trim());
280
- const belongsToThisUS = acIds.some((acId) => {
281
- // Extract US ID from AC-ID
282
- // AC-US1-01 → US1 → US-001
283
- // AC-US001-01 → US001 → US-001
284
- const usMatch = acId.match(/AC-([A-Z]+\d+)-/);
285
- if (!usMatch) return false;
286
-
287
- // Normalize to US-XXX format (pad with zeros)
288
- const extractedUsId = usMatch[1]; // e.g., "US1" or "US001"
289
- const extractedNum = extractedUsId.replace(/^US/, ''); // "1" or "001"
290
- const normalizedExtracted = `US-${extractedNum.padStart(3, '0')}`; // "US-001"
291
-
292
- const currentNum = userStoryId.replace(/^US-?/, ''); // "001" or "1"
293
- const normalizedCurrent = `US-${currentNum.padStart(3, '0')}`; // "US-001"
294
-
295
- return normalizedExtracted === normalizedCurrent;
296
- });
297
315
 
298
316
  if (!belongsToThisUS) {
299
317
  continue;
@@ -303,6 +321,10 @@ export class CompletionCalculator {
303
321
  const statusMatch = taskBody.match(/\*\*Status\*\*:\s*\[([x ])\]/);
304
322
  const completed = statusMatch ? statusMatch[1] === 'x' : false;
305
323
 
324
+ // Extract AC list for userStories field (for backward compatibility)
325
+ const acMatch = taskBody.match(/\*\*(?:Satisfies ACs?|AC)\*\*:\s*([^\n]+)/);
326
+ const acIds = acMatch ? acMatch[1].trim().split(',').map((ac) => ac.trim()) : [];
327
+
306
328
  tasks.push({
307
329
  id: taskId,
308
330
  title: taskTitle,
@@ -36,7 +36,7 @@ async function selectGitHubRepos(options = {}) {
36
36
  `);
37
37
  const { selectionMethod } = await inquirer.prompt([
38
38
  {
39
- type: "list",
39
+ type: "select",
40
40
  name: "selectionMethod",
41
41
  message: "How would you like to select repositories?",
42
42
  choices: [
@@ -111,7 +111,7 @@ export async function selectGitHubRepos(
111
111
  // Decide selection method
112
112
  const { selectionMethod } = await inquirer.prompt([
113
113
  {
114
- type: 'list',
114
+ type: 'select',
115
115
  name: 'selectionMethod',
116
116
  message: 'How would you like to select repositories?',
117
117
  choices: [
@@ -33,7 +33,7 @@ async function selectJiraProjects(client, options = {}) {
33
33
  `);
34
34
  const { selectionMethod } = await inquirer.prompt([
35
35
  {
36
- type: "list",
36
+ type: "select",
37
37
  name: "selectionMethod",
38
38
  message: "How would you like to select projects?",
39
39
  choices: [
@@ -103,7 +103,7 @@ export async function selectJiraProjects(
103
103
  // Decide selection method
104
104
  const { selectionMethod } = await inquirer.prompt([
105
105
  {
106
- type: 'list',
106
+ type: 'select',
107
107
  name: 'selectionMethod',
108
108
  message: 'How would you like to select projects?',
109
109
  choices: [
@@ -39,7 +39,7 @@ async function setupJiraCredentials() {
39
39
  }
40
40
  const answers = await inquirer.prompt([
41
41
  {
42
- type: "list",
42
+ type: "select",
43
43
  name: "setupType",
44
44
  message: "How would you like to connect to Jira?",
45
45
  choices: [
@@ -86,7 +86,7 @@ export async function setupJiraCredentials(): Promise<JiraCredentials> {
86
86
  // Interactive credential entry
87
87
  const answers = await inquirer.prompt([
88
88
  {
89
- type: 'list',
89
+ type: 'select',
90
90
  name: 'setupType',
91
91
  message: 'How would you like to connect to Jira?',
92
92
  choices: [