prizmkit 1.0.8 → 1.0.9
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/bundled/VERSION.json +3 -3
- package/bundled/dev-pipeline/lib/heartbeat.sh +173 -0
- package/package.json +1 -1
- package/src/scaffold.js +1 -1
package/bundled/VERSION.json
CHANGED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================
|
|
3
|
+
# dev-pipeline/lib/heartbeat.sh - Shared heartbeat monitoring
|
|
4
|
+
#
|
|
5
|
+
# Provides start_heartbeat / stop_heartbeat functions that read
|
|
6
|
+
# structured progress from progress.json (written by
|
|
7
|
+
# parse-stream-progress.py) and fall back to tail-based monitoring.
|
|
8
|
+
#
|
|
9
|
+
# Usage:
|
|
10
|
+
# source "$SCRIPT_DIR/lib/heartbeat.sh"
|
|
11
|
+
# start_heartbeat "$cli_pid" "$session_log" "$progress_json" "$interval"
|
|
12
|
+
# # ... wait for CLI to finish ...
|
|
13
|
+
# stop_heartbeat "$_HEARTBEAT_PID"
|
|
14
|
+
#
|
|
15
|
+
# Requires: colors (GREEN, YELLOW, BLUE, NC) and log functions
|
|
16
|
+
# to be defined before sourcing.
|
|
17
|
+
# ============================================================
|
|
18
|
+
|
|
19
|
+
# Start a heartbeat monitor in the background.
|
|
20
|
+
# Sets _HEARTBEAT_PID to the background process PID.
|
|
21
|
+
#
|
|
22
|
+
# Arguments:
|
|
23
|
+
# $1 - cli_pid PID of the AI CLI process to monitor
|
|
24
|
+
# $2 - session_log Path to session.log
|
|
25
|
+
# $3 - progress_json Path to progress.json (may not exist if stream-json disabled)
|
|
26
|
+
# $4 - interval Heartbeat interval in seconds
|
|
27
|
+
start_heartbeat() {
|
|
28
|
+
local cli_pid="$1"
|
|
29
|
+
local session_log="$2"
|
|
30
|
+
local progress_json="$3"
|
|
31
|
+
local heartbeat_interval="$4"
|
|
32
|
+
|
|
33
|
+
(
|
|
34
|
+
local elapsed=0
|
|
35
|
+
local prev_size=0
|
|
36
|
+
while kill -0 "$cli_pid" 2>/dev/null; do
|
|
37
|
+
sleep "$heartbeat_interval"
|
|
38
|
+
elapsed=$((elapsed + heartbeat_interval))
|
|
39
|
+
kill -0 "$cli_pid" 2>/dev/null || break
|
|
40
|
+
|
|
41
|
+
# Get log file size
|
|
42
|
+
local cur_size=0
|
|
43
|
+
if [[ -f "$session_log" ]]; then
|
|
44
|
+
cur_size=$(wc -c < "$session_log" 2>/dev/null || echo 0)
|
|
45
|
+
cur_size=$(echo "$cur_size" | tr -d ' ')
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
local growth=$((cur_size - prev_size))
|
|
49
|
+
prev_size=$cur_size
|
|
50
|
+
|
|
51
|
+
local size_display
|
|
52
|
+
if [[ $cur_size -gt 1048576 ]]; then
|
|
53
|
+
size_display="$((cur_size / 1048576))MB"
|
|
54
|
+
elif [[ $cur_size -gt 1024 ]]; then
|
|
55
|
+
size_display="$((cur_size / 1024))KB"
|
|
56
|
+
else
|
|
57
|
+
size_display="${cur_size}B"
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
local mins=$((elapsed / 60))
|
|
61
|
+
local secs=$((elapsed % 60))
|
|
62
|
+
|
|
63
|
+
local status_icon
|
|
64
|
+
if [[ $growth -gt 0 ]]; then
|
|
65
|
+
status_icon="${GREEN}▶${NC}"
|
|
66
|
+
else
|
|
67
|
+
status_icon="${YELLOW}⏸${NC}"
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# Try structured progress from progress.json
|
|
71
|
+
if [[ -f "$progress_json" ]]; then
|
|
72
|
+
local phase tool msgs tools_total
|
|
73
|
+
phase=$(python3 -c "
|
|
74
|
+
import json, sys
|
|
75
|
+
try:
|
|
76
|
+
with open('$progress_json') as f:
|
|
77
|
+
d = json.load(f)
|
|
78
|
+
parts = []
|
|
79
|
+
if d.get('current_phase'):
|
|
80
|
+
parts.append('phase: ' + d['current_phase'])
|
|
81
|
+
if d.get('current_tool'):
|
|
82
|
+
parts.append('tool: ' + d['current_tool'])
|
|
83
|
+
parts.append('msgs: ' + str(d.get('message_count', 0)))
|
|
84
|
+
parts.append(str(d.get('total_tool_calls', 0)) + ' tool calls')
|
|
85
|
+
print(' | '.join(parts))
|
|
86
|
+
except Exception:
|
|
87
|
+
sys.exit(1)
|
|
88
|
+
" 2>/dev/null) && {
|
|
89
|
+
echo -e " ${status_icon} ${BLUE}[HEARTBEAT]${NC} ${mins}m${secs}s | log: ${size_display} | ${phase}"
|
|
90
|
+
continue
|
|
91
|
+
}
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
# Fallback: tail-based activity detection
|
|
95
|
+
local last_activity=""
|
|
96
|
+
if [[ -f "$session_log" ]]; then
|
|
97
|
+
last_activity=$(tail -20 "$session_log" 2>/dev/null | grep -v '^$' | tail -1 | cut -c1-80 || echo "")
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
echo -e " ${status_icon} ${BLUE}[HEARTBEAT]${NC} ${mins}m${secs}s elapsed | log: ${size_display} (+${growth}B) | ${last_activity}"
|
|
101
|
+
done
|
|
102
|
+
) &
|
|
103
|
+
_HEARTBEAT_PID=$!
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
# Stop a heartbeat monitor process.
|
|
107
|
+
#
|
|
108
|
+
# Arguments:
|
|
109
|
+
# $1 - heartbeat_pid PID returned by start_heartbeat
|
|
110
|
+
stop_heartbeat() {
|
|
111
|
+
local heartbeat_pid="$1"
|
|
112
|
+
if [[ -n "$heartbeat_pid" ]]; then
|
|
113
|
+
kill "$heartbeat_pid" 2>/dev/null || true
|
|
114
|
+
wait "$heartbeat_pid" 2>/dev/null || true
|
|
115
|
+
fi
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
# Start the stream-json progress parser as a background process.
|
|
119
|
+
# Sets _PARSER_PID to the background process PID.
|
|
120
|
+
# No-op if USE_STREAM_JSON is not "true".
|
|
121
|
+
#
|
|
122
|
+
# Arguments:
|
|
123
|
+
# $1 - session_log Path to session.log
|
|
124
|
+
# $2 - progress_json Path to write progress.json
|
|
125
|
+
# $3 - scripts_dir Path to scripts/ directory
|
|
126
|
+
start_progress_parser() {
|
|
127
|
+
local session_log="$1"
|
|
128
|
+
local progress_json="$2"
|
|
129
|
+
local scripts_dir="$3"
|
|
130
|
+
|
|
131
|
+
_PARSER_PID=""
|
|
132
|
+
|
|
133
|
+
if [[ "${USE_STREAM_JSON:-}" != "true" ]]; then
|
|
134
|
+
return 0
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
local parser_script="$scripts_dir/parse-stream-progress.py"
|
|
138
|
+
if [[ ! -f "$parser_script" ]]; then
|
|
139
|
+
return 0
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
python3 "$parser_script" \
|
|
143
|
+
--session-log "$session_log" \
|
|
144
|
+
--progress-file "$progress_json" &
|
|
145
|
+
_PARSER_PID=$!
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
# Stop the progress parser process.
|
|
149
|
+
#
|
|
150
|
+
# Arguments:
|
|
151
|
+
# $1 - parser_pid PID returned by start_progress_parser
|
|
152
|
+
stop_progress_parser() {
|
|
153
|
+
local parser_pid="$1"
|
|
154
|
+
if [[ -n "$parser_pid" ]]; then
|
|
155
|
+
kill "$parser_pid" 2>/dev/null || true
|
|
156
|
+
wait "$parser_pid" 2>/dev/null || true
|
|
157
|
+
fi
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
# Detect whether the AI CLI supports --output-format stream-json.
|
|
161
|
+
# Sets USE_STREAM_JSON to "true" or "false".
|
|
162
|
+
#
|
|
163
|
+
# Arguments:
|
|
164
|
+
# $1 - cli_cmd The AI CLI command
|
|
165
|
+
detect_stream_json_support() {
|
|
166
|
+
local cli_cmd="$1"
|
|
167
|
+
USE_STREAM_JSON="false"
|
|
168
|
+
|
|
169
|
+
# Try to detect support via --help output
|
|
170
|
+
if "$cli_cmd" --help 2>&1 | grep -q "stream-json" 2>/dev/null; then
|
|
171
|
+
USE_STREAM_JSON="true"
|
|
172
|
+
fi
|
|
173
|
+
}
|
package/package.json
CHANGED
package/src/scaffold.js
CHANGED
|
@@ -435,7 +435,7 @@ async function installPipeline(projectRoot, dryRun) {
|
|
|
435
435
|
const items = [
|
|
436
436
|
'run.sh', 'retry-feature.sh', 'reset-feature.sh', 'launch-daemon.sh',
|
|
437
437
|
'run-bugfix.sh', 'retry-bug.sh', 'launch-bugfix-daemon.sh',
|
|
438
|
-
'scripts', 'templates', 'assets', 'README.md', '.gitignore',
|
|
438
|
+
'lib', 'scripts', 'templates', 'assets', 'README.md', '.gitignore',
|
|
439
439
|
];
|
|
440
440
|
|
|
441
441
|
let installedCount = 0;
|