claude-dev-env 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/LICENSE +21 -0
- package/README.md +219 -0
- package/agents/agent-writer.md +157 -0
- package/agents/clasp-deployment-orchestrator.md +609 -0
- package/agents/clean-coder.md +295 -0
- package/agents/code-quality-agent.md +40 -0
- package/agents/code-standards-agent.md +93 -0
- package/agents/config-centralizer.md +686 -0
- package/agents/config-extraction-agent.md +225 -0
- package/agents/doc-orchestrator.md +47 -0
- package/agents/docs-agent.md +112 -0
- package/agents/docx-agent.md +211 -0
- package/agents/git-commit-crafter.md +100 -0
- package/agents/magic-value-eliminator-agent.md +72 -0
- package/agents/mandatory-agent-workflow-agent.md +88 -0
- package/agents/parallel-workflow-coordinator.md +779 -0
- package/agents/pdf-agent.md +302 -0
- package/agents/plan-executor.md +226 -0
- package/agents/pr-description-writer.md +87 -0
- package/agents/project-context-loader.md +238 -0
- package/agents/project-docs-analyzer.md +54 -0
- package/agents/project-structure-organizer-agent.md +72 -0
- package/agents/readability-review-agent.md +76 -0
- package/agents/refactoring-specialist.md +69 -0
- package/agents/right-sized-engineer.md +129 -0
- package/agents/session-continuity-manager.md +53 -0
- package/agents/skill-to-agent-converter.md +371 -0
- package/agents/skill-writer-agent.md +470 -0
- package/agents/stub-detector-agent.md +140 -0
- package/agents/tdd-test-writer.md +62 -0
- package/agents/test-data-builder.md +68 -0
- package/agents/tooling-builder.md +78 -0
- package/agents/user-docs-writer.md +67 -0
- package/agents/validation-expert.md +71 -0
- package/agents/workflow-visual-documenter.md +82 -0
- package/agents/xlsx-agent.md +169 -0
- package/bin/install.mjs +256 -0
- package/commands/commit.md +28 -0
- package/commands/docupdate.md +322 -0
- package/commands/implement.md +102 -0
- package/commands/initialize.md +91 -0
- package/commands/plan.md +63 -0
- package/commands/pr-comments.md +47 -0
- package/commands/readability-review.md +20 -0
- package/commands/review-plan.md +7 -0
- package/commands/right-size.md +15 -0
- package/commands/stubcheck.md +89 -0
- package/commands/sum.md +30 -0
- package/docs/CODE_RULES.md +186 -0
- package/docs/DJANGO_PATTERNS.md +80 -0
- package/docs/REACT_PATTERNS.md +185 -0
- package/docs/TEST_QUALITY.md +104 -0
- package/hooks/advisory/migration-safety-advisor.py +49 -0
- package/hooks/advisory/refactor-guard.py +205 -0
- package/hooks/blocking/block-main-commit.py +168 -0
- package/hooks/blocking/code-rules-enforcer.py +549 -0
- package/hooks/blocking/destructive-command-blocker.py +107 -0
- package/hooks/blocking/docker-settings-guard.py +44 -0
- package/hooks/blocking/hedging-language-blocker.py +130 -0
- package/hooks/blocking/parallel-task-blocker.py +69 -0
- package/hooks/blocking/pr-description-enforcer.py +87 -0
- package/hooks/blocking/pyautogui-scroll-blocker.py +74 -0
- package/hooks/blocking/sensitive-file-protector.py +70 -0
- package/hooks/blocking/tdd-enforcer.py +62 -0
- package/hooks/blocking/test-preflight-check.py +343 -0
- package/hooks/blocking/write-existing-file-blocker.py +63 -0
- package/hooks/git-hooks/post-commit.py +103 -0
- package/hooks/github-action/test_workflow.py +33 -0
- package/hooks/hooks.json +246 -0
- package/hooks/lifecycle/config-change-guard.py +84 -0
- package/hooks/lifecycle/session-end-cleanup.py +59 -0
- package/hooks/notification/attention-needed-notify.py +63 -0
- package/hooks/notification/claude-notification-handler.py +59 -0
- package/hooks/notification/notification_utils.py +206 -0
- package/hooks/rewrite-plugin-paths.py +116 -0
- package/hooks/session/bulk-edit-reminder.py +30 -0
- package/hooks/session/code-rules-reminder.py +97 -0
- package/hooks/session/compact-context-reinject.py +39 -0
- package/hooks/session/hook-structure-context.py +140 -0
- package/hooks/session/plugin-data-dir-cleanup.py +39 -0
- package/hooks/validation/code-style-validator.py +145 -0
- package/hooks/validation/e2e-test-validator.py +142 -0
- package/hooks/validation/hook-format-validator.py +66 -0
- package/hooks/validation/mypy_validator.py +180 -0
- package/hooks/validators/README.md +125 -0
- package/hooks/validators/VALIDATION_REPORT.md +287 -0
- package/hooks/validators/__init__.py +19 -0
- package/hooks/validators/abbreviation_checks.py +82 -0
- package/hooks/validators/code_quality_checks.py +133 -0
- package/hooks/validators/comment_checks.py +188 -0
- package/hooks/validators/file_structure_checks.py +182 -0
- package/hooks/validators/git_checks.py +107 -0
- package/hooks/validators/health_check.py +214 -0
- package/hooks/validators/magic_value_checks.py +81 -0
- package/hooks/validators/mypy_integration.py +52 -0
- package/hooks/validators/output_formatter.py +266 -0
- package/hooks/validators/pr_reference_checks.py +72 -0
- package/hooks/validators/python_antipattern_checks.py +110 -0
- package/hooks/validators/python_style_checks.py +364 -0
- package/hooks/validators/react_checks.py +90 -0
- package/hooks/validators/ruff_integration.py +80 -0
- package/hooks/validators/run_all_validators.py +772 -0
- package/hooks/validators/security_checks.py +135 -0
- package/hooks/validators/test_abbreviation_checks.py +76 -0
- package/hooks/validators/test_bad.tsx +7 -0
- package/hooks/validators/test_code_quality_checks.py +129 -0
- package/hooks/validators/test_file_structure_checks.py +307 -0
- package/hooks/validators/test_files/01_basic_component.tsx +10 -0
- package/hooks/validators/test_files/02_component_without_react.tsx +10 -0
- package/hooks/validators/test_files/03_pure_component.tsx +10 -0
- package/hooks/validators/test_files/04_pure_component_import.tsx +10 -0
- package/hooks/validators/test_files/05_typescript_generics.tsx +14 -0
- package/hooks/validators/test_files/06_typescript_two_generics.tsx +18 -0
- package/hooks/validators/test_files/07_multiline_declaration.tsx +11 -0
- package/hooks/validators/test_files/08_error_boundary_valid.tsx +14 -0
- package/hooks/validators/test_files/09_error_boundary_with_other_class.tsx +20 -0
- package/hooks/validators/test_files/10_inheritance_chain.tsx +16 -0
- package/hooks/validators/test_files/11_ts_file.ts +10 -0
- package/hooks/validators/test_files/12_non_react_class.tsx +14 -0
- package/hooks/validators/test_files/13_functional_component.tsx +8 -0
- package/hooks/validators/test_files/14_indented_class.tsx +13 -0
- package/hooks/validators/test_files/15_getDerivedStateFromError.tsx +14 -0
- package/hooks/validators/test_files/16_mixed_components.tsx +20 -0
- package/hooks/validators/test_files/EXECUTIVE_SUMMARY.md +175 -0
- package/hooks/validators/test_files/TEST_RESULTS_TABLE.txt +60 -0
- package/hooks/validators/test_files/VALIDATION_REPORT.md +201 -0
- package/hooks/validators/test_files/async_views.py +23 -0
- package/hooks/validators/test_files/async_with_imports.py +14 -0
- package/hooks/validators/test_files/bad_inline_imports.py +37 -0
- package/hooks/validators/test_files/management/commands/cmd_01_no_debug_check.py +10 -0
- package/hooks/validators/test_files/management/commands/cmd_02_proper_debug_check.py +14 -0
- package/hooks/validators/test_files/management/commands/cmd_03_debug_check_with_return.py +14 -0
- package/hooks/validators/test_files/management/commands/cmd_04_imported_DEBUG.py +14 -0
- package/hooks/validators/test_files/management/commands/cmd_05_debug_check_in_helper.py +16 -0
- package/hooks/validators/test_files/management/commands/cmd_06_debug_check_late.py +22 -0
- package/hooks/validators/test_files/management/commands/cmd_07_positive_debug_check.py +15 -0
- package/hooks/validators/test_files/management/commands/cmd_08_debug_with_and.py +14 -0
- package/hooks/validators/test_files/not_management_command.py +10 -0
- package/hooks/validators/test_files/skip_decorators/test_01_simple_skip.py +8 -0
- package/hooks/validators/test_files/skip_decorators/test_02_pytest_skipif.py +8 -0
- package/hooks/validators/test_files/skip_decorators/test_03_unittest_skipIf.py +8 -0
- package/hooks/validators/test_files/skip_decorators/test_04_skip_with_parens.py +8 -0
- package/hooks/validators/test_files/skip_decorators/test_05_xfail.py +7 -0
- package/hooks/validators/test_files/skip_decorators/test_06_custom_skip.py +11 -0
- package/hooks/validators/test_files/skip_decorators/test_07_capital_Skip.py +8 -0
- package/hooks/validators/test_files/skip_decorators/test_08_skipUnless.py +7 -0
- package/hooks/validators/test_files/skip_decorators/test_09_pytest_mark_skip_simple.py +7 -0
- package/hooks/validators/test_files/test_async_functions.py +45 -0
- package/hooks/validators/test_files/test_purecomponent/PureComponentExample.tsx +7 -0
- package/hooks/validators/test_files/test_purecomponent/ReactPureComponentExample.tsx +7 -0
- package/hooks/validators/test_git_checks.py +295 -0
- package/hooks/validators/test_good.tsx +5 -0
- package/hooks/validators/test_health_check.py +57 -0
- package/hooks/validators/test_magic_value_checks.py +63 -0
- package/hooks/validators/test_mypy_integration.py +27 -0
- package/hooks/validators/test_output_formatter.py +150 -0
- package/hooks/validators/test_pr_reference_checks.py +41 -0
- package/hooks/validators/test_python_antipattern_checks.py +113 -0
- package/hooks/validators/test_python_style_checks.py +439 -0
- package/hooks/validators/test_react_checks.py +213 -0
- package/hooks/validators/test_results.txt +25 -0
- package/hooks/validators/test_ruff_integration.py +27 -0
- package/hooks/validators/test_run_all_validators.py +228 -0
- package/hooks/validators/test_run_all_validators_integration.py +48 -0
- package/hooks/validators/test_safety_checks.py +243 -0
- package/hooks/validators/test_security_checks.py +105 -0
- package/hooks/validators/test_test_safety_checks.py +321 -0
- package/hooks/validators/test_todo_checks.py +39 -0
- package/hooks/validators/test_type_safety_checks.py +85 -0
- package/hooks/validators/test_useless_test_checks.py +55 -0
- package/hooks/validators/test_validator_base.py +26 -0
- package/hooks/validators/test_verify_paths.py +34 -0
- package/hooks/validators/todo_checks.py +59 -0
- package/hooks/validators/type_safety_checks.py +101 -0
- package/hooks/validators/useless_test_checks.py +92 -0
- package/hooks/validators/validator_base.py +19 -0
- package/hooks/validators/verify_paths.py +57 -0
- package/hooks/workflow/auto-formatter.py +114 -0
- package/hooks/workflow/investigation-tracker-reset.py +46 -0
- package/package.json +30 -0
- package/rules/agent-spawn-protocol.md +47 -0
- package/rules/cleanup-temp-files.md +27 -0
- package/rules/code-reviews.md +11 -0
- package/rules/code-standards.md +43 -0
- package/rules/conservative-action.md +20 -0
- package/rules/context7.md +12 -0
- package/rules/explore-thoroughly.md +27 -0
- package/rules/git-workflow.md +42 -0
- package/rules/parallel-tools.md +23 -0
- package/rules/research-mode.md +23 -0
- package/rules/right-sized-engineering.md +28 -0
- package/rules/tdd.md +7 -0
- package/rules/testing.md +12 -0
- package/skills/agent-prompt/SKILL.md +102 -0
- package/skills/anthropic-plan/SKILL.md +107 -0
- package/skills/everything-search/SKILL.md +144 -0
- package/skills/ingest/SKILL.md +40 -0
- package/skills/npm-creator/SKILL.md +183 -0
- package/skills/pr-review-responder/EXAMPLES.md +590 -0
- package/skills/pr-review-responder/PRINCIPLES.md +539 -0
- package/skills/pr-review-responder/README.md +209 -0
- package/skills/pr-review-responder/SKILL.md +202 -0
- package/skills/pr-review-responder/TESTING.md +407 -0
- package/skills/pr-review-responder/scripts/respond_to_reviews.py +376 -0
- package/skills/pr-review-responder/update_skill.py +297 -0
- package/skills/prompt-generator/REFERENCE.md +150 -0
- package/skills/prompt-generator/SKILL.md +154 -0
- package/skills/readability-review/SKILL.md +127 -0
- package/skills/recall/SKILL.md +27 -0
- package/skills/remember/SKILL.md +63 -0
- package/skills/rule-audit/SKILL.md +307 -0
- package/skills/rule-creator/SKILL.md +150 -0
- package/skills/skill-writer/REFERENCE.md +246 -0
- package/skills/skill-writer/SKILL.md +270 -0
- package/skills/tdd-team/SKILL.md +128 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Type safety checks validator.
|
|
2
|
+
|
|
3
|
+
Implements:
|
|
4
|
+
- Check 39: Missing type hints on functions
|
|
5
|
+
- Check 40: Any type usage
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import ast
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import List
|
|
12
|
+
|
|
13
|
+
from validator_base import Violation
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def check_missing_type_hints(tree: ast.AST, filename: str) -> List[Violation]:
|
|
17
|
+
violations: List[Violation] = []
|
|
18
|
+
|
|
19
|
+
for node in ast.walk(tree):
|
|
20
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
21
|
+
if node.name.startswith("_") and node.name != "__init__":
|
|
22
|
+
continue
|
|
23
|
+
|
|
24
|
+
if node.returns is None:
|
|
25
|
+
violations.append(
|
|
26
|
+
Violation(
|
|
27
|
+
filename,
|
|
28
|
+
node.lineno,
|
|
29
|
+
f"Function '{node.name}' missing return type annotation",
|
|
30
|
+
)
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
for arg in node.args.args:
|
|
34
|
+
if arg.arg == "self" or arg.arg == "cls":
|
|
35
|
+
continue
|
|
36
|
+
if arg.annotation is None:
|
|
37
|
+
violations.append(
|
|
38
|
+
Violation(
|
|
39
|
+
filename,
|
|
40
|
+
node.lineno,
|
|
41
|
+
f"Parameter '{arg.arg}' in '{node.name}' missing type annotation",
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
return violations
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def check_any_type(tree: ast.AST, filename: str) -> List[Violation]:
|
|
49
|
+
violations: List[Violation] = []
|
|
50
|
+
|
|
51
|
+
for node in ast.walk(tree):
|
|
52
|
+
if isinstance(node, ast.Name) and node.id == "Any":
|
|
53
|
+
violations.append(
|
|
54
|
+
Violation(
|
|
55
|
+
filename,
|
|
56
|
+
node.lineno,
|
|
57
|
+
"Any type used - use specific type or generic",
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
return violations
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def validate_file(file_path: Path) -> List[Violation]:
|
|
65
|
+
violations: List[Violation] = []
|
|
66
|
+
filename = str(file_path)
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
source = file_path.read_text(encoding="utf-8")
|
|
70
|
+
tree = ast.parse(source)
|
|
71
|
+
except Exception as error:
|
|
72
|
+
return [Violation(filename, 0, f"Error: {error}")]
|
|
73
|
+
|
|
74
|
+
violations.extend(check_missing_type_hints(tree, filename))
|
|
75
|
+
violations.extend(check_any_type(tree, filename))
|
|
76
|
+
|
|
77
|
+
return violations
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def main() -> int:
|
|
81
|
+
if len(sys.argv) < 2:
|
|
82
|
+
print("Usage: type_safety_checks.py <file1.py> [file2.py ...]", file=sys.stderr)
|
|
83
|
+
return 1
|
|
84
|
+
|
|
85
|
+
all_violations: List[Violation] = []
|
|
86
|
+
|
|
87
|
+
for file_arg in sys.argv[1:]:
|
|
88
|
+
file_path = Path(file_arg)
|
|
89
|
+
if not file_path.exists():
|
|
90
|
+
print(f"Error: File not found: {file_path}", file=sys.stderr)
|
|
91
|
+
return 1
|
|
92
|
+
all_violations.extend(validate_file(file_path))
|
|
93
|
+
|
|
94
|
+
for violation in all_violations:
|
|
95
|
+
print(violation)
|
|
96
|
+
|
|
97
|
+
return 1 if all_violations else 0
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
if __name__ == "__main__":
|
|
101
|
+
sys.exit(main())
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Useless test detection validator.
|
|
2
|
+
|
|
3
|
+
Implements check 12: No useless tests.
|
|
4
|
+
Tests must verify behavior, not existence or constant values.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import ast
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import List
|
|
11
|
+
|
|
12
|
+
from validator_base import Violation
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def check_useless_tests(tree: ast.AST, filename: str) -> List[Violation]:
|
|
16
|
+
violations: List[Violation] = []
|
|
17
|
+
|
|
18
|
+
for node in ast.walk(tree):
|
|
19
|
+
if isinstance(node, ast.FunctionDef) and node.name.startswith("test_"):
|
|
20
|
+
for child in ast.walk(node):
|
|
21
|
+
if isinstance(child, ast.Assert):
|
|
22
|
+
if _is_callable_check(child):
|
|
23
|
+
violations.append(
|
|
24
|
+
Violation(filename, child.lineno, "Useless test: callable() check doesn't verify behavior")
|
|
25
|
+
)
|
|
26
|
+
elif _is_hasattr_check(child):
|
|
27
|
+
violations.append(
|
|
28
|
+
Violation(filename, child.lineno, "Useless test: hasattr() check doesn't verify behavior")
|
|
29
|
+
)
|
|
30
|
+
elif _is_constant_value_check(child):
|
|
31
|
+
violations.append(
|
|
32
|
+
Violation(filename, child.lineno, "Useless test: testing constant value doesn't verify behavior")
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
return violations
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _is_callable_check(node: ast.Assert) -> bool:
|
|
39
|
+
if isinstance(node.test, ast.Call):
|
|
40
|
+
if isinstance(node.test.func, ast.Name) and node.test.func.id == "callable":
|
|
41
|
+
return True
|
|
42
|
+
return False
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _is_hasattr_check(node: ast.Assert) -> bool:
|
|
46
|
+
if isinstance(node.test, ast.Call):
|
|
47
|
+
if isinstance(node.test.func, ast.Name) and node.test.func.id == "hasattr":
|
|
48
|
+
return True
|
|
49
|
+
return False
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _is_constant_value_check(node: ast.Assert) -> bool:
|
|
53
|
+
if isinstance(node.test, ast.Compare):
|
|
54
|
+
if len(node.test.ops) == 1 and isinstance(node.test.ops[0], ast.Eq):
|
|
55
|
+
left = node.test.left
|
|
56
|
+
right = node.test.comparators[0] if node.test.comparators else None
|
|
57
|
+
if isinstance(left, ast.Name) and left.id.isupper():
|
|
58
|
+
if isinstance(right, ast.Constant) and isinstance(right.value, str):
|
|
59
|
+
return True
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def validate_file(file_path: Path) -> List[Violation]:
|
|
64
|
+
filename = str(file_path)
|
|
65
|
+
if "test" not in filename.lower():
|
|
66
|
+
return []
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
source = file_path.read_text(encoding="utf-8")
|
|
70
|
+
tree = ast.parse(source)
|
|
71
|
+
except Exception as error:
|
|
72
|
+
return [Violation(filename, 0, f"Error: {error}")]
|
|
73
|
+
|
|
74
|
+
return check_useless_tests(tree, filename)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def main() -> int:
|
|
78
|
+
if len(sys.argv) < 2:
|
|
79
|
+
return 1
|
|
80
|
+
|
|
81
|
+
all_violations: List[Violation] = []
|
|
82
|
+
for file_arg in sys.argv[1:]:
|
|
83
|
+
all_violations.extend(validate_file(Path(file_arg)))
|
|
84
|
+
|
|
85
|
+
for violation in all_violations:
|
|
86
|
+
print(violation)
|
|
87
|
+
|
|
88
|
+
return 1 if all_violations else 0
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
if __name__ == "__main__":
|
|
92
|
+
sys.exit(main())
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Base classes for validators.
|
|
2
|
+
|
|
3
|
+
Provides shared dataclasses used across all validator modules.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass(frozen=True)
|
|
10
|
+
class Violation:
|
|
11
|
+
"""Represents a validation violation."""
|
|
12
|
+
|
|
13
|
+
file: str
|
|
14
|
+
line: int
|
|
15
|
+
message: str
|
|
16
|
+
|
|
17
|
+
def __str__(self) -> str:
|
|
18
|
+
"""Format as file:line: message."""
|
|
19
|
+
return f"{self.file}:{self.line}: {self.message}"
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Verify all validator paths referenced in SKILL.md exist."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
SKILL_MD_PATH = Path(__file__).parent.parent.parent / "skills" / "pr-review-responder" / "SKILL.md"
|
|
9
|
+
VALIDATORS_DIR = Path(__file__).parent
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def extract_validator_paths(content: str) -> list[str]:
|
|
13
|
+
"""Extract validator file paths from SKILL.md content."""
|
|
14
|
+
pattern = r"validators[/\\](\w+\.py)"
|
|
15
|
+
matches = re.findall(pattern, content)
|
|
16
|
+
return list(set(matches))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def verify_validators() -> int:
|
|
20
|
+
"""Verify all referenced validators exist.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
Exit code: 0 if all exist, 1 if any missing
|
|
24
|
+
"""
|
|
25
|
+
if not SKILL_MD_PATH.exists():
|
|
26
|
+
print(f"ERROR: SKILL.md not found at {SKILL_MD_PATH}")
|
|
27
|
+
return 1
|
|
28
|
+
|
|
29
|
+
content = SKILL_MD_PATH.read_text(encoding="utf-8")
|
|
30
|
+
referenced_validators = extract_validator_paths(content)
|
|
31
|
+
|
|
32
|
+
print(f"Found {len(referenced_validators)} validator references in SKILL.md")
|
|
33
|
+
print()
|
|
34
|
+
|
|
35
|
+
missing = []
|
|
36
|
+
for validator_file in sorted(referenced_validators):
|
|
37
|
+
validator_path = VALIDATORS_DIR / validator_file
|
|
38
|
+
if validator_path.exists():
|
|
39
|
+
print(f" [OK] {validator_file}")
|
|
40
|
+
else:
|
|
41
|
+
print(f" [MISSING] {validator_file}")
|
|
42
|
+
missing.append(validator_file)
|
|
43
|
+
|
|
44
|
+
print()
|
|
45
|
+
|
|
46
|
+
if missing:
|
|
47
|
+
print(f"ERROR: {len(missing)} validator(s) missing:")
|
|
48
|
+
for validator_file in missing:
|
|
49
|
+
print(f" - {validator_file}")
|
|
50
|
+
return 1
|
|
51
|
+
|
|
52
|
+
print("All referenced validators exist.")
|
|
53
|
+
return 0
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
if __name__ == "__main__":
|
|
57
|
+
sys.exit(verify_validators())
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
PYTHON_EXTENSIONS = {".py"}
|
|
10
|
+
JS_EXTENSIONS = {".js", ".ts", ".tsx", ".jsx", ".mjs", ".cjs"}
|
|
11
|
+
JSON_EXTENSIONS = {".json"}
|
|
12
|
+
PLUGIN_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
13
|
+
HOOKS_DIR = os.path.join(PLUGIN_ROOT, "hooks") + os.sep
|
|
14
|
+
PYTHON_FORMAT_TIMEOUT_SECONDS = 15
|
|
15
|
+
JS_FORMAT_TIMEOUT_SECONDS = 30
|
|
16
|
+
PRETTIER_CONFIG_NAMES = {
|
|
17
|
+
".prettierrc",
|
|
18
|
+
".prettierrc.json",
|
|
19
|
+
".prettierrc.yml",
|
|
20
|
+
".prettierrc.yaml",
|
|
21
|
+
".prettierrc.js",
|
|
22
|
+
".prettierrc.cjs",
|
|
23
|
+
".prettierrc.mjs",
|
|
24
|
+
".prettierrc.toml",
|
|
25
|
+
"prettier.config.js",
|
|
26
|
+
"prettier.config.cjs",
|
|
27
|
+
"prettier.config.mjs",
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def has_prettier_config(file_path: str) -> bool:
|
|
32
|
+
each_ancestor = Path(file_path).resolve().parent
|
|
33
|
+
while True:
|
|
34
|
+
for config_name in PRETTIER_CONFIG_NAMES:
|
|
35
|
+
if (each_ancestor / config_name).exists():
|
|
36
|
+
return True
|
|
37
|
+
parent = each_ancestor.parent
|
|
38
|
+
if parent == each_ancestor:
|
|
39
|
+
break
|
|
40
|
+
each_ancestor = parent
|
|
41
|
+
return False
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def is_untracked_in_git(file_path: str) -> bool:
|
|
45
|
+
"""Check if file is untracked (brand new) by git."""
|
|
46
|
+
containing_directory = str(Path(file_path).parent)
|
|
47
|
+
try:
|
|
48
|
+
git_check = subprocess.run(
|
|
49
|
+
["git", "ls-files", "--error-unmatch", file_path],
|
|
50
|
+
capture_output=True,
|
|
51
|
+
text=True,
|
|
52
|
+
cwd=containing_directory,
|
|
53
|
+
timeout=5,
|
|
54
|
+
)
|
|
55
|
+
return git_check.returncode != 0
|
|
56
|
+
except (FileNotFoundError, subprocess.TimeoutExpired):
|
|
57
|
+
return False
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def main() -> None:
|
|
61
|
+
try:
|
|
62
|
+
hook_input = json.load(sys.stdin)
|
|
63
|
+
except (json.JSONDecodeError, ValueError):
|
|
64
|
+
sys.exit(0)
|
|
65
|
+
|
|
66
|
+
tool_name = hook_input.get("tool_name", "")
|
|
67
|
+
file_path = hook_input.get("tool_input", {}).get("file_path", "")
|
|
68
|
+
if not file_path:
|
|
69
|
+
sys.exit(0)
|
|
70
|
+
|
|
71
|
+
if tool_name == "Edit":
|
|
72
|
+
sys.exit(0)
|
|
73
|
+
|
|
74
|
+
if tool_name == "Write" and not is_untracked_in_git(file_path):
|
|
75
|
+
sys.exit(0)
|
|
76
|
+
|
|
77
|
+
if file_path.startswith(HOOKS_DIR):
|
|
78
|
+
sys.exit(0)
|
|
79
|
+
|
|
80
|
+
suffix = Path(file_path).suffix.lower()
|
|
81
|
+
|
|
82
|
+
if suffix in PYTHON_EXTENSIONS:
|
|
83
|
+
for each_formatter_command in [
|
|
84
|
+
["ruff", "format", file_path],
|
|
85
|
+
[sys.executable, "-m", "ruff", "format", file_path],
|
|
86
|
+
["black", file_path],
|
|
87
|
+
[sys.executable, "-m", "black", file_path],
|
|
88
|
+
]:
|
|
89
|
+
try:
|
|
90
|
+
format_run = subprocess.run(each_formatter_command, capture_output=True, text=True, timeout=PYTHON_FORMAT_TIMEOUT_SECONDS)
|
|
91
|
+
if format_run.returncode == 0:
|
|
92
|
+
break
|
|
93
|
+
except FileNotFoundError:
|
|
94
|
+
continue
|
|
95
|
+
except subprocess.TimeoutExpired:
|
|
96
|
+
break
|
|
97
|
+
elif suffix in JS_EXTENSIONS or suffix in JSON_EXTENSIONS:
|
|
98
|
+
if not has_prettier_config(file_path):
|
|
99
|
+
sys.exit(0)
|
|
100
|
+
try:
|
|
101
|
+
subprocess.run(
|
|
102
|
+
["npx", "--yes", "prettier", "--write", file_path],
|
|
103
|
+
capture_output=True,
|
|
104
|
+
text=True,
|
|
105
|
+
timeout=JS_FORMAT_TIMEOUT_SECONDS,
|
|
106
|
+
)
|
|
107
|
+
except (FileNotFoundError, subprocess.TimeoutExpired):
|
|
108
|
+
pass
|
|
109
|
+
|
|
110
|
+
sys.exit(0)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
if __name__ == "__main__":
|
|
114
|
+
main()
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""PostToolUse hook — resets the serial investigation tracker when delegation occurs.
|
|
3
|
+
|
|
4
|
+
Clears the investigation timestamp tracker when the lead session delegates work
|
|
5
|
+
via Agent, Task, or TeamCreate tools. This allows the lead to resume limited
|
|
6
|
+
diagnostic calls after properly delegating.
|
|
7
|
+
|
|
8
|
+
Companion: blocking/serial-investigation-blocker.py (PreToolUse on Read|Bash|Grep)
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
import os
|
|
13
|
+
import sys
|
|
14
|
+
|
|
15
|
+
TRACKER_STATE_PATH = os.path.join(
|
|
16
|
+
os.path.expanduser("~"), ".claude", "runtime", "investigation-tracker.json"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
DELEGATION_TOOLS = frozenset({"Agent", "Task", "TeamCreate"})
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def clear_investigation_tracker() -> None:
|
|
23
|
+
try:
|
|
24
|
+
os.remove(TRACKER_STATE_PATH)
|
|
25
|
+
except FileNotFoundError:
|
|
26
|
+
pass
|
|
27
|
+
except OSError:
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def main() -> None:
|
|
32
|
+
try:
|
|
33
|
+
hook_input = json.load(sys.stdin)
|
|
34
|
+
except json.JSONDecodeError:
|
|
35
|
+
sys.exit(0)
|
|
36
|
+
|
|
37
|
+
tool_name = hook_input.get("tool_name", "")
|
|
38
|
+
if tool_name not in DELEGATION_TOOLS:
|
|
39
|
+
sys.exit(0)
|
|
40
|
+
|
|
41
|
+
clear_investigation_tracker()
|
|
42
|
+
sys.exit(0)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
if __name__ == "__main__":
|
|
46
|
+
main()
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "claude-dev-env",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Claude Code development standards — rules, hooks, agents, commands, and skills",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"claude-dev-env": "bin/install.mjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"rules/",
|
|
12
|
+
"docs/",
|
|
13
|
+
"commands/",
|
|
14
|
+
"agents/",
|
|
15
|
+
"skills/",
|
|
16
|
+
"hooks/"
|
|
17
|
+
],
|
|
18
|
+
"keywords": [
|
|
19
|
+
"claude-code",
|
|
20
|
+
"plugin",
|
|
21
|
+
"cli",
|
|
22
|
+
"tdd",
|
|
23
|
+
"code-quality"
|
|
24
|
+
],
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/jl-cmd/claude-code-config.git"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Agent Spawn Protocol (Mandatory)
|
|
2
|
+
|
|
3
|
+
**When this applies:** Before any Agent or Task tool invocation (Explore, implementation, research, or team subagents).
|
|
4
|
+
|
|
5
|
+
<agent_spawn_protocol>
|
|
6
|
+
|
|
7
|
+
## Before spawning ANY agent — no exceptions
|
|
8
|
+
|
|
9
|
+
Every Agent and Task tool call must follow this protocol. This includes Explore agents, research agents, execution agents, and team members.
|
|
10
|
+
|
|
11
|
+
### Step 1: Context sufficiency check
|
|
12
|
+
|
|
13
|
+
Before writing any agent prompt, verify you can answer all of these:
|
|
14
|
+
- [ ] What specific files, directories, or areas of the codebase are involved?
|
|
15
|
+
- [ ] What constraints apply? (patterns to follow, things NOT to change, boundaries)
|
|
16
|
+
- [ ] What does success look like? (expected output, acceptance criteria)
|
|
17
|
+
- [ ] Is the task unambiguous enough to delegate?
|
|
18
|
+
|
|
19
|
+
If ANY answer is "I don't know" -- investigate first (read files, search code) or ask the user. Do NOT spawn with incomplete context.
|
|
20
|
+
|
|
21
|
+
### Step 2: Craft the prompt with /prompt-generator
|
|
22
|
+
|
|
23
|
+
Run the `/prompt-generator` skill to produce a structured prompt. Feed it:
|
|
24
|
+
- The task description and goal
|
|
25
|
+
- Target files/directories discovered in Step 1
|
|
26
|
+
- Constraints and boundaries
|
|
27
|
+
- Expected output format
|
|
28
|
+
- Acceptance criteria
|
|
29
|
+
|
|
30
|
+
The skill will ask 1-3 clarifying questions if information is missing -- this is the built-in context verification.
|
|
31
|
+
|
|
32
|
+
Use the skill's output as the agent's `prompt` parameter.
|
|
33
|
+
|
|
34
|
+
### Step 3: Spawn the agent
|
|
35
|
+
|
|
36
|
+
Pass the structured prompt from Step 2 to the Agent/Task tool.
|
|
37
|
+
|
|
38
|
+
</agent_spawn_protocol>
|
|
39
|
+
|
|
40
|
+
## Why
|
|
41
|
+
|
|
42
|
+
Agents receiving vague prompts waste tokens exploring in circles, produce code that misses constraints, and require expensive rework. A 30-second investment in prompt quality via /prompt-generator saves 5-minute agent failures. This applies equally to Explore agents (which waste context on unfocused searches) and execution agents (which write wrong code).
|
|
43
|
+
|
|
44
|
+
## Relationship to other rules
|
|
45
|
+
|
|
46
|
+
- **conservative-action.md** gates acting when ambiguous. This extends that: do not delegate when the task is ambiguous—investigate or ask the user first.
|
|
47
|
+
- Project-specific rules or `~/.claude/CLAUDE.md` may define *whether* to use subagents or teams; this rule governs *how* to craft prompts when you do delegate.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Clean Up Temporary Files
|
|
2
|
+
|
|
3
|
+
**When this applies:** After tasks that created scratch files, debug dumps, or one-off scripts the user did not ask to keep.
|
|
4
|
+
|
|
5
|
+
Source: [Anthropic — Reduce file creation in agentic coding](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices#reduce-file-creation-in-agentic-coding)
|
|
6
|
+
|
|
7
|
+
## During a task
|
|
8
|
+
|
|
9
|
+
- Prefer working in memory over creating scratchpad files. Use variables and tool results instead of writing intermediate data to disk.
|
|
10
|
+
- When a temporary file is genuinely needed (e.g., a helper script, a test fixture, a debug output), track it mentally for cleanup.
|
|
11
|
+
|
|
12
|
+
## When a task is complete
|
|
13
|
+
|
|
14
|
+
- Remove every temporary file, script, or helper file you created during the task.
|
|
15
|
+
- Leave the working directory cleaner than you found it.
|
|
16
|
+
- If a file was created at the user's explicit request (not as a byproduct of your process), leave it in place.
|
|
17
|
+
|
|
18
|
+
## What counts as temporary
|
|
19
|
+
|
|
20
|
+
- Scripts written to test a hypothesis or run a one-off check
|
|
21
|
+
- Debug output files, log dumps, or intermediate data exports
|
|
22
|
+
- Helper files created to work around tool limitations
|
|
23
|
+
- Any file the user did not ask for and would not expect to find after the task
|
|
24
|
+
|
|
25
|
+
## Why
|
|
26
|
+
|
|
27
|
+
Temporary files accumulate across sessions and clutter the project root. Latest models sometimes use files as scratchpads during iteration, and these leftovers confuse both the user and future sessions if not cleaned up.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Responding to Code Reviews
|
|
2
|
+
|
|
3
|
+
**When this applies:** GitHub PR review feedback on a branch you are fixing.
|
|
4
|
+
|
|
5
|
+
**MANDATORY PROTOCOL (use pr-review-responder skill):**
|
|
6
|
+
|
|
7
|
+
1. Fetch ALL reviewer comments BEFORE any fixes
|
|
8
|
+
2. Create TodoWrite checklist - One item per comment
|
|
9
|
+
3. Fix systematically - Mark each todo complete
|
|
10
|
+
4. Reply to EACH comment inline
|
|
11
|
+
5. Create ONE review fix commit - DO NOT squash with original
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Code Standards
|
|
2
|
+
|
|
3
|
+
> **MANDATORY REFERENCE:** CODE_RULES.md - Load for ALL code generation.
|
|
4
|
+
> This is the single source of truth for code standards. Non-negotiable.
|
|
5
|
+
|
|
6
|
+
@${CLAUDE_PLUGIN_ROOT}/docs/CODE_RULES.md
|
|
7
|
+
|
|
8
|
+
**Key principles (see CODE_RULES.md for complete reference):**
|
|
9
|
+
- Self-documenting code (no comments)
|
|
10
|
+
- Centralized configuration (one source of truth)
|
|
11
|
+
- Reuse constants (search before creating)
|
|
12
|
+
- No magic values (everything named)
|
|
13
|
+
- No abbreviations (full words)
|
|
14
|
+
- Complete type hints
|
|
15
|
+
- TDD (test first)
|
|
16
|
+
|
|
17
|
+
## Function Parameters - Required vs Optional
|
|
18
|
+
|
|
19
|
+
**Use required parameters when no valid use case exists for optional.**
|
|
20
|
+
**Remove unused parameters.**
|
|
21
|
+
|
|
22
|
+
## Encapsulation - Logic Belongs in Models
|
|
23
|
+
|
|
24
|
+
**NEVER scatter construction logic in calling code.**
|
|
25
|
+
|
|
26
|
+
Path/URL building, formatting, transformations -> Put in model methods.
|
|
27
|
+
If you find yourself building the same string pattern in multiple places, it belongs in the model.
|
|
28
|
+
|
|
29
|
+
## Document Temporary Code
|
|
30
|
+
|
|
31
|
+
**Scaffolding/placeholder code MUST have TODO comments.**
|
|
32
|
+
|
|
33
|
+
When code exists only to enable testing before full implementation:
|
|
34
|
+
- Add `// TODO: Replace with...` explaining what will replace it
|
|
35
|
+
- Explain WHY it's temporary, not just WHAT it does
|
|
36
|
+
|
|
37
|
+
## Naming Reflects Behavior
|
|
38
|
+
|
|
39
|
+
**Name components after what they ARE, not abstract concepts.**
|
|
40
|
+
|
|
41
|
+
If it overlays the viewport -> "Overlay" not "Screen"
|
|
42
|
+
If it validates input -> "Validator" not "Handler"
|
|
43
|
+
Names should describe observable behavior or visual appearance.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Conservative Action
|
|
2
|
+
|
|
3
|
+
Source: [Anthropic - Tool Usage](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices#tool-usage)
|
|
4
|
+
|
|
5
|
+
<do_not_act_before_instructions>
|
|
6
|
+
When the user's intent is ambiguous, default to research and recommendations rather than taking action. Provide information, explain options, and surface tradeoffs — then let the user decide before making changes.
|
|
7
|
+
|
|
8
|
+
Proceed with edits, file modifications, or implementations only when the user explicitly requests them.
|
|
9
|
+
</do_not_act_before_instructions>
|
|
10
|
+
|
|
11
|
+
## Deciding whether to act
|
|
12
|
+
|
|
13
|
+
- If the user asks a question, answer the question. Do not also fix the thing they asked about.
|
|
14
|
+
- If the user describes a problem, investigate and recommend. Do not jump to implementation.
|
|
15
|
+
- If the user says "do it", "go ahead", "make the change", or similarly explicit language, proceed with action.
|
|
16
|
+
- When in doubt, ask: "Would you like me to make this change, or just show you the approach?"
|
|
17
|
+
|
|
18
|
+
## Why
|
|
19
|
+
|
|
20
|
+
Acting prematurely wastes effort and round-trips when the user wanted a different approach. Exploring first produces better outcomes than committing early. This is especially important with models that have a strong action bias.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
alwaysApply: true
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
When working with libraries, frameworks, or APIs — use Context7 MCP to fetch current documentation instead of relying on training data. This includes setup questions, code generation, API references, and anything involving specific packages.
|
|
6
|
+
|
|
7
|
+
## Steps
|
|
8
|
+
|
|
9
|
+
1. Call `resolve-library-id` with the library name and the user's question
|
|
10
|
+
2. Pick the best match — prefer exact names and version-specific IDs when a version is mentioned
|
|
11
|
+
3. Call `query-docs` with the selected library ID and the user's question
|
|
12
|
+
4. Answer using the fetched docs — include code examples and cite the version
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Explore Thoroughly
|
|
2
|
+
|
|
3
|
+
Source: [Anthropic - Overthinking and Excessive Thoroughness](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices#overthinking-and-excessive-thoroughness)
|
|
4
|
+
|
|
5
|
+
Note: This deliberately chooses exploration depth over the "commit and execute quickly" pattern from the same source. Thorough upfront exploration is preferred for the intended workflow.
|
|
6
|
+
|
|
7
|
+
## Before committing to an approach
|
|
8
|
+
|
|
9
|
+
- Read the relevant files. Understand what exists before proposing what to change.
|
|
10
|
+
- Map the existing patterns: naming conventions, file organization, architectural decisions.
|
|
11
|
+
- Identify constraints that could invalidate an approach before investing effort in it.
|
|
12
|
+
- For unfamiliar codebases or high-stakes changes, invest more time exploring than feels necessary.
|
|
13
|
+
|
|
14
|
+
## Exploration scales with risk
|
|
15
|
+
|
|
16
|
+
- Small change to a familiar file: a quick read of the file and its immediate neighbors is sufficient.
|
|
17
|
+
- New feature or cross-cutting change: read broadly across the codebase to understand how similar things are done.
|
|
18
|
+
- Architectural decision: explore the full landscape before recommending a direction.
|
|
19
|
+
|
|
20
|
+
## Relationship to other rules
|
|
21
|
+
|
|
22
|
+
- **conservative-action.md** gates *whether* to act. This rule governs *how deeply* to investigate.
|
|
23
|
+
- **research-mode.md** ensures factual claims are grounded. This rule ensures implementation plans are grounded in the actual codebase.
|
|
24
|
+
|
|
25
|
+
## Why
|
|
26
|
+
|
|
27
|
+
Premature commitment leads to wasted effort when the chosen approach conflicts with existing patterns or misses important context. Thorough exploration surfaces constraints early and produces better-informed solutions.
|