juno-code 1.0.41 → 1.0.42
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/dist/bin/cli.js +1 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/cli.mjs +1 -0
- package/dist/bin/cli.mjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/templates/scripts/install_requirements.sh +3 -4
- package/dist/templates/scripts/run_until_completion.sh +163 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -52,10 +52,9 @@ BLUE='\033[0;34m'
|
|
|
52
52
|
NC='\033[0m' # No Color
|
|
53
53
|
|
|
54
54
|
# Required packages
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
SLACK_PACKAGES=("slack_sdk" "python-dotenv")
|
|
55
|
+
# Note: requests and python-dotenv are required by github.py
|
|
56
|
+
# slack_sdk is required by Slack integration scripts (slack_fetch.py, slack_respond.py)
|
|
57
|
+
REQUIRED_PACKAGES=("juno-kanban" "roundtable-ai" "requests" "python-dotenv" "slack_sdk")
|
|
59
58
|
|
|
60
59
|
# Version check cache configuration
|
|
61
60
|
# This ensures we don't check PyPI on every run (performance optimization per Task RTafs5)
|
|
@@ -4,11 +4,10 @@
|
|
|
4
4
|
#
|
|
5
5
|
# Purpose: Continuously run juno-code until all kanban tasks are completed
|
|
6
6
|
#
|
|
7
|
-
# This script uses a
|
|
8
|
-
# then checks the kanban board for tasks
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# doesn't initially detect any tasks.
|
|
7
|
+
# This script uses a while loop pattern: it ALWAYS runs pre-run hooks/commands,
|
|
8
|
+
# then checks the kanban board for tasks BEFORE running juno-code. If no tasks
|
|
9
|
+
# exist, juno-code is NOT executed. This allows pre-run hooks (e.g., Slack sync,
|
|
10
|
+
# GitHub sync) to create tasks that will then be processed by juno-code.
|
|
12
11
|
#
|
|
13
12
|
# Usage: ./.juno_task/scripts/run_until_completion.sh [options] [juno-code arguments]
|
|
14
13
|
# Example: ./.juno_task/scripts/run_until_completion.sh -s claude -i 5 -v
|
|
@@ -33,6 +32,9 @@
|
|
|
33
32
|
# - Using the flag multiple times: --pre-run-hook A --pre-run-hook B
|
|
34
33
|
# - Comma-separated: --pre-run-hook "A,B,C"
|
|
35
34
|
# - Pipe-separated: --pre-run-hook "A|B|C"
|
|
35
|
+
# --stale-threshold <n> - Number of stale iterations before exiting (default: 3)
|
|
36
|
+
# Set to 0 to disable stale detection
|
|
37
|
+
# --no-stale-check - Alias for --stale-threshold 0
|
|
36
38
|
#
|
|
37
39
|
# All other arguments are forwarded to juno-code.
|
|
38
40
|
# The script shows all stdout/stderr from juno-code in real-time.
|
|
@@ -42,8 +44,16 @@
|
|
|
42
44
|
# JUNO_VERBOSE=true - Show [RUN_UNTIL] informational messages
|
|
43
45
|
# JUNO_PRE_RUN - Alternative way to specify pre-run command (env var)
|
|
44
46
|
# JUNO_PRE_RUN_HOOK - Alternative way to specify pre-run hook name (env var)
|
|
47
|
+
# JUNO_STALE_THRESHOLD - Number of stale iterations before exiting (default: 3)
|
|
48
|
+
# Set to 0 to disable stale detection
|
|
45
49
|
# (JUNO_DEBUG and JUNO_VERBOSE default to false for silent operation)
|
|
46
50
|
#
|
|
51
|
+
# Stale Iteration Detection:
|
|
52
|
+
# The script tracks kanban state (task IDs and statuses) between iterations.
|
|
53
|
+
# If no changes are detected for JUNO_STALE_THRESHOLD consecutive iterations,
|
|
54
|
+
# the script will exit to prevent infinite loops where the agent doesn't
|
|
55
|
+
# process any tasks.
|
|
56
|
+
#
|
|
47
57
|
# Created by: juno-code init command
|
|
48
58
|
# Date: Auto-generated during project initialization
|
|
49
59
|
|
|
@@ -66,6 +76,12 @@ NC='\033[0m' # No Color
|
|
|
66
76
|
SCRIPTS_DIR=".juno_task/scripts"
|
|
67
77
|
KANBAN_SCRIPT="${SCRIPTS_DIR}/kanban.sh"
|
|
68
78
|
|
|
79
|
+
# Stale iteration detection configuration
|
|
80
|
+
# Number of consecutive iterations without kanban changes before exiting
|
|
81
|
+
STALE_THRESHOLD="${JUNO_STALE_THRESHOLD:-3}"
|
|
82
|
+
STALE_COUNTER=0
|
|
83
|
+
PREVIOUS_KANBAN_STATE=""
|
|
84
|
+
|
|
69
85
|
# Arrays to store pre-run commands, hooks, and juno-code arguments
|
|
70
86
|
declare -a PRE_RUN_CMDS=()
|
|
71
87
|
declare -a PRE_RUN_HOOKS=()
|
|
@@ -86,6 +102,22 @@ parse_arguments() {
|
|
|
86
102
|
PRE_RUN_CMDS+=("$2")
|
|
87
103
|
shift 2
|
|
88
104
|
;;
|
|
105
|
+
--stale-threshold)
|
|
106
|
+
if [[ -z "${2:-}" ]]; then
|
|
107
|
+
echo "[ERROR] --stale-threshold requires a number argument" >&2
|
|
108
|
+
exit 1
|
|
109
|
+
fi
|
|
110
|
+
if ! [[ "$2" =~ ^[0-9]+$ ]]; then
|
|
111
|
+
echo "[ERROR] --stale-threshold must be a non-negative integer, got: $2" >&2
|
|
112
|
+
exit 1
|
|
113
|
+
fi
|
|
114
|
+
STALE_THRESHOLD="$2"
|
|
115
|
+
shift 2
|
|
116
|
+
;;
|
|
117
|
+
--no-stale-check)
|
|
118
|
+
STALE_THRESHOLD=0
|
|
119
|
+
shift
|
|
120
|
+
;;
|
|
89
121
|
--pre-run-hook|--pre-run-hooks|--run-pre-hook|--run-pre-hooks)
|
|
90
122
|
if [[ -z "${2:-}" ]]; then
|
|
91
123
|
echo "[ERROR] $1 requires a hook name argument" >&2
|
|
@@ -327,6 +359,63 @@ PROJECT_ROOT="$( cd "$SCRIPT_DIR/../.." && pwd )"
|
|
|
327
359
|
# Change to project root
|
|
328
360
|
cd "$PROJECT_ROOT"
|
|
329
361
|
|
|
362
|
+
# Function to get a snapshot of kanban state for comparison
|
|
363
|
+
# Returns a sorted string of "task_id:status" pairs
|
|
364
|
+
get_kanban_state_snapshot() {
|
|
365
|
+
local snapshot=""
|
|
366
|
+
|
|
367
|
+
# Check if kanban script exists
|
|
368
|
+
if [ ! -f "$KANBAN_SCRIPT" ]; then
|
|
369
|
+
echo ""
|
|
370
|
+
return
|
|
371
|
+
fi
|
|
372
|
+
|
|
373
|
+
# Get all non-done/archive tasks as JSON
|
|
374
|
+
local kanban_output
|
|
375
|
+
if kanban_output=$("$KANBAN_SCRIPT" list --status backlog todo in_progress 2>/dev/null); then
|
|
376
|
+
# Extract just the JSON array part (skip the SUMMARY section)
|
|
377
|
+
local json_part
|
|
378
|
+
json_part=$(echo "$kanban_output" | grep -E '^\[' | head -1)
|
|
379
|
+
|
|
380
|
+
if [[ -z "$json_part" ]]; then
|
|
381
|
+
# Try to find JSON array in the output
|
|
382
|
+
json_part=$(echo "$kanban_output" | sed -n '/^\[/,/^\]/p' | head -1)
|
|
383
|
+
fi
|
|
384
|
+
|
|
385
|
+
# If we have JSON output, extract task IDs and statuses
|
|
386
|
+
if [[ -n "$json_part" ]] && command -v jq &> /dev/null; then
|
|
387
|
+
# Create a deterministic snapshot: sorted "id:status" pairs
|
|
388
|
+
snapshot=$(echo "$kanban_output" | jq -r 'if type == "array" then .[] | "\(.id):\(.status)" else empty end' 2>/dev/null | sort | tr '\n' '|')
|
|
389
|
+
else
|
|
390
|
+
# Fallback: use the raw output as state (less precise but still detects changes)
|
|
391
|
+
snapshot=$(echo "$kanban_output" | grep -E '"id"|"status"' | tr -d ' \n')
|
|
392
|
+
fi
|
|
393
|
+
fi
|
|
394
|
+
|
|
395
|
+
echo "$snapshot"
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
# Function to check if kanban state has changed
|
|
399
|
+
# Returns 0 if state changed, 1 if stale (no change)
|
|
400
|
+
check_kanban_state_changed() {
|
|
401
|
+
local current_state
|
|
402
|
+
current_state=$(get_kanban_state_snapshot)
|
|
403
|
+
|
|
404
|
+
if [ "${JUNO_DEBUG:-false}" = "true" ]; then
|
|
405
|
+
echo "[DEBUG] Previous kanban state: $PREVIOUS_KANBAN_STATE" >&2
|
|
406
|
+
echo "[DEBUG] Current kanban state: $current_state" >&2
|
|
407
|
+
fi
|
|
408
|
+
|
|
409
|
+
if [[ "$current_state" == "$PREVIOUS_KANBAN_STATE" ]]; then
|
|
410
|
+
# State is the same - no changes detected
|
|
411
|
+
return 1
|
|
412
|
+
else
|
|
413
|
+
# State changed
|
|
414
|
+
PREVIOUS_KANBAN_STATE="$current_state"
|
|
415
|
+
return 0
|
|
416
|
+
fi
|
|
417
|
+
}
|
|
418
|
+
|
|
330
419
|
# Function to check if there are tasks remaining
|
|
331
420
|
has_remaining_tasks() {
|
|
332
421
|
log_info "Checking kanban for remaining tasks..."
|
|
@@ -391,19 +480,37 @@ main() {
|
|
|
391
480
|
log_status "Maximum iterations: unlimited"
|
|
392
481
|
fi
|
|
393
482
|
|
|
483
|
+
if [ "$STALE_THRESHOLD" -gt 0 ]; then
|
|
484
|
+
log_status "Stale iteration threshold: $STALE_THRESHOLD"
|
|
485
|
+
else
|
|
486
|
+
log_status "Stale iteration detection: disabled"
|
|
487
|
+
fi
|
|
488
|
+
|
|
489
|
+
# Capture initial kanban state before first iteration
|
|
490
|
+
PREVIOUS_KANBAN_STATE=$(get_kanban_state_snapshot)
|
|
491
|
+
|
|
394
492
|
# Check if we have any arguments for juno-code
|
|
395
493
|
if [[ ${#JUNO_ARGS[@]} -eq 0 ]]; then
|
|
396
494
|
log_warning "No arguments provided. Running juno-code with no arguments."
|
|
397
495
|
fi
|
|
398
496
|
|
|
399
|
-
#
|
|
400
|
-
#
|
|
497
|
+
# ALWAYS execute pre-run hooks and commands before checking for tasks
|
|
498
|
+
# This ensures hooks (e.g., Slack sync, GitHub sync) can create tasks
|
|
499
|
+
# that will then be processed by juno-code
|
|
401
500
|
execute_pre_run_hooks
|
|
402
501
|
execute_pre_run_commands
|
|
403
502
|
|
|
404
|
-
#
|
|
405
|
-
#
|
|
406
|
-
|
|
503
|
+
# Check for tasks BEFORE entering the main loop
|
|
504
|
+
# If no tasks exist after running pre-run hooks, exit gracefully
|
|
505
|
+
if ! has_remaining_tasks; then
|
|
506
|
+
log_success ""
|
|
507
|
+
log_success "=========================================="
|
|
508
|
+
log_success "No tasks found in kanban. Pre-run hooks executed, juno-code skipped."
|
|
509
|
+
log_success "=========================================="
|
|
510
|
+
exit 0
|
|
511
|
+
fi
|
|
512
|
+
|
|
513
|
+
# While loop pattern: Only run juno-code if there are tasks to process
|
|
407
514
|
while true; do
|
|
408
515
|
iteration=$((iteration + 1))
|
|
409
516
|
|
|
@@ -425,7 +532,6 @@ main() {
|
|
|
425
532
|
log_status "------------------------------------------"
|
|
426
533
|
|
|
427
534
|
# Run juno-code with parsed arguments (excluding --pre-run which was already processed)
|
|
428
|
-
# We run juno-code FIRST (do-while pattern), then check for remaining tasks
|
|
429
535
|
if juno-code "${JUNO_ARGS[@]}"; then
|
|
430
536
|
log_success "juno-code completed successfully"
|
|
431
537
|
else
|
|
@@ -441,9 +547,52 @@ main() {
|
|
|
441
547
|
# Small delay to prevent rapid-fire execution and allow user to Ctrl+C if needed
|
|
442
548
|
sleep 1
|
|
443
549
|
|
|
444
|
-
# Check for
|
|
445
|
-
# This
|
|
446
|
-
|
|
550
|
+
# Check for stale iterations (no kanban state changes)
|
|
551
|
+
# This prevents infinite loops where agent doesn't process any tasks
|
|
552
|
+
if [ "$STALE_THRESHOLD" -gt 0 ]; then
|
|
553
|
+
if check_kanban_state_changed; then
|
|
554
|
+
# State changed - reset the stale counter
|
|
555
|
+
STALE_COUNTER=0
|
|
556
|
+
log_info "Kanban state changed. Stale counter reset."
|
|
557
|
+
else
|
|
558
|
+
# State unchanged - increment stale counter
|
|
559
|
+
STALE_COUNTER=$((STALE_COUNTER + 1))
|
|
560
|
+
log_warning "No kanban changes detected. Stale iteration count: $STALE_COUNTER/$STALE_THRESHOLD"
|
|
561
|
+
|
|
562
|
+
if [ "$STALE_COUNTER" -ge "$STALE_THRESHOLD" ]; then
|
|
563
|
+
log_error ""
|
|
564
|
+
log_error "=========================================="
|
|
565
|
+
log_error "STALE ITERATION LIMIT REACHED"
|
|
566
|
+
log_error "=========================================="
|
|
567
|
+
log_error ""
|
|
568
|
+
log_error "The script has run $STALE_COUNTER consecutive iterations"
|
|
569
|
+
log_error "without any changes to the kanban board state."
|
|
570
|
+
log_error ""
|
|
571
|
+
log_error "This typically happens when:"
|
|
572
|
+
log_error " 1. The agent doesn't recognize or prioritize remaining tasks"
|
|
573
|
+
log_error " 2. Tasks are stuck in a state the agent cannot process"
|
|
574
|
+
log_error " 3. There's a configuration or prompt issue"
|
|
575
|
+
log_error ""
|
|
576
|
+
log_error "Remaining tasks are still in the kanban system but"
|
|
577
|
+
log_error "the agent is not making progress on them."
|
|
578
|
+
log_error ""
|
|
579
|
+
log_error "To adjust this threshold, set JUNO_STALE_THRESHOLD"
|
|
580
|
+
log_error "environment variable (current: $STALE_THRESHOLD, default: 3)"
|
|
581
|
+
log_error "Set to 0 to disable stale detection."
|
|
582
|
+
log_error ""
|
|
583
|
+
log_error "=========================================="
|
|
584
|
+
# Also print to stdout so it's visible in all contexts
|
|
585
|
+
echo ""
|
|
586
|
+
echo "STALE ITERATION LIMIT REACHED: No kanban changes detected for $STALE_COUNTER iterations."
|
|
587
|
+
echo "The agent is not processing remaining tasks. Exiting to prevent infinite loop."
|
|
588
|
+
echo "Set JUNO_STALE_THRESHOLD=0 to disable this check, or increase the threshold value."
|
|
589
|
+
echo ""
|
|
590
|
+
exit 2
|
|
591
|
+
fi
|
|
592
|
+
fi
|
|
593
|
+
fi
|
|
594
|
+
|
|
595
|
+
# Check for remaining tasks AFTER running juno-code
|
|
447
596
|
if ! has_remaining_tasks; then
|
|
448
597
|
log_success ""
|
|
449
598
|
log_success "=========================================="
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "juno-code",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.42",
|
|
4
4
|
"description": "Ralph Wiggum meet Kanban! Ralph style execution for [Claude Code, Codex, Gemini, Cursor]. One task per iteration, automatic progress tracking, and git commits. Set it and let it run.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ralph",
|