@kraftapps-ai/kai 1.8.7 → 1.9.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.
Files changed (2) hide show
  1. package/kai +30 -56
  2. 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
@@ -297,6 +291,7 @@ You are an expert Shopify developer. You have access to the Shopify Dev MCP tool
297
291
 
298
292
  ## Rules
299
293
  - ONE STORY PER LOOP.
294
+ - **NEVER switch branches.** Always commit to the current branch. Do NOT run `git checkout`, `git switch`, or `git branch`. The PM manages branches — you just commit your work.
300
295
  - **TDD is mandatory.** Tests first, then implementation. No exceptions.
301
296
  - No placeholders. Fully implement or report BLOCKED.
302
297
  - Do not break existing functionality. Run the full test suite ONCE at the end as a final check.
@@ -352,51 +347,37 @@ while :; do
352
347
 
353
348
  start_time=$(date +%s)
354
349
 
355
- # Run worker in background with heartbeat monitor
350
+ # jq filter for streaming claude output — shows tool calls, text, and results
351
+ STREAM_FILTER='
352
+ if .type == "assistant" then
353
+ ([.message.content[] |
354
+ if .type == "tool_use" then "⚡ " + .name + ": " + (.input.command // .input.file_path // .input.pattern // "" | tostring | .[0:150])
355
+ elif .type == "text" then .text
356
+ else empty end
357
+ ] | join("\n"))
358
+ elif .type == "user" and .tool_use_result then
359
+ " → " + (.tool_use_result.stdout // "" | .[0:200] | gsub("\n"; " "))
360
+ elif .type == "result" then
361
+ "✅ Done (" + (.duration_ms / 1000 | tostring | .[0:5]) + "s, $" + (.total_cost_usd | tostring | .[0:6]) + ")"
362
+ else empty end'
363
+
364
+ # Stream worker output live
356
365
  set +e
357
- touch .kai/worker-heartbeat
358
- claude -p --dangerously-skip-permissions $LOOP_MCP_ARGS --system-prompt "$WORKER_PROMPT" $context_files > .kai/worker-output.tmp 2>&1 &
359
- worker_pid=$!
360
-
361
- echo " Worker started (PID $worker_pid)"
362
- while kill -0 $worker_pid 2>/dev/null; do
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)
366
+ claude -p --output-format stream-json --verbose --dangerously-skip-permissions $LOOP_MCP_ARGS \
367
+ --system-prompt "$WORKER_PROMPT" $context_files 2>&1 | \
368
+ tee .kai/worker-stream.tmp | \
369
+ jq --unbuffered -r "$STREAM_FILTER" 2>/dev/null
370
+ exit_code=${PIPESTATUS[0]}
371
+ result=$(jq -r 'select(.type == "result") | .result // empty' .kai/worker-stream.tmp 2>/dev/null)
387
372
  set -e
388
373
 
389
374
  elapsed=$(( $(date +%s) - start_time ))
390
375
 
391
376
  if [ $exit_code -ne 0 ]; then
392
- echo " Worker failed (code ${exit_code}). Last output:"
393
- echo "$result" | tail -10
394
- echo " Restarting..."
377
+ echo " Worker failed (code ${exit_code}). Restarting..."
395
378
  continue
396
379
  fi
397
380
 
398
- echo "$result" | tail -20
399
-
400
381
  if [[ "$result" == *"<promise>COMPLETE</promise>"* ]]; then
401
382
  echo "All stories complete after $iteration iterations!"
402
383
  exit 0
@@ -405,7 +386,8 @@ while :; do
405
386
  # Review
406
387
  STORY_PASSES=$(jq -r --arg id "$NEXT_ID" '.userStories[] | select(.id == $id) | .passes' "$PRD_FILE")
407
388
  if [ "$STORY_PASSES" = "true" ]; then
408
- echo " Reviewing story #${NEXT_ID}..."
389
+ echo ""
390
+ echo " 📋 Reviewing story #${NEXT_ID}..."
409
391
  last_commit=$(git log --oneline -1 2>/dev/null || echo "no git")
410
392
  ACCEPTANCE=$(jq -r --arg id "$NEXT_ID" '.userStories[] | select(.id == $id) | .acceptanceCriteria | join("\n- ")' "$PRD_FILE")
411
393
 
@@ -420,21 +402,13 @@ If ANY fails: REVIEW_FAIL: [reason]
420
402
  If all pass: REVIEW_PASS"
421
403
 
422
404
  set +e
423
- claude -p --dangerously-skip-permissions $LOOP_MCP_ARGS "$REVIEW_PROMPT" > .kai/review-output.tmp 2>&1 &
424
- review_pid=$!
425
-
426
- while kill -0 $review_pid 2>/dev/null; do
427
- sleep 15
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)
405
+ claude -p --output-format stream-json --verbose --dangerously-skip-permissions $LOOP_MCP_ARGS \
406
+ "$REVIEW_PROMPT" 2>&1 | \
407
+ tee .kai/review-stream.tmp | \
408
+ jq --unbuffered -r "$STREAM_FILTER" 2>/dev/null
409
+ review=$(jq -r 'select(.type == "result") | .result // empty' .kai/review-stream.tmp 2>/dev/null)
434
410
  set -e
435
411
 
436
- echo "$review" | tail -5
437
-
438
412
  if [[ "$review" == *"REVIEW_FAIL"* ]]; then
439
413
  jq --arg id "$NEXT_ID" '(.userStories[] | select(.id == $id)).passes = false' "$PRD_FILE" > "${PRD_FILE}.tmp" && mv "${PRD_FILE}.tmp" "$PRD_FILE"
440
414
  echo "REVIEW FEEDBACK: $review" >> "$PROGRESS_FILE"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kraftapps-ai/kai",
3
- "version": "1.8.7",
3
+ "version": "1.9.1",
4
4
  "description": "Autonomous AI developer loop for Claude Code",
5
5
  "bin": {
6
6
  "kai": "kai"