specweave 0.28.0 → 0.28.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -72
- package/dist/plugins/specweave-github/lib/github-client-v2.d.ts +6 -2
- package/dist/plugins/specweave-github/lib/github-client-v2.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-client-v2.js +28 -8
- package/dist/plugins/specweave-github/lib/github-client-v2.js.map +1 -1
- package/dist/plugins/specweave-github/lib/github-feature-sync-cli.d.ts +21 -0
- package/dist/plugins/specweave-github/lib/github-feature-sync-cli.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-feature-sync-cli.js +166 -0
- package/dist/plugins/specweave-github/lib/github-feature-sync-cli.js.map +1 -0
- package/dist/src/core/repo-structure/repo-structure-manager.d.ts +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.js +5 -11
- package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
- package/dist/src/core/sync/label-detector.d.ts.map +1 -1
- package/dist/src/core/sync/label-detector.js +22 -9
- package/dist/src/core/sync/label-detector.js.map +1 -1
- package/dist/src/metrics/calculators/deployment-frequency.d.ts +12 -8
- package/dist/src/metrics/calculators/deployment-frequency.d.ts.map +1 -1
- package/dist/src/metrics/calculators/deployment-frequency.js +16 -12
- package/dist/src/metrics/calculators/deployment-frequency.js.map +1 -1
- package/dist/src/metrics/dora-calculator.d.ts +2 -1
- package/dist/src/metrics/dora-calculator.d.ts.map +1 -1
- package/dist/src/metrics/dora-calculator.js +9 -4
- package/dist/src/metrics/dora-calculator.js.map +1 -1
- package/dist/src/metrics/github-client.d.ts +12 -0
- package/dist/src/metrics/github-client.d.ts.map +1 -1
- package/dist/src/metrics/github-client.js +30 -0
- package/dist/src/metrics/github-client.js.map +1 -1
- package/dist/src/sync/sync-coordinator.d.ts +33 -0
- package/dist/src/sync/sync-coordinator.d.ts.map +1 -1
- package/dist/src/sync/sync-coordinator.js +203 -2
- package/dist/src/sync/sync-coordinator.js.map +1 -1
- package/dist/src/utils/env-file-generator.d.ts +8 -23
- package/dist/src/utils/env-file-generator.d.ts.map +1 -1
- package/dist/src/utils/env-file-generator.js +31 -71
- package/dist/src/utils/env-file-generator.js.map +1 -1
- package/package.json +7 -2
- package/plugins/specweave/agents/architect/AGENT.md +2 -2
- package/plugins/specweave/agents/docs-writer/AGENT.md +2 -2
- package/plugins/specweave/agents/pm/AGENT.md +2 -2
- package/plugins/specweave/agents/qa-lead/AGENT.md +2 -2
- package/plugins/specweave/agents/security/AGENT.md +2 -2
- package/plugins/specweave/agents/tdd-orchestrator/AGENT.md +2 -2
- package/plugins/specweave/agents/tech-lead/AGENT.md +2 -2
- package/plugins/specweave/agents/test-aware-planner/AGENT.md +2 -2
- package/plugins/specweave/hooks/post-increment-completion.sh +84 -0
- package/plugins/specweave/hooks/post-increment-planning.sh +114 -7
- package/plugins/specweave/lib/hooks/sync-increment-closure.js +66 -0
- package/plugins/specweave/lib/hooks/sync-increment-closure.ts +111 -0
- package/plugins/specweave-github/lib/github-client-v2.js +32 -8
- package/plugins/specweave-github/lib/github-client-v2.ts +31 -9
- package/plugins/specweave-github/lib/github-feature-sync-cli.js +135 -0
- package/plugins/specweave-github/lib/github-feature-sync-cli.ts +194 -0
- package/plugins/specweave-github/skills/github-issue-standard/SKILL.md +43 -0
- package/plugins/specweave-infrastructure/agents/devops/AGENT.md +2 -2
- package/src/templates/.env.example +9 -26
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
name: qa-lead
|
|
3
3
|
description: QA Lead that creates test suites ONE FILE AT A TIME to prevent crashes. Handles test plans, test cases, testing strategies, quality gates. **CRITICAL CHUNKING RULE - Large test suites (15 files) done incrementally.** Activates for: QA, quality assurance, testing, test strategy, test plan, test cases, unit tests, integration tests, E2E tests, end-to-end testing, Playwright, Jest, Mocha, Cypress, test automation, test coverage, regression, test-driven development, TDD, BDD, behavior-driven development, quality gates, acceptance criteria, test data, test scenarios, smoke tests, sanity tests, exploratory testing.
|
|
4
4
|
tools: Read, Write, Edit, Bash
|
|
5
|
-
model: claude-
|
|
6
|
-
model_preference:
|
|
5
|
+
model: claude-opus-4-5-20251101
|
|
6
|
+
model_preference: opus
|
|
7
7
|
cost_profile: execution
|
|
8
8
|
fallback_behavior: flexible
|
|
9
9
|
max_response_tokens: 2000
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
name: security
|
|
3
3
|
description: Security Engineer and application security expert. Performs threat modeling, security architecture review, penetration testing, vulnerability assessment, and security compliance. Handles OWASP Top 10, authentication security, authorization, encryption, secrets management, HTTPS/TLS, CORS, CSRF, XSS, SQL injection prevention, secure coding practices, security audits, and compliance (GDPR, HIPAA, PCI-DSS, SOC 2). Activates for: security, security review, threat model, vulnerability, penetration testing, pen test, OWASP, authentication security, authorization, encryption, secrets, HTTPS, TLS, SSL, CORS, CSRF, XSS, SQL injection, secure coding, security audit, compliance, GDPR, HIPAA, PCI-DSS, SOC 2, security architecture, secrets management, rate limiting, brute force protection, session security, token security, JWT security.
|
|
4
4
|
tools: Read, Bash, Grep
|
|
5
|
-
model: claude-
|
|
6
|
-
model_preference:
|
|
5
|
+
model: claude-opus-4-5-20251101
|
|
6
|
+
model_preference: opus
|
|
7
7
|
cost_profile: planning
|
|
8
8
|
fallback_behavior: strict
|
|
9
9
|
max_response_tokens: 2000
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: tdd-orchestrator
|
|
3
3
|
description: Master TDD orchestrator specializing in red-green-refactor discipline, multi-agent workflow coordination, and comprehensive test-driven development practices. Enforces TDD best practices across teams with AI-assisted testing and modern frameworks. Use PROACTIVELY for TDD implementation and governance.
|
|
4
|
-
model: claude-
|
|
5
|
-
model_preference:
|
|
4
|
+
model: claude-opus-4-5-20251101
|
|
5
|
+
model_preference: opus
|
|
6
6
|
cost_profile: execution
|
|
7
7
|
fallback_behavior: flexible
|
|
8
8
|
max_response_tokens: 2000
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
name: tech-lead
|
|
3
3
|
description: Technical Lead that implements code ONE FILE AT A TIME to prevent crashes. Handles code review, best practices, mentorship, implementation planning. **CRITICAL CHUNKING RULE - Large implementations (auth system = auth.ts + tests + middleware) done incrementally.** Activates for: tech lead, code review, best practices, refactoring, technical debt, code quality, design patterns, SOLID principles, clean code, code standards, implementation plan, technical guidance, mentorship, code optimization, complexity analysis, technical planning, estimation, implementation strategy, code architecture.
|
|
4
4
|
tools: Read, Write, Edit, Bash
|
|
5
|
-
model: claude-
|
|
6
|
-
model_preference:
|
|
5
|
+
model: claude-opus-4-5-20251101
|
|
6
|
+
model_preference: opus
|
|
7
7
|
cost_profile: execution
|
|
8
8
|
fallback_behavior: flexible
|
|
9
9
|
max_response_tokens: 2000
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
name: test-aware-planner
|
|
3
3
|
description: Test-Aware Planning agent that generates tasks.md **ONE USER STORY AT A TIME** with embedded test plans. **CRITICAL CHUNKING RULE - Prevents crashes.** Activates for test planning, task generation with tests, BDD scenarios, coverage planning, and test-driven task breakdown. Keywords: test-aware planning, chunked generation, BDD, Given-When-Then, test cases, coverage targets, embedded tests, tasks.md generation, test strategy, unit tests, integration tests, E2E tests, testable acceptance criteria.
|
|
4
4
|
tools: Read, Write, Grep, Glob, Edit
|
|
5
|
-
model: claude-
|
|
6
|
-
model_preference:
|
|
5
|
+
model: claude-opus-4-5-20251101
|
|
6
|
+
model_preference: opus
|
|
7
7
|
cost_profile: planning
|
|
8
8
|
fallback_behavior: strict
|
|
9
9
|
max_response_tokens: 2000
|
|
@@ -366,4 +366,88 @@ else
|
|
|
366
366
|
echo ""
|
|
367
367
|
fi
|
|
368
368
|
|
|
369
|
+
# ============================================================================
|
|
370
|
+
# GITHUB ISSUE CLOSURE (v0.28.1 - CRITICAL FIX)
|
|
371
|
+
# ============================================================================
|
|
372
|
+
# After creating/syncing GitHub issues, close User Story issues for this increment.
|
|
373
|
+
# This was the MISSING feature causing issues to stay open indefinitely.
|
|
374
|
+
#
|
|
375
|
+
# WHY THIS IS SEPARATE FROM consolidated-sync.js:
|
|
376
|
+
# - consolidated-sync.js handles task-level sync (called by post-task-completion too)
|
|
377
|
+
# - sync-increment-closure.js ONLY runs on increment completion
|
|
378
|
+
# - Closing issues is a DESTRUCTIVE operation that should only happen once
|
|
379
|
+
#
|
|
380
|
+
# GATE CHECK: All gates are checked inside sync-increment-closure.js
|
|
381
|
+
# - canUpdateExternalItems must be true
|
|
382
|
+
# - autoSyncOnCompletion must be true
|
|
383
|
+
# - sync.github.enabled must be true
|
|
384
|
+
#
|
|
385
|
+
# See: Root cause analysis - User Story issues created but never closed
|
|
386
|
+
|
|
387
|
+
if command -v node &> /dev/null; then
|
|
388
|
+
echo ""
|
|
389
|
+
echo "🔒 Closing GitHub issues for completed user stories..."
|
|
390
|
+
|
|
391
|
+
# ========================================================================
|
|
392
|
+
# LOCATE CLOSURE SYNC SCRIPT
|
|
393
|
+
# ========================================================================
|
|
394
|
+
# Find sync-increment-closure.js in order of preference:
|
|
395
|
+
# 1. In-place compiled (development, esbuild output)
|
|
396
|
+
# 2. Local dist (development, tsc output)
|
|
397
|
+
# 3. node_modules (installed as dependency) ← USER PROJECTS
|
|
398
|
+
# 4. Plugin marketplace (Claude Code global installation)
|
|
399
|
+
|
|
400
|
+
CLOSURE_SCRIPT=""
|
|
401
|
+
if [ -f "$PROJECT_ROOT/plugins/specweave/lib/hooks/sync-increment-closure.js" ]; then
|
|
402
|
+
# Development: Use in-place compiled hooks (esbuild, not tsc)
|
|
403
|
+
CLOSURE_SCRIPT="$PROJECT_ROOT/plugins/specweave/lib/hooks/sync-increment-closure.js"
|
|
404
|
+
echo " 🔧 Using in-place compiled hook (development mode)"
|
|
405
|
+
elif [ -f "$PROJECT_ROOT/dist/plugins/specweave/lib/hooks/sync-increment-closure.js" ]; then
|
|
406
|
+
# Development: Use project's compiled files (has node_modules)
|
|
407
|
+
CLOSURE_SCRIPT="$PROJECT_ROOT/dist/plugins/specweave/lib/hooks/sync-increment-closure.js"
|
|
408
|
+
echo " 🔧 Using local dist (development mode)"
|
|
409
|
+
elif [ -f "$PROJECT_ROOT/node_modules/specweave/dist/plugins/specweave/lib/hooks/sync-increment-closure.js" ]; then
|
|
410
|
+
# Installed as dependency: Use node_modules version (MOST USER PROJECTS)
|
|
411
|
+
CLOSURE_SCRIPT="$PROJECT_ROOT/node_modules/specweave/dist/plugins/specweave/lib/hooks/sync-increment-closure.js"
|
|
412
|
+
echo " 📦 Using node_modules version"
|
|
413
|
+
elif [ -n "${CLAUDE_PLUGIN_ROOT}" ] && [ -f "${CLAUDE_PLUGIN_ROOT}/lib/hooks/sync-increment-closure.js" ]; then
|
|
414
|
+
# Fallback: Plugin marketplace (may fail if deps missing)
|
|
415
|
+
CLOSURE_SCRIPT="${CLAUDE_PLUGIN_ROOT}/lib/hooks/sync-increment-closure.js"
|
|
416
|
+
echo " 🌐 Using plugin marketplace version"
|
|
417
|
+
fi
|
|
418
|
+
|
|
419
|
+
# ========================================================================
|
|
420
|
+
# EXECUTE CLOSURE SYNC
|
|
421
|
+
# ========================================================================
|
|
422
|
+
# Run closure sync to close all User Story GitHub issues.
|
|
423
|
+
# Non-blocking: Errors logged but don't crash hook (increment already closed)
|
|
424
|
+
|
|
425
|
+
if [ -n "$CLOSURE_SCRIPT" ]; then
|
|
426
|
+
# Ensure GITHUB_TOKEN is available (may have been set earlier)
|
|
427
|
+
if [ -z "$GITHUB_TOKEN" ] && [ -f "$PROJECT_ROOT/.env" ]; then
|
|
428
|
+
GITHUB_TOKEN_FROM_ENV=$(grep -E '^GITHUB_TOKEN=' "$PROJECT_ROOT/.env" 2>/dev/null | head -1 | cut -d'=' -f2- | sed 's/^["'\'']//' | sed 's/["'\'']$//')
|
|
429
|
+
if [ -n "$GITHUB_TOKEN_FROM_ENV" ]; then
|
|
430
|
+
export GITHUB_TOKEN="$GITHUB_TOKEN_FROM_ENV"
|
|
431
|
+
fi
|
|
432
|
+
fi
|
|
433
|
+
|
|
434
|
+
# Run closure sync (synchronous - user sees immediate feedback)
|
|
435
|
+
if (cd "$PROJECT_ROOT" && node "$CLOSURE_SCRIPT" "$INCREMENT_ID") 2>&1; then
|
|
436
|
+
echo " ✅ GitHub issue closure complete"
|
|
437
|
+
echo ""
|
|
438
|
+
else
|
|
439
|
+
echo " ⚠️ Failed to close GitHub issues (non-blocking - you can close manually)" >&2
|
|
440
|
+
echo ""
|
|
441
|
+
fi
|
|
442
|
+
else
|
|
443
|
+
echo " ⚠️ sync-increment-closure.js not found in any location - skipping issue closure" >&2
|
|
444
|
+
echo " 💡 User Story GitHub issues may remain open until manually closed" >&2
|
|
445
|
+
echo ""
|
|
446
|
+
fi
|
|
447
|
+
else
|
|
448
|
+
echo ""
|
|
449
|
+
echo " ⚠️ Node.js not found - skipping GitHub issue closure" >&2
|
|
450
|
+
echo ""
|
|
451
|
+
fi
|
|
452
|
+
|
|
369
453
|
exit 0
|
|
@@ -896,8 +896,12 @@ EOF_MINIMAL
|
|
|
896
896
|
local spec_md_path="$increment_dir/spec.md"
|
|
897
897
|
|
|
898
898
|
if [ -f "$spec_md_path" ]; then
|
|
899
|
+
# Extract feature ID from multiple possible frontmatter fields:
|
|
900
|
+
# - epic: (preferred)
|
|
901
|
+
# - feature_id:
|
|
902
|
+
# - feature:
|
|
899
903
|
FEATURE_ID=$(awk '
|
|
900
|
-
BEGIN { in_frontmatter=0 }
|
|
904
|
+
BEGIN { in_frontmatter=0; feature_id="" }
|
|
901
905
|
/^---$/ {
|
|
902
906
|
if (in_frontmatter == 0) {
|
|
903
907
|
in_frontmatter=1; next
|
|
@@ -908,15 +912,32 @@ EOF_MINIMAL
|
|
|
908
912
|
in_frontmatter == 1 && /^epic:/ {
|
|
909
913
|
gsub(/^epic:[ \t]*/, "");
|
|
910
914
|
gsub(/["'\'']/, "");
|
|
911
|
-
|
|
912
|
-
exit
|
|
915
|
+
feature_id = $0;
|
|
913
916
|
}
|
|
917
|
+
in_frontmatter == 1 && /^feature_id:/ {
|
|
918
|
+
gsub(/^feature_id:[ \t]*/, "");
|
|
919
|
+
gsub(/["'\'']/, "");
|
|
920
|
+
if (feature_id == "") feature_id = $0;
|
|
921
|
+
}
|
|
922
|
+
in_frontmatter == 1 && /^feature:/ {
|
|
923
|
+
gsub(/^feature:[ \t]*/, "");
|
|
924
|
+
gsub(/["'\'']/, "");
|
|
925
|
+
if (feature_id == "") feature_id = $0;
|
|
926
|
+
}
|
|
927
|
+
END { print feature_id }
|
|
914
928
|
' "$spec_md_path" | tr -d '\r\n')
|
|
915
929
|
|
|
916
930
|
if [ -n "$FEATURE_ID" ]; then
|
|
917
931
|
log_debug " 📎 Extracted feature ID: $FEATURE_ID"
|
|
918
932
|
else
|
|
919
|
-
|
|
933
|
+
# AUTO-GENERATE feature ID from increment number (NEW - ADR-0139)
|
|
934
|
+
local increment_num=$(echo "$increment_id" | grep -oE '^[0-9]+')
|
|
935
|
+
if [ -n "$increment_num" ]; then
|
|
936
|
+
FEATURE_ID="FS-${increment_num}"
|
|
937
|
+
log_info " 📝 Auto-generated feature ID: $FEATURE_ID (no epic/feature_id in spec.md)"
|
|
938
|
+
else
|
|
939
|
+
log_debug " ⚠️ No feature ID found and could not auto-generate"
|
|
940
|
+
fi
|
|
920
941
|
fi
|
|
921
942
|
fi
|
|
922
943
|
|
|
@@ -979,10 +1000,96 @@ EOF_MINIMAL
|
|
|
979
1000
|
fi
|
|
980
1001
|
fi
|
|
981
1002
|
|
|
982
|
-
#
|
|
983
|
-
#
|
|
1003
|
+
# ============================================================================
|
|
1004
|
+
# STEP 8: EXPLICIT GITHUB ISSUE CREATION (NEW - ADR-0139)
|
|
1005
|
+
# ============================================================================
|
|
1006
|
+
# After living docs are created, explicitly create GitHub issues for User Stories.
|
|
1007
|
+
# This ensures GitHub issues are created even if sync-living-docs.js gates fail.
|
|
1008
|
+
#
|
|
1009
|
+
# Why this is needed:
|
|
1010
|
+
# - sync-living-docs.js has 5 config gates that can silently skip GitHub sync
|
|
1011
|
+
# - Living docs exist but GitHub issues might not be created
|
|
1012
|
+
# - User expects GitHub issues after /specweave:increment
|
|
1013
|
+
#
|
|
1014
|
+
# Retry mechanism: 2 attempts with 3 second delay
|
|
1015
|
+
# ============================================================================
|
|
1016
|
+
|
|
1017
|
+
log_info ""
|
|
1018
|
+
log_info "🐙 Creating GitHub issues for User Stories..."
|
|
1019
|
+
|
|
1020
|
+
# Check if GitHub is enabled
|
|
1021
|
+
local github_enabled=$(cat "$CONFIG_FILE" 2>/dev/null | grep -A 5 '"github"' | grep -o '"enabled"[[:space:]]*:[[:space:]]*\(true\|false\)' | head -1 | grep -o '\(true\|false\)' || echo "false")
|
|
1022
|
+
|
|
1023
|
+
if [ "$github_enabled" = "true" ] && [ -n "$FEATURE_ID" ]; then
|
|
1024
|
+
# Find the GitHub feature sync script
|
|
1025
|
+
# Priority: dist/ first (compiled with correct imports), then marketplace
|
|
1026
|
+
local GITHUB_SYNC_SCRIPT=""
|
|
1027
|
+
if [ -f "$PROJECT_ROOT/dist/plugins/specweave-github/lib/github-feature-sync-cli.js" ]; then
|
|
1028
|
+
# Prefer dist/ (compiled with correct imports)
|
|
1029
|
+
GITHUB_SYNC_SCRIPT="$PROJECT_ROOT/dist/plugins/specweave-github/lib/github-feature-sync-cli.js"
|
|
1030
|
+
elif [ -n "${CLAUDE_PLUGIN_ROOT}" ]; then
|
|
1031
|
+
# Try specweave-github plugin path (marketplace)
|
|
1032
|
+
local github_plugin_root="${CLAUDE_PLUGIN_ROOT/specweave/specweave-github}"
|
|
1033
|
+
if [ -f "$github_plugin_root/lib/github-feature-sync-cli.js" ]; then
|
|
1034
|
+
GITHUB_SYNC_SCRIPT="$github_plugin_root/lib/github-feature-sync-cli.js"
|
|
1035
|
+
fi
|
|
1036
|
+
elif [ -f "$PROJECT_ROOT/node_modules/specweave/dist/plugins/specweave-github/lib/github-feature-sync-cli.js" ]; then
|
|
1037
|
+
# Try node_modules (npm install)
|
|
1038
|
+
GITHUB_SYNC_SCRIPT="$PROJECT_ROOT/node_modules/specweave/dist/plugins/specweave-github/lib/github-feature-sync-cli.js"
|
|
1039
|
+
fi
|
|
1040
|
+
|
|
1041
|
+
if [ -n "$GITHUB_SYNC_SCRIPT" ]; then
|
|
1042
|
+
log_info " 🔄 Syncing $FEATURE_ID to GitHub..."
|
|
1043
|
+
|
|
1044
|
+
# Load GitHub token
|
|
1045
|
+
local GITHUB_TOKEN=""
|
|
1046
|
+
if [ -f "$PROJECT_ROOT/.env" ]; then
|
|
1047
|
+
GITHUB_TOKEN=$(grep -E '^GITHUB_TOKEN=' "$PROJECT_ROOT/.env" 2>/dev/null | head -1 | cut -d'=' -f2- | sed 's/^["'\'']//' | sed 's/["'\'']$//')
|
|
1048
|
+
fi
|
|
1049
|
+
|
|
1050
|
+
if [ -z "$GITHUB_TOKEN" ]; then
|
|
1051
|
+
log_info " ⚠️ GITHUB_TOKEN not found in .env - skipping GitHub sync"
|
|
1052
|
+
log_info " 💡 To enable: Add GITHUB_TOKEN=ghp_xxx to .env"
|
|
1053
|
+
else
|
|
1054
|
+
# Retry mechanism: 2 attempts
|
|
1055
|
+
local github_sync_success=false
|
|
1056
|
+
local max_attempts=2
|
|
1057
|
+
|
|
1058
|
+
for attempt in $(seq 1 $max_attempts); do
|
|
1059
|
+
log_debug " GitHub sync attempt $attempt of $max_attempts..."
|
|
1060
|
+
|
|
1061
|
+
if GITHUB_TOKEN="$GITHUB_TOKEN" node "$GITHUB_SYNC_SCRIPT" "$FEATURE_ID" 2>&1 | \
|
|
1062
|
+
grep -E "✅|❌|⚠️|📝|🎯|Issue|Milestone" | while read -r line; do echo " $line"; done; then
|
|
1063
|
+
github_sync_success=true
|
|
1064
|
+
break
|
|
1065
|
+
else
|
|
1066
|
+
if [ "$attempt" -lt "$max_attempts" ]; then
|
|
1067
|
+
log_info " ⚠️ Attempt $attempt failed, retrying in 3 seconds..."
|
|
1068
|
+
sleep 3
|
|
1069
|
+
fi
|
|
1070
|
+
fi
|
|
1071
|
+
done
|
|
1072
|
+
|
|
1073
|
+
if [ "$github_sync_success" = "true" ]; then
|
|
1074
|
+
log_info " ✅ GitHub issues created successfully!"
|
|
1075
|
+
else
|
|
1076
|
+
log_info " ⚠️ GitHub sync failed after $max_attempts attempts (non-blocking)"
|
|
1077
|
+
log_info " 💡 Run /specweave-github:sync $FEATURE_ID manually to retry"
|
|
1078
|
+
fi
|
|
1079
|
+
fi
|
|
1080
|
+
else
|
|
1081
|
+
log_debug " GitHub sync script not found"
|
|
1082
|
+
log_info " ℹ️ GitHub sync will be handled by living docs sync"
|
|
1083
|
+
fi
|
|
1084
|
+
elif [ "$github_enabled" != "true" ]; then
|
|
1085
|
+
log_info " ℹ️ GitHub sync disabled (sync.github.enabled = false)"
|
|
1086
|
+
log_info " 💡 To enable: Set sync.github.enabled = true in config.json"
|
|
1087
|
+
elif [ -z "$FEATURE_ID" ]; then
|
|
1088
|
+
log_info " ⚠️ No feature ID - GitHub issues cannot be created"
|
|
1089
|
+
log_info " 💡 Add epic: FS-XXX or feature_id: FS-XXX to spec.md frontmatter"
|
|
1090
|
+
fi
|
|
984
1091
|
|
|
985
|
-
#
|
|
1092
|
+
# 9. Sync spec content to external tools (if configured)
|
|
986
1093
|
log_info ""
|
|
987
1094
|
log_info "🔗 Checking spec content sync..."
|
|
988
1095
|
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { SyncCoordinator } from "../../../../dist/src/sync/sync-coordinator.js";
|
|
3
|
+
import { consoleLogger } from "../vendor/utils/logger.js";
|
|
4
|
+
async function syncIncrementClosure(incrementId) {
|
|
5
|
+
try {
|
|
6
|
+
console.log("\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
7
|
+
console.log(`\u{1F512} SYNC INCREMENT CLOSURE: ${incrementId}`);
|
|
8
|
+
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
9
|
+
const projectRoot = process.cwd();
|
|
10
|
+
const coordinator = new SyncCoordinator({
|
|
11
|
+
projectRoot,
|
|
12
|
+
incrementId,
|
|
13
|
+
logger: consoleLogger
|
|
14
|
+
});
|
|
15
|
+
const result = await coordinator.syncIncrementClosure();
|
|
16
|
+
console.log("\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
17
|
+
if (result.success) {
|
|
18
|
+
console.log("\u2705 INCREMENT CLOSURE SYNC COMPLETED");
|
|
19
|
+
console.log(` Issues closed: ${result.closedIssues.length}`);
|
|
20
|
+
if (result.closedIssues.length > 0) {
|
|
21
|
+
console.log(` Issue numbers: ${result.closedIssues.join(", ")}`);
|
|
22
|
+
}
|
|
23
|
+
} else {
|
|
24
|
+
console.log("\u26A0\uFE0F INCREMENT CLOSURE SYNC HAD ERRORS");
|
|
25
|
+
console.log(` Issues closed: ${result.closedIssues.length}`);
|
|
26
|
+
console.log(` Errors: ${result.errors.length}`);
|
|
27
|
+
}
|
|
28
|
+
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n");
|
|
29
|
+
return {
|
|
30
|
+
success: result.success,
|
|
31
|
+
closedIssues: result.closedIssues,
|
|
32
|
+
errors: result.errors
|
|
33
|
+
};
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error("\n\u274C FATAL ERROR in sync increment closure:", error.message);
|
|
36
|
+
return {
|
|
37
|
+
success: false,
|
|
38
|
+
closedIssues: [],
|
|
39
|
+
errors: [error.message]
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
|
|
44
|
+
if (isMainModule) {
|
|
45
|
+
const incrementId = process.argv[2];
|
|
46
|
+
if (!incrementId) {
|
|
47
|
+
console.error("Usage: node sync-increment-closure.js <increment-id>");
|
|
48
|
+
console.error("Example: node sync-increment-closure.js 0059-progressive-plugin");
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
syncIncrementClosure(incrementId).then((result) => {
|
|
52
|
+
if (result.success) {
|
|
53
|
+
console.log("\n\u2705 Increment closure sync completed successfully");
|
|
54
|
+
process.exit(0);
|
|
55
|
+
} else {
|
|
56
|
+
console.error("\n\u26A0\uFE0F Increment closure sync had errors (non-blocking)");
|
|
57
|
+
process.exit(0);
|
|
58
|
+
}
|
|
59
|
+
}).catch((error) => {
|
|
60
|
+
console.error("\n\u274C Fatal error:", error);
|
|
61
|
+
process.exit(0);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
export {
|
|
65
|
+
syncIncrementClosure
|
|
66
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Sync Increment Closure Hook (NEW in v0.28.1)
|
|
4
|
+
*
|
|
5
|
+
* This script handles the CLOSURE flow for increments - closing GitHub issues
|
|
6
|
+
* when an increment is marked as "completed".
|
|
7
|
+
*
|
|
8
|
+
* CRITICAL FIX: Previously, User Story GitHub issues were CREATED but NEVER CLOSED.
|
|
9
|
+
* This script ensures proper closure of all related issues.
|
|
10
|
+
*
|
|
11
|
+
* Called by: post-increment-completion.sh (after increment status → "completed")
|
|
12
|
+
*
|
|
13
|
+
* Flow:
|
|
14
|
+
* 1. Load SyncCoordinator for the increment
|
|
15
|
+
* 2. Call syncIncrementClosure() which:
|
|
16
|
+
* - Ensures all GitHub issues exist (idempotent)
|
|
17
|
+
* - Closes all User Story issues with completion comment
|
|
18
|
+
* 3. Report results
|
|
19
|
+
*
|
|
20
|
+
* Usage:
|
|
21
|
+
* node sync-increment-closure.js <increment-id>
|
|
22
|
+
*
|
|
23
|
+
* Environment:
|
|
24
|
+
* GITHUB_TOKEN - Required for GitHub API access
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { SyncCoordinator } from '../../../../dist/src/sync/sync-coordinator.js';
|
|
28
|
+
import { consoleLogger } from '../vendor/utils/logger.js';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Main function to sync increment closure
|
|
32
|
+
*/
|
|
33
|
+
async function syncIncrementClosure(incrementId: string): Promise<{
|
|
34
|
+
success: boolean;
|
|
35
|
+
closedIssues: number[];
|
|
36
|
+
errors: string[];
|
|
37
|
+
}> {
|
|
38
|
+
try {
|
|
39
|
+
console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
40
|
+
console.log(`🔒 SYNC INCREMENT CLOSURE: ${incrementId}`);
|
|
41
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
42
|
+
|
|
43
|
+
const projectRoot = process.cwd();
|
|
44
|
+
|
|
45
|
+
const coordinator = new SyncCoordinator({
|
|
46
|
+
projectRoot,
|
|
47
|
+
incrementId,
|
|
48
|
+
logger: consoleLogger
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const result = await coordinator.syncIncrementClosure();
|
|
52
|
+
|
|
53
|
+
console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
54
|
+
if (result.success) {
|
|
55
|
+
console.log('✅ INCREMENT CLOSURE SYNC COMPLETED');
|
|
56
|
+
console.log(` Issues closed: ${result.closedIssues.length}`);
|
|
57
|
+
if (result.closedIssues.length > 0) {
|
|
58
|
+
console.log(` Issue numbers: ${result.closedIssues.join(', ')}`);
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
console.log('⚠️ INCREMENT CLOSURE SYNC HAD ERRORS');
|
|
62
|
+
console.log(` Issues closed: ${result.closedIssues.length}`);
|
|
63
|
+
console.log(` Errors: ${result.errors.length}`);
|
|
64
|
+
}
|
|
65
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
success: result.success,
|
|
69
|
+
closedIssues: result.closedIssues,
|
|
70
|
+
errors: result.errors
|
|
71
|
+
};
|
|
72
|
+
} catch (error: any) {
|
|
73
|
+
console.error('\n❌ FATAL ERROR in sync increment closure:', error.message);
|
|
74
|
+
return {
|
|
75
|
+
success: false,
|
|
76
|
+
closedIssues: [],
|
|
77
|
+
errors: [error.message]
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// CLI Interface
|
|
83
|
+
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
|
|
84
|
+
if (isMainModule) {
|
|
85
|
+
const incrementId = process.argv[2];
|
|
86
|
+
|
|
87
|
+
if (!incrementId) {
|
|
88
|
+
console.error('Usage: node sync-increment-closure.js <increment-id>');
|
|
89
|
+
console.error('Example: node sync-increment-closure.js 0059-progressive-plugin');
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
syncIncrementClosure(incrementId)
|
|
94
|
+
.then((result) => {
|
|
95
|
+
if (result.success) {
|
|
96
|
+
console.log('\n✅ Increment closure sync completed successfully');
|
|
97
|
+
process.exit(0);
|
|
98
|
+
} else {
|
|
99
|
+
console.error('\n⚠️ Increment closure sync had errors (non-blocking)');
|
|
100
|
+
// Exit 0 to not block the hook chain
|
|
101
|
+
process.exit(0);
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
.catch((error) => {
|
|
105
|
+
console.error('\n❌ Fatal error:', error);
|
|
106
|
+
// Exit 0 to not block the hook chain
|
|
107
|
+
process.exit(0);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export { syncIncrementClosure };
|
|
@@ -138,27 +138,51 @@ class GitHubClientV2 {
|
|
|
138
138
|
* Validate issue title format
|
|
139
139
|
*
|
|
140
140
|
* CRITICAL: Enforces correct data flow architecture
|
|
141
|
-
* - ✅ CORRECT: "US-
|
|
141
|
+
* - ✅ CORRECT: "[FS-XXX][US-YYY] Title" (User Story - STANDARD)
|
|
142
|
+
* - ✅ CORRECT: "[FS-XXX] Title" (Feature-level, rare)
|
|
142
143
|
* - ❌ WRONG: "[Increment XXXX] Title" (deprecated old format)
|
|
144
|
+
* - ❌ WRONG: "[BUG] Title" (type prefixes are labels, not title)
|
|
145
|
+
* - ❌ WRONG: "[HOTFIX] Title" (type prefixes are labels, not title)
|
|
146
|
+
* - ❌ WRONG: "[FEATURE] Title" (type prefixes are labels, not title)
|
|
143
147
|
*
|
|
144
|
-
* @throws Error if title uses
|
|
148
|
+
* @throws Error if title uses invalid format
|
|
145
149
|
*/
|
|
146
150
|
validateIssueTitle(title) {
|
|
147
|
-
const
|
|
148
|
-
if (
|
|
151
|
+
const deprecatedIncrementPattern = /\[Increment\s+\d+\]/i;
|
|
152
|
+
if (deprecatedIncrementPattern.test(title)) {
|
|
149
153
|
throw new Error(
|
|
150
154
|
`\u274C DEPRECATED FORMAT DETECTED: "${title}"
|
|
151
155
|
|
|
152
156
|
GitHub issues MUST use living docs format:
|
|
153
|
-
\u2705 CORRECT: "US-
|
|
154
|
-
\u2705 CORRECT: "FS-YY-MM-DD: Title" (Feature Spec)
|
|
157
|
+
\u2705 CORRECT: "[FS-XXX][US-YYY] Title" (User Story)
|
|
155
158
|
\u274C WRONG: "[Increment XXXX] Title" (old format)
|
|
156
159
|
|
|
157
160
|
WHY: Correct data flow is: Increment \u2192 Living Docs \u2192 GitHub
|
|
158
161
|
Living docs are the source of truth for GitHub sync.
|
|
159
162
|
|
|
160
|
-
FIX: Use /specweave:sync-docs to generate living docs, then sync to GitHub
|
|
161
|
-
|
|
163
|
+
FIX: Use /specweave:sync-docs to generate living docs, then sync to GitHub.`
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
const typePrefixPattern = /^\[(BUG|HOTFIX|FEATURE|DOCS|REFACTOR|CHORE|EXPERIMENT|Bug|Hotfix|Feature|Docs|Refactor|Chore|Experiment)\]/i;
|
|
167
|
+
if (typePrefixPattern.test(title)) {
|
|
168
|
+
const match = title.match(typePrefixPattern);
|
|
169
|
+
const badPrefix = match ? match[0] : "[TYPE]";
|
|
170
|
+
throw new Error(
|
|
171
|
+
`\u274C INVALID TITLE FORMAT: "${title}"
|
|
172
|
+
|
|
173
|
+
Type prefixes like ${badPrefix} belong as LABELS, not in the title!
|
|
174
|
+
|
|
175
|
+
GitHub issues MUST use this format:
|
|
176
|
+
\u2705 CORRECT: "[FS-XXX][US-YYY] Title" (User Story)
|
|
177
|
+
\u274C WRONG: "${badPrefix} Title" (use 'bug' label instead)
|
|
178
|
+
|
|
179
|
+
WHY: All SpecWeave issues follow [FS-XXX][US-YYY] format for traceability.
|
|
180
|
+
Use GitHub labels for categorization (bug, enhancement, etc.).
|
|
181
|
+
|
|
182
|
+
FIX:
|
|
183
|
+
1. Link this work to a Feature (FS-XXX) and User Story (US-YYY)
|
|
184
|
+
2. Use /specweave-github:sync to create issue with correct format
|
|
185
|
+
3. Add '${match ? match[1].toLowerCase() : "bug"}' as a label instead`
|
|
162
186
|
);
|
|
163
187
|
}
|
|
164
188
|
}
|
|
@@ -196,26 +196,48 @@ export class GitHubClientV2 {
|
|
|
196
196
|
* Validate issue title format
|
|
197
197
|
*
|
|
198
198
|
* CRITICAL: Enforces correct data flow architecture
|
|
199
|
-
* - ✅ CORRECT: "US-
|
|
199
|
+
* - ✅ CORRECT: "[FS-XXX][US-YYY] Title" (User Story - STANDARD)
|
|
200
|
+
* - ✅ CORRECT: "[FS-XXX] Title" (Feature-level, rare)
|
|
200
201
|
* - ❌ WRONG: "[Increment XXXX] Title" (deprecated old format)
|
|
202
|
+
* - ❌ WRONG: "[BUG] Title" (type prefixes are labels, not title)
|
|
203
|
+
* - ❌ WRONG: "[HOTFIX] Title" (type prefixes are labels, not title)
|
|
204
|
+
* - ❌ WRONG: "[FEATURE] Title" (type prefixes are labels, not title)
|
|
201
205
|
*
|
|
202
|
-
* @throws Error if title uses
|
|
206
|
+
* @throws Error if title uses invalid format
|
|
203
207
|
*/
|
|
204
208
|
private validateIssueTitle(title: string): void {
|
|
205
209
|
// Check for deprecated [Increment XXXX] format
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
if (deprecatedPattern.test(title)) {
|
|
210
|
+
const deprecatedIncrementPattern = /\[Increment\s+\d+\]/i;
|
|
211
|
+
if (deprecatedIncrementPattern.test(title)) {
|
|
209
212
|
throw new Error(
|
|
210
213
|
`❌ DEPRECATED FORMAT DETECTED: "${title}"\n\n` +
|
|
211
214
|
`GitHub issues MUST use living docs format:\n` +
|
|
212
|
-
` ✅ CORRECT: "US-
|
|
213
|
-
` ✅ CORRECT: "FS-YY-MM-DD: Title" (Feature Spec)\n` +
|
|
215
|
+
` ✅ CORRECT: "[FS-XXX][US-YYY] Title" (User Story)\n` +
|
|
214
216
|
` ❌ WRONG: "[Increment XXXX] Title" (old format)\n\n` +
|
|
215
217
|
`WHY: Correct data flow is: Increment → Living Docs → GitHub\n` +
|
|
216
218
|
` Living docs are the source of truth for GitHub sync.\n\n` +
|
|
217
|
-
`FIX: Use /specweave:sync-docs to generate living docs, then sync to GitHub
|
|
218
|
-
|
|
219
|
+
`FIX: Use /specweave:sync-docs to generate living docs, then sync to GitHub.`
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Check for type-based prefixes (CRITICAL FIX for issue #749)
|
|
224
|
+
// These prefixes belong as LABELS, not in the issue title!
|
|
225
|
+
const typePrefixPattern = /^\[(BUG|HOTFIX|FEATURE|DOCS|REFACTOR|CHORE|EXPERIMENT|Bug|Hotfix|Feature|Docs|Refactor|Chore|Experiment)\]/i;
|
|
226
|
+
if (typePrefixPattern.test(title)) {
|
|
227
|
+
const match = title.match(typePrefixPattern);
|
|
228
|
+
const badPrefix = match ? match[0] : '[TYPE]';
|
|
229
|
+
throw new Error(
|
|
230
|
+
`❌ INVALID TITLE FORMAT: "${title}"\n\n` +
|
|
231
|
+
`Type prefixes like ${badPrefix} belong as LABELS, not in the title!\n\n` +
|
|
232
|
+
`GitHub issues MUST use this format:\n` +
|
|
233
|
+
` ✅ CORRECT: "[FS-XXX][US-YYY] Title" (User Story)\n` +
|
|
234
|
+
` ❌ WRONG: "${badPrefix} Title" (use 'bug' label instead)\n\n` +
|
|
235
|
+
`WHY: All SpecWeave issues follow [FS-XXX][US-YYY] format for traceability.\n` +
|
|
236
|
+
` Use GitHub labels for categorization (bug, enhancement, etc.).\n\n` +
|
|
237
|
+
`FIX:\n` +
|
|
238
|
+
` 1. Link this work to a Feature (FS-XXX) and User Story (US-YYY)\n` +
|
|
239
|
+
` 2. Use /specweave-github:sync to create issue with correct format\n` +
|
|
240
|
+
` 3. Add '${match ? match[1].toLowerCase() : 'bug'}' as a label instead`
|
|
219
241
|
);
|
|
220
242
|
}
|
|
221
243
|
}
|