qualia-framework 2.2.1 → 2.4.1
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/bin/collect-metrics.sh +62 -0
- package/framework/agents/qualia-phase-researcher.md +6 -3
- package/framework/agents/qualia-planner.md +10 -7
- package/framework/agents/qualia-research-synthesizer.md +110 -147
- package/framework/agents/red-team-qa.md +130 -0
- package/framework/hooks/auto-format.sh +9 -1
- package/framework/hooks/confirm-delete.sh +2 -2
- package/framework/hooks/migration-validate.sh +21 -16
- package/framework/hooks/pre-commit.sh +17 -9
- package/framework/hooks/pre-deploy-gate.sh +22 -15
- package/framework/hooks/retention-cleanup.sh +4 -4
- package/framework/hooks/save-session-state.sh +18 -10
- package/framework/hooks/session-context-loader.sh +21 -0
- package/framework/hooks/skill-announce.sh +2 -0
- package/framework/install.sh +9 -4
- package/framework/qualia-engine/VERSION +1 -1
- package/framework/qualia-engine/bin/collect-metrics.sh +71 -0
- package/framework/qualia-engine/bin/qualia-tools.js +104 -63
- package/framework/qualia-engine/references/continuation-prompt.md +97 -0
- package/framework/qualia-engine/references/employee-guide.md +167 -0
- package/framework/qualia-engine/templates/lab-notes.md +16 -0
- package/framework/qualia-engine/templates/projects/ai-agent.md +1 -1
- package/framework/qualia-engine/templates/projects/voice-agent.md +4 -4
- package/framework/qualia-engine/templates/roadmap.md +4 -0
- package/framework/qualia-engine/templates/state.md +3 -0
- package/framework/qualia-engine/workflows/execute-phase.md +17 -17
- package/framework/qualia-engine/workflows/new-project.md +54 -130
- package/framework/qualia-engine/workflows/progress.md +63 -28
- package/framework/skills/client-handoff/SKILL.md +135 -0
- package/framework/skills/collab-onboard/SKILL.md +111 -0
- package/framework/skills/deep-research/SKILL.md +34 -71
- package/framework/skills/docs-lookup/SKILL.md +4 -3
- package/framework/skills/learn/SKILL.md +30 -6
- package/framework/skills/mobile-expo/SKILL.md +117 -4
- package/framework/skills/openrouter-agent/SKILL.md +922 -0
- package/framework/skills/qualia/SKILL.md +65 -19
- package/framework/skills/qualia-audit-milestone/SKILL.md +5 -2
- package/framework/skills/qualia-complete-milestone/SKILL.md +34 -8
- package/framework/skills/qualia-evolve/SKILL.md +200 -0
- package/framework/skills/qualia-execute-phase/SKILL.md +5 -2
- package/framework/skills/qualia-guide/SKILL.md +32 -0
- package/framework/skills/qualia-help/SKILL.md +100 -64
- package/framework/skills/qualia-new-project/SKILL.md +186 -62
- package/framework/skills/qualia-plan-phase/SKILL.md +5 -2
- package/framework/skills/qualia-report/SKILL.md +217 -0
- package/framework/skills/qualia-start/SKILL.md +31 -59
- package/framework/skills/qualia-verify-work/SKILL.md +33 -6
- package/framework/skills/qualia-workflow/SKILL.md +5 -5
- package/framework/skills/ship/SKILL.md +32 -6
- package/framework/skills/voice-agent/SKILL.md +1174 -269
- package/package.json +1 -1
|
@@ -10,37 +10,39 @@ if [ ! -t 0 ]; then
|
|
|
10
10
|
fi
|
|
11
11
|
fi
|
|
12
12
|
|
|
13
|
+
DESTRUCTIVE=0
|
|
14
|
+
WARNINGS_COUNT=0
|
|
15
|
+
|
|
13
16
|
check_sql_file() {
|
|
14
17
|
local file="$1"
|
|
15
|
-
local issues=0
|
|
16
18
|
[ ! -f "$file" ] && return 0
|
|
17
19
|
|
|
20
|
+
# Destructive ops → block
|
|
18
21
|
if grep -iE '\bDROP\s+(TABLE|SCHEMA|DATABASE)\b' "$file" > /dev/null 2>&1; then
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
q_fail "DROP TABLE/SCHEMA in ${file}"
|
|
23
|
+
DESTRUCTIVE=$((DESTRUCTIVE + 1))
|
|
21
24
|
fi
|
|
22
25
|
if grep -iE '\bTRUNCATE\b' "$file" > /dev/null 2>&1; then
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
q_fail "TRUNCATE in ${file}"
|
|
27
|
+
DESTRUCTIVE=$((DESTRUCTIVE + 1))
|
|
25
28
|
fi
|
|
26
29
|
if grep -iE '\bDELETE\s+FROM\b' "$file" > /dev/null 2>&1 && ! grep -iE '\bWHERE\b' "$file" > /dev/null 2>&1; then
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
q_fail "DELETE without WHERE in ${file}"
|
|
31
|
+
DESTRUCTIVE=$((DESTRUCTIVE + 1))
|
|
29
32
|
fi
|
|
30
33
|
if grep -iE '\bALTER\s+TABLE\b.*\bDROP\s+COLUMN\b' "$file" > /dev/null 2>&1; then
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
q_fail "DROP COLUMN in ${file}"
|
|
35
|
+
DESTRUCTIVE=$((DESTRUCTIVE + 1))
|
|
33
36
|
fi
|
|
37
|
+
# Missing RLS → warn only (reminder, not destructive)
|
|
34
38
|
if grep -iE '\bCREATE\s+TABLE\b' "$file" > /dev/null 2>&1 && ! grep -iE '\bENABLE\s+ROW\s+LEVEL\s+SECURITY\b' "$file" > /dev/null 2>&1; then
|
|
35
|
-
q_warn "New table
|
|
36
|
-
|
|
39
|
+
q_warn "New table needs RLS in ${file} — tell Claude: 'add RLS policies to the new table'"
|
|
40
|
+
WARNINGS_COUNT=$((WARNINGS_COUNT + 1))
|
|
37
41
|
fi
|
|
38
|
-
return $issues
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
TOTAL=0
|
|
42
45
|
TRIGGERED=false
|
|
43
|
-
WARN_DETAILS=""
|
|
44
46
|
|
|
45
47
|
# Mode 1: SQL file written
|
|
46
48
|
if [ -n "$FILE_PATH" ] && [[ "$FILE_PATH" == *.sql ]]; then
|
|
@@ -59,9 +61,12 @@ if [ -n "$COMMAND" ] && echo "$COMMAND" | grep -qE 'supabase\s+db\s+push'; then
|
|
|
59
61
|
done
|
|
60
62
|
fi
|
|
61
63
|
|
|
62
|
-
#
|
|
63
|
-
if $TRIGGERED && [ "$
|
|
64
|
-
printf '{"continue":
|
|
64
|
+
# Block on destructive ops, warn on missing RLS
|
|
65
|
+
if $TRIGGERED && [ "$DESTRUCTIVE" -gt 0 ]; then
|
|
66
|
+
printf '{"continue":false,"stopReason":"◆ MIGRATION: %d destructive operation(s) blocked","systemMessage":"◆ MIGRATION BLOCKED: %d destructive operation(s) found. Tell Claude to review the SQL and confirm these operations are intentional."}' "$DESTRUCTIVE" "$DESTRUCTIVE"
|
|
67
|
+
exit 2
|
|
68
|
+
elif $TRIGGERED && [ "$WARNINGS_COUNT" -gt 0 ]; then
|
|
69
|
+
printf '{"continue":true,"systemMessage":"◆ MIGRATION CHECK: %d warning(s) — tell Claude to review missing RLS policies."}' "$WARNINGS_COUNT"
|
|
65
70
|
elif $TRIGGERED; then
|
|
66
71
|
printf '{"continue":true,"systemMessage":"◆ MIGRATION CHECK: clean"}'
|
|
67
72
|
fi
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
# Pre-commit validation — secrets, debug statements, TypeScript, lint
|
|
3
3
|
source "$(dirname "$0")/qualia-colors.sh"
|
|
4
4
|
|
|
5
|
+
if ! command -v node &>/dev/null; then
|
|
6
|
+
[ ! -t 0 ] && cat > /dev/null
|
|
7
|
+
printf '{"continue":false,"stopReason":"PRE-COMMIT: node is not installed — cannot verify safety. Install node to proceed."}'
|
|
8
|
+
exit 2
|
|
9
|
+
fi
|
|
10
|
+
|
|
5
11
|
if [ ! -t 0 ]; then
|
|
6
12
|
INPUT=$(cat)
|
|
7
13
|
COMMAND=$(echo "$INPUT" | node -e "try{const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));process.stdout.write(d.tool_input?.command||d.tool_input||'')}catch(e){}" 2>/dev/null)
|
|
@@ -28,7 +34,7 @@ SECRETS_PATTERN="(api[_-]?key|apikey|secret[_-]?key|password|passwd|pwd|token|au
|
|
|
28
34
|
for file in $STAGED_FILES; do
|
|
29
35
|
if [ -f "$file" ] && grep -iE "$SECRETS_PATTERN" "$file" > /dev/null 2>&1; then
|
|
30
36
|
q_fail "Secret in ${file}"
|
|
31
|
-
FAIL_DETAILS="${FAIL_DETAILS}
|
|
37
|
+
FAIL_DETAILS="${FAIL_DETAILS}A password or API key was found in ${file} — tell Claude: 'remove the secret and use an environment variable instead.' "
|
|
32
38
|
BLOCKED=true
|
|
33
39
|
fi
|
|
34
40
|
done
|
|
@@ -37,16 +43,18 @@ done
|
|
|
37
43
|
ENV_FILES=$(echo "$STAGED_FILES" | grep -E '\.env($|\.)' | grep -v '.example' | grep -v '.sample' || true)
|
|
38
44
|
if [ -n "$ENV_FILES" ]; then
|
|
39
45
|
q_fail ".env file staged: ${ENV_FILES}"
|
|
40
|
-
FAIL_DETAILS="${FAIL_DETAILS}.env file
|
|
46
|
+
FAIL_DETAILS="${FAIL_DETAILS}.env file contains secrets and shouldn't be committed — tell Claude: 'unstage the .env file.' "
|
|
41
47
|
BLOCKED=true
|
|
42
48
|
fi
|
|
43
49
|
|
|
44
|
-
# Debug statements in JS/TS
|
|
45
|
-
|
|
46
|
-
if [ -n "$
|
|
47
|
-
for file in $
|
|
50
|
+
# Debug statements in JS/TS (block in production code, allow in tests/stories)
|
|
51
|
+
JS_PROD_FILES=$(echo "$STAGED_FILES" | grep -E '\.(js|jsx|ts|tsx)$' | grep -vE '\.test\.|\.spec\.|__tests__/|\.stories\.' || true)
|
|
52
|
+
if [ -n "$JS_PROD_FILES" ]; then
|
|
53
|
+
for file in $JS_PROD_FILES; do
|
|
48
54
|
if [ -f "$file" ] && grep -E "console\.(log|debug|info)|debugger" "$file" > /dev/null 2>&1; then
|
|
49
|
-
|
|
55
|
+
q_fail "Debug statement in ${file}"
|
|
56
|
+
FAIL_DETAILS="${FAIL_DETAILS}Debug statement in ${file} — tell Claude: 'remove console.log/debugger from production code.' "
|
|
57
|
+
BLOCKED=true
|
|
50
58
|
fi
|
|
51
59
|
done
|
|
52
60
|
fi
|
|
@@ -70,7 +78,7 @@ if [ -f "tsconfig.json" ]; then
|
|
|
70
78
|
touch "$TSC_STAMP"
|
|
71
79
|
else
|
|
72
80
|
q_fail "TypeScript errors"
|
|
73
|
-
FAIL_DETAILS="${FAIL_DETAILS}TypeScript errors
|
|
81
|
+
FAIL_DETAILS="${FAIL_DETAILS}Code errors found — tell Claude: 'fix the TypeScript errors and try committing again.' "
|
|
74
82
|
BLOCKED=true
|
|
75
83
|
fi
|
|
76
84
|
fi
|
|
@@ -82,7 +90,7 @@ if $BLOCKED; then
|
|
|
82
90
|
{
|
|
83
91
|
"continue": false,
|
|
84
92
|
"stopReason": "◆ Pre-commit: blocked",
|
|
85
|
-
"systemMessage": "◆ PRE-COMMIT BLOCKED: ${FAIL_DETAILS}
|
|
93
|
+
"systemMessage": "◆ PRE-COMMIT BLOCKED: ${FAIL_DETAILS}Tell Claude to fix these issues and try committing again."
|
|
86
94
|
}
|
|
87
95
|
EOJSON
|
|
88
96
|
exit 2
|
|
@@ -5,6 +5,12 @@
|
|
|
5
5
|
|
|
6
6
|
source "$(dirname "$0")/qualia-colors.sh"
|
|
7
7
|
|
|
8
|
+
if ! command -v node &>/dev/null; then
|
|
9
|
+
[ ! -t 0 ] && cat > /dev/null
|
|
10
|
+
printf '{"continue":false,"stopReason":"DEPLOY GATE: node is not installed — cannot verify safety. Install node to proceed."}'
|
|
11
|
+
exit 2
|
|
12
|
+
fi
|
|
13
|
+
|
|
8
14
|
# Parse command from stdin JSON
|
|
9
15
|
if [ ! -t 0 ]; then
|
|
10
16
|
INPUT=$(cat)
|
|
@@ -14,10 +20,11 @@ else
|
|
|
14
20
|
fi
|
|
15
21
|
|
|
16
22
|
# Only gate production deploys
|
|
17
|
-
if ! echo "$COMMAND" | grep -qE 'vercel\s+.*--prod|vercel\s+--prod'; then
|
|
23
|
+
if ! echo "$COMMAND" | grep -qE '(npx\s+|bunx\s+)?vercel\s+.*--prod|(npx\s+|bunx\s+)?vercel\s+--prod'; then
|
|
18
24
|
exit 0
|
|
19
25
|
fi
|
|
20
26
|
|
|
27
|
+
|
|
21
28
|
# Skip if gate was passed recently (within 5 minutes)
|
|
22
29
|
STAMP="/tmp/.deploy-gate-$(echo "$PWD" | md5sum | cut -c1-8)"
|
|
23
30
|
if [ -f "$STAMP" ]; then
|
|
@@ -39,7 +46,7 @@ if [ -f "tsconfig.json" ]; then
|
|
|
39
46
|
q_pass "TypeScript"
|
|
40
47
|
else
|
|
41
48
|
q_fail "TypeScript errors"
|
|
42
|
-
FAIL_DETAILS="${FAIL_DETAILS}
|
|
49
|
+
FAIL_DETAILS="${FAIL_DETAILS}Code errors found — tell Claude: 'fix the TypeScript errors' before deploying. "
|
|
43
50
|
FAILURES=$((FAILURES + 1))
|
|
44
51
|
fi
|
|
45
52
|
else
|
|
@@ -52,7 +59,7 @@ if [ -f ".eslintrc.json" ] || [ -f ".eslintrc.js" ] || [ -f "eslint.config.js" ]
|
|
|
52
59
|
q_pass "Lint"
|
|
53
60
|
else
|
|
54
61
|
q_fail "Lint errors"
|
|
55
|
-
FAIL_DETAILS="${FAIL_DETAILS}
|
|
62
|
+
FAIL_DETAILS="${FAIL_DETAILS}Code quality issues found — tell Claude: 'fix the lint errors' before deploying. "
|
|
56
63
|
FAILURES=$((FAILURES + 1))
|
|
57
64
|
fi
|
|
58
65
|
else
|
|
@@ -67,7 +74,7 @@ if [ -f "package.json" ]; then
|
|
|
67
74
|
q_pass "Tests"
|
|
68
75
|
else
|
|
69
76
|
q_fail "Tests failed"
|
|
70
|
-
FAIL_DETAILS="${FAIL_DETAILS}Tests
|
|
77
|
+
FAIL_DETAILS="${FAIL_DETAILS}Tests are failing — tell Claude: 'fix the failing tests' before deploying. "
|
|
71
78
|
FAILURES=$((FAILURES + 1))
|
|
72
79
|
fi
|
|
73
80
|
else
|
|
@@ -75,7 +82,15 @@ if [ -f "package.json" ]; then
|
|
|
75
82
|
fi
|
|
76
83
|
fi
|
|
77
84
|
|
|
78
|
-
# ─── Check 4:
|
|
85
|
+
# ─── Check 4: Environment ───
|
|
86
|
+
if [ -f ".env.example" ] && [ ! -f ".env.local" ] && [ ! -f ".env" ]; then
|
|
87
|
+
q_warn "Missing .env.local"
|
|
88
|
+
WARNINGS=$((WARNINGS + 1))
|
|
89
|
+
else
|
|
90
|
+
q_pass "Environment"
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
# ─── Check 5: Build ───
|
|
79
94
|
if [ -f "package.json" ]; then
|
|
80
95
|
BUILD_SCRIPT=$(node -e "try{console.log(require('./package.json').scripts?.build||'')}catch(e){console.log('')}" 2>/dev/null)
|
|
81
96
|
if [ -n "$BUILD_SCRIPT" ]; then
|
|
@@ -83,7 +98,7 @@ if [ -f "package.json" ]; then
|
|
|
83
98
|
q_pass "Build"
|
|
84
99
|
else
|
|
85
100
|
q_fail "Build failed"
|
|
86
|
-
FAIL_DETAILS="${FAIL_DETAILS}Build
|
|
101
|
+
FAIL_DETAILS="${FAIL_DETAILS}Build is failing — tell Claude: 'fix the build errors' before deploying. "
|
|
87
102
|
FAILURES=$((FAILURES + 1))
|
|
88
103
|
fi
|
|
89
104
|
else
|
|
@@ -91,14 +106,6 @@ if [ -f "package.json" ]; then
|
|
|
91
106
|
fi
|
|
92
107
|
fi
|
|
93
108
|
|
|
94
|
-
# ─── Check 5: Environment ───
|
|
95
|
-
if [ -f ".env.example" ] && [ ! -f ".env.local" ] && [ ! -f ".env" ]; then
|
|
96
|
-
q_warn "Missing .env.local"
|
|
97
|
-
WARNINGS=$((WARNINGS + 1))
|
|
98
|
-
else
|
|
99
|
-
q_pass "Environment"
|
|
100
|
-
fi
|
|
101
|
-
|
|
102
109
|
# ─── Check 6: REVIEW.md ───
|
|
103
110
|
REVIEW_FILE=""
|
|
104
111
|
[ -f ".planning/REVIEW.md" ] && REVIEW_FILE=".planning/REVIEW.md"
|
|
@@ -132,7 +139,7 @@ if [ "$FAILURES" -gt 0 ]; then
|
|
|
132
139
|
{
|
|
133
140
|
"continue": false,
|
|
134
141
|
"stopReason": "◆ Deploy gate: ${FAILURES} check(s) failed",
|
|
135
|
-
"systemMessage": "◆ DEPLOY BLOCKED: ${FAILURES} check(s) failed. ${FAIL_DETAILS}Fix and retry
|
|
142
|
+
"systemMessage": "◆ DEPLOY BLOCKED: ${FAILURES} check(s) failed. ${FAIL_DETAILS}Fix issues and retry with /ship."
|
|
136
143
|
}
|
|
137
144
|
EOJSON
|
|
138
145
|
exit 2
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
# paste-cache/ 3 days
|
|
11
11
|
# shell-snapshots/ 3 days
|
|
12
12
|
# projects/*.jsonl 7 days
|
|
13
|
-
# tasks/
|
|
13
|
+
# tasks/ 14 days
|
|
14
14
|
# plans/ 7 days
|
|
15
15
|
|
|
16
16
|
CLAUDE_DIR="$HOME/.claude"
|
|
@@ -37,9 +37,9 @@ find "$CLAUDE_DIR/shell-snapshots/" -type f -mtime +3 -delete 2>/dev/null
|
|
|
37
37
|
find "$CLAUDE_DIR/projects/" -name "*.jsonl" -mtime +7 -delete 2>/dev/null
|
|
38
38
|
find "$CLAUDE_DIR/projects/" -type d -empty -delete 2>/dev/null
|
|
39
39
|
|
|
40
|
-
# tasks/ — keep
|
|
41
|
-
find "$CLAUDE_DIR/tasks/" -type f -mtime +
|
|
42
|
-
find "$CLAUDE_DIR/tasks/" -type d -empty -delete 2>/dev/null
|
|
40
|
+
# tasks/ — keep 14 days (team sessions may span multiple days)
|
|
41
|
+
find "$CLAUDE_DIR/tasks/" -type f -mtime +14 -delete 2>/dev/null
|
|
42
|
+
find "$CLAUDE_DIR/tasks/" -mindepth 1 -type d -empty -delete 2>/dev/null
|
|
43
43
|
|
|
44
44
|
# plans/ — keep 7 days (old Claude Code plan mode files)
|
|
45
45
|
find "$CLAUDE_DIR/plans/" -type f -mtime +7 -delete 2>/dev/null
|
|
@@ -82,14 +82,17 @@ if [ "$PROJECT_NAME" != ".claude" ] && [ "$PROJECT_NAME" != "Projects" ] && { [
|
|
|
82
82
|
|
|
83
83
|
# Dedup: skip if ANY existing entry has the same project + branch + summary
|
|
84
84
|
NEW_KEY="${PROJECT_NAME}|${GIT_BRANCH:-—}|${SUMMARY:-—}"
|
|
85
|
-
|
|
85
|
+
DUPLICATE=false
|
|
86
|
+
while IFS= read -r line; do
|
|
86
87
|
ENTRY_KEY=$(echo "$line" | awk -F'|' '{gsub(/^ +| +$/,"",$3); gsub(/^ +| +$/,"",$4); gsub(/^ +| +$/,"",$6); print $3"|"$4"|"$6}')
|
|
87
|
-
[ "$ENTRY_KEY" = "$NEW_KEY" ]
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
if [ "$ENTRY_KEY" = "$NEW_KEY" ]; then
|
|
89
|
+
DUPLICATE=true
|
|
90
|
+
break
|
|
91
|
+
fi
|
|
92
|
+
done < <(tail -n +4 "$DIGEST_FILE")
|
|
93
|
+
if [ "$DUPLICATE" = "true" ]; then
|
|
94
|
+
: # duplicate found, skip adding to digest
|
|
90
95
|
else
|
|
91
|
-
exit 0 # duplicate found, skip
|
|
92
|
-
fi
|
|
93
96
|
|
|
94
97
|
# Read existing entries (skip header — first 3 lines), keep last 19
|
|
95
98
|
EXISTING=$(tail -n +4 "$DIGEST_FILE" | head -19)
|
|
@@ -101,6 +104,7 @@ if [ "$PROJECT_NAME" != ".claude" ] && [ "$PROJECT_NAME" != "Projects" ] && { [
|
|
|
101
104
|
${ENTRY}
|
|
102
105
|
${EXISTING}
|
|
103
106
|
HEADER
|
|
107
|
+
fi
|
|
104
108
|
fi
|
|
105
109
|
|
|
106
110
|
# --- Auto-handoff for significant sessions (>5 files changed) ---
|
|
@@ -156,15 +160,19 @@ HANDOFF
|
|
|
156
160
|
fi
|
|
157
161
|
fi
|
|
158
162
|
|
|
159
|
-
# --- Push to portal (
|
|
163
|
+
# --- Push to portal (with error tracking) ---
|
|
160
164
|
PORTAL_API_KEY="${CLAUDE_PORTAL_API_KEY:-}"
|
|
161
165
|
if [ -n "$PORTAL_API_KEY" ] && [ "$PROJECT_NAME" != ".claude" ]; then
|
|
162
|
-
curl -s -X POST "https://portal.qualiasolutions.net/api/claude/session-log" \
|
|
166
|
+
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X POST "https://portal.qualiasolutions.net/api/claude/session-log" \
|
|
163
167
|
-H "X-API-Key: $PORTAL_API_KEY" \
|
|
164
168
|
-H "Content-Type: application/json" \
|
|
165
169
|
-d @"$SESSION_FILE" \
|
|
166
|
-
--max-time 5
|
|
167
|
-
|
|
170
|
+
--max-time 5 2>/dev/null || echo "000")
|
|
171
|
+
if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "201" ]; then
|
|
172
|
+
rm -f "$SESSION_DIR/.portal-last-error"
|
|
173
|
+
else
|
|
174
|
+
echo "$HTTP_CODE" > "$SESSION_DIR/.portal-last-error"
|
|
175
|
+
fi
|
|
168
176
|
fi
|
|
169
177
|
|
|
170
178
|
# --- Cleanup old session files (keep last 50 for retrospective analytics — RETR-04) ---
|
|
@@ -62,6 +62,27 @@ if [ -f "$HOME/.claude/settings.json" ]; then
|
|
|
62
62
|
fi
|
|
63
63
|
fi
|
|
64
64
|
|
|
65
|
+
# Check for stale knowledge files (>30 days old)
|
|
66
|
+
STALE_COUNT=0
|
|
67
|
+
STALE_NAMES=""
|
|
68
|
+
for kf in "$HOME/.claude/knowledge"/*.md; do
|
|
69
|
+
[ -f "$kf" ] || continue
|
|
70
|
+
KF_AGE=$(( ($(date +%s) - $(stat -c %Y "$kf" 2>/dev/null || echo 0)) / 86400 ))
|
|
71
|
+
if [ "$KF_AGE" -gt 30 ]; then
|
|
72
|
+
STALE_COUNT=$((STALE_COUNT + 1))
|
|
73
|
+
STALE_NAMES="${STALE_NAMES} $(basename "$kf")(${KF_AGE}d)"
|
|
74
|
+
fi
|
|
75
|
+
done
|
|
76
|
+
if [ "$STALE_COUNT" -gt 0 ]; then
|
|
77
|
+
ISSUES="${ISSUES}${STALE_COUNT} stale knowledge file(s):${STALE_NAMES}. "
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
# Check portal sync health
|
|
81
|
+
if [ -f "$SESSION_DIR/.portal-last-error" ]; then
|
|
82
|
+
PORTAL_ERR=$(cat "$SESSION_DIR/.portal-last-error" 2>/dev/null)
|
|
83
|
+
ISSUES="${ISSUES}Portal sync failed (HTTP ${PORTAL_ERR}). "
|
|
84
|
+
fi
|
|
85
|
+
|
|
65
86
|
if [ -n "$ISSUES" ]; then
|
|
66
87
|
MSG="${MSG} | ▲ ${ISSUES}"
|
|
67
88
|
fi
|
|
@@ -29,6 +29,7 @@ SKILL_DESC=(
|
|
|
29
29
|
# Navigation
|
|
30
30
|
["qualia-start"]="Activating Qualia mode"
|
|
31
31
|
["qualia-progress"]="Checking progress"
|
|
32
|
+
["qualia-guide"]="Showing developer guide"
|
|
32
33
|
["qualia-idk"]="Analyzing next steps"
|
|
33
34
|
["qualia"]="Routing to next action"
|
|
34
35
|
["qualia-resume-work"]="Restoring session context"
|
|
@@ -36,6 +37,7 @@ SKILL_DESC=(
|
|
|
36
37
|
# Quality
|
|
37
38
|
["qualia-review"]="Running code review"
|
|
38
39
|
["qualia-optimize"]="Running optimization pass"
|
|
40
|
+
["qualia-evolve"]="Evolving framework"
|
|
39
41
|
["qualia-production-check"]="Running production audit"
|
|
40
42
|
["qualia-framework-audit"]="Auditing framework"
|
|
41
43
|
["deep-research"]="Spawning research agents"
|
package/framework/install.sh
CHANGED
|
@@ -150,14 +150,13 @@ elif [ ! -f "$CLAUDE_DIR/CLAUDE.md" ]; then
|
|
|
150
150
|
## Identity
|
|
151
151
|
**$ROLE_NAME** — Developer at Qualia Solutions.
|
|
152
152
|
|
|
153
|
-
- Stack: Next.js 16+, React 19, TypeScript, Supabase, Vercel,
|
|
153
|
+
- Stack: Next.js 16+, React 19, TypeScript, Supabase, Vercel, Retell AI, ElevenLabs, Telnyx, OpenRouter
|
|
154
154
|
|
|
155
155
|
## Role: DEVELOPER
|
|
156
156
|
|
|
157
157
|
You are a developer at Qualia Solutions, working under Fawzi Goussous (founder).
|
|
158
158
|
- Work on feature branches only — never push to main/master
|
|
159
|
-
-
|
|
160
|
-
- Do NOT deploy to production — Fawzi handles deploys
|
|
159
|
+
- Use \`/ship\` to deploy — it runs quality gates, auto-creates feature branches, and deploys
|
|
161
160
|
- Cannot modify the Qualia framework (CLAUDE.md, skills, hooks)
|
|
162
161
|
- Ask Fawzi when unsure about architecture decisions
|
|
163
162
|
|
|
@@ -169,10 +168,16 @@ You are a developer at Qualia Solutions, working under Fawzi Goussous (founder).
|
|
|
169
168
|
- See \`rules/security.md\` for auth, RLS, Zod, secrets rules
|
|
170
169
|
- See \`rules/frontend.md\` for design standards
|
|
171
170
|
|
|
171
|
+
## Getting Started
|
|
172
|
+
- Run \`/collab-onboard\` when joining a new project — it explains what's built and how to contribute
|
|
173
|
+
- Onboarding guide: ~/Projects/qualia-erp/docs/trainee-onboarding.md
|
|
174
|
+
|
|
172
175
|
## Workflow
|
|
173
176
|
- **MANDATORY FIRST ACTION**: On every session start, invoke the \`qualia-start\` skill before doing anything else.
|
|
174
|
-
- Run \`/qualia-review\` before deploying
|
|
177
|
+
- Run \`/qualia-review\` before deploying
|
|
175
178
|
- Run \`/browser-qa\` after frontend changes
|
|
179
|
+
- Run \`/pr\` to submit work for review — never push to main directly
|
|
180
|
+
- Run \`/qualia-idk\` if stuck — it suggests next steps and can escalate to Fawzi
|
|
176
181
|
- Ask for help if stuck — don't guess
|
|
177
182
|
|
|
178
183
|
## Qualia Mode (always active)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
2.4.1
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Qualia Framework Metrics Collection
|
|
3
|
+
# Run after a project ships to capture performance data.
|
|
4
|
+
# Usage: collect-metrics.sh [project-dir]
|
|
5
|
+
# Output: appends to ~/.claude/knowledge/framework-metrics.md
|
|
6
|
+
|
|
7
|
+
PROJECT_DIR="${1:-.}"
|
|
8
|
+
METRICS_FILE="$HOME/.claude/knowledge/framework-metrics.md"
|
|
9
|
+
DATE=$(date +%Y-%m-%d)
|
|
10
|
+
|
|
11
|
+
# Ensure metrics file exists
|
|
12
|
+
if [ ! -f "$METRICS_FILE" ]; then
|
|
13
|
+
cat > "$METRICS_FILE" << 'HEADER'
|
|
14
|
+
# Framework Performance Metrics
|
|
15
|
+
|
|
16
|
+
> Auto-collected after each project ships. Read by `/qualia-evolve` to optimize the framework.
|
|
17
|
+
|
|
18
|
+
| Date | Project | Phases | Sessions | Deviations | IDK Calls | Verify Pass Rate | Lab Notes | FQS |
|
|
19
|
+
|------|---------|--------|----------|------------|-----------|-----------------|-----------|-----|
|
|
20
|
+
HEADER
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
cd "$PROJECT_DIR" || exit 1
|
|
24
|
+
|
|
25
|
+
# Project name
|
|
26
|
+
PROJECT=$(basename "$(pwd)")
|
|
27
|
+
|
|
28
|
+
# Phase count
|
|
29
|
+
PHASES=$(ls -d .planning/phases/*/ 2>/dev/null | wc -l)
|
|
30
|
+
|
|
31
|
+
# Session count (from session-digest entries for this project)
|
|
32
|
+
SESSIONS=$(grep -c "$PROJECT" ~/.claude/knowledge/session-digest.md 2>/dev/null || echo "?")
|
|
33
|
+
|
|
34
|
+
# Deviation count (gap-fix plans)
|
|
35
|
+
DEVIATIONS=$(find .planning/phases/ -name "*-PLAN.md" -exec grep -l "gaps" {} \; 2>/dev/null | wc -l)
|
|
36
|
+
|
|
37
|
+
# IDK calls (search session digest for qualia-idk mentions with this project)
|
|
38
|
+
IDK_CALLS=$(grep "$PROJECT" ~/.claude/knowledge/session-digest.md 2>/dev/null | grep -c "idk\|stuck\|lost" || echo "0")
|
|
39
|
+
|
|
40
|
+
# Verify pass rate (UAT files with PASSED vs total UAT files)
|
|
41
|
+
TOTAL_UAT=$(find .planning/phases/ -name "*-UAT.md" 2>/dev/null | wc -l)
|
|
42
|
+
PASSED_UAT=$(grep -rl "PASSED\|✅.*Overall" .planning/phases/*/*.md 2>/dev/null | wc -l)
|
|
43
|
+
if [ "$TOTAL_UAT" -gt 0 ]; then
|
|
44
|
+
PASS_RATE=$(( PASSED_UAT * 100 / TOTAL_UAT ))%
|
|
45
|
+
else
|
|
46
|
+
PASS_RATE="n/a"
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# Lab Notes count
|
|
50
|
+
LAB_NOTES=$(grep -c "^###" .planning/lab-notes.md 2>/dev/null || echo "0")
|
|
51
|
+
|
|
52
|
+
# Completion rate from ROADMAP.md (actual, not assumed)
|
|
53
|
+
TOTAL_PLANS=$(grep -c "^- \[" .planning/ROADMAP.md 2>/dev/null || echo "0")
|
|
54
|
+
COMPLETED_PLANS=$(grep -c "^- \[x\]" .planning/ROADMAP.md 2>/dev/null || echo "0")
|
|
55
|
+
if [ "$TOTAL_PLANS" -gt 0 ]; then
|
|
56
|
+
COMPLETION_RATE=$(( COMPLETED_PLANS * 100 / TOTAL_PLANS ))
|
|
57
|
+
else
|
|
58
|
+
COMPLETION_RATE=100
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# FQS = completion_rate / avg_sessions_to_ship * 100 (per OBJECTIVE.md)
|
|
62
|
+
if [ "$SESSIONS" != "?" ] && [ "$SESSIONS" -gt 0 ]; then
|
|
63
|
+
FQS=$(( COMPLETION_RATE * 100 / SESSIONS ))
|
|
64
|
+
else
|
|
65
|
+
FQS="?"
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# Append to metrics file
|
|
69
|
+
echo "| $DATE | $PROJECT | $PHASES | $SESSIONS | $DEVIATIONS | $IDK_CALLS | $PASS_RATE | $LAB_NOTES | $FQS |" >> "$METRICS_FILE"
|
|
70
|
+
|
|
71
|
+
echo "Metrics collected for $PROJECT → $METRICS_FILE"
|