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.
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +17 -1
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/helpers/init/index.d.ts +1 -0
- package/dist/src/cli/helpers/init/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/index.js +2 -0
- package/dist/src/cli/helpers/init/index.js.map +1 -1
- package/dist/src/cli/helpers/init/translation-config.d.ts +53 -0
- package/dist/src/cli/helpers/init/translation-config.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/translation-config.js +216 -0
- package/dist/src/cli/helpers/init/translation-config.js.map +1 -0
- package/dist/src/cli/helpers/init/types.d.ts +33 -0
- package/dist/src/cli/helpers/init/types.d.ts.map +1 -1
- package/dist/src/core/config/types.d.ts +115 -0
- package/dist/src/core/config/types.d.ts.map +1 -1
- package/dist/src/core/config/types.js.map +1 -1
- package/dist/src/core/repo-structure/repo-id-generator.d.ts +24 -95
- package/dist/src/core/repo-structure/repo-id-generator.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-id-generator.js +31 -223
- package/dist/src/core/repo-structure/repo-id-generator.js.map +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 +12 -46
- package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
- package/dist/src/utils/multi-repo-detector.d.ts +85 -0
- package/dist/src/utils/multi-repo-detector.d.ts.map +1 -0
- package/dist/src/utils/multi-repo-detector.js +264 -0
- package/dist/src/utils/multi-repo-detector.js.map +1 -0
- package/package.json +1 -1
- package/plugins/specweave/agents/pm/AGENT.md +141 -0
- package/plugins/specweave/commands/specweave-done.md +28 -0
- package/plugins/specweave/hooks/hooks.json +12 -0
- package/plugins/specweave/hooks/post-increment-completion.sh +59 -0
- package/plugins/specweave/hooks/post-increment-planning.sh +95 -51
- package/plugins/specweave/hooks/pre-task-completion-edit.sh +355 -0
- package/plugins/specweave/lib/hooks/sync-living-docs.js +43 -0
- package/plugins/specweave/skills/umbrella-repo-detector/SKILL.md +219 -0
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +18 -0
- package/plugins/specweave-infrastructure/skills/hetzner-provisioner/README.md +1 -1
- 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 (
|
|
62
|
-
TRANSLATION_ENABLED=
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
#
|
|
104
|
-
local
|
|
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" = "
|
|
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
|
-
#
|
|
112
|
-
local
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
#
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
589
|
-
|
|
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
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
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
|
|
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 "đ
|
|
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
|
|
717
|
+
log_info "â
Increment files translated to $TARGET_LANGUAGE! ($increment_total_count file(s))"
|
|
679
718
|
else
|
|
680
|
-
log_error "
|
|
719
|
+
log_error "Translation completed with errors: $increment_success_count/$increment_total_count files"
|
|
681
720
|
fi
|
|
682
|
-
|
|
683
|
-
|
|
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
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
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+)
|