all-for-claudecode 2.0.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.
- package/.claude-plugin/marketplace.json +21 -0
- package/.claude-plugin/plugin.json +12 -0
- package/LICENSE +21 -0
- package/MIGRATION.md +180 -0
- package/README.md +216 -0
- package/agents/afc-architect.md +49 -0
- package/agents/afc-security.md +49 -0
- package/bin/cli.mjs +111 -0
- package/commands/analyze.md +126 -0
- package/commands/architect.md +142 -0
- package/commands/auto.md +304 -0
- package/commands/checkpoint.md +88 -0
- package/commands/clarify.md +78 -0
- package/commands/debug.md +126 -0
- package/commands/doctor.md +179 -0
- package/commands/implement.md +206 -0
- package/commands/init.md +272 -0
- package/commands/plan.md +195 -0
- package/commands/principles.md +107 -0
- package/commands/research.md +109 -0
- package/commands/resume.md +81 -0
- package/commands/review.md +205 -0
- package/commands/security.md +131 -0
- package/commands/spec.md +149 -0
- package/commands/tasks.md +137 -0
- package/commands/test.md +123 -0
- package/docs/critic-loop-rules.md +104 -0
- package/docs/nfr-templates.md +40 -0
- package/docs/phase-gate-protocol.md +44 -0
- package/hooks/hooks.json +211 -0
- package/package.json +62 -0
- package/scripts/afc-auto-format.sh +70 -0
- package/scripts/afc-bash-guard.sh +85 -0
- package/scripts/afc-config-change.sh +58 -0
- package/scripts/afc-failure-hint.sh +78 -0
- package/scripts/afc-notify.sh +64 -0
- package/scripts/afc-parallel-validate.sh +158 -0
- package/scripts/afc-permission-request.sh +91 -0
- package/scripts/afc-pipeline-manage.sh +186 -0
- package/scripts/afc-preflight-check.sh +195 -0
- package/scripts/afc-session-end.sh +45 -0
- package/scripts/afc-stop-gate.sh +78 -0
- package/scripts/afc-subagent-context.sh +65 -0
- package/scripts/afc-subagent-stop.sh +60 -0
- package/scripts/afc-task-completed-gate.sh +66 -0
- package/scripts/afc-teammate-idle.sh +49 -0
- package/scripts/afc-timeline-log.sh +97 -0
- package/scripts/afc-user-prompt-submit.sh +35 -0
- package/scripts/pre-compact-checkpoint.sh +112 -0
- package/scripts/session-start-context.sh +80 -0
- package/scripts/track-afc-changes.sh +48 -0
- package/templates/afc.config.express-api.md +99 -0
- package/templates/afc.config.monorepo.md +98 -0
- package/templates/afc.config.nextjs-fsd.md +107 -0
- package/templates/afc.config.react-spa.md +96 -0
- package/templates/afc.config.template.md +90 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
# TaskCompleted Gate Hook: Block task completion while pipeline is active and CI has not passed
|
|
4
|
+
# Physically prevents Claude from skipping CI and completing a task
|
|
5
|
+
#
|
|
6
|
+
# Gap fix: "Prompts are not enforcement" -> Physical enforcement via exit 2
|
|
7
|
+
|
|
8
|
+
# trap: Preserve exit code on abnormal termination + stderr message
|
|
9
|
+
# shellcheck disable=SC2329
|
|
10
|
+
cleanup() {
|
|
11
|
+
local exit_code=$?
|
|
12
|
+
if [ "$exit_code" -ne 0 ] && [ "$exit_code" -ne 2 ]; then
|
|
13
|
+
echo "AFC TASK GATE: Abnormal exit (exit code: $exit_code)" >&2
|
|
14
|
+
fi
|
|
15
|
+
exit "$exit_code"
|
|
16
|
+
}
|
|
17
|
+
trap cleanup EXIT
|
|
18
|
+
|
|
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
|
+
# Consume stdin (required -- pipe breaks if not consumed)
|
|
25
|
+
cat > /dev/null
|
|
26
|
+
|
|
27
|
+
# If pipeline is not active -> pass through
|
|
28
|
+
if [ ! -f "$PIPELINE_FLAG" ]; then
|
|
29
|
+
exit 0
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
FEATURE="$(head -1 "$PIPELINE_FLAG" | tr -d '\n\r')"
|
|
33
|
+
|
|
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:-}"
|
|
40
|
+
|
|
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
|
|
47
|
+
|
|
48
|
+
# 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
|
|
51
|
+
exit 2
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
# 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
|
+
NOW="$(date +%s)"
|
|
58
|
+
if [ "$CI_TIME" -gt 0 ]; then
|
|
59
|
+
DIFF=$(( NOW - CI_TIME ))
|
|
60
|
+
if [ "$DIFF" -gt 600 ]; then
|
|
61
|
+
echo "AFC TASK GATE: CI results are stale (${DIFF} seconds ago). Please run your CI command again." >&2
|
|
62
|
+
exit 2
|
|
63
|
+
fi
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
exit 0
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
# TeammateIdle Hook: Block idle during implement/review Phase while pipeline is active
|
|
4
|
+
# Physically prevents Claude from stopping mid-task
|
|
5
|
+
#
|
|
6
|
+
# Gap fix: "Prompts are not enforcement" -> Physical enforcement via exit 2
|
|
7
|
+
|
|
8
|
+
# trap: Preserve exit code on abnormal termination + stderr message
|
|
9
|
+
# shellcheck disable=SC2329
|
|
10
|
+
cleanup() {
|
|
11
|
+
local exit_code=$?
|
|
12
|
+
if [ "$exit_code" -ne 0 ] && [ "$exit_code" -ne 2 ]; then
|
|
13
|
+
echo "AFC TEAMMATE GATE: Abnormal exit (exit code: $exit_code)" >&2
|
|
14
|
+
fi
|
|
15
|
+
exit "$exit_code"
|
|
16
|
+
}
|
|
17
|
+
trap cleanup EXIT
|
|
18
|
+
|
|
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
|
+
# Consume stdin (required -- pipe breaks if not consumed)
|
|
24
|
+
cat > /dev/null
|
|
25
|
+
|
|
26
|
+
# If pipeline is not active -> pass through
|
|
27
|
+
if [ ! -f "$PIPELINE_FLAG" ]; then
|
|
28
|
+
exit 0
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
FEATURE="$(head -1 "$PIPELINE_FLAG" | tr -d '\n\r')"
|
|
32
|
+
|
|
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:-}"
|
|
39
|
+
|
|
40
|
+
# Block idle during implement/review Phase -> force work to continue
|
|
41
|
+
case "${CURRENT_PHASE:-}" in
|
|
42
|
+
implement|review)
|
|
43
|
+
echo "AFC TEAMMATE GATE: Pipeline '${FEATURE:-unknown}' Phase '${CURRENT_PHASE:-unknown}' is active. Please complete the task." >&2
|
|
44
|
+
exit 2
|
|
45
|
+
;;
|
|
46
|
+
*)
|
|
47
|
+
exit 0
|
|
48
|
+
;;
|
|
49
|
+
esac
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
# JSONL Event Logger: Appends structured events to .claude/.afc-timeline.jsonl
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# afc-timeline-log.sh <event_type> <message> [extra_json_fields]
|
|
7
|
+
#
|
|
8
|
+
# event_type: phase-start, phase-end, gate-pass, gate-fail, error,
|
|
9
|
+
# pipeline-start, pipeline-end
|
|
10
|
+
# message: human-readable description
|
|
11
|
+
# extra_json_fields: optional JSON object string to merge (e.g. '{"tool":"bash"}')
|
|
12
|
+
|
|
13
|
+
# shellcheck disable=SC2329
|
|
14
|
+
cleanup() {
|
|
15
|
+
:
|
|
16
|
+
}
|
|
17
|
+
trap cleanup EXIT
|
|
18
|
+
|
|
19
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
20
|
+
FLAG_DIR="$PROJECT_DIR/.claude"
|
|
21
|
+
TIMELINE_FILE="$FLAG_DIR/.afc-timeline.jsonl"
|
|
22
|
+
ROTATE_FILE="$FLAG_DIR/.afc-timeline.jsonl.1"
|
|
23
|
+
MAX_BYTES=1048576 # 1 MB
|
|
24
|
+
|
|
25
|
+
EVENT_TYPE="${1:-}"
|
|
26
|
+
MESSAGE="${2:-}"
|
|
27
|
+
EXTRA="${3:-}"
|
|
28
|
+
|
|
29
|
+
# Validate required arguments
|
|
30
|
+
if [ -z "$EVENT_TYPE" ] || [ -z "$MESSAGE" ]; then
|
|
31
|
+
printf 'Usage: %s <event_type> <message> [extra_json_fields]\n' "$0" >&2
|
|
32
|
+
exit 0
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# Sanitize inputs (strip newlines; limit length)
|
|
36
|
+
EVENT_TYPE=$(printf '%s' "$EVENT_TYPE" | tr -d '\n\r' | cut -c1-64)
|
|
37
|
+
MESSAGE=$(printf '%s' "$MESSAGE" | tr -d '\n\r' | cut -c1-500)
|
|
38
|
+
|
|
39
|
+
# Read pipeline state (gracefully handle missing files)
|
|
40
|
+
FEATURE="none"
|
|
41
|
+
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)
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# Timestamp (no jq dependency)
|
|
50
|
+
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
51
|
+
|
|
52
|
+
# Escape a string for JSON (handle backslash, double-quote, and control chars)
|
|
53
|
+
json_escape() {
|
|
54
|
+
printf '%s' "$1" \
|
|
55
|
+
| sed 's/\\/\\\\/g' \
|
|
56
|
+
| sed 's/"/\\"/g' \
|
|
57
|
+
| tr -d '\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017' \
|
|
58
|
+
| tr -d '\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037'
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
TS_ESC=$(json_escape "$TS")
|
|
62
|
+
EVENT_ESC=$(json_escape "$EVENT_TYPE")
|
|
63
|
+
MSG_ESC=$(json_escape "$MESSAGE")
|
|
64
|
+
FEATURE_ESC=$(json_escape "$FEATURE")
|
|
65
|
+
PHASE_ESC=$(json_escape "$PHASE")
|
|
66
|
+
|
|
67
|
+
# Build the base JSON line
|
|
68
|
+
BASE="{\"ts\":\"${TS_ESC}\",\"event\":\"${EVENT_ESC}\",\"msg\":\"${MSG_ESC}\",\"feature\":\"${FEATURE_ESC}\",\"phase\":\"${PHASE_ESC}\"}"
|
|
69
|
+
|
|
70
|
+
# Merge extra JSON fields if provided (append before closing brace)
|
|
71
|
+
if [ -n "$EXTRA" ]; then
|
|
72
|
+
# Strip outer braces from EXTRA and append, only if it looks like a JSON object
|
|
73
|
+
INNER=$(printf '%s' "$EXTRA" | sed 's/^[[:space:]]*{//;s/}[[:space:]]*$//')
|
|
74
|
+
if [ -n "$INNER" ]; then
|
|
75
|
+
LINE="${BASE%\}},${INNER}}"
|
|
76
|
+
else
|
|
77
|
+
LINE="$BASE"
|
|
78
|
+
fi
|
|
79
|
+
else
|
|
80
|
+
LINE="$BASE"
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# Ensure the flag directory exists
|
|
84
|
+
mkdir -p "$FLAG_DIR"
|
|
85
|
+
|
|
86
|
+
# Auto-rotate if the timeline file exceeds MAX_BYTES
|
|
87
|
+
if [ -f "$TIMELINE_FILE" ]; then
|
|
88
|
+
FILE_SIZE=$(wc -c < "$TIMELINE_FILE" | tr -d ' ')
|
|
89
|
+
if [ "$FILE_SIZE" -ge "$MAX_BYTES" ]; then
|
|
90
|
+
mv "$TIMELINE_FILE" "$ROTATE_FILE"
|
|
91
|
+
fi
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
# Append the JSONL line
|
|
95
|
+
printf '%s\n' "$LINE" >> "$TIMELINE_FILE"
|
|
96
|
+
|
|
97
|
+
exit 0
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# UserPromptSubmit Hook: Inject pipeline Phase/Feature context on every prompt
|
|
5
|
+
# Exit 0 immediately if pipeline is inactive (minimize overhead)
|
|
6
|
+
|
|
7
|
+
# shellcheck disable=SC2329
|
|
8
|
+
cleanup() {
|
|
9
|
+
:
|
|
10
|
+
}
|
|
11
|
+
trap cleanup EXIT
|
|
12
|
+
|
|
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
|
+
# Consume stdin (required -- pipe breaks if not consumed)
|
|
18
|
+
cat > /dev/null
|
|
19
|
+
|
|
20
|
+
# Exit silently if pipeline is inactive
|
|
21
|
+
if [ ! -f "$PIPELINE_FLAG" ]; then
|
|
22
|
+
exit 0
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# 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
|
|
31
|
+
|
|
32
|
+
# Output additionalContext to stdout (injected into Claude context)
|
|
33
|
+
printf '{"hookSpecificOutput":{"additionalContext":"[Pipeline: %s] [Phase: %s]"}}\n' "$FEATURE" "$PHASE"
|
|
34
|
+
|
|
35
|
+
exit 0
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
# Pre-Compact Hook: Auto-checkpoint before context compaction
|
|
4
|
+
# Prevents loss of progress state during session interruption/compaction
|
|
5
|
+
#
|
|
6
|
+
# Gap fix: Enforces OMC auto-state-save via physical script
|
|
7
|
+
|
|
8
|
+
# shellcheck disable=SC2329
|
|
9
|
+
cleanup() {
|
|
10
|
+
# Extend here if temporary file cleanup is needed
|
|
11
|
+
:
|
|
12
|
+
}
|
|
13
|
+
trap cleanup EXIT
|
|
14
|
+
|
|
15
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
16
|
+
|
|
17
|
+
# Consume stdin (required -- pipe breaks if not consumed)
|
|
18
|
+
cat > /dev/null
|
|
19
|
+
|
|
20
|
+
# Dynamically derive auto-memory directory from project path
|
|
21
|
+
PROJECT_PATH=$(cd "$PROJECT_DIR" 2>/dev/null && pwd || true)
|
|
22
|
+
PROJECT_PATH="${PROJECT_PATH:-$PROJECT_DIR}"
|
|
23
|
+
ENCODED_PATH="${PROJECT_PATH//\//-}"
|
|
24
|
+
MEMORY_DIR="$HOME/.claude/projects/$ENCODED_PATH/memory"
|
|
25
|
+
CHECKPOINT="$MEMORY_DIR/checkpoint.md"
|
|
26
|
+
|
|
27
|
+
# Create memory directory if it doesn't exist
|
|
28
|
+
mkdir -p "$MEMORY_DIR"
|
|
29
|
+
|
|
30
|
+
# Collect current git status
|
|
31
|
+
BRANCH=$(cd "$PROJECT_DIR" 2>/dev/null && git branch --show-current 2>/dev/null || echo "unknown")
|
|
32
|
+
|
|
33
|
+
ALL_MODIFIED=$(cd "$PROJECT_DIR" 2>/dev/null && git diff --name-only 2>/dev/null || true)
|
|
34
|
+
MODIFIED=$(printf '%s\n' "$ALL_MODIFIED" | head -10)
|
|
35
|
+
|
|
36
|
+
ALL_STAGED=$(cd "$PROJECT_DIR" 2>/dev/null && git diff --cached --name-only 2>/dev/null || true)
|
|
37
|
+
STAGED=$(printf '%s\n' "$ALL_STAGED" | head -10)
|
|
38
|
+
|
|
39
|
+
# Count files (capture into variable instead of piping wc -l)
|
|
40
|
+
MODIFIED_COUNT=0
|
|
41
|
+
if [ -n "$ALL_MODIFIED" ]; then
|
|
42
|
+
MODIFIED_RAW=$(printf '%s\n' "$ALL_MODIFIED" | wc -l)
|
|
43
|
+
MODIFIED_COUNT=$(printf '%s' "$MODIFIED_RAW" | tr -d ' ')
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
STAGED_COUNT=0
|
|
47
|
+
if [ -n "$ALL_STAGED" ]; then
|
|
48
|
+
STAGED_RAW=$(printf '%s\n' "$ALL_STAGED" | wc -l)
|
|
49
|
+
STAGED_COUNT=$(printf '%s' "$STAGED_RAW" | tr -d ' ')
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# Check afc pipeline active status
|
|
53
|
+
PIPELINE_FLAG="$PROJECT_DIR/.claude/.afc-active"
|
|
54
|
+
PIPELINE_FEATURE=""
|
|
55
|
+
if [ -f "$PIPELINE_FLAG" ]; then
|
|
56
|
+
PIPELINE_FEATURE=$(head -1 "$PIPELINE_FLAG" 2>/dev/null | tr -d '\n\r' || true)
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# Check tasks.md progress status
|
|
60
|
+
TASKS_DONE=0
|
|
61
|
+
TASKS_TOTAL=0
|
|
62
|
+
if [ -n "$PIPELINE_FEATURE" ] && [ -d "$PROJECT_DIR/.claude/afc/specs/$PIPELINE_FEATURE" ]; then
|
|
63
|
+
TASKS_FILE="$PROJECT_DIR/.claude/afc/specs/$PIPELINE_FEATURE/tasks.md"
|
|
64
|
+
if [ -f "$TASKS_FILE" ]; then
|
|
65
|
+
TASKS_DONE=$(grep -cE '\[x\]' "$TASKS_FILE" 2>/dev/null || echo 0)
|
|
66
|
+
TASKS_TOTAL=$(grep -cE '\[(x| )\]' "$TASKS_FILE" 2>/dev/null || echo 0)
|
|
67
|
+
fi
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# Guard against empty lists
|
|
71
|
+
if [ -n "$MODIFIED" ]; then
|
|
72
|
+
# shellcheck disable=SC2001
|
|
73
|
+
MODIFIED_LIST=$(echo "$MODIFIED" | sed 's/^/ - /')
|
|
74
|
+
else
|
|
75
|
+
MODIFIED_LIST=" (none)"
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
if [ -n "$STAGED" ]; then
|
|
79
|
+
# shellcheck disable=SC2001
|
|
80
|
+
STAGED_LIST=$(echo "$STAGED" | sed 's/^/ - /')
|
|
81
|
+
else
|
|
82
|
+
STAGED_LIST=" (none)"
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# Write checkpoint.md
|
|
86
|
+
cat > "$CHECKPOINT" << EOF
|
|
87
|
+
# Auto Checkpoint (Pre-Compact)
|
|
88
|
+
> Auto-generated: $(date '+%Y-%m-%d %H:%M:%S')
|
|
89
|
+
> Trigger: context compaction
|
|
90
|
+
|
|
91
|
+
## Git Status
|
|
92
|
+
- Branch: $BRANCH
|
|
93
|
+
- Modified files: ${MODIFIED_COUNT}
|
|
94
|
+
$MODIFIED_LIST
|
|
95
|
+
|
|
96
|
+
## Staged Files (${STAGED_COUNT})
|
|
97
|
+
$STAGED_LIST
|
|
98
|
+
|
|
99
|
+
## Pipeline Status
|
|
100
|
+
- Active: $([ -f "$PIPELINE_FLAG" ] && echo "Yes ($PIPELINE_FEATURE)" || echo "No")
|
|
101
|
+
- Task progress: $TASKS_DONE/$TASKS_TOTAL
|
|
102
|
+
|
|
103
|
+
## Restore Command
|
|
104
|
+
\`\`\`
|
|
105
|
+
/afc:resume
|
|
106
|
+
\`\`\`
|
|
107
|
+
EOF
|
|
108
|
+
|
|
109
|
+
# Inject context via stdout (Claude can see this info after compaction)
|
|
110
|
+
echo "Auto-checkpoint saved to .claude/afc/memory/checkpoint.md (branch: $BRANCH, pipeline: ${PIPELINE_FEATURE:-inactive})"
|
|
111
|
+
|
|
112
|
+
exit 0
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Session Start Hook: Restore pipeline state on session start
|
|
5
|
+
# Inject context so progress state is not lost after resume/compact
|
|
6
|
+
#
|
|
7
|
+
# Gap fix: Enforces OMC session continuity via physical script
|
|
8
|
+
|
|
9
|
+
# shellcheck disable=SC2329
|
|
10
|
+
cleanup() {
|
|
11
|
+
local exit_code=$?
|
|
12
|
+
if [ "$exit_code" -ne 0 ]; then
|
|
13
|
+
echo "[all-for-claudecode] session-start-context.sh exited abnormally" >&2
|
|
14
|
+
fi
|
|
15
|
+
exit "$exit_code"
|
|
16
|
+
}
|
|
17
|
+
trap cleanup EXIT
|
|
18
|
+
|
|
19
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
20
|
+
|
|
21
|
+
# Consume stdin (required -- pipe breaks if not consumed)
|
|
22
|
+
cat > /dev/null
|
|
23
|
+
|
|
24
|
+
# Dynamically derive auto-memory directory from project path
|
|
25
|
+
PROJECT_PATH=$(cd "$PROJECT_DIR" 2>/dev/null && pwd || echo "$PROJECT_DIR")
|
|
26
|
+
ENCODED_PATH="${PROJECT_PATH//\//-}"
|
|
27
|
+
MEMORY_DIR="$HOME/.claude/projects/$ENCODED_PATH/memory"
|
|
28
|
+
CHECKPOINT="$MEMORY_DIR/checkpoint.md"
|
|
29
|
+
PIPELINE_FLAG="$PROJECT_DIR/.claude/.afc-active"
|
|
30
|
+
|
|
31
|
+
OUTPUT=""
|
|
32
|
+
|
|
33
|
+
# 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)
|
|
36
|
+
OUTPUT="[AFC PIPELINE ACTIVE] Feature: $FEATURE"
|
|
37
|
+
|
|
38
|
+
# tasks.md progress
|
|
39
|
+
TASKS_FILE="$PROJECT_DIR/.claude/afc/specs/$FEATURE/tasks.md"
|
|
40
|
+
if [ -f "$TASKS_FILE" ]; then
|
|
41
|
+
DONE=$(grep -cE '\[x\]' "$TASKS_FILE" 2>/dev/null || echo 0)
|
|
42
|
+
TOTAL=$(grep -cE '\[(x| )\]' "$TASKS_FILE" 2>/dev/null || echo 0)
|
|
43
|
+
OUTPUT="$OUTPUT | Tasks: $DONE/$TOTAL"
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# 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))"
|
|
50
|
+
fi
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# 2. Check if checkpoint exists
|
|
54
|
+
if [ -f "$CHECKPOINT" ]; then
|
|
55
|
+
RAW_LINE=$(grep 'Auto-generated:' "$CHECKPOINT" 2>/dev/null || echo "")
|
|
56
|
+
FIRST_LINE=$(echo "$RAW_LINE" | head -1)
|
|
57
|
+
CHECKPOINT_DATE="${FIRST_LINE##*Auto-generated: }"
|
|
58
|
+
if [ -n "$CHECKPOINT_DATE" ]; then
|
|
59
|
+
if [ -n "$OUTPUT" ]; then
|
|
60
|
+
OUTPUT="$OUTPUT | Checkpoint: $CHECKPOINT_DATE"
|
|
61
|
+
else
|
|
62
|
+
OUTPUT="[CHECKPOINT EXISTS] Date: $CHECKPOINT_DATE — Run /afc:resume to restore"
|
|
63
|
+
fi
|
|
64
|
+
fi
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# 3. Check for safety tag
|
|
68
|
+
HAS_SAFETY_TAG=$(cd "$PROJECT_DIR" 2>/dev/null && git tag -l 'afc/pre-*' 2>/dev/null | head -1 || echo "")
|
|
69
|
+
if [ -n "$HAS_SAFETY_TAG" ]; then
|
|
70
|
+
if [ -n "$OUTPUT" ]; then
|
|
71
|
+
OUTPUT="$OUTPUT | Safety tag: $HAS_SAFETY_TAG"
|
|
72
|
+
fi
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
# Output (stdout -> injected into Claude context)
|
|
76
|
+
if [ -n "$OUTPUT" ]; then
|
|
77
|
+
printf '%s\n' "$OUTPUT"
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
exit 0
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
# PostToolUse Hook: Track file changes
|
|
4
|
+
# Record changed files after Edit/Write tool usage
|
|
5
|
+
# Track which files have changed for the CI gate
|
|
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"
|
|
11
|
+
|
|
12
|
+
# shellcheck disable=SC2329
|
|
13
|
+
cleanup() {
|
|
14
|
+
# Placeholder for temporary resource cleanup if needed
|
|
15
|
+
:
|
|
16
|
+
}
|
|
17
|
+
trap cleanup EXIT
|
|
18
|
+
|
|
19
|
+
# If pipeline is inactive -> skip
|
|
20
|
+
if [ ! -f "$PIPELINE_FLAG" ]; then
|
|
21
|
+
exit 0
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
# Parse tool input from stdin
|
|
25
|
+
INPUT=$(cat)
|
|
26
|
+
|
|
27
|
+
# Skip if stdin is empty
|
|
28
|
+
if [ -z "$INPUT" ]; then
|
|
29
|
+
exit 0
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
# Extract file_path with jq if available, otherwise grep/sed fallback
|
|
33
|
+
if command -v jq &> /dev/null; then
|
|
34
|
+
FILE_PATH=$(printf '%s\n' "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null || true)
|
|
35
|
+
else
|
|
36
|
+
FILE_PATH=$(printf '%s\n' "$INPUT" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*:[[:space:]]*"//;s/"$//' 2>/dev/null || true)
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
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"
|
|
43
|
+
|
|
44
|
+
# Invalidate CI results since a file was changed
|
|
45
|
+
rm -f "$CI_FLAG"
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
exit 0
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# AFC Configuration
|
|
2
|
+
|
|
3
|
+
> This file defines project-specific settings for the afc command system.
|
|
4
|
+
> All afc commands reference this file to determine project-specific behavior.
|
|
5
|
+
|
|
6
|
+
## CI Commands
|
|
7
|
+
|
|
8
|
+
```yaml
|
|
9
|
+
ci: "npm run build && npm run lint && npm run test" # Full CI (build + lint + test)
|
|
10
|
+
typecheck: "npx tsc --noEmit" # Typecheck only
|
|
11
|
+
lint: "npx eslint src/" # Lint only
|
|
12
|
+
lint_fix: "npx eslint src/ --fix" # Auto-fix lint
|
|
13
|
+
gate: "npx tsc --noEmit && npx eslint src/" # Phase gate (run repeatedly during implement)
|
|
14
|
+
test: "npx jest --runInBand" # Tests
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Architecture
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
style: "Layered" # Layered architecture
|
|
21
|
+
layers: # Top → bottom order
|
|
22
|
+
- src/routes
|
|
23
|
+
- src/controllers
|
|
24
|
+
- src/services
|
|
25
|
+
- src/repositories
|
|
26
|
+
- src/models
|
|
27
|
+
- src/middleware
|
|
28
|
+
- src/lib
|
|
29
|
+
- src/types
|
|
30
|
+
- src/config
|
|
31
|
+
import_rule: "Upper layers (routes) depend only in order: controllers → services → repositories"
|
|
32
|
+
segments: []
|
|
33
|
+
path_alias: "@/* → ./src/*"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Framework
|
|
37
|
+
|
|
38
|
+
```yaml
|
|
39
|
+
name: "Express.js"
|
|
40
|
+
runtime: "Node.js (CommonJS or ESM)"
|
|
41
|
+
client_directive: "" # Server-only — not applicable
|
|
42
|
+
server_client_boundary: false # Server-only application
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Code Style
|
|
46
|
+
|
|
47
|
+
```yaml
|
|
48
|
+
language: "TypeScript"
|
|
49
|
+
strict_mode: true
|
|
50
|
+
type_keyword: "type" # Use type instead of interface
|
|
51
|
+
import_type: true # Use import type { ... }
|
|
52
|
+
component_style: "" # No UI components
|
|
53
|
+
props_position: "" # No UI components
|
|
54
|
+
handler_naming: "camelCase"
|
|
55
|
+
boolean_naming: "is/has/can[State]"
|
|
56
|
+
constant_naming: "UPPER_SNAKE_CASE"
|
|
57
|
+
any_policy: "banned (use unknown with strict mode)"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## State Management
|
|
61
|
+
|
|
62
|
+
```yaml
|
|
63
|
+
global_state: "" # Server — stateless
|
|
64
|
+
server_state: ""
|
|
65
|
+
local_state: ""
|
|
66
|
+
store_location: ""
|
|
67
|
+
query_location: ""
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Styling
|
|
71
|
+
|
|
72
|
+
```yaml
|
|
73
|
+
framework: "" # Not applicable
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Testing
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
framework: "Jest + Supertest"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Project-Specific Risks
|
|
83
|
+
|
|
84
|
+
> Project-specific risk patterns that must be checked in the Plan's RISK Critic
|
|
85
|
+
|
|
86
|
+
1. Prisma migration and schema mismatch
|
|
87
|
+
2. Express middleware ordering errors (auth → validation → handler)
|
|
88
|
+
3. Missing async/await error handling (try-catch or wrapper)
|
|
89
|
+
4. Runtime errors when environment variables (.env) are not set
|
|
90
|
+
5. SQL injection (caution with raw queries when using Prisma)
|
|
91
|
+
|
|
92
|
+
## Mini-Review Checklist
|
|
93
|
+
|
|
94
|
+
> Items to inspect for each file in the Mini-Review of the Implement Phase gate
|
|
95
|
+
|
|
96
|
+
1. TypeScript strict mode violations
|
|
97
|
+
2. Error handling (try-catch or asyncHandler on async routes)
|
|
98
|
+
3. Input validation (type checking of req.body/params/query)
|
|
99
|
+
4. Unused imports / dead code
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# AFC Configuration
|
|
2
|
+
|
|
3
|
+
> This file defines project-specific settings for the afc command system.
|
|
4
|
+
> All afc commands reference this file to determine project-specific behavior.
|
|
5
|
+
|
|
6
|
+
## CI Commands
|
|
7
|
+
|
|
8
|
+
```yaml
|
|
9
|
+
ci: "pnpm turbo build lint test" # Full CI (lint + typecheck + build)
|
|
10
|
+
typecheck: "pnpm turbo typecheck" # Typecheck only
|
|
11
|
+
lint: "pnpm turbo lint" # Lint only
|
|
12
|
+
lint_fix: "pnpm turbo lint -- --fix" # Auto-fix lint
|
|
13
|
+
gate: "pnpm turbo typecheck lint" # Phase gate (run repeatedly during implement)
|
|
14
|
+
test: "pnpm turbo test" # Tests
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Architecture
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
style: "Monorepo"
|
|
21
|
+
layers: # Root → package order
|
|
22
|
+
- apps/
|
|
23
|
+
- packages/
|
|
24
|
+
import_rule: "apps/ may only import from packages/. packages/ must declare explicit dependencies (package.json)"
|
|
25
|
+
segments:
|
|
26
|
+
- apps/web # Web app
|
|
27
|
+
- apps/api # API server
|
|
28
|
+
- packages/ui # Shared UI components
|
|
29
|
+
- packages/config # Shared configuration (ESLint, Prettier, etc.)
|
|
30
|
+
- packages/tsconfig # Shared TypeScript configuration
|
|
31
|
+
- packages/utils # Shared utilities
|
|
32
|
+
path_alias: "@repo/* → packages/*"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Framework
|
|
36
|
+
|
|
37
|
+
```yaml
|
|
38
|
+
name: "Turborepo + pnpm workspace"
|
|
39
|
+
runtime: "Multiple (varies per app)"
|
|
40
|
+
client_directive: "Varies per app"
|
|
41
|
+
server_client_boundary: "Varies per app" # Determined by each app's framework
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Code Style
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
language: "TypeScript"
|
|
48
|
+
strict_mode: true
|
|
49
|
+
type_keyword: "type" # Use type instead of interface
|
|
50
|
+
import_type: true # Use import type { ... }
|
|
51
|
+
component_style: "PascalCase"
|
|
52
|
+
props_position: "above component" # Define Props type above the component
|
|
53
|
+
handler_naming: "handle[Event]"
|
|
54
|
+
boolean_naming: "is/has/can[State]"
|
|
55
|
+
constant_naming: "UPPER_SNAKE_CASE"
|
|
56
|
+
any_policy: "minimize (especially strict for shared packages)"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## State Management
|
|
60
|
+
|
|
61
|
+
```yaml
|
|
62
|
+
global_state: "Varies per app"
|
|
63
|
+
server_state: "Varies per app"
|
|
64
|
+
local_state: "Varies per app"
|
|
65
|
+
store_location: "Within each app"
|
|
66
|
+
query_location: "Within each app"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Styling
|
|
70
|
+
|
|
71
|
+
```yaml
|
|
72
|
+
framework: "Varies per app (shared UI package uses Tailwind CSS)"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Testing
|
|
76
|
+
|
|
77
|
+
```yaml
|
|
78
|
+
framework: "Varies per app (Vitest or Jest)"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Project-Specific Risks
|
|
82
|
+
|
|
83
|
+
> Project-specific risk patterns that must be checked in the Plan's RISK Critic
|
|
84
|
+
|
|
85
|
+
1. Circular dependencies between packages (turborepo detects, but runtime errors possible)
|
|
86
|
+
2. Build failures in dependent apps when shared packages change
|
|
87
|
+
3. npm publish errors when pnpm workspace protocol (workspace:*) is missing
|
|
88
|
+
4. tsconfig inheritance chain mismatch (extends path errors)
|
|
89
|
+
5. Stale builds due to incorrect pipeline cache settings in turbo.json
|
|
90
|
+
|
|
91
|
+
## Mini-Review Checklist
|
|
92
|
+
|
|
93
|
+
> Items to inspect for each file in the Mini-Review of the Implement Phase gate
|
|
94
|
+
|
|
95
|
+
1. Dependency direction between packages (apps → packages only)
|
|
96
|
+
2. Shared package export paths (package.json exports field)
|
|
97
|
+
3. TypeScript strict mode + path alias consistency
|
|
98
|
+
4. turbo.json pipeline configuration matches actual scripts
|