timsquad 3.7.0 → 3.8.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/README.ko.md +8 -9
- package/README.md +44 -11
- package/dist/commands/audit.d.ts +6 -0
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +111 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/log.d.ts +6 -0
- package/dist/commands/log.d.ts.map +1 -0
- package/dist/commands/log.js +85 -0
- package/dist/commands/log.js.map +1 -0
- package/dist/commands/next.d.ts +15 -0
- package/dist/commands/next.d.ts.map +1 -0
- package/dist/commands/next.js +146 -0
- package/dist/commands/next.js.map +1 -0
- package/dist/commands/plan.d.ts +6 -0
- package/dist/commands/plan.d.ts.map +1 -0
- package/dist/commands/plan.js +83 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/retro.d.ts +6 -0
- package/dist/commands/retro.d.ts.map +1 -0
- package/dist/commands/retro.js +74 -0
- package/dist/commands/retro.js.map +1 -0
- package/dist/commands/spec.d.ts +6 -0
- package/dist/commands/spec.d.ts.map +1 -0
- package/dist/commands/spec.js +56 -0
- package/dist/commands/spec.js.map +1 -0
- package/dist/commands/status.d.ts +6 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +99 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +12 -10
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/meta-cache.d.ts +2 -1
- package/dist/daemon/meta-cache.d.ts.map +1 -1
- package/dist/daemon/meta-cache.js +20 -4
- package/dist/daemon/meta-cache.js.map +1 -1
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +14 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/planning-parser.d.ts +65 -0
- package/dist/lib/planning-parser.d.ts.map +1 -0
- package/dist/lib/planning-parser.js +306 -0
- package/dist/lib/planning-parser.js.map +1 -0
- package/dist/lib/skill-generator.d.ts.map +1 -1
- package/dist/lib/skill-generator.js +7 -3
- package/dist/lib/skill-generator.js.map +1 -1
- package/dist/lib/template.d.ts.map +1 -1
- package/dist/lib/template.js +22 -5
- package/dist/lib/template.js.map +1 -1
- package/dist/lib/workflow-state.d.ts +77 -0
- package/dist/lib/workflow-state.d.ts.map +1 -1
- package/dist/lib/workflow-state.js +194 -0
- package/dist/lib/workflow-state.js.map +1 -1
- package/dist/types/config.d.ts +14 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +15 -1
- package/dist/types/config.js.map +1 -1
- package/package.json +1 -1
- package/templates/base/agents/base/tsq-librarian.md +1 -1
- package/templates/base/scripts/calculate-retro-metrics.sh +46 -0
- package/templates/base/scripts/check-circular-deps.sh +82 -0
- package/templates/base/scripts/cleanup-trails.sh +44 -0
- package/templates/base/scripts/generate-prd-traceability.sh +91 -0
- package/templates/base/scripts/manage-fp-registry.sh +83 -0
- package/templates/base/scripts/validate-gherkin.sh +113 -0
- package/templates/base/skills/tsq-controller/SKILL.md +60 -37
- package/templates/base/skills/tsq-controller/references/model-routing.md +38 -0
- package/templates/base/skills/tsq-controller/references/wave-dispatch.md +50 -0
- package/templates/base/skills/tsq-full/SKILL.md +70 -0
- package/templates/base/skills/tsq-grill/SKILL.md +60 -55
- package/templates/base/skills/tsq-grill/references/interview-guide.md +86 -0
- package/templates/base/skills/tsq-inspect/SKILL.md +108 -0
- package/templates/base/skills/tsq-inspect/references/checklist.md +162 -0
- package/templates/base/skills/tsq-quick/SKILL.md +58 -0
- package/templates/base/skills/tsq-start/SKILL.md +17 -44
- package/templates/base/skills/tsq-start/references/onboarding-steps.md +85 -0
- package/templates/platforms/claude-code/scripts/build-gate.sh +25 -2
- package/templates/platforms/claude-code/scripts/check-capability.sh +41 -10
- package/templates/platforms/claude-code/scripts/completion-guard.sh +79 -3
- package/templates/platforms/claude-code/scripts/detect-env.sh +124 -0
- package/templates/platforms/claude-code/scripts/stale-guard.sh +47 -0
- package/templates/platforms/claude-code/scripts/subagent-stop.sh +41 -2
- package/templates/platforms/claude-code/scripts/tdd-guard.sh +57 -0
- package/templates/platforms/claude-code/scripts/validate-completion-report.sh +86 -0
- package/templates/platforms/claude-code/settings.json +10 -0
- package/templates/project-types/fintech/config.yaml +1 -1
- package/templates/project-types/mobile-app/config.yaml +1 -1
- package/templates/project-types/web-app/config.yaml +1 -1
- package/templates/project-types/web-service/config.yaml +1 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# cleanup-trails.sh — trail 아카이브 10개 초과 시 자동 정리
|
|
3
|
+
# Usage: bash .timsquad/scripts/cleanup-trails.sh [project_root] [max_count]
|
|
4
|
+
# Output: JSON {archived, remaining}
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
ROOT="${1:-.}"
|
|
8
|
+
MAX_COUNT="${2:-10}"
|
|
9
|
+
TRAILS_DIR="$ROOT/.timsquad/trails"
|
|
10
|
+
ARCHIVE_DIR="$TRAILS_DIR/.archive"
|
|
11
|
+
|
|
12
|
+
if [ ! -d "$TRAILS_DIR" ]; then
|
|
13
|
+
echo '{"archived":0,"remaining":0,"reason":"trails directory not found"}'
|
|
14
|
+
exit 0
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# Count trail files (exclude .archive directory)
|
|
18
|
+
trail_files=()
|
|
19
|
+
while IFS= read -r -d '' f; do
|
|
20
|
+
trail_files+=("$f")
|
|
21
|
+
done < <(find "$TRAILS_DIR" -maxdepth 1 -type f -print0 | sort -z)
|
|
22
|
+
|
|
23
|
+
count=${#trail_files[@]}
|
|
24
|
+
|
|
25
|
+
if [ "$count" -le "$MAX_COUNT" ]; then
|
|
26
|
+
echo '{"archived":0,"remaining":'"$count"'}'
|
|
27
|
+
exit 0
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# Archive oldest files beyond MAX_COUNT
|
|
31
|
+
to_archive=$((count - MAX_COUNT))
|
|
32
|
+
archive_month=$(date -u +%Y-%m)
|
|
33
|
+
archive_dest="$ARCHIVE_DIR/$archive_month"
|
|
34
|
+
mkdir -p "$archive_dest"
|
|
35
|
+
|
|
36
|
+
archived=0
|
|
37
|
+
for ((i=0; i<to_archive; i++)); do
|
|
38
|
+
file="${trail_files[$i]}"
|
|
39
|
+
mv "$file" "$archive_dest/"
|
|
40
|
+
((archived++))
|
|
41
|
+
done
|
|
42
|
+
|
|
43
|
+
remaining=$((count - archived))
|
|
44
|
+
echo '{"archived":'"$archived"',"remaining":'"$remaining"',"archive_path":"'"$archive_dest"'"}'
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# generate-prd-traceability.sh — planning.md ↔ PRD 추적성 매트릭스 생성
|
|
3
|
+
# Usage: bash .timsquad/scripts/generate-prd-traceability.sh [project_root]
|
|
4
|
+
# Output: .timsquad/reports/traceability-matrix.md
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
ROOT="${1:-.}"
|
|
8
|
+
PRD="$ROOT/.timsquad/ssot/prd.md"
|
|
9
|
+
PLANNING="$ROOT/.timsquad/ssot/planning.md"
|
|
10
|
+
REPORT_DIR="$ROOT/.timsquad/reports"
|
|
11
|
+
OUTPUT="$REPORT_DIR/traceability-matrix.md"
|
|
12
|
+
|
|
13
|
+
if [ ! -f "$PRD" ]; then
|
|
14
|
+
echo '{"status":"skip","reason":"prd.md not found"}'
|
|
15
|
+
exit 0
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
if [ ! -f "$PLANNING" ]; then
|
|
19
|
+
echo '{"status":"skip","reason":"planning.md not found"}'
|
|
20
|
+
exit 0
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
mkdir -p "$REPORT_DIR"
|
|
24
|
+
|
|
25
|
+
# Extract PRD feature sections (## headings)
|
|
26
|
+
prd_features=()
|
|
27
|
+
while IFS= read -r line; do
|
|
28
|
+
if [[ "$line" =~ ^##[[:space:]]+(.+) ]]; then
|
|
29
|
+
prd_features+=("${BASH_REMATCH[1]}")
|
|
30
|
+
fi
|
|
31
|
+
done < "$PRD"
|
|
32
|
+
|
|
33
|
+
# Extract planning tasks with their phase/sequence context
|
|
34
|
+
declare -A task_map
|
|
35
|
+
current_phase=""
|
|
36
|
+
current_seq=""
|
|
37
|
+
|
|
38
|
+
while IFS= read -r line; do
|
|
39
|
+
if [[ "$line" =~ ^##[[:space:]]+Phase.*\(([A-Z][0-9]+)\) ]]; then
|
|
40
|
+
current_phase="${BASH_REMATCH[1]}"
|
|
41
|
+
elif [[ "$line" =~ ^##[[:space:]]+.+\(([A-Z][0-9]+-S[0-9]+)\) ]]; then
|
|
42
|
+
current_seq="${BASH_REMATCH[1]}"
|
|
43
|
+
elif [[ "$line" =~ ^###[[:space:]]+(.+)\(([A-Z][0-9]+-S[0-9]+-T[0-9]+)\) ]]; then
|
|
44
|
+
task_title="${BASH_REMATCH[1]}"
|
|
45
|
+
task_id="${BASH_REMATCH[2]}"
|
|
46
|
+
task_map["$task_id"]="$current_phase | $current_seq | $task_title"
|
|
47
|
+
fi
|
|
48
|
+
done < "$PLANNING"
|
|
49
|
+
|
|
50
|
+
# Generate traceability matrix
|
|
51
|
+
{
|
|
52
|
+
echo "# PRD Traceability Matrix"
|
|
53
|
+
echo ""
|
|
54
|
+
echo "> Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
55
|
+
echo ""
|
|
56
|
+
echo "| PRD Feature | Mapped Tasks | Coverage |"
|
|
57
|
+
echo "|-------------|-------------|----------|"
|
|
58
|
+
|
|
59
|
+
mapped=0
|
|
60
|
+
total=${#prd_features[@]}
|
|
61
|
+
|
|
62
|
+
for feature in "${prd_features[@]}"; do
|
|
63
|
+
# Find tasks that reference this feature (case-insensitive partial match)
|
|
64
|
+
feature_lower=$(echo "$feature" | tr '[:upper:]' '[:lower:]')
|
|
65
|
+
matching_tasks=""
|
|
66
|
+
|
|
67
|
+
for task_id in "${!task_map[@]}"; do
|
|
68
|
+
task_lower=$(echo "${task_map[$task_id]}" | tr '[:upper:]' '[:lower:]')
|
|
69
|
+
if [[ "$task_lower" == *"$feature_lower"* ]] || [[ "$feature_lower" == *"$task_lower"* ]]; then
|
|
70
|
+
matching_tasks+="$task_id "
|
|
71
|
+
fi
|
|
72
|
+
done
|
|
73
|
+
|
|
74
|
+
if [ -n "$matching_tasks" ]; then
|
|
75
|
+
echo "| $feature | $(echo "$matching_tasks" | xargs | tr ' ' ', ') | Mapped |"
|
|
76
|
+
((mapped++))
|
|
77
|
+
else
|
|
78
|
+
echo "| $feature | — | **Unmapped** |"
|
|
79
|
+
fi
|
|
80
|
+
done
|
|
81
|
+
|
|
82
|
+
echo ""
|
|
83
|
+
if [ "$total" -gt 0 ]; then
|
|
84
|
+
coverage=$((mapped * 100 / total))
|
|
85
|
+
echo "**Coverage:** $mapped / $total ($coverage%)"
|
|
86
|
+
else
|
|
87
|
+
echo "**Coverage:** No PRD features found"
|
|
88
|
+
fi
|
|
89
|
+
} > "$OUTPUT"
|
|
90
|
+
|
|
91
|
+
echo '{"status":"ok","output":"'"$OUTPUT"'","features":'"$total"',"mapped":'"$mapped"'}'
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# manage-fp-registry.sh — audit False Positive 자동 필터링
|
|
3
|
+
# Usage: bash .timsquad/scripts/manage-fp-registry.sh [project_root]
|
|
4
|
+
# bash .timsquad/scripts/manage-fp-registry.sh . add "pattern-id"
|
|
5
|
+
# bash .timsquad/scripts/manage-fp-registry.sh . exclude "pattern-id"
|
|
6
|
+
# Output: JSON fp-registry
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
ROOT="${1:-.}"
|
|
10
|
+
ACTION="${2:-scan}"
|
|
11
|
+
PATTERN_ID="${3:-}"
|
|
12
|
+
REGISTRY="$ROOT/.timsquad/retrospective/fp-registry.json"
|
|
13
|
+
RETRO_DIR="$ROOT/.timsquad/retrospective"
|
|
14
|
+
|
|
15
|
+
if ! command -v jq &>/dev/null; then
|
|
16
|
+
echo '{"error":"jq is required"}' >&2
|
|
17
|
+
exit 1
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
# Initialize registry if missing
|
|
21
|
+
if [ ! -f "$REGISTRY" ]; then
|
|
22
|
+
mkdir -p "$RETRO_DIR"
|
|
23
|
+
echo '{"patterns":[],"excluded":[]}' > "$REGISTRY"
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
case "$ACTION" in
|
|
27
|
+
scan)
|
|
28
|
+
# Scan retrospective cycles for repeated feedback patterns
|
|
29
|
+
CYCLES_DIR="$RETRO_DIR/cycles"
|
|
30
|
+
if [ ! -d "$CYCLES_DIR" ]; then
|
|
31
|
+
cat "$REGISTRY"
|
|
32
|
+
exit 0
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# Count feedback pattern occurrences across cycles
|
|
36
|
+
pattern_counts=$(find "$CYCLES_DIR" -name '*.json' -type f -exec \
|
|
37
|
+
jq -r '.problem[]? // empty' {} \; 2>/dev/null | \
|
|
38
|
+
sort | uniq -c | sort -rn | head -20)
|
|
39
|
+
|
|
40
|
+
# Update registry: patterns with 3+ occurrences → candidate FP
|
|
41
|
+
while IFS= read -r line; do
|
|
42
|
+
[ -z "$line" ] && continue
|
|
43
|
+
count=$(echo "$line" | awk '{print $1}')
|
|
44
|
+
pattern=$(echo "$line" | sed 's/^[[:space:]]*[0-9]*[[:space:]]*//')
|
|
45
|
+
[ "$count" -lt 3 ] && continue
|
|
46
|
+
|
|
47
|
+
# Add/update in registry
|
|
48
|
+
existing=$(jq -r --arg p "$pattern" '.patterns[] | select(.id == $p) | .id' "$REGISTRY" 2>/dev/null)
|
|
49
|
+
if [ -z "$existing" ]; then
|
|
50
|
+
jq --arg p "$pattern" --argjson c "$count" \
|
|
51
|
+
'.patterns += [{"id": $p, "count": $c, "last_occurrence": (now | todate)}]' \
|
|
52
|
+
"$REGISTRY" > "$REGISTRY.tmp" && mv "$REGISTRY.tmp" "$REGISTRY"
|
|
53
|
+
else
|
|
54
|
+
jq --arg p "$pattern" --argjson c "$count" \
|
|
55
|
+
'(.patterns[] | select(.id == $p)) |= (.count = $c | .last_occurrence = (now | todate))' \
|
|
56
|
+
"$REGISTRY" > "$REGISTRY.tmp" && mv "$REGISTRY.tmp" "$REGISTRY"
|
|
57
|
+
fi
|
|
58
|
+
done <<< "$pattern_counts"
|
|
59
|
+
|
|
60
|
+
cat "$REGISTRY"
|
|
61
|
+
;;
|
|
62
|
+
|
|
63
|
+
add)
|
|
64
|
+
[ -z "$PATTERN_ID" ] && { echo '{"error":"pattern id required"}' >&2; exit 1; }
|
|
65
|
+
jq --arg p "$PATTERN_ID" \
|
|
66
|
+
'if (.patterns | map(.id) | index($p)) then . else .patterns += [{"id": $p, "count": 1, "last_occurrence": (now | todate)}] end' \
|
|
67
|
+
"$REGISTRY" > "$REGISTRY.tmp" && mv "$REGISTRY.tmp" "$REGISTRY"
|
|
68
|
+
cat "$REGISTRY"
|
|
69
|
+
;;
|
|
70
|
+
|
|
71
|
+
exclude)
|
|
72
|
+
[ -z "$PATTERN_ID" ] && { echo '{"error":"pattern id required"}' >&2; exit 1; }
|
|
73
|
+
jq --arg p "$PATTERN_ID" \
|
|
74
|
+
'if (.excluded | index($p)) then . else .excluded += [$p] end' \
|
|
75
|
+
"$REGISTRY" > "$REGISTRY.tmp" && mv "$REGISTRY.tmp" "$REGISTRY"
|
|
76
|
+
cat "$REGISTRY"
|
|
77
|
+
;;
|
|
78
|
+
|
|
79
|
+
*)
|
|
80
|
+
echo '{"error":"unknown action: '"$ACTION"'. Use scan|add|exclude"}' >&2
|
|
81
|
+
exit 1
|
|
82
|
+
;;
|
|
83
|
+
esac
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# validate-gherkin.sh — BDD feature 파일 구문 검증
|
|
3
|
+
# Usage: bash .timsquad/scripts/validate-gherkin.sh [features_dir]
|
|
4
|
+
# Output: JSON {valid, errors, total_files}
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
FEATURES_DIR="${1:-features}"
|
|
8
|
+
|
|
9
|
+
if [ ! -d "$FEATURES_DIR" ]; then
|
|
10
|
+
echo '{"valid":true,"errors":[],"total_files":0,"reason":"features directory not found"}'
|
|
11
|
+
exit 0
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
errors=()
|
|
15
|
+
total=0
|
|
16
|
+
|
|
17
|
+
while IFS= read -r file; do
|
|
18
|
+
((total++))
|
|
19
|
+
line_num=0
|
|
20
|
+
has_feature=false
|
|
21
|
+
has_scenario=false
|
|
22
|
+
in_scenario=false
|
|
23
|
+
step_order="" # track Given/When/Then order
|
|
24
|
+
|
|
25
|
+
while IFS= read -r line; do
|
|
26
|
+
((line_num++))
|
|
27
|
+
trimmed=$(echo "$line" | sed 's/^[[:space:]]*//')
|
|
28
|
+
|
|
29
|
+
# Skip empty lines and comments
|
|
30
|
+
[[ -z "$trimmed" || "$trimmed" == \#* ]] && continue
|
|
31
|
+
|
|
32
|
+
# Feature keyword
|
|
33
|
+
if [[ "$trimmed" =~ ^Feature:[[:space:]]*.+ ]]; then
|
|
34
|
+
has_feature=true
|
|
35
|
+
continue
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# Scenario / Scenario Outline
|
|
39
|
+
if [[ "$trimmed" =~ ^(Scenario|Scenario\ Outline):[[:space:]]*.+ ]]; then
|
|
40
|
+
has_scenario=true
|
|
41
|
+
in_scenario=true
|
|
42
|
+
step_order=""
|
|
43
|
+
continue
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Step keywords
|
|
47
|
+
if [[ "$trimmed" =~ ^(Given|When|Then|And|But)[[:space:]]+ ]]; then
|
|
48
|
+
keyword="${BASH_REMATCH[1]}"
|
|
49
|
+
if [[ "$keyword" == "Given" ]]; then
|
|
50
|
+
if [[ "$step_order" == *"Then"* ]]; then
|
|
51
|
+
errors+=("{\"file\":\"$file\",\"line\":$line_num,\"msg\":\"Given after Then\"}")
|
|
52
|
+
fi
|
|
53
|
+
step_order+="Given "
|
|
54
|
+
elif [[ "$keyword" == "When" ]]; then
|
|
55
|
+
step_order+="When "
|
|
56
|
+
elif [[ "$keyword" == "Then" ]]; then
|
|
57
|
+
step_order+="Then "
|
|
58
|
+
fi
|
|
59
|
+
continue
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# Examples keyword (only valid in Scenario Outline)
|
|
63
|
+
if [[ "$trimmed" =~ ^Examples: ]]; then
|
|
64
|
+
continue
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# Table rows
|
|
68
|
+
if [[ "$trimmed" =~ ^\| ]]; then
|
|
69
|
+
continue
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# Tags
|
|
73
|
+
if [[ "$trimmed" =~ ^@ ]]; then
|
|
74
|
+
continue
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
# Background
|
|
78
|
+
if [[ "$trimmed" =~ ^Background: ]]; then
|
|
79
|
+
continue
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# Rule (Gherkin 6)
|
|
83
|
+
if [[ "$trimmed" =~ ^Rule:[[:space:]]*.+ ]]; then
|
|
84
|
+
continue
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# Doc strings
|
|
88
|
+
if [[ "$trimmed" == '"""' || "$trimmed" == '```' ]]; then
|
|
89
|
+
continue
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
done < "$file"
|
|
93
|
+
|
|
94
|
+
# Validate structure
|
|
95
|
+
if ! $has_feature; then
|
|
96
|
+
errors+=("{\"file\":\"$file\",\"line\":1,\"msg\":\"Missing Feature keyword\"}")
|
|
97
|
+
fi
|
|
98
|
+
if ! $has_scenario; then
|
|
99
|
+
errors+=("{\"file\":\"$file\",\"line\":1,\"msg\":\"No Scenario defined\"}")
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
done < <(find "$FEATURES_DIR" -name '*.feature' -type f | sort)
|
|
103
|
+
|
|
104
|
+
# Build JSON output
|
|
105
|
+
if [ ${#errors[@]} -eq 0 ]; then
|
|
106
|
+
echo '{"valid":true,"errors":[],"total_files":'"$total"'}'
|
|
107
|
+
exit 0
|
|
108
|
+
else
|
|
109
|
+
error_json=$(printf '%s,' "${errors[@]}")
|
|
110
|
+
error_json="[${error_json%,}]"
|
|
111
|
+
echo '{"valid":false,"errors":'"$error_json"',"total_files":'"$total"'}'
|
|
112
|
+
exit 1
|
|
113
|
+
fi
|
|
@@ -4,39 +4,63 @@ description: |
|
|
|
4
4
|
Context DI 컨테이너. 서브에이전트 위임 시 compiled spec을 의존성으로 주입.
|
|
5
5
|
서브에이전트 호출, Task() 위임, 에이전트 실행 시 자동 트리거.
|
|
6
6
|
Use when: "구현해줘", "테스트해줘", "리뷰해줘", "설계해줘", 서브에이전트 위임
|
|
7
|
-
version: "
|
|
8
|
-
tags: [tsq, controller, di, context-injection]
|
|
7
|
+
version: "3.0.0"
|
|
8
|
+
tags: [tsq, controller, di, context-injection, hybrid]
|
|
9
9
|
user-invocable: false
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
# Controller (Context DI
|
|
12
|
+
# Controller (Hybrid — Context DI + CLI)
|
|
13
13
|
|
|
14
14
|
서브에이전트에게 작업을 위임할 때 컨텍스트를 자동 해석하고 주입하는 컨테이너.
|
|
15
|
+
v3.0: 결정론적 로직(상태, 순서, 게이트)은 `tsq next` CLI로 이동. Controller는 판단(스펙 결정, 품질 평가, 프롬프트 구성)에 집중.
|
|
15
16
|
|
|
16
17
|
## Contract
|
|
17
18
|
|
|
18
19
|
- **Trigger**: 서브에이전트 위임 시 (구현, 테스트, 리뷰 등)
|
|
19
|
-
- **Input**:
|
|
20
|
+
- **Input**: `tsq next` JSON + 에이전트 파일 + compiled specs
|
|
20
21
|
- **Output**: 조합된 프롬프트로 Task() 실행
|
|
21
22
|
- **Error**: spec stale 시 `tsq compile` 재실행 안내
|
|
22
23
|
|
|
23
24
|
## Protocol
|
|
24
25
|
|
|
25
|
-
1.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
10. **
|
|
37
|
-
11.
|
|
38
|
-
12.
|
|
39
|
-
|
|
26
|
+
1. **다음 태스크 조회**: `tsq next` 실행 → JSON 출력에서 taskId, phaseId, sequenceId, title, agent 추출
|
|
27
|
+
- `all_complete` → 사용자에게 완료 안내
|
|
28
|
+
- `error` → planning.md 부재 시 `/tsq-decompose` 안내
|
|
29
|
+
2. **Task Context 기록**: `.timsquad/.daemon/task-context.json`에 현재 태스크 정보 저장 (SubagentStop hook이 읽음)
|
|
30
|
+
3. **Memory 참조**: `memory/` 디렉토리의 모든 .md 파일 Read
|
|
31
|
+
4. **SSOT Map 참조**: `.timsquad/ssot-map.yaml` → 티어 compiled spec 목록 확인
|
|
32
|
+
5. **Capability Token 발급**: `.timsquad/state/controller-active` + `allowed-paths.txt` 생성
|
|
33
|
+
6. **에이전트 파일 확인**: `.claude/agents/{agent}.md` 읽기
|
|
34
|
+
7. **Prerequisites 파싱**: `<prerequisites>` 태그에서 SSOT 목록 추출
|
|
35
|
+
8. **Spec Resolve**: `references/`에서 해당 compiled spec 로드
|
|
36
|
+
9. **Meta Index 쿼리**: `.timsquad/.daemon/task-context.json` 읽기 → scope 파일 구조를 프롬프트에 주입 (Daemon이 자동 갱신)
|
|
37
|
+
10. **Stale 체크**: `.compile-manifest.json` hash 비교
|
|
38
|
+
11. **방법론 참조**: `config.yaml`의 `methodology.development` → 해당 스킬 Protocol 로드
|
|
39
|
+
12. **프롬프트 조합**: tsq-protocol + **phase-memory carry-over** + memory + specs + meta-index scope + methodology + phase 제약 + 지시
|
|
40
|
+
- `.timsquad/state/phase-memory.md` 존재 시 carry-over/주의 섹션을 프롬프트 앞에 강제 삽입
|
|
41
|
+
13. **Model Routing → Task() 호출**: Model Routing 테이블에 따라 최종 모델을 결정한 뒤, 조합된 프롬프트로 서브에이전트 실행. 결정된 모델을 Task()의 model 파라미터로 전달
|
|
42
|
+
14. **Completion Report 검증**: 5개 필드(Task, Status, Files, Tests, Notes) 확인 — 누락 시 재요청
|
|
43
|
+
15. **Capability Token 회수**: `controller-active` + `allowed-paths.txt` 삭제
|
|
44
|
+
16. **다음 태스크**: Step 1로 돌아가서 반복 (또는 Phase 완료 시 Librarian 호출)
|
|
45
|
+
|
|
46
|
+
> 이전(v2.1)에서 Controller가 직접 하던 작업의 코드 이동:
|
|
47
|
+
> - ~~planning.md 파싱~~ → `tsq next` CLI (결정론적)
|
|
48
|
+
> - ~~workflow.json 갱신~~ → SubagentStop hook이 `tsq next --complete` 자동 호출
|
|
49
|
+
> - ~~Phase 완료 판정~~ → completion-guard hook이 `tsq next --phase-status` 호출
|
|
50
|
+
> - ~~phase-memory append~~ → SubagentStop hook이 자동 append
|
|
51
|
+
|
|
52
|
+
## Model Routing
|
|
53
|
+
|
|
54
|
+
`references/model-routing.md` 참조. `config.yaml`의 `model_routing` 설정(enabled, strategy)에 따라 태스크 복잡도 기반 모델 동적 선택.
|
|
55
|
+
- **aggressive**: 최대 haiku 사용 (비용 최적화)
|
|
56
|
+
- **balanced**: phase 적합 모델 (기본값)
|
|
57
|
+
- **conservative**: 최대 opus 사용 (품질 우선, fintech 기본)
|
|
58
|
+
|
|
59
|
+
## Wave Dispatch (병렬)
|
|
60
|
+
|
|
61
|
+
`references/wave-dispatch.md` 참조. `tsq next --wave`로 독립 태스크를 Wave로 묶어 동시 실행.
|
|
62
|
+
- `waveSize > 1` → 병렬 Task() 호출, 태스크별 Capability Token 개별 발급
|
|
63
|
+
- `waveSize === 1` → 기존 순차 Protocol 따름
|
|
40
64
|
|
|
41
65
|
## Delegation Rules
|
|
42
66
|
|
|
@@ -47,28 +71,27 @@ user-invocable: false
|
|
|
47
71
|
|
|
48
72
|
## Triggers
|
|
49
73
|
|
|
50
|
-
|
|
74
|
+
코드 강제(Hook/CLI) + LLM 판단(Controller) 하이브리드. Daemon 장애 시 Controller는 정상 동작.
|
|
51
75
|
|
|
52
|
-
### task-complete
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
76
|
+
### task-complete
|
|
77
|
+
- **Hook 자동 처리**: SubagentStop hook → `tsq next --complete` → workflow.json 갱신 + phase-memory append
|
|
78
|
+
- **Controller 판단** (LLM):
|
|
79
|
+
1. Completion Report 검증 — 5필드 확인, 누락 시 재요청
|
|
80
|
+
2. 단위 테스트 확인 — Status=pass 필수, fail 시 Developer에 재위임
|
|
81
|
+
3. L1 로그 확인 — Daemon이 L1 생성 (SubagentStop Hook). Daemon 장애 시 수동 기록
|
|
82
|
+
4. 다음 태스크 → `tsq next` 실행하여 다음 미완료 태스크로 진행
|
|
59
83
|
|
|
60
|
-
### sequence-complete
|
|
84
|
+
### sequence-complete
|
|
61
85
|
1. **통합 게이트**: `npm run test:integration` + `tsc --noEmit` — 실패 시 차단, Developer에 수정 위임
|
|
62
86
|
2. **L2 로그 확인**: `.timsquad/logs/sequences/{seq-id}.md` 존재 확인
|
|
63
|
-
3.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
1.
|
|
69
|
-
2.
|
|
70
|
-
3.
|
|
71
|
-
4. **사용자 안내**: "Phase {id} 완료. 다음 단계: (1) `/tsq-retro` — 회고 실행, (2) `/clear` — 컨텍스트 초기화 (phase-memory 자동 주입됩니다)"
|
|
87
|
+
3. **Spec Compliance 체크**: Sub-PRD Must-Have vs 완료 산출물 대조 (경고, block 아님)
|
|
88
|
+
|
|
89
|
+
### phase-complete
|
|
90
|
+
- **Hook 자동 감지**: completion-guard → `tsq next --phase-status` → Phase 완료 시 systemMessage로 안내
|
|
91
|
+
- **Controller 판단** (LLM):
|
|
92
|
+
1. E2E 게이트: `npm run test:e2e` — 실패 시 차단
|
|
93
|
+
2. Librarian 호출: Task(librarian) — Phase Memory 아카이브 + 새 HEAD 생성
|
|
94
|
+
3. 사용자 안내: "`/tsq-retro` → `/clear`"
|
|
72
95
|
|
|
73
96
|
### ssot-changed (비동기, Daemon 전담)
|
|
74
97
|
Daemon이 파일 감시로 `.compile-manifest.json` 갱신. 다음 Controller 실행 시 Stale 체크로 감지.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Model Routing
|
|
3
|
+
category: reference
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Model Routing Reference
|
|
7
|
+
|
|
8
|
+
`config.yaml`의 `model_routing.enabled`가 `true`이면 아래 테이블에 따라 모델을 동적 선택.
|
|
9
|
+
`false`이면 에이전트 파일의 `model` 필드(기본값)를 그대로 사용.
|
|
10
|
+
|
|
11
|
+
## Strategy별 라우팅 테이블
|
|
12
|
+
|
|
13
|
+
| 에이전트 | 태스크 유형 | aggressive | balanced | conservative |
|
|
14
|
+
|---------|-----------|-----------|----------|-------------|
|
|
15
|
+
| **Architect** | 설계/리뷰 | sonnet | opus | opus |
|
|
16
|
+
| **Developer** | 복잡한 구현 (아키텍처 변경, 복잡한 비즈니스 로직) | sonnet | sonnet | opus |
|
|
17
|
+
| **Developer** | 일반 구현 | haiku | sonnet | sonnet |
|
|
18
|
+
| **Developer** | 단순 구현 (CRUD, 스캐폴딩, 보일러플레이트) | haiku | haiku | sonnet |
|
|
19
|
+
| **QA** | 코드 리뷰 | haiku | sonnet | opus |
|
|
20
|
+
| **Security** | 보안 검토 | sonnet | sonnet | opus |
|
|
21
|
+
| **DBA** | DB 설계/마이그레이션 | sonnet | sonnet | opus |
|
|
22
|
+
| **Designer** | UI/UX 설계 | haiku | sonnet | sonnet |
|
|
23
|
+
| **Librarian** | 문서 기록 | haiku | haiku | sonnet |
|
|
24
|
+
|
|
25
|
+
## 복잡도 판정 기준
|
|
26
|
+
|
|
27
|
+
- **복잡**: 아키텍처 결정, 다중 모듈 연동, 상태 머신, 보안 로직, 트랜잭션
|
|
28
|
+
- **일반**: 단일 모듈 기능 구현, API 엔드포인트, 컴포넌트 개발
|
|
29
|
+
- **단순**: CRUD, 설정 파일 수정, 타입 정의, 보일러플레이트, 문서 갱신
|
|
30
|
+
|
|
31
|
+
## 적용 절차
|
|
32
|
+
|
|
33
|
+
1. `config.yaml` → `model_routing` 섹션 읽기
|
|
34
|
+
2. `enabled: false`이면 에이전트 기본 모델 사용 → 종료
|
|
35
|
+
3. 태스크 설명 + phase에서 복잡도 판정 (복잡/일반/단순)
|
|
36
|
+
4. 라우팅 테이블에서 `strategy` 열의 모델 선택
|
|
37
|
+
5. 선택된 모델을 Task()의 `model` 파라미터로 전달
|
|
38
|
+
6. Completion Report 첫 줄에 `[MODEL: {selected}]` 표기
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Wave Dispatch
|
|
3
|
+
category: reference
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Wave Dispatch — 병렬 서브에이전트 실행
|
|
7
|
+
|
|
8
|
+
## 개요
|
|
9
|
+
|
|
10
|
+
`tsq next --wave` 실행 시 의존성이 충족된 독립 태스크를 Wave로 반환.
|
|
11
|
+
Controller는 Wave 내 태스크를 동시에 Task() 호출하여 속도를 3-5x 향상.
|
|
12
|
+
|
|
13
|
+
## 프로토콜
|
|
14
|
+
|
|
15
|
+
1. `tsq next --wave` 실행 → `{ wave: [...tasks], waveSize, parallel }` JSON
|
|
16
|
+
2. `waveSize === 1` → 단일 태스크, 기존 순차 Protocol 12-16 따름
|
|
17
|
+
3. `waveSize > 1` → 병렬 디스패치:
|
|
18
|
+
a. 각 태스크에 대해 개별 Capability Token 발급 (`.timsquad/state/cap-{taskId}`)
|
|
19
|
+
b. 각 태스크의 Model Routing 독립 수행
|
|
20
|
+
c. 모든 Task()를 동시 호출 (Agent tool 병렬 호출)
|
|
21
|
+
d. 모든 완료 후 각 Completion Report 검증
|
|
22
|
+
e. 개별 Capability Token 회수
|
|
23
|
+
4. Wave 완료 → 다시 Step 1로 (다음 Wave 조회)
|
|
24
|
+
|
|
25
|
+
## 의존성 분석 규칙
|
|
26
|
+
|
|
27
|
+
- `dependencies` 없는 태스크: 즉시 실행 가능
|
|
28
|
+
- `dependencies` 있는 태스크: 모든 선행 태스크 완료 후 실행 가능
|
|
29
|
+
- 같은 Sequence 내 태스크도 의존성 없으면 병렬 가능
|
|
30
|
+
- 순환 의존성 감지 시: fallback으로 첫 번째 태스크만 반환
|
|
31
|
+
|
|
32
|
+
## Capability Token (병렬)
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
# 순차 (기존)
|
|
36
|
+
.timsquad/state/controller-active
|
|
37
|
+
.timsquad/state/allowed-paths.txt
|
|
38
|
+
|
|
39
|
+
# 병렬 (Wave)
|
|
40
|
+
.timsquad/state/cap-P1-S001-T001
|
|
41
|
+
.timsquad/state/cap-P1-S001-T002
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
병렬 실행 시 각 태스크에 독립 토큰을 발급하여 격리. 완료 시 개별 회수.
|
|
45
|
+
|
|
46
|
+
## 제약
|
|
47
|
+
|
|
48
|
+
- 같은 Phase 내 태스크만 Wave로 묶음 (Phase 간 병렬 불가)
|
|
49
|
+
- Wave 내 태스크가 같은 파일을 수정하면 충돌 가능 — outputs 필드로 사전 감지
|
|
50
|
+
- Wave 크기 상한: 5 (Claude Code 동시 에이전트 제한)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tsq-full
|
|
3
|
+
description: |
|
|
4
|
+
Controller 경유 풀 파이프라인 실행. Phase-Sequence-Task DAG를 순차적으로 진행하며
|
|
5
|
+
각 단계마다 게이트 검증(unit→integration→e2e), Librarian 기록, Phase Memory carry-over를 수행한다.
|
|
6
|
+
세션이 끊겨도 workflow.json에서 마지막 위치를 복원하여 이어서 진행한다.
|
|
7
|
+
Use when: "/tsq-full", "전체 구현", "풀 파이프라인", "본격적으로 시작",
|
|
8
|
+
"새 기능 개발", "인증 시스템 구현", "결제 모듈 만들어", "대규모 리팩토링",
|
|
9
|
+
"Phase 진행", "Phase 2부터", "파이프라인 재개", "이어서 진행",
|
|
10
|
+
또는 planning.md 기반으로 여러 태스크를 연속 실행해야 할 때.
|
|
11
|
+
다단계 기능, 여러 파일/모듈에 걸친 구현, 아키텍처 변경이면 이 스킬을 사용한다.
|
|
12
|
+
version: "1.0.0"
|
|
13
|
+
tags: [tsq, full, controller, pipeline]
|
|
14
|
+
user-invocable: true
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# /tsq-full — Controller 경유 풀 파이프라인
|
|
18
|
+
|
|
19
|
+
Phase-Sequence-Task 전체 워크플로우를 Controller 경유로 실행한다.
|
|
20
|
+
planning.md 기반으로 체계적 구현, 게이트 검증, Librarian 기록까지 수행하는 이유:
|
|
21
|
+
다단계 작업에서 각 Phase의 산출물이 다음 Phase의 입력이 되므로, 게이트로 품질을 보장하지 않으면
|
|
22
|
+
후속 작업에서 누적 결함이 발생하기 때문이다.
|
|
23
|
+
|
|
24
|
+
## Pre-conditions
|
|
25
|
+
|
|
26
|
+
1. **planning.md 필수**: `.timsquad/ssot/planning.md` 존재 확인
|
|
27
|
+
- 없으면 → "`/tsq-decompose`로 실행 계획을 먼저 생성하세요" 안내
|
|
28
|
+
2. **SSOT 충족**: PRD + requirements 최소 작성 완료
|
|
29
|
+
- 미충족 → "`/tsq-start`로 온보딩을 먼저 진행하세요" 안내
|
|
30
|
+
|
|
31
|
+
## Protocol
|
|
32
|
+
|
|
33
|
+
1. **다음 태스크 조회**: `tsq next` CLI 실행 → 다음 미완료 태스크 JSON 확인
|
|
34
|
+
- `all_complete` → 모든 태스크 완료. 사용자에게 안내
|
|
35
|
+
- `error: planning.md not found` → `/tsq-decompose` 안내
|
|
36
|
+
2. **Controller 풀 실행** (tsq-controller Protocol 전체 수행):
|
|
37
|
+
- `tsq next`가 반환한 태스크부터 순차 진행
|
|
38
|
+
- Sequence 내 Task 위임 (Developer → QA)
|
|
39
|
+
- 게이트 검증: unit → integration → e2e
|
|
40
|
+
- Librarian 호출 (Phase 완료 시)
|
|
41
|
+
- Phase Memory carry-over
|
|
42
|
+
3. **Phase 완료 안내**: "`/tsq-retro` 회고 → `/clear` 컨텍스트 초기화"
|
|
43
|
+
|
|
44
|
+
> workflow.json 갱신은 SubagentStop hook이 `tsq next --complete`를 자동 호출하여 처리.
|
|
45
|
+
> Phase 완료 감지는 completion-guard hook이 `tsq next --phase-status`를 호출하여 처리.
|
|
46
|
+
|
|
47
|
+
## Resumption
|
|
48
|
+
|
|
49
|
+
세션이 끊긴 후 `/tsq-full`을 다시 실행하면:
|
|
50
|
+
- `tsq next`가 workflow.json 기반으로 다음 미완료 Task를 자동 결정
|
|
51
|
+
- 이미 완료된 Task는 자동 스킵
|
|
52
|
+
- 컨텍스트 압축 후에도 phase-memory.md의 Progress 섹션에서 진행 상황 복원
|
|
53
|
+
|
|
54
|
+
## vs /tsq-quick
|
|
55
|
+
|
|
56
|
+
| 항목 | /tsq-full | /tsq-quick |
|
|
57
|
+
|------|-----------|-----------|
|
|
58
|
+
| Phase-Sequence-Task | O (전체) | X (단일) |
|
|
59
|
+
| Controller 경유 | O | O |
|
|
60
|
+
| SSOT/메모리 참조 | O | O |
|
|
61
|
+
| 게이트 | unit → integration → e2e | unit만 |
|
|
62
|
+
| Librarian 호출 | O | X |
|
|
63
|
+
| planning.md 필요 | O | X |
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
/tsq-full
|
|
69
|
+
/tsq-full Phase 2부터 재개
|
|
70
|
+
```
|