specweave 0.22.14 → 0.23.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/CLAUDE.md +178 -1
- package/dist/src/cli/commands/import-external.d.ts +22 -0
- package/dist/src/cli/commands/import-external.d.ts.map +1 -0
- package/dist/src/cli/commands/import-external.js +282 -0
- package/dist/src/cli/commands/import-external.js.map +1 -0
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +46 -0
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/helpers/github-repo-selector.d.ts +59 -0
- package/dist/src/cli/helpers/github-repo-selector.d.ts.map +1 -0
- package/dist/src/cli/helpers/github-repo-selector.js +265 -0
- package/dist/src/cli/helpers/github-repo-selector.js.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.js +5 -17
- package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
- package/dist/src/config/types.d.ts +16 -16
- package/dist/src/core/increment/ac-status-manager.d.ts.map +1 -1
- package/dist/src/core/increment/ac-status-manager.js +4 -2
- package/dist/src/core/increment/ac-status-manager.js.map +1 -1
- package/dist/src/core/increment/completion-validator.d.ts +30 -1
- package/dist/src/core/increment/completion-validator.d.ts.map +1 -1
- package/dist/src/core/increment/completion-validator.js +151 -3
- package/dist/src/core/increment/completion-validator.js.map +1 -1
- package/dist/src/core/increment/increment-archiver.d.ts +25 -0
- package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
- package/dist/src/core/increment/increment-archiver.js +130 -3
- package/dist/src/core/increment/increment-archiver.js.map +1 -1
- package/dist/src/core/living-docs/feature-archiver.d.ts +37 -0
- package/dist/src/core/living-docs/feature-archiver.d.ts.map +1 -1
- package/dist/src/core/living-docs/feature-archiver.js +262 -18
- package/dist/src/core/living-docs/feature-archiver.js.map +1 -1
- package/dist/src/core/living-docs/feature-id-manager.d.ts +17 -0
- package/dist/src/core/living-docs/feature-id-manager.d.ts.map +1 -1
- package/dist/src/core/living-docs/feature-id-manager.js +25 -0
- package/dist/src/core/living-docs/feature-id-manager.js.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts +14 -0
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +46 -0
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/repo-structure/repo-id-generator.d.ts +20 -0
- package/dist/src/core/repo-structure/repo-id-generator.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-id-generator.js +44 -0
- 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 +5 -2
- package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
- package/dist/src/core/sync/sync-event-logger.d.ts +15 -1
- package/dist/src/core/sync/sync-event-logger.d.ts.map +1 -1
- package/dist/src/core/sync/sync-event-logger.js +39 -1
- package/dist/src/core/sync/sync-event-logger.js.map +1 -1
- package/dist/src/core/types/sync-config-validator.d.ts +57 -0
- package/dist/src/core/types/sync-config-validator.d.ts.map +1 -0
- package/dist/src/core/types/sync-config-validator.js +116 -0
- package/dist/src/core/types/sync-config-validator.js.map +1 -0
- package/dist/src/importers/duplicate-detector.d.ts +107 -0
- package/dist/src/importers/duplicate-detector.d.ts.map +1 -0
- package/dist/src/importers/duplicate-detector.js +189 -0
- package/dist/src/importers/duplicate-detector.js.map +1 -0
- package/dist/src/importers/import-coordinator.d.ts +15 -0
- package/dist/src/importers/import-coordinator.d.ts.map +1 -1
- package/dist/src/importers/import-coordinator.js +43 -1
- package/dist/src/importers/import-coordinator.js.map +1 -1
- package/dist/src/importers/item-converter.d.ts +5 -0
- package/dist/src/importers/item-converter.d.ts.map +1 -1
- package/dist/src/importers/item-converter.js +27 -2
- package/dist/src/importers/item-converter.js.map +1 -1
- package/dist/src/importers/rate-limiter.d.ts +128 -0
- package/dist/src/importers/rate-limiter.d.ts.map +1 -0
- package/dist/src/importers/rate-limiter.js +200 -0
- package/dist/src/importers/rate-limiter.js.map +1 -0
- package/dist/src/init/compliance/types.d.ts +2 -2
- package/dist/src/integrations/ado/ado-client.d.ts +6 -0
- package/dist/src/integrations/ado/ado-client.d.ts.map +1 -1
- package/dist/src/integrations/ado/ado-client.js +23 -0
- package/dist/src/integrations/ado/ado-client.js.map +1 -1
- package/dist/src/integrations/jira/jira-client.d.ts +6 -0
- package/dist/src/integrations/jira/jira-client.d.ts.map +1 -1
- package/dist/src/integrations/jira/jira-client.js +38 -0
- package/dist/src/integrations/jira/jira-client.js.map +1 -1
- package/dist/src/sync/external-item-sync-service.d.ts +150 -0
- package/dist/src/sync/external-item-sync-service.d.ts.map +1 -0
- package/dist/src/sync/external-item-sync-service.js +241 -0
- package/dist/src/sync/external-item-sync-service.js.map +1 -0
- package/dist/src/sync/format-preservation-sync.d.ts +90 -0
- package/dist/src/sync/format-preservation-sync.d.ts.map +1 -0
- package/dist/src/sync/format-preservation-sync.js +173 -0
- package/dist/src/sync/format-preservation-sync.js.map +1 -0
- package/dist/src/sync/index.d.ts +8 -0
- package/dist/src/sync/index.d.ts.map +1 -0
- package/dist/src/sync/index.js +6 -0
- package/dist/src/sync/index.js.map +1 -0
- package/dist/src/sync/sync-coordinator.d.ts +49 -0
- package/dist/src/sync/sync-coordinator.d.ts.map +1 -0
- package/dist/src/sync/sync-coordinator.js +248 -0
- package/dist/src/sync/sync-coordinator.js.map +1 -0
- package/dist/src/sync/sync-metadata.d.ts +75 -0
- package/dist/src/sync/sync-metadata.d.ts.map +1 -0
- package/dist/src/sync/sync-metadata.js +100 -0
- package/dist/src/sync/sync-metadata.js.map +1 -0
- package/dist/src/types/living-docs-us-file.d.ts +63 -0
- package/dist/src/types/living-docs-us-file.d.ts.map +1 -0
- package/dist/src/types/living-docs-us-file.js +27 -0
- package/dist/src/types/living-docs-us-file.js.map +1 -0
- package/dist/src/validators/format-preservation-validator.d.ts +127 -0
- package/dist/src/validators/format-preservation-validator.d.ts.map +1 -0
- package/dist/src/validators/format-preservation-validator.js +187 -0
- package/dist/src/validators/format-preservation-validator.js.map +1 -0
- package/package.json +3 -2
- package/plugins/specweave/.claude-plugin/plugin.json +20 -0
- package/plugins/specweave/commands/specweave-archive-features.md +11 -1
- package/plugins/specweave/commands/specweave-archive.md +51 -15
- package/plugins/specweave/commands/specweave-import-docs.md +88 -278
- package/plugins/specweave/commands/specweave-import-external.md +407 -0
- package/plugins/specweave/hooks/post-edit-spec.sh +94 -0
- package/plugins/specweave/hooks/post-increment-completion.sh +0 -0
- package/plugins/specweave/hooks/post-spec-update.sh +0 -0
- package/plugins/specweave/hooks/post-task-completion.sh +13 -3
- package/plugins/specweave/hooks/post-write-spec.sh +91 -0
- package/plugins/specweave/lib/hooks/auto-transition.js +1 -1
- package/plugins/specweave/lib/hooks/auto-transition.js.bak +50 -0
- package/plugins/specweave/lib/hooks/auto-transition.ts +1 -1
- package/plugins/specweave/lib/hooks/auto-transition.ts.bak +84 -0
- package/plugins/specweave/lib/hooks/git-diff-analyzer.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/git-diff-analyzer.d.ts.bak +89 -0
- package/plugins/specweave/lib/hooks/git-diff-analyzer.js.bak +142 -0
- package/plugins/specweave/lib/hooks/git-diff-analyzer.ts.bak +269 -0
- package/plugins/specweave/lib/hooks/invoke-translator-skill.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/invoke-translator-skill.d.ts.bak +60 -0
- package/plugins/specweave/lib/hooks/invoke-translator-skill.js +1 -1
- package/plugins/specweave/lib/hooks/invoke-translator-skill.js.bak +155 -0
- package/plugins/specweave/lib/hooks/invoke-translator-skill.ts +1 -1
- package/plugins/specweave/lib/hooks/invoke-translator-skill.ts.bak +264 -0
- package/plugins/specweave/lib/hooks/prepare-reflection-context.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/prepare-reflection-context.d.ts.bak +42 -0
- package/plugins/specweave/lib/hooks/prepare-reflection-context.js.bak +110 -0
- package/plugins/specweave/lib/hooks/prepare-reflection-context.ts.bak +178 -0
- package/plugins/specweave/lib/hooks/reflection-config-loader.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-config-loader.d.ts.bak +45 -0
- package/plugins/specweave/lib/hooks/reflection-config-loader.js.bak +92 -0
- package/plugins/specweave/lib/hooks/reflection-config-loader.ts.bak +156 -0
- package/plugins/specweave/lib/hooks/reflection-parser.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-parser.d.ts.bak +33 -0
- package/plugins/specweave/lib/hooks/reflection-parser.js.bak +301 -0
- package/plugins/specweave/lib/hooks/reflection-parser.ts.bak +484 -0
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.d.ts.bak +56 -0
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.js.bak +182 -0
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.ts.bak +306 -0
- package/plugins/specweave/lib/hooks/reflection-storage.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-storage.d.ts.bak +64 -0
- package/plugins/specweave/lib/hooks/reflection-storage.js.bak +231 -0
- package/plugins/specweave/lib/hooks/reflection-storage.ts.bak +369 -0
- package/plugins/specweave/lib/hooks/run-self-reflection.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/run-self-reflection.d.ts.bak +43 -0
- package/plugins/specweave/lib/hooks/run-self-reflection.js.bak +132 -0
- package/plugins/specweave/lib/hooks/run-self-reflection.ts.bak +258 -0
- package/plugins/specweave/lib/hooks/sync-cache.js.bak +294 -0
- package/plugins/specweave/lib/hooks/sync-living-docs.d.js.bak +1 -0
- package/plugins/specweave/lib/hooks/sync-living-docs.d.ts.bak +27 -0
- package/plugins/specweave/lib/hooks/sync-living-docs.js +35 -1
- package/plugins/specweave/lib/hooks/sync-living-docs.js.bak +339 -0
- package/plugins/specweave/lib/hooks/sync-us-tasks.js +179 -3
- package/plugins/specweave/lib/hooks/sync-us-tasks.js.bak +476 -0
- package/plugins/specweave/lib/hooks/translate-file.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/translate-file.d.ts.bak +59 -0
- package/plugins/specweave/lib/hooks/translate-file.js +1 -1
- package/plugins/specweave/lib/hooks/translate-file.js.bak +289 -0
- package/plugins/specweave/lib/hooks/translate-file.ts +1 -1
- package/plugins/specweave/lib/hooks/translate-file.ts.bak +428 -0
- package/plugins/specweave/lib/hooks/translate-living-docs.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/translate-living-docs.d.ts.bak +13 -0
- package/plugins/specweave/lib/hooks/translate-living-docs.js.bak +119 -0
- package/plugins/specweave/lib/hooks/translate-living-docs.ts.bak +224 -0
- package/plugins/specweave/lib/hooks/update-ac-status.js +1 -1
- package/plugins/specweave/lib/hooks/update-ac-status.js.bak +51 -0
- package/plugins/specweave/lib/hooks/update-ac-status.ts +1 -1
- package/plugins/specweave/lib/hooks/update-ac-status.ts.bak +103 -0
- package/plugins/specweave/lib/hooks/update-tasks-md.d.js.bak +1 -0
- package/plugins/specweave/lib/hooks/update-tasks-md.d.ts.bak +29 -0
- package/plugins/specweave/lib/hooks/update-tasks-md.js.bak +296 -0
- package/plugins/specweave/lib/hooks/update-tasks-md.ts.bak +489 -0
- package/plugins/specweave/lib/vendor/core/increment/ac-status-manager.d.ts +115 -0
- package/plugins/specweave/lib/vendor/core/increment/ac-status-manager.js +345 -0
- package/plugins/specweave/lib/vendor/core/increment/ac-status-manager.js.map +1 -0
- package/plugins/specweave/lib/vendor/core/increment/active-increment-manager.d.ts +106 -0
- package/plugins/specweave/lib/vendor/core/increment/active-increment-manager.js +220 -0
- package/plugins/specweave/lib/vendor/core/increment/active-increment-manager.js.map +1 -0
- package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.d.ts +60 -0
- package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.js +192 -0
- package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.js.map +1 -0
- package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.d.ts +52 -0
- package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.js +276 -0
- package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.js.map +1 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.d.ts +163 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js +541 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js.map +1 -0
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.d.ts +157 -0
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.js +191 -0
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.js.map +1 -0
- package/plugins/specweave/lib/vendor/generators/spec/task-parser.d.ts +95 -0
- package/plugins/specweave/lib/vendor/generators/spec/task-parser.js +301 -0
- package/plugins/specweave/lib/vendor/generators/spec/task-parser.js.map +1 -0
- package/plugins/specweave/lib/vendor/utils/logger.d.ts +48 -0
- package/plugins/specweave/lib/vendor/utils/logger.js +53 -0
- package/plugins/specweave/lib/vendor/utils/logger.js.map +1 -0
- package/plugins/specweave/lib/vendor/utils/translation.d.ts +187 -0
- package/plugins/specweave/lib/vendor/utils/translation.js +414 -0
- package/plugins/specweave/lib/vendor/utils/translation.js.map +1 -0
- package/plugins/specweave-github/commands/specweave-github-update-user-story.md +1 -1
- package/plugins/specweave-github/skills/github-issue-standard/SKILL.md +1 -1
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +531 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translation Utilities
|
|
3
|
+
*
|
|
4
|
+
* LLM-native translation system for SpecWeave multilingual support.
|
|
5
|
+
* Provides zero-cost language detection and cost-efficient translation
|
|
6
|
+
* using Claude Haiku via current LLM session.
|
|
7
|
+
*
|
|
8
|
+
* Strategy:
|
|
9
|
+
* - Language Detection: Simple heuristic (no API calls, <1ms)
|
|
10
|
+
* - Translation: Claude Haiku via current session (~$0.0025 per file)
|
|
11
|
+
* - Preservation: Markdown, code blocks, technical terms stay intact
|
|
12
|
+
*
|
|
13
|
+
* @see .specweave/increments/0006-llm-native-i18n/reports/DESIGN-POST-GENERATION-TRANSLATION.md
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Language detection patterns (Unicode ranges for major scripts)
|
|
17
|
+
*/
|
|
18
|
+
const LANGUAGE_PATTERNS = {
|
|
19
|
+
ru: /[а-яА-ЯёЁ]/, // Cyrillic (Russian)
|
|
20
|
+
zh: /[\u4e00-\u9fff]/, // Chinese characters (CJK Unified Ideographs)
|
|
21
|
+
ja: /[\u3040-\u309f\u30a0-\u30ff]/, // Hiragana + Katakana (Japanese)
|
|
22
|
+
ko: /[\uac00-\ud7af]/, // Hangul (Korean)
|
|
23
|
+
ar: /[\u0600-\u06ff]/, // Arabic
|
|
24
|
+
he: /[\u0590-\u05ff]/, // Hebrew
|
|
25
|
+
// Latin-based languages need context (Spanish, German, French, Portuguese)
|
|
26
|
+
// We'll use heuristics for these
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Spanish-specific words/patterns
|
|
30
|
+
*/
|
|
31
|
+
const SPANISH_INDICATORS = [
|
|
32
|
+
'ción', 'sión', 'qué', 'cuál', 'español', 'también', 'año', 'señor'
|
|
33
|
+
];
|
|
34
|
+
/**
|
|
35
|
+
* German-specific words/patterns
|
|
36
|
+
*/
|
|
37
|
+
const GERMAN_INDICATORS = [
|
|
38
|
+
'ß', 'ä', 'ö', 'ü', 'dass', 'ich', 'und', 'der', 'die', 'das'
|
|
39
|
+
];
|
|
40
|
+
/**
|
|
41
|
+
* French-specific words/patterns
|
|
42
|
+
*/
|
|
43
|
+
const FRENCH_INDICATORS = [
|
|
44
|
+
'ç', 'où', 'être', 'français', 'avec', 'dans', 'pour', 'qui', 'que'
|
|
45
|
+
];
|
|
46
|
+
/**
|
|
47
|
+
* Portuguese-specific words/patterns
|
|
48
|
+
*/
|
|
49
|
+
const PORTUGUESE_INDICATORS = [
|
|
50
|
+
'ção', 'português', 'também', 'não', 'com', 'para', 'seu', 'sua', 'documentação'
|
|
51
|
+
];
|
|
52
|
+
/**
|
|
53
|
+
* Detects the language of the given content using simple heuristics
|
|
54
|
+
*
|
|
55
|
+
* @param content - The text content to analyze
|
|
56
|
+
* @returns Language detection result with confidence score
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* const result = detectLanguage('Это тестовый документ');
|
|
61
|
+
* console.log(result.language); // 'ru'
|
|
62
|
+
* console.log(result.confidence); // 0.95
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export function detectLanguage(content) {
|
|
66
|
+
// Calculate non-ASCII ratio
|
|
67
|
+
const nonAsciiChars = content.match(/[^\x00-\x7F]/g) || [];
|
|
68
|
+
const totalChars = content.length;
|
|
69
|
+
const nonAsciiRatio = totalChars > 0 ? nonAsciiChars.length / totalChars : 0;
|
|
70
|
+
// If <5% non-ASCII, likely English
|
|
71
|
+
if (nonAsciiRatio < 0.05) {
|
|
72
|
+
return {
|
|
73
|
+
language: 'en',
|
|
74
|
+
confidence: 0.95,
|
|
75
|
+
nonAsciiRatio,
|
|
76
|
+
detectionMethod: 'heuristic'
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
// Try to detect specific language
|
|
80
|
+
const detected = detectSpecificLanguage(content);
|
|
81
|
+
if (detected !== 'unknown') {
|
|
82
|
+
return {
|
|
83
|
+
language: detected,
|
|
84
|
+
confidence: 0.90,
|
|
85
|
+
nonAsciiRatio,
|
|
86
|
+
detectionMethod: 'heuristic'
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
// Fallback: unknown language
|
|
90
|
+
return {
|
|
91
|
+
language: 'unknown',
|
|
92
|
+
confidence: 0.5,
|
|
93
|
+
nonAsciiRatio,
|
|
94
|
+
detectionMethod: 'heuristic'
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Detects specific language from content
|
|
99
|
+
*
|
|
100
|
+
* @param content - The text content to analyze
|
|
101
|
+
* @returns Detected language code or 'unknown'
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```typescript
|
|
105
|
+
* detectSpecificLanguage('Это текст'); // 'ru'
|
|
106
|
+
* detectSpecificLanguage('这是文本'); // 'zh'
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export function detectSpecificLanguage(content) {
|
|
110
|
+
// Test against Unicode ranges first (most reliable)
|
|
111
|
+
for (const [lang, pattern] of Object.entries(LANGUAGE_PATTERNS)) {
|
|
112
|
+
if (pattern.test(content)) {
|
|
113
|
+
return lang;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// For Latin-based languages, use indicator words
|
|
117
|
+
const lowerContent = content.toLowerCase();
|
|
118
|
+
// Spanish
|
|
119
|
+
if (SPANISH_INDICATORS.some(indicator => lowerContent.includes(indicator))) {
|
|
120
|
+
return 'es';
|
|
121
|
+
}
|
|
122
|
+
// Portuguese (check before French due to overlap in 'ção' and 'em')
|
|
123
|
+
if (PORTUGUESE_INDICATORS.some(indicator => lowerContent.includes(indicator))) {
|
|
124
|
+
return 'pt';
|
|
125
|
+
}
|
|
126
|
+
// German
|
|
127
|
+
if (GERMAN_INDICATORS.some(indicator => lowerContent.includes(indicator))) {
|
|
128
|
+
return 'de';
|
|
129
|
+
}
|
|
130
|
+
// French
|
|
131
|
+
if (FRENCH_INDICATORS.some(indicator => lowerContent.includes(indicator))) {
|
|
132
|
+
return 'fr';
|
|
133
|
+
}
|
|
134
|
+
return 'unknown';
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Preserves code blocks, inline code, and links before translation
|
|
138
|
+
*
|
|
139
|
+
* @param content - Markdown content to preserve
|
|
140
|
+
* @returns Preserved content with placeholders
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* const content = 'Text\n```js\ncode\n```\nMore text';
|
|
145
|
+
* const preserved = preserveCodeBlocks(content);
|
|
146
|
+
* // preserved.blocks = ['```js\ncode\n```']
|
|
147
|
+
* // preserved.preserved = 'Text\n__CODE_BLOCK_0__\nMore text'
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
export function preserveCodeBlocks(content) {
|
|
151
|
+
const blocks = [];
|
|
152
|
+
const inlineCode = [];
|
|
153
|
+
const links = [];
|
|
154
|
+
// 1. Preserve fenced code blocks (```...```)
|
|
155
|
+
let preserved = content.replace(/```[\s\S]*?```/g, (match) => {
|
|
156
|
+
blocks.push(match);
|
|
157
|
+
return `__CODE_BLOCK_${blocks.length - 1}__`;
|
|
158
|
+
});
|
|
159
|
+
// 2. Preserve inline code (`...`)
|
|
160
|
+
preserved = preserved.replace(/`[^`]+`/g, (match) => {
|
|
161
|
+
inlineCode.push(match);
|
|
162
|
+
return `__INLINE_CODE_${inlineCode.length - 1}__`;
|
|
163
|
+
});
|
|
164
|
+
// 3. Preserve markdown links ([text](url))
|
|
165
|
+
preserved = preserved.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, text, url) => {
|
|
166
|
+
links.push(match);
|
|
167
|
+
return `__LINK_${links.length - 1}__`;
|
|
168
|
+
});
|
|
169
|
+
return {
|
|
170
|
+
preserved,
|
|
171
|
+
blocks,
|
|
172
|
+
inlineCode,
|
|
173
|
+
links
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Restores preserved code blocks, inline code, and links after translation
|
|
178
|
+
*
|
|
179
|
+
* @param translated - Translated text with placeholders
|
|
180
|
+
* @param preserved - Preserved content structure
|
|
181
|
+
* @returns Restored text with original code blocks and links
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```typescript
|
|
185
|
+
* const translated = 'Текст\n__CODE_BLOCK_0__\nБольше текста';
|
|
186
|
+
* const preserved = { blocks: ['```js\ncode\n```'], inlineCode: [], links: [] };
|
|
187
|
+
* const restored = restoreCodeBlocks(translated, preserved);
|
|
188
|
+
* // Result: 'Текст\n```js\ncode\n```\nБольше текста'
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
export function restoreCodeBlocks(translated, preserved) {
|
|
192
|
+
let restored = translated;
|
|
193
|
+
// Restore in reverse order of preservation (links → inline code → blocks)
|
|
194
|
+
// 1. Restore links
|
|
195
|
+
preserved.links.forEach((link, i) => {
|
|
196
|
+
restored = restored.replace(`__LINK_${i}__`, link);
|
|
197
|
+
});
|
|
198
|
+
// 2. Restore inline code
|
|
199
|
+
preserved.inlineCode.forEach((code, i) => {
|
|
200
|
+
restored = restored.replace(`__INLINE_CODE_${i}__`, code);
|
|
201
|
+
});
|
|
202
|
+
// 3. Restore code blocks
|
|
203
|
+
preserved.blocks.forEach((block, i) => {
|
|
204
|
+
restored = restored.replace(`__CODE_BLOCK_${i}__`, block);
|
|
205
|
+
});
|
|
206
|
+
return restored;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Estimates the number of tokens in a text
|
|
210
|
+
* Rule of thumb: ~4 characters per token for English, ~2-3 for other languages
|
|
211
|
+
*
|
|
212
|
+
* @param text - Text to estimate
|
|
213
|
+
* @param language - Language code for estimation
|
|
214
|
+
* @returns Estimated token count
|
|
215
|
+
*/
|
|
216
|
+
export function estimateTokens(text, language = 'en') {
|
|
217
|
+
const charsPerToken = language === 'en' ? 4 : 3;
|
|
218
|
+
return Math.ceil(text.length / charsPerToken);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Estimates translation cost using Claude Haiku pricing
|
|
222
|
+
* Haiku pricing (as of 2025): $0.25 per 1M input tokens, $1.25 per 1M output tokens
|
|
223
|
+
*
|
|
224
|
+
* @param inputTokens - Input token count
|
|
225
|
+
* @param outputTokens - Output token count (defaults to input for balanced estimate)
|
|
226
|
+
* @returns Estimated cost in USD
|
|
227
|
+
*/
|
|
228
|
+
export function estimateTranslationCost(inputTokens, outputTokens) {
|
|
229
|
+
const HAIKU_INPUT_COST_PER_1M = 0.25;
|
|
230
|
+
const HAIKU_OUTPUT_COST_PER_1M = 1.25;
|
|
231
|
+
const actualOutputTokens = outputTokens || inputTokens; // Assume similar length
|
|
232
|
+
const inputCost = (inputTokens / 1000000) * HAIKU_INPUT_COST_PER_1M;
|
|
233
|
+
const outputCost = (actualOutputTokens / 1000000) * HAIKU_OUTPUT_COST_PER_1M;
|
|
234
|
+
return inputCost + outputCost;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Generates translation prompt for LLM
|
|
238
|
+
*
|
|
239
|
+
* @param content - Content to translate
|
|
240
|
+
* @param sourceLanguage - Source language code
|
|
241
|
+
* @param targetLanguage - Target language code (default: 'en')
|
|
242
|
+
* @returns Translation prompt for LLM
|
|
243
|
+
*/
|
|
244
|
+
export function generateTranslationPrompt(content, sourceLanguage, targetLanguage = 'en') {
|
|
245
|
+
const languageNames = {
|
|
246
|
+
en: 'English',
|
|
247
|
+
ru: 'Russian',
|
|
248
|
+
es: 'Spanish',
|
|
249
|
+
zh: 'Chinese',
|
|
250
|
+
de: 'German',
|
|
251
|
+
fr: 'French',
|
|
252
|
+
ja: 'Japanese',
|
|
253
|
+
ko: 'Korean',
|
|
254
|
+
pt: 'Portuguese',
|
|
255
|
+
ar: 'Arabic',
|
|
256
|
+
he: 'Hebrew',
|
|
257
|
+
unknown: 'Unknown'
|
|
258
|
+
};
|
|
259
|
+
const sourceName = languageNames[sourceLanguage] || sourceLanguage;
|
|
260
|
+
const targetName = languageNames[targetLanguage] || targetLanguage;
|
|
261
|
+
return `You are a technical translator specializing in software documentation.
|
|
262
|
+
|
|
263
|
+
Translate the following ${sourceName} document to ${targetName}.
|
|
264
|
+
|
|
265
|
+
PRESERVATION RULES (CRITICAL):
|
|
266
|
+
1. **Markdown Formatting**: Preserve ALL markdown syntax exactly (headers, lists, links, code blocks, tables)
|
|
267
|
+
2. **YAML Frontmatter**: Keep structure intact, translate values only
|
|
268
|
+
3. **Code Blocks**: NEVER translate code (keep as-is, including comments if in English)
|
|
269
|
+
4. **Inline Code**: NEVER translate \`code spans\` (keep as-is)
|
|
270
|
+
5. **Technical Terms**: Keep in English (Git, Docker, Kubernetes, TypeScript, React, etc.)
|
|
271
|
+
6. **Framework Terms**: Keep in English (Increment, Living Docs, SpecWeave, ADR, RFC, HLD, PRD)
|
|
272
|
+
7. **Document Structure**: Maintain exact heading hierarchy and nesting
|
|
273
|
+
8. **Links**: Preserve link structure, translate link text only if needed
|
|
274
|
+
9. **Formatting**: Preserve bold (**text**), italic (*text*), code spans (\`code\`)
|
|
275
|
+
10. **Placeholders**: Do NOT translate placeholders like __CODE_BLOCK_0__, __INLINE_CODE_1__, __LINK_2__
|
|
276
|
+
11. **IDs and References**: Keep task IDs (T-001), test IDs (TC-001), user story IDs (US-001) unchanged
|
|
277
|
+
|
|
278
|
+
TRANSLATION STYLE:
|
|
279
|
+
- Professional technical ${targetName}
|
|
280
|
+
- Clear, concise, unambiguous language
|
|
281
|
+
- Industry-standard terminology
|
|
282
|
+
- Consistent term usage throughout
|
|
283
|
+
- Natural phrasing (not word-for-word literal)
|
|
284
|
+
|
|
285
|
+
SOURCE DOCUMENT (${sourceName}):
|
|
286
|
+
---
|
|
287
|
+
${content}
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
TRANSLATED ${targetName.toUpperCase()} VERSION (preserve all formatting):`;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Translates content to English using LLM (Claude Haiku)
|
|
294
|
+
* This function generates the prompt but delegates actual LLM invocation
|
|
295
|
+
* to the caller (via Task tool, skill, or direct API)
|
|
296
|
+
*
|
|
297
|
+
* @param content - Content to translate
|
|
298
|
+
* @param sourceLanguage - Source language code
|
|
299
|
+
* @returns Translation prompt and metadata (caller must invoke LLM)
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* ```typescript
|
|
303
|
+
* const content = 'Это тестовый документ';
|
|
304
|
+
* const result = prepareTranslation(content, 'ru');
|
|
305
|
+
* // Caller then invokes LLM with result.prompt
|
|
306
|
+
* ```
|
|
307
|
+
*/
|
|
308
|
+
export function prepareTranslation(content, sourceLanguage, targetLanguage = 'en') {
|
|
309
|
+
// 1. Preserve code blocks and links
|
|
310
|
+
const preserved = preserveCodeBlocks(content);
|
|
311
|
+
// 2. Generate translation prompt
|
|
312
|
+
const prompt = generateTranslationPrompt(preserved.preserved, sourceLanguage, targetLanguage);
|
|
313
|
+
// 3. Estimate cost
|
|
314
|
+
const inputTokens = estimateTokens(prompt, sourceLanguage);
|
|
315
|
+
const outputTokens = estimateTokens(preserved.preserved, targetLanguage);
|
|
316
|
+
const estimatedCost = estimateTranslationCost(inputTokens, outputTokens);
|
|
317
|
+
return {
|
|
318
|
+
prompt,
|
|
319
|
+
preserved,
|
|
320
|
+
estimatedTokens: inputTokens + outputTokens,
|
|
321
|
+
estimatedCost
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Post-processes translated content
|
|
326
|
+
* Restores code blocks, validates markdown, cleans up extra whitespace
|
|
327
|
+
*
|
|
328
|
+
* @param translated - Translated text from LLM
|
|
329
|
+
* @param preserved - Preserved content structure
|
|
330
|
+
* @returns Cleaned and restored translated content
|
|
331
|
+
*/
|
|
332
|
+
export function postProcessTranslation(translated, preserved) {
|
|
333
|
+
// 1. Restore preserved blocks
|
|
334
|
+
let restored = restoreCodeBlocks(translated, preserved);
|
|
335
|
+
// 2. Clean up extra whitespace (LLM sometimes adds extra newlines)
|
|
336
|
+
restored = restored
|
|
337
|
+
.replace(/\n{4,}/g, '\n\n\n') // Max 3 consecutive newlines
|
|
338
|
+
.replace(/[ \t]+$/gm, ''); // Remove trailing spaces
|
|
339
|
+
// 3. Ensure file ends with single newline
|
|
340
|
+
restored = restored.trim() + '\n';
|
|
341
|
+
return restored;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Validates that translated content preserves markdown structure
|
|
345
|
+
* Returns warnings if structure doesn't match
|
|
346
|
+
*
|
|
347
|
+
* @param original - Original content
|
|
348
|
+
* @param translated - Translated content
|
|
349
|
+
* @returns Array of validation warnings (empty if valid)
|
|
350
|
+
*/
|
|
351
|
+
export function validateTranslation(original, translated) {
|
|
352
|
+
const warnings = [];
|
|
353
|
+
// 1. Check heading count matches
|
|
354
|
+
const originalHeadings = (original.match(/^#{1,6}\s/gm) || []).length;
|
|
355
|
+
const translatedHeadings = (translated.match(/^#{1,6}\s/gm) || []).length;
|
|
356
|
+
if (originalHeadings !== translatedHeadings) {
|
|
357
|
+
warnings.push(`Heading count mismatch: original has ${originalHeadings}, translated has ${translatedHeadings}`);
|
|
358
|
+
}
|
|
359
|
+
// 2. Check code block count matches
|
|
360
|
+
const originalCodeBlocks = (original.match(/```/g) || []).length;
|
|
361
|
+
const translatedCodeBlocks = (translated.match(/```/g) || []).length;
|
|
362
|
+
if (originalCodeBlocks !== translatedCodeBlocks) {
|
|
363
|
+
warnings.push(`Code block count mismatch: original has ${originalCodeBlocks}, translated has ${translatedCodeBlocks}`);
|
|
364
|
+
}
|
|
365
|
+
// 3. Check link count matches
|
|
366
|
+
const originalLinks = (original.match(/\[([^\]]+)\]\(([^)]+)\)/g) || []).length;
|
|
367
|
+
const translatedLinks = (translated.match(/\[([^\]]+)\]\(([^)]+)\)/g) || []).length;
|
|
368
|
+
if (originalLinks !== translatedLinks) {
|
|
369
|
+
warnings.push(`Link count mismatch: original has ${originalLinks}, translated has ${translatedLinks}`);
|
|
370
|
+
}
|
|
371
|
+
// 4. Check YAML frontmatter present in both (if exists in original)
|
|
372
|
+
const hasOriginalYAML = /^---\n[\s\S]*?\n---/m.test(original);
|
|
373
|
+
const hasTranslatedYAML = /^---\n[\s\S]*?\n---/m.test(translated);
|
|
374
|
+
if (hasOriginalYAML && !hasTranslatedYAML) {
|
|
375
|
+
warnings.push('YAML frontmatter missing in translation');
|
|
376
|
+
}
|
|
377
|
+
return warnings;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Gets human-readable language name
|
|
381
|
+
*
|
|
382
|
+
* @param code - Language code
|
|
383
|
+
* @returns Human-readable name
|
|
384
|
+
*/
|
|
385
|
+
export function getLanguageName(code) {
|
|
386
|
+
const names = {
|
|
387
|
+
en: 'English',
|
|
388
|
+
ru: 'Russian',
|
|
389
|
+
es: 'Spanish',
|
|
390
|
+
zh: 'Chinese',
|
|
391
|
+
de: 'German',
|
|
392
|
+
fr: 'French',
|
|
393
|
+
ja: 'Japanese',
|
|
394
|
+
ko: 'Korean',
|
|
395
|
+
pt: 'Portuguese',
|
|
396
|
+
ar: 'Arabic',
|
|
397
|
+
he: 'Hebrew',
|
|
398
|
+
unknown: 'Unknown'
|
|
399
|
+
};
|
|
400
|
+
return names[code] || code;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Formats cost for display
|
|
404
|
+
*
|
|
405
|
+
* @param cost - Cost in USD
|
|
406
|
+
* @returns Formatted string (e.g., "$0.0025" or "<$0.001")
|
|
407
|
+
*/
|
|
408
|
+
export function formatCost(cost) {
|
|
409
|
+
if (cost < 0.001) {
|
|
410
|
+
return '<$0.001';
|
|
411
|
+
}
|
|
412
|
+
return `$${cost.toFixed(4)}`;
|
|
413
|
+
}
|
|
414
|
+
//# sourceMappingURL=translation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translation.js","sourceRoot":"","sources":["../../../src/utils/translation.ts"],"names":[],"mappings":"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"}
|
|
@@ -53,7 +53,7 @@ description: Update GitHub issue for user story with proper ACs and tasks
|
|
|
53
53
|
**What Gets Updated**:
|
|
54
54
|
|
|
55
55
|
```markdown
|
|
56
|
-
**Feature**: [FS-031](../../_features/FS-031/FEATURE.md)
|
|
56
|
+
**Feature**: [FS-031](../../_features/_archive/FS-031/FEATURE.md)
|
|
57
57
|
**Status**: complete
|
|
58
58
|
**Priority**: P1
|
|
59
59
|
**Project**: default
|
|
@@ -94,7 +94,7 @@ if (repo && taskLink.startsWith('../../')) {
|
|
|
94
94
|
**I want** feature
|
|
95
95
|
**So that** benefit
|
|
96
96
|
|
|
97
|
-
📄 View full story: [`us-004-name.md`](https://github.com/owner/repo/tree/develop/.specweave/docs/internal/specs/default/FS-031/us-004-name.md)
|
|
97
|
+
📄 View full story: [`us-004-name.md`](https://github.com/owner/repo/tree/develop/.specweave/docs/internal/specs/default/_archive/FS-031/us-004-name.md)
|
|
98
98
|
|
|
99
99
|
---
|
|
100
100
|
|