specweave 0.28.7 → 0.28.11

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 (39) hide show
  1. package/dist/src/cli/commands/init.d.ts.map +1 -1
  2. package/dist/src/cli/commands/init.js +17 -1
  3. package/dist/src/cli/commands/init.js.map +1 -1
  4. package/dist/src/cli/helpers/init/index.d.ts +1 -0
  5. package/dist/src/cli/helpers/init/index.d.ts.map +1 -1
  6. package/dist/src/cli/helpers/init/index.js +2 -0
  7. package/dist/src/cli/helpers/init/index.js.map +1 -1
  8. package/dist/src/cli/helpers/init/translation-config.d.ts +53 -0
  9. package/dist/src/cli/helpers/init/translation-config.d.ts.map +1 -0
  10. package/dist/src/cli/helpers/init/translation-config.js +216 -0
  11. package/dist/src/cli/helpers/init/translation-config.js.map +1 -0
  12. package/dist/src/cli/helpers/init/types.d.ts +33 -0
  13. package/dist/src/cli/helpers/init/types.d.ts.map +1 -1
  14. package/dist/src/core/config/types.d.ts +115 -0
  15. package/dist/src/core/config/types.d.ts.map +1 -1
  16. package/dist/src/core/config/types.js.map +1 -1
  17. package/dist/src/core/repo-structure/repo-id-generator.d.ts +24 -95
  18. package/dist/src/core/repo-structure/repo-id-generator.d.ts.map +1 -1
  19. package/dist/src/core/repo-structure/repo-id-generator.js +31 -223
  20. package/dist/src/core/repo-structure/repo-id-generator.js.map +1 -1
  21. package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
  22. package/dist/src/core/repo-structure/repo-structure-manager.js +12 -46
  23. package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
  24. package/dist/src/utils/multi-repo-detector.d.ts +85 -0
  25. package/dist/src/utils/multi-repo-detector.d.ts.map +1 -0
  26. package/dist/src/utils/multi-repo-detector.js +264 -0
  27. package/dist/src/utils/multi-repo-detector.js.map +1 -0
  28. package/package.json +1 -1
  29. package/plugins/specweave/agents/pm/AGENT.md +141 -0
  30. package/plugins/specweave/commands/specweave-done.md +28 -0
  31. package/plugins/specweave/hooks/hooks.json +12 -0
  32. package/plugins/specweave/hooks/post-increment-completion.sh +59 -0
  33. package/plugins/specweave/hooks/post-increment-planning.sh +95 -51
  34. package/plugins/specweave/hooks/pre-task-completion-edit.sh +355 -0
  35. package/plugins/specweave/lib/hooks/sync-living-docs.js +43 -0
  36. package/plugins/specweave/skills/umbrella-repo-detector/SKILL.md +219 -0
  37. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +18 -0
  38. package/plugins/specweave-infrastructure/skills/hetzner-provisioner/README.md +1 -1
  39. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +27 -0
@@ -437,6 +437,147 @@ graph TD
437
437
 
438
438
  ---
439
439
 
440
+ ## 🔀 Multi-Repo Project-Scoped User Stories (v0.28.8+)
441
+
442
+ **CRITICAL**: When user describes a multi-repo architecture, you MUST generate **project-scoped user stories** with prefixes!
443
+
444
+ ### Detection Patterns
445
+
446
+ Detect multi-repo intent when user mentions:
447
+ - **Explicit repos**: "3 repos", "multiple repos", "separate repos"
448
+ - **Repo types**: "Frontend repo", "Backend API repo", "Shared library"
449
+ - **Architecture patterns**: "monorepo with services", "microservices"
450
+ - **Tech stack splits**: React frontend + Node backend + Shared types
451
+ - **GitHub URLs**: Multiple github.com/... URLs
452
+
453
+ ### User Story Prefixing Rules (MANDATORY!)
454
+
455
+ **When multi-repo detected, NEVER generate generic `US-001`!**
456
+
457
+ | Repo Type | Prefix | Detection Keywords |
458
+ |-----------|--------|-------------------|
459
+ | Frontend | `FE` | UI, component, page, form, view, theme, drag-drop, builder, menu display |
460
+ | Backend | `BE` | API, endpoint, CRUD, webhook, notification, analytics, database, service |
461
+ | Shared | `SHARED` | validator, schema, types, utilities, localization, common, helpers |
462
+ | Mobile | `MOBILE` | iOS, Android, mobile app, push notification, native |
463
+ | Infrastructure | `INFRA` | Terraform, K8s, Docker, CI/CD, deployment |
464
+
465
+ ### Example: Generic vs Project-Scoped
466
+
467
+ **❌ WRONG (Generic - for single-repo only)**:
468
+ ```markdown
469
+ ## User Stories
470
+
471
+ ### US-001: User Registration
472
+ As a user, I want to register...
473
+
474
+ ### US-002: Registration API
475
+ As a system, I want to process registrations...
476
+
477
+ ### US-003: Validation Schema
478
+ As a developer, I want shared validation...
479
+ ```
480
+
481
+ **✅ CORRECT (Project-Scoped - for multi-repo)**:
482
+ ```markdown
483
+ ## User Stories
484
+
485
+ ### US-FE-001: User Registration Form
486
+ **Related Repo**: frontend
487
+ As a user, I want to fill out the registration form...
488
+
489
+ ### US-BE-001: Registration API Endpoint
490
+ **Related Repo**: backend
491
+ As a system, I want to process POST /api/register...
492
+
493
+ ### US-SHARED-001: Registration Validation Schema
494
+ **Related Repo**: shared
495
+ As a developer, I want reusable validation schemas...
496
+ ```
497
+
498
+ ### Acceptance Criteria Also Prefixed
499
+
500
+ ```markdown
501
+ ### US-FE-001: Menu Builder Interface
502
+
503
+ **Acceptance Criteria**:
504
+ - [ ] **AC-FE-US1-01**: Drag-drop menu item ordering
505
+ - Priority: P0 (Critical)
506
+ - Testable: Yes
507
+ - [ ] **AC-FE-US1-02**: Category management UI
508
+ - Priority: P0 (Critical)
509
+ - Testable: Yes
510
+
511
+ ### US-BE-001: Menu CRUD API
512
+
513
+ **Acceptance Criteria**:
514
+ - [ ] **AC-BE-US1-01**: POST /api/menus creates menu
515
+ - Priority: P0 (Critical)
516
+ - Testable: Yes
517
+ - [ ] **AC-BE-US1-02**: GET /api/menus/:id returns menu
518
+ - Priority: P0 (Critical)
519
+ - Testable: Yes
520
+ ```
521
+
522
+ ### Cross-Cutting User Stories
523
+
524
+ For features that span multiple repos (auth, shared state):
525
+
526
+ ```markdown
527
+ ### US-AUTH-001: OAuth Integration (Cross-Project)
528
+ **Related Repos**: frontend, backend
529
+ **Tags**: ["cross-project", "auth"]
530
+
531
+ **Child Stories**:
532
+ - US-FE-002: OAuth Login Button (frontend)
533
+ - US-BE-002: OAuth Token Validation (backend)
534
+ - US-SHARED-002: OAuth Types (shared)
535
+
536
+ As a user, I want to log in with Google OAuth...
537
+ ```
538
+
539
+ ### Workflow in Multi-Repo Mode
540
+
541
+ 1. **Detect** multi-repo intent from user prompt
542
+ 2. **Confirm** with user: "I detected FE/BE/Shared architecture. Should I create project-scoped user stories?"
543
+ 3. **Generate** prefixed user stories: US-FE-*, US-BE-*, US-SHARED-*
544
+ 4. **Route** stories to correct increment in each repo
545
+ 5. **Sync** to each repo's own GitHub issues
546
+
547
+ ### Config Check (Optional)
548
+
549
+ If `.specweave/config.json` has umbrella config:
550
+ ```json
551
+ {
552
+ "umbrella": {
553
+ "enabled": true,
554
+ "childRepos": [
555
+ { "id": "fe", "prefix": "FE" },
556
+ { "id": "be", "prefix": "BE" },
557
+ { "id": "shared", "prefix": "SHARED" }
558
+ ]
559
+ }
560
+ }
561
+ ```
562
+
563
+ Use these prefixes for user stories. If no config, infer from user prompt.
564
+
565
+ ### Why This Matters
566
+
567
+ Without project-scoped stories:
568
+ - ❌ All issues created in ONE repo (wrong!)
569
+ - ❌ No clarity which team owns what
570
+ - ❌ Cross-project dependencies unclear
571
+ - ❌ Frontend dev sees backend tasks in their repo
572
+
573
+ With project-scoped stories:
574
+ - ✅ Each repo gets only its user stories
575
+ - ✅ Clear ownership per team/repo
576
+ - ✅ GitHub issues in correct repo
577
+ - ✅ Clean separation of concerns
578
+
579
+ ---
580
+
440
581
  **Role**: Product Manager specialized in product strategy, requirements gathering, and feature prioritization.
441
582
 
442
583
  ## Purpose
@@ -487,6 +487,34 @@ Closing increment 0001-user-authentication...
487
487
 
488
488
  ### Step 5: Post-Closure Sync (AUTOMATIC)
489
489
 
490
+ **CRITICAL**: After increment closes, the following syncs happen AUTOMATICALLY via the `post-increment-completion.sh` hook:
491
+
492
+ #### 0) Sync spec.md Status (ALWAYS - v0.28.8+)
493
+
494
+ **MANDATORY**: Ensures spec.md frontmatter status matches metadata.json.
495
+
496
+ ```
497
+ 🔄 Syncing spec.md status to 'completed'...
498
+ ✅ spec.md status updated: active → completed
499
+ ✅ Status line cache updated
500
+ ```
501
+
502
+ **Why this matters**:
503
+ - Prevents desyncs between metadata.json and spec.md
504
+ - Ensures status line shows correct increment count
505
+ - Maintains source-of-truth discipline
506
+ - No need to manually run `/specweave:sync-status`
507
+
508
+ **What gets synced**:
509
+ 1. spec.md YAML frontmatter `status` field → `completed`
510
+ 2. Status line cache updated via `lib/update-status-line.sh`
511
+
512
+ **If you still see desync after closure**:
513
+ ```bash
514
+ # Manual fix (should rarely be needed)
515
+ /specweave:sync-status --fix
516
+ ```
517
+
490
518
  **CRITICAL**: After increment closes, automatically perform these syncs:
491
519
 
492
520
  #### A) Sync Living Docs to GitHub Project
@@ -1,5 +1,17 @@
1
1
  {
2
2
  "hooks": {
3
+ "PreToolUse": [
4
+ {
5
+ "matcher": "Edit",
6
+ "matcher_content": "\\.specweave/increments/[0-9]{4}-.+/tasks\\.md",
7
+ "hooks": [
8
+ {
9
+ "type": "command",
10
+ "command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre-task-completion-edit.sh"
11
+ }
12
+ ]
13
+ }
14
+ ],
3
15
  "UserPromptSubmit": [
4
16
  {
5
17
  "hooks": [
@@ -117,10 +117,69 @@ Increment \`$INCREMENT_ID\` has been marked as complete.
117
117
  fi
118
118
  fi
119
119
 
120
+ # ============================================================================
121
+ # SYNC SPEC.MD STATUS (CRITICAL - v0.28.8)
122
+ # ============================================================================
123
+ # PROBLEM: metadata.json is updated to "completed" but spec.md frontmatter
124
+ # may still say "active". This causes desyncs that break status line.
125
+ #
126
+ # SOLUTION: Explicitly update spec.md frontmatter to match metadata.json.
127
+ # This ensures source-of-truth discipline is maintained.
128
+ #
129
+ # See: Incident 2025-11-20 - metadata.json="completed" but spec.md="active"
130
+ # See: /specweave:sync-status command for manual recovery
131
+
132
+ SPEC_FILE="$INCREMENT_DIR/spec.md"
133
+
134
+ if [ -f "$SPEC_FILE" ]; then
135
+ echo "🔄 Syncing spec.md status to 'completed'..."
136
+
137
+ # Read current status from spec.md frontmatter
138
+ SPEC_STATUS=$(awk '
139
+ BEGIN { in_frontmatter=0 }
140
+ /^---$/ {
141
+ if (in_frontmatter == 0) {
142
+ in_frontmatter=1; next
143
+ } else {
144
+ exit
145
+ }
146
+ }
147
+ in_frontmatter == 1 && /^status:/ {
148
+ gsub(/^status:[ \t]*/, "");
149
+ gsub(/["'\''']/, "");
150
+ print;
151
+ exit
152
+ }
153
+ ' "$SPEC_FILE" | tr -d '\r\n')
154
+
155
+ if [ "$SPEC_STATUS" != "completed" ]; then
156
+ # Update spec.md frontmatter to "completed"
157
+ # Use sed for atomic in-place update
158
+ if [[ "$(uname)" == "Darwin" ]]; then
159
+ # macOS sed requires different syntax
160
+ sed -i '' 's/^status:.*$/status: completed/' "$SPEC_FILE" 2>/dev/null || {
161
+ echo "âš ī¸ Failed to update spec.md status (non-blocking)" >&2
162
+ }
163
+ else
164
+ # GNU sed
165
+ sed -i 's/^status:.*$/status: completed/' "$SPEC_FILE" 2>/dev/null || {
166
+ echo "âš ī¸ Failed to update spec.md status (non-blocking)" >&2
167
+ }
168
+ fi
169
+ echo "✅ spec.md status updated: $SPEC_STATUS → completed"
170
+ else
171
+ echo "✅ spec.md status already 'completed'"
172
+ fi
173
+ else
174
+ echo "âš ī¸ spec.md not found at $SPEC_FILE" >&2
175
+ fi
176
+
120
177
  # Update status line cache (increment no longer open)
121
178
  HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
122
179
  bash "$HOOK_DIR/lib/update-status-line.sh" 2>/dev/null || true
123
180
 
181
+ echo "✅ Status line cache updated"
182
+
124
183
  # ============================================================================
125
184
  # SYNC LIVING DOCS (NEW in v0.24.0 - Critical Missing Feature)
126
185
  # ============================================================================
@@ -58,10 +58,12 @@ cd "$PROJECT_ROOT" 2>/dev/null || true
58
58
  # CONFIGURATION
59
59
  # ============================================================================
60
60
 
61
- # Translation settings (can be overridden by .specweave/config.json)
62
- TRANSLATION_ENABLED=true
63
- AUTO_TRANSLATE_INTERNAL_DOCS=true
64
- TARGET_LANGUAGE="en" # Always translate TO English (for maintainability)
61
+ # Translation settings (loaded from .specweave/config.json)
62
+ TRANSLATION_ENABLED=false # Opt-in: User MUST enable in config
63
+ AUTO_TRANSLATE_INCREMENT_SPECS=false # Opt-in: scope.incrementSpecs
64
+ AUTO_TRANSLATE_LIVING_DOCS=false # Opt-in: scope.livingDocs
65
+ TARGET_LANGUAGE="en" # Loaded from config.language (default: en)
66
+ KEEP_ENGLISH_ORIGINALS=false # If true, create .en.md backups
65
67
 
66
68
  # Paths
67
69
  SPECWEAVE_DIR=".specweave"
@@ -96,24 +98,59 @@ log_error() {
96
98
 
97
99
  load_config() {
98
100
  if [ ! -f "$CONFIG_FILE" ]; then
99
- log_debug "No config file found, using defaults"
101
+ log_debug "No config file found, using defaults (translation disabled)"
100
102
  return
101
103
  fi
102
104
 
103
- # Check if translation is enabled in config
104
- local translation_enabled=$(cat "$CONFIG_FILE" | grep -o '"enabled"[[:space:]]*:[[:space:]]*\(true\|false\)' | grep -o '\(true\|false\)' || echo "true")
105
+ # Load target language from config.language (default: en)
106
+ local config_language=$(cat "$CONFIG_FILE" | grep -o '"language"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/' || echo "en")
107
+ if [ -n "$config_language" ]; then
108
+ TARGET_LANGUAGE="$config_language"
109
+ log_debug "Target language: $TARGET_LANGUAGE"
110
+ fi
111
+
112
+ # If target language is English, no translation needed
113
+ if [ "$TARGET_LANGUAGE" = "en" ]; then
114
+ TRANSLATION_ENABLED=false
115
+ log_debug "Target language is English, translation not needed"
116
+ return
117
+ fi
118
+
119
+ # Check if translation is enabled in config.translation.enabled
120
+ # Search within "translation" block for "enabled"
121
+ local translation_section=$(cat "$CONFIG_FILE" | awk '/"translation"[[:space:]]*:/,/^[[:space:]]*}/' 2>/dev/null)
122
+ local translation_enabled=$(echo "$translation_section" | grep -o '"enabled"[[:space:]]*:[[:space:]]*\(true\|false\)' | head -1 | grep -o '\(true\|false\)' || echo "false")
105
123
 
106
- if [ "$translation_enabled" = "false" ]; then
124
+ if [ "$translation_enabled" = "true" ]; then
125
+ TRANSLATION_ENABLED=true
126
+ log_debug "Translation enabled in config"
127
+ else
107
128
  TRANSLATION_ENABLED=false
108
- log_debug "Translation disabled in config"
129
+ log_debug "Translation disabled in config (opt-in required)"
130
+ fi
131
+
132
+ # Check translation scope (within translation.scope block)
133
+ local scope_section=$(echo "$translation_section" | awk '/"scope"[[:space:]]*:/,/^[[:space:]]*}/' 2>/dev/null)
134
+
135
+ # scope.incrementSpecs - translate spec.md, plan.md, tasks.md
136
+ local scope_increment=$(echo "$scope_section" | grep -o '"incrementSpecs"[[:space:]]*:[[:space:]]*\(true\|false\)' | grep -o '\(true\|false\)' || echo "false")
137
+ if [ "$scope_increment" = "true" ]; then
138
+ AUTO_TRANSLATE_INCREMENT_SPECS=true
139
+ log_debug "Auto-translate increment specs enabled"
109
140
  fi
110
141
 
111
- # Check if auto-translation of internal docs is enabled
112
- local auto_translate=$(cat "$CONFIG_FILE" | grep -o '"autoTranslateInternalDocs"[[:space:]]*:[[:space:]]*\(true\|false\)' | grep -o '\(true\|false\)' || echo "true")
142
+ # scope.livingDocs - translate living docs on update
143
+ local scope_living=$(echo "$scope_section" | grep -o '"livingDocs"[[:space:]]*:[[:space:]]*\(true\|false\)' | grep -o '\(true\|false\)' || echo "false")
144
+ if [ "$scope_living" = "true" ]; then
145
+ AUTO_TRANSLATE_LIVING_DOCS=true
146
+ log_debug "Auto-translate living docs enabled"
147
+ fi
113
148
 
114
- if [ "$auto_translate" = "false" ]; then
115
- AUTO_TRANSLATE_INTERNAL_DOCS=false
116
- log_debug "Auto-translation of internal docs disabled in config"
149
+ # keepEnglishOriginals - create .en.md backups
150
+ local keep_originals=$(echo "$translation_section" | grep -o '"keepEnglishOriginals"[[:space:]]*:[[:space:]]*\(true\|false\)' | grep -o '\(true\|false\)' || echo "false")
151
+ if [ "$keep_originals" = "true" ]; then
152
+ KEEP_ENGLISH_ORIGINALS=true
153
+ log_debug "Keep English originals enabled"
117
154
  fi
118
155
  }
119
156
 
@@ -168,21 +205,21 @@ detect_file_language() {
168
205
  translate_file() {
169
206
  local file_path="$1"
170
207
  local file_name=$(basename "$file_path")
208
+ local target_lang="${TARGET_LANGUAGE:-en}"
171
209
 
172
- log_info " 📄 Translating $file_name..."
210
+ log_info " 📄 Translating $file_name to $target_lang..."
173
211
 
174
212
  # Call the translate-file.ts script
175
- # In production, this would invoke the LLM via Task tool
176
- # For now, we'll create a marker file to indicate translation is needed
213
+ # Uses TARGET_LANGUAGE from config (default: en)
177
214
 
178
215
  if [ -f "${CLAUDE_PLUGIN_ROOT}/lib/hooks/translate-file.js" ]; then
179
216
  # Production: Use compiled TypeScript
180
- node "${CLAUDE_PLUGIN_ROOT}/lib/hooks/translate-file.js" "$file_path" --target-lang en --verbose 2>&1 | while read -r line; do
217
+ node "${CLAUDE_PLUGIN_ROOT}/lib/hooks/translate-file.js" "$file_path" --target-lang "$target_lang" --verbose 2>&1 | while read -r line; do
181
218
  echo " $line"
182
219
  done
183
220
 
184
221
  if [ ${PIPESTATUS[0]} -eq 0 ]; then
185
- log_info " ✅ $file_name translated successfully"
222
+ log_info " ✅ $file_name translated to $target_lang"
186
223
  return 0
187
224
  else
188
225
  log_error " âš ī¸ Translation failed for $file_name"
@@ -191,7 +228,7 @@ translate_file() {
191
228
  else
192
229
  # Development/Testing: Just mark the file
193
230
  log_info " â„šī¸ Translation script not compiled (run 'npm run build')"
194
- log_info " â„šī¸ In production, $file_name would be translated to English"
231
+ log_info " â„šī¸ In production, $file_name would be translated to $target_lang"
195
232
  return 0
196
233
  fi
197
234
  }
@@ -584,26 +621,20 @@ main() {
584
621
  # 1. Load configuration
585
622
  load_config
586
623
 
624
+ # Check if translation is needed (non-English target + enabled)
587
625
  if [ "$TRANSLATION_ENABLED" = "false" ]; then
588
- log_debug "Translation disabled, exiting"
589
- cat <<EOF
590
- {
591
- "continue": true,
592
- "message": "Translation disabled in config"
593
- }
594
- EOF
595
- exit 0
626
+ log_debug "Translation disabled or target is English, skipping translation"
627
+ # Continue with other hook tasks (GitHub sync, living docs, etc.)
596
628
  fi
597
629
 
598
- if [ "$AUTO_TRANSLATE_INTERNAL_DOCS" = "false" ]; then
599
- log_debug "Auto-translation of internal docs disabled, exiting"
600
- cat <<EOF
601
- {
602
- "continue": true,
603
- "message": "Auto-translation of internal docs disabled"
604
- }
605
- EOF
606
- exit 0
630
+ # Log translation configuration
631
+ if [ "$TRANSLATION_ENABLED" = "true" ]; then
632
+ log_info ""
633
+ log_info "🌐 Translation Configuration:"
634
+ log_info " Target language: $TARGET_LANGUAGE"
635
+ log_info " Increment specs: $AUTO_TRANSLATE_INCREMENT_SPECS"
636
+ log_info " Living docs: $AUTO_TRANSLATE_LIVING_DOCS"
637
+ log_info " Keep English originals: $KEEP_ENGLISH_ORIGINALS"
607
638
  fi
608
639
 
609
640
  # 2. Get latest increment directory
@@ -656,17 +687,25 @@ EOF
656
687
  fi
657
688
  fi
658
689
 
659
- # 4. Translate increment files (if needed)
690
+ # 4. Translate increment files (if enabled in scope and non-English content detected)
660
691
  local increment_success_count=0
661
692
  local increment_total_count=${#files_to_translate[@]}
662
693
 
663
- if [ "$needs_translation" = "true" ] && [ ${#files_to_translate[@]} -gt 0 ]; then
664
- # 5. Perform translation of increment files
694
+ if [ "$TRANSLATION_ENABLED" = "true" ] && [ "$AUTO_TRANSLATE_INCREMENT_SPECS" = "true" ] && [ "$needs_translation" = "true" ] && [ ${#files_to_translate[@]} -gt 0 ]; then
695
+ # 5. Perform translation of increment files TO user's language
665
696
  log_info ""
666
- log_info "🌐 Detected non-English content in increment $increment_id"
667
- log_info " Translating increment files to English..."
697
+ log_info "🌐 Translating increment $increment_id to $TARGET_LANGUAGE..."
668
698
  log_info ""
669
699
 
700
+ # Create English backups if configured
701
+ if [ "$KEEP_ENGLISH_ORIGINALS" = "true" ]; then
702
+ for file in "${files_to_translate[@]}"; do
703
+ local backup="${file%.md}.en.md"
704
+ cp "$file" "$backup" 2>/dev/null || true
705
+ log_debug "Created English backup: $backup"
706
+ done
707
+ fi
708
+
670
709
  for file in "${files_to_translate[@]}"; do
671
710
  if translate_file "$file"; then
672
711
  ((increment_success_count++))
@@ -675,19 +714,24 @@ EOF
675
714
 
676
715
  log_info ""
677
716
  if [ "$increment_success_count" -eq "$increment_total_count" ]; then
678
- log_info "✅ Increment files translation complete! All $increment_total_count file(s) now in English"
717
+ log_info "✅ Increment files translated to $TARGET_LANGUAGE! ($increment_total_count file(s))"
679
718
  else
680
- log_error "Increment files translation completed with errors: $increment_success_count/$increment_total_count files translated"
719
+ log_error "Translation completed with errors: $increment_success_count/$increment_total_count files"
681
720
  fi
682
- else
683
- log_info "✅ All increment files already in English"
721
+ elif [ "$TRANSLATION_ENABLED" = "true" ] && [ "$AUTO_TRANSLATE_INCREMENT_SPECS" = "false" ]; then
722
+ log_debug "Increment spec translation disabled in scope.incrementSpecs"
723
+ elif [ "$needs_translation" = "false" ]; then
724
+ log_debug "All increment files already in target language"
684
725
  fi
685
726
 
686
- # 6. Translate living docs specs (if any were created)
687
- log_info ""
688
- log_info "🌐 Checking living docs for translation..."
689
-
690
- translate_living_docs_specs "$increment_id"
727
+ # 6. Translate living docs specs (if enabled in scope)
728
+ if [ "$TRANSLATION_ENABLED" = "true" ] && [ "$AUTO_TRANSLATE_LIVING_DOCS" = "true" ]; then
729
+ log_info ""
730
+ log_info "🌐 Checking living docs for translation to $TARGET_LANGUAGE..."
731
+ translate_living_docs_specs "$increment_id"
732
+ else
733
+ log_debug "Living docs translation disabled (scope.livingDocs=$AUTO_TRANSLATE_LIVING_DOCS)"
734
+ fi
691
735
 
692
736
  # ============================================================================
693
737
  # INCREMENT-LEVEL GITHUB ISSUE CREATION (DEPRECATED v0.24.0+)