ai-sprint-kit 1.3.1 → 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/LICENSE +35 -123
- package/README.md +39 -207
- package/bin/ai-sprint.js +105 -0
- package/lib/auth.js +73 -0
- package/lib/installer.js +59 -195
- package/lib/messages.js +53 -0
- package/package.json +15 -18
- package/bin/cli.js +0 -135
- package/lib/scanner.js +0 -321
- package/templates/.claude/.env.example +0 -13
- package/templates/.claude/agents/debugger.md +0 -668
- package/templates/.claude/agents/devops.md +0 -728
- package/templates/.claude/agents/docs.md +0 -662
- package/templates/.claude/agents/implementer.md +0 -288
- package/templates/.claude/agents/planner.md +0 -273
- package/templates/.claude/agents/researcher.md +0 -454
- package/templates/.claude/agents/reviewer.md +0 -644
- package/templates/.claude/agents/security.md +0 -203
- package/templates/.claude/agents/tester.md +0 -647
- package/templates/.claude/commands/ai-sprint-auto.md +0 -150
- package/templates/.claude/commands/ai-sprint-code.md +0 -316
- package/templates/.claude/commands/ai-sprint-debug.md +0 -453
- package/templates/.claude/commands/ai-sprint-deploy.md +0 -475
- package/templates/.claude/commands/ai-sprint-docs.md +0 -519
- package/templates/.claude/commands/ai-sprint-plan.md +0 -136
- package/templates/.claude/commands/ai-sprint-review.md +0 -433
- package/templates/.claude/commands/ai-sprint-scan.md +0 -146
- package/templates/.claude/commands/ai-sprint-secure.md +0 -88
- package/templates/.claude/commands/ai-sprint-test.md +0 -352
- package/templates/.claude/commands/ai-sprint-validate.md +0 -253
- package/templates/.claude/settings.json +0 -27
- package/templates/.claude/skills/codebase-context/SKILL.md +0 -68
- package/templates/.claude/skills/codebase-context/references/reading-context.md +0 -68
- package/templates/.claude/skills/codebase-context/references/refresh-triggers.md +0 -82
- package/templates/.claude/skills/implementation/SKILL.md +0 -70
- package/templates/.claude/skills/implementation/references/error-handling.md +0 -106
- package/templates/.claude/skills/implementation/references/security-patterns.md +0 -73
- package/templates/.claude/skills/implementation/references/validation-patterns.md +0 -107
- package/templates/.claude/skills/memory/SKILL.md +0 -67
- package/templates/.claude/skills/memory/references/decisions-format.md +0 -68
- package/templates/.claude/skills/memory/references/learning-format.md +0 -74
- package/templates/.claude/skills/planning/SKILL.md +0 -72
- package/templates/.claude/skills/planning/references/plan-templates.md +0 -81
- package/templates/.claude/skills/planning/references/research-phase.md +0 -62
- package/templates/.claude/skills/planning/references/solution-design.md +0 -66
- package/templates/.claude/skills/quality-assurance/SKILL.md +0 -79
- package/templates/.claude/skills/quality-assurance/references/review-checklist.md +0 -72
- package/templates/.claude/skills/quality-assurance/references/security-checklist.md +0 -70
- package/templates/.claude/skills/quality-assurance/references/testing-strategy.md +0 -85
- package/templates/.claude/skills/quality-assurance/scripts/check-size.py +0 -333
- package/templates/.claude/statusline.sh +0 -126
- package/templates/.claude/workflows/development-rules.md +0 -133
- package/templates/.claude/workflows/orchestration-protocol.md +0 -194
- package/templates/.mcp.json.example +0 -36
- package/templates/CLAUDE.md +0 -412
- package/templates/README.md +0 -331
- package/templates/ai_context/codebase/.gitkeep +0 -0
- package/templates/ai_context/memory/active.md +0 -15
- package/templates/ai_context/memory/decisions.md +0 -18
- package/templates/ai_context/memory/learning.md +0 -22
- package/templates/ai_context/plans/.gitkeep +0 -0
- package/templates/ai_context/reports/.gitkeep +0 -0
- package/templates/docs/user-guide-th.md +0 -454
- package/templates/docs/user-guide.md +0 -595
|
@@ -1,333 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Design principles size checker.
|
|
4
|
-
Detects files >500 lines and functions >50 lines.
|
|
5
|
-
Supports: Python, JavaScript, TypeScript, Go, Java, Rust
|
|
6
|
-
Exit code: 0 = no violations (pass), 1 = violations found (warn only)
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
import argparse
|
|
10
|
-
import ast
|
|
11
|
-
import os
|
|
12
|
-
import re
|
|
13
|
-
import sys
|
|
14
|
-
from pathlib import Path
|
|
15
|
-
from dataclasses import dataclass
|
|
16
|
-
from typing import List
|
|
17
|
-
|
|
18
|
-
@dataclass
|
|
19
|
-
class Violation:
|
|
20
|
-
file: str
|
|
21
|
-
line: int
|
|
22
|
-
type: str # 'file' or 'function'
|
|
23
|
-
name: str
|
|
24
|
-
actual: int
|
|
25
|
-
limit: int
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def count_file_lines(path: Path) -> int:
|
|
29
|
-
"""Count non-empty, non-comment lines."""
|
|
30
|
-
try:
|
|
31
|
-
with open(path, 'r', encoding='utf-8', errors='ignore') as f:
|
|
32
|
-
lines = [l for l in f.readlines() if l.strip()
|
|
33
|
-
and not l.strip().startswith(('#', '//', '--', '/*', '*'))]
|
|
34
|
-
return len(lines)
|
|
35
|
-
except Exception:
|
|
36
|
-
return 0
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def check_python_functions(path: Path, max_lines: int) -> List[Violation]:
|
|
40
|
-
"""Check Python function lengths using AST."""
|
|
41
|
-
violations = []
|
|
42
|
-
try:
|
|
43
|
-
with open(path, 'r', encoding='utf-8') as f:
|
|
44
|
-
tree = ast.parse(f.read())
|
|
45
|
-
for node in ast.walk(tree):
|
|
46
|
-
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
47
|
-
length = (node.end_lineno or node.lineno) - node.lineno + 1
|
|
48
|
-
if length > max_lines:
|
|
49
|
-
violations.append(Violation(
|
|
50
|
-
file=str(path), line=node.lineno, type='function',
|
|
51
|
-
name=node.name, actual=length, limit=max_lines
|
|
52
|
-
))
|
|
53
|
-
except (SyntaxError, Exception):
|
|
54
|
-
pass
|
|
55
|
-
return violations
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def check_js_functions(path: Path, max_lines: int) -> List[Violation]:
|
|
59
|
-
"""Check JS/TS function lengths using brace counting."""
|
|
60
|
-
violations = []
|
|
61
|
-
try:
|
|
62
|
-
with open(path, 'r', encoding='utf-8') as f:
|
|
63
|
-
lines = f.readlines()
|
|
64
|
-
|
|
65
|
-
func_pattern = re.compile(
|
|
66
|
-
r'(function\s+(\w+)|(\w+)\s*=\s*(async\s+)?\([^)]*\)\s*=>|'
|
|
67
|
-
r'(async\s+)?(\w+)\s*\([^)]*\)\s*\{)'
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
in_func = False
|
|
71
|
-
func_start = 0
|
|
72
|
-
func_name = 'anonymous'
|
|
73
|
-
brace_count = 0
|
|
74
|
-
|
|
75
|
-
for i, line in enumerate(lines, 1):
|
|
76
|
-
if not in_func:
|
|
77
|
-
match = func_pattern.search(line)
|
|
78
|
-
if match and '{' in line:
|
|
79
|
-
in_func = True
|
|
80
|
-
func_start = i
|
|
81
|
-
func_name = match.group(2) or match.group(3) or match.group(6) or 'anonymous'
|
|
82
|
-
brace_count = line.count('{') - line.count('}')
|
|
83
|
-
else:
|
|
84
|
-
brace_count += line.count('{') - line.count('}')
|
|
85
|
-
if brace_count <= 0:
|
|
86
|
-
length = i - func_start + 1
|
|
87
|
-
if length > max_lines:
|
|
88
|
-
violations.append(Violation(
|
|
89
|
-
file=str(path), line=func_start, type='function',
|
|
90
|
-
name=func_name, actual=length, limit=max_lines
|
|
91
|
-
))
|
|
92
|
-
in_func = False
|
|
93
|
-
brace_count = 0
|
|
94
|
-
except Exception:
|
|
95
|
-
pass
|
|
96
|
-
return violations
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
def check_go_functions(path: Path, max_lines: int) -> List[Violation]:
|
|
100
|
-
"""Check Go function lengths."""
|
|
101
|
-
violations = []
|
|
102
|
-
try:
|
|
103
|
-
with open(path, 'r', encoding='utf-8') as f:
|
|
104
|
-
lines = f.readlines()
|
|
105
|
-
|
|
106
|
-
func_pattern = re.compile(r'^func\s+(\w+|\([^)]+\)\s+\w+)\s*\(')
|
|
107
|
-
in_func = False
|
|
108
|
-
func_start = 0
|
|
109
|
-
func_name = ''
|
|
110
|
-
brace_count = 0
|
|
111
|
-
|
|
112
|
-
for i, line in enumerate(lines, 1):
|
|
113
|
-
if not in_func:
|
|
114
|
-
match = func_pattern.match(line)
|
|
115
|
-
if match:
|
|
116
|
-
in_func = True
|
|
117
|
-
func_start = i
|
|
118
|
-
func_name = match.group(1).split()[-1]
|
|
119
|
-
brace_count = line.count('{') - line.count('}')
|
|
120
|
-
else:
|
|
121
|
-
brace_count += line.count('{') - line.count('}')
|
|
122
|
-
if brace_count <= 0:
|
|
123
|
-
length = i - func_start + 1
|
|
124
|
-
if length > max_lines:
|
|
125
|
-
violations.append(Violation(
|
|
126
|
-
file=str(path), line=func_start, type='function',
|
|
127
|
-
name=func_name, actual=length, limit=max_lines
|
|
128
|
-
))
|
|
129
|
-
in_func = False
|
|
130
|
-
except Exception:
|
|
131
|
-
pass
|
|
132
|
-
return violations
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def check_java_functions(path: Path, max_lines: int) -> List[Violation]:
|
|
136
|
-
"""Check Java method lengths."""
|
|
137
|
-
violations = []
|
|
138
|
-
try:
|
|
139
|
-
with open(path, 'r', encoding='utf-8') as f:
|
|
140
|
-
lines = f.readlines()
|
|
141
|
-
|
|
142
|
-
method_pattern = re.compile(
|
|
143
|
-
r'(public|private|protected|static|\s)+[\w<>\[\]]+\s+(\w+)\s*\([^)]*\)\s*(\{|throws)'
|
|
144
|
-
)
|
|
145
|
-
in_method = False
|
|
146
|
-
method_start = 0
|
|
147
|
-
method_name = ''
|
|
148
|
-
brace_count = 0
|
|
149
|
-
|
|
150
|
-
for i, line in enumerate(lines, 1):
|
|
151
|
-
if not in_method:
|
|
152
|
-
match = method_pattern.search(line)
|
|
153
|
-
if match and '{' in line:
|
|
154
|
-
in_method = True
|
|
155
|
-
method_start = i
|
|
156
|
-
method_name = match.group(2)
|
|
157
|
-
brace_count = line.count('{') - line.count('}')
|
|
158
|
-
else:
|
|
159
|
-
brace_count += line.count('{') - line.count('}')
|
|
160
|
-
if brace_count <= 0:
|
|
161
|
-
length = i - method_start + 1
|
|
162
|
-
if length > max_lines:
|
|
163
|
-
violations.append(Violation(
|
|
164
|
-
file=str(path), line=method_start, type='function',
|
|
165
|
-
name=method_name, actual=length, limit=max_lines
|
|
166
|
-
))
|
|
167
|
-
in_method = False
|
|
168
|
-
except Exception:
|
|
169
|
-
pass
|
|
170
|
-
return violations
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
def check_rust_functions(path: Path, max_lines: int) -> List[Violation]:
|
|
174
|
-
"""Check Rust function lengths."""
|
|
175
|
-
violations = []
|
|
176
|
-
try:
|
|
177
|
-
with open(path, 'r', encoding='utf-8') as f:
|
|
178
|
-
lines = f.readlines()
|
|
179
|
-
|
|
180
|
-
func_pattern = re.compile(r'^\s*(pub\s+)?(async\s+)?fn\s+(\w+)')
|
|
181
|
-
in_func = False
|
|
182
|
-
func_start = 0
|
|
183
|
-
func_name = ''
|
|
184
|
-
brace_count = 0
|
|
185
|
-
|
|
186
|
-
for i, line in enumerate(lines, 1):
|
|
187
|
-
if not in_func:
|
|
188
|
-
match = func_pattern.match(line)
|
|
189
|
-
if match and '{' in line:
|
|
190
|
-
in_func = True
|
|
191
|
-
func_start = i
|
|
192
|
-
func_name = match.group(3)
|
|
193
|
-
brace_count = line.count('{') - line.count('}')
|
|
194
|
-
else:
|
|
195
|
-
brace_count += line.count('{') - line.count('}')
|
|
196
|
-
if brace_count <= 0:
|
|
197
|
-
length = i - func_start + 1
|
|
198
|
-
if length > max_lines:
|
|
199
|
-
violations.append(Violation(
|
|
200
|
-
file=str(path), line=func_start, type='function',
|
|
201
|
-
name=func_name, actual=length, limit=max_lines
|
|
202
|
-
))
|
|
203
|
-
in_func = False
|
|
204
|
-
except Exception:
|
|
205
|
-
pass
|
|
206
|
-
return violations
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
LANG_CHECKERS = {
|
|
210
|
-
'.py': check_python_functions,
|
|
211
|
-
'.js': check_js_functions,
|
|
212
|
-
'.ts': check_js_functions,
|
|
213
|
-
'.tsx': check_js_functions,
|
|
214
|
-
'.jsx': check_js_functions,
|
|
215
|
-
'.go': check_go_functions,
|
|
216
|
-
'.java': check_java_functions,
|
|
217
|
-
'.rs': check_rust_functions,
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
SKIP_DIRS = {'node_modules', '.git', 'dist', 'build', '__pycache__', '.venv',
|
|
221
|
-
'venv', 'vendor', 'target', '.next', 'coverage'}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
def scan_directory(path: Path, max_file: int, max_func: int) -> List[Violation]:
|
|
225
|
-
"""Scan directory for size violations."""
|
|
226
|
-
violations = []
|
|
227
|
-
|
|
228
|
-
for root, dirs, files in os.walk(path):
|
|
229
|
-
dirs[:] = [d for d in dirs if d not in SKIP_DIRS]
|
|
230
|
-
|
|
231
|
-
for file in files:
|
|
232
|
-
filepath = Path(root) / file
|
|
233
|
-
ext = filepath.suffix.lower()
|
|
234
|
-
|
|
235
|
-
if ext not in LANG_CHECKERS:
|
|
236
|
-
continue
|
|
237
|
-
|
|
238
|
-
# Check file length
|
|
239
|
-
file_lines = count_file_lines(filepath)
|
|
240
|
-
if file_lines > max_file:
|
|
241
|
-
violations.append(Violation(
|
|
242
|
-
file=str(filepath), line=1, type='file',
|
|
243
|
-
name=file, actual=file_lines, limit=max_file
|
|
244
|
-
))
|
|
245
|
-
|
|
246
|
-
# Check function lengths
|
|
247
|
-
checker = LANG_CHECKERS.get(ext)
|
|
248
|
-
if checker:
|
|
249
|
-
violations.extend(checker(filepath, max_func))
|
|
250
|
-
|
|
251
|
-
return violations
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
def generate_report(violations: List[Violation]) -> str:
|
|
255
|
-
"""Generate markdown report."""
|
|
256
|
-
if not violations:
|
|
257
|
-
return "# Size Check Report\n\n**Status:** ✅ PASS\n\nNo design principle violations found."
|
|
258
|
-
|
|
259
|
-
file_v = [v for v in violations if v.type == 'file']
|
|
260
|
-
func_v = [v for v in violations if v.type == 'function']
|
|
261
|
-
|
|
262
|
-
lines = [
|
|
263
|
-
"# Size Check Report",
|
|
264
|
-
"",
|
|
265
|
-
"**Status:** ⚠️ WARNING",
|
|
266
|
-
"",
|
|
267
|
-
f"**Total Violations:** {len(violations)}",
|
|
268
|
-
f"- Files exceeding limit: {len(file_v)}",
|
|
269
|
-
f"- Functions exceeding limit: {len(func_v)}",
|
|
270
|
-
""
|
|
271
|
-
]
|
|
272
|
-
|
|
273
|
-
if file_v:
|
|
274
|
-
lines.extend([
|
|
275
|
-
"## Files Exceeding 500 Lines",
|
|
276
|
-
"",
|
|
277
|
-
"| File | Lines | Limit |",
|
|
278
|
-
"|------|-------|-------|"
|
|
279
|
-
])
|
|
280
|
-
for v in sorted(file_v, key=lambda x: -x.actual):
|
|
281
|
-
lines.append(f"| `{v.file}` | {v.actual} | {v.limit} |")
|
|
282
|
-
lines.append("")
|
|
283
|
-
|
|
284
|
-
if func_v:
|
|
285
|
-
lines.extend([
|
|
286
|
-
"## Functions Exceeding 50 Lines",
|
|
287
|
-
"",
|
|
288
|
-
"| File | Line | Function | Lines | Limit |",
|
|
289
|
-
"|------|------|----------|-------|-------|"
|
|
290
|
-
])
|
|
291
|
-
for v in sorted(func_v, key=lambda x: -x.actual):
|
|
292
|
-
lines.append(f"| `{v.file}` | {v.line} | `{v.name}` | {v.actual} | {v.limit} |")
|
|
293
|
-
lines.append("")
|
|
294
|
-
|
|
295
|
-
lines.extend([
|
|
296
|
-
"## Remediation",
|
|
297
|
-
"",
|
|
298
|
-
"### Large Files",
|
|
299
|
-
"- Identify logical groupings",
|
|
300
|
-
"- Extract to separate modules",
|
|
301
|
-
"",
|
|
302
|
-
"### Long Functions",
|
|
303
|
-
"- Extract helper functions",
|
|
304
|
-
"- Apply single responsibility principle"
|
|
305
|
-
])
|
|
306
|
-
|
|
307
|
-
return "\n".join(lines)
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
def main():
|
|
311
|
-
parser = argparse.ArgumentParser(description='Check code size limits (warning only)')
|
|
312
|
-
parser.add_argument('--path', default='.', help='Directory to scan')
|
|
313
|
-
parser.add_argument('--max-file-lines', type=int, default=500)
|
|
314
|
-
parser.add_argument('--max-function-lines', type=int, default=50)
|
|
315
|
-
parser.add_argument('--output', help='Output file (default: stdout)')
|
|
316
|
-
|
|
317
|
-
args = parser.parse_args()
|
|
318
|
-
violations = scan_directory(Path(args.path), args.max_file_lines, args.max_function_lines)
|
|
319
|
-
report = generate_report(violations)
|
|
320
|
-
|
|
321
|
-
if args.output:
|
|
322
|
-
with open(args.output, 'w') as f:
|
|
323
|
-
f.write(report)
|
|
324
|
-
print(f"Report saved to {args.output}")
|
|
325
|
-
else:
|
|
326
|
-
print(report)
|
|
327
|
-
|
|
328
|
-
# Exit 1 if violations (for CI awareness), but documented as warning only
|
|
329
|
-
sys.exit(1 if violations else 0)
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
if __name__ == '__main__':
|
|
333
|
-
main()
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# AI Sprint Statusline
|
|
3
|
-
# Displays: directory, git branch, model, context usage, cost
|
|
4
|
-
# Requires: jq (optional - graceful fallback without it)
|
|
5
|
-
|
|
6
|
-
set -euo pipefail
|
|
7
|
-
|
|
8
|
-
# Check for jq
|
|
9
|
-
HAS_JQ=false
|
|
10
|
-
command -v jq >/dev/null 2>&1 && HAS_JQ=true
|
|
11
|
-
|
|
12
|
-
# Read JSON from stdin
|
|
13
|
-
INPUT=$(cat)
|
|
14
|
-
|
|
15
|
-
# Fallback without jq
|
|
16
|
-
if ! $HAS_JQ; then
|
|
17
|
-
echo "🚀 AI Sprint"
|
|
18
|
-
exit 0
|
|
19
|
-
fi
|
|
20
|
-
|
|
21
|
-
# --- Helper Functions ---
|
|
22
|
-
|
|
23
|
-
# Expand home directory to ~
|
|
24
|
-
expand_home() {
|
|
25
|
-
local path="$1"
|
|
26
|
-
echo "${path/#$HOME/~}"
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
# Get git branch
|
|
30
|
-
get_git_branch() {
|
|
31
|
-
if git rev-parse --git-dir >/dev/null 2>&1; then
|
|
32
|
-
git branch --show-current 2>/dev/null || git rev-parse --short HEAD 2>/dev/null || echo ""
|
|
33
|
-
fi
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
# Progress bar (12 chars): ▰▰▰▱▱▱▱▱▱▱▱▱
|
|
37
|
-
progress_bar() {
|
|
38
|
-
local percent=${1:-0}
|
|
39
|
-
local width=12
|
|
40
|
-
|
|
41
|
-
# Clamp to 0-100
|
|
42
|
-
(( percent < 0 )) && percent=0
|
|
43
|
-
(( percent > 100 )) && percent=100
|
|
44
|
-
|
|
45
|
-
local filled=$((percent * width / 100))
|
|
46
|
-
local empty=$((width - filled))
|
|
47
|
-
|
|
48
|
-
local bar=""
|
|
49
|
-
for ((i=0; i<filled; i++)); do bar+="▰"; done
|
|
50
|
-
for ((i=0; i<empty; i++)); do bar+="▱"; done
|
|
51
|
-
|
|
52
|
-
echo "$bar"
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
# Severity emoji based on percentage
|
|
56
|
-
severity_emoji() {
|
|
57
|
-
local percent=${1:-0}
|
|
58
|
-
if (( percent >= 90 )); then echo "🔴"
|
|
59
|
-
elif (( percent >= 70 )); then echo "🟡"
|
|
60
|
-
else echo "🟢"
|
|
61
|
-
fi
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
# --- Parse JSON ---
|
|
65
|
-
|
|
66
|
-
# Directory
|
|
67
|
-
CWD=$(echo "$INPUT" | jq -r '.workspace.current_dir // .cwd // "unknown"')
|
|
68
|
-
CWD=$(expand_home "$CWD")
|
|
69
|
-
|
|
70
|
-
# Model
|
|
71
|
-
MODEL=$(echo "$INPUT" | jq -r '.model.display_name // "Claude"')
|
|
72
|
-
|
|
73
|
-
# Context window
|
|
74
|
-
INPUT_TOKENS=$(echo "$INPUT" | jq -r '.context_window.total_input_tokens // 0')
|
|
75
|
-
OUTPUT_TOKENS=$(echo "$INPUT" | jq -r '.context_window.total_output_tokens // 0')
|
|
76
|
-
CONTEXT_SIZE=$(echo "$INPUT" | jq -r '.context_window.context_window_size // 0')
|
|
77
|
-
|
|
78
|
-
CONTEXT_PCT=0
|
|
79
|
-
if (( CONTEXT_SIZE > 0 )); then
|
|
80
|
-
TOTAL_TOKENS=$((INPUT_TOKENS + OUTPUT_TOKENS))
|
|
81
|
-
CONTEXT_PCT=$((TOTAL_TOKENS * 100 / CONTEXT_SIZE))
|
|
82
|
-
fi
|
|
83
|
-
|
|
84
|
-
# Cost (optional)
|
|
85
|
-
COST=$(echo "$INPUT" | jq -r '.cost.total_cost_usd // empty')
|
|
86
|
-
|
|
87
|
-
# Lines changed
|
|
88
|
-
LINES_ADDED=$(echo "$INPUT" | jq -r '.cost.total_lines_added // 0')
|
|
89
|
-
LINES_REMOVED=$(echo "$INPUT" | jq -r '.cost.total_lines_removed // 0')
|
|
90
|
-
|
|
91
|
-
# --- Build Output ---
|
|
92
|
-
|
|
93
|
-
OUTPUT=""
|
|
94
|
-
|
|
95
|
-
# Directory
|
|
96
|
-
OUTPUT+="📁 $CWD"
|
|
97
|
-
|
|
98
|
-
# Git branch
|
|
99
|
-
GIT_BRANCH=$(get_git_branch)
|
|
100
|
-
if [[ -n "$GIT_BRANCH" ]]; then
|
|
101
|
-
OUTPUT+=" 🌿 $GIT_BRANCH"
|
|
102
|
-
fi
|
|
103
|
-
|
|
104
|
-
# Model
|
|
105
|
-
OUTPUT+=" 🤖 $MODEL"
|
|
106
|
-
|
|
107
|
-
# Context usage
|
|
108
|
-
if (( CONTEXT_PCT > 0 )); then
|
|
109
|
-
EMOJI=$(severity_emoji "$CONTEXT_PCT")
|
|
110
|
-
BAR=$(progress_bar "$CONTEXT_PCT")
|
|
111
|
-
OUTPUT+=" $EMOJI $BAR ${CONTEXT_PCT}%"
|
|
112
|
-
fi
|
|
113
|
-
|
|
114
|
-
# Cost (only show if non-zero)
|
|
115
|
-
if [[ -n "$COST" && "$COST" != "null" && "$COST" != "0" ]]; then
|
|
116
|
-
# Format to 4 decimal places
|
|
117
|
-
COST_FMT=$(printf "%.4f" "$COST" 2>/dev/null || echo "$COST")
|
|
118
|
-
OUTPUT+=" 💵 \$$COST_FMT"
|
|
119
|
-
fi
|
|
120
|
-
|
|
121
|
-
# Lines changed
|
|
122
|
-
if (( LINES_ADDED > 0 || LINES_REMOVED > 0 )); then
|
|
123
|
-
OUTPUT+=" 📝 +$LINES_ADDED -$LINES_REMOVED"
|
|
124
|
-
fi
|
|
125
|
-
|
|
126
|
-
echo "$OUTPUT"
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
# Development Rules
|
|
2
|
-
|
|
3
|
-
Core principles enforced across all agents and commands.
|
|
4
|
-
|
|
5
|
-
## Core Principles
|
|
6
|
-
|
|
7
|
-
1. **YAGNI** - You Aren't Gonna Need It
|
|
8
|
-
2. **KISS** - Keep It Simple, Stupid
|
|
9
|
-
3. **DRY** - Don't Repeat Yourself
|
|
10
|
-
4. **SRP** - Single Responsibility Principle
|
|
11
|
-
5. **Security-First** - Security in every layer
|
|
12
|
-
|
|
13
|
-
## Design Principles Enforcement
|
|
14
|
-
|
|
15
|
-
### Size Limits (Warning level - non-blocking)
|
|
16
|
-
| Metric | Limit | Action if Exceeded |
|
|
17
|
-
|--------|-------|-------------------|
|
|
18
|
-
| File lines | 500 | Split into modules |
|
|
19
|
-
| Function lines | 50 | Extract helpers |
|
|
20
|
-
| Parameters | 4 | Use options object |
|
|
21
|
-
| Nesting levels | 3 | Use early returns |
|
|
22
|
-
|
|
23
|
-
### YAGNI Checklist
|
|
24
|
-
- Only build explicitly requested features
|
|
25
|
-
- Delete unused code immediately
|
|
26
|
-
- No "future-proofing" abstractions
|
|
27
|
-
- No unused parameters "for later"
|
|
28
|
-
|
|
29
|
-
### KISS Checklist
|
|
30
|
-
- Prefer explicit over implicit
|
|
31
|
-
- Prefer flat over nested
|
|
32
|
-
- Prefer composition over inheritance
|
|
33
|
-
- No clever code - readable > clever
|
|
34
|
-
|
|
35
|
-
### SRP Checklist
|
|
36
|
-
- One file = one concept
|
|
37
|
-
- One function = one operation
|
|
38
|
-
- If name needs "and" → split it
|
|
39
|
-
|
|
40
|
-
### Automated Checking
|
|
41
|
-
Run size checker (warning only):
|
|
42
|
-
```bash
|
|
43
|
-
python3 .claude/skills/quality-assurance/scripts/check-size.py
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Included in `/ai-sprint-review` and `/ai-sprint-validate` workflows.
|
|
47
|
-
|
|
48
|
-
## Date Handling
|
|
49
|
-
|
|
50
|
-
**CRITICAL**: Never guess dates. Always use bash:
|
|
51
|
-
```bash
|
|
52
|
-
date "+%Y-%m-%d" # For reports: 2025-12-24
|
|
53
|
-
date "+%y%m%d-%H%M" # For filenames: 251224-2115
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Context Engineering
|
|
57
|
-
|
|
58
|
-
All AI context stored under `ai_context/`:
|
|
59
|
-
```
|
|
60
|
-
ai_context/
|
|
61
|
-
├── plans/ # Implementation plans
|
|
62
|
-
├── docs/ # AI-specific documentation
|
|
63
|
-
├── refs/ # Reference materials
|
|
64
|
-
├── memory/ # Session memory
|
|
65
|
-
│ ├── learning.md # Retrospective lessons
|
|
66
|
-
│ ├── decisions.md # Key decisions log
|
|
67
|
-
│ └── active.md # Current session state
|
|
68
|
-
└── reports/ # Agent reports
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## Memory Integration
|
|
72
|
-
|
|
73
|
-
Before any task:
|
|
74
|
-
- Check `ai_context/memory/learning.md` for past lessons
|
|
75
|
-
|
|
76
|
-
After any task:
|
|
77
|
-
- Update `ai_context/memory/learning.md` with new lessons
|
|
78
|
-
- Record decisions in `ai_context/memory/decisions.md`
|
|
79
|
-
|
|
80
|
-
## Quality Gates
|
|
81
|
-
|
|
82
|
-
### Code Quality
|
|
83
|
-
- [ ] All tests passing
|
|
84
|
-
- [ ] >80% code coverage
|
|
85
|
-
- [ ] No linting errors
|
|
86
|
-
- [ ] Types complete (TypeScript)
|
|
87
|
-
|
|
88
|
-
### Security
|
|
89
|
-
- [ ] No hardcoded secrets
|
|
90
|
-
- [ ] Input validation present
|
|
91
|
-
- [ ] OWASP Top 10 compliant
|
|
92
|
-
- [ ] Security scan passed
|
|
93
|
-
|
|
94
|
-
### Documentation
|
|
95
|
-
- [ ] Code comments where needed
|
|
96
|
-
- [ ] API documented
|
|
97
|
-
- [ ] README updated
|
|
98
|
-
|
|
99
|
-
## Agent DO NOT Directives
|
|
100
|
-
|
|
101
|
-
Every agent must follow:
|
|
102
|
-
- DO NOT guess dates - use bash date command
|
|
103
|
-
- DO NOT hardcode secrets
|
|
104
|
-
- DO NOT skip security checks
|
|
105
|
-
- DO NOT leave failing tests
|
|
106
|
-
- DO NOT modify code without reading it first
|
|
107
|
-
|
|
108
|
-
## Output Standards
|
|
109
|
-
|
|
110
|
-
### Reports
|
|
111
|
-
- Save to `ai_context/reports/` with timestamped filename
|
|
112
|
-
- Use format: `{type}-{YYMMDD}-{slug}.md`
|
|
113
|
-
- Include date from bash command
|
|
114
|
-
|
|
115
|
-
### Plans
|
|
116
|
-
- Save to `ai_context/ai-sprint-plans/` with timestamped folder
|
|
117
|
-
- Use format: `{YYMMDD-HHMM}-{feature}/`
|
|
118
|
-
- Include phase files if complex
|
|
119
|
-
|
|
120
|
-
## Review Before Commit
|
|
121
|
-
|
|
122
|
-
All code changes must pass:
|
|
123
|
-
1. `/ai-sprint-test` - All tests pass
|
|
124
|
-
2. `/ai-sprint-review` - Code quality check
|
|
125
|
-
3. `/ai-sprint-secure` - Security scan
|
|
126
|
-
|
|
127
|
-
## Human-in-the-Loop Gates
|
|
128
|
-
|
|
129
|
-
Require user approval for:
|
|
130
|
-
- Production deployments
|
|
131
|
-
- Infrastructure changes
|
|
132
|
-
- Database migrations
|
|
133
|
-
- Security vulnerability fixes
|