specweave 0.26.4 → 0.26.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.
Files changed (82) hide show
  1. package/CLAUDE.md +154 -4
  2. package/bin/specweave.js +15 -0
  3. package/dist/plugins/specweave-github/lib/completion-calculator.js +2 -2
  4. package/dist/plugins/specweave-github/lib/completion-calculator.js.map +1 -1
  5. package/dist/plugins/specweave-github/lib/github-feature-sync.d.ts +28 -1
  6. package/dist/plugins/specweave-github/lib/github-feature-sync.d.ts.map +1 -1
  7. package/dist/plugins/specweave-github/lib/github-feature-sync.js +191 -19
  8. package/dist/plugins/specweave-github/lib/github-feature-sync.js.map +1 -1
  9. package/dist/plugins/specweave-github/lib/user-story-issue-builder.d.ts +3 -0
  10. package/dist/plugins/specweave-github/lib/user-story-issue-builder.d.ts.map +1 -1
  11. package/dist/plugins/specweave-github/lib/user-story-issue-builder.js +25 -2
  12. package/dist/plugins/specweave-github/lib/user-story-issue-builder.js.map +1 -1
  13. package/dist/src/cli/commands/archive.d.ts +10 -0
  14. package/dist/src/cli/commands/archive.d.ts.map +1 -0
  15. package/dist/src/cli/commands/archive.js +78 -0
  16. package/dist/src/cli/commands/archive.js.map +1 -0
  17. package/dist/src/cli/commands/init.js +2 -2
  18. package/dist/src/cli/commands/init.js.map +1 -1
  19. package/dist/src/cli/helpers/init/initial-increment-generator.d.ts.map +1 -1
  20. package/dist/src/cli/helpers/init/initial-increment-generator.js +48 -8
  21. package/dist/src/cli/helpers/init/initial-increment-generator.js.map +1 -1
  22. package/dist/src/core/increment/increment-reopener.d.ts.map +1 -1
  23. package/dist/src/core/increment/increment-reopener.js +13 -14
  24. package/dist/src/core/increment/increment-reopener.js.map +1 -1
  25. package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
  26. package/dist/src/core/increment/metadata-manager.js +19 -0
  27. package/dist/src/core/increment/metadata-manager.js.map +1 -1
  28. package/dist/src/core/increment/status-change-sync-trigger.d.ts +85 -0
  29. package/dist/src/core/increment/status-change-sync-trigger.d.ts.map +1 -0
  30. package/dist/src/core/increment/status-change-sync-trigger.js +137 -0
  31. package/dist/src/core/increment/status-change-sync-trigger.js.map +1 -0
  32. package/dist/src/core/increment/sync-circuit-breaker.d.ts +64 -0
  33. package/dist/src/core/increment/sync-circuit-breaker.d.ts.map +1 -0
  34. package/dist/src/core/increment/sync-circuit-breaker.js +95 -0
  35. package/dist/src/core/increment/sync-circuit-breaker.js.map +1 -0
  36. package/dist/src/core/living-docs/living-docs-sync.d.ts +12 -0
  37. package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
  38. package/dist/src/core/living-docs/living-docs-sync.js +157 -24
  39. package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
  40. package/dist/src/init/repo/types.d.ts +1 -1
  41. package/package.json +2 -2
  42. package/plugins/specweave/agents/pm/AGENT.md +13 -7
  43. package/plugins/specweave/commands/sync-diagnostics.md +227 -0
  44. package/plugins/specweave/hooks/docs-changed.sh.backup +79 -0
  45. package/plugins/specweave/hooks/human-input-required.sh.backup +75 -0
  46. package/plugins/specweave/hooks/post-first-increment.sh.backup +61 -0
  47. package/plugins/specweave/hooks/post-increment-change.sh.backup +98 -0
  48. package/plugins/specweave/hooks/post-increment-completion.sh.backup +231 -0
  49. package/plugins/specweave/hooks/post-increment-planning.sh.backup +1048 -0
  50. package/plugins/specweave/hooks/post-increment-status-change.sh.backup +147 -0
  51. package/plugins/specweave/hooks/post-spec-update.sh.backup +158 -0
  52. package/plugins/specweave/hooks/post-user-story-complete.sh.backup +179 -0
  53. package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +83 -0
  54. package/plugins/specweave/hooks/pre-implementation.sh.backup +67 -0
  55. package/plugins/specweave/hooks/pre-task-completion.sh.backup +194 -0
  56. package/plugins/specweave/hooks/pre-tool-use.sh.backup +133 -0
  57. package/plugins/specweave/hooks/user-prompt-submit.sh +20 -8
  58. package/plugins/specweave/hooks/user-prompt-submit.sh.backup +386 -0
  59. package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js +19 -0
  60. package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js.map +1 -1
  61. package/plugins/specweave/skills/brownfield-analyzer/SKILL.md +267 -868
  62. package/plugins/specweave/skills/increment-planner/SKILL.md +379 -1245
  63. package/plugins/specweave/skills/role-orchestrator/SKILL.md +293 -969
  64. package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +353 -0
  65. package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +172 -0
  66. package/plugins/specweave-ado/lib/ado-multi-project-sync.js +1 -0
  67. package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
  68. package/plugins/specweave-docs/skills/technical-writing/SKILL.md +333 -839
  69. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +1080 -0
  70. package/plugins/specweave-github/hooks/post-task-completion.sh.backup +258 -0
  71. package/plugins/specweave-github/lib/completion-calculator.js +1 -1
  72. package/plugins/specweave-github/lib/completion-calculator.ts +2 -2
  73. package/plugins/specweave-github/lib/github-feature-sync.js +152 -18
  74. package/plugins/specweave-github/lib/github-feature-sync.ts +225 -22
  75. package/plugins/specweave-github/lib/user-story-issue-builder.js +21 -1
  76. package/plugins/specweave-github/lib/user-story-issue-builder.ts +31 -3
  77. package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +172 -0
  78. package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
  79. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +981 -0
  80. package/plugins/specweave-release/hooks/post-task-completion.sh.backup +110 -0
  81. package/plugins/specweave-testing/skills/tdd-expert/SKILL.md +269 -749
  82. package/plugins/specweave-testing/skills/unit-testing-expert/SKILL.md +318 -810
package/CLAUDE.md CHANGED
@@ -14,6 +14,8 @@ For **contributors to SpecWeave itself** (not users).
14
14
 
15
15
  **NEVER run commands you know will fail.** Act on reasoning BEFORE execution.
16
16
 
17
+ **Context Management**: Active increment with 10+ tasks + editing unrelated 2000+ line file = crash risk (context overflow). Pause first: `/specweave:pause XXXX` → edit → `/specweave:resume XXXX`. See ADR-0133, Section 15.
18
+
17
19
  ```bash
18
20
  # ❌ WRONG: node -e "require('./dist/file.js')" (before build)
19
21
  # ✅ CORRECT: npm run rebuild && node -e "require('./dist/file.js')"
@@ -69,11 +71,36 @@ bash scripts/refresh-marketplace.sh --local # Local dev only (filesystem coupli
69
71
  3. `README.md` (optional)
70
72
 
71
73
  **Inside increment folders - ONLY at root**: `spec.md`, `plan.md`, `tasks.md`, `metadata.json`
72
- **Everything else → subfolders**: `reports/`, `scripts/`, `logs/`
74
+
75
+ **Everything else → subfolders**:
76
+ - `reports/` - Completion reports, investigation findings, final summaries
77
+ - `scripts/` - Helper scripts, automation, migration tools
78
+ - `logs/` - Debug logs, performance logs, execution traces
79
+ - `backups/` - Backup files, .backup versions
80
+ - `docs/` - Additional documentation, diagrams, references
81
+
82
+ **Examples**:
83
+ ```
84
+ 0055-feature/
85
+ ├── spec.md ✅ Required
86
+ ├── plan.md ✅ Required
87
+ ├── tasks.md ✅ Required
88
+ ├── metadata.json ✅ Required
89
+ ├── reports/ ✅ Good organization
90
+ │ ├── completion-summary.md
91
+ │ └── FINAL-REPORT.md
92
+ ├── scripts/ ✅ Good organization
93
+ │ └── migration.sh
94
+ └── backups/ ✅ Good organization
95
+ └── SKILL.md.backup
96
+ ```
73
97
 
74
98
  ```bash
75
99
  # Validation (should output NOTHING):
76
100
  ls -1 .specweave/increments/ | grep -v "^[0-9]" | grep -v "^_archive" | grep -v "^README.md"
101
+
102
+ # Check for misplaced files in increment roots:
103
+ find .specweave/increments -maxdepth 2 -type f ! -name "spec.md" ! -name "plan.md" ! -name "tasks.md" ! -name "metadata.json" | grep -E "/[0-9]{4}-"
77
104
  ```
78
105
 
79
106
  ---
@@ -264,6 +291,39 @@ ls .specweave/docs/internal/architecture/adr/*.md | grep -E '/[0-9]{4}-' | \
264
291
 
265
292
  **Agent naming**: `{plugin}:{directory}:{yaml-name}`
266
293
 
294
+ ### Skills Must NOT Spawn Large Content-Generating Agents (ADR-0133)
295
+
296
+ **CRITICAL**: Skills spawning agents via `Task()` causes Claude Code crashes due to context explosion.
297
+
298
+ **Problem**: Skill (1500 lines) + Agent (600 lines) + Agent output (2000+ lines) = 4000+ lines in memory = CRASH 💥
299
+
300
+ **❌ FORBIDDEN**:
301
+ ```typescript
302
+ // In a skill SKILL.md:
303
+ Task({
304
+ subagent_type: "specweave:architect:architect", // ❌ Generates 1000-3000 lines
305
+ subagent_type: "specweave:pm:pm", // ❌ Generates 500-2000 lines
306
+ subagent_type: "specweave:test-aware-planner", // ❌ Generates 500-1500 lines
307
+ });
308
+ ```
309
+
310
+ **✅ CORRECT**:
311
+ ```typescript
312
+ // Skills create templates and guide users:
313
+ 1. Create basic templates (< 50 lines each)
314
+ 2. Output: "Tell Claude: 'Complete the spec for increment 0005-feature'"
315
+ 3. Agents activate in MAIN context (not nested) = SAFE
316
+ ```
317
+
318
+ **When to use Task() from skills**:
319
+ - ✅ Small utility agents (output < 200 lines)
320
+ - ✅ Data processing agents (no large generation)
321
+ - ❌ Content generators (specs, ADRs, plans, tasks)
322
+
323
+ **Main Context Pattern**: Same explosion occurs when editing files outside active increments. Large increment spec (800+ lines) + unrelated file edit (2000+ lines) + tool invocation (AskUserQuestion) = crash. Solution: Pause increment before editing unrelated files (see Section 0).
324
+
325
+ **Reference**: ADR-0133, Architect crash incident (2025-11-24, Increment 0052); Context explosion incident (2025-11-24, Increment 0058, init.ts edit)
326
+
267
327
  ---
268
328
 
269
329
  ## 16. YAML Frontmatter
@@ -307,6 +367,94 @@ const result = await provider.validateRepository('owner', 'repo', token);
307
367
 
308
368
  ---
309
369
 
370
+ ## Sync Orchestration Architecture (v0.26.3+)
371
+
372
+ ### **How GitHub Issue Sync Works**
373
+
374
+ **3-Phase Sync Flow**:
375
+ ```
376
+ TodoWrite → Hook → US Completion Orchestrator → Living Docs Sync → External Tool Sync → GitHub Issues Updated
377
+ ```
378
+
379
+ **Phase 1: Task Completion Detection**
380
+ - User marks task complete via `TodoWrite`
381
+ - `post-task-completion.sh` fires (sets `SKIP_GITHUB_SYNC=true` to prevent duplicate syncs)
382
+ - `consolidated-sync.js` runs 6 operations sequentially
383
+
384
+ **Phase 2: US Completion Orchestration**
385
+ - `syncCompletedUserStories()` (operation 5 of 6) detects newly completed user stories
386
+ - Checks if all ACs for a US are complete (100% → status: "completed")
387
+ - **Throttle**: 60s window prevents spam (manual override: `/specweave:sync-progress`)
388
+ - If newly completed USs found → triggers Phase 3
389
+
390
+ **Phase 3: External Tool Sync**
391
+ - `LivingDocsSync.syncIncrement()` called
392
+ - `detectExternalTools()` checks **3 levels** for GitHub config:
393
+ - **Level 1**: `metadata.json` (increment-cached links)
394
+ - **Level 2**: `config.json` - **4 detection methods** (ADR-0137):
395
+ - Method 1: `config.sync.github.enabled` ← **Most common (60% of users)**
396
+ - Method 2: `config.sync.profiles[activeProfile]` ← Multi-profile setups
397
+ - Method 3: `config.multiProject.projects[project].externalTools.github` ← Multi-project
398
+ - Method 4: `config.plugins.settings['specweave-github']` ← Legacy
399
+ - **Level 3**: Environment variables (`GITHUB_TOKEN` + `GITHUB_OWNER`/`GITHUB_REPOSITORY`)
400
+ - If GitHub detected → `syncToGitHub()` → `GitHubFeatureSync.syncFeatureToGitHub()`
401
+ - Updates GitHub issues with completed AC checkboxes
402
+
403
+ ### **GitHub Configuration (Required)**
404
+
405
+ **Recommended Setup (Pattern 1 - Simplest)**:
406
+ ```json
407
+ // .specweave/config.json
408
+ {
409
+ "sync": {
410
+ "github": {
411
+ "enabled": true,
412
+ "owner": "your-org",
413
+ "repo": "your-repo"
414
+ }
415
+ }
416
+ }
417
+ ```
418
+
419
+ **Plus `.env`**:
420
+ ```bash
421
+ GITHUB_TOKEN=ghp_your_token_here
422
+ GITHUB_OWNER=your-org # Optional if in config.json
423
+ GITHUB_REPO=your-repo # Optional if in config.json
424
+ ```
425
+
426
+ **Diagnostic**: Run `node dist/test-github-detection.js` to verify detection (create this file if needed)
427
+
428
+ ### **Troubleshooting Sync Issues**
429
+
430
+ **Issue**: GitHub issues not updating after US completion
431
+ **Diagnosis**:
432
+ ```bash
433
+ # 1. Check detection
434
+ grep "External tools detected" .specweave/logs/hooks-debug.log | tail -5
435
+ # Should see: "📡 External tools detected: github"
436
+
437
+ # 2. Check config
438
+ cat .specweave/config.json | jq '.sync.github'
439
+ # Should have: enabled: true, owner: "...", repo: "..."
440
+
441
+ # 3. Check throttle
442
+ grep "throttled" .specweave/logs/hooks-debug.log | tail -3
443
+ # If throttled → wait 60s OR run: /specweave:sync-progress
444
+ ```
445
+
446
+ **Issue**: Throttle blocking sync
447
+ **Solution**: Manual sync (bypasses throttle):
448
+ ```bash
449
+ /specweave:sync-progress 0054 # Sync specific increment
450
+ /specweave-github:sync FS-054 # Sync entire feature
451
+ ```
452
+
453
+ **Issue**: Detection not finding GitHub config
454
+ **Fix**: ADR-0137 enhanced detection (v0.26.3+)
455
+ - Checks 4 config locations + env vars
456
+ - Update to latest version: `npm update specweave`
457
+
310
458
  ## Hook Performance & Safety
311
459
 
312
460
  **Emergency**: `export SPECWEAVE_DISABLE_HOOKS=1` → `rm -f .specweave/state/.hook-*` → `npm run rebuild`
@@ -316,6 +464,7 @@ const result = await provider.validateRepository('owner', 'repo', token);
316
464
  **Targets**: <100ms, 0-2 processes, 0 breaker trips
317
465
 
318
466
  **Critical Fixes**:
467
+ - v0.26.3: **Multi-location GitHub config detection!** (ADR-0137) → Checks 4 config patterns + env vars
319
468
  - v0.26.1: **Automatic US sync restored!** `SKIP_US_SYNC` removed → Smart throttle (60s window) → fs.writeFile() validated safe
320
469
  - v0.25.2: `SKIP_EXTERNAL_SYNC` guard at LivingDocsSync layer → prevents recursion cascade
321
470
  - v0.25.1: TodoWrite crash → emergency `SKIP_US_SYNC=true` → manual `/specweave:sync-progress` (temporary fix)
@@ -455,12 +604,13 @@ plugins/ # Skills, agents, commands, hooks
455
604
 
456
605
  **Remember**:
457
606
  1. Push → GitHub → auto-updates (5-10s)
458
- 2. Keep root clean (reports in increment subfolders)
607
+ 2. **Keep increment roots clean**: Only spec.md, plan.md, tasks.md, metadata.json. Everything else in subfolders (reports/, scripts/, logs/, backups/, docs/)
459
608
  3. Test before commit
460
609
  4. NEVER delete `.specweave/`
461
610
  5. Use `/specweave:done` (not manual edits)
462
611
  6. ALWAYS use GitHub mode for marketplace refresh (unless actively developing uncommitted changes)
463
612
  7. tasks.md + spec.md are SOURCE OF TRUTH (not internal TODO)
613
+ 8. Pause large increments (10+ tasks) before editing unrelated files to prevent crashes
464
614
 
465
615
  **See**: `.github/CONTRIBUTING.md`, https://spec-weave.com
466
616
 
@@ -470,8 +620,8 @@ plugins/ # Skills, agents, commands, hooks
470
620
 
471
621
  **ADRs**: 0032 (GitHub Hierarchy), 0050 (Config Management), 0051 (Caching), 0060 (Hook Optimization), 0061 (No Increment References), 0064 (AC Presence), 0069 (Git Provider Abstraction), 0070 (Hook Consolidation), 0129 (US Sync Guard Rails), 0132 (No Early Returns)
472
622
 
473
- **Emergency Procedures**: `.specweave/docs/internal/emergency-procedures/HOOK-CRASH-RECOVERY.md`, `TODOWRITE-CRASH-RECOVERY.md`, `AC-SYNC-CONFLICT-FIX-2025-11-24.md`
623
+ **Emergency Procedures**: `.specweave/docs/internal/emergency-procedures/HOOK-CRASH-RECOVERY.md`, `TODOWRITE-CRASH-RECOVERY.md`, `AC-SYNC-CONFLICT-FIX-2025-11-24.md`, `CONTEXT-EXPLOSION-PREVENTION.md`
474
624
 
475
- **Incident Reports**: See increment 0044 (TODO desync), 0047 (GitHub sync removal), 0050 (Hook crashes, AC presence, GitHub issues), 0051 (PROJECT_ROOT order), 0053 (Safe deletion, TodoWrite crash, AC parser, GitHub multi-repo)
625
+ **Incident Reports**: See increment 0044 (TODO desync), 0047 (GitHub sync removal), 0050 (Hook crashes, AC presence, GitHub issues), 0051 (PROJECT_ROOT order), 0053 (Safe deletion, TodoWrite crash, AC parser, GitHub multi-repo), 0058 (Context explosion, init.ts edit crash)
476
626
 
477
627
  **Validation Scripts**: `validate-marketplace-plugins.sh`, `validate-plugin-directories.sh`, `validate-hook-variable-order.sh`, `cleanup-duplicate-github-issues.sh`
package/bin/specweave.js CHANGED
@@ -104,6 +104,21 @@ program
104
104
  await abandonCommand(incrementId, options);
105
105
  });
106
106
 
107
+ // Archive command - Archive completed increments and sync living docs
108
+ program
109
+ .command('archive [increments...]')
110
+ .description('Archive completed increments and sync living docs (_features/ + project-specific)')
111
+ .option('--keep-last <n>', 'Keep last N increments, archive the rest', '10')
112
+ .option('--older-than <days>', 'Archive increments older than N days')
113
+ .option('--pattern <pattern>', 'Archive increments matching pattern (regex)')
114
+ .option('--archive-completed', 'Archive all completed increments')
115
+ .option('--no-preserve-active', 'Allow archiving active/paused increments (dangerous!)')
116
+ .option('--dry-run', 'Preview what would be archived without moving files')
117
+ .action(async (incrementIds, options) => {
118
+ const { archiveCommand } = await import('../dist/src/cli/commands/archive.js');
119
+ await archiveCommand(incrementIds, options);
120
+ });
121
+
107
122
  // Delete feature command - Registered dynamically in startup
108
123
  // (See registerDeleteFeatureCommand call below)
109
124
 
@@ -169,8 +169,8 @@ export class CompletionCalculator {
169
169
  const taskId = match[1];
170
170
  const taskTitle = match[2].trim();
171
171
  const taskBody = match[3];
172
- // Extract AC list
173
- const acMatch = taskBody.match(/\*\*AC\*\*:\s*([^\n]+)/);
172
+ // Extract AC list (support both old and new field names)
173
+ const acMatch = taskBody.match(/\*\*(?:Satisfies ACs?|AC)\*\*:\s*([^\n]+)/);
174
174
  if (!acMatch) {
175
175
  continue; // Skip tasks without AC field
176
176
  }
@@ -1 +1 @@
1
- {"version":3,"file":"completion-calculator.js","sourceRoot":"","sources":["../../../../plugins/specweave-github/lib/completion-calculator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAsD7B,MAAM,OAAO,oBAAoB;IAG/B,YAAY,WAAmB;QAC7B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IACjC,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,mBAAmB,CAAC,aAAqB;QAC7C,oCAAoC;QACpC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QACvD,MAAM,WAAW,GAAG,IAAI,CAAC,yBAAyB,CAAC,OAAO,CAAC,CAAC;QAE5D,sCAAsC;QACtC,MAAM,GAAG,GAAG,IAAI,CAAC,yBAAyB,CAAC,OAAO,CAAC,CAAC;QAEpD,mDAAmD;QACnD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;QAE/D,4BAA4B;QAC5B,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC;QAC7D,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC;QAE/D,uCAAuC;QACvC,aAAa;QACb,0CAA0C;QAC1C,sBAAsB;QACtB,6DAA6D;QAC7D,MAAM,eAAe,GACnB,GAAG,CAAC,MAAM,GAAG,CAAC;YACd,YAAY,KAAK,GAAG,CAAC,MAAM;YAC3B,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,cAAc,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC;QAE1D,OAAO;YACL,QAAQ,EAAE,GAAG,CAAC,MAAM;YACpB,YAAY;YACZ,aAAa,EAAE,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YACrE,UAAU,EAAE,KAAK,CAAC,MAAM;YACxB,cAAc;YACd,eAAe,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YAC7E,eAAe;YACf,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;YACjE,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAClE,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,yBAAyB,CAAC,OAAe;QAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAErD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;QAED,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAyB,CAAC;IACtD,CAAC;IAED;;;;;;;;;;;OAWG;IACK,yBAAyB,CAAC,OAAe;QAC/C,MAAM,QAAQ,GAAyB,EAAE,CAAC;QAE1C,yCAAyC;QACzC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;QAErF,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAE7B,sCAAsC;QACtC,4CAA4C;QAC5C,yCAAyC;QACzC,MAAM,qBAAqB,GACzB,mFAAmF,CAAC;QAEtF,wCAAwC;QACxC,wCAAwC;QACxC,MAAM,mBAAmB,GACvB,uEAAuE,CAAC;QAE1E,oCAAoC;QACpC,IAAI,KAAK,CAAC;QACV,IAAI,QAAQ,GAAG,KAAK,CAAC;QAErB,OAAO,CAAC,KAAK,GAAG,qBAAqB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAChE,QAAQ,GAAG,IAAI,CAAC;YAChB,QAAQ,CAAC,IAAI,CAAC;gBACZ,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,gCAAgC;gBAC9C,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;gBAC5B,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,qCAAqC;aACnE,CAAC,CAAC;QACL,CAAC;QAED,yDAAyD;QACzD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC9D,QAAQ,CAAC,IAAI,CAAC;oBACZ,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,gCAAgC;oBAC9C,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;oBAC5B,SAAS,EAAE,KAAK,EAAE,2BAA2B;iBAC9C,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;;;;OAQG;IACK,KAAK,CAAC,YAAY,CAAC,gBAAwB,EAAE,WAAmB;QACtE,MAAM,KAAK,GAAW,EAAE,CAAC;QAEzB,wDAAwD;QACxD,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;QAE3F,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,KAAK,CAAC,CAAC,wBAAwB;QACxC,CAAC;QAED,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAEjC,mDAAmD;QACnD,gEAAgE;QAChE,MAAM,cAAc,GAAG,WAAW,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;QAE9E,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO,KAAK,CAAC,CAAC,sBAAsB;QACtC,CAAC;QAED,MAAM,WAAW,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;QAEtC,mCAAmC;QACnC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CACzB,IAAI,CAAC,WAAW,EAChB,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,UAAU,CACX,CAAC;QAEF,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAC,CAAC,gCAAgC;QAChD,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAExD,0DAA0D;QAC1D,WAAW;QACX,wBAAwB;QACxB,sBAAsB;QACtB,+DAA+D;QAC/D,+BAA+B;QAC/B,MAAM,WAAW,GAAG,8DAA8D,CAAC;QACnF,IAAI,KAAK,CAAC;QAEV,OAAO,CAAC,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACzD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACxB,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YAE1B,kBAAkB;YAClB,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;YACzD,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,SAAS,CAAC,8BAA8B;YAC1C,CAAC;YACD,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAEjC,6DAA6D;YAC7D,qBAAqB;YACrB,uBAAuB;YACvB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;YACvD,MAAM,eAAe,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;gBAC1C,2BAA2B;gBAC3B,2BAA2B;gBAC3B,+BAA+B;gBAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;gBAC9C,IAAI,CAAC,OAAO;oBAAE,OAAO,KAAK,CAAC;gBAE3B,8CAA8C;gBAC9C,MAAM,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,yBAAyB;gBAC3D,MAAM,YAAY,GAAG,aAAa,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe;gBACtE,MAAM,mBAAmB,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,WAAW;gBAE9E,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe;gBACpE,MAAM,iBAAiB,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,WAAW;gBAE1E,OAAO,mBAAmB,KAAK,iBAAiB,CAAC;YACnD,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,eAAe,EAAE,CAAC;gBACrB,SAAS;YACX,CAAC;YAED,0DAA0D;YAC1D,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;YACnE,MAAM,SAAS,GAAG,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;YAE/D,KAAK,CAAC,IAAI,CAAC;gBACT,EAAE,EAAE,MAAM;gBACV,KAAK,EAAE,SAAS;gBAChB,SAAS,EAAE,wCAAwC;gBACnD,WAAW,EAAE,KAAK;aACnB,CAAC,CAAC;QACL,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;OAIG;IACH,sBAAsB,CAAC,UAA4B;QACjD,OAAO;;;2BAGgB,UAAU,CAAC,YAAY,IAAI,UAAU,CAAC,QAAQ;4BAC7C,UAAU,CAAC,cAAc,IAAI,UAAU,CAAC,UAAU;;;;iDAI7B,CAAC;IAChD,CAAC;IAED;;;;OAIG;IACH,oBAAoB,CAAC,UAA4B;QAC/C,MAAM,QAAQ,GAAa,EAAE,CAAC;QAE9B,QAAQ,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;QACxC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAElB,cAAc;QACd,MAAM,MAAM,GAAG,UAAU,CAAC,aAAa,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7D,QAAQ,CAAC,IAAI,CACX,GAAG,MAAM,6BAA6B,UAAU,CAAC,YAAY,IAAI,UAAU,CAAC,QAAQ,KAAK,UAAU,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CACjI,CAAC;QAEF,IAAI,UAAU,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAClB,QAAQ,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;YACrC,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;gBAC1C,QAAQ,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAElB,gBAAgB;QAChB,MAAM,QAAQ,GAAG,UAAU,CAAC,eAAe,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;QACjE,QAAQ,CAAC,IAAI,CACX,GAAG,QAAQ,8BAA8B,UAAU,CAAC,cAAc,IAAI,UAAU,CAAC,UAAU,KAAK,UAAU,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAC1I,CAAC;QAEF,IAAI,UAAU,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAClB,QAAQ,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;YACvC,KAAK,MAAM,MAAM,IAAI,UAAU,CAAC,aAAa,EAAE,CAAC;gBAC9C,QAAQ,CAAC,IAAI,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;YACnC,CAAC;QACH,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAClB,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,QAAQ,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;QAEjE,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAED;;;;OAIG;IACH,kBAAkB,CAChB,UAA4B,EAC5B,SAAiB,0BAA0B;QAE3C,MAAM,QAAQ,GAAa,EAAE,CAAC;QAE9B,QAAQ,CAAC,IAAI,CAAC,0BAA0B,MAAM,IAAI,CAAC,CAAC;QACpD,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAElB,QAAQ,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QACrC,QAAQ,CAAC,IAAI,CACX,0BAA0B,UAAU,CAAC,YAAY,IAAI,UAAU,CAAC,QAAQ,KAAK,UAAU,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CACrH,CAAC;QACF,QAAQ,CAAC,IAAI,CACX,2BAA2B,UAAU,CAAC,cAAc,IAAI,UAAU,CAAC,UAAU,KAAK,UAAU,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAC5H,CAAC;QAEF,MAAM,aAAa,GAAG,UAAU,CAAC,WAAW,CAAC,MAAM,GAAG,UAAU,CAAC,aAAa,CAAC,MAAM,CAAC;QAEtF,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;YACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAClB,QAAQ,CAAC,IAAI,CAAC,uBAAuB,aAAa,IAAI,CAAC,CAAC;YAExD,IAAI,UAAU,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAClB,QAAQ,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;gBAC1C,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;oBAC1C,QAAQ,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;gBACjC,CAAC;YACH,CAAC;YAED,IAAI,UAAU,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAClB,QAAQ,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;gBAC3C,KAAK,MAAM,MAAM,IAAI,UAAU,CAAC,aAAa,EAAE,CAAC;oBAC9C,QAAQ,CAAC,IAAI,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;gBACnC,CAAC;YACH,CAAC;QACH,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAClB,QAAQ,CAAC,IAAI,CAAC,+EAA+E,CAAC,CAAC;QAC/F,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAClB,QAAQ,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;QAElE,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;CACF"}
1
+ {"version":3,"file":"completion-calculator.js","sourceRoot":"","sources":["../../../../plugins/specweave-github/lib/completion-calculator.ts"],"names":[],"mappings":"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"}
@@ -20,6 +20,8 @@ export declare class GitHubFeatureSync {
20
20
  private specsDir;
21
21
  private projectRoot;
22
22
  private calculator;
23
+ private static syncLocks;
24
+ private static readonly LOCK_DURATION_MS;
23
25
  constructor(client: GitHubClientV2, specsDir: string, projectRoot: string);
24
26
  /**
25
27
  * Sync Feature folder to GitHub (Milestone + User Story Issues)
@@ -54,7 +56,7 @@ export declare class GitHubFeatureSync {
54
56
  */
55
57
  private findProjectFolders;
56
58
  /**
57
- * Create GitHub Milestone for Feature
59
+ * Create GitHub Milestone for Feature (with duplicate detection)
58
60
  */
59
61
  private createMilestone;
60
62
  /**
@@ -75,6 +77,31 @@ export declare class GitHubFeatureSync {
75
77
  * This prevents Issue #574 type bugs (premature closure)
76
78
  */
77
79
  private updateUserStoryIssue;
80
+ /**
81
+ * Update status labels on GitHub issue based on completion state
82
+ *
83
+ * SMART LABEL MANAGEMENT:
84
+ * - Only manages status:* labels (status:not_started, status:in-progress, status:completed)
85
+ * - Preserves all other labels (priority, type, custom labels)
86
+ * - Ensures exactly one status label is present
87
+ */
88
+ private updateStatusLabels;
89
+ /**
90
+ * Post progress comment only if it differs from the last comment
91
+ *
92
+ * DEDUPLICATION FIX (2025-11-24):
93
+ * - Prevents posting identical consecutive comments
94
+ * - Fetches last comment from issue
95
+ * - Compares content (ignoring timestamps)
96
+ * - Only posts if progress has changed
97
+ *
98
+ * Root Cause: updateUserStoryIssue() was posting progress comments on EVERY sync,
99
+ * even when progress hadn't changed, causing 4+ duplicate comments.
100
+ *
101
+ * @param issueNumber - GitHub issue number
102
+ * @param completion - Completion status with AC/task metrics
103
+ */
104
+ private postProgressCommentIfChanged;
78
105
  /**
79
106
  * Update FEATURE.md with GitHub Milestone link
80
107
  */
@@ -1 +1 @@
1
- {"version":3,"file":"github-feature-sync.d.ts","sourceRoot":"","sources":["../../../../plugins/specweave-github/lib/github-feature-sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAgCvD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,UAAU,CAAuB;gBAE7B,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;IAOzE;;;;;;;;OAQG;IACG,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QACpD,eAAe,EAAE,MAAM,CAAC;QACxB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,EAAE,MAAM,CAAC;QACtB,oBAAoB,EAAE,MAAM,CAAC;KAC9B,CAAC;IAmKF;;OAEG;YACW,iBAAiB;IAU/B;;OAEG;YACW,cAAc;IAW5B;;OAEG;YACW,eAAe;IA4C7B;;OAEG;YACW,kBAAkB;IAgBhC;;OAEG;YACW,eAAe;IA+B7B;;;;;;OAMG;YACW,oBAAoB;IAoElC;;;;;;;;OAQG;YACW,oBAAoB;IA2ElC;;OAEG;YACW,eAAe;IA+B7B;;OAEG;YACW,0BAA0B;CA8BzC"}
1
+ {"version":3,"file":"github-feature-sync.d.ts","sourceRoot":"","sources":["../../../../plugins/specweave-github/lib/github-feature-sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAgCvD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,UAAU,CAAuB;IAIzC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAkC;IAC1D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAErC,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;IAOzE;;;;;;;;OAQG;IACG,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QACpD,eAAe,EAAE,MAAM,CAAC;QACxB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,EAAE,MAAM,CAAC;QACtB,oBAAoB,EAAE,MAAM,CAAC;KAC9B,CAAC;IAkMF;;OAEG;YACW,iBAAiB;IAU/B;;OAEG;YACW,cAAc;IAW5B;;OAEG;YACW,eAAe;IA4C7B;;OAEG;YACW,kBAAkB;IAgBhC;;OAEG;YACW,eAAe;IA0D7B;;;;;;OAMG;YACW,oBAAoB;IA6DlC;;;;;;;;OAQG;YACW,oBAAoB;IAmElC;;;;;;;OAOG;YACW,kBAAkB;IAqEhC;;;;;;;;;;;;;;OAcG;YACW,4BAA4B;IA+D1C;;OAEG;YACW,eAAe;IA+B7B;;OAEG;YACW,0BAA0B;CA8BzC"}
@@ -39,6 +39,27 @@ export class GitHubFeatureSync {
39
39
  * 4. Update frontmatter with GitHub issue links
40
40
  */
41
41
  async syncFeatureToGitHub(featureId) {
42
+ // SYNC LOCK CHECK: Prevent concurrent/rapid syncs of the same feature
43
+ // Root cause: Two sync paths (task completion + status change) can fire simultaneously
44
+ // Result: Duplicate GitHub comments due to race condition
45
+ const now = Date.now();
46
+ const lastSync = GitHubFeatureSync.syncLocks.get(featureId);
47
+ if (lastSync && (now - lastSync) < GitHubFeatureSync.LOCK_DURATION_MS) {
48
+ const secondsRemaining = Math.ceil((GitHubFeatureSync.LOCK_DURATION_MS - (now - lastSync)) / 1000);
49
+ console.log(`\n⏭️ Sync already in progress for ${featureId} (or completed ${Math.floor((now - lastSync) / 1000)}s ago)`);
50
+ console.log(` ℹ️ Sync will be available in ${secondsRemaining}s to prevent duplicates`);
51
+ console.log(` 💡 This prevents race conditions between task completion and status change syncs`);
52
+ // Return placeholder result (sync was skipped, not failed)
53
+ return {
54
+ milestoneNumber: 0,
55
+ milestoneUrl: '',
56
+ issuesCreated: 0,
57
+ issuesUpdated: 0,
58
+ userStoriesProcessed: 0
59
+ };
60
+ }
61
+ // Acquire lock
62
+ GitHubFeatureSync.syncLocks.set(featureId, now);
42
63
  console.log(`\n🔄 Syncing Feature ${featureId} to GitHub...`);
43
64
  // 1. Load Feature FEATURE.md
44
65
  const featureFolder = await this.findFeatureFolder(featureId);
@@ -147,14 +168,20 @@ export class GitHubFeatureSync {
147
168
  }
148
169
  // Update User Story frontmatter with issue link
149
170
  await this.updateUserStoryFrontmatter(userStory.filePath, issueNumber);
171
+ // ✅ CRITICAL FIX (2025-11-24): Check completion for ALL issues (new AND reused)
172
+ // BUG: Previously only checked completion for reused issues, not new ones
173
+ // RESULT: New issues stayed OPEN even if status:complete
174
+ //
175
+ // Now we always call updateUserStoryIssue() which:
176
+ // 1. Calculates ACTUAL completion from [x] checkboxes
177
+ // 2. Closes issue if all ACs and tasks verified complete
178
+ // 3. Updates status labels automatically
179
+ await this.updateUserStoryIssue(issueNumber, issueContent, userStory.filePath);
150
180
  // Update completion tracking
151
181
  if (result.wasReused) {
152
- // Update existing issue with latest content
153
- await this.updateUserStoryIssue(issueNumber, issueContent, userStory.filePath);
154
182
  issuesUpdated++;
155
183
  }
156
184
  else {
157
- // New issue created
158
185
  issuesCreated++;
159
186
  }
160
187
  }
@@ -246,10 +273,32 @@ export class GitHubFeatureSync {
246
273
  return folders;
247
274
  }
248
275
  /**
249
- * Create GitHub Milestone for Feature
276
+ * Create GitHub Milestone for Feature (with duplicate detection)
250
277
  */
251
278
  async createMilestone(featureData) {
252
279
  const title = `${featureData.id}: ${featureData.title}`;
280
+ // CRITICAL: Check if milestone already exists before creating
281
+ const existingResult = await execFileNoThrow('gh', [
282
+ 'api',
283
+ 'repos/:owner/:repo/milestones',
284
+ '--jq',
285
+ `.[] | select(.title == "${title}") | {number, html_url}`,
286
+ ]);
287
+ // DEBUG: Log detection result
288
+ console.log(` 🔍 Milestone detection: exitCode=${existingResult.exitCode}, stdout length=${existingResult.stdout.length}`);
289
+ if (existingResult.exitCode !== 0) {
290
+ console.log(` ⚠️ Detection failed: ${existingResult.stderr}`);
291
+ }
292
+ if (existingResult.exitCode === 0 && existingResult.stdout.trim()) {
293
+ const existing = JSON.parse(existingResult.stdout);
294
+ console.log(` ♻️ Reusing existing Milestone #${existing.number}`);
295
+ return {
296
+ number: existing.number,
297
+ url: existing.html_url,
298
+ };
299
+ }
300
+ console.log(` ℹ️ No existing milestone found, creating new one...`);
301
+ // Milestone doesn't exist, create new one
253
302
  const description = `Feature ${featureData.id}\n\nStatus: ${featureData.status}\nCreated: ${featureData.created}`;
254
303
  const result = await execFileNoThrow('gh', [
255
304
  'api',
@@ -316,15 +365,10 @@ export class GitHubFeatureSync {
316
365
  console.log(` ✅ Created and verified complete: ${completion.acsCompleted}/${completion.acsTotal} ACs, ${completion.tasksCompleted}/${completion.tasksTotal} tasks`);
317
366
  }
318
367
  else {
319
- // ⚠️ INCOMPLETE - Leave open with progress comment
320
- await execFileNoThrow('gh', [
321
- 'issue',
322
- 'comment',
323
- issueNumber.toString(),
324
- '--body',
325
- this.calculator.buildProgressComment(completion),
326
- ]);
327
- console.log(` 📊 Created: ${completion.acsPercentage.toFixed(0)}% ACs, ${completion.tasksPercentage.toFixed(0)}% tasks`);
368
+ // ⚠️ INCOMPLETE - Leave open with progress comment (with deduplication)
369
+ // Note: For newly created issues, this is the first comment so deduplication
370
+ // will likely pass through, but the logic is here for consistency
371
+ await this.postProgressCommentIfChanged(issueNumber, completion);
328
372
  }
329
373
  return issueNumber;
330
374
  }
@@ -381,18 +425,142 @@ export class GitHubFeatureSync {
381
425
  console.log(` ⚠️ Reopened: ${completion.blockingAcs.length + completion.blockingTasks.length} items incomplete`);
382
426
  }
383
427
  else {
384
- // Update progress comment
428
+ // Update progress comment (with deduplication)
429
+ await this.postProgressCommentIfChanged(issueNumber, completion);
430
+ }
431
+ }
432
+ // **NEW (2025-11-24)**: Update status labels based on completion
433
+ await this.updateStatusLabels(issueNumber, completion);
434
+ }
435
+ /**
436
+ * Update status labels on GitHub issue based on completion state
437
+ *
438
+ * SMART LABEL MANAGEMENT:
439
+ * - Only manages status:* labels (status:not_started, status:in-progress, status:completed)
440
+ * - Preserves all other labels (priority, type, custom labels)
441
+ * - Ensures exactly one status label is present
442
+ */
443
+ async updateStatusLabels(issueNumber, completion) {
444
+ try {
445
+ // Get current issue labels
446
+ const issueData = await this.client.getIssue(issueNumber);
447
+ const currentLabels = issueData.labels || [];
448
+ // Separate status labels from other labels
449
+ const statusLabels = currentLabels.filter((label) => label.startsWith('status:'));
450
+ const otherLabels = currentLabels.filter((label) => !label.startsWith('status:'));
451
+ // Determine correct status label based on completion
452
+ // NOTE: Label names must match repository labels exactly
453
+ let newStatusLabel;
454
+ if (completion.overallComplete) {
455
+ newStatusLabel = 'status:complete'; // Repository uses "complete" not "completed"
456
+ }
457
+ else if (completion.acsPercentage > 0 || completion.tasksPercentage > 0) {
458
+ newStatusLabel = 'status:active'; // Repository uses "active" not "in-progress"
459
+ }
460
+ else {
461
+ newStatusLabel = 'status:not_started';
462
+ }
463
+ // Check if update needed
464
+ const needsUpdate = statusLabels.length !== 1 || !statusLabels.includes(newStatusLabel);
465
+ if (!needsUpdate) {
466
+ return; // Status label already correct
467
+ }
468
+ // Update labels using gh CLI
469
+ // Strategy: Remove old status labels first (if any), then add new one
470
+ // Step 1: Remove old status labels (only if they exist)
471
+ if (statusLabels.length > 0) {
385
472
  await execFileNoThrow('gh', [
386
473
  'issue',
387
- 'comment',
474
+ 'edit',
388
475
  issueNumber.toString(),
389
- '--body',
390
- this.calculator.buildProgressComment(completion),
476
+ '--remove-label',
477
+ ...statusLabels,
391
478
  ]);
392
- console.log(` 📊 Progress: ${completion.acsPercentage.toFixed(0)}% ACs, ${completion.tasksPercentage.toFixed(0)}% tasks`);
393
479
  }
480
+ // Step 2: Add new status label
481
+ const result = await execFileNoThrow('gh', [
482
+ 'issue',
483
+ 'edit',
484
+ issueNumber.toString(),
485
+ '--add-label',
486
+ newStatusLabel,
487
+ ]);
488
+ if (result.exitCode === 0) {
489
+ console.log(` 🏷️ Updated label: ${newStatusLabel}`);
490
+ }
491
+ else {
492
+ console.warn(` ⚠️ Failed to add label ${newStatusLabel}: ${result.stderr}`);
493
+ }
494
+ }
495
+ catch (error) {
496
+ // Non-blocking: Label update failure shouldn't break sync
497
+ console.warn(` ⚠️ Failed to update status labels: ${error.message}`);
498
+ }
499
+ }
500
+ /**
501
+ * Post progress comment only if it differs from the last comment
502
+ *
503
+ * DEDUPLICATION FIX (2025-11-24):
504
+ * - Prevents posting identical consecutive comments
505
+ * - Fetches last comment from issue
506
+ * - Compares content (ignoring timestamps)
507
+ * - Only posts if progress has changed
508
+ *
509
+ * Root Cause: updateUserStoryIssue() was posting progress comments on EVERY sync,
510
+ * even when progress hadn't changed, causing 4+ duplicate comments.
511
+ *
512
+ * @param issueNumber - GitHub issue number
513
+ * @param completion - Completion status with AC/task metrics
514
+ */
515
+ async postProgressCommentIfChanged(issueNumber, completion) {
516
+ try {
517
+ // 1. Fetch last comment from the issue
518
+ const commentsResult = await execFileNoThrow('gh', [
519
+ 'api',
520
+ 'repos/:owner/:repo/issues/' + issueNumber + '/comments',
521
+ '--jq',
522
+ '.[-1] | {body: .body, created_at: .created_at}', // Get last comment only
523
+ ]);
524
+ let lastCommentBody = '';
525
+ if (commentsResult.exitCode === 0 && commentsResult.stdout.trim()) {
526
+ try {
527
+ const lastComment = JSON.parse(commentsResult.stdout);
528
+ lastCommentBody = lastComment.body || '';
529
+ }
530
+ catch {
531
+ // No valid last comment, proceed with posting
532
+ }
533
+ }
534
+ // 2. Build new progress comment
535
+ const newCommentBody = this.calculator.buildProgressComment(completion);
536
+ // 3. Normalize both comments for comparison (remove timestamps, whitespace differences)
537
+ const normalizeComment = (text) => {
538
+ return text
539
+ .replace(/🤖 Auto-updated by SpecWeave AC Completion Gate/g, '')
540
+ .replace(/\s+/g, ' ')
541
+ .trim();
542
+ };
543
+ const normalizedLast = normalizeComment(lastCommentBody);
544
+ const normalizedNew = normalizeComment(newCommentBody);
545
+ // 4. Check if comments are identical (ignoring formatting differences)
546
+ if (normalizedLast === normalizedNew) {
547
+ console.log(` ⏭️ Progress unchanged (${completion.acsPercentage.toFixed(0)}% ACs, ${completion.tasksPercentage.toFixed(0)}% tasks) - skipping duplicate comment`);
548
+ return;
549
+ }
550
+ // 5. Post new comment only if progress has changed
551
+ await execFileNoThrow('gh', [
552
+ 'issue',
553
+ 'comment',
554
+ issueNumber.toString(),
555
+ '--body',
556
+ newCommentBody,
557
+ ]);
558
+ console.log(` 📊 Progress: ${completion.acsPercentage.toFixed(0)}% ACs, ${completion.tasksPercentage.toFixed(0)}% tasks (updated)`);
559
+ }
560
+ catch (error) {
561
+ // Non-blocking: Log error but don't break sync
562
+ console.error(` ⚠️ Failed to check/post progress comment: ${error.message}`);
394
563
  }
395
- // Note: Labels are not updated to avoid overwriting manually added labels
396
564
  }
397
565
  /**
398
566
  * Update FEATURE.md with GitHub Milestone link
@@ -441,4 +609,8 @@ export class GitHubFeatureSync {
441
609
  await writeFile(userStoryPath, newContent, 'utf-8');
442
610
  }
443
611
  }
612
+ // SYNC LOCK: Prevent concurrent syncs of the same feature
613
+ // Maps featureId → last sync timestamp
614
+ GitHubFeatureSync.syncLocks = new Map();
615
+ GitHubFeatureSync.LOCK_DURATION_MS = 30000; // 30 seconds
444
616
  //# sourceMappingURL=github-feature-sync.js.map