claude-pro-minmax 1.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/CLAUDE.md +60 -0
- package/.claude/agents/README.ko.md +210 -0
- package/.claude/agents/README.md +210 -0
- package/.claude/agents/builder.md +96 -0
- package/.claude/agents/dplanner.md +58 -0
- package/.claude/agents/planner.md +52 -0
- package/.claude/agents/reviewer.md +69 -0
- package/.claude/commands/README.ko.md +381 -0
- package/.claude/commands/README.md +381 -0
- package/.claude/commands/analyze-failures.md +49 -0
- package/.claude/commands/compact-phase.md +75 -0
- package/.claude/commands/do-opus.md +43 -0
- package/.claude/commands/do-sonnet.md +43 -0
- package/.claude/commands/do.md +56 -0
- package/.claude/commands/dplan.md +36 -0
- package/.claude/commands/learn.md +64 -0
- package/.claude/commands/llms-txt.md +50 -0
- package/.claude/commands/load-context.md +46 -0
- package/.claude/commands/plan.md +62 -0
- package/.claude/commands/review.md +55 -0
- package/.claude/commands/session-load.md +61 -0
- package/.claude/commands/session-save.md +79 -0
- package/.claude/commands/watch.md +58 -0
- package/.claude/contexts/README.ko.md +94 -0
- package/.claude/contexts/README.md +94 -0
- package/.claude/contexts/backend-context.md +23 -0
- package/.claude/contexts/frontend-context.md +24 -0
- package/.claude/rules/README.ko.md +98 -0
- package/.claude/rules/README.md +98 -0
- package/.claude/rules/code-style.md +21 -0
- package/.claude/rules/critical-actions.md +34 -0
- package/.claude/rules/security.md +13 -0
- package/.claude/sessions/2025-01-27-auth-jwt-refresh.md +32 -0
- package/.claude/sessions/README.ko.md +195 -0
- package/.claude/sessions/README.md +195 -0
- package/.claude/settings.json +167 -0
- package/.claude/settings.local.example.json +3 -0
- package/.claude/skills/README.ko.md +60 -0
- package/.claude/skills/README.md +60 -0
- package/.claude/skills/cli-wrappers/SKILL.md +38 -0
- package/.claude/skills/cli-wrappers/references/github-cli.md +18 -0
- package/.claude/skills/cli-wrappers/references/mgrep.md +18 -0
- package/.claude/skills/learned/README.ko.md +64 -0
- package/.claude/skills/learned/README.md +64 -0
- package/.claude.json +28 -0
- package/.claudeignore +17 -0
- package/LICENSE +21 -0
- package/README.ko.md +441 -0
- package/README.md +441 -0
- package/bin/cpmm.js +171 -0
- package/install.sh +154 -0
- package/package.json +59 -0
- package/scripts/README.ko.md +150 -0
- package/scripts/README.md +150 -0
- package/scripts/analyze-failures.sh +145 -0
- package/scripts/build.sh +34 -0
- package/scripts/claude_command_smoke.sh +116 -0
- package/scripts/commit.sh +7 -0
- package/scripts/create-branch.sh +14 -0
- package/scripts/hooks/README.ko.md +117 -0
- package/scripts/hooks/README.md +118 -0
- package/scripts/hooks/compact-suggest.sh +52 -0
- package/scripts/hooks/critical-action-check.sh +68 -0
- package/scripts/hooks/notification.sh +47 -0
- package/scripts/hooks/post-edit-format.sh +39 -0
- package/scripts/hooks/pre-compact.sh +55 -0
- package/scripts/hooks/readonly-check.sh +19 -0
- package/scripts/hooks/retry-check.sh +32 -0
- package/scripts/hooks/session-cleanup.sh +83 -0
- package/scripts/hooks/session-start.sh +70 -0
- package/scripts/hooks/stop-collect-context.sh +39 -0
- package/scripts/hooks/tool-failure-log.sh +46 -0
- package/scripts/lint.sh +34 -0
- package/scripts/runtime/README.ko.md +60 -0
- package/scripts/runtime/README.md +60 -0
- package/scripts/runtime/adapters/README.ko.md +68 -0
- package/scripts/runtime/adapters/README.md +68 -0
- package/scripts/runtime/adapters/_interface.sh +53 -0
- package/scripts/runtime/adapters/_template.sh +67 -0
- package/scripts/runtime/adapters/generic.sh +78 -0
- package/scripts/runtime/adapters/go.sh +51 -0
- package/scripts/runtime/adapters/jvm.sh +97 -0
- package/scripts/runtime/adapters/node.sh +104 -0
- package/scripts/runtime/adapters/python.sh +116 -0
- package/scripts/runtime/adapters/rust.sh +49 -0
- package/scripts/runtime/detect.sh +52 -0
- package/scripts/scrub-secrets.js +48 -0
- package/scripts/snapshot.sh +45 -0
- package/scripts/test.sh +34 -0
- package/scripts/verify.sh +35 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# retry-check.sh - Stop Hook (For Builder Subagent)
|
|
3
|
+
# Enforce 2-Retry Cap (0 tokens, ~50 tokens on block)
|
|
4
|
+
# Hardened Hook
|
|
5
|
+
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
INPUT=$(cat)
|
|
9
|
+
|
|
10
|
+
# check stop_hook_active - to prevent infinite loops
|
|
11
|
+
STOP_HOOK_ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active // false')
|
|
12
|
+
if [ "$STOP_HOOK_ACTIVE" = "true" ]; then
|
|
13
|
+
exit 0 # Already continuing from stop hook result - do not intervene
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
# Get transcript path
|
|
17
|
+
TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // empty')
|
|
18
|
+
|
|
19
|
+
if [ -n "$TRANSCRIPT_PATH" ] && [ -f "$TRANSCRIPT_PATH" ]; then
|
|
20
|
+
# Extract tool_result from last 50 lines (sufficient buffer) and check if last 2 are both errors
|
|
21
|
+
# tail: optimizes performance by not reading the entire file
|
|
22
|
+
# jq: parses JSONL to extract is_error field
|
|
23
|
+
CONSECUTIVE_ERRORS=$(tail -n 50 "$TRANSCRIPT_PATH" | jq -r 'select(.type=="tool_result") | .is_error // false' | tail -n 2 | grep -c "true")
|
|
24
|
+
|
|
25
|
+
# Escalate on 2 consecutive failures
|
|
26
|
+
if [ "$CONSECUTIVE_ERRORS" -ge 2 ]; then
|
|
27
|
+
echo "RETRY_CAP: 2 consecutive failures detected. Escalation to --sonnet, @planner, or @dplanner is recommended." >&2
|
|
28
|
+
exit 2
|
|
29
|
+
fi
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
exit 0
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# session-cleanup.sh - SessionEnd Hook
|
|
3
|
+
# Save session summary + Secret scrubbing on session end (0 tokens)
|
|
4
|
+
# Hardened Hook
|
|
5
|
+
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
INPUT=$(cat)
|
|
9
|
+
|
|
10
|
+
# Check jq dependency
|
|
11
|
+
if ! command -v jq &> /dev/null; then
|
|
12
|
+
echo "Error: jq is required but not installed." >&2
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
# Set project directories
|
|
17
|
+
SESSION_DIR="$HOME/.claude/sessions"
|
|
18
|
+
SCRUBBER="$HOME/.claude/scripts/scrub-secrets.js"
|
|
19
|
+
|
|
20
|
+
mkdir -p "$SESSION_DIR"
|
|
21
|
+
|
|
22
|
+
# Save session summary
|
|
23
|
+
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"')
|
|
24
|
+
REASON=$(echo "$INPUT" | jq -r '.reason // "other"')
|
|
25
|
+
TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
|
|
26
|
+
SUMMARY_FILE="$SESSION_DIR/${TIMESTAMP}-session-end.md"
|
|
27
|
+
|
|
28
|
+
# Git change summary
|
|
29
|
+
GIT_SUMMARY=""
|
|
30
|
+
if git rev-parse --is-inside-work-tree &>/dev/null; then
|
|
31
|
+
CHANGED_FILES=$(git diff --name-only HEAD 2>/dev/null | wc -l | tr -d ' ')
|
|
32
|
+
STAGED_FILES=$(git diff --cached --name-only 2>/dev/null | wc -l | tr -d ' ')
|
|
33
|
+
BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
|
|
34
|
+
GIT_SUMMARY="Branch: $BRANCH, Changed: $CHANGED_FILES, Staged: $STAGED_FILES"
|
|
35
|
+
else
|
|
36
|
+
GIT_SUMMARY="Not a git repository"
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
# Create summary file
|
|
40
|
+
cat > "$SUMMARY_FILE" <<EOF
|
|
41
|
+
---
|
|
42
|
+
type: session-end
|
|
43
|
+
session_id: $SESSION_ID
|
|
44
|
+
reason: $REASON
|
|
45
|
+
timestamp: $(date +"%Y-%m-%d %H:%M:%S")
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
# Session End Summary
|
|
49
|
+
|
|
50
|
+
## Session Info
|
|
51
|
+
- ID: $SESSION_ID
|
|
52
|
+
- End Reason: $REASON
|
|
53
|
+
- Time: $(date +"%H:%M:%S")
|
|
54
|
+
|
|
55
|
+
## Git Status
|
|
56
|
+
$GIT_SUMMARY
|
|
57
|
+
|
|
58
|
+
## Working Directory
|
|
59
|
+
$(pwd)
|
|
60
|
+
|
|
61
|
+
## Context for Next Session
|
|
62
|
+
[Reference this file with /session-load in the next session]
|
|
63
|
+
EOF
|
|
64
|
+
|
|
65
|
+
echo "[SessionEnd] Summary saved: $SUMMARY_FILE" >&2
|
|
66
|
+
|
|
67
|
+
# ===== Existing: Secret Scrubbing =====
|
|
68
|
+
# Skip if scrubber does not exist
|
|
69
|
+
[ ! -f "$SCRUBBER" ] && exit 0
|
|
70
|
+
|
|
71
|
+
# Scrub session files modified within last 5 minutes (*.md)
|
|
72
|
+
find "$SESSION_DIR" -name "*.md" -mmin -5 -print0 2>/dev/null | while IFS= read -r -d '' file; do
|
|
73
|
+
if [ -f "$file" ]; then
|
|
74
|
+
temp_file=$(mktemp)
|
|
75
|
+
if node "$SCRUBBER" < "$file" > "$temp_file" 2>/dev/null; then
|
|
76
|
+
mv "$temp_file" "$file"
|
|
77
|
+
else
|
|
78
|
+
rm -f "$temp_file"
|
|
79
|
+
fi
|
|
80
|
+
fi
|
|
81
|
+
done
|
|
82
|
+
|
|
83
|
+
exit 0
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# session-start.sh - SessionStart Hook
|
|
3
|
+
# 1. Set environment variables (using CLAUDE_ENV_FILE)
|
|
4
|
+
# 2. Notify previous session context (opt-in: CLAUDE_SESSION_NOTIFY=1)
|
|
5
|
+
# Official Docs: Environment variables can be persisted via CLAUDE_ENV_FILE in SessionStart
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
# 1. Set environment variables (0 tokens) - Always runs
|
|
9
|
+
if [ -n "${CLAUDE_ENV_FILE:-}" ]; then
|
|
10
|
+
# Example: project-specific environment variables
|
|
11
|
+
# echo 'export NODE_ENV=development' >> "$CLAUDE_ENV_FILE"
|
|
12
|
+
# echo 'export DEBUG=true' >> "$CLAUDE_ENV_FILE"
|
|
13
|
+
|
|
14
|
+
# Load .env.local if exists (Security: values are not exposed)
|
|
15
|
+
ENV_LOCAL="${CLAUDE_PROJECT_DIR:-.}/.env.local"
|
|
16
|
+
if [ -f "$ENV_LOCAL" ]; then
|
|
17
|
+
# Extract only variable names and export (values are loaded at runtime)
|
|
18
|
+
grep -v '^#' "$ENV_LOCAL" | grep '=' | while read -r line; do
|
|
19
|
+
var_name="${line%%=*}"
|
|
20
|
+
echo "export $var_name=\"\${$var_name:-}\"" >> "$CLAUDE_ENV_FILE"
|
|
21
|
+
done
|
|
22
|
+
fi
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# 2. Previous session notification (opt-in, ~30 tokens)
|
|
26
|
+
if [ "${CLAUDE_SESSION_NOTIFY:-0}" = "1" ]; then
|
|
27
|
+
SESSION_DIR="$HOME/.claude/sessions"
|
|
28
|
+
RECENT=$(find "$SESSION_DIR" -name "*.md" -mtime -7 2>/dev/null | sort -r | head -1)
|
|
29
|
+
|
|
30
|
+
if [ -n "$RECENT" ] && [ -f "$RECENT" ]; then
|
|
31
|
+
cat <<EOF
|
|
32
|
+
{
|
|
33
|
+
"hookSpecificOutput": {
|
|
34
|
+
"hookEventName": "SessionStart",
|
|
35
|
+
"additionalContext": "📂 Previous session found: $(basename "$RECENT"). To restore: /session-load $(basename "$RECENT" .md)"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
EOF
|
|
39
|
+
fi
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# 3. Failure log notification (opt-in, ~30 tokens)
|
|
43
|
+
if [ "${CLAUDE_FAILURE_NOTIFY:-0}" = "1" ]; then
|
|
44
|
+
LOG_FILE="$HOME/.claude/logs/tool-failures.log"
|
|
45
|
+
if [ -f "$LOG_FILE" ]; then
|
|
46
|
+
FAILURE_COUNT=$(wc -l < "$LOG_FILE" 2>/dev/null | tr -d ' ')
|
|
47
|
+
if [ "$FAILURE_COUNT" -gt 10 ]; then
|
|
48
|
+
cat <<EOF
|
|
49
|
+
{
|
|
50
|
+
"hookSpecificOutput": {
|
|
51
|
+
"hookEventName": "SessionStart",
|
|
52
|
+
"additionalContext": "⚠️ ${FAILURE_COUNT} tool failures accumulated. To analyze: /analyze-failures"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
EOF
|
|
56
|
+
fi
|
|
57
|
+
fi
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# 4. Message budget reminder (always-on, ~40 tokens)
|
|
61
|
+
cat <<'BUDGET'
|
|
62
|
+
{
|
|
63
|
+
"hookSpecificOutput": {
|
|
64
|
+
"hookEventName": "SessionStart",
|
|
65
|
+
"additionalContext": "📊 Pro Plan Strategy: ~45 msg/5h target (short conversations)\n• Default (/do): 2 msg (Batch plan+build+verify)\n• Complex (/plan): 6+ msg (Use for 4+ files)\n• Cost: Haiku(1x) vs Sonnet(3x) vs Opus(5x) | Out=5x In"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
BUDGET
|
|
69
|
+
|
|
70
|
+
exit 0
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# stop-collect-context.sh - Stop Hook
|
|
3
|
+
# Collect additional context on tool failure (0 tokens)
|
|
4
|
+
# Optional: Activated when additional context is needed besides PostToolUseFailure
|
|
5
|
+
# Hardened Hook
|
|
6
|
+
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
INPUT=$(cat)
|
|
10
|
+
|
|
11
|
+
# Check jq dependency
|
|
12
|
+
if ! command -v jq &> /dev/null; then
|
|
13
|
+
exit 0 # Silently skip if jq is missing
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
# check stop_hook_active - to prevent infinite loops
|
|
17
|
+
STOP_HOOK_ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active // false')
|
|
18
|
+
[ "$STOP_HOOK_ACTIVE" = "true" ] && exit 0
|
|
19
|
+
|
|
20
|
+
# Transcript path
|
|
21
|
+
TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // empty')
|
|
22
|
+
[ -z "$TRANSCRIPT_PATH" ] || [ ! -f "$TRANSCRIPT_PATH" ] && exit 0
|
|
23
|
+
|
|
24
|
+
# Check for error in recent tool_result
|
|
25
|
+
LAST_ERROR=$(tail -100 "$TRANSCRIPT_PATH" 2>/dev/null | jq -s '[.[] | select(.type=="tool_result" and .is_error==true)] | last' 2>/dev/null || echo "null")
|
|
26
|
+
|
|
27
|
+
if [ "$LAST_ERROR" != "null" ] && [ "$LAST_ERROR" != "" ]; then
|
|
28
|
+
TOOL_NAME=$(echo "$LAST_ERROR" | jq -r '.tool_name // "unknown"')
|
|
29
|
+
ERROR_MSG=$(echo "$LAST_ERROR" | jq -r '.error // "unknown"')
|
|
30
|
+
|
|
31
|
+
LOG_DIR="$HOME/.claude/logs"
|
|
32
|
+
mkdir -p "$LOG_DIR"
|
|
33
|
+
CONTEXT_FILE="$LOG_DIR/failure-contexts.jsonl"
|
|
34
|
+
|
|
35
|
+
# Save context (JSONL format)
|
|
36
|
+
echo "$LAST_ERROR" >> "$CONTEXT_FILE"
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
exit 0
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# tool-failure-log.sh - PostToolUseFailure Hook
|
|
3
|
+
# Logging and escalation recommendations on tool failure (0 tokens)
|
|
4
|
+
# Hardened Hook
|
|
5
|
+
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
INPUT=$(cat)
|
|
9
|
+
|
|
10
|
+
# Check jq dependency
|
|
11
|
+
if ! command -v jq &> /dev/null; then
|
|
12
|
+
echo "Error: jq is required but not installed." >&2
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
# Parsing
|
|
17
|
+
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // "unknown"')
|
|
18
|
+
ERROR_MSG=$(echo "$INPUT" | jq -r '.error // "unknown error"')
|
|
19
|
+
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"')
|
|
20
|
+
|
|
21
|
+
# Log directory
|
|
22
|
+
LOG_DIR="$HOME/.claude/logs"
|
|
23
|
+
mkdir -p "$LOG_DIR"
|
|
24
|
+
|
|
25
|
+
LOG_FILE="$LOG_DIR/tool-failures.log"
|
|
26
|
+
TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
|
|
27
|
+
|
|
28
|
+
# Record log
|
|
29
|
+
echo "[$TIMESTAMP] Tool: $TOOL_NAME | Error: $ERROR_MSG | Session: $SESSION_ID" >> "$LOG_FILE"
|
|
30
|
+
|
|
31
|
+
# Check for identical tool failures within last 5 minutes (from log file)
|
|
32
|
+
if [ -f "$LOG_FILE" ]; then
|
|
33
|
+
FIVE_MIN_AGO=$(date -v-5M +"%Y-%m-%d %H:%M:%S" 2>/dev/null || date -d "5 minutes ago" +"%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "")
|
|
34
|
+
if [ -n "$FIVE_MIN_AGO" ]; then
|
|
35
|
+
RECENT_FAILURES=$(grep "$TOOL_NAME" "$LOG_FILE" 2>/dev/null | tail -10 | wc -l | tr -d ' ')
|
|
36
|
+
else
|
|
37
|
+
RECENT_FAILURES=$(grep -c "$TOOL_NAME" "$LOG_FILE" 2>/dev/null || echo 0)
|
|
38
|
+
fi
|
|
39
|
+
else
|
|
40
|
+
RECENT_FAILURES=1
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# Recommend escalation on 3 or more failures
|
|
44
|
+
if [ "$RECENT_FAILURES" -ge 3 ]; then
|
|
45
|
+
echo "[ToolFailure] Tool $TOOL_NAME failed ${RECENT_FAILURES} times. Escalation to @planner or @dplanner recommended." >&2
|
|
46
|
+
fi
|
package/scripts/lint.sh
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# lint.sh - Universal Lint
|
|
3
|
+
# Delegates to runtime-specific adapter
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
8
|
+
RUNTIME_DIR="$SCRIPT_DIR/runtime"
|
|
9
|
+
|
|
10
|
+
# Detect runtime
|
|
11
|
+
RUNTIME=$("$RUNTIME_DIR/detect.sh" "$@")
|
|
12
|
+
|
|
13
|
+
# Parse JSON - prefer jq, fallback to bash
|
|
14
|
+
parse_json() {
|
|
15
|
+
local key="$1"
|
|
16
|
+
if command -v jq &>/dev/null; then
|
|
17
|
+
echo "$RUNTIME" | jq -r ".$key"
|
|
18
|
+
else
|
|
19
|
+
echo "$RUNTIME" | sed 's/.*"'"$key"'":"\([^"]*\)".*/\1/'
|
|
20
|
+
fi
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
ADAPTER=$(parse_json adapter)
|
|
24
|
+
RUNTIME_NAME=$(parse_json runtime)
|
|
25
|
+
TOOL_NAME=$(parse_json tool)
|
|
26
|
+
|
|
27
|
+
echo "🔍 Detected: $RUNTIME_NAME ($TOOL_NAME)"
|
|
28
|
+
|
|
29
|
+
# Source adapter
|
|
30
|
+
source "$RUNTIME_DIR/adapters/$ADAPTER"
|
|
31
|
+
|
|
32
|
+
# Execute
|
|
33
|
+
echo "🔎 Running linter..."
|
|
34
|
+
adapter_lint
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
> **[English Version](README.md)**
|
|
2
|
+
|
|
3
|
+
# Runtime Detection Layer
|
|
4
|
+
|
|
5
|
+
## 목적
|
|
6
|
+
언어 독립적 작업을 위한 OCP 준수 런타임 감지. 코어 스크립트 수정 없이 새 언어 추가 가능.
|
|
7
|
+
|
|
8
|
+
## 구조
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
runtime/
|
|
12
|
+
├── detect.sh # 프로젝트 런타임 자동 감지
|
|
13
|
+
└── adapters/ # 언어별 구현체
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## detect.sh
|
|
17
|
+
|
|
18
|
+
프로젝트 유형을 자동 감지하고 JSON을 출력합니다.
|
|
19
|
+
|
|
20
|
+
**사용법:**
|
|
21
|
+
```bash
|
|
22
|
+
# 기본 사용
|
|
23
|
+
./detect.sh
|
|
24
|
+
# 출력: {"runtime":"node","tool":"npm","adapter":"node.sh"}
|
|
25
|
+
|
|
26
|
+
# 모노레포 지원 (하위 디렉토리)
|
|
27
|
+
./detect.sh --path backend
|
|
28
|
+
# 출력: {"runtime":"jvm","tool":"gradle","adapter":"jvm.sh"}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**감지 우선순위:**
|
|
32
|
+
1. JVM: `build.gradle.kts` > `build.gradle` > `pom.xml`
|
|
33
|
+
2. Node: `package.json` (락 파일로 패키지 매니저 확인)
|
|
34
|
+
3. Rust: `Cargo.toml`
|
|
35
|
+
4. Go: `go.mod`
|
|
36
|
+
5. Python: `pyproject.toml` > `setup.py` > `requirements.txt`
|
|
37
|
+
6. Generic: Makefile로 폴백
|
|
38
|
+
|
|
39
|
+
## 통합
|
|
40
|
+
|
|
41
|
+
유니버설 스크립트가 이 레이어를 사용합니다:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# scripts/verify.sh
|
|
45
|
+
RUNTIME=$("$RUNTIME_DIR/detect.sh" "$@")
|
|
46
|
+
ADAPTER=$(echo "$RUNTIME" | jq -r '.adapter')
|
|
47
|
+
source "$RUNTIME_DIR/adapters/$ADAPTER"
|
|
48
|
+
adapter_verify
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## 새 런타임 추가
|
|
52
|
+
|
|
53
|
+
`detect.sh`만 업데이트:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# 감지 패턴 추가
|
|
57
|
+
[[ -f "$dir/mix.exs" ]] && echo '{"runtime":"elixir","tool":"mix","adapter":"elixir.sh"}' && return
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
그 다음 `adapters/elixir.sh`에 어댑터 생성.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
> **[한국어 버전](README.ko.md)**
|
|
2
|
+
|
|
3
|
+
# Runtime Detection Layer
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
OCP-compliant runtime detection for language-agnostic operations. Add new languages without modifying core scripts.
|
|
7
|
+
|
|
8
|
+
## Structure
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
runtime/
|
|
12
|
+
├── detect.sh # Auto-detect project runtime
|
|
13
|
+
└── adapters/ # Language-specific implementations
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## detect.sh
|
|
17
|
+
|
|
18
|
+
Automatically detects project type and outputs JSON.
|
|
19
|
+
|
|
20
|
+
**Usage:**
|
|
21
|
+
```bash
|
|
22
|
+
# Basic usage
|
|
23
|
+
./detect.sh
|
|
24
|
+
# Output: {"runtime":"node","tool":"npm","adapter":"node.sh"}
|
|
25
|
+
|
|
26
|
+
# Monorepo support (subdirectory)
|
|
27
|
+
./detect.sh --path backend
|
|
28
|
+
# Output: {"runtime":"jvm","tool":"gradle","adapter":"jvm.sh"}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Detection Priority:**
|
|
32
|
+
1. JVM: `build.gradle.kts` > `build.gradle` > `pom.xml`
|
|
33
|
+
2. Node: `package.json` (then check lock files for pm)
|
|
34
|
+
3. Rust: `Cargo.toml`
|
|
35
|
+
4. Go: `go.mod`
|
|
36
|
+
5. Python: `pyproject.toml` > `setup.py` > `requirements.txt`
|
|
37
|
+
6. Generic: Fallback to Makefile
|
|
38
|
+
|
|
39
|
+
## Integration
|
|
40
|
+
|
|
41
|
+
Universal scripts use this layer:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# scripts/verify.sh
|
|
45
|
+
RUNTIME=$("$RUNTIME_DIR/detect.sh" "$@")
|
|
46
|
+
ADAPTER=$(echo "$RUNTIME" | jq -r '.adapter')
|
|
47
|
+
source "$RUNTIME_DIR/adapters/$ADAPTER"
|
|
48
|
+
adapter_verify
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Adding New Runtimes
|
|
52
|
+
|
|
53
|
+
Update `detect.sh` only:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# Add detection pattern
|
|
57
|
+
[[ -f "$dir/mix.exs" ]] && echo '{"runtime":"elixir","tool":"mix","adapter":"elixir.sh"}' && return
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Then create the adapter in `adapters/elixir.sh`.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
> **[English Version](README.md)**
|
|
2
|
+
|
|
3
|
+
# Adapters Directory
|
|
4
|
+
|
|
5
|
+
## 목적
|
|
6
|
+
어댑터 계약을 따르는 언어별 구현체. 각 어댑터는 빌드, 테스트, 린트 작업에 대해 통합 인터페이스를 제공합니다.
|
|
7
|
+
|
|
8
|
+
## 사용 가능한 어댑터
|
|
9
|
+
|
|
10
|
+
| 어댑터 | 런타임 | 빌드 도구 | 언어 |
|
|
11
|
+
|---------|---------|-------------|-----------|
|
|
12
|
+
| `jvm.sh` | JVM | Gradle, Maven | Java, Kotlin |
|
|
13
|
+
| `node.sh` | Node | npm, pnpm, yarn, bun | TypeScript, JavaScript |
|
|
14
|
+
| `go.sh` | Go | Go 모듈 | Go |
|
|
15
|
+
| `rust.sh` | Rust | Cargo | Rust |
|
|
16
|
+
| `python.sh` | Python | pip, poetry, uv | Python |
|
|
17
|
+
| `generic.sh` | Generic | Makefile | Any |
|
|
18
|
+
|
|
19
|
+
## 개발 유틸리티
|
|
20
|
+
|
|
21
|
+
| 파일 | 목적 |
|
|
22
|
+
|------|------|
|
|
23
|
+
| `_interface.sh` | 계약 검증기 - 어댑터가 모든 필수 함수를 구현했는지 검증 |
|
|
24
|
+
| `_template.sh` | 어댑터 템플릿 - 새 어댑터 생성 시 복사하여 사용 |
|
|
25
|
+
|
|
26
|
+
## 어댑터 계약
|
|
27
|
+
|
|
28
|
+
모든 어댑터는 다음 함수를 구현해야 합니다 (`_interface.sh`에 정의됨):
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
adapter_info() # 어댑터 메타데이터를 JSON으로 반환
|
|
32
|
+
adapter_verify() # 전체 검증 실행 (빌드 + 테스트 + 린트)
|
|
33
|
+
adapter_build() # 프로젝트 빌드
|
|
34
|
+
adapter_test() # 테스트 실행
|
|
35
|
+
adapter_lint() # 린터 실행
|
|
36
|
+
adapter_format() # 코드 포맷
|
|
37
|
+
adapter_clean() # 빌드 산출물 정리
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
선택 사항:
|
|
41
|
+
```bash
|
|
42
|
+
adapter_run() # 개발 서버 실행
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 새 어댑터 추가
|
|
46
|
+
|
|
47
|
+
**3단계 (OCP - 코어 수정 없음):**
|
|
48
|
+
|
|
49
|
+
1. 템플릿 복사:
|
|
50
|
+
```bash
|
|
51
|
+
cp _template.sh elixir.sh
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
2. 모든 `adapter_*` 함수 구현
|
|
55
|
+
|
|
56
|
+
3. `../detect.sh`에 감지 패턴 추가:
|
|
57
|
+
```bash
|
|
58
|
+
[[ -f "$dir/mix.exs" ]] && echo '{"runtime":"elixir","tool":"mix","adapter":"elixir.sh"}' && return
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
완료! Universal scripts가 자동으로 새 어댑터 사용
|
|
62
|
+
|
|
63
|
+
## 어댑터 준수 검증
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
./adapters/_interface.sh ./adapters/elixir.sh
|
|
67
|
+
# 출력: ✓ Adapter implements all required functions
|
|
68
|
+
```
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
> **[한국어 버전](README.ko.md)**
|
|
2
|
+
|
|
3
|
+
# Adapters Directory
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
Language-specific implementations following the adapter contract. Each adapter provides a unified interface for build, test, lint operations.
|
|
7
|
+
|
|
8
|
+
## Available Adapters
|
|
9
|
+
|
|
10
|
+
| Adapter | Runtime | Build Tools | Languages |
|
|
11
|
+
|---------|---------|-------------|-----------|
|
|
12
|
+
| `jvm.sh` | JVM | Gradle, Maven | Java, Kotlin |
|
|
13
|
+
| `node.sh` | Node | npm, pnpm, yarn, bun | TypeScript, JavaScript |
|
|
14
|
+
| `go.sh` | Go | Go modules | Go |
|
|
15
|
+
| `rust.sh` | Rust | Cargo | Rust |
|
|
16
|
+
| `python.sh` | Python | pip, poetry, uv | Python |
|
|
17
|
+
| `generic.sh` | Generic | Makefile | Any |
|
|
18
|
+
|
|
19
|
+
## Development Utilities
|
|
20
|
+
|
|
21
|
+
| File | Purpose |
|
|
22
|
+
|------|---------|
|
|
23
|
+
| `_interface.sh` | Contract validator - verifies adapter implements all required functions |
|
|
24
|
+
| `_template.sh` | Adapter template - copy this to create new adapters |
|
|
25
|
+
|
|
26
|
+
## Adapter Contract
|
|
27
|
+
|
|
28
|
+
All adapters MUST implement these functions (defined in `_interface.sh`):
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
adapter_info() # Return adapter metadata as JSON
|
|
32
|
+
adapter_verify() # Run full verification (build + test + lint)
|
|
33
|
+
adapter_build() # Build project
|
|
34
|
+
adapter_test() # Run tests
|
|
35
|
+
adapter_lint() # Run linter
|
|
36
|
+
adapter_format() # Format code
|
|
37
|
+
adapter_clean() # Clean build artifacts
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Optional:
|
|
41
|
+
```bash
|
|
42
|
+
adapter_run() # Run dev server
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Adding a New Adapter
|
|
46
|
+
|
|
47
|
+
**3 Steps (OCP - no core modifications):**
|
|
48
|
+
|
|
49
|
+
1. Copy template:
|
|
50
|
+
```bash
|
|
51
|
+
cp _template.sh elixir.sh
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
2. Implement all `adapter_*` functions
|
|
55
|
+
|
|
56
|
+
3. Add detection pattern to `../detect.sh`:
|
|
57
|
+
```bash
|
|
58
|
+
[[ -f "$dir/mix.exs" ]] && echo '{"runtime":"elixir","tool":"mix","adapter":"elixir.sh"}' && return
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Done! Universal scripts automatically use the new adapter.
|
|
62
|
+
|
|
63
|
+
## Verify Adapter Compliance
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
./adapters/_interface.sh ./adapters/elixir.sh
|
|
67
|
+
# Output: ✓ Adapter implements all required functions
|
|
68
|
+
```
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# _interface.sh - Adapter Interface Contract
|
|
3
|
+
# All adapters MUST implement these functions
|
|
4
|
+
#
|
|
5
|
+
# Usage: source this file to verify adapter compliance
|
|
6
|
+
#
|
|
7
|
+
# Required functions:
|
|
8
|
+
# adapter_info() - Return adapter metadata as JSON
|
|
9
|
+
# adapter_verify() - Run full verification (build + test + lint)
|
|
10
|
+
# adapter_build() - Build project
|
|
11
|
+
# adapter_test() - Run tests
|
|
12
|
+
# adapter_lint() - Run linter
|
|
13
|
+
# adapter_format() - Format code
|
|
14
|
+
# adapter_clean() - Clean build artifacts
|
|
15
|
+
#
|
|
16
|
+
# Optional functions:
|
|
17
|
+
# adapter_run() - Run dev server
|
|
18
|
+
|
|
19
|
+
REQUIRED_FUNCTIONS=(
|
|
20
|
+
"adapter_info"
|
|
21
|
+
"adapter_verify"
|
|
22
|
+
"adapter_build"
|
|
23
|
+
"adapter_test"
|
|
24
|
+
"adapter_lint"
|
|
25
|
+
"adapter_format"
|
|
26
|
+
"adapter_clean"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
verify_adapter() {
|
|
30
|
+
local adapter_file="$1"
|
|
31
|
+
local missing=()
|
|
32
|
+
|
|
33
|
+
source "$adapter_file"
|
|
34
|
+
|
|
35
|
+
for func in "${REQUIRED_FUNCTIONS[@]}"; do
|
|
36
|
+
if ! declare -f "$func" > /dev/null 2>&1; then
|
|
37
|
+
missing+=("$func")
|
|
38
|
+
fi
|
|
39
|
+
done
|
|
40
|
+
|
|
41
|
+
if [ ${#missing[@]} -gt 0 ]; then
|
|
42
|
+
echo "ERROR: Adapter missing functions: ${missing[*]}" >&2
|
|
43
|
+
return 1
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
echo "✓ Adapter $adapter_file implements all required functions"
|
|
47
|
+
return 0
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# If called directly with an argument, verify that adapter
|
|
51
|
+
if [ $# -gt 0 ]; then
|
|
52
|
+
verify_adapter "$1"
|
|
53
|
+
fi
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# _template.sh - Template for New Adapters
|
|
3
|
+
# Copy this file to create a new adapter
|
|
4
|
+
#
|
|
5
|
+
# Steps to add a new language:
|
|
6
|
+
# 1. cp _template.sh elixir.sh
|
|
7
|
+
# 2. Implement all adapter_* functions
|
|
8
|
+
# 3. Add detection pattern to ../detect.sh
|
|
9
|
+
# Done! Core scripts unchanged (OCP).
|
|
10
|
+
#
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
14
|
+
|
|
15
|
+
# Return adapter metadata as JSON
|
|
16
|
+
adapter_info() {
|
|
17
|
+
echo '{"runtime":"RUNTIME_NAME","tool":"TOOL_NAME","languages":["LANGUAGE"]}'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
# Run full verification (compile + test + lint)
|
|
21
|
+
adapter_verify() {
|
|
22
|
+
echo "TODO: Implement verify for RUNTIME_NAME"
|
|
23
|
+
echo "Example: mix compile && mix test"
|
|
24
|
+
exit 1
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
# Build the project
|
|
28
|
+
adapter_build() {
|
|
29
|
+
echo "TODO: Implement build for RUNTIME_NAME"
|
|
30
|
+
echo "Example: mix release"
|
|
31
|
+
exit 1
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Run tests
|
|
35
|
+
adapter_test() {
|
|
36
|
+
echo "TODO: Implement test for RUNTIME_NAME"
|
|
37
|
+
echo "Example: mix test"
|
|
38
|
+
exit 1
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# Run linter
|
|
42
|
+
adapter_lint() {
|
|
43
|
+
echo "TODO: Implement lint for RUNTIME_NAME"
|
|
44
|
+
echo "Example: mix credo"
|
|
45
|
+
exit 1
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# Format code
|
|
49
|
+
adapter_format() {
|
|
50
|
+
echo "TODO: Implement format for RUNTIME_NAME"
|
|
51
|
+
echo "Example: mix format"
|
|
52
|
+
exit 1
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# Clean build artifacts
|
|
56
|
+
adapter_clean() {
|
|
57
|
+
echo "TODO: Implement clean for RUNTIME_NAME"
|
|
58
|
+
echo "Example: mix clean"
|
|
59
|
+
exit 1
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# Optional: Run dev server
|
|
63
|
+
adapter_run() {
|
|
64
|
+
echo "TODO: Implement run for RUNTIME_NAME"
|
|
65
|
+
echo "Example: mix phx.server"
|
|
66
|
+
exit 1
|
|
67
|
+
}
|