@kraftapps-ai/kai 1.8.7 → 1.9.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/kai +29 -56
- package/package.json +1 -1
package/kai
CHANGED
|
@@ -244,12 +244,6 @@ LOOP_MCP_ARGS="--mcp-config .kai/loop-mcp.json"
|
|
|
244
244
|
# Cap Node.js memory to prevent test runners from consuming all RAM
|
|
245
245
|
export NODE_OPTIONS="--max-old-space-size=2048"
|
|
246
246
|
|
|
247
|
-
# Stream output live when running in a tmux pane
|
|
248
|
-
KAI_STREAM=false
|
|
249
|
-
if [ -n "${TMUX:-}" ]; then
|
|
250
|
-
KAI_STREAM=true
|
|
251
|
-
fi
|
|
252
|
-
|
|
253
247
|
WORKER_PROMPT='You are an autonomous AI developer specializing in Shopify app and theme development.
|
|
254
248
|
|
|
255
249
|
## Your Shopify expertise
|
|
@@ -352,51 +346,37 @@ while :; do
|
|
|
352
346
|
|
|
353
347
|
start_time=$(date +%s)
|
|
354
348
|
|
|
355
|
-
#
|
|
349
|
+
# jq filter for streaming claude output — shows tool calls, text, and results
|
|
350
|
+
STREAM_FILTER='
|
|
351
|
+
if .type == "assistant" then
|
|
352
|
+
([.message.content[] |
|
|
353
|
+
if .type == "tool_use" then "⚡ " + .name + ": " + (.input.command // .input.file_path // .input.pattern // "" | tostring | .[0:150])
|
|
354
|
+
elif .type == "text" then .text
|
|
355
|
+
else empty end
|
|
356
|
+
] | join("\n"))
|
|
357
|
+
elif .type == "user" and .tool_use_result then
|
|
358
|
+
" → " + (.tool_use_result.stdout // "" | .[0:200] | gsub("\n"; " "))
|
|
359
|
+
elif .type == "result" then
|
|
360
|
+
"✅ Done (" + (.duration_ms / 1000 | tostring | .[0:5]) + "s, $" + (.total_cost_usd | tostring | .[0:6]) + ")"
|
|
361
|
+
else empty end'
|
|
362
|
+
|
|
363
|
+
# Stream worker output live
|
|
356
364
|
set +e
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
sleep 30
|
|
364
|
-
elapsed_now=$(( $(date +%s) - start_time ))
|
|
365
|
-
mins=$((elapsed_now / 60))
|
|
366
|
-
secs=$((elapsed_now % 60))
|
|
367
|
-
|
|
368
|
-
# Detect what's running
|
|
369
|
-
activity=""
|
|
370
|
-
pgrep -f "vitest" > /dev/null 2>&1 && activity="running tests"
|
|
371
|
-
pgrep -f "esbuild" > /dev/null 2>&1 && activity="${activity:+$activity + }building"
|
|
372
|
-
pgrep -f "npm run build" > /dev/null 2>&1 && activity="${activity:+$activity + }building"
|
|
373
|
-
[ -z "$activity" ] && activity="thinking"
|
|
374
|
-
|
|
375
|
-
# Show recently changed files
|
|
376
|
-
changed=$(find . \( -name '*.ts' -o -name '*.tsx' -o -name '*.php' -o -name '*.less' -o -name '*.css' -o -name '*.json' \) \
|
|
377
|
-
-not -path './node_modules/*' -not -path './.kai/*' -not -path './vendor/*' \
|
|
378
|
-
-newer .kai/worker-heartbeat -printf '%f\n' 2>/dev/null | sort -u | head -5 | tr '\n' ', ')
|
|
379
|
-
|
|
380
|
-
echo " [${mins}m${secs}s] ${activity}${changed:+ | files: ${changed%,}}"
|
|
381
|
-
touch .kai/worker-heartbeat
|
|
382
|
-
done
|
|
383
|
-
|
|
384
|
-
wait $worker_pid
|
|
385
|
-
exit_code=$?
|
|
386
|
-
result=$(cat .kai/worker-output.tmp)
|
|
365
|
+
claude -p --output-format stream-json --verbose --dangerously-skip-permissions $LOOP_MCP_ARGS \
|
|
366
|
+
--system-prompt "$WORKER_PROMPT" $context_files 2>&1 | \
|
|
367
|
+
tee .kai/worker-stream.tmp | \
|
|
368
|
+
jq --unbuffered -r "$STREAM_FILTER" 2>/dev/null
|
|
369
|
+
exit_code=${PIPESTATUS[0]}
|
|
370
|
+
result=$(jq -r 'select(.type == "result") | .result // empty' .kai/worker-stream.tmp 2>/dev/null)
|
|
387
371
|
set -e
|
|
388
372
|
|
|
389
373
|
elapsed=$(( $(date +%s) - start_time ))
|
|
390
374
|
|
|
391
375
|
if [ $exit_code -ne 0 ]; then
|
|
392
|
-
echo " Worker failed (code ${exit_code}).
|
|
393
|
-
echo "$result" | tail -10
|
|
394
|
-
echo " Restarting..."
|
|
376
|
+
echo " Worker failed (code ${exit_code}). Restarting..."
|
|
395
377
|
continue
|
|
396
378
|
fi
|
|
397
379
|
|
|
398
|
-
echo "$result" | tail -20
|
|
399
|
-
|
|
400
380
|
if [[ "$result" == *"<promise>COMPLETE</promise>"* ]]; then
|
|
401
381
|
echo "All stories complete after $iteration iterations!"
|
|
402
382
|
exit 0
|
|
@@ -405,7 +385,8 @@ while :; do
|
|
|
405
385
|
# Review
|
|
406
386
|
STORY_PASSES=$(jq -r --arg id "$NEXT_ID" '.userStories[] | select(.id == $id) | .passes' "$PRD_FILE")
|
|
407
387
|
if [ "$STORY_PASSES" = "true" ]; then
|
|
408
|
-
echo "
|
|
388
|
+
echo ""
|
|
389
|
+
echo " 📋 Reviewing story #${NEXT_ID}..."
|
|
409
390
|
last_commit=$(git log --oneline -1 2>/dev/null || echo "no git")
|
|
410
391
|
ACCEPTANCE=$(jq -r --arg id "$NEXT_ID" '.userStories[] | select(.id == $id) | .acceptanceCriteria | join("\n- ")' "$PRD_FILE")
|
|
411
392
|
|
|
@@ -420,21 +401,13 @@ If ANY fails: REVIEW_FAIL: [reason]
|
|
|
420
401
|
If all pass: REVIEW_PASS"
|
|
421
402
|
|
|
422
403
|
set +e
|
|
423
|
-
claude -p --dangerously-skip-permissions $LOOP_MCP_ARGS
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
elapsed_now=$(( $(date +%s) - start_time ))
|
|
429
|
-
echo " [${elapsed_now}s] reviewing..."
|
|
430
|
-
done
|
|
431
|
-
|
|
432
|
-
wait $review_pid
|
|
433
|
-
review=$(cat .kai/review-output.tmp)
|
|
404
|
+
claude -p --output-format stream-json --verbose --dangerously-skip-permissions $LOOP_MCP_ARGS \
|
|
405
|
+
"$REVIEW_PROMPT" 2>&1 | \
|
|
406
|
+
tee .kai/review-stream.tmp | \
|
|
407
|
+
jq --unbuffered -r "$STREAM_FILTER" 2>/dev/null
|
|
408
|
+
review=$(jq -r 'select(.type == "result") | .result // empty' .kai/review-stream.tmp 2>/dev/null)
|
|
434
409
|
set -e
|
|
435
410
|
|
|
436
|
-
echo "$review" | tail -5
|
|
437
|
-
|
|
438
411
|
if [[ "$review" == *"REVIEW_FAIL"* ]]; then
|
|
439
412
|
jq --arg id "$NEXT_ID" '(.userStories[] | select(.id == $id)).passes = false' "$PRD_FILE" > "${PRD_FILE}.tmp" && mv "${PRD_FILE}.tmp" "$PRD_FILE"
|
|
440
413
|
echo "REVIEW FEEDBACK: $review" >> "$PROGRESS_FILE"
|