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.
- 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/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/package.json +1 -1
- package/plugins/specweave/commands/specweave-archive.md +51 -15
- package/plugins/specweave/hooks/post-edit-spec.sh +62 -9
- package/plugins/specweave/hooks/post-write-spec.sh +62 -8
- package/plugins/specweave/lib/hooks/auto-transition.js.bak +50 -0
- 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.bak +155 -0
- 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.bak +339 -0
- 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.bak +289 -0
- 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.bak +51 -0
- 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-ado/lib/ado-multi-project-sync.js +1 -0
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
- 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
|
-
#
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
#
|
|
33
|
-
if
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
#
|
|
26
|
-
|
|
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
|
-
#
|
|
29
|
-
if
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
+
}
|
|
File without changes
|
|
@@ -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
|
+
};
|