specweave 0.23.0 → 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.
Files changed (71) hide show
  1. package/dist/src/cli/helpers/issue-tracker/index.d.ts.map +1 -1
  2. package/dist/src/cli/helpers/issue-tracker/index.js +5 -17
  3. package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
  4. package/dist/src/core/repo-structure/repo-id-generator.d.ts +20 -0
  5. package/dist/src/core/repo-structure/repo-id-generator.d.ts.map +1 -1
  6. package/dist/src/core/repo-structure/repo-id-generator.js +44 -0
  7. package/dist/src/core/repo-structure/repo-id-generator.js.map +1 -1
  8. package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
  9. package/dist/src/core/repo-structure/repo-structure-manager.js +5 -2
  10. package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
  11. package/package.json +1 -1
  12. package/plugins/specweave/commands/specweave-archive.md +51 -15
  13. package/plugins/specweave/hooks/post-edit-spec.sh +62 -9
  14. package/plugins/specweave/hooks/post-write-spec.sh +62 -8
  15. package/plugins/specweave/lib/hooks/auto-transition.js.bak +50 -0
  16. package/plugins/specweave/lib/hooks/auto-transition.ts.bak +84 -0
  17. package/plugins/specweave/lib/hooks/git-diff-analyzer.d.js.bak +0 -0
  18. package/plugins/specweave/lib/hooks/git-diff-analyzer.d.ts.bak +89 -0
  19. package/plugins/specweave/lib/hooks/git-diff-analyzer.js.bak +142 -0
  20. package/plugins/specweave/lib/hooks/git-diff-analyzer.ts.bak +269 -0
  21. package/plugins/specweave/lib/hooks/invoke-translator-skill.d.js.bak +0 -0
  22. package/plugins/specweave/lib/hooks/invoke-translator-skill.d.ts.bak +60 -0
  23. package/plugins/specweave/lib/hooks/invoke-translator-skill.js.bak +155 -0
  24. package/plugins/specweave/lib/hooks/invoke-translator-skill.ts.bak +264 -0
  25. package/plugins/specweave/lib/hooks/prepare-reflection-context.d.js.bak +0 -0
  26. package/plugins/specweave/lib/hooks/prepare-reflection-context.d.ts.bak +42 -0
  27. package/plugins/specweave/lib/hooks/prepare-reflection-context.js.bak +110 -0
  28. package/plugins/specweave/lib/hooks/prepare-reflection-context.ts.bak +178 -0
  29. package/plugins/specweave/lib/hooks/reflection-config-loader.d.js.bak +0 -0
  30. package/plugins/specweave/lib/hooks/reflection-config-loader.d.ts.bak +45 -0
  31. package/plugins/specweave/lib/hooks/reflection-config-loader.js.bak +92 -0
  32. package/plugins/specweave/lib/hooks/reflection-config-loader.ts.bak +156 -0
  33. package/plugins/specweave/lib/hooks/reflection-parser.d.js.bak +0 -0
  34. package/plugins/specweave/lib/hooks/reflection-parser.d.ts.bak +33 -0
  35. package/plugins/specweave/lib/hooks/reflection-parser.js.bak +301 -0
  36. package/plugins/specweave/lib/hooks/reflection-parser.ts.bak +484 -0
  37. package/plugins/specweave/lib/hooks/reflection-prompt-builder.d.js.bak +0 -0
  38. package/plugins/specweave/lib/hooks/reflection-prompt-builder.d.ts.bak +56 -0
  39. package/plugins/specweave/lib/hooks/reflection-prompt-builder.js.bak +182 -0
  40. package/plugins/specweave/lib/hooks/reflection-prompt-builder.ts.bak +306 -0
  41. package/plugins/specweave/lib/hooks/reflection-storage.d.js.bak +0 -0
  42. package/plugins/specweave/lib/hooks/reflection-storage.d.ts.bak +64 -0
  43. package/plugins/specweave/lib/hooks/reflection-storage.js.bak +231 -0
  44. package/plugins/specweave/lib/hooks/reflection-storage.ts.bak +369 -0
  45. package/plugins/specweave/lib/hooks/run-self-reflection.d.js.bak +0 -0
  46. package/plugins/specweave/lib/hooks/run-self-reflection.d.ts.bak +43 -0
  47. package/plugins/specweave/lib/hooks/run-self-reflection.js.bak +132 -0
  48. package/plugins/specweave/lib/hooks/run-self-reflection.ts.bak +258 -0
  49. package/plugins/specweave/lib/hooks/sync-cache.js.bak +294 -0
  50. package/plugins/specweave/lib/hooks/sync-living-docs.d.js.bak +1 -0
  51. package/plugins/specweave/lib/hooks/sync-living-docs.d.ts.bak +27 -0
  52. package/plugins/specweave/lib/hooks/sync-living-docs.js.bak +339 -0
  53. package/plugins/specweave/lib/hooks/sync-us-tasks.js.bak +476 -0
  54. package/plugins/specweave/lib/hooks/translate-file.d.js.bak +0 -0
  55. package/plugins/specweave/lib/hooks/translate-file.d.ts.bak +59 -0
  56. package/plugins/specweave/lib/hooks/translate-file.js.bak +289 -0
  57. package/plugins/specweave/lib/hooks/translate-file.ts.bak +428 -0
  58. package/plugins/specweave/lib/hooks/translate-living-docs.d.js.bak +0 -0
  59. package/plugins/specweave/lib/hooks/translate-living-docs.d.ts.bak +13 -0
  60. package/plugins/specweave/lib/hooks/translate-living-docs.js.bak +119 -0
  61. package/plugins/specweave/lib/hooks/translate-living-docs.ts.bak +224 -0
  62. package/plugins/specweave/lib/hooks/update-ac-status.js.bak +51 -0
  63. package/plugins/specweave/lib/hooks/update-ac-status.ts.bak +103 -0
  64. package/plugins/specweave/lib/hooks/update-tasks-md.d.js.bak +1 -0
  65. package/plugins/specweave/lib/hooks/update-tasks-md.d.ts.bak +29 -0
  66. package/plugins/specweave/lib/hooks/update-tasks-md.js.bak +296 -0
  67. package/plugins/specweave/lib/hooks/update-tasks-md.ts.bak +489 -0
  68. package/plugins/specweave-ado/lib/ado-multi-project-sync.js +1 -0
  69. package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
  70. package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
  71. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +6225 -0
@@ -7,6 +7,11 @@
7
7
  #
8
8
  # This ensures status line stays in sync when ACs are marked complete via Edit tool
9
9
  # (not just TodoWrite, which only tracks internal todo lists)
10
+ #
11
+ # CRITICAL FIX (v0.24.1): Enhanced file detection to handle increment completion
12
+ # - Detects edits via TOOL_USE_CONTENT, TOOL_RESULT, and argument parsing
13
+ # - Always updates status line for ANY spec.md/tasks.md edit in increments folder
14
+ # - Fixes bug where status line wasn't updating on increment close
10
15
 
11
16
  set -e
12
17
 
@@ -24,17 +29,65 @@ find_project_root() {
24
29
  }
25
30
 
26
31
  PROJECT_ROOT=$(find_project_root)
32
+ LOGS_DIR="$PROJECT_ROOT/.specweave/logs"
33
+ DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
34
+
35
+ # Ensure logs directory exists
36
+ mkdir -p "$LOGS_DIR" 2>/dev/null || true
37
+
38
+ # Extract edited file from multiple sources (Claude Code provides this in various ways)
39
+ EDITED_FILE=""
40
+
41
+ # Method 1: TOOL_USE_CONTENT environment variable (primary)
42
+ if [[ -n "${TOOL_USE_CONTENT:-}" ]]; then
43
+ EDITED_FILE="$TOOL_USE_CONTENT"
44
+ fi
45
+
46
+ # Method 2: TOOL_RESULT environment variable (fallback)
47
+ if [[ -z "$EDITED_FILE" ]] && [[ -n "${TOOL_RESULT:-}" ]]; then
48
+ # Extract file_path from tool result JSON
49
+ EDITED_FILE=$(echo "$TOOL_RESULT" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/' || echo "")
50
+ fi
51
+
52
+ # Method 3: Parse tool use arguments (last resort)
53
+ if [[ -z "$EDITED_FILE" ]] && [[ -n "${TOOL_USE_ARGS:-}" ]]; then
54
+ # Extract file_path from tool arguments
55
+ EDITED_FILE=$(echo "$TOOL_USE_ARGS" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/' || echo "")
56
+ fi
57
+
58
+ # Log detection attempt
59
+ echo "[$(date)] post-edit-spec: Detected file: ${EDITED_FILE:-<none>}" >> "$DEBUG_LOG" 2>/dev/null || true
60
+
61
+ # Check if we detected a spec.md or tasks.md edit in increments folder
62
+ SHOULD_UPDATE=false
63
+
64
+ if [[ -n "$EDITED_FILE" ]]; then
65
+ # Check if the file is spec.md or tasks.md
66
+ if [[ "$EDITED_FILE" == *"/spec.md" ]] || [[ "$EDITED_FILE" == *"/tasks.md" ]]; then
67
+ # Check if it's in an increment folder
68
+ if [[ "$EDITED_FILE" == *"/.specweave/increments/"* ]]; then
69
+ SHOULD_UPDATE=true
70
+ echo "[$(date)] post-edit-spec: Increment file edited - will update status line" >> "$DEBUG_LOG" 2>/dev/null || true
71
+ fi
72
+ fi
73
+ fi
74
+
75
+ # If we couldn't detect the file via environment variables, always update status line
76
+ # This ensures we don't miss updates during increment closure
77
+ if [[ -z "$EDITED_FILE" ]]; then
78
+ echo "[$(date)] post-edit-spec: No file detected - updating status line as safety measure" >> "$DEBUG_LOG" 2>/dev/null || true
79
+ SHOULD_UPDATE=true
80
+ fi
27
81
 
28
- # Get the file that was edited from TOOL_USE_CONTENT environment variable
29
- # Claude Code provides this in the hook context
30
- EDITED_FILE="${TOOL_USE_CONTENT:-}"
82
+ # Update status line if needed
83
+ if [[ "$SHOULD_UPDATE" == "true" ]]; then
84
+ echo "[$(date)] post-edit-spec: Running update-status-line.sh" >> "$DEBUG_LOG" 2>/dev/null || true
31
85
 
32
- # Only update status line if spec.md or tasks.md was edited
33
- if [[ "$EDITED_FILE" == *"/spec.md"* ]] || [[ "$EDITED_FILE" == *"/tasks.md"* ]]; then
34
- # Check if the edit is in an increment folder
35
- if [[ "$EDITED_FILE" == *"/.specweave/increments/"* ]]; then
36
- # Run status line update
37
- "$PROJECT_ROOT/plugins/specweave/hooks/lib/update-status-line.sh" &>/dev/null || true
86
+ # Run status line update (capture errors for debugging)
87
+ if "$PROJECT_ROOT/plugins/specweave/hooks/lib/update-status-line.sh" 2>&1 | tee -a "$DEBUG_LOG" >/dev/null; then
88
+ echo "[$(date)] post-edit-spec: Status line updated successfully" >> "$DEBUG_LOG" 2>/dev/null || true
89
+ else
90
+ echo "[$(date)] post-edit-spec: Warning - status line update failed (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true
38
91
  fi
39
92
  fi
40
93
 
@@ -4,6 +4,11 @@
4
4
  #
5
5
  # Triggers: After Write tool creates/replaces spec.md or tasks.md
6
6
  # Action: Updates status line cache to reflect latest AC/task progress
7
+ #
8
+ # CRITICAL FIX (v0.24.1): Enhanced file detection to handle increment completion
9
+ # - Detects writes via TOOL_USE_CONTENT, TOOL_RESULT, and argument parsing
10
+ # - Always updates status line for ANY spec.md/tasks.md write in increments folder
11
+ # - Matches post-edit-spec.sh robustness improvements
7
12
 
8
13
  set -e
9
14
 
@@ -21,16 +26,65 @@ find_project_root() {
21
26
  }
22
27
 
23
28
  PROJECT_ROOT=$(find_project_root)
29
+ LOGS_DIR="$PROJECT_ROOT/.specweave/logs"
30
+ DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
31
+
32
+ # Ensure logs directory exists
33
+ mkdir -p "$LOGS_DIR" 2>/dev/null || true
34
+
35
+ # Extract written file from multiple sources (Claude Code provides this in various ways)
36
+ WRITTEN_FILE=""
37
+
38
+ # Method 1: TOOL_USE_CONTENT environment variable (primary)
39
+ if [[ -n "${TOOL_USE_CONTENT:-}" ]]; then
40
+ WRITTEN_FILE="$TOOL_USE_CONTENT"
41
+ fi
42
+
43
+ # Method 2: TOOL_RESULT environment variable (fallback)
44
+ if [[ -z "$WRITTEN_FILE" ]] && [[ -n "${TOOL_RESULT:-}" ]]; then
45
+ # Extract file_path from tool result JSON
46
+ WRITTEN_FILE=$(echo "$TOOL_RESULT" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/' || echo "")
47
+ fi
48
+
49
+ # Method 3: Parse tool use arguments (last resort)
50
+ if [[ -z "$WRITTEN_FILE" ]] && [[ -n "${TOOL_USE_ARGS:-}" ]]; then
51
+ # Extract file_path from tool arguments
52
+ WRITTEN_FILE=$(echo "$TOOL_USE_ARGS" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/' || echo "")
53
+ fi
54
+
55
+ # Log detection attempt
56
+ echo "[$(date)] post-write-spec: Detected file: ${WRITTEN_FILE:-<none>}" >> "$DEBUG_LOG" 2>/dev/null || true
57
+
58
+ # Check if we detected a spec.md or tasks.md write in increments folder
59
+ SHOULD_UPDATE=false
60
+
61
+ if [[ -n "$WRITTEN_FILE" ]]; then
62
+ # Check if the file is spec.md or tasks.md
63
+ if [[ "$WRITTEN_FILE" == *"/spec.md" ]] || [[ "$WRITTEN_FILE" == *"/tasks.md" ]]; then
64
+ # Check if it's in an increment folder
65
+ if [[ "$WRITTEN_FILE" == *"/.specweave/increments/"* ]]; then
66
+ SHOULD_UPDATE=true
67
+ echo "[$(date)] post-write-spec: Increment file written - will update status line" >> "$DEBUG_LOG" 2>/dev/null || true
68
+ fi
69
+ fi
70
+ fi
71
+
72
+ # If we couldn't detect the file via environment variables, always update status line
73
+ # This ensures we don't miss updates during increment closure
74
+ if [[ -z "$WRITTEN_FILE" ]]; then
75
+ echo "[$(date)] post-write-spec: No file detected - updating status line as safety measure" >> "$DEBUG_LOG" 2>/dev/null || true
76
+ SHOULD_UPDATE=true
77
+ fi
24
78
 
25
- # Get the file that was written from TOOL_USE_CONTENT environment variable
26
- WRITTEN_FILE="${TOOL_USE_CONTENT:-}"
79
+ # Update status line if needed
80
+ if [[ "$SHOULD_UPDATE" == "true" ]]; then
81
+ echo "[$(date)] post-write-spec: Running update-status-line.sh" >> "$DEBUG_LOG" 2>/dev/null || true
27
82
 
28
- # Only update status line if spec.md or tasks.md was written
29
- if [[ "$WRITTEN_FILE" == *"/spec.md"* ]] || [[ "$WRITTEN_FILE" == *"/tasks.md"* ]]; then
30
- # Check if the write is in an increment folder
31
- if [[ "$WRITTEN_FILE" == *"/.specweave/increments/"* ]]; then
32
- # Run status line update
33
- "$PROJECT_ROOT/plugins/specweave/hooks/lib/update-status-line.sh" &>/dev/null || true
83
+ # Run status line update (capture errors for debugging)
84
+ if "$PROJECT_ROOT/plugins/specweave/hooks/lib/update-status-line.sh" 2>&1 | tee -a "$DEBUG_LOG" >/dev/null; then
85
+ echo "[$(date)] post-write-spec: Status line updated successfully" >> "$DEBUG_LOG" 2>/dev/null || true
86
+ else
87
+ echo "[$(date)] post-write-spec: Warning - status line update failed (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true
34
88
  fi
35
89
  fi
36
90
 
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+ import { AutoTransitionManager } from "../../../../dist/src/core/increment/auto-transition-manager.js";
3
+ async function main() {
4
+ const event = process.argv[2];
5
+ const incrementId = process.argv[3];
6
+ const force = process.argv.includes("--force");
7
+ if (!event || !incrementId) {
8
+ console.error("Usage: auto-transition.ts <event> <increment-id> [--force]");
9
+ console.error("Events: spec-created, tasks-created, task-started, auto-correct");
10
+ console.error("Example: node auto-transition.ts spec-created 0039-ultra-smart-next-command");
11
+ process.exit(1);
12
+ }
13
+ const projectRoot = process.cwd();
14
+ const manager = new AutoTransitionManager(projectRoot);
15
+ let result;
16
+ try {
17
+ switch (event) {
18
+ case "spec-created":
19
+ result = await manager.handleSpecCreated(incrementId);
20
+ break;
21
+ case "tasks-created":
22
+ result = await manager.handleTasksCreated(incrementId);
23
+ break;
24
+ case "task-started":
25
+ result = await manager.handleTaskStarted(incrementId);
26
+ break;
27
+ case "auto-correct":
28
+ result = await manager.autoCorrect(incrementId, force);
29
+ break;
30
+ default:
31
+ console.error(`\u274C Unknown event: ${event}`);
32
+ console.error("Valid events: spec-created, tasks-created, task-started, auto-correct");
33
+ process.exit(1);
34
+ }
35
+ if (result.transitioned) {
36
+ console.log(`\u2705 Auto-transition: ${result.from} \u2192 ${result.to}`);
37
+ console.log(` Reason: ${result.reason}`);
38
+ } else {
39
+ console.log(`\u2139\uFE0F No transition: ${result.reason}`);
40
+ }
41
+ process.exit(0);
42
+ } catch (error) {
43
+ console.error("\u274C Auto-transition error:", error);
44
+ process.exit(1);
45
+ }
46
+ }
47
+ const isMainModule = import.meta.url === `file://${process.argv[1]}`;
48
+ if (isMainModule) {
49
+ main();
50
+ }
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Auto-Transition Hook Handler
5
+ *
6
+ * CLI wrapper for AutoTransitionManager
7
+ * Called by bash hooks to trigger status transitions
8
+ *
9
+ * Events:
10
+ * - spec-created: When spec.md is created (BACKLOG → PLANNING)
11
+ * - tasks-created: When tasks.md is created (PLANNING/BACKLOG → ACTIVE)
12
+ * - task-started: When first task is started (PLANNING → ACTIVE)
13
+ * - auto-correct: Fix status based on artifacts
14
+ *
15
+ * Usage:
16
+ * node auto-transition.ts spec-created 0039-ultra-smart-next-command
17
+ * node auto-transition.ts tasks-created 0039-ultra-smart-next-command
18
+ * node auto-transition.ts task-started 0039-ultra-smart-next-command
19
+ * node auto-transition.ts auto-correct 0039-ultra-smart-next-command
20
+ */
21
+
22
+ import { AutoTransitionManager } from '../../../../dist/src/core/increment/auto-transition-manager.js';
23
+
24
+ async function main() {
25
+ const event = process.argv[2];
26
+ const incrementId = process.argv[3];
27
+ const force = process.argv.includes('--force');
28
+
29
+ if (!event || !incrementId) {
30
+ console.error('Usage: auto-transition.ts <event> <increment-id> [--force]');
31
+ console.error('Events: spec-created, tasks-created, task-started, auto-correct');
32
+ console.error('Example: node auto-transition.ts spec-created 0039-ultra-smart-next-command');
33
+ process.exit(1);
34
+ }
35
+
36
+ const projectRoot = process.cwd();
37
+ const manager = new AutoTransitionManager(projectRoot);
38
+
39
+ let result;
40
+
41
+ try {
42
+ switch (event) {
43
+ case 'spec-created':
44
+ result = await manager.handleSpecCreated(incrementId);
45
+ break;
46
+
47
+ case 'tasks-created':
48
+ result = await manager.handleTasksCreated(incrementId);
49
+ break;
50
+
51
+ case 'task-started':
52
+ result = await manager.handleTaskStarted(incrementId);
53
+ break;
54
+
55
+ case 'auto-correct':
56
+ result = await manager.autoCorrect(incrementId, force);
57
+ break;
58
+
59
+ default:
60
+ console.error(`❌ Unknown event: ${event}`);
61
+ console.error('Valid events: spec-created, tasks-created, task-started, auto-correct');
62
+ process.exit(1);
63
+ }
64
+
65
+ // Display result
66
+ if (result.transitioned) {
67
+ console.log(`✅ Auto-transition: ${result.from} → ${result.to}`);
68
+ console.log(` Reason: ${result.reason}`);
69
+ } else {
70
+ console.log(`ℹ️ No transition: ${result.reason}`);
71
+ }
72
+
73
+ process.exit(0);
74
+ } catch (error) {
75
+ console.error('❌ Auto-transition error:', error);
76
+ process.exit(1);
77
+ }
78
+ }
79
+
80
+ // Run if executed directly
81
+ const isMainModule = import.meta.url === `file://${process.argv[1]}`;
82
+ if (isMainModule) {
83
+ main();
84
+ }
@@ -0,0 +1,89 @@
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
+ import { GitDiffInfo } from './types/reflection-types';
10
+ /**
11
+ * Check if directory is a git repository
12
+ * @param dir Directory to check (defaults to cwd)
13
+ * @returns True if directory is in a git repository
14
+ */
15
+ export declare function isGitRepository(dir?: string): boolean;
16
+ /**
17
+ * Get list of modified files in the working directory
18
+ * Includes both staged and unstaged changes
19
+ *
20
+ * @param cwd Working directory (optional, defaults to process.cwd())
21
+ * @returns Array of file paths relative to git root
22
+ */
23
+ export declare function getModifiedFilesList(cwd?: string): string[];
24
+ /**
25
+ * Parse git diff numstat output to get line counts
26
+ * Format: <added>\t<removed>\t<filename>
27
+ *
28
+ * @param numstatOutput Output from git diff --numstat
29
+ * @returns Map of filename to {added, removed} counts
30
+ */
31
+ export declare function parseNumstat(numstatOutput: string): Map<string, {
32
+ added: number;
33
+ removed: number;
34
+ }>;
35
+ /**
36
+ * Get diff content for a specific file
37
+ * @param file File path relative to git root
38
+ * @param cwd Working directory (optional)
39
+ * @returns Diff content as string
40
+ */
41
+ export declare function getFileDiff(file: string, cwd?: string): string;
42
+ /**
43
+ * Get current file content
44
+ * @param file File path (can be absolute or relative to cwd)
45
+ * @param cwd Working directory (optional)
46
+ * @returns File content as string, or empty string if file doesn't exist
47
+ */
48
+ export declare function getFileContent(file: string, cwd?: string): string;
49
+ /**
50
+ * Get modified files with diff information
51
+ * Main function for reflection analysis
52
+ *
53
+ * @param cwd Working directory (optional, defaults to process.cwd())
54
+ * @param maxFiles Maximum number of files to return (optional, defaults to 100)
55
+ * @returns Array of GitDiffInfo objects with file changes
56
+ */
57
+ export declare function getModifiedFiles(cwd?: string, maxFiles?: number): GitDiffInfo[];
58
+ /**
59
+ * Get summary statistics for modified files
60
+ * Useful for reflection metadata
61
+ *
62
+ * @param modifiedFiles Array of GitDiffInfo objects
63
+ * @returns Summary with file count, total lines added/removed
64
+ */
65
+ export declare function getModifiedFilesSummary(modifiedFiles: GitDiffInfo[]): {
66
+ count: number;
67
+ linesAdded: number;
68
+ linesRemoved: number;
69
+ totalChanges: number;
70
+ };
71
+ /**
72
+ * Filter files by extension
73
+ * Useful for focusing reflection on specific file types
74
+ *
75
+ * @param modifiedFiles Array of GitDiffInfo objects
76
+ * @param extensions Array of file extensions (e.g., ['.ts', '.js'])
77
+ * @returns Filtered array of GitDiffInfo objects
78
+ */
79
+ export declare function filterFilesByExtension(modifiedFiles: GitDiffInfo[], extensions: string[]): GitDiffInfo[];
80
+ /**
81
+ * Exclude files matching patterns
82
+ * Useful for excluding generated files, test files, etc.
83
+ *
84
+ * @param modifiedFiles Array of GitDiffInfo objects
85
+ * @param patterns Array of glob patterns to exclude
86
+ * @returns Filtered array of GitDiffInfo objects
87
+ */
88
+ export declare function excludeFilesByPattern(modifiedFiles: GitDiffInfo[], patterns: string[]): GitDiffInfo[];
89
+ //# sourceMappingURL=git-diff-analyzer.d.ts.map
@@ -0,0 +1,142 @@
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
+ };