cortexhawk 3.1.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/.cortexhawk-team.yml +65 -0
- package/CHANGELOG.md +268 -0
- package/CLAUDE.md +96 -0
- package/LICENSE +21 -0
- package/PACKS.md +14 -0
- package/README.md +418 -0
- package/REGISTRY.md +23 -0
- package/agents/architect.md +46 -0
- package/agents/brainstormer.md +57 -0
- package/agents/code-simplifier.md +56 -0
- package/agents/codebase-mapper.md +63 -0
- package/agents/copywriter.md +48 -0
- package/agents/debugger.md +44 -0
- package/agents/designer.md +53 -0
- package/agents/devops.md +49 -0
- package/agents/docs-manager.md +50 -0
- package/agents/fullstack-developer.md +55 -0
- package/agents/git-manager.md +63 -0
- package/agents/implementer.md +30 -0
- package/agents/journal-writer.md +53 -0
- package/agents/planner.md +52 -0
- package/agents/project-manager.md +50 -0
- package/agents/researcher.md +46 -0
- package/agents/reviewer.md +63 -0
- package/agents/security-auditor.md +92 -0
- package/agents/teacher.md +71 -0
- package/agents/tester.md +41 -0
- package/commands/api-gen.md +17 -0
- package/commands/backlog.md +26 -0
- package/commands/bootstrap.md +32 -0
- package/commands/brainstorm.md +18 -0
- package/commands/build.md +16 -0
- package/commands/chain.md +46 -0
- package/commands/changelog.md +16 -0
- package/commands/check.md +40 -0
- package/commands/ci.md +32 -0
- package/commands/context.md +35 -0
- package/commands/debug.md +16 -0
- package/commands/deploy.md +16 -0
- package/commands/doc.md +15 -0
- package/commands/export.md +17 -0
- package/commands/journal.md +18 -0
- package/commands/learn.md +16 -0
- package/commands/map.md +16 -0
- package/commands/migrate.md +17 -0
- package/commands/monitor.md +16 -0
- package/commands/optimize.md +17 -0
- package/commands/plan.md +17 -0
- package/commands/pulse.md +46 -0
- package/commands/refactor.md +16 -0
- package/commands/research.md +18 -0
- package/commands/review.md +16 -0
- package/commands/scan.md +19 -0
- package/commands/ship.md +17 -0
- package/commands/simplify.md +16 -0
- package/commands/task.md +32 -0
- package/commands/tdd.md +17 -0
- package/commands/test.md +16 -0
- package/commands/upgrade.md +27 -0
- package/cortexhawk +450 -0
- package/hooks/agent-analytics.sh +67 -0
- package/hooks/branch-guard.sh +56 -0
- package/hooks/codex-dispatcher.sh +84 -0
- package/hooks/commit-guard.sh +71 -0
- package/hooks/compose.yml +47 -0
- package/hooks/dependency-check.sh +56 -0
- package/hooks/file-guard.sh +69 -0
- package/hooks/hooks.json +46 -0
- package/hooks/self-review.sh +71 -0
- package/hooks/session-start.sh +132 -0
- package/hooks/session-telemetry.sh +60 -0
- package/hooks/test-reminder.sh +75 -0
- package/install.sh +3805 -0
- package/mcp/README.md +37 -0
- package/mcp/context7.json +8 -0
- package/mcp/puppeteer.json +8 -0
- package/mcp/sequential-thinking.json +8 -0
- package/modes/default.md +5 -0
- package/modes/fast.md +5 -0
- package/modes/learn.md +9 -0
- package/modes/orchestration.md +5 -0
- package/modes/pair.md +10 -0
- package/modes/research.md +5 -0
- package/modes/review.md +5 -0
- package/package.json +32 -0
- package/profiles/api.json +27 -0
- package/profiles/data.json +23 -0
- package/profiles/fullstack.json +27 -0
- package/scripts/autodetect-profile.sh +68 -0
- package/scripts/benchmark.sh +106 -0
- package/scripts/chain-post-save.sh +23 -0
- package/scripts/generate-plans-index.sh +50 -0
- package/scripts/git-workflow-init.sh +115 -0
- package/scripts/install-codex.sh +128 -0
- package/scripts/interactive-init.sh +264 -0
- package/scripts/post-install-audit.sh +130 -0
- package/scripts/validate.sh +214 -0
- package/settings.json +90 -0
- package/setup.sh +67 -0
- package/skills/databases/schema-designer/SKILL.md +54 -0
- package/skills/databases/sql-optimizer/SKILL.md +37 -0
- package/skills/devops/ci-cd/SKILL.md +59 -0
- package/skills/devops/deployment/SKILL.md +49 -0
- package/skills/devops/docker/SKILL.md +57 -0
- package/skills/frameworks/api-design/SKILL.md +103 -0
- package/skills/frameworks/fastapi/SKILL.md +68 -0
- package/skills/frameworks/nextjs/SKILL.md +74 -0
- package/skills/frameworks/python/SKILL.md +89 -0
- package/skills/frameworks/react/SKILL.md +83 -0
- package/skills/frameworks/sveltekit/SKILL.md +69 -0
- package/skills/frameworks/tailwindcss/SKILL.md +75 -0
- package/skills/frameworks/typescript/SKILL.md +94 -0
- package/skills/meta/mcp-builder/SKILL.md +54 -0
- package/skills/meta/skill-creator/SKILL.md +43 -0
- package/skills/optimization/performance/SKILL.md +70 -0
- package/skills/quality/complexity-analyzer/SKILL.md +52 -0
- package/skills/quality/error-handling/SKILL.md +123 -0
- package/skills/quality/log-analyzer/SKILL.md +31 -0
- package/skills/quality/pattern-detector/SKILL.md +50 -0
- package/skills/security/auth-analyzer/SKILL.md +96 -0
- package/skills/security/compliance-checker/SKILL.md +92 -0
- package/skills/security/container-security/SKILL.md +128 -0
- package/skills/security/dependency-auditor/SKILL.md +100 -0
- package/skills/security/encryption/SKILL.md +94 -0
- package/skills/security/incident-response/SKILL.md +127 -0
- package/skills/security/secrets/SKILL.md +93 -0
- package/skills/security/security-headers/SKILL.md +83 -0
- package/skills/security/security-logging/SKILL.md +107 -0
- package/skills/security/vulnerability-scanner/SKILL.md +114 -0
- package/skills/testing/e2e-testing/SKILL.md +119 -0
- package/skills/testing/tdd/SKILL.md +40 -0
- package/skills/testing/test-generator/SKILL.md +39 -0
- package/skills/workflow/commit/SKILL.md +61 -0
- package/skills/workflow/confidence-check/SKILL.md +90 -0
- package/skills/workflow/pr-review-comments/SKILL.md +81 -0
- package/skills/workflow/pr-review-comments/scripts/fetch_comments.py +237 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# commit-guard — Validates commit format and checks for staged secrets
|
|
3
|
+
# Hook type: PreToolUse (Bash)
|
|
4
|
+
|
|
5
|
+
# Read command from stdin JSON (Claude Code hook protocol)
|
|
6
|
+
if [ -n "$CORTEXHAWK_COMMAND" ]; then
|
|
7
|
+
CMD="$CORTEXHAWK_COMMAND"
|
|
8
|
+
else
|
|
9
|
+
INPUT=$(cat)
|
|
10
|
+
CMD=$(printf '%s' "$INPUT" | grep -o '"command" *: *"[^"]*"' | head -1 | sed 's/.*: *"//;s/"$//')
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
if [[ -z "$CMD" ]]; then
|
|
14
|
+
exit 0
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# Only check git commit commands
|
|
18
|
+
if ! echo "$CMD" | grep -qE 'git\s+commit'; then
|
|
19
|
+
exit 0
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
# Extract commit message from -m flag
|
|
23
|
+
COMMIT_MSG=$(echo "$CMD" | grep -oP '(?<=-m\s["\x27]).*?(?=["\x27])' 2>/dev/null)
|
|
24
|
+
if [[ -z "$COMMIT_MSG" ]]; then
|
|
25
|
+
COMMIT_MSG=$(echo "$CMD" | grep -oP '(?<=-m\s)(\S+)' 2>/dev/null)
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# Load git workflow config — skip conventional check if freeform
|
|
29
|
+
CONF_FILE="$(git rev-parse --show-toplevel 2>/dev/null)/.claude/git-workflow.conf"
|
|
30
|
+
_COMMIT_CONVENTION="conventional"
|
|
31
|
+
if [[ -f "$CONF_FILE" ]]; then
|
|
32
|
+
_COMMIT_CONVENTION=$(grep '^COMMIT_CONVENTION=' "$CONF_FILE" | cut -d= -f2)
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# Validate conventional commit format
|
|
36
|
+
if [[ -n "$COMMIT_MSG" ]] && [[ "$_COMMIT_CONVENTION" != "freeform" ]]; then
|
|
37
|
+
VALID_TYPES="feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert"
|
|
38
|
+
if ! echo "$COMMIT_MSG" | grep -qE "^(${VALID_TYPES})(\(.+\))?!?:\s.+"; then
|
|
39
|
+
echo "commit-guard: Non-conventional commit format detected"
|
|
40
|
+
echo "Expected: type(scope): description"
|
|
41
|
+
echo "Types: $VALID_TYPES"
|
|
42
|
+
echo "Got: $COMMIT_MSG"
|
|
43
|
+
# Warning only — don't block
|
|
44
|
+
fi
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# Check staged files for secrets
|
|
48
|
+
STAGED_FILES=$(git diff --cached --name-only 2>/dev/null)
|
|
49
|
+
if [[ -n "$STAGED_FILES" ]]; then
|
|
50
|
+
SECRET_PATTERNS='(PRIVATE.KEY|AWS_SECRET|api_key|password|secret)\s*[=:]\s*["\x27][^\s"'\'']{8,}'
|
|
51
|
+
|
|
52
|
+
while IFS= read -r file; do
|
|
53
|
+
if [[ -f "$file" ]]; then
|
|
54
|
+
MATCHES=$(grep -cEi "$SECRET_PATTERNS" "$file" 2>/dev/null || echo 0)
|
|
55
|
+
if [[ "$MATCHES" -gt 0 ]]; then
|
|
56
|
+
echo "BLOCKED: Potential secret detected in staged file: $file" >&2
|
|
57
|
+
echo "Review the file and remove secrets before committing" >&2
|
|
58
|
+
exit 2
|
|
59
|
+
fi
|
|
60
|
+
fi
|
|
61
|
+
done <<< "$STAGED_FILES"
|
|
62
|
+
|
|
63
|
+
# Warn if .env files are staged
|
|
64
|
+
if echo "$STAGED_FILES" | grep -qE '\.env($|\.)'; then
|
|
65
|
+
echo "BLOCKED: .env file staged for commit" >&2
|
|
66
|
+
echo "Remove with: git reset HEAD <file>" >&2
|
|
67
|
+
exit 2
|
|
68
|
+
fi
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
exit 0
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# CortexHawk Hook Compositions
|
|
2
|
+
# Defines hook pipelines per event type. Converted to settings.json at install.
|
|
3
|
+
#
|
|
4
|
+
# Format:
|
|
5
|
+
# composition-name:
|
|
6
|
+
# event: SessionStart|PreToolUse|PostToolUse|SessionEnd
|
|
7
|
+
# matcher: tool pattern (e.g., "Read|Edit|Write", "Bash", "*")
|
|
8
|
+
# hooks:
|
|
9
|
+
# - hook-name (matches .sh file in hooks/)
|
|
10
|
+
#
|
|
11
|
+
# To add a hook: add its name to the hooks list
|
|
12
|
+
# To remove a hook: delete or comment the line
|
|
13
|
+
|
|
14
|
+
compositions:
|
|
15
|
+
session-init:
|
|
16
|
+
event: SessionStart
|
|
17
|
+
matcher: "*"
|
|
18
|
+
hooks:
|
|
19
|
+
- session-start
|
|
20
|
+
|
|
21
|
+
pre-file-access:
|
|
22
|
+
event: PreToolUse
|
|
23
|
+
matcher: "Read|Edit|Write"
|
|
24
|
+
hooks:
|
|
25
|
+
- file-guard
|
|
26
|
+
|
|
27
|
+
pre-command:
|
|
28
|
+
event: PreToolUse
|
|
29
|
+
matcher: Bash
|
|
30
|
+
hooks:
|
|
31
|
+
- branch-guard
|
|
32
|
+
- commit-guard
|
|
33
|
+
|
|
34
|
+
post-edit:
|
|
35
|
+
event: PostToolUse
|
|
36
|
+
matcher: "Write|Edit"
|
|
37
|
+
hooks:
|
|
38
|
+
- self-review
|
|
39
|
+
- dependency-check
|
|
40
|
+
- test-reminder
|
|
41
|
+
- agent-analytics
|
|
42
|
+
|
|
43
|
+
session-cleanup:
|
|
44
|
+
event: SessionEnd
|
|
45
|
+
matcher: "*"
|
|
46
|
+
hooks:
|
|
47
|
+
- session-telemetry
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# dependency-check — Alerts when dependency files are modified
|
|
3
|
+
# Hook type: PostToolUse (Write|Edit)
|
|
4
|
+
|
|
5
|
+
# Read file_path from stdin JSON (Claude Code hook protocol)
|
|
6
|
+
if [ -n "$CORTEXHAWK_FILE_PATH" ]; then
|
|
7
|
+
MODIFIED_FILE="$CORTEXHAWK_FILE_PATH"
|
|
8
|
+
else
|
|
9
|
+
INPUT=$(cat)
|
|
10
|
+
MODIFIED_FILE=$(printf '%s' "$INPUT" | grep -o '"file_path" *: *"[^"]*"' | head -1 | sed 's/.*: *"//;s/"$//')
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
if [[ -z "$MODIFIED_FILE" ]]; then
|
|
14
|
+
exit 0
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
BASENAME=$(basename "$MODIFIED_FILE")
|
|
18
|
+
|
|
19
|
+
case "$BASENAME" in
|
|
20
|
+
package.json)
|
|
21
|
+
echo "Dependencies modified: $BASENAME"
|
|
22
|
+
echo "- Run 'npm install' to sync node_modules"
|
|
23
|
+
echo "- Run 'npm audit' to check for vulnerabilities"
|
|
24
|
+
echo "- Commit package-lock.json alongside package.json"
|
|
25
|
+
;;
|
|
26
|
+
requirements.txt|requirements-*.txt)
|
|
27
|
+
echo "Dependencies modified: $BASENAME"
|
|
28
|
+
echo "- Run 'pip install -r $BASENAME' to sync"
|
|
29
|
+
echo "- Run 'pip audit' or 'safety check' for vulnerabilities"
|
|
30
|
+
echo "- Pin exact versions for reproducible builds"
|
|
31
|
+
;;
|
|
32
|
+
pyproject.toml)
|
|
33
|
+
if grep -q '\[project.dependencies\]\|dependencies\s*=' "$MODIFIED_FILE" 2>/dev/null; then
|
|
34
|
+
echo "Dependencies modified: $BASENAME"
|
|
35
|
+
echo "- Run 'pip install -e .' or 'poetry install' to sync"
|
|
36
|
+
echo "- Lock file should be committed too"
|
|
37
|
+
fi
|
|
38
|
+
;;
|
|
39
|
+
Cargo.toml)
|
|
40
|
+
echo "Dependencies modified: $BASENAME"
|
|
41
|
+
echo "- Run 'cargo build' to sync and generate Cargo.lock"
|
|
42
|
+
echo "- Run 'cargo audit' for vulnerability check"
|
|
43
|
+
;;
|
|
44
|
+
go.mod)
|
|
45
|
+
echo "Dependencies modified: $BASENAME"
|
|
46
|
+
echo "- Run 'go mod tidy' to sync"
|
|
47
|
+
echo "- Commit go.sum alongside go.mod"
|
|
48
|
+
;;
|
|
49
|
+
Gemfile)
|
|
50
|
+
echo "Dependencies modified: $BASENAME"
|
|
51
|
+
echo "- Run 'bundle install' to sync"
|
|
52
|
+
echo "- Commit Gemfile.lock alongside Gemfile"
|
|
53
|
+
;;
|
|
54
|
+
esac
|
|
55
|
+
|
|
56
|
+
exit 0
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# file-guard — Blocks Claude from accessing sensitive files
|
|
3
|
+
# Hook type: PreToolUse (Read|Edit|Write)
|
|
4
|
+
|
|
5
|
+
BLOCKED_PATTERNS=(
|
|
6
|
+
".env"
|
|
7
|
+
".env.*"
|
|
8
|
+
"*.pem"
|
|
9
|
+
"*.key"
|
|
10
|
+
"*credentials*"
|
|
11
|
+
"*secret*"
|
|
12
|
+
"id_rsa"
|
|
13
|
+
"id_ed25519"
|
|
14
|
+
".ssh/*"
|
|
15
|
+
"*.p12"
|
|
16
|
+
"*.pfx"
|
|
17
|
+
"*.keystore"
|
|
18
|
+
"docker-compose*.yml"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
# Read file_path from stdin JSON (Claude Code hook protocol)
|
|
22
|
+
if [ -n "$CORTEXHAWK_FILE_PATH" ]; then
|
|
23
|
+
FILE_ARG="$CORTEXHAWK_FILE_PATH"
|
|
24
|
+
else
|
|
25
|
+
INPUT=$(cat)
|
|
26
|
+
FILE_ARG=$(printf '%s' "$INPUT" | grep -o '"file_path" *: *"[^"]*"' | head -1 | sed 's/.*: *"//;s/"$//')
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
if [[ -z "$FILE_ARG" ]]; then
|
|
30
|
+
exit 0
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
# Normalize path — resolve symlinks and relative paths
|
|
34
|
+
if command -v realpath &>/dev/null; then
|
|
35
|
+
RESOLVED=$(realpath -m "$FILE_ARG" 2>/dev/null || echo "$FILE_ARG")
|
|
36
|
+
else
|
|
37
|
+
RESOLVED=$(cd "$(dirname "$FILE_ARG")" 2>/dev/null && echo "$(pwd)/$(basename "$FILE_ARG")" || echo "$FILE_ARG")
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Extract just the filename for pattern matching
|
|
41
|
+
BASENAME=$(basename "$RESOLVED")
|
|
42
|
+
# Also check against the full resolved path
|
|
43
|
+
RELPATH="$RESOLVED"
|
|
44
|
+
|
|
45
|
+
for pattern in "${BLOCKED_PATTERNS[@]}"; do
|
|
46
|
+
if [[ "$BASENAME" == $pattern ]] || [[ "$RELPATH" == *$pattern ]]; then
|
|
47
|
+
echo "BLOCKED: Access to '$FILE_ARG' denied by file-guard" >&2
|
|
48
|
+
echo "Resolved path: $RESOLVED" >&2
|
|
49
|
+
echo "Matched pattern: '$pattern'" >&2
|
|
50
|
+
exit 2
|
|
51
|
+
fi
|
|
52
|
+
done
|
|
53
|
+
|
|
54
|
+
# Block symlinks pointing to sensitive files
|
|
55
|
+
if [[ -L "$FILE_ARG" ]]; then
|
|
56
|
+
LINK_TARGET=$(readlink -f "$FILE_ARG" 2>/dev/null)
|
|
57
|
+
if [[ -n "$LINK_TARGET" ]]; then
|
|
58
|
+
LINK_BASENAME=$(basename "$LINK_TARGET")
|
|
59
|
+
for pattern in "${BLOCKED_PATTERNS[@]}"; do
|
|
60
|
+
if [[ "$LINK_BASENAME" == $pattern ]]; then
|
|
61
|
+
echo "BLOCKED: Symlink '$FILE_ARG' -> '$LINK_TARGET' denied by file-guard" >&2
|
|
62
|
+
echo "Matched pattern: '$pattern'" >&2
|
|
63
|
+
exit 2
|
|
64
|
+
fi
|
|
65
|
+
done
|
|
66
|
+
fi
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
exit 0
|
package/hooks/hooks.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": [
|
|
3
|
+
{
|
|
4
|
+
"name": "session-start",
|
|
5
|
+
"type": "SessionStart",
|
|
6
|
+
"script": "hooks/session-start.sh",
|
|
7
|
+
"description": "Injects project context on startup"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"name": "file-guard",
|
|
11
|
+
"type": "PreToolUse",
|
|
12
|
+
"script": "hooks/file-guard.sh",
|
|
13
|
+
"description": "Blocks access to sensitive files (.env, keys, secrets)"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"name": "self-review",
|
|
17
|
+
"type": "PostToolUse",
|
|
18
|
+
"script": "hooks/self-review.sh",
|
|
19
|
+
"description": "Auto-review after code edits"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"name": "branch-guard",
|
|
23
|
+
"type": "PreToolUse",
|
|
24
|
+
"script": "hooks/branch-guard.sh",
|
|
25
|
+
"description": "Prevents direct push to protected branches"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "dependency-check",
|
|
29
|
+
"type": "PostToolUse",
|
|
30
|
+
"script": "hooks/dependency-check.sh",
|
|
31
|
+
"description": "Alerts when dependency files are modified"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "commit-guard",
|
|
35
|
+
"type": "PreToolUse",
|
|
36
|
+
"script": "hooks/commit-guard.sh",
|
|
37
|
+
"description": "Validates commit format and checks for staged secrets"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "test-reminder",
|
|
41
|
+
"type": "PostToolUse",
|
|
42
|
+
"script": "hooks/test-reminder.sh",
|
|
43
|
+
"description": "Reminds to update tests when source files change"
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# self-review — Auto-review after file edits
|
|
3
|
+
# Hook type: PostToolUse (Write|Edit)
|
|
4
|
+
|
|
5
|
+
# Read file_path from stdin JSON (Claude Code hook protocol)
|
|
6
|
+
if [ -n "$CORTEXHAWK_FILE_PATH" ]; then
|
|
7
|
+
MODIFIED_FILE="$CORTEXHAWK_FILE_PATH"
|
|
8
|
+
else
|
|
9
|
+
INPUT=$(cat)
|
|
10
|
+
MODIFIED_FILE=$(printf '%s' "$INPUT" | grep -o '"file_path" *: *"[^"]*"' | head -1 | sed 's/.*: *"//;s/"$//')
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
if [[ -z "$MODIFIED_FILE" ]] || [[ ! -f "$MODIFIED_FILE" ]]; then
|
|
14
|
+
exit 0
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# Only review code files
|
|
18
|
+
case "$MODIFIED_FILE" in
|
|
19
|
+
*.py|*.js|*.ts|*.jsx|*.tsx|*.go|*.rs|*.java|*.rb|*.sh)
|
|
20
|
+
;;
|
|
21
|
+
*)
|
|
22
|
+
exit 0
|
|
23
|
+
;;
|
|
24
|
+
esac
|
|
25
|
+
|
|
26
|
+
ISSUES=""
|
|
27
|
+
|
|
28
|
+
# Check for TODO/FIXME
|
|
29
|
+
TODO_COUNT=$(grep -cEi 'TODO|FIXME|HACK|XXX' "$MODIFIED_FILE" 2>/dev/null || echo 0)
|
|
30
|
+
if [[ "$TODO_COUNT" -gt 0 ]]; then
|
|
31
|
+
ISSUES="${ISSUES}\n- $TODO_COUNT TODO/FIXME markers found"
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# Check for hardcoded secrets patterns
|
|
35
|
+
SECRET_PATTERNS='(api[_-]?key|api[_-]?secret|password|passwd|token|secret[_-]?key)\s*[=:]\s*["\x27][^\s"'\'']{8,}'
|
|
36
|
+
SECRET_COUNT=$(grep -cEi "$SECRET_PATTERNS" "$MODIFIED_FILE" 2>/dev/null || echo 0)
|
|
37
|
+
if [[ "$SECRET_COUNT" -gt 0 ]]; then
|
|
38
|
+
ISSUES="${ISSUES}\n- ⚠️ $SECRET_COUNT potential hardcoded secret(s) detected"
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# Check for debug artifacts
|
|
42
|
+
case "$MODIFIED_FILE" in
|
|
43
|
+
*.py)
|
|
44
|
+
DBG_COUNT=$(grep -cE '^\s*(print\(|breakpoint\(\)|import pdb|pdb\.set_trace)' "$MODIFIED_FILE" 2>/dev/null || echo 0)
|
|
45
|
+
;;
|
|
46
|
+
*.js|*.ts|*.jsx|*.tsx)
|
|
47
|
+
DBG_COUNT=$(grep -cE '^\s*console\.(log|debug|warn|error)\(' "$MODIFIED_FILE" 2>/dev/null || echo 0)
|
|
48
|
+
;;
|
|
49
|
+
*)
|
|
50
|
+
DBG_COUNT=0
|
|
51
|
+
;;
|
|
52
|
+
esac
|
|
53
|
+
if [[ "$DBG_COUNT" -gt 0 ]]; then
|
|
54
|
+
ISSUES="${ISSUES}\n- $DBG_COUNT debug statement(s) found (console.log/print)"
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
# Syntax check for shell scripts
|
|
58
|
+
if [[ "$MODIFIED_FILE" == *.sh ]]; then
|
|
59
|
+
SYNTAX_ERR=$(bash -n "$MODIFIED_FILE" 2>&1)
|
|
60
|
+
if [[ $? -ne 0 ]]; then
|
|
61
|
+
ISSUES="${ISSUES}\n- Syntax error: $SYNTAX_ERR"
|
|
62
|
+
fi
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# Report
|
|
66
|
+
if [[ -n "$ISSUES" ]]; then
|
|
67
|
+
echo "🔍 Self-review: $MODIFIED_FILE"
|
|
68
|
+
echo -e "$ISSUES"
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
exit 0
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# session-start — Inject project context on Claude Code startup
|
|
3
|
+
# Hook type: SessionStart
|
|
4
|
+
|
|
5
|
+
echo "CortexHawk loaded"
|
|
6
|
+
echo ""
|
|
7
|
+
|
|
8
|
+
# Write session start timestamp for telemetry
|
|
9
|
+
if [ -d "docs/.metrics" ] || [ -d "docs" ]; then
|
|
10
|
+
mkdir -p "docs/.metrics"
|
|
11
|
+
date +%s > "docs/.metrics/.session-start"
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
# Detect project type
|
|
15
|
+
if [ -f "package.json" ]; then
|
|
16
|
+
echo "Project: Node.js/TypeScript"
|
|
17
|
+
DEP_COUNT=$(grep -c '"dependencies"' package.json 2>/dev/null || echo 0)
|
|
18
|
+
echo "Dependency groups: $DEP_COUNT"
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
if [ -f "requirements.txt" ] || [ -f "pyproject.toml" ]; then
|
|
22
|
+
echo "Project: Python"
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
if [ -f "Cargo.toml" ]; then
|
|
26
|
+
echo "Project: Rust"
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
if [ -f "go.mod" ]; then
|
|
30
|
+
echo "Project: Go"
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
if [ -f "docker-compose.yml" ] || [ -f "docker-compose.yaml" ]; then
|
|
34
|
+
echo "Docker: compose detected"
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
if [ -f ".env.example" ] && [ ! -f ".env" ]; then
|
|
38
|
+
echo "Warning: .env missing — copy from .env.example"
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# Generate shared context for all agents
|
|
42
|
+
if [ -d "docs/.context" ] && [ ! -L "docs/.context" ]; then
|
|
43
|
+
SHARED="docs/.context/_shared.md"
|
|
44
|
+
|
|
45
|
+
echo "# Shared Context" > "$SHARED"
|
|
46
|
+
echo "" >> "$SHARED"
|
|
47
|
+
echo "_Auto-generated by session-start. Do not edit manually._" >> "$SHARED"
|
|
48
|
+
echo "" >> "$SHARED"
|
|
49
|
+
|
|
50
|
+
# Backlog summary
|
|
51
|
+
if [ -f "docs/backlog.md" ]; then
|
|
52
|
+
ACTIVE=$(grep -c '| todo |' docs/backlog.md 2>/dev/null || echo 0)
|
|
53
|
+
DEFERRED=$(grep -c '| deferred |' docs/backlog.md 2>/dev/null || echo 0)
|
|
54
|
+
DONE=$(grep -c '| done |' docs/backlog.md 2>/dev/null || echo 0)
|
|
55
|
+
echo "## Backlog" >> "$SHARED"
|
|
56
|
+
echo "- Active: $ACTIVE | Deferred: $DEFERRED | Done: $DONE" >> "$SHARED"
|
|
57
|
+
# List active items
|
|
58
|
+
grep '| todo |' docs/backlog.md >> "$SHARED" 2>/dev/null || true
|
|
59
|
+
echo "" >> "$SHARED"
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# Recent commits
|
|
63
|
+
if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
|
|
64
|
+
echo "## Recent Commits" >> "$SHARED"
|
|
65
|
+
git log --oneline -5 2>/dev/null >> "$SHARED" || true
|
|
66
|
+
echo "" >> "$SHARED"
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
# User context (persistent key-value pairs from /context set)
|
|
70
|
+
if [ -f "docs/.context/_user.md" ]; then
|
|
71
|
+
cat "docs/.context/_user.md" >> "$SHARED"
|
|
72
|
+
echo "" >> "$SHARED"
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
# Active warnings
|
|
76
|
+
echo "## Warnings" >> "$SHARED"
|
|
77
|
+
WARNINGS=0
|
|
78
|
+
if [ -f ".env.example" ] && [ ! -f ".env" ]; then
|
|
79
|
+
echo "- .env missing — copy from .env.example" >> "$SHARED"
|
|
80
|
+
WARNINGS=$((WARNINGS + 1))
|
|
81
|
+
fi
|
|
82
|
+
if [ "$WARNINGS" -eq 0 ]; then
|
|
83
|
+
echo "- None" >> "$SHARED"
|
|
84
|
+
fi
|
|
85
|
+
echo "" >> "$SHARED"
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
# Agent memory status
|
|
89
|
+
if [ -d "docs/.context" ] && [ ! -L "docs/.context" ]; then
|
|
90
|
+
CONTEXT_COUNT=$(find docs/.context -maxdepth 1 -type f -name '*.md' 2>/dev/null | wc -l | tr -d ' ')
|
|
91
|
+
if [ "$CONTEXT_COUNT" -gt 0 ]; then
|
|
92
|
+
echo "Agent memory: $CONTEXT_COUNT context file(s)"
|
|
93
|
+
fi
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# Agent analytics summary
|
|
97
|
+
if [ -d "docs/.metrics" ]; then
|
|
98
|
+
TODAY=$(date +"%Y-%m-%d")
|
|
99
|
+
if [ -f "docs/.metrics/$TODAY.jsonl" ]; then
|
|
100
|
+
INVOCATIONS=$(grep -c '"agent"' "docs/.metrics/$TODAY.jsonl" 2>/dev/null || echo 0)
|
|
101
|
+
echo "Agent analytics: $INVOCATIONS invocation(s) today"
|
|
102
|
+
fi
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
# Skill suggestions — detect relevant but uninstalled skills
|
|
106
|
+
CORTEXHAWK_SRC="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")/.." && pwd)"
|
|
107
|
+
SKILL_DIR=".claude/skills"
|
|
108
|
+
if [ -d "$SKILL_DIR" ]; then
|
|
109
|
+
MISSING=""
|
|
110
|
+
for skill_file in "$CORTEXHAWK_SRC"/skills/*/*/SKILL.md; do
|
|
111
|
+
[ -f "$skill_file" ] || continue
|
|
112
|
+
detect=$(sed -n '/^---$/,/^---$/{ /^detect:/{ s/^detect: //; p; } }' "$skill_file")
|
|
113
|
+
[ -z "$detect" ] && continue
|
|
114
|
+
skill_path="${skill_file#$CORTEXHAWK_SRC/skills/}"
|
|
115
|
+
skill_path="${skill_path%/SKILL.md}"
|
|
116
|
+
[ -f "$SKILL_DIR/$skill_path/SKILL.md" ] && continue
|
|
117
|
+
for marker in $detect; do
|
|
118
|
+
case "$marker" in
|
|
119
|
+
base) matched=true ;;
|
|
120
|
+
dir:*) [ -d "${marker#dir:}" ] && matched=true ;;
|
|
121
|
+
*:*) f="${marker%%:*}"; p="${marker#*:}"; [ -f "$f" ] && grep -qi "$p" "$f" 2>/dev/null && matched=true ;;
|
|
122
|
+
*) [ -f "$marker" ] && matched=true ;;
|
|
123
|
+
esac
|
|
124
|
+
[ "${matched:-}" = true ] && { MISSING="${MISSING:+$MISSING, }$skill_path"; break; }
|
|
125
|
+
unset matched
|
|
126
|
+
done
|
|
127
|
+
done
|
|
128
|
+
[ -n "$MISSING" ] && echo "Suggested skills: $MISSING"
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
echo ""
|
|
132
|
+
echo "Commands: /plan /build /test /review /ship /debug /scan /check /refactor /research /doc /bootstrap /tdd /optimize /migrate /monitor /api-gen /changelog /journal /brainstorm /simplify /deploy /export /backlog /pulse /map /learn /chain /task /ci /context"
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# session-telemetry — Generate session summary on exit
|
|
3
|
+
# Hook type: SessionEnd
|
|
4
|
+
|
|
5
|
+
# Read session_id from stdin JSON (Claude Code hook protocol)
|
|
6
|
+
INPUT=$(cat)
|
|
7
|
+
SESSION_ID=$(printf '%s' "$INPUT" | grep -o '"session_id" *: *"[^"]*"' | head -1 | sed 's/.*: *"//;s/"$//')
|
|
8
|
+
SESSION_ID="${SESSION_ID:-unknown}"
|
|
9
|
+
METRICS_DIR="docs/.metrics"
|
|
10
|
+
TODAY=$(date +"%Y-%m-%d")
|
|
11
|
+
JSONL_FILE="$METRICS_DIR/$TODAY.jsonl"
|
|
12
|
+
START_FILE="$METRICS_DIR/.session-start"
|
|
13
|
+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
14
|
+
|
|
15
|
+
mkdir -p "$METRICS_DIR"
|
|
16
|
+
|
|
17
|
+
# Duration
|
|
18
|
+
DURATION=0
|
|
19
|
+
if [ -f "$START_FILE" ]; then
|
|
20
|
+
START_TS=$(cat "$START_FILE")
|
|
21
|
+
NOW_TS=$(date +%s)
|
|
22
|
+
DURATION=$((NOW_TS - START_TS))
|
|
23
|
+
[ "$DURATION" -lt 0 ] && DURATION=0
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
# Agent invocations from today's JSONL
|
|
27
|
+
AGENTS_INVOKED=0
|
|
28
|
+
UNIQUE_AGENTS=""
|
|
29
|
+
TOTAL_TOKENS=0
|
|
30
|
+
if [ -f "$JSONL_FILE" ]; then
|
|
31
|
+
AGENTS_INVOKED=$(grep -c '"agent"' "$JSONL_FILE" 2>/dev/null || echo 0)
|
|
32
|
+
UNIQUE_AGENTS=$(grep -o '"agent":"[^"]*"' "$JSONL_FILE" 2>/dev/null \
|
|
33
|
+
| sort -u | sed 's/"agent":"//;s/"//' | paste -sd ',' - || echo "")
|
|
34
|
+
TOTAL_TOKENS=$(grep -o '"estimated_tokens":[0-9]*' "$JSONL_FILE" 2>/dev/null \
|
|
35
|
+
| sed 's/"estimated_tokens"://' | awk '{s+=$1} END {print s+0}')
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# Files modified (uncommitted + last commit)
|
|
39
|
+
FILES_MODIFIED=0
|
|
40
|
+
if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
|
|
41
|
+
UNCOMMITTED=$(git diff --name-only HEAD 2>/dev/null | wc -l | tr -d ' ')
|
|
42
|
+
UNTRACKED=$(git ls-files --others --exclude-standard 2>/dev/null | wc -l | tr -d ' ')
|
|
43
|
+
FILES_MODIFIED=$((UNCOMMITTED + UNTRACKED))
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Escape strings for safe JSON
|
|
47
|
+
json_escape() { printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'; }
|
|
48
|
+
|
|
49
|
+
SESSION_ESC=$(json_escape "$SESSION_ID")
|
|
50
|
+
AGENTS_ESC=$(json_escape "$UNIQUE_AGENTS")
|
|
51
|
+
|
|
52
|
+
# Append session summary to JSONL
|
|
53
|
+
printf '{"type":"session","timestamp":"%s","session_id":"%s","duration_seconds":%d,"agents_invoked":%d,"unique_agents":"%s","total_estimated_tokens":%d,"files_modified":%d}\n' \
|
|
54
|
+
"$TIMESTAMP" "$SESSION_ESC" "$DURATION" "$AGENTS_INVOKED" "$AGENTS_ESC" "$TOTAL_TOKENS" "$FILES_MODIFIED" \
|
|
55
|
+
>> "$JSONL_FILE"
|
|
56
|
+
|
|
57
|
+
# Cleanup start marker
|
|
58
|
+
rm -f "$START_FILE"
|
|
59
|
+
|
|
60
|
+
exit 0
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# test-reminder — Reminds to update tests when source files change
|
|
3
|
+
# Hook type: PostToolUse (Write|Edit)
|
|
4
|
+
|
|
5
|
+
# Read file_path from stdin JSON (Claude Code hook protocol)
|
|
6
|
+
if [ -n "$CORTEXHAWK_FILE_PATH" ]; then
|
|
7
|
+
MODIFIED_FILE="$CORTEXHAWK_FILE_PATH"
|
|
8
|
+
else
|
|
9
|
+
INPUT=$(cat)
|
|
10
|
+
MODIFIED_FILE=$(printf '%s' "$INPUT" | grep -o '"file_path" *: *"[^"]*"' | head -1 | sed 's/.*: *"//;s/"$//')
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
if [[ -z "$MODIFIED_FILE" ]] || [[ ! -f "$MODIFIED_FILE" ]]; then
|
|
14
|
+
exit 0
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# Skip non-code files
|
|
18
|
+
case "$MODIFIED_FILE" in
|
|
19
|
+
*.py|*.js|*.ts|*.jsx|*.tsx|*.go|*.rs|*.java|*.rb)
|
|
20
|
+
;;
|
|
21
|
+
*)
|
|
22
|
+
exit 0
|
|
23
|
+
;;
|
|
24
|
+
esac
|
|
25
|
+
|
|
26
|
+
# Skip if already a test file
|
|
27
|
+
if echo "$MODIFIED_FILE" | grep -qE '(test_|_test\.|\.test\.|\.spec\.|tests/|__tests__/)'; then
|
|
28
|
+
exit 0
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
BASENAME=$(basename "$MODIFIED_FILE")
|
|
32
|
+
FILENAME="${BASENAME%.*}"
|
|
33
|
+
EXT="${BASENAME##*.}"
|
|
34
|
+
DIR=$(dirname "$MODIFIED_FILE")
|
|
35
|
+
|
|
36
|
+
# Build possible test file paths
|
|
37
|
+
TEST_CANDIDATES=()
|
|
38
|
+
|
|
39
|
+
case "$EXT" in
|
|
40
|
+
py)
|
|
41
|
+
TEST_CANDIDATES+=("${DIR}/test_${BASENAME}" "${DIR}/tests/test_${BASENAME}" "${DIR}/../tests/test_${BASENAME}")
|
|
42
|
+
;;
|
|
43
|
+
js|ts|jsx|tsx)
|
|
44
|
+
TEST_CANDIDATES+=("${DIR}/${FILENAME}.test.${EXT}" "${DIR}/${FILENAME}.spec.${EXT}")
|
|
45
|
+
TEST_CANDIDATES+=("${DIR}/__tests__/${BASENAME}" "${DIR}/../__tests__/${BASENAME}")
|
|
46
|
+
;;
|
|
47
|
+
go)
|
|
48
|
+
TEST_CANDIDATES+=("${DIR}/${FILENAME}_test.go")
|
|
49
|
+
;;
|
|
50
|
+
rs)
|
|
51
|
+
# Rust tests are usually inline — skip
|
|
52
|
+
exit 0
|
|
53
|
+
;;
|
|
54
|
+
java)
|
|
55
|
+
TEST_CANDIDATES+=("${DIR}/${FILENAME}Test.java" "${DIR}/../test/${BASENAME}")
|
|
56
|
+
;;
|
|
57
|
+
rb)
|
|
58
|
+
TEST_CANDIDATES+=("${DIR}/${FILENAME}_spec.rb" "${DIR}/../spec/${BASENAME}")
|
|
59
|
+
;;
|
|
60
|
+
esac
|
|
61
|
+
|
|
62
|
+
# Check if any test file exists
|
|
63
|
+
for candidate in "${TEST_CANDIDATES[@]}"; do
|
|
64
|
+
if [[ -f "$candidate" ]]; then
|
|
65
|
+
echo "Test reminder: $BASENAME has tests at $(basename "$candidate")"
|
|
66
|
+
echo "- Consider updating tests to cover your changes"
|
|
67
|
+
exit 0
|
|
68
|
+
fi
|
|
69
|
+
done
|
|
70
|
+
|
|
71
|
+
# No test file found
|
|
72
|
+
echo "Test reminder: No test file found for $BASENAME"
|
|
73
|
+
echo "- Consider creating tests for this file"
|
|
74
|
+
|
|
75
|
+
exit 0
|