specweave 0.26.2 → 0.26.4

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 (113) hide show
  1. package/CLAUDE.md +172 -1413
  2. package/dist/src/cli/commands/plan/plan-orchestrator.js +2 -2
  3. package/dist/src/cli/commands/plan/plan-orchestrator.js.map +1 -1
  4. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.d.ts.map +1 -1
  5. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js +147 -55
  6. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js.map +1 -1
  7. package/dist/src/core/increment/completion-validator.d.ts +4 -0
  8. package/dist/src/core/increment/completion-validator.d.ts.map +1 -1
  9. package/dist/src/core/increment/completion-validator.js +36 -0
  10. package/dist/src/core/increment/completion-validator.js.map +1 -1
  11. package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
  12. package/dist/src/core/living-docs/living-docs-sync.js +47 -13
  13. package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
  14. package/dist/src/core/us-sync-throttle.d.ts +113 -0
  15. package/dist/src/core/us-sync-throttle.d.ts.map +1 -0
  16. package/dist/src/core/us-sync-throttle.js +195 -0
  17. package/dist/src/core/us-sync-throttle.js.map +1 -0
  18. package/dist/src/utils/external-tool-drift-detector.d.ts +76 -0
  19. package/dist/src/utils/external-tool-drift-detector.d.ts.map +1 -0
  20. package/dist/src/utils/external-tool-drift-detector.js +235 -0
  21. package/dist/src/utils/external-tool-drift-detector.js.map +1 -0
  22. package/package.json +4 -4
  23. package/plugins/specweave/hooks/post-task-completion.sh +6 -6
  24. package/plugins/specweave/hooks/pre-increment-start.sh +6 -1
  25. package/plugins/specweave/lib/hooks/us-completion-orchestrator.js +62 -89
  26. package/plugins/specweave/lib/hooks/us-completion-orchestrator.ts +215 -0
  27. package/plugins/specweave-ado/lib/ado-multi-project-sync.js +0 -1
  28. package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
  29. package/plugins/specweave-release/hooks/post-task-completion.sh +5 -1
  30. package/plugins/specweave/agents/pm/AGENT.md.bak +0 -1893
  31. package/plugins/specweave/hooks/docs-changed.sh.backup +0 -79
  32. package/plugins/specweave/hooks/human-input-required.sh.backup +0 -75
  33. package/plugins/specweave/hooks/lib/migrate-increment-work.sh.bak +0 -245
  34. package/plugins/specweave/hooks/lib/sync-spec-content.sh.bak +0 -149
  35. package/plugins/specweave/hooks/lib/validate-spec-status.sh.bak +0 -163
  36. package/plugins/specweave/hooks/post-first-increment.sh.backup +0 -61
  37. package/plugins/specweave/hooks/post-first-increment.sh.bak +0 -61
  38. package/plugins/specweave/hooks/post-increment-change.sh.backup +0 -98
  39. package/plugins/specweave/hooks/post-increment-completion.sh.backup +0 -231
  40. package/plugins/specweave/hooks/post-increment-planning.sh.backup +0 -1048
  41. package/plugins/specweave/hooks/post-increment-status-change.sh.backup +0 -147
  42. package/plugins/specweave/hooks/post-spec-update.sh.backup +0 -158
  43. package/plugins/specweave/hooks/post-spec-update.sh.bak +0 -158
  44. package/plugins/specweave/hooks/post-user-story-complete.sh.backup +0 -179
  45. package/plugins/specweave/hooks/post-user-story-complete.sh.bak +0 -179
  46. package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +0 -83
  47. package/plugins/specweave/hooks/pre-command-deduplication.sh.bak +0 -83
  48. package/plugins/specweave/hooks/pre-implementation.sh.backup +0 -67
  49. package/plugins/specweave/hooks/pre-task-completion.sh.backup +0 -194
  50. package/plugins/specweave/hooks/pre-tool-use.sh.backup +0 -133
  51. package/plugins/specweave/hooks/user-prompt-submit.sh.backup +0 -386
  52. package/plugins/specweave/hooks/user-prompt-submit.sh.bak +0 -386
  53. package/plugins/specweave/lib/hooks/auto-transition.js.bak +0 -50
  54. package/plugins/specweave/lib/hooks/auto-transition.ts.bak +0 -84
  55. package/plugins/specweave/lib/hooks/git-diff-analyzer.d.js.bak +0 -0
  56. package/plugins/specweave/lib/hooks/git-diff-analyzer.d.ts.bak +0 -89
  57. package/plugins/specweave/lib/hooks/git-diff-analyzer.js.bak +0 -142
  58. package/plugins/specweave/lib/hooks/git-diff-analyzer.ts.bak +0 -269
  59. package/plugins/specweave/lib/hooks/invoke-translator-skill.d.js.bak +0 -0
  60. package/plugins/specweave/lib/hooks/invoke-translator-skill.d.ts.bak +0 -60
  61. package/plugins/specweave/lib/hooks/invoke-translator-skill.js.bak +0 -155
  62. package/plugins/specweave/lib/hooks/invoke-translator-skill.ts.bak +0 -264
  63. package/plugins/specweave/lib/hooks/prepare-reflection-context.d.js.bak +0 -0
  64. package/plugins/specweave/lib/hooks/prepare-reflection-context.d.ts.bak +0 -42
  65. package/plugins/specweave/lib/hooks/prepare-reflection-context.js.bak +0 -110
  66. package/plugins/specweave/lib/hooks/prepare-reflection-context.ts.bak +0 -178
  67. package/plugins/specweave/lib/hooks/reflection-config-loader.d.js.bak +0 -0
  68. package/plugins/specweave/lib/hooks/reflection-config-loader.d.ts.bak +0 -45
  69. package/plugins/specweave/lib/hooks/reflection-config-loader.js.bak +0 -92
  70. package/plugins/specweave/lib/hooks/reflection-config-loader.ts.bak +0 -156
  71. package/plugins/specweave/lib/hooks/reflection-parser.d.js.bak +0 -0
  72. package/plugins/specweave/lib/hooks/reflection-parser.d.ts.bak +0 -33
  73. package/plugins/specweave/lib/hooks/reflection-parser.js.bak +0 -301
  74. package/plugins/specweave/lib/hooks/reflection-parser.ts.bak +0 -484
  75. package/plugins/specweave/lib/hooks/reflection-prompt-builder.d.js.bak +0 -0
  76. package/plugins/specweave/lib/hooks/reflection-prompt-builder.d.ts.bak +0 -56
  77. package/plugins/specweave/lib/hooks/reflection-prompt-builder.js.bak +0 -182
  78. package/plugins/specweave/lib/hooks/reflection-prompt-builder.ts.bak +0 -306
  79. package/plugins/specweave/lib/hooks/reflection-storage.d.js.bak +0 -0
  80. package/plugins/specweave/lib/hooks/reflection-storage.d.ts.bak +0 -64
  81. package/plugins/specweave/lib/hooks/reflection-storage.js.bak +0 -231
  82. package/plugins/specweave/lib/hooks/reflection-storage.ts.bak +0 -369
  83. package/plugins/specweave/lib/hooks/run-self-reflection.d.js.bak +0 -0
  84. package/plugins/specweave/lib/hooks/run-self-reflection.d.ts.bak +0 -43
  85. package/plugins/specweave/lib/hooks/run-self-reflection.js.bak +0 -132
  86. package/plugins/specweave/lib/hooks/run-self-reflection.ts.bak +0 -258
  87. package/plugins/specweave/lib/hooks/sync-cache.js.bak +0 -294
  88. package/plugins/specweave/lib/hooks/sync-living-docs.d.js.bak +0 -1
  89. package/plugins/specweave/lib/hooks/sync-living-docs.d.ts.bak +0 -27
  90. package/plugins/specweave/lib/hooks/sync-living-docs.js.bak +0 -339
  91. package/plugins/specweave/lib/hooks/sync-us-tasks.js.bak +0 -476
  92. package/plugins/specweave/lib/hooks/translate-file.d.js.bak +0 -0
  93. package/plugins/specweave/lib/hooks/translate-file.d.ts.bak +0 -59
  94. package/plugins/specweave/lib/hooks/translate-file.js.bak +0 -289
  95. package/plugins/specweave/lib/hooks/translate-file.ts.bak +0 -428
  96. package/plugins/specweave/lib/hooks/translate-living-docs.d.js.bak +0 -0
  97. package/plugins/specweave/lib/hooks/translate-living-docs.d.ts.bak +0 -13
  98. package/plugins/specweave/lib/hooks/translate-living-docs.js.bak +0 -119
  99. package/plugins/specweave/lib/hooks/translate-living-docs.ts.bak +0 -224
  100. package/plugins/specweave/lib/hooks/update-ac-status.js.bak +0 -51
  101. package/plugins/specweave/lib/hooks/update-ac-status.ts.bak +0 -103
  102. package/plugins/specweave/lib/hooks/update-tasks-md.d.js.bak +0 -1
  103. package/plugins/specweave/lib/hooks/update-tasks-md.d.ts.bak +0 -29
  104. package/plugins/specweave/lib/hooks/update-tasks-md.js.bak +0 -296
  105. package/plugins/specweave/lib/hooks/update-tasks-md.ts.bak +0 -489
  106. package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +0 -353
  107. package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +0 -172
  108. package/plugins/specweave-ado/lib/enhanced-ado-sync.js +0 -170
  109. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +0 -904
  110. package/plugins/specweave-github/hooks/post-task-completion.sh.backup +0 -258
  111. package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +0 -172
  112. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +0 -738
  113. package/plugins/specweave-release/hooks/post-task-completion.sh.backup +0 -110
@@ -1,142 +0,0 @@
1
- import { execSync } from "child_process";
2
- import fs from "fs-extra";
3
- import path from "path";
4
- function executeGitCommand(command, cwd) {
5
- try {
6
- return execSync(command, {
7
- cwd: cwd || process.cwd(),
8
- encoding: "utf-8",
9
- stdio: ["pipe", "pipe", "pipe"]
10
- });
11
- } catch (error) {
12
- throw new Error(`Git command failed: ${command}. ${error.message}`);
13
- }
14
- }
15
- function isGitRepository(dir = process.cwd()) {
16
- try {
17
- executeGitCommand("git rev-parse --git-dir", dir);
18
- return true;
19
- } catch {
20
- return false;
21
- }
22
- }
23
- function getModifiedFilesList(cwd) {
24
- if (!isGitRepository(cwd)) {
25
- return [];
26
- }
27
- try {
28
- const output = executeGitCommand("git diff --name-only HEAD", cwd);
29
- if (!output.trim()) {
30
- return [];
31
- }
32
- return output.trim().split("\n").filter((file) => file.length > 0).filter((file) => !file.startsWith(".git/"));
33
- } catch {
34
- return [];
35
- }
36
- }
37
- function parseNumstat(numstatOutput) {
38
- const stats = /* @__PURE__ */ new Map();
39
- if (!numstatOutput.trim()) {
40
- return stats;
41
- }
42
- const lines = numstatOutput.trim().split("\n");
43
- for (const line of lines) {
44
- const parts = line.split(" ");
45
- if (parts.length < 3) continue;
46
- const added = parts[0] === "-" ? 0 : parseInt(parts[0], 10);
47
- const removed = parts[1] === "-" ? 0 : parseInt(parts[1], 10);
48
- const filename = parts[2];
49
- stats.set(filename, { added, removed });
50
- }
51
- return stats;
52
- }
53
- function getFileDiff(file, cwd) {
54
- if (!isGitRepository(cwd)) {
55
- return "";
56
- }
57
- try {
58
- const output = executeGitCommand(`git diff HEAD -- "${file}"`, cwd);
59
- return output;
60
- } catch {
61
- return "";
62
- }
63
- }
64
- function getFileContent(file, cwd) {
65
- try {
66
- const workingDir = cwd || process.cwd();
67
- const absolutePath = path.isAbsolute(file) ? file : path.join(workingDir, file);
68
- if (!fs.existsSync(absolutePath)) {
69
- return "";
70
- }
71
- return fs.readFileSync(absolutePath, "utf-8");
72
- } catch {
73
- return "";
74
- }
75
- }
76
- function getModifiedFiles(cwd, maxFiles = 100) {
77
- if (!isGitRepository(cwd)) {
78
- return [];
79
- }
80
- const workingDir = cwd || process.cwd();
81
- const modifiedFiles = getModifiedFilesList(workingDir);
82
- if (modifiedFiles.length === 0) {
83
- return [];
84
- }
85
- const filesToAnalyze = modifiedFiles.slice(0, maxFiles);
86
- let numstatOutput = "";
87
- try {
88
- numstatOutput = executeGitCommand("git diff --numstat HEAD", workingDir);
89
- } catch {
90
- }
91
- const stats = parseNumstat(numstatOutput);
92
- const result = [];
93
- for (const file of filesToAnalyze) {
94
- const fileStat = stats.get(file) || { added: 0, removed: 0 };
95
- const diffContent = getFileDiff(file, workingDir);
96
- if (fileStat.added > 0 || fileStat.removed > 0 || diffContent.length > 0) {
97
- result.push({
98
- file,
99
- linesAdded: fileStat.added,
100
- linesRemoved: fileStat.removed,
101
- content: diffContent
102
- });
103
- }
104
- }
105
- return result;
106
- }
107
- function getModifiedFilesSummary(modifiedFiles) {
108
- return {
109
- count: modifiedFiles.length,
110
- linesAdded: modifiedFiles.reduce((sum, file) => sum + file.linesAdded, 0),
111
- linesRemoved: modifiedFiles.reduce((sum, file) => sum + file.linesRemoved, 0),
112
- totalChanges: modifiedFiles.reduce(
113
- (sum, file) => sum + file.linesAdded + file.linesRemoved,
114
- 0
115
- )
116
- };
117
- }
118
- function filterFilesByExtension(modifiedFiles, extensions) {
119
- return modifiedFiles.filter((file) => {
120
- const ext = path.extname(file.file).toLowerCase();
121
- return extensions.some((allowedExt) => ext === allowedExt.toLowerCase());
122
- });
123
- }
124
- function excludeFilesByPattern(modifiedFiles, patterns) {
125
- return modifiedFiles.filter((file) => {
126
- return !patterns.some((pattern) => {
127
- const regex = new RegExp("^" + pattern.replace(/\*/g, ".*") + "$");
128
- return regex.test(file.file);
129
- });
130
- });
131
- }
132
- export {
133
- excludeFilesByPattern,
134
- filterFilesByExtension,
135
- getFileContent,
136
- getFileDiff,
137
- getModifiedFiles,
138
- getModifiedFilesList,
139
- getModifiedFilesSummary,
140
- isGitRepository,
141
- parseNumstat
142
- };
@@ -1,269 +0,0 @@
1
- /**
2
- * Git Diff Analyzer
3
- *
4
- * Extracts modified files from git diff for reflection analysis
5
- * Parses git diff output to get file changes, line counts, and content
6
- *
7
- * @module git-diff-analyzer
8
- */
9
-
10
- import { execSync } from 'child_process';
11
- import fs from 'fs-extra';
12
- import path from 'path';
13
- import { GitDiffInfo } from './types/reflection-types';
14
-
15
- /**
16
- * Execute git command safely
17
- * @param command Git command to execute
18
- * @param cwd Working directory (optional)
19
- * @returns Command output as string
20
- * @throws Error if command fails
21
- */
22
- function executeGitCommand(command: string, cwd?: string): string {
23
- try {
24
- return execSync(command, {
25
- cwd: cwd || process.cwd(),
26
- encoding: 'utf-8',
27
- stdio: ['pipe', 'pipe', 'pipe']
28
- });
29
- } catch (error: any) {
30
- throw new Error(`Git command failed: ${command}. ${error.message}`);
31
- }
32
- }
33
-
34
- /**
35
- * Check if directory is a git repository
36
- * @param dir Directory to check (defaults to cwd)
37
- * @returns True if directory is in a git repository
38
- */
39
- export function isGitRepository(dir: string = process.cwd()): boolean {
40
- try {
41
- executeGitCommand('git rev-parse --git-dir', dir);
42
- return true;
43
- } catch {
44
- return false;
45
- }
46
- }
47
-
48
- /**
49
- * Get list of modified files in the working directory
50
- * Includes both staged and unstaged changes
51
- *
52
- * @param cwd Working directory (optional, defaults to process.cwd())
53
- * @returns Array of file paths relative to git root
54
- */
55
- export function getModifiedFilesList(cwd?: string): string[] {
56
- if (!isGitRepository(cwd)) {
57
- return [];
58
- }
59
-
60
- try {
61
- // Get both staged and unstaged changes
62
- const output = executeGitCommand('git diff --name-only HEAD', cwd);
63
-
64
- if (!output.trim()) {
65
- return [];
66
- }
67
-
68
- return output
69
- .trim()
70
- .split('\n')
71
- .filter(file => file.length > 0)
72
- .filter(file => !file.startsWith('.git/')); // Exclude .git directory
73
- } catch {
74
- return [];
75
- }
76
- }
77
-
78
- /**
79
- * Parse git diff numstat output to get line counts
80
- * Format: <added>\t<removed>\t<filename>
81
- *
82
- * @param numstatOutput Output from git diff --numstat
83
- * @returns Map of filename to {added, removed} counts
84
- */
85
- export function parseNumstat(numstatOutput: string): Map<string, { added: number; removed: number }> {
86
- const stats = new Map<string, { added: number; removed: number }>();
87
-
88
- if (!numstatOutput.trim()) {
89
- return stats;
90
- }
91
-
92
- const lines = numstatOutput.trim().split('\n');
93
-
94
- for (const line of lines) {
95
- const parts = line.split('\t');
96
- if (parts.length < 3) continue;
97
-
98
- const added = parts[0] === '-' ? 0 : parseInt(parts[0], 10);
99
- const removed = parts[1] === '-' ? 0 : parseInt(parts[1], 10);
100
- const filename = parts[2];
101
-
102
- stats.set(filename, { added, removed });
103
- }
104
-
105
- return stats;
106
- }
107
-
108
- /**
109
- * Get diff content for a specific file
110
- * @param file File path relative to git root
111
- * @param cwd Working directory (optional)
112
- * @returns Diff content as string
113
- */
114
- export function getFileDiff(file: string, cwd?: string): string {
115
- if (!isGitRepository(cwd)) {
116
- return '';
117
- }
118
-
119
- try {
120
- // Get unified diff for the file
121
- const output = executeGitCommand(`git diff HEAD -- "${file}"`, cwd);
122
- return output;
123
- } catch {
124
- return '';
125
- }
126
- }
127
-
128
- /**
129
- * Get current file content
130
- * @param file File path (can be absolute or relative to cwd)
131
- * @param cwd Working directory (optional)
132
- * @returns File content as string, or empty string if file doesn't exist
133
- */
134
- export function getFileContent(file: string, cwd?: string): string {
135
- try {
136
- const workingDir = cwd || process.cwd();
137
- const absolutePath = path.isAbsolute(file) ? file : path.join(workingDir, file);
138
-
139
- if (!fs.existsSync(absolutePath)) {
140
- return '';
141
- }
142
-
143
- return fs.readFileSync(absolutePath, 'utf-8');
144
- } catch {
145
- return '';
146
- }
147
- }
148
-
149
- /**
150
- * Get modified files with diff information
151
- * Main function for reflection analysis
152
- *
153
- * @param cwd Working directory (optional, defaults to process.cwd())
154
- * @param maxFiles Maximum number of files to return (optional, defaults to 100)
155
- * @returns Array of GitDiffInfo objects with file changes
156
- */
157
- export function getModifiedFiles(
158
- cwd?: string,
159
- maxFiles: number = 100
160
- ): GitDiffInfo[] {
161
- if (!isGitRepository(cwd)) {
162
- return [];
163
- }
164
-
165
- const workingDir = cwd || process.cwd();
166
-
167
- // Get list of modified files
168
- const modifiedFiles = getModifiedFilesList(workingDir);
169
-
170
- if (modifiedFiles.length === 0) {
171
- return [];
172
- }
173
-
174
- // Limit number of files to prevent overwhelming the analysis
175
- const filesToAnalyze = modifiedFiles.slice(0, maxFiles);
176
-
177
- // Get line count statistics
178
- let numstatOutput = '';
179
- try {
180
- numstatOutput = executeGitCommand('git diff --numstat HEAD', workingDir);
181
- } catch {
182
- // If numstat fails, continue with empty stats
183
- }
184
-
185
- const stats = parseNumstat(numstatOutput);
186
-
187
- // Build GitDiffInfo array
188
- const result: GitDiffInfo[] = [];
189
-
190
- for (const file of filesToAnalyze) {
191
- const fileStat = stats.get(file) || { added: 0, removed: 0 };
192
- const diffContent = getFileDiff(file, workingDir);
193
-
194
- // Only include files with actual changes
195
- if (fileStat.added > 0 || fileStat.removed > 0 || diffContent.length > 0) {
196
- result.push({
197
- file,
198
- linesAdded: fileStat.added,
199
- linesRemoved: fileStat.removed,
200
- content: diffContent
201
- });
202
- }
203
- }
204
-
205
- return result;
206
- }
207
-
208
- /**
209
- * Get summary statistics for modified files
210
- * Useful for reflection metadata
211
- *
212
- * @param modifiedFiles Array of GitDiffInfo objects
213
- * @returns Summary with file count, total lines added/removed
214
- */
215
- export function getModifiedFilesSummary(modifiedFiles: GitDiffInfo[]): {
216
- count: number;
217
- linesAdded: number;
218
- linesRemoved: number;
219
- totalChanges: number;
220
- } {
221
- return {
222
- count: modifiedFiles.length,
223
- linesAdded: modifiedFiles.reduce((sum, file) => sum + file.linesAdded, 0),
224
- linesRemoved: modifiedFiles.reduce((sum, file) => sum + file.linesRemoved, 0),
225
- totalChanges: modifiedFiles.reduce(
226
- (sum, file) => sum + file.linesAdded + file.linesRemoved,
227
- 0
228
- )
229
- };
230
- }
231
-
232
- /**
233
- * Filter files by extension
234
- * Useful for focusing reflection on specific file types
235
- *
236
- * @param modifiedFiles Array of GitDiffInfo objects
237
- * @param extensions Array of file extensions (e.g., ['.ts', '.js'])
238
- * @returns Filtered array of GitDiffInfo objects
239
- */
240
- export function filterFilesByExtension(
241
- modifiedFiles: GitDiffInfo[],
242
- extensions: string[]
243
- ): GitDiffInfo[] {
244
- return modifiedFiles.filter(file => {
245
- const ext = path.extname(file.file).toLowerCase();
246
- return extensions.some(allowedExt => ext === allowedExt.toLowerCase());
247
- });
248
- }
249
-
250
- /**
251
- * Exclude files matching patterns
252
- * Useful for excluding generated files, test files, etc.
253
- *
254
- * @param modifiedFiles Array of GitDiffInfo objects
255
- * @param patterns Array of glob patterns to exclude
256
- * @returns Filtered array of GitDiffInfo objects
257
- */
258
- export function excludeFilesByPattern(
259
- modifiedFiles: GitDiffInfo[],
260
- patterns: string[]
261
- ): GitDiffInfo[] {
262
- return modifiedFiles.filter(file => {
263
- return !patterns.some(pattern => {
264
- // Simple pattern matching (supports * wildcard)
265
- const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$');
266
- return regex.test(file.file);
267
- });
268
- });
269
- }
@@ -1,60 +0,0 @@
1
- /**
2
- * Translator Skill Invocation Utility
3
- *
4
- * Provides programmatic invocation of the translator skill for automated translation.
5
- * Used by hooks and CLI scripts to translate content without manual intervention.
6
- *
7
- * @see plugins/specweave/skills/translator/SKILL.md
8
- * @see plugins/specweave/commands/translate.md
9
- */
10
- import { type SupportedLanguage } from '../../../../src/utils/translation.js';
11
- /**
12
- * Translation result
13
- */
14
- export interface TranslationResult {
15
- success: boolean;
16
- sourceLanguage: SupportedLanguage;
17
- targetLanguage: SupportedLanguage;
18
- originalContent: string;
19
- translatedContent?: string;
20
- error?: string;
21
- }
22
- /**
23
- * Invokes translator skill to translate content
24
- *
25
- * This function integrates with the translator skill by:
26
- * 1. Preparing translation prompt
27
- * 2. Writing prompt to a temp file
28
- * 3. Outputting instructions for Claude to process
29
- * 4. Returning the translated content
30
- *
31
- * In an automated context (hooks), this provides clear instructions.
32
- * In an interactive context, the translator skill can auto-activate.
33
- *
34
- * @param content - Content to translate
35
- * @param sourceLang - Source language
36
- * @param targetLang - Target language
37
- * @returns Translation result
38
- */
39
- export declare function invokeTranslatorSkill(content: string, sourceLang: SupportedLanguage, targetLang?: SupportedLanguage): Promise<TranslationResult>;
40
- /**
41
- * Translate a file using translator skill
42
- *
43
- * @param filePath - Path to file to translate
44
- * @param targetLang - Target language
45
- * @returns Translation result
46
- */
47
- export declare function translateFile(filePath: string, targetLang?: SupportedLanguage): Promise<TranslationResult & {
48
- filePath: string;
49
- }>;
50
- /**
51
- * Batch translate multiple files
52
- *
53
- * @param filePaths - Array of file paths
54
- * @param targetLang - Target language
55
- * @returns Array of translation results
56
- */
57
- export declare function batchTranslateFiles(filePaths: string[], targetLang?: SupportedLanguage): Promise<Array<TranslationResult & {
58
- filePath: string;
59
- }>>;
60
- //# sourceMappingURL=invoke-translator-skill.d.ts.map
@@ -1,155 +0,0 @@
1
- import fs from "fs-extra";
2
- import {
3
- detectLanguage,
4
- prepareTranslation,
5
- postProcessTranslation,
6
- getLanguageName
7
- } from "../../../../dist/src/utils/translation.js";
8
- async function invokeTranslatorSkill(content, sourceLang, targetLang = "en") {
9
- try {
10
- const prepared = prepareTranslation(content, sourceLang, targetLang);
11
- const result = {
12
- success: true,
13
- sourceLanguage: sourceLang,
14
- targetLanguage: targetLang,
15
- originalContent: content,
16
- translatedContent: await performTranslation(prepared.prompt, prepared.preserved)
17
- };
18
- return result;
19
- } catch (error) {
20
- const errorMessage = error instanceof Error ? error.message : String(error);
21
- return {
22
- success: false,
23
- sourceLanguage: sourceLang,
24
- targetLanguage: targetLang,
25
- originalContent: content,
26
- error: errorMessage
27
- };
28
- }
29
- }
30
- async function performTranslation(prompt, preserved) {
31
- const contentMatch = prompt.match(/SOURCE DOCUMENT[^\n]*:\n---\n([\s\S]*?)\n---/);
32
- const contentToTranslate = contentMatch ? contentMatch[1] : "";
33
- const apiKey = process.env.ANTHROPIC_API_KEY;
34
- if (apiKey) {
35
- console.log(`
36
- \u{1F916} Translating via Anthropic API (Haiku model)...`);
37
- try {
38
- const Anthropic = await import("@anthropic-ai/sdk").then((m) => m.default);
39
- const anthropic = new Anthropic({
40
- apiKey
41
- });
42
- const message = await anthropic.messages.create({
43
- model: "claude-3-haiku-20240307",
44
- max_tokens: 8e3,
45
- messages: [
46
- {
47
- role: "user",
48
- content: prompt
49
- }
50
- ]
51
- });
52
- const translatedContent = message.content[0].type === "text" ? message.content[0].text : contentToTranslate;
53
- console.log(`\u2705 Translation complete via API`);
54
- console.log(` Input tokens: ${message.usage.input_tokens}`);
55
- console.log(` Output tokens: ${message.usage.output_tokens}`);
56
- console.log(` Cost: ~$${((message.usage.input_tokens * 0.25 + message.usage.output_tokens * 1.25) / 1e6).toFixed(4)}
57
- `);
58
- return postProcessTranslation(translatedContent, preserved);
59
- } catch (error) {
60
- console.error(`
61
- \u274C API translation failed: ${error.message}`);
62
- console.error(` Falling back to manual translation instructions
63
- `);
64
- }
65
- }
66
- const isInteractive = process.env.CLAUDE_CODE_SESSION === "true";
67
- if (isInteractive) {
68
- console.log("\n" + "=".repeat(80));
69
- console.log("\u{1F310} TRANSLATION REQUEST (translator skill will auto-activate)");
70
- console.log("=".repeat(80));
71
- console.log(prompt);
72
- console.log("=".repeat(80));
73
- console.log("\u{1F4A1} Tip: Set ANTHROPIC_API_KEY for fully automatic translation\n");
74
- return postProcessTranslation(
75
- `<!-- \u26A0\uFE0F TRANSLATION REQUESTED - Awaiting translator skill activation -->
76
-
77
- ${contentToTranslate}`,
78
- preserved
79
- );
80
- } else {
81
- console.error("\n\u26A0\uFE0F AUTO-TRANSLATION REQUIRES ONE OF:");
82
- console.error(" Option A (Recommended): Set ANTHROPIC_API_KEY environment variable");
83
- console.error(" Option B: Run /specweave:translate <file-path>");
84
- console.error(" Option C: Manually translate the content\n");
85
- return postProcessTranslation(
86
- `<!-- \u26A0\uFE0F AUTO-TRANSLATION PENDING -->
87
- <!-- Set ANTHROPIC_API_KEY for automatic translation -->
88
- <!-- Or run: /specweave:translate to complete -->
89
- <!-- Original content below -->
90
-
91
- ${contentToTranslate}`,
92
- preserved
93
- );
94
- }
95
- }
96
- async function translateFile(filePath, targetLang = "en") {
97
- if (!await fs.pathExists(filePath)) {
98
- throw new Error(`File not found: ${filePath}`);
99
- }
100
- const content = await fs.readFile(filePath, "utf-8");
101
- const detection = detectLanguage(content);
102
- const sourceLang = detection.language;
103
- if (sourceLang === targetLang) {
104
- return {
105
- success: true,
106
- filePath,
107
- sourceLanguage: sourceLang,
108
- targetLanguage: targetLang,
109
- originalContent: content,
110
- translatedContent: content
111
- };
112
- }
113
- const result = await invokeTranslatorSkill(content, sourceLang, targetLang);
114
- if (result.success && result.translatedContent) {
115
- await fs.writeFile(filePath, result.translatedContent, "utf-8");
116
- console.log(`\u2705 Translated: ${filePath} (${getLanguageName(sourceLang)} \u2192 ${getLanguageName(targetLang)})`);
117
- }
118
- return {
119
- ...result,
120
- filePath
121
- };
122
- }
123
- async function batchTranslateFiles(filePaths, targetLang = "en") {
124
- const results = [];
125
- console.log(`
126
- \u{1F310} Batch translating ${filePaths.length} file(s) to ${getLanguageName(targetLang)}...
127
- `);
128
- for (const filePath of filePaths) {
129
- try {
130
- const result = await translateFile(filePath, targetLang);
131
- results.push(result);
132
- } catch (error) {
133
- const errorMessage = error instanceof Error ? error.message : String(error);
134
- console.error(`\u274C Failed to translate ${filePath}: ${errorMessage}`);
135
- results.push({
136
- success: false,
137
- filePath,
138
- sourceLanguage: "unknown",
139
- targetLanguage: targetLang,
140
- originalContent: "",
141
- error: errorMessage
142
- });
143
- }
144
- }
145
- const successful = results.filter((r) => r.success).length;
146
- console.log(`
147
- \u{1F4CA} Batch translation complete: ${successful}/${filePaths.length} files translated
148
- `);
149
- return results;
150
- }
151
- export {
152
- batchTranslateFiles,
153
- invokeTranslatorSkill,
154
- translateFile
155
- };