@pageai/ralph-loop 1.0.0
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/.agent/PROMPT.md +58 -0
- package/.agent/STEERING.md +3 -0
- package/.agent/logs/LOG.md +13 -0
- package/.agent/prd/.gitkeep +0 -0
- package/.agent/screenshots/.gitkeep +0 -0
- package/.agent/skills/component-refactoring/SKILL.md +247 -0
- package/.agent/skills/component-refactoring/references/complexity-patterns.md +485 -0
- package/.agent/skills/component-refactoring/references/component-splitting.md +419 -0
- package/.agent/skills/component-refactoring/references/hook-extraction.md +317 -0
- package/.agent/skills/e2e-tester/SKILL.md +595 -0
- package/.agent/skills/frontend-code-review/SKILL.md +73 -0
- package/.agent/skills/frontend-code-review/references/code-quality.md +28 -0
- package/.agent/skills/frontend-code-review/references/performance.md +36 -0
- package/.agent/skills/frontend-testing/SKILL.md +316 -0
- package/.agent/skills/frontend-testing/assets/component-test.template.tsx +293 -0
- package/.agent/skills/frontend-testing/assets/hook-test.template.ts +207 -0
- package/.agent/skills/frontend-testing/assets/utility-test.template.ts +154 -0
- package/.agent/skills/frontend-testing/references/async-testing.md +345 -0
- package/.agent/skills/frontend-testing/references/checklist.md +188 -0
- package/.agent/skills/frontend-testing/references/common-patterns.md +449 -0
- package/.agent/skills/frontend-testing/references/mocking.md +289 -0
- package/.agent/skills/frontend-testing/references/workflow.md +265 -0
- package/.agent/skills/prd-creator/JSON.md +613 -0
- package/.agent/skills/prd-creator/PRD.md +196 -0
- package/.agent/skills/prd-creator/SKILL.md +143 -0
- package/.agent/skills/skill-creator/SKILL.md +355 -0
- package/.agent/skills/skill-creator/references/output-patterns.md +86 -0
- package/.agent/skills/skill-creator/references/workflows.md +28 -0
- package/.agent/skills/skill-creator/scripts/init_skill.py +300 -0
- package/.agent/skills/skill-creator/scripts/package_skill.py +110 -0
- package/.agent/skills/vercel-react-best-practices/AGENTS.md +2249 -0
- package/.agent/skills/vercel-react-best-practices/SKILL.md +125 -0
- package/.agent/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/.agent/skills/vercel-react-best-practices/rules/advanced-use-latest.md +49 -0
- package/.agent/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
- package/.agent/skills/vercel-react-best-practices/rules/async-defer-await.md +80 -0
- package/.agent/skills/vercel-react-best-practices/rules/async-dependencies.md +36 -0
- package/.agent/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
- package/.agent/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/.agent/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/.agent/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
- package/.agent/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/.agent/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/.agent/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
- package/.agent/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
- package/.agent/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +82 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
- package/.agent/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/.agent/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
- package/.agent/skills/vercel-react-best-practices/rules/server-cache-react.md +26 -0
- package/.agent/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +79 -0
- package/.agent/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
- package/.agent/skills/vitest-best-practices/AGENTS.md +84 -0
- package/.agent/skills/vitest-best-practices/SKILL.md +130 -0
- package/.agent/skills/vitest-best-practices/references/aaa-pattern.md +260 -0
- package/.agent/skills/vitest-best-practices/references/assertions.md +393 -0
- package/.agent/skills/vitest-best-practices/references/async-testing.md +454 -0
- package/.agent/skills/vitest-best-practices/references/error-handling.md +382 -0
- package/.agent/skills/vitest-best-practices/references/organization.md +212 -0
- package/.agent/skills/vitest-best-practices/references/parameterized-tests.md +297 -0
- package/.agent/skills/vitest-best-practices/references/performance.md +528 -0
- package/.agent/skills/vitest-best-practices/references/snapshot-testing.md +483 -0
- package/.agent/skills/vitest-best-practices/references/test-doubles.md +499 -0
- package/.agent/skills/vitest-best-practices/references/vitest-features.md +529 -0
- package/.agent/skills/web-design-guidelines/SKILL.md +39 -0
- package/.agent/tasks/.gitkeep +0 -0
- package/.agent/tasks.json +1 -0
- package/.claude/agents/code-reviewer.md +172 -0
- package/.claude/commands/aw.md +50 -0
- package/.claude/hooks/play-sound.js +87 -0
- package/.claude/hooks/pre-tool-use.js +40 -0
- package/.claude/settings.json +54 -0
- package/.claude/settings.local.json +13 -0
- package/.mcp.json +31 -0
- package/AGENTS.md +44 -0
- package/CLAUDE.md +1 -0
- package/README.md +236 -0
- package/bin/cli.js +156 -0
- package/bin/lib/copy.js +149 -0
- package/bin/lib/display.js +137 -0
- package/package.json +65 -0
- package/ralph.sh +333 -0
- package/scripts/lib/args.sh +44 -0
- package/scripts/lib/cleanup.sh +53 -0
- package/scripts/lib/constants.sh +25 -0
- package/scripts/lib/display.sh +196 -0
- package/scripts/lib/logging.sh +30 -0
- package/scripts/lib/notify.sh +41 -0
- package/scripts/lib/output.sh +147 -0
- package/scripts/lib/preflight.sh +57 -0
- package/scripts/lib/preview.sh +77 -0
- package/scripts/lib/promise.sh +76 -0
- package/scripts/lib/spinner.sh +85 -0
- package/scripts/lib/terminal.sh +57 -0
- package/scripts/lib/timing.sh +223 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Spinner module for ralph.sh
|
|
3
|
+
# Animated spinner display with step tracking
|
|
4
|
+
# Dependencies: constants.sh, timing.sh, terminal.sh
|
|
5
|
+
|
|
6
|
+
# Spinner characters
|
|
7
|
+
SPINNER='โ โ โ นโ ธโ ผโ ดโ ฆโ งโ โ '
|
|
8
|
+
SPINNER_PID=""
|
|
9
|
+
CURRENT_STEP="Thinking"
|
|
10
|
+
|
|
11
|
+
# Spinner function - runs in background, reads step from STEP_FILE
|
|
12
|
+
# Usage: start_spinner; do_work; stop_spinner
|
|
13
|
+
start_spinner() {
|
|
14
|
+
echo "Thinking" > "$STEP_FILE"
|
|
15
|
+
echo "" > "$PREVIEW_LINE_FILE"
|
|
16
|
+
|
|
17
|
+
(
|
|
18
|
+
# Spinner chars as array for proper unicode handling
|
|
19
|
+
local -a SPIN_CHARS=(โ โ โ น โ ธ โ ผ โ ด โ ฆ โ ง โ โ )
|
|
20
|
+
local i=0
|
|
21
|
+
local spin_len=${#SPIN_CHARS[@]}
|
|
22
|
+
local term_width=$(tput cols 2>/dev/null || echo 80)
|
|
23
|
+
local preview_max=$((term_width - 6)) # Leave room for " > "
|
|
24
|
+
while true; do
|
|
25
|
+
local step=$(cat "$STEP_FILE" 2>/dev/null || echo "Thinking")
|
|
26
|
+
local preview=$(cat "$PREVIEW_LINE_FILE" 2>/dev/null || echo "")
|
|
27
|
+
local char="${SPIN_CHARS[$i]}"
|
|
28
|
+
# Truncate preview if needed
|
|
29
|
+
if [ ${#preview} -gt $preview_max ]; then
|
|
30
|
+
preview="${preview:0:$((preview_max - 3))}..."
|
|
31
|
+
fi
|
|
32
|
+
# Line 1: spinner + step, Line 2: dimmed preview
|
|
33
|
+
printf "\r\033[K ${C}%s${R} %s" "$char" "$step"
|
|
34
|
+
if [ -n "$preview" ]; then
|
|
35
|
+
printf "\n\033[K ${D}โธ %s${R}\033[A" "$preview"
|
|
36
|
+
fi
|
|
37
|
+
i=$(( (i + 1) % spin_len ))
|
|
38
|
+
sleep 0.1
|
|
39
|
+
done
|
|
40
|
+
) &
|
|
41
|
+
SPINNER_PID=$!
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# Stop the spinner
|
|
45
|
+
stop_spinner() {
|
|
46
|
+
if [ -n "$SPINNER_PID" ] && kill -0 "$SPINNER_PID" 2>/dev/null; then
|
|
47
|
+
kill "$SPINNER_PID" 2>/dev/null
|
|
48
|
+
wait "$SPINNER_PID" 2>/dev/null || true
|
|
49
|
+
# Clear both lines (spinner and preview)
|
|
50
|
+
printf "\r\033[K\n\033[K\033[A\r"
|
|
51
|
+
fi
|
|
52
|
+
SPINNER_PID=""
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# Update spinner step based on output line and record step timing
|
|
56
|
+
update_spinner_step() {
|
|
57
|
+
local line="$1"
|
|
58
|
+
local detected=$(detect_step "$line")
|
|
59
|
+
if [ -n "$detected" ]; then
|
|
60
|
+
echo "$detected" > "$STEP_FILE"
|
|
61
|
+
|
|
62
|
+
# Clean step name (remove trailing spaces) for timing tracking
|
|
63
|
+
local clean_step=$(echo "$detected" | sed 's/ *$//')
|
|
64
|
+
|
|
65
|
+
# Record timing if step changed
|
|
66
|
+
if [ "$clean_step" != "$CURRENT_STEP_NAME" ]; then
|
|
67
|
+
record_step_time "$clean_step"
|
|
68
|
+
fi
|
|
69
|
+
fi
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# Update the preview line shown under the spinner
|
|
73
|
+
update_preview_line() {
|
|
74
|
+
local line="$1"
|
|
75
|
+
# Skip empty lines or lines that are just whitespace
|
|
76
|
+
[ -z "$line" ] && return
|
|
77
|
+
[[ "$line" =~ ^[[:space:]]*$ ]] && return
|
|
78
|
+
# Sanitize: replace newlines/tabs with spaces, collapse multiple spaces
|
|
79
|
+
# This prevents multi-line content from breaking cursor positioning
|
|
80
|
+
line=$(echo "$line" | tr '\n\t\r' ' ' | sed 's/ */ /g; s/^ *//; s/ *$//')
|
|
81
|
+
# Skip if sanitization resulted in empty string
|
|
82
|
+
[ -z "$line" ] && return
|
|
83
|
+
# Write to preview file (spinner reads this)
|
|
84
|
+
echo "$line" > "$PREVIEW_LINE_FILE"
|
|
85
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Terminal module for ralph.sh
|
|
3
|
+
# ANSI support detection and terminal width utilities
|
|
4
|
+
# Dependencies: constants.sh
|
|
5
|
+
|
|
6
|
+
# Check if terminal supports ANSI escape sequences
|
|
7
|
+
check_ansi_support() {
|
|
8
|
+
# Check if $TERM is set and not dumb
|
|
9
|
+
if [ -z "$TERM" ] || [ "$TERM" = "dumb" ]; then
|
|
10
|
+
ANSI_SUPPORTED=false
|
|
11
|
+
return
|
|
12
|
+
fi
|
|
13
|
+
# Check for known terminal types that don't support ANSI
|
|
14
|
+
case "$TERM" in
|
|
15
|
+
dumb|unknown|network)
|
|
16
|
+
ANSI_SUPPORTED=false
|
|
17
|
+
return
|
|
18
|
+
;;
|
|
19
|
+
esac
|
|
20
|
+
# Check if stdout is a terminal
|
|
21
|
+
if [ ! -t 1 ]; then
|
|
22
|
+
ANSI_SUPPORTED=false
|
|
23
|
+
return
|
|
24
|
+
fi
|
|
25
|
+
ANSI_SUPPORTED=true
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
# Get terminal width (default to 80 if unavailable)
|
|
29
|
+
get_terminal_width() {
|
|
30
|
+
if command -v tput &> /dev/null; then
|
|
31
|
+
local width=$(tput cols 2>/dev/null)
|
|
32
|
+
if [ -n "$width" ] && [ "$width" -gt 0 ]; then
|
|
33
|
+
echo "$width"
|
|
34
|
+
return
|
|
35
|
+
fi
|
|
36
|
+
fi
|
|
37
|
+
# Fallback to stty
|
|
38
|
+
if command -v stty &> /dev/null; then
|
|
39
|
+
local width=$(stty size 2>/dev/null | cut -d' ' -f2)
|
|
40
|
+
if [ -n "$width" ] && [ "$width" -gt 0 ]; then
|
|
41
|
+
echo "$width"
|
|
42
|
+
return
|
|
43
|
+
fi
|
|
44
|
+
fi
|
|
45
|
+
echo "80"
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# Truncate line to fit terminal width
|
|
49
|
+
truncate_line() {
|
|
50
|
+
local line="$1"
|
|
51
|
+
local max_width="$2"
|
|
52
|
+
if [ ${#line} -gt $max_width ]; then
|
|
53
|
+
echo "${line:0:$((max_width - 3))}..."
|
|
54
|
+
else
|
|
55
|
+
echo "$line"
|
|
56
|
+
fi
|
|
57
|
+
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Timing module for ralph.sh
|
|
3
|
+
# Step timing tracking and duration formatting
|
|
4
|
+
# Dependencies: constants.sh
|
|
5
|
+
#
|
|
6
|
+
# Steps: Thinking, Reading code, Implementing, Writing tests, Testing, Linting,
|
|
7
|
+
# Typechecking, Committing
|
|
8
|
+
|
|
9
|
+
# Step timing tracking (using indexed arrays for bash 3.x compatibility)
|
|
10
|
+
STEP_NAMES=("Thinking" "Reading code" "Implementing" "Writing tests" "Testing" "Linting" "Typechecking" "Committing")
|
|
11
|
+
ITERATION_STEP_VALUES=(0 0 0 0 0 0 0 0) # Step times for current iteration
|
|
12
|
+
SESSION_STEP_VALUES=(0 0 0 0 0 0 0 0) # Accumulated step times across all iterations
|
|
13
|
+
CURRENT_STEP_NAME="" # Name of current step being timed
|
|
14
|
+
CURRENT_STEP_START=0 # Timestamp when current step started
|
|
15
|
+
|
|
16
|
+
# Get step emoji by name (bash 3.x compatible)
|
|
17
|
+
get_step_emoji() {
|
|
18
|
+
case "$1" in
|
|
19
|
+
"Thinking") echo "๐ค" ;;
|
|
20
|
+
"Reading code") echo "๐" ;;
|
|
21
|
+
"Implementing") echo "โก" ;;
|
|
22
|
+
"Writing tests") echo "โ๏ธ" ;;
|
|
23
|
+
"Testing") echo "๐งช" ;;
|
|
24
|
+
"Linting") echo "๐งน" ;;
|
|
25
|
+
"Typechecking") echo "๐" ;;
|
|
26
|
+
"Committing") echo "๐ฆ" ;;
|
|
27
|
+
*) echo "" ;;
|
|
28
|
+
esac
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# Get step index by name (-1 if not found)
|
|
32
|
+
get_step_index() {
|
|
33
|
+
local name="$1"
|
|
34
|
+
for i in "${!STEP_NAMES[@]}"; do
|
|
35
|
+
if [ "${STEP_NAMES[$i]}" = "$name" ]; then
|
|
36
|
+
echo "$i"
|
|
37
|
+
return
|
|
38
|
+
fi
|
|
39
|
+
done
|
|
40
|
+
echo "-1"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# Format duration in seconds to MM:SS or HH:MM:SS
|
|
44
|
+
format_duration() {
|
|
45
|
+
local seconds=$1
|
|
46
|
+
local hours=$((seconds / 3600))
|
|
47
|
+
local mins=$(((seconds % 3600) / 60))
|
|
48
|
+
local secs=$((seconds % 60))
|
|
49
|
+
|
|
50
|
+
if [ $hours -gt 0 ]; then
|
|
51
|
+
printf "%02d:%02d:%02d" $hours $mins $secs
|
|
52
|
+
else
|
|
53
|
+
printf "%02d:%02d" $mins $secs
|
|
54
|
+
fi
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# Format delta with color coding (stock market style)
|
|
58
|
+
# Returns: colored string with +/- prefix, or empty if first iteration
|
|
59
|
+
format_delta() {
|
|
60
|
+
local current=$1
|
|
61
|
+
local previous=$2
|
|
62
|
+
|
|
63
|
+
# Skip if first iteration (no previous time)
|
|
64
|
+
if [ "$previous" -eq 0 ]; then
|
|
65
|
+
echo ""
|
|
66
|
+
return
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
local delta=$((current - previous))
|
|
70
|
+
|
|
71
|
+
if [ $delta -lt 0 ]; then
|
|
72
|
+
# Faster (green with - prefix)
|
|
73
|
+
local abs_delta=$((-delta))
|
|
74
|
+
printf "${GR}-%ds${R}" $abs_delta
|
|
75
|
+
elif [ $delta -gt 0 ]; then
|
|
76
|
+
# Slower (red with + prefix)
|
|
77
|
+
printf "${RD}+%ds${R}" $delta
|
|
78
|
+
else
|
|
79
|
+
# Same time
|
|
80
|
+
printf "~"
|
|
81
|
+
fi
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# Record time spent in current step when transitioning to a new step
|
|
85
|
+
# Usage: record_step_time "new_step_name"
|
|
86
|
+
# Pass empty string to finalize the last step without starting a new one
|
|
87
|
+
record_step_time() {
|
|
88
|
+
local new_step="$1"
|
|
89
|
+
|
|
90
|
+
# If we have a current step, record its elapsed time
|
|
91
|
+
if [ -n "$CURRENT_STEP_NAME" ] && [ "$CURRENT_STEP_START" -gt 0 ]; then
|
|
92
|
+
local now=$(date +%s)
|
|
93
|
+
local elapsed=$((now - CURRENT_STEP_START))
|
|
94
|
+
|
|
95
|
+
# Only record if there's actual time (more than 0 seconds)
|
|
96
|
+
if [ "$elapsed" -gt 0 ]; then
|
|
97
|
+
local idx=$(get_step_index "$CURRENT_STEP_NAME")
|
|
98
|
+
if [ "$idx" -ge 0 ]; then
|
|
99
|
+
# Add to iteration step times
|
|
100
|
+
local current_time=${ITERATION_STEP_VALUES[$idx]}
|
|
101
|
+
ITERATION_STEP_VALUES[$idx]=$((current_time + elapsed))
|
|
102
|
+
|
|
103
|
+
# Add to session step times
|
|
104
|
+
local session_time=${SESSION_STEP_VALUES[$idx]}
|
|
105
|
+
SESSION_STEP_VALUES[$idx]=$((session_time + elapsed))
|
|
106
|
+
fi
|
|
107
|
+
fi
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
# Start timing the new step (if provided)
|
|
111
|
+
if [ -n "$new_step" ]; then
|
|
112
|
+
CURRENT_STEP_NAME="$new_step"
|
|
113
|
+
CURRENT_STEP_START=$(date +%s)
|
|
114
|
+
else
|
|
115
|
+
# No new step - clear tracking
|
|
116
|
+
CURRENT_STEP_NAME=""
|
|
117
|
+
CURRENT_STEP_START=0
|
|
118
|
+
fi
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
# Format step duration for display
|
|
122
|
+
# Usage: format_step_duration 45 # -> "45s"
|
|
123
|
+
# Usage: format_step_duration 125 # -> "02:05"
|
|
124
|
+
format_step_duration() {
|
|
125
|
+
local seconds=$1
|
|
126
|
+
if [ "$seconds" -lt 60 ]; then
|
|
127
|
+
echo "${seconds}s"
|
|
128
|
+
else
|
|
129
|
+
local mins=$((seconds / 60))
|
|
130
|
+
local secs=$((seconds % 60))
|
|
131
|
+
printf "%02d:%02d" $mins $secs
|
|
132
|
+
fi
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
# Format step times as inline display string
|
|
136
|
+
# Usage: format_step_times "ITERATION" or "SESSION"
|
|
137
|
+
# Returns: "โ ๐งช Testing: 45s โ ๐งน Linting: 12s" (sorted by duration descending)
|
|
138
|
+
format_step_times() {
|
|
139
|
+
local mode="$1"
|
|
140
|
+
local output=""
|
|
141
|
+
local sorted_steps=()
|
|
142
|
+
|
|
143
|
+
# Build array of "duration:step_name" for sorting
|
|
144
|
+
for i in "${!STEP_NAMES[@]}"; do
|
|
145
|
+
local step="${STEP_NAMES[$i]}"
|
|
146
|
+
local time
|
|
147
|
+
if [ "$mode" = "SESSION" ]; then
|
|
148
|
+
time=${SESSION_STEP_VALUES[$i]}
|
|
149
|
+
else
|
|
150
|
+
time=${ITERATION_STEP_VALUES[$i]}
|
|
151
|
+
fi
|
|
152
|
+
if [ "$time" -gt 0 ]; then
|
|
153
|
+
sorted_steps+=("$time:$step")
|
|
154
|
+
fi
|
|
155
|
+
done
|
|
156
|
+
|
|
157
|
+
# Sort by duration descending (reverse numeric sort on first field)
|
|
158
|
+
if [ ${#sorted_steps[@]} -gt 0 ]; then
|
|
159
|
+
IFS=$'\n' sorted_steps=($(sort -t: -k1 -rn <<<"${sorted_steps[*]}"))
|
|
160
|
+
unset IFS
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
# Build output string
|
|
164
|
+
for item in "${sorted_steps[@]}"; do
|
|
165
|
+
local time="${item%%:*}"
|
|
166
|
+
local step="${item#*:}"
|
|
167
|
+
local emoji=$(get_step_emoji "$step")
|
|
168
|
+
local formatted=$(format_step_duration $time)
|
|
169
|
+
|
|
170
|
+
if [ -n "$output" ]; then
|
|
171
|
+
output="$output ${C}โ${R} "
|
|
172
|
+
fi
|
|
173
|
+
output="$output$emoji $step: ${Y}$formatted${R}"
|
|
174
|
+
done
|
|
175
|
+
|
|
176
|
+
echo "$output"
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
# Initialize iteration step times at start of new iteration
|
|
180
|
+
# Usage: init_iteration_step_times
|
|
181
|
+
init_iteration_step_times() {
|
|
182
|
+
# Clear iteration step times (reset all to 0)
|
|
183
|
+
ITERATION_STEP_VALUES=(0 0 0 0 0 0 0 0)
|
|
184
|
+
|
|
185
|
+
# Start timing with "Thinking" as default initial step
|
|
186
|
+
CURRENT_STEP_NAME="Thinking"
|
|
187
|
+
CURRENT_STEP_START=$(date +%s)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
# Display session step totals at end of run
|
|
191
|
+
# Usage: display_session_step_totals
|
|
192
|
+
display_session_step_totals() {
|
|
193
|
+
local step_output=$(format_step_times "SESSION")
|
|
194
|
+
|
|
195
|
+
if [ -n "$step_output" ]; then
|
|
196
|
+
echo -e " ๐ Session totals: $step_output"
|
|
197
|
+
fi
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
# Detect current step from output line
|
|
201
|
+
# Returns: step name based on output patterns
|
|
202
|
+
detect_step() {
|
|
203
|
+
local line="$1"
|
|
204
|
+
|
|
205
|
+
# Check patterns in order of specificity
|
|
206
|
+
if echo "$line" | grep -qiE "(git commit|committing)"; then
|
|
207
|
+
echo "Committing "
|
|
208
|
+
elif echo "$line" | grep -qiE "(npm test|jest|vitest|testing|test.*pass|test.*fail)"; then
|
|
209
|
+
echo "Testing "
|
|
210
|
+
elif echo "$line" | grep -qiE "(eslint|lint|prettier|formatting)"; then
|
|
211
|
+
echo "Linting "
|
|
212
|
+
elif echo "$line" | grep -qiE "(npm run typecheck|tsc|typescript|typecheck)"; then
|
|
213
|
+
echo "Typechecking "
|
|
214
|
+
elif echo "$line" | grep -qiE "(\.test\.|\.spec\.|test file|writing test)"; then
|
|
215
|
+
echo "Writing tests "
|
|
216
|
+
elif echo "$line" | grep -qiE "(write|edit|creating|updating|modifying).*\.(ts|js|sh|json|md)"; then
|
|
217
|
+
echo "Implementing "
|
|
218
|
+
elif echo "$line" | grep -qiE "(read|glob|grep|searching|finding|looking)"; then
|
|
219
|
+
echo "Reading code "
|
|
220
|
+
else
|
|
221
|
+
echo ""
|
|
222
|
+
fi
|
|
223
|
+
}
|