all-for-claudecode 2.0.0 → 2.2.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.
Files changed (67) hide show
  1. package/.claude-plugin/marketplace.json +4 -4
  2. package/.claude-plugin/plugin.json +3 -4
  3. package/MIGRATION.md +10 -7
  4. package/README.md +68 -119
  5. package/agents/afc-architect.md +16 -0
  6. package/agents/afc-impl-worker.md +40 -0
  7. package/agents/afc-security.md +11 -0
  8. package/bin/cli.mjs +1 -1
  9. package/commands/analyze.md +6 -7
  10. package/commands/architect.md +5 -7
  11. package/commands/auto.md +355 -102
  12. package/commands/checkpoint.md +3 -4
  13. package/commands/clarify.md +8 -1
  14. package/commands/debug.md +40 -3
  15. package/commands/doctor.md +12 -13
  16. package/commands/ideate.md +191 -0
  17. package/commands/implement.md +211 -66
  18. package/commands/init.md +76 -61
  19. package/commands/launch.md +181 -0
  20. package/commands/plan.md +86 -22
  21. package/commands/principles.md +6 -2
  22. package/commands/resume.md +1 -2
  23. package/commands/review.md +68 -18
  24. package/commands/security.md +10 -13
  25. package/commands/spec.md +60 -3
  26. package/commands/tasks.md +19 -4
  27. package/commands/test.md +24 -6
  28. package/docs/phase-gate-protocol.md +6 -6
  29. package/hooks/hooks.json +29 -3
  30. package/package.json +19 -11
  31. package/schemas/hooks.schema.json +75 -0
  32. package/schemas/marketplace.schema.json +52 -0
  33. package/schemas/plugin.schema.json +53 -0
  34. package/scripts/afc-bash-guard.sh +6 -6
  35. package/scripts/afc-blast-radius.sh +418 -0
  36. package/scripts/afc-config-change.sh +6 -4
  37. package/scripts/afc-consistency-check.sh +261 -0
  38. package/scripts/afc-dag-validate.mjs +94 -0
  39. package/scripts/afc-dag-validate.sh +142 -0
  40. package/scripts/afc-failure-hint.sh +6 -4
  41. package/scripts/afc-parallel-validate.mjs +81 -0
  42. package/scripts/afc-parallel-validate.sh +33 -45
  43. package/scripts/afc-permission-request.sh +56 -11
  44. package/scripts/afc-pipeline-manage.sh +46 -46
  45. package/scripts/afc-preflight-check.sh +6 -3
  46. package/scripts/afc-schema-validate.sh +225 -0
  47. package/scripts/afc-session-end.sh +5 -5
  48. package/scripts/afc-state.sh +256 -0
  49. package/scripts/afc-stop-gate.sh +32 -24
  50. package/scripts/afc-subagent-context.sh +15 -6
  51. package/scripts/afc-subagent-stop.sh +4 -2
  52. package/scripts/afc-task-completed-gate.sh +19 -25
  53. package/scripts/afc-teammate-idle.sh +9 -14
  54. package/scripts/afc-test-pre-gen.sh +141 -0
  55. package/scripts/afc-timeline-log.sh +9 -6
  56. package/scripts/afc-user-prompt-submit.sh +8 -10
  57. package/scripts/afc-worktree-create.sh +56 -0
  58. package/scripts/afc-worktree-remove.sh +47 -0
  59. package/scripts/install-shellspec.sh +38 -0
  60. package/scripts/pre-compact-checkpoint.sh +6 -4
  61. package/scripts/session-start-context.sh +9 -8
  62. package/scripts/track-afc-changes.sh +6 -9
  63. package/templates/afc.config.template.md +12 -76
  64. package/templates/afc.config.express-api.md +0 -99
  65. package/templates/afc.config.monorepo.md +0 -98
  66. package/templates/afc.config.nextjs-fsd.md +0 -107
  67. package/templates/afc.config.react-spa.md +0 -96
@@ -4,6 +4,9 @@ set -euo pipefail
4
4
  # SubagentStop Hook: Log subagent completion/failure results to pipeline log
5
5
  # Enables pipeline orchestrator to track task progress
6
6
 
7
+ # shellcheck source=afc-state.sh
8
+ . "$(dirname "$0")/afc-state.sh"
9
+
7
10
  # shellcheck disable=SC2329
8
11
  cleanup() {
9
12
  :
@@ -11,7 +14,6 @@ cleanup() {
11
14
  trap cleanup EXIT
12
15
 
13
16
  PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
14
- PIPELINE_FLAG="$PROJECT_DIR/.claude/.afc-active"
15
17
  RESULTS_LOG="$PROJECT_DIR/.claude/.afc-task-results.log"
16
18
 
17
19
  # Read hook data from stdin
@@ -34,7 +36,7 @@ if [ "$STOP_HOOK_ACTIVE" = "true" ]; then
34
36
  fi
35
37
 
36
38
  # Exit silently if pipeline is inactive
37
- if [ ! -f "$PIPELINE_FLAG" ]; then
39
+ if ! afc_state_is_active; then
38
40
  exit 0
39
41
  fi
40
42
 
@@ -5,60 +5,54 @@ set -euo pipefail
5
5
  #
6
6
  # Gap fix: "Prompts are not enforcement" -> Physical enforcement via exit 2
7
7
 
8
+ # shellcheck source=afc-state.sh
9
+ . "$(dirname "$0")/afc-state.sh"
10
+
8
11
  # trap: Preserve exit code on abnormal termination + stderr message
9
12
  # shellcheck disable=SC2329
10
13
  cleanup() {
11
14
  local exit_code=$?
12
15
  if [ "$exit_code" -ne 0 ] && [ "$exit_code" -ne 2 ]; then
13
- echo "AFC TASK GATE: Abnormal exit (exit code: $exit_code)" >&2
16
+ echo "[afc:task-gate] Abnormal exit (code: $exit_code)" >&2
14
17
  fi
15
18
  exit "$exit_code"
16
19
  }
17
20
  trap cleanup EXIT
18
21
 
19
- PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
20
- PIPELINE_FLAG="${PROJECT_DIR}/.claude/.afc-active"
21
- CI_FLAG="${PROJECT_DIR}/.claude/.afc-ci-passed"
22
- PHASE_FLAG="${PROJECT_DIR}/.claude/.afc-phase"
23
-
24
22
  # Consume stdin (required -- pipe breaks if not consumed)
25
23
  cat > /dev/null
26
24
 
27
25
  # If pipeline is not active -> pass through
28
- if [ ! -f "$PIPELINE_FLAG" ]; then
26
+ if ! afc_state_is_active; then
29
27
  exit 0
30
28
  fi
31
29
 
32
- FEATURE="$(head -1 "$PIPELINE_FLAG" | tr -d '\n\r')"
30
+ FEATURE="$(afc_state_read feature || echo '')"
33
31
 
34
- # Check current Phase if phase file exists
35
- CURRENT_PHASE=""
36
- if [ -f "$PHASE_FLAG" ]; then
37
- CURRENT_PHASE="$(head -1 "$PHASE_FLAG" | tr -d '\n\r')"
38
- fi
39
- CURRENT_PHASE="${CURRENT_PHASE:-}"
32
+ # Check current Phase
33
+ CURRENT_PHASE="$(afc_state_read phase || echo '')"
40
34
 
41
- # Spec/Plan/Tasks Phase (1-3) do not require CI -> pass through
42
- case "${CURRENT_PHASE:-}" in
43
- spec|plan|tasks)
44
- exit 0
45
- ;;
46
- esac
35
+ # Preparatory phases do not require CI -> pass through
36
+ if afc_is_ci_exempt "${CURRENT_PHASE:-}"; then
37
+ exit 0
38
+ fi
47
39
 
48
40
  # Implement/Review/Clean Phase (4-6) require CI to pass
49
- if [ ! -f "$CI_FLAG" ]; then
50
- echo "AFC TASK GATE: CI has not been run. Pipeline '${FEATURE:-unknown}' Phase '${CURRENT_PHASE:-unknown}' requires passing the CI gate. Run your CI command and record the timestamp in .claude/.afc-ci-passed." >&2
41
+ CI_TIME="$(afc_state_read ciPassedAt 2>/dev/null || echo '')"
42
+ CI_TIME="$(printf '%s' "$CI_TIME" | tr -dc '0-9')"
43
+ CI_TIME="${CI_TIME:-0}"
44
+
45
+ if [ "$CI_TIME" -eq 0 ]; then
46
+ printf "[afc:task-gate] CI has not been run. Pipeline '%s' Phase '%s' requires CI gate.\n → Run your CI command to pass the gate\n" "${FEATURE:-unknown}" "${CURRENT_PHASE:-unknown}" >&2
51
47
  exit 2
52
48
  fi
53
49
 
54
50
  # Verify CI passed within the last 10 minutes (prevent stale results)
55
- CI_TIME="$(cat "$CI_FLAG" 2>/dev/null | head -1 | tr -dc '0-9' || true)"
56
- CI_TIME="${CI_TIME:-0}"
57
51
  NOW="$(date +%s)"
58
52
  if [ "$CI_TIME" -gt 0 ]; then
59
53
  DIFF=$(( NOW - CI_TIME ))
60
54
  if [ "$DIFF" -gt 600 ]; then
61
- echo "AFC TASK GATE: CI results are stale (${DIFF} seconds ago). Please run your CI command again." >&2
55
+ printf "[afc:task-gate] CI results are stale (%ss ago).\n → Run your CI command again\n" "$DIFF" >&2
62
56
  exit 2
63
57
  fi
64
58
  fi
@@ -5,42 +5,37 @@ set -euo pipefail
5
5
  #
6
6
  # Gap fix: "Prompts are not enforcement" -> Physical enforcement via exit 2
7
7
 
8
+ # shellcheck source=afc-state.sh
9
+ . "$(dirname "$0")/afc-state.sh"
10
+
8
11
  # trap: Preserve exit code on abnormal termination + stderr message
9
12
  # shellcheck disable=SC2329
10
13
  cleanup() {
11
14
  local exit_code=$?
12
15
  if [ "$exit_code" -ne 0 ] && [ "$exit_code" -ne 2 ]; then
13
- echo "AFC TEAMMATE GATE: Abnormal exit (exit code: $exit_code)" >&2
16
+ echo "[afc:teammate] Abnormal exit (code: $exit_code)" >&2
14
17
  fi
15
18
  exit "$exit_code"
16
19
  }
17
20
  trap cleanup EXIT
18
21
 
19
- PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
20
- PIPELINE_FLAG="${PROJECT_DIR}/.claude/.afc-active"
21
- PHASE_FLAG="${PROJECT_DIR}/.claude/.afc-phase"
22
-
23
22
  # Consume stdin (required -- pipe breaks if not consumed)
24
23
  cat > /dev/null
25
24
 
26
25
  # If pipeline is not active -> pass through
27
- if [ ! -f "$PIPELINE_FLAG" ]; then
26
+ if ! afc_state_is_active; then
28
27
  exit 0
29
28
  fi
30
29
 
31
- FEATURE="$(head -1 "$PIPELINE_FLAG" | tr -d '\n\r')"
30
+ FEATURE="$(afc_state_read feature || echo '')"
32
31
 
33
- # Check current Phase if phase file exists
34
- CURRENT_PHASE=""
35
- if [ -f "$PHASE_FLAG" ]; then
36
- CURRENT_PHASE="$(head -1 "$PHASE_FLAG" | tr -d '\n\r')"
37
- fi
38
- CURRENT_PHASE="${CURRENT_PHASE:-}"
32
+ # Check current Phase
33
+ CURRENT_PHASE="$(afc_state_read phase || echo '')"
39
34
 
40
35
  # Block idle during implement/review Phase -> force work to continue
41
36
  case "${CURRENT_PHASE:-}" in
42
37
  implement|review)
43
- echo "AFC TEAMMATE GATE: Pipeline '${FEATURE:-unknown}' Phase '${CURRENT_PHASE:-unknown}' is active. Please complete the task." >&2
38
+ printf "[afc:teammate] Pipeline '%s' Phase '%s' is active.\n → Complete the current task before going idle\n" "${FEATURE:-unknown}" "${CURRENT_PHASE:-unknown}" >&2
44
39
  exit 2
45
40
  ;;
46
41
  *)
@@ -0,0 +1,141 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ # afc-test-pre-gen.sh — Generate ShellSpec test skeletons for testable tasks
5
+ # Reads a tasks.md file, identifies tasks targeting .sh scripts, and generates
6
+ # pending ShellSpec spec files for scripts that lack test coverage.
7
+ #
8
+ # Usage: afc-test-pre-gen.sh <tasks_file> [output_dir]
9
+ # tasks_file : path to a tasks.md file
10
+ # output_dir : directory for generated spec files (default: spec/ relative to project root)
11
+ # Exit: 0 = success, 1 = error
12
+
13
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
14
+
15
+ # shellcheck disable=SC2329
16
+ cleanup() {
17
+ :
18
+ }
19
+ trap cleanup EXIT
20
+
21
+ # --- Argument validation ---
22
+ TASKS_FILE="${1:-}"
23
+ if [ -z "$TASKS_FILE" ]; then
24
+ printf '[afc:test-pre-gen] Usage: %s <tasks_file> [output_dir]\n' "$0" >&2
25
+ exit 1
26
+ fi
27
+
28
+ if [ ! -f "$TASKS_FILE" ]; then
29
+ printf '[afc:test-pre-gen] Error: file not found: %s\n' "$TASKS_FILE" >&2
30
+ exit 1
31
+ fi
32
+
33
+ OUTPUT_DIR="${2:-${PROJECT_DIR}/spec}"
34
+ mkdir -p "$OUTPUT_DIR"
35
+
36
+ # --- Counters ---
37
+ TASKS_ANALYZED=0
38
+ TESTABLE_SH=0
39
+ SKIPPED_NON_SH=0
40
+ ALREADY_EXISTS=0
41
+ GENERATED=0
42
+ GENERATED_FILES=""
43
+
44
+ # --- Parse tasks ---
45
+ # Match lines like: - [ ] T001 ... `scripts/some-name.sh`
46
+ # Also handles: - [x] T001 ... (checked tasks are still analyzed)
47
+ while IFS= read -r line || [ -n "$line" ]; do
48
+ # Only match task lines: - [ ] TNNN or - [x] TNNN
49
+ if ! printf '%s\n' "$line" | grep -qE '^\s*-\s*\[[ xX]\]\s+T[0-9]+'; then
50
+ continue
51
+ fi
52
+
53
+ TASKS_ANALYZED=$((TASKS_ANALYZED + 1))
54
+
55
+ # Extract all backtick-quoted file paths from the line
56
+ # shellcheck disable=SC2207,SC2016
57
+ PATHS=($(printf '%s\n' "$line" | grep -oE '`[^`]+`' | tr -d '`'))
58
+
59
+ if [ ${#PATHS[@]} -eq 0 ]; then
60
+ continue
61
+ fi
62
+
63
+ HAS_SH_TARGET=false
64
+ for fpath in "${PATHS[@]}"; do
65
+ # Only process .sh files under scripts/
66
+ case "$fpath" in
67
+ scripts/*.sh)
68
+ HAS_SH_TARGET=true
69
+ TESTABLE_SH=$((TESTABLE_SH + 1))
70
+
71
+ # Extract script name from path (e.g., scripts/afc-blast-radius.sh -> afc-blast-radius.sh)
72
+ SCRIPT_NAME="${fpath##*/}"
73
+ # Derive spec name (e.g., afc-blast-radius.sh -> afc-blast-radius_spec.sh)
74
+ SPEC_NAME="${SCRIPT_NAME%.sh}_spec.sh"
75
+ SPEC_PATH="${OUTPUT_DIR}/${SPEC_NAME}"
76
+
77
+ # Check if spec already exists
78
+ if [ -f "$SPEC_PATH" ]; then
79
+ ALREADY_EXISTS=$((ALREADY_EXISTS + 1))
80
+ printf '[afc:test-pre-gen] Skip (exists): %s\n' "$SPEC_NAME" >&2
81
+ continue
82
+ fi
83
+
84
+ # Generate ShellSpec skeleton
85
+ cat > "$SPEC_PATH" << SKELETON
86
+ #!/bin/bash
87
+ # shellcheck shell=bash
88
+ # Auto-generated test skeleton for ${SCRIPT_NAME}
89
+ # TODO: Replace Pending examples with real tests
90
+
91
+ Describe "${SCRIPT_NAME}"
92
+ setup() {
93
+ setup_tmpdir TEST_DIR
94
+ }
95
+ cleanup() { cleanup_tmpdir "\$TEST_DIR"; }
96
+ Before "setup"
97
+ After "cleanup"
98
+
99
+ Context "basic usage"
100
+ It "exits 0 on valid input"
101
+ Pending "implement test"
102
+ End
103
+
104
+ It "exits 1 on missing arguments"
105
+ Pending "implement test"
106
+ End
107
+ End
108
+ End
109
+ SKELETON
110
+
111
+ GENERATED=$((GENERATED + 1))
112
+ if [ -n "$GENERATED_FILES" ]; then
113
+ GENERATED_FILES="${GENERATED_FILES}, ${SPEC_NAME}"
114
+ else
115
+ GENERATED_FILES="${SPEC_NAME}"
116
+ fi
117
+ printf '[afc:test-pre-gen] Generated: %s\n' "$SPEC_NAME" >&2
118
+ ;;
119
+ *)
120
+ # Non-.sh file — counted once per task below
121
+ ;;
122
+ esac
123
+ done
124
+
125
+ if [ "$HAS_SH_TARGET" = false ]; then
126
+ SKIPPED_NON_SH=$((SKIPPED_NON_SH + 1))
127
+ fi
128
+ done < "$TASKS_FILE"
129
+
130
+ # --- Summary report ---
131
+ printf 'Test pre-generation:\n'
132
+ printf ' Tasks analyzed: %d\n' "$TASKS_ANALYZED"
133
+ printf ' Testable (.sh): %d\n' "$TESTABLE_SH"
134
+ printf ' Skipped (non-.sh): %d\n' "$SKIPPED_NON_SH"
135
+ printf ' Already exists: %d\n' "$ALREADY_EXISTS"
136
+ printf ' Generated: %d skeletons\n' "$GENERATED"
137
+ if [ -n "$GENERATED_FILES" ]; then
138
+ printf ' Files: %s\n' "$GENERATED_FILES"
139
+ else
140
+ printf ' Files: (none)\n'
141
+ fi
@@ -10,6 +10,9 @@ set -euo pipefail
10
10
  # message: human-readable description
11
11
  # extra_json_fields: optional JSON object string to merge (e.g. '{"tool":"bash"}')
12
12
 
13
+ # shellcheck source=afc-state.sh
14
+ . "$(dirname "$0")/afc-state.sh"
15
+
13
16
  # shellcheck disable=SC2329
14
17
  cleanup() {
15
18
  :
@@ -36,14 +39,14 @@ fi
36
39
  EVENT_TYPE=$(printf '%s' "$EVENT_TYPE" | tr -d '\n\r' | cut -c1-64)
37
40
  MESSAGE=$(printf '%s' "$MESSAGE" | tr -d '\n\r' | cut -c1-500)
38
41
 
39
- # Read pipeline state (gracefully handle missing files)
42
+ # Read pipeline state (gracefully handle missing state)
40
43
  FEATURE="none"
41
44
  PHASE="none"
42
- if [ -f "$FLAG_DIR/.afc-active" ]; then
43
- FEATURE=$(head -1 "$FLAG_DIR/.afc-active" | tr -d '\n\r' | cut -c1-100)
44
- fi
45
- if [ -f "$FLAG_DIR/.afc-phase" ]; then
46
- PHASE=$(head -1 "$FLAG_DIR/.afc-phase" | tr -d '\n\r' | cut -c1-64)
45
+ if afc_state_is_active; then
46
+ FEATURE=$(afc_state_read feature || echo "none")
47
+ FEATURE=$(printf '%s' "$FEATURE" | cut -c1-100)
48
+ PHASE=$(afc_state_read phase || echo "none")
49
+ PHASE=$(printf '%s' "$PHASE" | cut -c1-64)
47
50
  fi
48
51
 
49
52
  # Timestamp (no jq dependency)
@@ -4,30 +4,28 @@ set -euo pipefail
4
4
  # UserPromptSubmit Hook: Inject pipeline Phase/Feature context on every prompt
5
5
  # Exit 0 immediately if pipeline is inactive (minimize overhead)
6
6
 
7
+ # shellcheck source=afc-state.sh
8
+ . "$(dirname "$0")/afc-state.sh"
9
+
7
10
  # shellcheck disable=SC2329
8
11
  cleanup() {
9
12
  :
10
13
  }
11
14
  trap cleanup EXIT
12
15
 
13
- PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
14
- PIPELINE_FLAG="$PROJECT_DIR/.claude/.afc-active"
15
- PHASE_FLAG="$PROJECT_DIR/.claude/.afc-phase"
16
-
17
16
  # Consume stdin (required -- pipe breaks if not consumed)
18
17
  cat > /dev/null
19
18
 
20
19
  # Exit silently if pipeline is inactive
21
- if [ ! -f "$PIPELINE_FLAG" ]; then
20
+ if ! afc_state_is_active; then
22
21
  exit 0
23
22
  fi
24
23
 
25
24
  # Read Feature/Phase + JSON-safe processing (strip special characters)
26
- FEATURE="$(head -1 "$PIPELINE_FLAG" | tr -d '\n\r' | tr -d '"' | cut -c1-100)"
27
- PHASE="unknown"
28
- if [ -f "$PHASE_FLAG" ]; then
29
- PHASE="$(head -1 "$PHASE_FLAG" | tr -d '\n\r' | tr -d '"' | cut -c1-100)"
30
- fi
25
+ FEATURE="$(afc_state_read feature || echo '')"
26
+ FEATURE="$(printf '%s' "$FEATURE" | tr -d '"' | cut -c1-100)"
27
+ PHASE="$(afc_state_read phase || echo 'unknown')"
28
+ PHASE="$(printf '%s' "$PHASE" | tr -d '"' | cut -c1-100)"
31
29
 
32
30
  # Output additionalContext to stdout (injected into Claude context)
33
31
  printf '{"hookSpecificOutput":{"additionalContext":"[Pipeline: %s] [Phase: %s]"}}\n' "$FEATURE" "$PHASE"
@@ -0,0 +1,56 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ # WorktreeCreate Hook: Inject pipeline context into new worktrees
5
+ # Ensures worker worktrees have access to pipeline state and config
6
+
7
+ # shellcheck source=afc-state.sh
8
+ . "$(dirname "$0")/afc-state.sh"
9
+
10
+ # shellcheck disable=SC2329
11
+ cleanup() {
12
+ :
13
+ }
14
+ trap cleanup EXIT
15
+
16
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
17
+
18
+ # Read hook data from stdin
19
+ INPUT=$(cat)
20
+
21
+ # Exit silently if pipeline is inactive
22
+ if ! afc_state_is_active; then
23
+ exit 0
24
+ fi
25
+
26
+ # Parse worktree_path from stdin JSON
27
+ WORKTREE_PATH=""
28
+ if command -v jq &>/dev/null; then
29
+ WORKTREE_PATH=$(printf '%s\n' "$INPUT" | jq -r '.worktree_path // empty' 2>/dev/null || true)
30
+ else
31
+ WORKTREE_PATH=$(printf '%s\n' "$INPUT" | grep -o '"worktree_path"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*:[[:space:]]*"//;s/"$//' 2>/dev/null || true)
32
+ fi
33
+
34
+ # Exit if no worktree path provided
35
+ if [ -z "$WORKTREE_PATH" ]; then
36
+ exit 0
37
+ fi
38
+
39
+ # Read pipeline state
40
+ FEATURE=$(afc_state_read feature || echo "unknown")
41
+ PHASE=$(afc_state_read phase || echo "unknown")
42
+
43
+ # Inject pipeline context into worktree
44
+ CONTEXT="[AFC WORKTREE] Feature: $FEATURE | Phase: ${PHASE:-unknown} | Source: $PROJECT_DIR"
45
+
46
+ # Output as hookSpecificOutput JSON
47
+ if command -v jq &>/dev/null; then
48
+ jq -n --arg ctx "$CONTEXT" \
49
+ '{"hookSpecificOutput":{"additionalContext":$ctx}}' 2>/dev/null || true
50
+ else
51
+ # shellcheck disable=SC1003
52
+ SAFE_CONTEXT=$(printf '%s' "$CONTEXT" | tr -d '"' | tr -d '\\' | cut -c1-2000)
53
+ printf '{"hookSpecificOutput":{"additionalContext":"%s"}}\n' "$SAFE_CONTEXT"
54
+ fi
55
+
56
+ exit 0
@@ -0,0 +1,47 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ # WorktreeRemove Hook: Archive worker results when worktree is removed
5
+ # Ensures task results are preserved in the main project log
6
+
7
+ # shellcheck source=afc-state.sh
8
+ . "$(dirname "$0")/afc-state.sh"
9
+
10
+ # shellcheck disable=SC2329
11
+ cleanup() {
12
+ :
13
+ }
14
+ trap cleanup EXIT
15
+
16
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
17
+ RESULTS_LOG="$PROJECT_DIR/.claude/.afc-task-results.log"
18
+
19
+ # Read hook data from stdin
20
+ INPUT=$(cat)
21
+
22
+ # Exit silently if pipeline is inactive (also handles race condition on pipeline end)
23
+ if ! afc_state_is_active; then
24
+ exit 0
25
+ fi
26
+
27
+ # Parse worktree_path from stdin JSON
28
+ WORKTREE_PATH=""
29
+ if command -v jq &>/dev/null; then
30
+ WORKTREE_PATH=$(printf '%s\n' "$INPUT" | jq -r '.worktree_path // empty' 2>/dev/null || true)
31
+ else
32
+ WORKTREE_PATH=$(printf '%s\n' "$INPUT" | grep -o '"worktree_path"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*:[[:space:]]*"//;s/"$//' 2>/dev/null || true)
33
+ fi
34
+
35
+ # Exit if no worktree path provided
36
+ if [ -z "$WORKTREE_PATH" ]; then
37
+ exit 0
38
+ fi
39
+
40
+ # Archive worktree task results to main project
41
+ WORKTREE_RESULTS="$WORKTREE_PATH/.claude/.afc-task-results.log"
42
+ if [ -f "$WORKTREE_RESULTS" ]; then
43
+ printf '%s\n' "--- worktree: $WORKTREE_PATH ---" >> "$RESULTS_LOG"
44
+ cat "$WORKTREE_RESULTS" >> "$RESULTS_LOG" 2>/dev/null || true
45
+ fi
46
+
47
+ exit 0
@@ -0,0 +1,38 @@
1
+ #!/bin/bash
2
+ # Install ShellSpec locally to vendor/shellspec/
3
+ # Usage: bash scripts/install-shellspec.sh
4
+ set -euo pipefail
5
+
6
+ trap cleanup EXIT
7
+ cleanup() { :; }
8
+
9
+ SHELLSPEC_VERSION="0.28.1"
10
+ PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
11
+ VENDOR_DIR="$PROJECT_ROOT/vendor"
12
+ SHELLSPEC_DIR="$VENDOR_DIR/shellspec"
13
+
14
+ if [ -f "$SHELLSPEC_DIR/shellspec" ]; then
15
+ printf 'ShellSpec %s already installed at %s\n' "$SHELLSPEC_VERSION" "$SHELLSPEC_DIR"
16
+ exit 0
17
+ fi
18
+
19
+ printf 'Installing ShellSpec %s to %s ...\n' "$SHELLSPEC_VERSION" "$SHELLSPEC_DIR"
20
+
21
+ mkdir -p "$VENDOR_DIR"
22
+
23
+ TARBALL_URL="https://github.com/shellspec/shellspec/archive/refs/tags/${SHELLSPEC_VERSION}.tar.gz"
24
+
25
+ if command -v curl >/dev/null 2>&1; then
26
+ curl -fsSL "$TARBALL_URL" | tar -xzf - -C "$VENDOR_DIR"
27
+ elif command -v wget >/dev/null 2>&1; then
28
+ wget -qO - "$TARBALL_URL" | tar -xzf - -C "$VENDOR_DIR"
29
+ else
30
+ printf '[afc] Error: curl or wget is required to install ShellSpec\n' >&2
31
+ exit 1
32
+ fi
33
+
34
+ mv "$VENDOR_DIR/shellspec-${SHELLSPEC_VERSION}" "$SHELLSPEC_DIR"
35
+ chmod +x "$SHELLSPEC_DIR/shellspec"
36
+
37
+ printf 'ShellSpec %s installed successfully at %s\n' "$SHELLSPEC_VERSION" "$SHELLSPEC_DIR"
38
+ printf 'Run tests with: npm test\n'
@@ -5,6 +5,9 @@ set -euo pipefail
5
5
  #
6
6
  # Gap fix: Enforces OMC auto-state-save via physical script
7
7
 
8
+ # shellcheck source=afc-state.sh
9
+ . "$(dirname "$0")/afc-state.sh"
10
+
8
11
  # shellcheck disable=SC2329
9
12
  cleanup() {
10
13
  # Extend here if temporary file cleanup is needed
@@ -50,10 +53,9 @@ if [ -n "$ALL_STAGED" ]; then
50
53
  fi
51
54
 
52
55
  # Check afc pipeline active status
53
- PIPELINE_FLAG="$PROJECT_DIR/.claude/.afc-active"
54
56
  PIPELINE_FEATURE=""
55
- if [ -f "$PIPELINE_FLAG" ]; then
56
- PIPELINE_FEATURE=$(head -1 "$PIPELINE_FLAG" 2>/dev/null | tr -d '\n\r' || true)
57
+ if afc_state_is_active; then
58
+ PIPELINE_FEATURE=$(afc_state_read feature || true)
57
59
  fi
58
60
 
59
61
  # Check tasks.md progress status
@@ -97,7 +99,7 @@ $MODIFIED_LIST
97
99
  $STAGED_LIST
98
100
 
99
101
  ## Pipeline Status
100
- - Active: $([ -f "$PIPELINE_FLAG" ] && echo "Yes ($PIPELINE_FEATURE)" || echo "No")
102
+ - Active: $([ -n "$PIPELINE_FEATURE" ] && echo "Yes ($PIPELINE_FEATURE)" || echo "No")
101
103
  - Task progress: $TASKS_DONE/$TASKS_TOTAL
102
104
 
103
105
  ## Restore Command
@@ -6,11 +6,14 @@ set -euo pipefail
6
6
  #
7
7
  # Gap fix: Enforces OMC session continuity via physical script
8
8
 
9
+ # shellcheck source=afc-state.sh
10
+ . "$(dirname "$0")/afc-state.sh"
11
+
9
12
  # shellcheck disable=SC2329
10
13
  cleanup() {
11
14
  local exit_code=$?
12
15
  if [ "$exit_code" -ne 0 ]; then
13
- echo "[all-for-claudecode] session-start-context.sh exited abnormally" >&2
16
+ echo "[afc:session] session-start-context.sh exited abnormally" >&2
14
17
  fi
15
18
  exit "$exit_code"
16
19
  }
@@ -26,13 +29,11 @@ PROJECT_PATH=$(cd "$PROJECT_DIR" 2>/dev/null && pwd || echo "$PROJECT_DIR")
26
29
  ENCODED_PATH="${PROJECT_PATH//\//-}"
27
30
  MEMORY_DIR="$HOME/.claude/projects/$ENCODED_PATH/memory"
28
31
  CHECKPOINT="$MEMORY_DIR/checkpoint.md"
29
- PIPELINE_FLAG="$PROJECT_DIR/.claude/.afc-active"
30
-
31
32
  OUTPUT=""
32
33
 
33
34
  # 1. Check for active pipeline
34
- if [ -f "$PIPELINE_FLAG" ]; then
35
- FEATURE=$(head -1 "$PIPELINE_FLAG" 2>/dev/null | tr -d '\n\r' || true)
35
+ if afc_state_is_active; then
36
+ FEATURE=$(afc_state_read feature || true)
36
37
  OUTPUT="[AFC PIPELINE ACTIVE] Feature: $FEATURE"
37
38
 
38
39
  # tasks.md progress
@@ -44,9 +45,9 @@ if [ -f "$PIPELINE_FLAG" ]; then
44
45
  fi
45
46
 
46
47
  # CI pass status
47
- CI_FLAG="$PROJECT_DIR/.claude/.afc-ci-passed"
48
- if [ -f "$CI_FLAG" ]; then
49
- OUTPUT="$OUTPUT | Last CI: PASSED ($(cat "$CI_FLAG" 2>/dev/null || true))"
48
+ CI_TIMESTAMP=$(afc_state_read ciPassedAt 2>/dev/null || true)
49
+ if [ -n "$CI_TIMESTAMP" ]; then
50
+ OUTPUT="$OUTPUT | Last CI: PASSED ($CI_TIMESTAMP)"
50
51
  fi
51
52
  fi
52
53
 
@@ -4,10 +4,8 @@ set -euo pipefail
4
4
  # Record changed files after Edit/Write tool usage
5
5
  # Track which files have changed for the CI gate
6
6
 
7
- PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
8
- PIPELINE_FLAG="$PROJECT_DIR/.claude/.afc-active"
9
- CHANGES_LOG="$PROJECT_DIR/.claude/.afc-changes.log"
10
- CI_FLAG="$PROJECT_DIR/.claude/.afc-ci-passed"
7
+ # shellcheck source=afc-state.sh
8
+ . "$(dirname "$0")/afc-state.sh"
11
9
 
12
10
  # shellcheck disable=SC2329
13
11
  cleanup() {
@@ -17,7 +15,7 @@ cleanup() {
17
15
  trap cleanup EXIT
18
16
 
19
17
  # If pipeline is inactive -> skip
20
- if [ ! -f "$PIPELINE_FLAG" ]; then
18
+ if ! afc_state_is_active; then
21
19
  exit 0
22
20
  fi
23
21
 
@@ -37,12 +35,11 @@ else
37
35
  fi
38
36
 
39
37
  if [ -n "$FILE_PATH" ]; then
40
- # Append to change log (deduplicate)
41
- printf '%s\n' "$FILE_PATH" >> "$CHANGES_LOG"
42
- sort -u -o "$CHANGES_LOG" "$CHANGES_LOG"
38
+ # Append to change log (deduplicate handled by afc_state_append_change)
39
+ afc_state_append_change "$FILE_PATH"
43
40
 
44
41
  # Invalidate CI results since a file was changed
45
- rm -f "$CI_FLAG"
42
+ afc_state_invalidate_ci
46
43
  fi
47
44
 
48
45
  exit 0