@walwal-harness/cli 4.0.0-alpha.7 → 4.0.0-alpha.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walwal-harness/cli",
|
|
3
|
-
"version": "4.0.0-alpha.
|
|
3
|
+
"version": "4.0.0-alpha.9",
|
|
4
4
|
"description": "Production harness for AI agent engineering — Planner, Generator(BE/FE), Evaluator(Func/Visual), optional Brainstormer (requirements refinement). Supports React and Flutter FE stacks.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"walwal-harness": "bin/init.js"
|
|
@@ -149,10 +149,54 @@ render_feature_list() {
|
|
|
149
149
|
echo ""
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
render_prompt_history() {
|
|
153
|
+
local log_file="$PROJECT_ROOT/.harness/progress.log"
|
|
154
|
+
if [ ! -f "$log_file" ]; then return; fi
|
|
155
|
+
|
|
156
|
+
# Get terminal height to limit display
|
|
157
|
+
local term_h
|
|
158
|
+
term_h=$(tput lines 2>/dev/null || echo 50)
|
|
159
|
+
local max_lines=10 # show latest 10 entries
|
|
160
|
+
|
|
161
|
+
echo -e " ${BOLD}Prompt History${RESET} ${DIM}(newest first)${RESET}"
|
|
162
|
+
|
|
163
|
+
# Read non-comment lines, reverse (newest first), take max_lines
|
|
164
|
+
grep -v '^#' "$log_file" 2>/dev/null | grep -v '^$' | tail -r 2>/dev/null | head -"$max_lines" | \
|
|
165
|
+
while IFS= read -r line; do
|
|
166
|
+
# Parse: date | agent | action | detail
|
|
167
|
+
local ts agent action detail
|
|
168
|
+
ts=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$1); print $1}')
|
|
169
|
+
agent=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$2); print $2}')
|
|
170
|
+
action=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$3); print $3}')
|
|
171
|
+
detail=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$4); print $4}')
|
|
172
|
+
|
|
173
|
+
local short_ts icon color
|
|
174
|
+
short_ts=$(echo "$ts" | sed 's/^[0-9]*-//')
|
|
175
|
+
|
|
176
|
+
case "$agent" in
|
|
177
|
+
dispatcher*|dispatch) icon="▸"; color="$MAGENTA" ;;
|
|
178
|
+
team-*) icon="⚡"; color="$CYAN" ;;
|
|
179
|
+
manual|user) icon="★"; color="$BOLD" ;;
|
|
180
|
+
planner*) icon="□"; color="$YELLOW" ;;
|
|
181
|
+
generator*|gen*) icon="▶"; color="$GREEN" ;;
|
|
182
|
+
eval*) icon="✦"; color="$RED" ;;
|
|
183
|
+
system) icon="⚙"; color="$DIM" ;;
|
|
184
|
+
*) icon="·"; color="$DIM" ;;
|
|
185
|
+
esac
|
|
186
|
+
|
|
187
|
+
if [ ${#detail} -gt 45 ]; then detail="${detail:0:43}.."; fi
|
|
188
|
+
|
|
189
|
+
echo -e " ${color}${icon}${RESET} ${DIM}${short_ts}${RESET} ${agent} ${DIM}${action}${RESET} ${detail}"
|
|
190
|
+
done
|
|
191
|
+
|
|
192
|
+
echo ""
|
|
193
|
+
}
|
|
194
|
+
|
|
152
195
|
render_all() {
|
|
153
196
|
render_header
|
|
154
197
|
render_queue_summary
|
|
155
198
|
render_teams
|
|
199
|
+
render_prompt_history
|
|
156
200
|
render_feature_list
|
|
157
201
|
echo -e " ${DIM}Refreshing every 3s${RESET}"
|
|
158
202
|
}
|
|
@@ -42,6 +42,25 @@ fi
|
|
|
42
42
|
FEATURES="$PROJECT_ROOT/.harness/actions/feature-list.json"
|
|
43
43
|
QUEUE="$PROJECT_ROOT/.harness/actions/feature-queue.json"
|
|
44
44
|
CONFIG="$PROJECT_ROOT/.harness/config.json"
|
|
45
|
+
QUEUE_LOCK="$PROJECT_ROOT/.harness/.queue-lock"
|
|
46
|
+
|
|
47
|
+
# ── Atomic queue lock — prevent race conditions between teams ──
|
|
48
|
+
acquire_queue_lock() {
|
|
49
|
+
local max_wait=30 waited=0
|
|
50
|
+
while ! mkdir "$QUEUE_LOCK" 2>/dev/null; do
|
|
51
|
+
sleep 0.1
|
|
52
|
+
waited=$((waited + 1))
|
|
53
|
+
if [ "$waited" -ge $((max_wait * 10)) ]; then
|
|
54
|
+
rm -rf "$QUEUE_LOCK"
|
|
55
|
+
mkdir "$QUEUE_LOCK" 2>/dev/null || true
|
|
56
|
+
break
|
|
57
|
+
fi
|
|
58
|
+
done
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
release_queue_lock() {
|
|
62
|
+
rm -rf "$QUEUE_LOCK" 2>/dev/null || true
|
|
63
|
+
}
|
|
45
64
|
|
|
46
65
|
# ── Concurrency from config ──
|
|
47
66
|
CONCURRENCY=3
|
|
@@ -122,12 +141,14 @@ cmd_dequeue() {
|
|
|
122
141
|
if [ -z "$team_id" ]; then echo "[queue] Usage: dequeue <team_id>"; exit 1; fi
|
|
123
142
|
if [ ! -f "$QUEUE" ]; then echo "[queue] Run 'init' first."; exit 1; fi
|
|
124
143
|
|
|
144
|
+
acquire_queue_lock
|
|
145
|
+
|
|
125
146
|
local feature
|
|
126
147
|
feature=$(jq -r '.queue.ready[0] // empty' "$QUEUE")
|
|
127
148
|
|
|
128
149
|
if [ -z "$feature" ]; then
|
|
150
|
+
release_queue_lock
|
|
129
151
|
echo "[queue] No features in ready queue."
|
|
130
|
-
# Check if all done
|
|
131
152
|
local in_prog blocked
|
|
132
153
|
in_prog=$(jq '.queue.in_progress | length' "$QUEUE")
|
|
133
154
|
blocked=$(jq '.queue.blocked | length' "$QUEUE")
|
|
@@ -137,13 +158,13 @@ cmd_dequeue() {
|
|
|
137
158
|
return 1
|
|
138
159
|
fi
|
|
139
160
|
|
|
140
|
-
# Move feature from ready → in_progress, assign to team
|
|
141
161
|
jq --arg fid "$feature" --arg tid "$team_id" '
|
|
142
162
|
.queue.ready -= [$fid] |
|
|
143
163
|
.queue.in_progress[$fid] = { team: ($tid | tonumber), phase: "gen", attempt: 1 } |
|
|
144
164
|
.teams[$tid] = { status: "busy", feature: $fid, branch: ("feature/" + $fid), pid: null }
|
|
145
165
|
' "$QUEUE" > "${QUEUE}.tmp" && mv "${QUEUE}.tmp" "$QUEUE"
|
|
146
166
|
|
|
167
|
+
release_queue_lock
|
|
147
168
|
echo "$feature"
|
|
148
169
|
}
|
|
149
170
|
|
|
@@ -155,11 +176,11 @@ cmd_pass() {
|
|
|
155
176
|
if [ -z "$fid" ]; then echo "[queue] Usage: pass <feature_id>"; exit 1; fi
|
|
156
177
|
if [ ! -f "$QUEUE" ]; then echo "[queue] Run 'init' first."; exit 1; fi
|
|
157
178
|
|
|
158
|
-
|
|
179
|
+
acquire_queue_lock
|
|
180
|
+
|
|
159
181
|
local team_id
|
|
160
182
|
team_id=$(jq -r --arg fid "$fid" '.queue.in_progress[$fid].team // empty' "$QUEUE")
|
|
161
183
|
|
|
162
|
-
# Move from in_progress → passed, free team, unblock dependents
|
|
163
184
|
jq --arg fid "$fid" --arg tid "${team_id:-0}" '
|
|
164
185
|
# Remove from in_progress
|
|
165
186
|
del(.queue.in_progress[$fid]) |
|
|
@@ -188,6 +209,7 @@ cmd_pass() {
|
|
|
188
209
|
|
|
189
210
|
local newly_ready
|
|
190
211
|
newly_ready=$(jq -r '.queue.ready | join(", ")' "$QUEUE")
|
|
212
|
+
release_queue_lock
|
|
191
213
|
echo "[queue] $fid PASSED. Ready: [$newly_ready]"
|
|
192
214
|
}
|
|
193
215
|
|
|
@@ -199,6 +221,8 @@ cmd_fail() {
|
|
|
199
221
|
if [ -z "$fid" ]; then echo "[queue] Usage: fail <feature_id>"; exit 1; fi
|
|
200
222
|
if [ ! -f "$QUEUE" ]; then exit 1; fi
|
|
201
223
|
|
|
224
|
+
acquire_queue_lock
|
|
225
|
+
|
|
202
226
|
local team_id
|
|
203
227
|
team_id=$(jq -r --arg fid "$fid" '.queue.in_progress[$fid].team // empty' "$QUEUE")
|
|
204
228
|
|
|
@@ -211,6 +235,7 @@ cmd_fail() {
|
|
|
211
235
|
else . end)
|
|
212
236
|
' "$QUEUE" > "${QUEUE}.tmp" && mv "${QUEUE}.tmp" "$QUEUE"
|
|
213
237
|
|
|
238
|
+
release_queue_lock
|
|
214
239
|
echo "[queue] $fid FAILED."
|
|
215
240
|
}
|
|
216
241
|
|
|
@@ -239,6 +264,8 @@ cmd_update_phase() {
|
|
|
239
264
|
exit 1
|
|
240
265
|
fi
|
|
241
266
|
|
|
267
|
+
acquire_queue_lock
|
|
268
|
+
|
|
242
269
|
local jq_expr
|
|
243
270
|
jq_expr=".queue.in_progress[\"$fid\"].phase = \"$phase\""
|
|
244
271
|
if [ -n "$attempt" ]; then
|
|
@@ -246,6 +273,7 @@ cmd_update_phase() {
|
|
|
246
273
|
fi
|
|
247
274
|
|
|
248
275
|
jq "$jq_expr" "$QUEUE" > "${QUEUE}.tmp" && mv "${QUEUE}.tmp" "$QUEUE"
|
|
276
|
+
release_queue_lock
|
|
249
277
|
}
|
|
250
278
|
|
|
251
279
|
# ══════════════════════════════════════════
|
|
@@ -280,7 +280,11 @@ while true; do
|
|
|
280
280
|
gen_prompt=$(build_gen_prompt "$feature_id" "$attempt" "$eval_feedback")
|
|
281
281
|
|
|
282
282
|
gen_start=$(date +%s)
|
|
283
|
-
|
|
283
|
+
log "${DIM} claude -p --dangerously-skip-permissions --model ${GEN_MODEL}${RESET}"
|
|
284
|
+
gen_output=$(cd "$PROJECT_ROOT" && claude -p "$gen_prompt" \
|
|
285
|
+
--dangerously-skip-permissions \
|
|
286
|
+
--model "$GEN_MODEL" \
|
|
287
|
+
--output-format text 2>&1 | tee /dev/stderr) 2>&1 || true
|
|
284
288
|
gen_elapsed=$(( $(date +%s) - gen_start ))
|
|
285
289
|
|
|
286
290
|
files_changed=$(cd "$PROJECT_ROOT" && git diff --name-only 2>/dev/null | wc -l | tr -d ' ')
|
|
@@ -308,7 +312,11 @@ while true; do
|
|
|
308
312
|
eval_prompt=$(build_eval_prompt "$feature_id")
|
|
309
313
|
|
|
310
314
|
eval_start=$(date +%s)
|
|
311
|
-
|
|
315
|
+
log "${DIM} claude -p --dangerously-skip-permissions --model ${EVAL_MODEL}${RESET}"
|
|
316
|
+
eval_output=$(cd "$PROJECT_ROOT" && claude -p "$eval_prompt" \
|
|
317
|
+
--dangerously-skip-permissions \
|
|
318
|
+
--model "$EVAL_MODEL" \
|
|
319
|
+
--output-format text 2>&1 | tee /dev/stderr) 2>&1 || true
|
|
312
320
|
eval_elapsed=$(( $(date +%s) - eval_start ))
|
|
313
321
|
|
|
314
322
|
# Parse result
|