qualia-framework 3.2.0 → 3.3.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/CLAUDE.md +3 -4
- package/README.md +59 -23
- package/agents/plan-checker.md +158 -0
- package/agents/planner.md +52 -0
- package/agents/research-synthesizer.md +86 -0
- package/agents/researcher.md +119 -0
- package/agents/roadmapper.md +157 -0
- package/agents/verifier.md +180 -32
- package/bin/cli.js +403 -9
- package/bin/install.js +219 -70
- package/bin/qualia-ui.js +11 -11
- package/bin/state.js +200 -6
- package/bin/statusline.js +4 -4
- package/docs/erp-contract.md +161 -0
- package/hooks/branch-guard.js +23 -2
- package/hooks/migration-guard.js +23 -0
- package/hooks/pre-compact.js +20 -0
- package/hooks/pre-deploy-gate.js +39 -0
- package/hooks/pre-push.js +20 -0
- package/hooks/session-start.js +16 -43
- package/package.json +6 -4
- package/references/questioning.md +123 -0
- package/rules/infrastructure.md +87 -0
- package/skills/qualia/SKILL.md +1 -0
- package/skills/qualia-build/SKILL.md +18 -0
- package/skills/qualia-design/SKILL.md +14 -8
- package/skills/qualia-discuss/SKILL.md +115 -0
- package/skills/qualia-help/SKILL.md +60 -0
- package/skills/qualia-learn/SKILL.md +27 -4
- package/skills/qualia-map/SKILL.md +145 -0
- package/skills/qualia-milestone/SKILL.md +148 -0
- package/skills/qualia-new/SKILL.md +374 -229
- package/skills/qualia-plan/SKILL.md +135 -30
- package/skills/qualia-polish/SKILL.md +167 -117
- package/skills/qualia-report/SKILL.md +17 -8
- package/skills/qualia-research/SKILL.md +124 -0
- package/skills/qualia-review/SKILL.md +126 -41
- package/skills/qualia-test/SKILL.md +134 -0
- package/skills/qualia-verify/SKILL.md +1 -1
- package/templates/DESIGN.md +440 -102
- package/templates/help.html +476 -0
- package/templates/phase-context.md +48 -0
- package/templates/plan.md +14 -0
- package/templates/projects/ai-agent.md +55 -0
- package/templates/projects/mobile-app.md +56 -0
- package/templates/projects/voice-agent.md +55 -0
- package/templates/projects/website.md +58 -0
- package/templates/requirements.md +69 -0
- package/templates/research-project/ARCHITECTURE.md +70 -0
- package/templates/research-project/FEATURES.md +60 -0
- package/templates/research-project/PITFALLS.md +73 -0
- package/templates/research-project/STACK.md +51 -0
- package/templates/research-project/SUMMARY.md +86 -0
- package/templates/roadmap.md +71 -0
- package/tests/bin.test.sh +20 -6
- package/tests/hooks.test.sh +76 -7
- package/tests/runner.js +1915 -0
- package/tests/state.test.sh +189 -11
package/tests/hooks.test.sh
CHANGED
|
@@ -34,6 +34,29 @@ for f in "$HOOKS_DIR"/*.js; do
|
|
|
34
34
|
fi
|
|
35
35
|
done
|
|
36
36
|
|
|
37
|
+
# --- block-env-edit.js ---
|
|
38
|
+
echo ""
|
|
39
|
+
echo "block-env-edit:"
|
|
40
|
+
|
|
41
|
+
echo '{"tool_input":{"file_path":".env.local"}}' | $NODE "$HOOKS_DIR/block-env-edit.js" > /dev/null 2>&1
|
|
42
|
+
assert_exit "blocks .env.local" 2 $?
|
|
43
|
+
|
|
44
|
+
echo '{"tool_input":{"file_path":".env.production"}}' | $NODE "$HOOKS_DIR/block-env-edit.js" > /dev/null 2>&1
|
|
45
|
+
assert_exit "blocks .env.production" 2 $?
|
|
46
|
+
|
|
47
|
+
echo '{"tool_input":{"file_path":".env"}}' | $NODE "$HOOKS_DIR/block-env-edit.js" > /dev/null 2>&1
|
|
48
|
+
assert_exit "blocks .env" 2 $?
|
|
49
|
+
|
|
50
|
+
# Windows-style path with backslashes (normalized by the hook)
|
|
51
|
+
echo '{"tool_input":{"file_path":"C:\\project\\.env.local"}}' | $NODE "$HOOKS_DIR/block-env-edit.js" > /dev/null 2>&1
|
|
52
|
+
assert_exit "blocks windows .env.local" 2 $?
|
|
53
|
+
|
|
54
|
+
echo '{"tool_input":{"file_path":"src/app.tsx"}}' | $NODE "$HOOKS_DIR/block-env-edit.js" > /dev/null 2>&1
|
|
55
|
+
assert_exit "allows src/app.tsx" 0 $?
|
|
56
|
+
|
|
57
|
+
echo '{"tool_input":{"file_path":"components/Footer.tsx"}}' | $NODE "$HOOKS_DIR/block-env-edit.js" > /dev/null 2>&1
|
|
58
|
+
assert_exit "allows components/Footer.tsx" 0 $?
|
|
59
|
+
|
|
37
60
|
# --- migration-guard.js ---
|
|
38
61
|
echo ""
|
|
39
62
|
echo "migration-guard:"
|
|
@@ -84,11 +107,11 @@ TMP=$(setup_guard_repo main OWNER)
|
|
|
84
107
|
assert_exit "OWNER on main → allowed" 0 $?
|
|
85
108
|
rm -rf "$TMP"
|
|
86
109
|
|
|
87
|
-
# EMPLOYEE on main → blocked (exit
|
|
110
|
+
# EMPLOYEE on main → blocked (exit 2)
|
|
88
111
|
TMP=$(setup_guard_repo main EMPLOYEE)
|
|
89
112
|
OUT=$(cd "$TMP/proj" && HOME="$TMP" $NODE "$HOOKS_DIR/branch-guard.js" 2>&1)
|
|
90
113
|
RC=$?
|
|
91
|
-
if [ "$RC" -eq
|
|
114
|
+
if [ "$RC" -eq 2 ] && echo "$OUT" | grep -q "BLOCKED" && echo "$OUT" | grep -q "main"; then
|
|
92
115
|
echo " ✓ EMPLOYEE on main → blocked (BLOCKED in stdout)"
|
|
93
116
|
PASS=$((PASS + 1))
|
|
94
117
|
else
|
|
@@ -100,7 +123,7 @@ rm -rf "$TMP"
|
|
|
100
123
|
# EMPLOYEE on master → blocked
|
|
101
124
|
TMP=$(setup_guard_repo master EMPLOYEE)
|
|
102
125
|
(cd "$TMP/proj" && HOME="$TMP" $NODE "$HOOKS_DIR/branch-guard.js" >/dev/null 2>&1)
|
|
103
|
-
assert_exit "EMPLOYEE on master → blocked"
|
|
126
|
+
assert_exit "EMPLOYEE on master → blocked" 2 $?
|
|
104
127
|
rm -rf "$TMP"
|
|
105
128
|
|
|
106
129
|
# EMPLOYEE on feature branch → allowed
|
|
@@ -115,13 +138,13 @@ TMP=$(setup_guard_repo feature/xyz OWNER)
|
|
|
115
138
|
assert_exit "OWNER on feature/xyz → allowed" 0 $?
|
|
116
139
|
rm -rf "$TMP"
|
|
117
140
|
|
|
118
|
-
# Missing config → fails closed (block, exit
|
|
141
|
+
# Missing config → fails closed (block, exit 2)
|
|
119
142
|
TMP=$(mktemp -d)
|
|
120
143
|
mkdir -p "$TMP/proj"
|
|
121
144
|
(cd "$TMP/proj" && git init -q && git checkout -b feature/x -q 2>/dev/null)
|
|
122
145
|
# NO .claude/.qualia-config.json
|
|
123
146
|
(cd "$TMP/proj" && HOME="$TMP" $NODE "$HOOKS_DIR/branch-guard.js" >/dev/null 2>&1)
|
|
124
|
-
assert_exit "missing config → blocked (fails closed)"
|
|
147
|
+
assert_exit "missing config → blocked (fails closed)" 2 $?
|
|
125
148
|
rm -rf "$TMP"
|
|
126
149
|
|
|
127
150
|
# Malformed config JSON → fails closed
|
|
@@ -130,7 +153,7 @@ mkdir -p "$TMP/proj" "$TMP/.claude"
|
|
|
130
153
|
(cd "$TMP/proj" && git init -q && git checkout -b feature/x -q 2>/dev/null)
|
|
131
154
|
echo 'not json{' > "$TMP/.claude/.qualia-config.json"
|
|
132
155
|
(cd "$TMP/proj" && HOME="$TMP" $NODE "$HOOKS_DIR/branch-guard.js" >/dev/null 2>&1)
|
|
133
|
-
assert_exit "malformed config JSON → blocked"
|
|
156
|
+
assert_exit "malformed config JSON → blocked" 2 $?
|
|
134
157
|
rm -rf "$TMP"
|
|
135
158
|
|
|
136
159
|
# Empty role field → fails closed
|
|
@@ -139,7 +162,7 @@ mkdir -p "$TMP/proj" "$TMP/.claude"
|
|
|
139
162
|
(cd "$TMP/proj" && git init -q && git checkout -b feature/x -q 2>/dev/null)
|
|
140
163
|
echo '{"role":""}' > "$TMP/.claude/.qualia-config.json"
|
|
141
164
|
(cd "$TMP/proj" && HOME="$TMP" $NODE "$HOOKS_DIR/branch-guard.js" >/dev/null 2>&1)
|
|
142
|
-
assert_exit "empty role field → blocked"
|
|
165
|
+
assert_exit "empty role field → blocked" 2 $?
|
|
143
166
|
rm -rf "$TMP"
|
|
144
167
|
|
|
145
168
|
# --- pre-push.js ---
|
|
@@ -263,6 +286,52 @@ else
|
|
|
263
286
|
fi
|
|
264
287
|
rm -rf "$TMP"
|
|
265
288
|
|
|
289
|
+
# --- pre-deploy-gate: Server Component / route handler exemptions ---
|
|
290
|
+
|
|
291
|
+
# route.ts with service_role → exempt (always server-side)
|
|
292
|
+
TMP=$(mktemp -d)
|
|
293
|
+
mkdir -p "$TMP/app/api/auth"
|
|
294
|
+
echo 'const key = process.env.SUPABASE_SERVICE_ROLE_KEY; export async function POST() {}' > "$TMP/app/api/auth/route.ts"
|
|
295
|
+
OUT=$( (cd "$TMP" && $NODE "$HOOKS_DIR/pre-deploy-gate.js") 2>&1 )
|
|
296
|
+
RC=$?
|
|
297
|
+
assert_exit "route.ts with service_role → exempt (exit 0)" 0 $RC
|
|
298
|
+
rm -rf "$TMP"
|
|
299
|
+
|
|
300
|
+
# middleware.ts with service_role → exempt (always server-side)
|
|
301
|
+
TMP=$(mktemp -d)
|
|
302
|
+
echo 'import { service_role } from "./config"; export function middleware() {}' > "$TMP/middleware.ts"
|
|
303
|
+
OUT=$( (cd "$TMP" && $NODE "$HOOKS_DIR/pre-deploy-gate.js") 2>&1 )
|
|
304
|
+
RC=$?
|
|
305
|
+
assert_exit "middleware.ts with service_role → exempt (exit 0)" 0 $RC
|
|
306
|
+
rm -rf "$TMP"
|
|
307
|
+
|
|
308
|
+
# File in app/api/ with service_role → exempt
|
|
309
|
+
TMP=$(mktemp -d)
|
|
310
|
+
mkdir -p "$TMP/app/api/webhook"
|
|
311
|
+
echo 'const sr = "service_role"; export async function GET() { return new Response(sr); }' > "$TMP/app/api/webhook/route.js"
|
|
312
|
+
OUT=$( (cd "$TMP" && $NODE "$HOOKS_DIR/pre-deploy-gate.js") 2>&1 )
|
|
313
|
+
RC=$?
|
|
314
|
+
assert_exit "app/api/ file with service_role → exempt (exit 0)" 0 $RC
|
|
315
|
+
rm -rf "$TMP"
|
|
316
|
+
|
|
317
|
+
# File with "use server" directive + service_role → exempt
|
|
318
|
+
TMP=$(mktemp -d)
|
|
319
|
+
mkdir -p "$TMP/app/admin"
|
|
320
|
+
printf '"use server"\nconst key = process.env.SUPABASE_SERVICE_ROLE_KEY;\nexport async function deleteUser() {}\n' > "$TMP/app/admin/actions.ts"
|
|
321
|
+
OUT=$( (cd "$TMP" && $NODE "$HOOKS_DIR/pre-deploy-gate.js") 2>&1 )
|
|
322
|
+
RC=$?
|
|
323
|
+
assert_exit "\"use server\" file with service_role → exempt (exit 0)" 0 $RC
|
|
324
|
+
rm -rf "$TMP"
|
|
325
|
+
|
|
326
|
+
# Regular app/page.tsx WITHOUT directive + service_role → still blocks
|
|
327
|
+
TMP=$(mktemp -d)
|
|
328
|
+
mkdir -p "$TMP/app/admin"
|
|
329
|
+
echo 'const key = "service_role"; export default function Page() { return <div>{key}</div>; }' > "$TMP/app/admin/page.tsx"
|
|
330
|
+
OUT=$( (cd "$TMP" && $NODE "$HOOKS_DIR/pre-deploy-gate.js") 2>&1 )
|
|
331
|
+
RC=$?
|
|
332
|
+
assert_exit "regular page.tsx with service_role → blocked (exit 1)" 1 $RC
|
|
333
|
+
rm -rf "$TMP"
|
|
334
|
+
|
|
266
335
|
# --- session-start.js — must exit 0 always ---
|
|
267
336
|
echo ""
|
|
268
337
|
echo "session-start:"
|