qualia-framework 2.1.6 → 2.2.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/framework/.claudeignore +51 -0
- package/framework/CLAUDE.md +54 -0
- package/framework/MCP_SETUP.md +229 -0
- package/framework/agents/architecture-strategist.md +1 -1
- package/framework/agents/code-simplicity-reviewer.md +1 -1
- package/framework/agents/kieran-typescript-reviewer.md +1 -1
- package/framework/agents/performance-oracle.md +1 -1
- package/framework/agents/qualia-codebase-mapper.md +1 -0
- package/framework/agents/qualia-debugger.md +1 -0
- package/framework/agents/qualia-executor.md +1 -0
- package/framework/agents/qualia-integration-checker.md +1 -0
- package/framework/agents/qualia-phase-researcher.md +1 -0
- package/framework/agents/qualia-plan-checker.md +1 -0
- package/framework/agents/qualia-planner.md +1 -0
- package/framework/agents/qualia-project-researcher.md +1 -0
- package/framework/agents/qualia-research-synthesizer.md +1 -0
- package/framework/agents/qualia-roadmapper.md +1 -0
- package/framework/agents/qualia-verifier.md +1 -0
- package/framework/agents/security-auditor.md +72 -0
- package/framework/agents/team-orchestrator.md +1 -0
- package/framework/agents/teams/framework-audit-team.md +66 -0
- package/framework/agents/teams/review-team.md +11 -3
- package/framework/hooks/block-env-edit.sh +4 -8
- package/framework/hooks/branch-guard.sh +2 -5
- package/framework/hooks/confirm-delete.sh +7 -4
- package/framework/hooks/migration-validate.sh +9 -8
- package/framework/hooks/notification-speak.sh +1 -1
- package/framework/hooks/pre-commit.sh +22 -10
- package/framework/hooks/pre-deploy-gate.sh +5 -6
- package/framework/hooks/retention-cleanup.sh +11 -2
- package/framework/hooks/save-session-state.sh +22 -0
- package/framework/hooks/session-context-loader.sh +27 -29
- package/framework/hooks/session-learn.sh +6 -5
- package/framework/hooks/skill-announce.sh +109 -6
- package/framework/hooks/tool-error-announce.sh +16 -7
- package/framework/install.ps1 +323 -0
- package/framework/install.sh +306 -0
- package/framework/qualia-engine/references/completion-checklists.md +359 -0
- package/framework/rules/deployment.md +4 -3
- package/framework/rules/speed.md +4 -0
- package/framework/skills/animate/SKILL.md +1 -1
- package/framework/skills/bolder/SKILL.md +1 -1
- package/framework/skills/colorize/SKILL.md +1 -1
- package/framework/skills/deep-research/SKILL.md +19 -13
- package/framework/skills/delight/SKILL.md +1 -1
- package/framework/skills/design-quieter/SKILL.md +1 -1
- package/framework/skills/distill/SKILL.md +1 -1
- package/framework/skills/qualia-audit-milestone/SKILL.md +1 -1
- package/framework/skills/qualia-complete-milestone/SKILL.md +2 -2
- package/framework/skills/qualia-design/SKILL.md +2 -2
- package/framework/skills/qualia-framework-audit/SKILL.md +604 -0
- package/framework/skills/qualia-help/SKILL.md +11 -1
- package/framework/skills/qualia-pause-work/SKILL.md +2 -2
- package/framework/skills/qualia-review/SKILL.md +1 -1
- package/framework/skills/qualia-start/SKILL.md +8 -1
- package/framework/skills/qualia-verify-work/SKILL.md +1 -1
- package/framework/skills/ship/SKILL.md +1 -1
- package/framework/statusline-command.sh +5 -6
- package/framework/teams/default/inboxes/plan-04.json +9 -0
- package/package.json +1 -1
- package/framework/askpass.sh +0 -2
- package/framework/commands/design.md +0 -53
- package/framework/commands/quick-db.md +0 -22
- package/framework/config/retention.json +0 -35
- package/framework/core/PRINCIPLES.md +0 -77
- package/framework/knowledge/claudecode-bible.md +0 -1384
- package/framework/knowledge/client-prefs.md +0 -22
- package/framework/knowledge/common-fixes.md +0 -25
- package/framework/knowledge/deployment-map.md +0 -35
- package/framework/knowledge/email-signature.html +0 -1
- package/framework/knowledge/employees.md +0 -8
- package/framework/knowledge/learned-patterns.md +0 -51
- package/framework/knowledge/optimization-research-2026.md +0 -137
- package/framework/knowledge/qualia-context.md +0 -67
- package/framework/knowledge/supabase-patterns.md +0 -50
- package/framework/knowledge/voice-agent-patterns.md +0 -46
- package/framework/statusline-command.js +0 -111
|
@@ -14,26 +14,22 @@ fi
|
|
|
14
14
|
BASENAME=$(basename "$FILE_PATH")
|
|
15
15
|
|
|
16
16
|
if [[ "$BASENAME" == .env* ]] || [[ "$FILE_PATH" == */.env ]] || [[ "$FILE_PATH" == */.env.* ]]; then
|
|
17
|
-
q_header "ENV GUARD"
|
|
18
|
-
q_fail "Editing ${BASENAME} blocked"
|
|
19
17
|
cat <<EOJSON
|
|
20
18
|
{
|
|
21
19
|
"continue": false,
|
|
22
|
-
"stopReason": "◆
|
|
23
|
-
"systemMessage": "BLOCKED: Cannot edit .env files through Claude Code. Tell the user EXACTLY what needs to change: which file, which variable, what value.
|
|
20
|
+
"stopReason": "◆ ENV GUARD: editing ${BASENAME} blocked",
|
|
21
|
+
"systemMessage": "◆ BLOCKED: Cannot edit .env files through Claude Code. Tell the user EXACTLY what needs to change: which file, which variable, what value."
|
|
24
22
|
}
|
|
25
23
|
EOJSON
|
|
26
24
|
exit 2
|
|
27
25
|
fi
|
|
28
26
|
|
|
29
27
|
if [[ "$FILE_PATH" == *credentials* ]] || [[ "$FILE_PATH" == *secret* ]] || [[ "$FILE_PATH" == *.pem ]] || [[ "$FILE_PATH" == *.key ]]; then
|
|
30
|
-
q_header "ENV GUARD"
|
|
31
|
-
q_fail "Editing credential file blocked"
|
|
32
28
|
cat <<EOJSON
|
|
33
29
|
{
|
|
34
30
|
"continue": false,
|
|
35
|
-
"stopReason": "◆
|
|
36
|
-
"systemMessage": "BLOCKED: Cannot edit credential/secret files through Claude. Tell the user what needs changing."
|
|
31
|
+
"stopReason": "◆ ENV GUARD: credential file blocked",
|
|
32
|
+
"systemMessage": "◆ BLOCKED: Cannot edit credential/secret files through Claude. Tell the user what needs changing."
|
|
37
33
|
}
|
|
38
34
|
EOJSON
|
|
39
35
|
exit 2
|
|
@@ -33,14 +33,11 @@ if [ "$ROLE" = "OWNER" ]; then
|
|
|
33
33
|
fi
|
|
34
34
|
|
|
35
35
|
# DEVELOPER/EMPLOYEE blocked
|
|
36
|
-
q_header "BRANCH GUARD"
|
|
37
|
-
q_fail "Push to ${BRANCH} blocked (${ROLE:-unknown} role)"
|
|
38
|
-
|
|
39
36
|
cat <<EOJSON
|
|
40
37
|
{
|
|
41
38
|
"continue": false,
|
|
42
|
-
"stopReason": "◆
|
|
43
|
-
"systemMessage": "BLOCKED: As
|
|
39
|
+
"stopReason": "◆ BRANCH GUARD: push to ${BRANCH} blocked (${ROLE:-unknown} role)",
|
|
40
|
+
"systemMessage": "◆ BLOCKED: As ${ROLE:-DEVELOPER}, cannot push to ${BRANCH}. Use /ship for feature branch workflow."
|
|
44
41
|
}
|
|
45
42
|
EOJSON
|
|
46
43
|
exit 2
|
|
@@ -17,13 +17,11 @@ case "$COMMAND" in
|
|
|
17
17
|
esac
|
|
18
18
|
|
|
19
19
|
block() {
|
|
20
|
-
q_header "DESTRUCTIVE GUARD"
|
|
21
|
-
q_fail "$1"
|
|
22
20
|
cat <<EOJSON
|
|
23
21
|
{
|
|
24
22
|
"continue": false,
|
|
25
|
-
"stopReason": "◆
|
|
26
|
-
"systemMessage": "BLOCKED: $1.
|
|
23
|
+
"stopReason": "◆ DESTRUCTIVE GUARD: $1",
|
|
24
|
+
"systemMessage": "◆ BLOCKED: $1. Find a safer alternative. Explain to the user what was blocked and what safer approach you're using instead."
|
|
27
25
|
}
|
|
28
26
|
EOJSON
|
|
29
27
|
exit 2
|
|
@@ -44,6 +42,11 @@ echo "$COMMAND" | grep -qE 'git\s+push\s+.*--force($|\s)' && ! echo "$COMMAND" |
|
|
|
44
42
|
echo "$COMMAND" | grep -qE 'git\s+reset\s+--hard' && block "git reset --hard discards work"
|
|
45
43
|
echo "$COMMAND" | grep -qE 'git\s+clean\s+-[a-z]*f' && block "git clean -f deletes untracked files"
|
|
46
44
|
|
|
45
|
+
# Supabase destructive
|
|
46
|
+
echo "$COMMAND" | grep -qE 'supabase\s+functions\s+delete' && block "supabase functions delete"
|
|
47
|
+
echo "$COMMAND" | grep -qE 'supabase\s+secrets\s+unset' && block "supabase secrets unset"
|
|
48
|
+
echo "$COMMAND" | grep -qE 'supabase\s+projects\s+delete' && block "supabase projects delete"
|
|
49
|
+
|
|
47
50
|
# Infrastructure
|
|
48
51
|
echo "$COMMAND" | grep -qE 'kubectl\s+delete\s' && block "kubectl delete"
|
|
49
52
|
echo "$COMMAND" | grep -qE 'docker\s+(rm|rmi)\s+-f' && block "docker force remove"
|
|
@@ -39,20 +39,19 @@ check_sql_file() {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
TOTAL=0
|
|
42
|
-
|
|
42
|
+
TRIGGERED=false
|
|
43
|
+
WARN_DETAILS=""
|
|
43
44
|
|
|
44
45
|
# Mode 1: SQL file written
|
|
45
46
|
if [ -n "$FILE_PATH" ] && [[ "$FILE_PATH" == *.sql ]]; then
|
|
46
|
-
|
|
47
|
-
HEADER_SHOWN=true
|
|
47
|
+
TRIGGERED=true
|
|
48
48
|
check_sql_file "$FILE_PATH"
|
|
49
49
|
TOTAL=$?
|
|
50
50
|
fi
|
|
51
51
|
|
|
52
52
|
# Mode 2: supabase db push
|
|
53
53
|
if [ -n "$COMMAND" ] && echo "$COMMAND" | grep -qE 'supabase\s+db\s+push'; then
|
|
54
|
-
|
|
55
|
-
HEADER_SHOWN=true
|
|
54
|
+
TRIGGERED=true
|
|
56
55
|
for sql_file in supabase/migrations/*.sql; do
|
|
57
56
|
[ -f "$sql_file" ] || continue
|
|
58
57
|
check_sql_file "$sql_file"
|
|
@@ -60,9 +59,11 @@ if [ -n "$COMMAND" ] && echo "$COMMAND" | grep -qE 'supabase\s+db\s+push'; then
|
|
|
60
59
|
done
|
|
61
60
|
fi
|
|
62
61
|
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
# Warn but don't block — surface via systemMessage
|
|
63
|
+
if $TRIGGERED && [ "$TOTAL" -gt 0 ]; then
|
|
64
|
+
printf '{"continue":true,"systemMessage":"◆ MIGRATION CHECK: %d issue(s) found — review carefully"}' "$TOTAL"
|
|
65
|
+
elif $TRIGGERED; then
|
|
66
|
+
printf '{"continue":true,"systemMessage":"◆ MIGRATION CHECK: clean"}'
|
|
65
67
|
fi
|
|
66
68
|
|
|
67
|
-
# Warn but don't block
|
|
68
69
|
exit 0
|
|
@@ -51,30 +51,42 @@ if [ -n "$JS_FILES" ]; then
|
|
|
51
51
|
done
|
|
52
52
|
fi
|
|
53
53
|
|
|
54
|
-
# TypeScript check
|
|
54
|
+
# TypeScript check (skip if tsc passed in last 5 minutes — pre-deploy-gate also runs tsc)
|
|
55
|
+
TSC_STAMP="/tmp/.tsc-pass-$(echo "$PWD" | md5sum | cut -c1-8)"
|
|
55
56
|
if [ -f "tsconfig.json" ]; then
|
|
56
|
-
if
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
if [ -f "$TSC_STAMP" ]; then
|
|
58
|
+
AGE=$(( $(date +%s) - $(stat -c %Y "$TSC_STAMP" 2>/dev/null || echo 0) ))
|
|
59
|
+
if [ "$AGE" -lt 300 ]; then
|
|
60
|
+
q_pass "TypeScript (cached)"
|
|
59
61
|
else
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
rm -f "$TSC_STAMP"
|
|
63
|
+
fi
|
|
64
|
+
fi
|
|
65
|
+
# Run tsc only if no valid cache
|
|
66
|
+
if [ ! -f "$TSC_STAMP" ]; then
|
|
67
|
+
if command -v npx &> /dev/null; then
|
|
68
|
+
if npx tsc --noEmit 2>/dev/null; then
|
|
69
|
+
q_pass "TypeScript"
|
|
70
|
+
touch "$TSC_STAMP"
|
|
71
|
+
else
|
|
72
|
+
q_fail "TypeScript errors"
|
|
73
|
+
FAIL_DETAILS="${FAIL_DETAILS}TypeScript errors. Run npx tsc --noEmit. "
|
|
74
|
+
BLOCKED=true
|
|
75
|
+
fi
|
|
63
76
|
fi
|
|
64
77
|
fi
|
|
65
78
|
fi
|
|
66
79
|
|
|
67
80
|
if $BLOCKED; then
|
|
68
|
-
q_blocked "Commit blocked"
|
|
69
81
|
cat <<EOJSON
|
|
70
82
|
{
|
|
71
83
|
"continue": false,
|
|
72
84
|
"stopReason": "◆ Pre-commit: blocked",
|
|
73
|
-
"systemMessage": "COMMIT BLOCKED
|
|
85
|
+
"systemMessage": "◆ PRE-COMMIT BLOCKED: ${FAIL_DETAILS}Fix issues, stage corrected files, and retry."
|
|
74
86
|
}
|
|
75
87
|
EOJSON
|
|
76
88
|
exit 2
|
|
77
89
|
fi
|
|
78
90
|
|
|
79
|
-
|
|
91
|
+
printf '{"continue":true,"systemMessage":"◆ PRE-COMMIT: all checks passed"}'
|
|
80
92
|
exit 0
|
|
@@ -128,24 +128,23 @@ fi
|
|
|
128
128
|
|
|
129
129
|
# ─── Verdict ───
|
|
130
130
|
if [ "$FAILURES" -gt 0 ]; then
|
|
131
|
-
q_blocked "${FAILURES} check(s) failed"
|
|
132
|
-
|
|
133
131
|
cat <<EOJSON
|
|
134
132
|
{
|
|
135
133
|
"continue": false,
|
|
136
134
|
"stopReason": "◆ Deploy gate: ${FAILURES} check(s) failed",
|
|
137
|
-
"systemMessage": "DEPLOY BLOCKED
|
|
135
|
+
"systemMessage": "◆ DEPLOY BLOCKED: ${FAILURES} check(s) failed. ${FAIL_DETAILS}Fix and retry vercel --prod."
|
|
138
136
|
}
|
|
139
137
|
EOJSON
|
|
140
138
|
exit 2
|
|
141
139
|
fi
|
|
142
140
|
|
|
141
|
+
WARN_MSG=""
|
|
143
142
|
if [ "$WARNINGS" -gt 0 ]; then
|
|
144
|
-
|
|
143
|
+
WARN_MSG=" (${WARNINGS} warning(s))"
|
|
145
144
|
fi
|
|
146
145
|
|
|
147
|
-
q_approved
|
|
148
|
-
|
|
149
146
|
# Stamp success
|
|
150
147
|
touch "$STAMP"
|
|
148
|
+
|
|
149
|
+
printf '{"continue":true,"systemMessage":"◆ DEPLOY GATE APPROVED%s"}' "$WARN_MSG"
|
|
151
150
|
exit 0
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# Retention cleanup — runs on SessionStart to enforce retention policies
|
|
3
3
|
# Keeps .claude/ lean by pruning stale data automatically
|
|
4
|
+
# This is the SINGLE SOURCE OF TRUTH for retention — config/retention.json is deprecated
|
|
5
|
+
#
|
|
6
|
+
# Policies:
|
|
7
|
+
# file-history/ 7 days
|
|
8
|
+
# session-env/ 50 JSON files + 10 UUID dirs
|
|
9
|
+
# backups/ 3 days
|
|
10
|
+
# paste-cache/ 3 days
|
|
11
|
+
# shell-snapshots/ 3 days
|
|
12
|
+
# projects/*.jsonl 7 days
|
|
13
|
+
# tasks/ 3 days
|
|
14
|
+
# plans/ 7 days
|
|
4
15
|
|
|
5
16
|
CLAUDE_DIR="$HOME/.claude"
|
|
6
17
|
|
|
7
|
-
# (debug/ and context-states/ removed — directories don't exist)
|
|
8
|
-
|
|
9
18
|
# file-history/ — keep 7 days max
|
|
10
19
|
find "$CLAUDE_DIR/file-history/" -type f -mtime +7 -delete 2>/dev/null
|
|
11
20
|
find "$CLAUDE_DIR/file-history/" -type d -empty -delete 2>/dev/null
|
|
@@ -8,6 +8,17 @@ DIGEST_FILE="$KNOWLEDGE_DIR/session-digest.md"
|
|
|
8
8
|
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
|
9
9
|
SESSION_FILE="$SESSION_DIR/session_$TIMESTAMP.json"
|
|
10
10
|
|
|
11
|
+
# Skip saving for very short sessions (< 30s) to reduce cruft
|
|
12
|
+
SESSION_START_FILE="$SESSION_DIR/.session-start"
|
|
13
|
+
if [ -f "$SESSION_START_FILE" ]; then
|
|
14
|
+
START_TS=$(cat "$SESSION_START_FILE" 2>/dev/null || echo 0)
|
|
15
|
+
NOW_TS=$(date +%s)
|
|
16
|
+
DURATION=$((NOW_TS - START_TS))
|
|
17
|
+
if [ "$DURATION" -lt 30 ]; then
|
|
18
|
+
exit 0
|
|
19
|
+
fi
|
|
20
|
+
fi
|
|
21
|
+
|
|
11
22
|
mkdir -p "$SESSION_DIR"
|
|
12
23
|
mkdir -p "$KNOWLEDGE_DIR"
|
|
13
24
|
|
|
@@ -69,6 +80,17 @@ if [ "$PROJECT_NAME" != ".claude" ] && [ "$PROJECT_NAME" != "Projects" ] && { [
|
|
|
69
80
|
DATE_SHORT=$(date '+%m-%d %H:%M')
|
|
70
81
|
ENTRY="| ${DATE_SHORT} | ${PROJECT_NAME} | ${GIT_BRANCH:-—} | ${FILES_CHANGED} | ${SUMMARY:-—} |"
|
|
71
82
|
|
|
83
|
+
# Dedup: skip if ANY existing entry has the same project + branch + summary
|
|
84
|
+
NEW_KEY="${PROJECT_NAME}|${GIT_BRANCH:-—}|${SUMMARY:-—}"
|
|
85
|
+
if tail -n +4 "$DIGEST_FILE" | while IFS= read -r line; do
|
|
86
|
+
ENTRY_KEY=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$3); gsub(/^ +| +$/,"",$4); gsub(/^ +| +$/,"",$6); print $3"|"$4"|"$6}')
|
|
87
|
+
[ "$ENTRY_KEY" = "$NEW_KEY" ] && exit 0
|
|
88
|
+
done; then
|
|
89
|
+
: # no match found, continue
|
|
90
|
+
else
|
|
91
|
+
exit 0 # duplicate found, skip
|
|
92
|
+
fi
|
|
93
|
+
|
|
72
94
|
# Read existing entries (skip header — first 3 lines), keep last 19
|
|
73
95
|
EXISTING=$(tail -n +4 "$DIGEST_FILE" | head -19)
|
|
74
96
|
|
|
@@ -1,77 +1,75 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# SessionStart hook —
|
|
3
|
-
#
|
|
4
|
-
source "$(dirname "$0")/qualia-colors.sh"
|
|
2
|
+
# SessionStart hook — session context with systemMessage for user visibility
|
|
3
|
+
# stderr only shows in verbose mode; systemMessage shows in normal transcript
|
|
5
4
|
|
|
6
5
|
CWD=$(pwd)
|
|
7
6
|
SESSION_DIR="$HOME/.claude/session-env"
|
|
8
7
|
COMPACT_FILE="$SESSION_DIR/pre-compact.json"
|
|
9
8
|
PROJECT=$(basename "$CWD")
|
|
10
9
|
|
|
11
|
-
#
|
|
12
|
-
|
|
10
|
+
# Record session start time for duration-based filtering in save-session-state.sh
|
|
11
|
+
mkdir -p "$SESSION_DIR"
|
|
12
|
+
date +%s > "$SESSION_DIR/.session-start"
|
|
13
|
+
|
|
14
|
+
# Build display message
|
|
15
|
+
MSG="◆ SESSION START"
|
|
16
|
+
ISSUES=""
|
|
13
17
|
|
|
14
18
|
# Last session info
|
|
15
19
|
if [ -f "$COMPACT_FILE" ]; then
|
|
16
20
|
LAST_PROJECT=$(node -e "try{const d=JSON.parse(require('fs').readFileSync('$COMPACT_FILE','utf8'));process.stdout.write(d.project_name||'')}catch(e){}" 2>/dev/null)
|
|
17
21
|
LAST_BRANCH=$(node -e "try{const d=JSON.parse(require('fs').readFileSync('$COMPACT_FILE','utf8'));process.stdout.write(d.git_branch||'')}catch(e){}" 2>/dev/null)
|
|
18
22
|
if [ -n "$LAST_PROJECT" ] && [ "$LAST_PROJECT" != ".claude" ]; then
|
|
19
|
-
|
|
23
|
+
MSG="${MSG} | Last: ${LAST_PROJECT} (${LAST_BRANCH:-no branch})"
|
|
20
24
|
fi
|
|
21
25
|
fi
|
|
22
26
|
|
|
23
|
-
|
|
24
|
-
q_pass "Project: ${PROJECT}"
|
|
27
|
+
MSG="${MSG} | Project: ${PROJECT}"
|
|
25
28
|
|
|
26
29
|
# Handoff file
|
|
27
30
|
if [ -f "$CWD/.continue-here.md" ]; then
|
|
28
|
-
|
|
31
|
+
MSG="${MSG} | ▲ Handoff: .continue-here.md"
|
|
29
32
|
fi
|
|
30
33
|
|
|
31
|
-
# Errors / warnings
|
|
32
|
-
ERRORS=0
|
|
33
|
-
|
|
34
34
|
# Check hooks health
|
|
35
35
|
HOOKS_OK=0
|
|
36
36
|
HOOKS_TOTAL=0
|
|
37
|
-
for h in branch-guard pre-commit confirm-delete migration-validate pre-deploy-gate block-env-edit auto-format session-context-loader retention-cleanup pre-compact save-session-state session-learn notification-speak qualia-colors; do
|
|
37
|
+
for h in branch-guard pre-commit confirm-delete migration-validate pre-deploy-gate block-env-edit auto-format session-context-loader retention-cleanup pre-compact save-session-state session-learn notification-speak qualia-colors skill-announce tool-error-announce; do
|
|
38
38
|
HOOKS_TOTAL=$((HOOKS_TOTAL + 1))
|
|
39
39
|
[ -f "$HOME/.claude/hooks/${h}.sh" ] && HOOKS_OK=$((HOOKS_OK + 1))
|
|
40
40
|
done
|
|
41
41
|
|
|
42
42
|
if [ "$HOOKS_OK" -eq "$HOOKS_TOTAL" ]; then
|
|
43
|
-
|
|
43
|
+
MSG="${MSG} | Hooks: ${HOOKS_OK}/${HOOKS_TOTAL}"
|
|
44
44
|
else
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
MSG="${MSG} | Hooks: ${HOOKS_OK}/${HOOKS_TOTAL} ($(( HOOKS_TOTAL - HOOKS_OK )) missing)"
|
|
46
|
+
ISSUES="${ISSUES}Missing hooks. "
|
|
47
47
|
fi
|
|
48
48
|
|
|
49
49
|
# Check CLAUDE.md exists
|
|
50
50
|
if [ -f "$HOME/.claude/CLAUDE.md" ]; then
|
|
51
51
|
ROLE=$(grep -m1 "^## Role:" "$HOME/.claude/CLAUDE.md" 2>/dev/null | sed 's/^## Role: *//')
|
|
52
|
-
|
|
52
|
+
MSG="${MSG} | Role: ${ROLE:-unknown}"
|
|
53
53
|
else
|
|
54
|
-
|
|
55
|
-
ERRORS=$((ERRORS + 1))
|
|
54
|
+
ISSUES="${ISSUES}CLAUDE.md missing. "
|
|
56
55
|
fi
|
|
57
56
|
|
|
58
57
|
# Check settings.json valid
|
|
59
58
|
if [ -f "$HOME/.claude/settings.json" ]; then
|
|
60
59
|
node -e "JSON.parse(require('fs').readFileSync('$HOME/.claude/settings.json','utf8'))" 2>/dev/null
|
|
61
|
-
if [ $? -
|
|
62
|
-
|
|
63
|
-
else
|
|
64
|
-
q_fail "Settings: invalid JSON!"
|
|
65
|
-
ERRORS=$((ERRORS + 1))
|
|
60
|
+
if [ $? -ne 0 ]; then
|
|
61
|
+
ISSUES="${ISSUES}settings.json invalid. "
|
|
66
62
|
fi
|
|
67
63
|
fi
|
|
68
64
|
|
|
69
|
-
if [ "$
|
|
70
|
-
|
|
65
|
+
if [ -n "$ISSUES" ]; then
|
|
66
|
+
MSG="${MSG} | ▲ ${ISSUES}"
|
|
71
67
|
fi
|
|
72
68
|
|
|
73
|
-
|
|
69
|
+
MSG="${MSG} | Qualia mode activating..."
|
|
70
|
+
|
|
71
|
+
# Escape for JSON
|
|
72
|
+
MSG=$(echo "$MSG" | sed 's/"/\\"/g' | tr '\n' ' ')
|
|
74
73
|
|
|
75
|
-
|
|
76
|
-
printf '{"continue":true}'
|
|
74
|
+
printf '{"continue":true,"systemMessage":"%s"}' "$MSG"
|
|
77
75
|
exit 0
|
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
# SessionEnd hook: prompt for lessons learned if significant work was done
|
|
3
3
|
# "Significant" = more than 3 files modified in the session
|
|
4
4
|
|
|
5
|
-
set -euo pipefail
|
|
6
|
-
|
|
7
5
|
LEARNED_FILE="$HOME/.claude/knowledge/learned-patterns.md"
|
|
8
6
|
|
|
7
|
+
# Skip if not in a git repo
|
|
8
|
+
git rev-parse --is-inside-work-tree &>/dev/null || exit 0
|
|
9
|
+
|
|
9
10
|
# Count files modified: committed in last 2 hours + uncommitted
|
|
10
|
-
COMMITTED=$(git diff --name-only "$(git log --since='2 hours ago' --format=%H | tail -1
|
|
11
|
-
UNCOMMITTED=$(git diff --name-only 2>/dev/null | wc -l || echo 0)
|
|
11
|
+
COMMITTED=$(git diff --name-only "$(git log --since='2 hours ago' --format=%H 2>/dev/null | tail -1 || echo HEAD)" HEAD 2>/dev/null | wc -l 2>/dev/null || echo 0)
|
|
12
|
+
UNCOMMITTED=$(git diff --name-only 2>/dev/null | wc -l 2>/dev/null || echo 0)
|
|
12
13
|
MODIFIED_COUNT=$((COMMITTED + UNCOMMITTED))
|
|
13
14
|
|
|
14
15
|
# Only trigger if significant work was done
|
|
@@ -25,6 +26,6 @@ if [ ! -f "$LEARNED_FILE" ]; then
|
|
|
25
26
|
fi
|
|
26
27
|
|
|
27
28
|
# Output reminder (shown to Claude in session context)
|
|
28
|
-
|
|
29
|
+
printf '{"continue":true,"systemMessage":"SESSION_LEARN: %d files changed this session. Consider running /learn to capture any lessons."}' "$MODIFIED_COUNT"
|
|
29
30
|
|
|
30
31
|
exit 0
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# Announce skill activation
|
|
2
|
+
# Announce skill activation — fires on every Skill() invocation
|
|
3
|
+
# Shows teal-branded banner on stderr (visible in terminal) + systemMessage for transcript
|
|
4
|
+
|
|
3
5
|
source "$(dirname "$0")/qualia-colors.sh"
|
|
4
6
|
|
|
5
7
|
if [ ! -t 0 ]; then
|
|
@@ -7,12 +9,113 @@ if [ ! -t 0 ]; then
|
|
|
7
9
|
SKILL_NAME=$(echo "$INPUT" | node -e "try{const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));process.stdout.write(d.tool_input?.skill||d.tool_input?.name||'')}catch(e){}" 2>/dev/null)
|
|
8
10
|
fi
|
|
9
11
|
|
|
10
|
-
[ -z "$SKILL_NAME" ] && exit 0
|
|
12
|
+
[ -z "$SKILL_NAME" ] && printf '{"continue":true}' && exit 0
|
|
13
|
+
|
|
14
|
+
# Skill descriptions for the banner
|
|
15
|
+
declare -A SKILL_DESC
|
|
16
|
+
SKILL_DESC=(
|
|
17
|
+
# Pipeline
|
|
18
|
+
["qualia-new-project"]="Initializing new project"
|
|
19
|
+
["qualia-new-milestone"]="Starting new milestone"
|
|
20
|
+
["qualia-discuss-phase"]="Clarifying phase decisions"
|
|
21
|
+
["qualia-list-phase-assumptions"]="Surfacing assumptions"
|
|
22
|
+
["qualia-research-phase"]="Researching phase domain"
|
|
23
|
+
["qualia-plan-phase"]="Creating execution plans"
|
|
24
|
+
["qualia-execute-phase"]="Executing phase plans"
|
|
25
|
+
["qualia-verify-work"]="Verifying deliverables"
|
|
26
|
+
["qualia-audit-milestone"]="Auditing milestone completion"
|
|
27
|
+
["qualia-complete-milestone"]="Completing milestone"
|
|
28
|
+
["qualia-plan-milestone-gaps"]="Planning gap fixes"
|
|
29
|
+
# Navigation
|
|
30
|
+
["qualia-start"]="Activating Qualia mode"
|
|
31
|
+
["qualia-progress"]="Checking progress"
|
|
32
|
+
["qualia-idk"]="Analyzing next steps"
|
|
33
|
+
["qualia"]="Routing to next action"
|
|
34
|
+
["qualia-resume-work"]="Restoring session context"
|
|
35
|
+
["qualia-pause-work"]="Saving session state"
|
|
36
|
+
# Quality
|
|
37
|
+
["qualia-review"]="Running code review"
|
|
38
|
+
["qualia-optimize"]="Running optimization pass"
|
|
39
|
+
["qualia-production-check"]="Running production audit"
|
|
40
|
+
["qualia-framework-audit"]="Auditing framework"
|
|
41
|
+
["deep-research"]="Spawning research agents"
|
|
42
|
+
# Design
|
|
43
|
+
["critique"]="Evaluating design"
|
|
44
|
+
["polish"]="Final detail pass"
|
|
45
|
+
["bolder"]="Amplifying design"
|
|
46
|
+
["design-quieter"]="Toning down design"
|
|
47
|
+
["distill"]="Stripping complexity"
|
|
48
|
+
["colorize"]="Adding color"
|
|
49
|
+
["normalize"]="Matching design system"
|
|
50
|
+
["responsive"]="Fixing responsive layout"
|
|
51
|
+
["animate"]="Adding motion"
|
|
52
|
+
["clarify"]="Improving UX copy"
|
|
53
|
+
["delight"]="Adding personality"
|
|
54
|
+
["harden"]="Hardening edge cases"
|
|
55
|
+
["onboard"]="Designing onboarding"
|
|
56
|
+
["frontend-master"]="Building frontend"
|
|
57
|
+
["qualia-design"]="Full design transformation"
|
|
58
|
+
# Deploy
|
|
59
|
+
["ship"]="Deploying to production"
|
|
60
|
+
["deploy"]="Quick deploy"
|
|
61
|
+
["deploy-verify"]="Verifying deployment"
|
|
62
|
+
["status"]="Fleet health check"
|
|
63
|
+
# Debug & Quick
|
|
64
|
+
["qualia-debug"]="Structured debugging"
|
|
65
|
+
["qualia-quick"]="Quick task with quality gates"
|
|
66
|
+
# Research
|
|
67
|
+
["stack-researcher"]="Researching tech stack"
|
|
68
|
+
["docs-lookup"]="Fetching documentation"
|
|
69
|
+
# Domain
|
|
70
|
+
["supabase"]="Supabase operations"
|
|
71
|
+
["voice-agent"]="Building voice agent"
|
|
72
|
+
["seo-master"]="SEO audit"
|
|
73
|
+
["browser-qa"]="Browser QA testing"
|
|
74
|
+
# Utility
|
|
75
|
+
["learn"]="Capturing lesson"
|
|
76
|
+
["memory"]="Managing memory"
|
|
77
|
+
["pr"]="Creating pull request"
|
|
78
|
+
["team"]="Orchestrating agent team"
|
|
79
|
+
["retro"]="Generating retrospective"
|
|
80
|
+
["test-runner"]="Running tests"
|
|
81
|
+
["zoho-workflow"]="Zoho operations"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# Get description or fallback
|
|
85
|
+
DESC="${SKILL_DESC[$SKILL_NAME]}"
|
|
86
|
+
[ -z "$DESC" ] && DESC="Activating"
|
|
87
|
+
|
|
88
|
+
# Clean name for display
|
|
89
|
+
DISPLAY_NAME=$(echo "$SKILL_NAME" | sed 's/-/ /g')
|
|
90
|
+
|
|
91
|
+
# Determine skill category icon
|
|
92
|
+
case "$SKILL_NAME" in
|
|
93
|
+
qualia-new-*|qualia-plan-*|qualia-execute-*|qualia-verify-*|qualia-audit-*|qualia-complete-*|qualia-discuss-*|qualia-list-*|qualia-research-*)
|
|
94
|
+
ICON="▶" ;;
|
|
95
|
+
qualia-review|qualia-optimize|qualia-production-check|qualia-framework-audit|deep-research)
|
|
96
|
+
ICON="⊘" ;;
|
|
97
|
+
critique|polish|bolder|design-quieter|distill|colorize|normalize|responsive|animate|clarify|delight|harden|onboard|frontend-master|qualia-design)
|
|
98
|
+
ICON="◇" ;;
|
|
99
|
+
ship|deploy|deploy-verify|status)
|
|
100
|
+
ICON="↑" ;;
|
|
101
|
+
qualia-debug|qualia-quick)
|
|
102
|
+
ICON="⚡" ;;
|
|
103
|
+
*)
|
|
104
|
+
ICON="◆" ;;
|
|
105
|
+
esac
|
|
11
106
|
|
|
12
|
-
#
|
|
13
|
-
|
|
107
|
+
# Build the teal banner — output to stderr (visible in terminal)
|
|
108
|
+
WIDTH=44
|
|
109
|
+
SKILL_UPPER="${DISPLAY_NAME^^}"
|
|
110
|
+
PAD_LEN=$(( WIDTH - ${#SKILL_UPPER} - 6 ))
|
|
111
|
+
[ "$PAD_LEN" -lt 2 ] && PAD_LEN=2
|
|
112
|
+
PADDING=$(printf '─%.0s' $(seq 1 $PAD_LEN))
|
|
14
113
|
|
|
15
|
-
|
|
114
|
+
printf "\n" >&2
|
|
115
|
+
printf "${Q_TEAL}${ICON}${Q_RESET} ${Q_BRIGHT}QUALIA${Q_RESET} ${Q_DIM}───${Q_RESET} ${Q_TEAL}/%s${Q_RESET} ${Q_DIM}%s${Q_RESET}\n" "$SKILL_NAME" "$PADDING" >&2
|
|
116
|
+
printf " ${Q_WHITE}%s${Q_RESET}${Q_DIM}...${Q_RESET}\n" "$DESC" >&2
|
|
117
|
+
printf "${Q_TEAL}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${Q_RESET}\n" >&2
|
|
16
118
|
|
|
17
|
-
|
|
119
|
+
# Also send systemMessage for transcript visibility
|
|
120
|
+
printf '{"continue":true,"systemMessage":"◆ QUALIA ─── /%s ─── %s"}' "$SKILL_NAME" "$DESC"
|
|
18
121
|
exit 0
|
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# Announce tool failures
|
|
2
|
+
# Announce tool failures — fires on PostToolUseFailure
|
|
3
|
+
# Shows teal-branded error on stderr + systemMessage for transcript
|
|
4
|
+
|
|
3
5
|
source "$(dirname "$0")/qualia-colors.sh"
|
|
4
6
|
|
|
5
7
|
if [ ! -t 0 ]; then
|
|
6
8
|
INPUT=$(cat)
|
|
7
9
|
TOOL_NAME=$(echo "$INPUT" | node -e "try{const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));process.stdout.write(d.tool_name||'')}catch(e){}" 2>/dev/null)
|
|
8
|
-
ERROR=$(echo "$INPUT" | node -e "try{const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));process.stdout.write(d.error||d.tool_output?.stderr||'')}catch(e){}" 2>/dev/null)
|
|
10
|
+
ERROR=$(echo "$INPUT" | node -e "try{const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));process.stdout.write((d.error||d.tool_output?.stderr||'').substring(0,200).replace(/\\/g,'\\\\').replace(/\"/g,'\\\"'))}catch(e){}" 2>/dev/null)
|
|
9
11
|
fi
|
|
10
12
|
|
|
11
|
-
[ -z "$TOOL_NAME" ] && exit 0
|
|
13
|
+
[ -z "$TOOL_NAME" ] && printf '{"continue":true}' && exit 0
|
|
14
|
+
|
|
15
|
+
# Teal-branded error banner on stderr
|
|
16
|
+
printf "\n" >&2
|
|
17
|
+
printf "${Q_FAIL}✗${Q_RESET} ${Q_BRIGHT}QUALIA${Q_RESET} ${Q_DIM}───${Q_RESET} ${Q_FAIL}%s failed${Q_RESET}\n" "$TOOL_NAME" >&2
|
|
18
|
+
[ -n "$ERROR" ] && printf " ${Q_DIM}%s${Q_RESET}\n" "$(echo "$ERROR" | head -c 120)" >&2
|
|
19
|
+
printf "${Q_TEAL}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${Q_RESET}\n" >&2
|
|
12
20
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
[ -n "$ERROR" ] &&
|
|
21
|
+
# systemMessage for transcript
|
|
22
|
+
MSG="◆ ERROR: ${TOOL_NAME} failed"
|
|
23
|
+
[ -n "$ERROR" ] && MSG="${MSG} — $(echo "$ERROR" | head -c 100)"
|
|
24
|
+
MSG=$(echo "$MSG" | sed 's/"/\\"/g' | tr '\n' ' ')
|
|
16
25
|
|
|
17
|
-
printf '{"continue":true}'
|
|
26
|
+
printf '{"continue":true,"systemMessage":"%s"}' "$MSG"
|
|
18
27
|
exit 0
|