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.
Files changed (58) hide show
  1. package/CLAUDE.md +3 -4
  2. package/README.md +59 -23
  3. package/agents/plan-checker.md +158 -0
  4. package/agents/planner.md +52 -0
  5. package/agents/research-synthesizer.md +86 -0
  6. package/agents/researcher.md +119 -0
  7. package/agents/roadmapper.md +157 -0
  8. package/agents/verifier.md +180 -32
  9. package/bin/cli.js +403 -9
  10. package/bin/install.js +219 -70
  11. package/bin/qualia-ui.js +11 -11
  12. package/bin/state.js +200 -6
  13. package/bin/statusline.js +4 -4
  14. package/docs/erp-contract.md +161 -0
  15. package/hooks/branch-guard.js +23 -2
  16. package/hooks/migration-guard.js +23 -0
  17. package/hooks/pre-compact.js +20 -0
  18. package/hooks/pre-deploy-gate.js +39 -0
  19. package/hooks/pre-push.js +20 -0
  20. package/hooks/session-start.js +16 -43
  21. package/package.json +6 -4
  22. package/references/questioning.md +123 -0
  23. package/rules/infrastructure.md +87 -0
  24. package/skills/qualia/SKILL.md +1 -0
  25. package/skills/qualia-build/SKILL.md +18 -0
  26. package/skills/qualia-design/SKILL.md +14 -8
  27. package/skills/qualia-discuss/SKILL.md +115 -0
  28. package/skills/qualia-help/SKILL.md +60 -0
  29. package/skills/qualia-learn/SKILL.md +27 -4
  30. package/skills/qualia-map/SKILL.md +145 -0
  31. package/skills/qualia-milestone/SKILL.md +148 -0
  32. package/skills/qualia-new/SKILL.md +374 -229
  33. package/skills/qualia-plan/SKILL.md +135 -30
  34. package/skills/qualia-polish/SKILL.md +167 -117
  35. package/skills/qualia-report/SKILL.md +17 -8
  36. package/skills/qualia-research/SKILL.md +124 -0
  37. package/skills/qualia-review/SKILL.md +126 -41
  38. package/skills/qualia-test/SKILL.md +134 -0
  39. package/skills/qualia-verify/SKILL.md +1 -1
  40. package/templates/DESIGN.md +440 -102
  41. package/templates/help.html +476 -0
  42. package/templates/phase-context.md +48 -0
  43. package/templates/plan.md +14 -0
  44. package/templates/projects/ai-agent.md +55 -0
  45. package/templates/projects/mobile-app.md +56 -0
  46. package/templates/projects/voice-agent.md +55 -0
  47. package/templates/projects/website.md +58 -0
  48. package/templates/requirements.md +69 -0
  49. package/templates/research-project/ARCHITECTURE.md +70 -0
  50. package/templates/research-project/FEATURES.md +60 -0
  51. package/templates/research-project/PITFALLS.md +73 -0
  52. package/templates/research-project/STACK.md +51 -0
  53. package/templates/research-project/SUMMARY.md +86 -0
  54. package/templates/roadmap.md +71 -0
  55. package/tests/bin.test.sh +20 -6
  56. package/tests/hooks.test.sh +76 -7
  57. package/tests/runner.js +1915 -0
  58. package/tests/state.test.sh +189 -11
@@ -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 1)
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 1 ] && echo "$OUT" | grep -q "BLOCKED" && echo "$OUT" | grep -q "main"; then
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" 1 $?
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 1)
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)" 1 $?
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" 1 $?
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" 1 $?
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:"