all-for-claudecode 2.4.0 → 2.6.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.
@@ -0,0 +1,142 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ # Triage Metadata Collector: Gathers PR and issue metadata via gh CLI
5
+ #
6
+ # Usage: afc-triage.sh [--pr|--issue|--all|#N #M ...]
7
+ # --pr Collect PRs only
8
+ # --issue Collect issues only
9
+ # --all Collect both (default)
10
+ # #N #M Collect specific items by number
11
+ #
12
+ # Output: JSON object with "prs" and "issues" arrays to stdout
13
+ # Exit 0: success
14
+ # Exit 1: gh CLI not available or API error
15
+
16
+ # shellcheck disable=SC2329
17
+ cleanup() {
18
+ :
19
+ }
20
+ trap cleanup EXIT
21
+
22
+ # ── Check prerequisites ──────────────────────────────────
23
+
24
+ if ! command -v gh >/dev/null 2>&1; then
25
+ printf '[afc:triage] Error: gh CLI not found. Install from https://cli.github.com/\n' >&2
26
+ exit 1
27
+ fi
28
+
29
+ if ! gh auth status >/dev/null 2>&1; then
30
+ printf '[afc:triage] Error: gh not authenticated. Run: gh auth login\n' >&2
31
+ exit 1
32
+ fi
33
+
34
+ # ── Parse arguments ──────────────────────────────────────
35
+
36
+ MODE="all"
37
+ SPECIFIC_NUMBERS=()
38
+ DEEP_FLAG="false"
39
+
40
+ for arg in "$@"; do
41
+ case "$arg" in
42
+ --pr) MODE="pr" ;;
43
+ --issue) MODE="issue" ;;
44
+ --all) MODE="all" ;;
45
+ --deep) DEEP_FLAG="true" ;;
46
+ \#*)
47
+ # Strip leading # and add number
48
+ num="${arg#\#}"
49
+ if [[ "$num" =~ ^[0-9]+$ ]]; then
50
+ SPECIFIC_NUMBERS+=("$num")
51
+ fi
52
+ ;;
53
+ *)
54
+ # Try as plain number
55
+ if [[ "$arg" =~ ^[0-9]+$ ]]; then
56
+ SPECIFIC_NUMBERS+=("$arg")
57
+ fi
58
+ ;;
59
+ esac
60
+ done
61
+
62
+ # ── Collect metadata ─────────────────────────────────────
63
+
64
+ PR_JSON="[]"
65
+ ISSUE_JSON="[]"
66
+
67
+ if [ ${#SPECIFIC_NUMBERS[@]} -gt 0 ]; then
68
+ # Specific items: try each as PR first, then as issue
69
+ PR_ITEMS="[]"
70
+ ISSUE_ITEMS="[]"
71
+
72
+ for num in "${SPECIFIC_NUMBERS[@]}"; do
73
+ # Try as PR
74
+ pr_data=""
75
+ pr_data=$(gh pr view "$num" --json number,title,headRefName,author,labels,additions,deletions,changedFiles,createdAt,updatedAt,reviewDecision,isDraft 2>/dev/null || true)
76
+
77
+ if [ -n "$pr_data" ]; then
78
+ if command -v jq >/dev/null 2>&1; then
79
+ PR_ITEMS=$(printf '%s\n' "$PR_ITEMS" | jq --argjson item "$pr_data" '. + [$item]')
80
+ else
81
+ # Fallback: accumulate newline-delimited JSON objects
82
+ if [ "$PR_ITEMS" = "[]" ]; then
83
+ PR_ITEMS="$pr_data"
84
+ else
85
+ PR_ITEMS="$PR_ITEMS
86
+ $pr_data"
87
+ fi
88
+ fi
89
+ else
90
+ # Try as issue
91
+ issue_data=""
92
+ issue_data=$(gh issue view "$num" --json number,title,labels,author,createdAt,updatedAt,comments 2>/dev/null || true)
93
+
94
+ if [ -n "$issue_data" ]; then
95
+ if command -v jq >/dev/null 2>&1; then
96
+ ISSUE_ITEMS=$(printf '%s\n' "$ISSUE_ITEMS" | jq --argjson item "$issue_data" '. + [$item]')
97
+ else
98
+ # Fallback: accumulate newline-delimited JSON objects
99
+ if [ "$ISSUE_ITEMS" = "[]" ]; then
100
+ ISSUE_ITEMS="$issue_data"
101
+ else
102
+ ISSUE_ITEMS="$ISSUE_ITEMS
103
+ $issue_data"
104
+ fi
105
+ fi
106
+ else
107
+ printf '[afc:triage] Warning: #%s not found as PR or issue\n' "$num" >&2
108
+ fi
109
+ fi
110
+ done
111
+
112
+ PR_JSON="$PR_ITEMS"
113
+ ISSUE_JSON="$ISSUE_ITEMS"
114
+ else
115
+ # Bulk collection by mode
116
+ if [ "$MODE" = "pr" ] || [ "$MODE" = "all" ]; then
117
+ PR_JSON=$(gh pr list --json number,title,headRefName,author,labels,additions,deletions,changedFiles,createdAt,updatedAt,reviewDecision,isDraft --limit 50 2>/dev/null || printf '[]')
118
+ fi
119
+
120
+ if [ "$MODE" = "issue" ] || [ "$MODE" = "all" ]; then
121
+ ISSUE_JSON=$(gh issue list --json number,title,labels,author,createdAt,updatedAt,comments --limit 50 2>/dev/null || printf '[]')
122
+ fi
123
+ fi
124
+
125
+ # ── Build output ─────────────────────────────────────────
126
+
127
+ if command -v jq >/dev/null 2>&1; then
128
+ jq -n \
129
+ --argjson prs "$PR_JSON" \
130
+ --argjson issues "$ISSUE_JSON" \
131
+ --arg deep "$DEEP_FLAG" \
132
+ '{prs: $prs, issues: $issues, deep: ($deep == "true"), collectedAt: now | todate}'
133
+ else
134
+ # Fallback: construct JSON manually
135
+ printf '{"prs":%s,"issues":%s,"deep":%s,"collectedAt":"%s"}\n' \
136
+ "$PR_JSON" \
137
+ "$ISSUE_JSON" \
138
+ "$DEEP_FLAG" \
139
+ "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
140
+ fi
141
+
142
+ exit 0
@@ -1,9 +1,10 @@
1
1
  #!/bin/bash
2
2
  set -euo pipefail
3
3
 
4
- # UserPromptSubmit Hook: Inject pipeline Phase/Feature context on every prompt
5
- # Also tracks prompt count and injects drift checkpoint at thresholds
6
- # Exit 0 immediately if pipeline is inactive (minimize overhead)
4
+ # UserPromptSubmit Hook: Two modes of operation:
5
+ # 1. Pipeline INACTIVE: No action (routing handled by CLAUDE.md intent-based skill table)
6
+ # 2. Pipeline ACTIVE: Inject Phase/Feature context + drift checkpoint at thresholds
7
+ # Exit 0 immediately if no action needed (minimize overhead)
7
8
 
8
9
  # shellcheck source=afc-state.sh
9
10
  . "$(dirname "$0")/afc-state.sh"
@@ -17,11 +18,15 @@ trap cleanup EXIT
17
18
  # Consume stdin (required -- pipe breaks if not consumed)
18
19
  cat > /dev/null
19
20
 
20
- # Exit silently if pipeline is inactive
21
+ # --- Branch: Pipeline INACTIVE no action needed ---
22
+ # Routing is handled by CLAUDE.md intent-based skill routing table.
23
+ # The main model classifies user intent natively — no hook-level keyword matching.
21
24
  if ! afc_state_is_active; then
22
25
  exit 0
23
26
  fi
24
27
 
28
+ # --- Branch: Pipeline ACTIVE → existing Phase/Feature context ---
29
+
25
30
  # Read Feature/Phase + JSON-safe processing (strip special characters)
26
31
  FEATURE="$(afc_state_read feature || echo '')"
27
32
  FEATURE="$(printf '%s' "$FEATURE" | tr -d '"' | cut -c1-100)"
@@ -79,14 +79,14 @@ fi
79
79
  # Guard against empty lists
80
80
  if [ -n "$MODIFIED" ]; then
81
81
  # shellcheck disable=SC2001
82
- MODIFIED_LIST=$(echo "$MODIFIED" | sed 's/^/ - /')
82
+ MODIFIED_LIST=$(printf '%s\n' "$MODIFIED" | sed 's/^/ - /')
83
83
  else
84
84
  MODIFIED_LIST=" (none)"
85
85
  fi
86
86
 
87
87
  if [ -n "$STAGED" ]; then
88
88
  # shellcheck disable=SC2001
89
- STAGED_LIST=$(echo "$STAGED" | sed 's/^/ - /')
89
+ STAGED_LIST=$(printf '%s\n' "$STAGED" | sed 's/^/ - /')
90
90
  else
91
91
  STAGED_LIST=" (none)"
92
92
  fi
@@ -49,6 +49,32 @@ if afc_state_is_active; then
49
49
  if [ -n "$CI_TIMESTAMP" ]; then
50
50
  OUTPUT="$OUTPUT | Last CI: PASSED ($CI_TIMESTAMP)"
51
51
  fi
52
+ elif [ -f "$PROJECT_DIR/.claude/.afc-state.json" ]; then
53
+ # 1a. Zombie state cleanup — file exists but afc_state_is_active returned false
54
+ rm -f "$PROJECT_DIR/.claude/.afc-state.json"
55
+ OUTPUT="${OUTPUT:+$OUTPUT | }[ZOMBIE STATE CLEANED] Removed invalid .afc-state.json"
56
+ fi
57
+
58
+ # 1b. Version mismatch detection
59
+ PLUGIN_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
60
+ if [ -f "$PLUGIN_ROOT/package.json" ]; then
61
+ # Read plugin version
62
+ if command -v jq >/dev/null 2>&1; then
63
+ PLUGIN_VERSION=$(jq -r '.version // empty' "$PLUGIN_ROOT/package.json" 2>/dev/null || true)
64
+ else
65
+ PLUGIN_VERSION=$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' "$PLUGIN_ROOT/package.json" 2>/dev/null | head -1 | sed 's/.*: *"//;s/"//') || true
66
+ fi
67
+
68
+ if [ -n "${PLUGIN_VERSION:-}" ]; then
69
+ # Read AFC block version from global CLAUDE.md
70
+ GLOBAL_CLAUDE="$HOME/.claude/CLAUDE.md"
71
+ if [ -f "$GLOBAL_CLAUDE" ]; then
72
+ BLOCK_VERSION=$(grep -o 'AFC:VERSION:[0-9][0-9.]*' "$GLOBAL_CLAUDE" 2>/dev/null | head -1 | sed 's/AFC:VERSION://' || true)
73
+ if [ -n "${BLOCK_VERSION:-}" ] && [ "$BLOCK_VERSION" != "$PLUGIN_VERSION" ]; then
74
+ OUTPUT="${OUTPUT:+$OUTPUT | }[AFC VERSION MISMATCH] v$PLUGIN_VERSION installed but CLAUDE.md block is v$BLOCK_VERSION. Run /afc:init to update."
75
+ fi
76
+ fi
77
+ fi
52
78
  fi
53
79
 
54
80
  # 2. Check if checkpoint exists (project-local first, fallback to auto-memory)
@@ -62,7 +88,7 @@ fi
62
88
 
63
89
  if [ -n "$CHECKPOINT_FILE" ]; then
64
90
  RAW_LINE=$(grep 'Auto-generated:' "$CHECKPOINT_FILE" 2>/dev/null || echo "")
65
- FIRST_LINE=$(echo "$RAW_LINE" | head -1)
91
+ FIRST_LINE=$(printf '%s\n' "$RAW_LINE" | head -1)
66
92
  CHECKPOINT_DATE="${FIRST_LINE##*Auto-generated: }"
67
93
  if [ -n "$CHECKPOINT_DATE" ]; then
68
94
  if [ -n "$OUTPUT" ]; then
@@ -14,14 +14,14 @@ cleanup() {
14
14
  }
15
15
  trap cleanup EXIT
16
16
 
17
+ # Consume stdin immediately (prevents SIGPIPE if exiting early)
18
+ INPUT=$(cat)
19
+
17
20
  # If pipeline is inactive -> skip
18
21
  if ! afc_state_is_active; then
19
22
  exit 0
20
23
  fi
21
24
 
22
- # Parse tool input from stdin
23
- INPUT=$(cat)
24
-
25
25
  # Skip if stdin is empty
26
26
  if [ -z "$INPUT" ]; then
27
27
  exit 0