juno-code 1.0.42 → 1.0.43

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.
@@ -9,6 +9,12 @@
9
9
  #
10
10
  # Usage: ./.juno_task/scripts/kanban.sh [juno-kanban arguments]
11
11
  # Example: ./.juno_task/scripts/kanban.sh list --limit 5
12
+ # Example: ./.juno_task/scripts/kanban.sh list -f json --raw # (flag order normalized)
13
+ # Example: ./.juno_task/scripts/kanban.sh -f json --raw list # (also works)
14
+ #
15
+ # Note: Global flags (-f/--format, -p/--pretty, --raw, -v/--verbose, -c/--config)
16
+ # can be placed anywhere in the command line. This wrapper normalizes them
17
+ # to appear before the command for juno-kanban compatibility.
12
18
  #
13
19
  # Environment Variables:
14
20
  # JUNO_DEBUG=true - Show [DEBUG] diagnostic messages
@@ -170,6 +176,67 @@ PROJECT_ROOT="$( cd "$SCRIPT_DIR/../.." && pwd )"
170
176
  # Change to project root
171
177
  cd "$PROJECT_ROOT"
172
178
 
179
+ # Arrays to store normalized arguments (declared at script level for proper handling)
180
+ declare -a NORMALIZED_GLOBAL_FLAGS=()
181
+ declare -a NORMALIZED_COMMAND_ARGS=()
182
+
183
+ # Normalize argument order for juno-kanban
184
+ # juno-kanban requires global flags BEFORE the command, but users often
185
+ # write them after (e.g., "list -f json --raw" instead of "-f json --raw list")
186
+ # This function reorders arguments so global flags come first.
187
+ # Results are stored in NORMALIZED_GLOBAL_FLAGS and NORMALIZED_COMMAND_ARGS arrays.
188
+ normalize_arguments() {
189
+ # Reset arrays
190
+ NORMALIZED_GLOBAL_FLAGS=()
191
+ NORMALIZED_COMMAND_ARGS=()
192
+ local found_command=false
193
+
194
+ # Known subcommands
195
+ local commands="create search get show update archive mark list merge"
196
+
197
+ while [[ $# -gt 0 ]]; do
198
+ case $1 in
199
+ # Global flags that take a value
200
+ -f|--format|-c|--config)
201
+ if [[ -n "${2:-}" ]]; then
202
+ NORMALIZED_GLOBAL_FLAGS+=("$1" "$2")
203
+ shift 2
204
+ else
205
+ NORMALIZED_GLOBAL_FLAGS+=("$1")
206
+ shift
207
+ fi
208
+ ;;
209
+ # Global flags that don't take a value
210
+ -p|--pretty|--raw|-v|--verbose|-h|--help|--version)
211
+ NORMALIZED_GLOBAL_FLAGS+=("$1")
212
+ shift
213
+ ;;
214
+ # Check if this is a known command
215
+ *)
216
+ # Check if this argument is a known command
217
+ local is_command=false
218
+ for cmd in $commands; do
219
+ if [[ "$1" == "$cmd" ]]; then
220
+ is_command=true
221
+ found_command=true
222
+ break
223
+ fi
224
+ done
225
+
226
+ # If we found a command, everything from here goes to command_args
227
+ if $is_command || $found_command; then
228
+ NORMALIZED_COMMAND_ARGS+=("$1")
229
+ found_command=true
230
+ else
231
+ # Before finding a command, treat as command arg
232
+ NORMALIZED_COMMAND_ARGS+=("$1")
233
+ fi
234
+ shift
235
+ ;;
236
+ esac
237
+ done
238
+ }
239
+
173
240
  # Main kanban logic
174
241
  main() {
175
242
  log_info "=== juno-kanban Wrapper ==="
@@ -182,11 +249,26 @@ main() {
182
249
 
183
250
  log_success "Python environment ready!"
184
251
 
185
- # Execute juno-kanban with all passed arguments from project root
252
+ # Normalize argument order (global flags before command)
253
+ # This allows users to write "list -f json --raw" which gets reordered to "-f json --raw list"
254
+ normalize_arguments "$@"
255
+
256
+ if [ "${JUNO_DEBUG:-false}" = "true" ]; then
257
+ echo "[DEBUG] Original args: $*" >&2
258
+ echo "[DEBUG] Normalized global flags: ${NORMALIZED_GLOBAL_FLAGS[*]:-<none>}" >&2
259
+ echo "[DEBUG] Normalized command args: ${NORMALIZED_COMMAND_ARGS[*]:-<none>}" >&2
260
+ fi
261
+
262
+ # Execute juno-kanban with normalized arguments from project root
186
263
  # Close stdin (redirect from /dev/null) to prevent hanging when called from tools
187
264
  # that don't provide stdin (similar to Issue #42 hook fix)
188
- log_info "Executing juno-kanban: $*"
189
- juno-kanban "$@" < /dev/null
265
+ # Build the command properly preserving argument quoting
266
+ log_info "Executing juno-kanban with normalized arguments"
267
+
268
+ # Execute with proper array expansion to preserve quoting
269
+ # Use ${arr[@]+"${arr[@]}"} pattern to handle empty arrays with set -u
270
+ juno-kanban ${NORMALIZED_GLOBAL_FLAGS[@]+"${NORMALIZED_GLOBAL_FLAGS[@]}"} \
271
+ ${NORMALIZED_COMMAND_ARGS[@]+"${NORMALIZED_COMMAND_ARGS[@]}"} < /dev/null
190
272
  }
191
273
 
192
274
  # Run main function with all arguments
@@ -360,7 +360,9 @@ PROJECT_ROOT="$( cd "$SCRIPT_DIR/../.." && pwd )"
360
360
  cd "$PROJECT_ROOT"
361
361
 
362
362
  # Function to get a snapshot of kanban state for comparison
363
- # Returns a sorted string of "task_id:status" pairs
363
+ # Uses the summary statistics (total_tasks + status_counts) as a reliable indicator
364
+ # of kanban state changes. This approach is more robust than parsing multi-line JSON
365
+ # which can contain control characters that break jq parsing.
364
366
  get_kanban_state_snapshot() {
365
367
  local snapshot=""
366
368
 
@@ -370,24 +372,44 @@ get_kanban_state_snapshot() {
370
372
  return
371
373
  fi
372
374
 
373
- # Get all non-done/archive tasks as JSON
375
+ # Use --raw format for cleaner JSON output
376
+ # The --raw flag outputs: line 1 = tasks array, line 2 = summary object
374
377
  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
378
+ if kanban_output=$("$KANBAN_SCRIPT" -f json --raw list --status backlog todo in_progress 2>/dev/null); then
379
+ if command -v jq &> /dev/null; then
380
+ # Extract the summary line (last line of --raw output)
381
+ local summary_line
382
+ summary_line=$(echo "$kanban_output" | tail -1)
383
+
384
+ # Extract status counts from summary - this is a reliable state indicator
385
+ # Format: "backlog:N|done:N|in_progress:N|todo:N|archive:N|total:N"
386
+ local summary_snapshot=""
387
+ if [[ -n "$summary_line" ]] && echo "$summary_line" | grep -q '"summary"'; then
388
+ summary_snapshot=$(echo "$summary_line" | jq -r '
389
+ .summary |
390
+ "backlog:\(.status_counts.backlog // 0)|" +
391
+ "todo:\(.status_counts.todo // 0)|" +
392
+ "in_progress:\(.status_counts.in_progress // 0)|" +
393
+ "done:\(.status_counts.done // 0)|" +
394
+ "archive:\(.status_counts.archive // 0)|" +
395
+ "total:\(.total_tasks // 0)"
396
+ ' 2>/dev/null)
397
+ fi
384
398
 
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' '|')
399
+ # Also try to extract task IDs using grep (more robust than jq for multi-line JSON)
400
+ # This catches cases where tasks are added/removed but counts stay the same
401
+ local task_ids=""
402
+ task_ids=$(echo "$kanban_output" | grep -o '"id": *"[^"]*"' | sed 's/"id": *"\([^"]*\)"/\1/' | sort | tr '\n' ',')
403
+
404
+ # Combine summary stats and task IDs for comprehensive state tracking
405
+ if [[ -n "$summary_snapshot" ]]; then
406
+ snapshot="${summary_snapshot}|ids:${task_ids}"
407
+ elif [[ -n "$task_ids" ]]; then
408
+ # Fallback to just task IDs if summary parsing failed
409
+ snapshot="ids:${task_ids}"
410
+ fi
389
411
  else
390
- # Fallback: use the raw output as state (less precise but still detects changes)
412
+ # Fallback without jq: use grep to extract id and status fields
391
413
  snapshot=$(echo "$kanban_output" | grep -E '"id"|"status"' | tr -d ' \n')
392
414
  fi
393
415
  fi
@@ -560,6 +582,11 @@ main() {
560
582
  log_warning "No kanban changes detected. Stale iteration count: $STALE_COUNTER/$STALE_THRESHOLD"
561
583
 
562
584
  if [ "$STALE_COUNTER" -ge "$STALE_THRESHOLD" ]; then
585
+ # Execute ON_STALE hook before exiting
586
+ log_status ""
587
+ log_status "Executing ON_STALE hook due to stale iteration detection"
588
+ execute_hook_commands "ON_STALE"
589
+
563
590
  log_error ""
564
591
  log_error "=========================================="
565
592
  log_error "STALE ITERATION LIMIT REACHED"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juno-code",
3
- "version": "1.0.42",
3
+ "version": "1.0.43",
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",