qualia-framework 2.6.0 → 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/CLAUDE.md +63 -0
- package/README.md +108 -30
- package/agents/builder.md +110 -0
- package/agents/planner.md +186 -0
- package/agents/qa-browser.md +186 -0
- package/agents/verifier.md +369 -0
- package/bin/cli.js +691 -492
- package/bin/install.js +622 -0
- package/bin/qualia-ui.js +284 -0
- package/bin/state.js +824 -0
- package/bin/statusline.js +252 -0
- package/docs/erp-contract.md +161 -0
- package/guide.md +63 -0
- package/hooks/auto-update.js +117 -0
- package/hooks/block-env-edit.js +52 -0
- package/hooks/branch-guard.js +68 -0
- package/hooks/migration-guard.js +83 -0
- package/hooks/pre-compact.js +52 -0
- package/hooks/pre-deploy-gate.js +149 -0
- package/hooks/pre-push.js +53 -0
- package/hooks/session-start.js +126 -0
- package/package.json +30 -20
- package/rules/design-reference.md +179 -0
- package/rules/frontend.md +126 -0
- package/rules/infrastructure.md +87 -0
- package/skills/qualia/SKILL.md +88 -0
- package/skills/qualia-build/SKILL.md +115 -0
- package/skills/qualia-debug/SKILL.md +87 -0
- package/skills/qualia-design/SKILL.md +99 -0
- package/skills/qualia-handoff/SKILL.md +66 -0
- package/skills/qualia-help/SKILL.md +60 -0
- package/skills/qualia-idk/SKILL.md +8 -0
- package/skills/qualia-learn/SKILL.md +111 -0
- package/skills/qualia-new/SKILL.md +323 -0
- package/skills/qualia-pause/SKILL.md +63 -0
- package/skills/qualia-plan/SKILL.md +101 -0
- package/skills/qualia-polish/SKILL.md +207 -0
- package/skills/qualia-quick/SKILL.md +37 -0
- package/skills/qualia-report/SKILL.md +114 -0
- package/skills/qualia-resume/SKILL.md +49 -0
- package/skills/qualia-review/SKILL.md +161 -0
- package/skills/qualia-ship/SKILL.md +90 -0
- package/skills/qualia-skill-new/SKILL.md +167 -0
- package/skills/qualia-task/SKILL.md +91 -0
- package/skills/qualia-test/SKILL.md +134 -0
- package/skills/qualia-verify/SKILL.md +113 -0
- package/templates/DESIGN.md +475 -0
- package/templates/help.html +476 -0
- package/templates/plan.md +42 -0
- package/templates/project.md +22 -0
- package/templates/state.md +27 -0
- package/templates/tracking.json +20 -0
- package/tests/bin.test.sh +687 -0
- package/tests/hooks.test.sh +384 -0
- package/tests/runner.js +1956 -0
- package/tests/state.test.sh +713 -0
- package/tests/statusline.test.sh +243 -0
- package/bin/collect-metrics.sh +0 -62
- package/framework/.claudeignore +0 -51
- package/framework/CLAUDE.md +0 -51
- package/framework/MCP_SETUP.md +0 -229
- package/framework/agents/architecture-strategist.md +0 -53
- package/framework/agents/backend-agent.md +0 -150
- package/framework/agents/code-simplicity-reviewer.md +0 -86
- package/framework/agents/frontend-agent.md +0 -111
- package/framework/agents/kieran-typescript-reviewer.md +0 -96
- package/framework/agents/performance-oracle.md +0 -111
- package/framework/agents/qualia-codebase-mapper.md +0 -761
- package/framework/agents/qualia-debugger.md +0 -1204
- package/framework/agents/qualia-executor.md +0 -882
- package/framework/agents/qualia-integration-checker.md +0 -424
- package/framework/agents/qualia-phase-researcher.md +0 -457
- package/framework/agents/qualia-plan-checker.md +0 -700
- package/framework/agents/qualia-planner.md +0 -1245
- package/framework/agents/qualia-project-researcher.md +0 -603
- package/framework/agents/qualia-research-synthesizer.md +0 -200
- package/framework/agents/qualia-roadmapper.md +0 -606
- package/framework/agents/qualia-verifier.md +0 -686
- package/framework/agents/red-team-qa.md +0 -130
- package/framework/agents/security-auditor.md +0 -72
- package/framework/agents/team-orchestrator.md +0 -229
- package/framework/agents/teams/framework-audit-team.md +0 -66
- package/framework/agents/teams/full-stack-team.md +0 -48
- package/framework/agents/teams/optimize-team.md +0 -53
- package/framework/agents/teams/review-team.md +0 -70
- package/framework/agents/teams/ship-team.md +0 -86
- package/framework/agents/test-agent.md +0 -182
- package/framework/hooks/auto-format.sh +0 -54
- package/framework/hooks/block-env-edit.sh +0 -42
- package/framework/hooks/branch-guard.sh +0 -43
- package/framework/hooks/confirm-delete.sh +0 -59
- package/framework/hooks/migration-validate.sh +0 -77
- package/framework/hooks/notification-speak.sh +0 -16
- package/framework/hooks/pre-commit.sh +0 -100
- package/framework/hooks/pre-compact.sh +0 -56
- package/framework/hooks/pre-deploy-gate.sh +0 -160
- package/framework/hooks/qualia-colors.sh +0 -32
- package/framework/hooks/retention-cleanup.sh +0 -62
- package/framework/hooks/save-session-state.sh +0 -185
- package/framework/hooks/session-context-loader.sh +0 -96
- package/framework/hooks/session-learn.sh +0 -32
- package/framework/hooks/skill-announce.sh +0 -123
- package/framework/hooks/tool-error-announce.sh +0 -27
- package/framework/install.ps1 +0 -323
- package/framework/install.sh +0 -313
- package/framework/qualia-framework/VERSION +0 -1
- package/framework/qualia-framework/assets/qualia-logo.png +0 -0
- package/framework/qualia-framework/bin/collect-metrics.sh +0 -67
- package/framework/qualia-framework/bin/generate-report-docx.py +0 -429
- package/framework/qualia-framework/bin/qualia-tools.js +0 -2201
- package/framework/qualia-framework/bin/qualia-tools.test.js +0 -1054
- package/framework/qualia-framework/references/checkpoints.md +0 -775
- package/framework/qualia-framework/references/completion-checklists.md +0 -359
- package/framework/qualia-framework/references/continuation-format.md +0 -249
- package/framework/qualia-framework/references/continuation-prompt.md +0 -97
- package/framework/qualia-framework/references/decimal-phase-calculation.md +0 -65
- package/framework/qualia-framework/references/design-quality.md +0 -56
- package/framework/qualia-framework/references/employee-guide.md +0 -167
- package/framework/qualia-framework/references/git-integration.md +0 -254
- package/framework/qualia-framework/references/git-planning-commit.md +0 -50
- package/framework/qualia-framework/references/model-profile-resolution.md +0 -32
- package/framework/qualia-framework/references/model-profiles.md +0 -73
- package/framework/qualia-framework/references/phase-argument-parsing.md +0 -61
- package/framework/qualia-framework/references/planning-config.md +0 -195
- package/framework/qualia-framework/references/questioning.md +0 -141
- package/framework/qualia-framework/references/tdd.md +0 -263
- package/framework/qualia-framework/references/ui-brand.md +0 -160
- package/framework/qualia-framework/references/verification-patterns.md +0 -612
- package/framework/qualia-framework/templates/DEBUG.md +0 -159
- package/framework/qualia-framework/templates/DESIGN.md +0 -81
- package/framework/qualia-framework/templates/UAT.md +0 -247
- package/framework/qualia-framework/templates/codebase/architecture.md +0 -255
- package/framework/qualia-framework/templates/codebase/concerns.md +0 -310
- package/framework/qualia-framework/templates/codebase/conventions.md +0 -307
- package/framework/qualia-framework/templates/codebase/integrations.md +0 -280
- package/framework/qualia-framework/templates/codebase/stack.md +0 -186
- package/framework/qualia-framework/templates/codebase/structure.md +0 -285
- package/framework/qualia-framework/templates/codebase/testing.md +0 -480
- package/framework/qualia-framework/templates/config.json +0 -35
- package/framework/qualia-framework/templates/context.md +0 -283
- package/framework/qualia-framework/templates/continue-here.md +0 -78
- package/framework/qualia-framework/templates/debug-subagent-prompt.md +0 -91
- package/framework/qualia-framework/templates/discovery.md +0 -146
- package/framework/qualia-framework/templates/lab-notes.md +0 -16
- package/framework/qualia-framework/templates/milestone-archive.md +0 -123
- package/framework/qualia-framework/templates/milestone.md +0 -115
- package/framework/qualia-framework/templates/phase-prompt.md +0 -567
- package/framework/qualia-framework/templates/planner-subagent-prompt.md +0 -117
- package/framework/qualia-framework/templates/project.md +0 -184
- package/framework/qualia-framework/templates/projects/ai-agent.md +0 -156
- package/framework/qualia-framework/templates/projects/mobile-app.md +0 -181
- package/framework/qualia-framework/templates/projects/voice-agent.md +0 -134
- package/framework/qualia-framework/templates/projects/website.md +0 -137
- package/framework/qualia-framework/templates/requirements.md +0 -231
- package/framework/qualia-framework/templates/research-project/ARCHITECTURE.md +0 -204
- package/framework/qualia-framework/templates/research-project/FEATURES.md +0 -147
- package/framework/qualia-framework/templates/research-project/PITFALLS.md +0 -200
- package/framework/qualia-framework/templates/research-project/STACK.md +0 -120
- package/framework/qualia-framework/templates/research-project/SUMMARY.md +0 -170
- package/framework/qualia-framework/templates/research.md +0 -552
- package/framework/qualia-framework/templates/roadmap.md +0 -206
- package/framework/qualia-framework/templates/state.md +0 -179
- package/framework/qualia-framework/templates/summary-complex.md +0 -59
- package/framework/qualia-framework/templates/summary-minimal.md +0 -41
- package/framework/qualia-framework/templates/summary-standard.md +0 -48
- package/framework/qualia-framework/templates/summary.md +0 -246
- package/framework/qualia-framework/templates/user-setup.md +0 -311
- package/framework/qualia-framework/templates/verification-report.md +0 -322
- package/framework/qualia-framework/workflows/add-phase.md +0 -179
- package/framework/qualia-framework/workflows/add-todo.md +0 -157
- package/framework/qualia-framework/workflows/audit-milestone.md +0 -241
- package/framework/qualia-framework/workflows/check-todos.md +0 -176
- package/framework/qualia-framework/workflows/complete-milestone.md +0 -858
- package/framework/qualia-framework/workflows/diagnose-issues.md +0 -219
- package/framework/qualia-framework/workflows/discovery-phase.md +0 -289
- package/framework/qualia-framework/workflows/discuss-phase.md +0 -534
- package/framework/qualia-framework/workflows/execute-phase.md +0 -559
- package/framework/qualia-framework/workflows/execute-plan.md +0 -438
- package/framework/qualia-framework/workflows/help.md +0 -470
- package/framework/qualia-framework/workflows/insert-phase.md +0 -220
- package/framework/qualia-framework/workflows/list-phase-assumptions.md +0 -178
- package/framework/qualia-framework/workflows/map-codebase.md +0 -327
- package/framework/qualia-framework/workflows/new-milestone.md +0 -363
- package/framework/qualia-framework/workflows/new-project.md +0 -982
- package/framework/qualia-framework/workflows/pause-work.md +0 -122
- package/framework/qualia-framework/workflows/plan-milestone-gaps.md +0 -256
- package/framework/qualia-framework/workflows/plan-phase.md +0 -422
- package/framework/qualia-framework/workflows/progress.md +0 -389
- package/framework/qualia-framework/workflows/quick.md +0 -252
- package/framework/qualia-framework/workflows/remove-phase.md +0 -326
- package/framework/qualia-framework/workflows/research-phase.md +0 -74
- package/framework/qualia-framework/workflows/resume-project.md +0 -306
- package/framework/qualia-framework/workflows/set-profile.md +0 -80
- package/framework/qualia-framework/workflows/settings.md +0 -145
- package/framework/qualia-framework/workflows/transition.md +0 -556
- package/framework/qualia-framework/workflows/update.md +0 -197
- package/framework/qualia-framework/workflows/verify-phase.md +0 -195
- package/framework/qualia-framework/workflows/verify-work.md +0 -625
- package/framework/rules/context7.md +0 -14
- package/framework/rules/frontend.md +0 -33
- package/framework/rules/speed.md +0 -23
- package/framework/scripts/__pycache__/say.cpython-314.pyc +0 -0
- package/framework/scripts/apply-retention.sh +0 -120
- package/framework/scripts/bootstrap-pop-os.sh +0 -354
- package/framework/scripts/claude-voice +0 -13
- package/framework/scripts/cleanup.sh +0 -131
- package/framework/scripts/cowork-mode.sh +0 -141
- package/framework/scripts/generate-project-claude-md.sh +0 -153
- package/framework/scripts/load-test-webhook.js +0 -172
- package/framework/scripts/say.py +0 -236
- package/framework/scripts/showcase-video-recorder/ffmpeg-builder.js +0 -167
- package/framework/scripts/showcase-video-recorder/playwright-helpers.js +0 -216
- package/framework/scripts/speak.py +0 -55
- package/framework/scripts/speak.sh +0 -18
- package/framework/scripts/status.sh +0 -138
- package/framework/scripts/sync-to-framework.sh +0 -65
- package/framework/scripts/voice-hotkey.py +0 -227
- package/framework/scripts/voice-input.sh +0 -51
- package/framework/skills/animate/SKILL.md +0 -202
- package/framework/skills/bolder/SKILL.md +0 -144
- package/framework/skills/browser-qa/SKILL.md +0 -536
- package/framework/skills/clarify/SKILL.md +0 -179
- package/framework/skills/client-handoff/SKILL.md +0 -135
- package/framework/skills/collab-onboard/SKILL.md +0 -111
- package/framework/skills/colorize/SKILL.md +0 -170
- package/framework/skills/critique/SKILL.md +0 -126
- package/framework/skills/deep-research/SKILL.md +0 -240
- package/framework/skills/delight/SKILL.md +0 -329
- package/framework/skills/deploy/SKILL.md +0 -261
- package/framework/skills/deploy-verify/SKILL.md +0 -377
- package/framework/skills/deploy-verify/scripts/canary-check.sh +0 -206
- package/framework/skills/deploy-verify/scripts/check-console-errors.js +0 -147
- package/framework/skills/deploy-verify/scripts/check-cwv.js +0 -139
- package/framework/skills/deploy-verify/scripts/project-detect.sh +0 -84
- package/framework/skills/deploy-verify/scripts/verify.sh +0 -548
- package/framework/skills/design-quieter/SKILL.md +0 -130
- package/framework/skills/distill/SKILL.md +0 -149
- package/framework/skills/docs-lookup/SKILL.md +0 -79
- package/framework/skills/fcm-notifications/SKILL.md +0 -125
- package/framework/skills/financial-ledger/SKILL.md +0 -1039
- package/framework/skills/frontend-master/NOTICE.md +0 -4
- package/framework/skills/frontend-master/SKILL.md +0 -127
- package/framework/skills/frontend-master/reference/color-and-contrast.md +0 -132
- package/framework/skills/frontend-master/reference/interaction-design.md +0 -123
- package/framework/skills/frontend-master/reference/motion-design.md +0 -99
- package/framework/skills/frontend-master/reference/responsive-design.md +0 -114
- package/framework/skills/frontend-master/reference/spatial-design.md +0 -100
- package/framework/skills/frontend-master/reference/typography.md +0 -131
- package/framework/skills/frontend-master/reference/ux-writing.md +0 -107
- package/framework/skills/harden/SKILL.md +0 -357
- package/framework/skills/i18n-rtl/SKILL.md +0 -752
- package/framework/skills/learn/SKILL.md +0 -95
- package/framework/skills/memory/SKILL.md +0 -50
- package/framework/skills/mobile-expo/SKILL.md +0 -977
- package/framework/skills/mobile-expo/references/store-checklist.md +0 -550
- package/framework/skills/nestjs-backend/README.md +0 -73
- package/framework/skills/nestjs-backend/SKILL.md +0 -446
- package/framework/skills/nestjs-backend/references/templates.md +0 -1173
- package/framework/skills/normalize/SKILL.md +0 -79
- package/framework/skills/onboard/SKILL.md +0 -242
- package/framework/skills/openrouter-agent/SKILL.md +0 -922
- package/framework/skills/polish/SKILL.md +0 -209
- package/framework/skills/pr/SKILL.md +0 -66
- package/framework/skills/qualia/SKILL.md +0 -199
- package/framework/skills/qualia-add-todo/SKILL.md +0 -68
- package/framework/skills/qualia-audit-milestone/SKILL.md +0 -95
- package/framework/skills/qualia-check-todos/SKILL.md +0 -55
- package/framework/skills/qualia-complete-milestone/SKILL.md +0 -134
- package/framework/skills/qualia-debug/SKILL.md +0 -149
- package/framework/skills/qualia-design/SKILL.md +0 -203
- package/framework/skills/qualia-discuss-phase/SKILL.md +0 -72
- package/framework/skills/qualia-evolve/SKILL.md +0 -200
- package/framework/skills/qualia-execute-phase/SKILL.md +0 -89
- package/framework/skills/qualia-framework-audit/SKILL.md +0 -604
- package/framework/skills/qualia-guide/SKILL.md +0 -32
- package/framework/skills/qualia-help/SKILL.md +0 -114
- package/framework/skills/qualia-idk/SKILL.md +0 -352
- package/framework/skills/qualia-list-phase-assumptions/SKILL.md +0 -67
- package/framework/skills/qualia-new-milestone/SKILL.md +0 -72
- package/framework/skills/qualia-new-project/SKILL.md +0 -232
- package/framework/skills/qualia-optimize/SKILL.md +0 -417
- package/framework/skills/qualia-pause-work/SKILL.md +0 -96
- package/framework/skills/qualia-plan-milestone-gaps/SKILL.md +0 -57
- package/framework/skills/qualia-plan-phase/SKILL.md +0 -104
- package/framework/skills/qualia-production-check/SKILL.md +0 -0
- package/framework/skills/qualia-progress/SKILL.md +0 -53
- package/framework/skills/qualia-quick/SKILL.md +0 -89
- package/framework/skills/qualia-report/SKILL.md +0 -166
- package/framework/skills/qualia-research-phase/SKILL.md +0 -88
- package/framework/skills/qualia-resume-work/SKILL.md +0 -62
- package/framework/skills/qualia-review/SKILL.md +0 -263
- package/framework/skills/qualia-start/SKILL.md +0 -161
- package/framework/skills/qualia-verify-work/SKILL.md +0 -132
- package/framework/skills/rag/SKILL.md +0 -750
- package/framework/skills/responsive/SKILL.md +0 -231
- package/framework/skills/retro/SKILL.md +0 -284
- package/framework/skills/sakani-conventions/SKILL.md +0 -136
- package/framework/skills/sakani-conventions/evals/evals.json +0 -23
- package/framework/skills/sakani-conventions/references/entities.md +0 -365
- package/framework/skills/sakani-conventions/references/error-codes.md +0 -95
- package/framework/skills/seo-master/SKILL.md +0 -490
- package/framework/skills/seo-master/references/checklist.md +0 -199
- package/framework/skills/seo-master/references/structured-data.md +0 -609
- package/framework/skills/ship/SKILL.md +0 -239
- package/framework/skills/stack-researcher/SKILL.md +0 -215
- package/framework/skills/status/SKILL.md +0 -154
- package/framework/skills/status/scripts/health-check.sh +0 -562
- package/framework/skills/subscription-payments/SKILL.md +0 -250
- package/framework/skills/supabase/SKILL.md +0 -973
- package/framework/skills/supabase/references/templates.md +0 -159
- package/framework/skills/team/SKILL.md +0 -67
- package/framework/skills/test-runner/SKILL.md +0 -202
- package/framework/skills/voice-agent/SKILL.md +0 -1312
- package/framework/skills/zoho-workflow/SKILL.md +0 -51
- package/framework/statusline-command.sh +0 -117
- package/framework/teams/default/inboxes/plan-04.json +0 -9
- package/framework/teams/review-team.md +0 -75
- package/framework/teams/ship-team.md +0 -86
- package/profiles/fawzi.json +0 -16
- package/profiles/hasan.json +0 -16
- package/profiles/moayad.json +0 -16
- package/templates/CLAUDE-owner.md +0 -52
- package/templates/CLAUDE.md.hbs +0 -58
- package/templates/env.claude.template +0 -12
- package/templates/settings.json +0 -172
- package/uninstall.sh +0 -90
- /package/{framework/rules → rules}/deployment.md +0 -0
- /package/{framework/rules → rules}/security.md +0 -0
|
@@ -0,0 +1,687 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Qualia Framework v2 — bin/ file behavioral tests (install.js, cli.js, qualia-ui.js)
|
|
3
|
+
# Run: bash tests/bin.test.sh
|
|
4
|
+
|
|
5
|
+
PASS=0
|
|
6
|
+
FAIL=0
|
|
7
|
+
FRAMEWORK_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
8
|
+
NODE="${NODE:-node}"
|
|
9
|
+
CLI_JS="$FRAMEWORK_DIR/bin/cli.js"
|
|
10
|
+
UI_JS="$FRAMEWORK_DIR/bin/qualia-ui.js"
|
|
11
|
+
INSTALL_JS="$FRAMEWORK_DIR/bin/install.js"
|
|
12
|
+
PKG_VERSION=$($NODE -e 'console.log(require("'"$FRAMEWORK_DIR"'/package.json").version)')
|
|
13
|
+
|
|
14
|
+
# Track tmp dirs we create so we can clean them up on exit
|
|
15
|
+
TMP_DIRS=()
|
|
16
|
+
cleanup() {
|
|
17
|
+
for d in "${TMP_DIRS[@]}"; do
|
|
18
|
+
[ -d "$d" ] && rm -rf "$d"
|
|
19
|
+
done
|
|
20
|
+
}
|
|
21
|
+
trap cleanup EXIT
|
|
22
|
+
|
|
23
|
+
mktmp() {
|
|
24
|
+
local t
|
|
25
|
+
t=$(mktemp -d)
|
|
26
|
+
TMP_DIRS+=("$t")
|
|
27
|
+
echo "$t"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
assert_exit() {
|
|
31
|
+
local name="$1" expected="$2" actual="$3"
|
|
32
|
+
if [ "$expected" = "$actual" ]; then
|
|
33
|
+
echo " ✓ $name"
|
|
34
|
+
PASS=$((PASS + 1))
|
|
35
|
+
else
|
|
36
|
+
echo " ✗ $name (expected exit $expected, got $actual)"
|
|
37
|
+
FAIL=$((FAIL + 1))
|
|
38
|
+
fi
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
pass() {
|
|
42
|
+
echo " ✓ $1"
|
|
43
|
+
PASS=$((PASS + 1))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
fail_case() {
|
|
47
|
+
echo " ✗ $1${2:+ — $2}"
|
|
48
|
+
FAIL=$((FAIL + 1))
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# Strip ANSI escape codes for cleaner matching against expected strings.
|
|
52
|
+
strip_ansi() {
|
|
53
|
+
sed 's/\x1b\[[0-9;]*m//g'
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
echo "=== bin/ Behavioral Tests ==="
|
|
57
|
+
echo ""
|
|
58
|
+
|
|
59
|
+
# Sanity checks
|
|
60
|
+
for f in "$CLI_JS" "$UI_JS" "$INSTALL_JS"; do
|
|
61
|
+
if [ ! -f "$f" ]; then
|
|
62
|
+
echo "FATAL: $f not found"
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
done
|
|
66
|
+
|
|
67
|
+
# ─── cli.js ───────────────────────────────────────────────
|
|
68
|
+
echo "cli.js:"
|
|
69
|
+
|
|
70
|
+
# 1. No args prints help banner
|
|
71
|
+
TMP=$(mktmp)
|
|
72
|
+
OUT=$(HOME="$TMP" $NODE "$CLI_JS" 2>&1)
|
|
73
|
+
EXIT=$?
|
|
74
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
75
|
+
if [ "$EXIT" -eq 0 ] \
|
|
76
|
+
&& echo "$CLEAN" | grep -q "Qualia Framework" \
|
|
77
|
+
&& echo "$CLEAN" | grep -q "Commands:"; then
|
|
78
|
+
pass "no args → help banner, exit 0"
|
|
79
|
+
else
|
|
80
|
+
fail_case "no args help" "exit=$EXIT"
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# 2. `help` (unknown subcommand) falls through to help
|
|
84
|
+
TMP=$(mktmp)
|
|
85
|
+
OUT=$(HOME="$TMP" $NODE "$CLI_JS" help 2>&1)
|
|
86
|
+
EXIT=$?
|
|
87
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
88
|
+
if [ "$EXIT" -eq 0 ] \
|
|
89
|
+
&& echo "$CLEAN" | grep -q "/qualia-new"; then
|
|
90
|
+
pass "help arg → shows /qualia-new, /qualia-plan list"
|
|
91
|
+
else
|
|
92
|
+
fail_case "help arg" "exit=$EXIT"
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
# 3. Unknown subcommand falls through to help
|
|
96
|
+
TMP=$(mktmp)
|
|
97
|
+
OUT=$(HOME="$TMP" $NODE "$CLI_JS" frobnicate 2>&1)
|
|
98
|
+
EXIT=$?
|
|
99
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
100
|
+
if [ "$EXIT" -eq 0 ] \
|
|
101
|
+
&& echo "$CLEAN" | grep -q "Qualia Framework"; then
|
|
102
|
+
pass "unknown command → help banner, exit 0"
|
|
103
|
+
else
|
|
104
|
+
fail_case "unknown command" "exit=$EXIT"
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
# 4. `version` without config — shows version, no User line, offline fallback
|
|
108
|
+
TMP=$(mktmp)
|
|
109
|
+
OUT=$(HOME="$TMP" npm_config_registry="http://127.0.0.1:1/" $NODE "$CLI_JS" version 2>&1)
|
|
110
|
+
EXIT=$?
|
|
111
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
112
|
+
if [ "$EXIT" -eq 0 ] \
|
|
113
|
+
&& echo "$CLEAN" | grep -q "Installed:" \
|
|
114
|
+
&& echo "$CLEAN" | grep -q "$PKG_VERSION" \
|
|
115
|
+
&& ! echo "$CLEAN" | grep -q "User:"; then
|
|
116
|
+
pass "version without config → shows version, no User line"
|
|
117
|
+
else
|
|
118
|
+
fail_case "version without config" "exit=$EXIT"
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
# 5. `version` exits cleanly regardless of network path
|
|
122
|
+
# The update check branches on execSync of `npm view ...`: it prints "Latest:"
|
|
123
|
+
# with the version (up-to-date), "Update available:", "(offline — couldn't check)",
|
|
124
|
+
# or nothing if npm returns an empty string. All of these are acceptable — the
|
|
125
|
+
# only real regression would be a crash or stderr on stdout.
|
|
126
|
+
if [ "$EXIT" -eq 0 ] \
|
|
127
|
+
&& ! echo "$CLEAN" | grep -qi "error" \
|
|
128
|
+
&& ! echo "$CLEAN" | grep -qi "traceback"; then
|
|
129
|
+
pass "version update-check branch → clean exit, no errors"
|
|
130
|
+
else
|
|
131
|
+
fail_case "version update-check branch" "exit=$EXIT"
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
# 6. `version` with saved config — shows User line
|
|
135
|
+
TMP=$(mktmp)
|
|
136
|
+
mkdir -p "$TMP/.claude"
|
|
137
|
+
cat > "$TMP/.claude/.qualia-config.json" <<'EOF'
|
|
138
|
+
{
|
|
139
|
+
"code": "QS-FAWZI-01",
|
|
140
|
+
"installed_by": "Fawzi Goussous",
|
|
141
|
+
"role": "OWNER",
|
|
142
|
+
"version": "2.8.1",
|
|
143
|
+
"installed_at": "2026-04-10"
|
|
144
|
+
}
|
|
145
|
+
EOF
|
|
146
|
+
OUT=$(HOME="$TMP" npm_config_registry="http://127.0.0.1:1/" $NODE "$CLI_JS" version 2>&1)
|
|
147
|
+
EXIT=$?
|
|
148
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
149
|
+
if [ "$EXIT" -eq 0 ] \
|
|
150
|
+
&& echo "$CLEAN" | grep -q "User:" \
|
|
151
|
+
&& echo "$CLEAN" | grep -q "Fawzi Goussous" \
|
|
152
|
+
&& echo "$CLEAN" | grep -q "OWNER" \
|
|
153
|
+
&& echo "$CLEAN" | grep -q "2026-04-10"; then
|
|
154
|
+
pass "version with config → shows User, role, date"
|
|
155
|
+
else
|
|
156
|
+
fail_case "version with config" "exit=$EXIT"
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
# 7. `-v` alias works the same as version
|
|
160
|
+
TMP=$(mktmp)
|
|
161
|
+
OUT=$(HOME="$TMP" npm_config_registry="http://127.0.0.1:1/" $NODE "$CLI_JS" -v 2>&1)
|
|
162
|
+
EXIT=$?
|
|
163
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
164
|
+
if [ "$EXIT" -eq 0 ] \
|
|
165
|
+
&& echo "$CLEAN" | grep -q "Installed:" \
|
|
166
|
+
&& echo "$CLEAN" | grep -q "$PKG_VERSION"; then
|
|
167
|
+
pass "-v alias → shows version"
|
|
168
|
+
else
|
|
169
|
+
fail_case "-v alias" "exit=$EXIT"
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
# 8. `--version` alias works
|
|
173
|
+
TMP=$(mktmp)
|
|
174
|
+
OUT=$(HOME="$TMP" npm_config_registry="http://127.0.0.1:1/" $NODE "$CLI_JS" --version 2>&1)
|
|
175
|
+
EXIT=$?
|
|
176
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
177
|
+
if [ "$EXIT" -eq 0 ] \
|
|
178
|
+
&& echo "$CLEAN" | grep -q "Installed:" \
|
|
179
|
+
&& echo "$CLEAN" | grep -q "$PKG_VERSION"; then
|
|
180
|
+
pass "--version alias → shows version"
|
|
181
|
+
else
|
|
182
|
+
fail_case "--version alias" "exit=$EXIT"
|
|
183
|
+
fi
|
|
184
|
+
|
|
185
|
+
# 9. `update` without saved config → exits 1 cleanly with clear message
|
|
186
|
+
TMP=$(mktmp)
|
|
187
|
+
OUT=$(HOME="$TMP" $NODE "$CLI_JS" update 2>&1)
|
|
188
|
+
EXIT=$?
|
|
189
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
190
|
+
if [ "$EXIT" -eq 1 ] \
|
|
191
|
+
&& echo "$CLEAN" | grep -q "No install code saved"; then
|
|
192
|
+
pass "update without config → exit 1, 'No install code saved'"
|
|
193
|
+
else
|
|
194
|
+
fail_case "update without config" "exit=$EXIT"
|
|
195
|
+
fi
|
|
196
|
+
|
|
197
|
+
# 10. `upgrade` alias behaves same as update (no config → exit 1)
|
|
198
|
+
TMP=$(mktmp)
|
|
199
|
+
OUT=$(HOME="$TMP" $NODE "$CLI_JS" upgrade 2>&1)
|
|
200
|
+
EXIT=$?
|
|
201
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
202
|
+
if [ "$EXIT" -eq 1 ] \
|
|
203
|
+
&& echo "$CLEAN" | grep -q "No install code saved"; then
|
|
204
|
+
pass "upgrade alias → exit 1, 'No install code saved'"
|
|
205
|
+
else
|
|
206
|
+
fail_case "upgrade alias" "exit=$EXIT"
|
|
207
|
+
fi
|
|
208
|
+
|
|
209
|
+
echo ""
|
|
210
|
+
|
|
211
|
+
# ─── qualia-ui.js ─────────────────────────────────────────
|
|
212
|
+
echo "qualia-ui.js:"
|
|
213
|
+
|
|
214
|
+
# 11. banner router (no state) — exit 0, renders QUALIA + SMART ROUTER
|
|
215
|
+
TMP=$(mktmp)
|
|
216
|
+
OUT=$(cd "$TMP" && HOME="$TMP" $NODE "$UI_JS" banner router 2>&1)
|
|
217
|
+
EXIT=$?
|
|
218
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
219
|
+
if [ "$EXIT" -eq 0 ] \
|
|
220
|
+
&& echo "$CLEAN" | grep -q "QUALIA" \
|
|
221
|
+
&& echo "$CLEAN" | grep -q "SMART ROUTER"; then
|
|
222
|
+
pass "banner router → 'QUALIA' + 'SMART ROUTER'"
|
|
223
|
+
else
|
|
224
|
+
fail_case "banner router" "exit=$EXIT"
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
# 12. banner plan 1 foundation — includes PLANNING + Phase 1 + subtitle
|
|
228
|
+
TMP=$(mktmp)
|
|
229
|
+
OUT=$(cd "$TMP" && HOME="$TMP" $NODE "$UI_JS" banner plan 1 foundation 2>&1)
|
|
230
|
+
EXIT=$?
|
|
231
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
232
|
+
if [ "$EXIT" -eq 0 ] \
|
|
233
|
+
&& echo "$CLEAN" | grep -q "PLANNING" \
|
|
234
|
+
&& echo "$CLEAN" | grep -q "Phase 1"; then
|
|
235
|
+
pass "banner plan 1 foundation → 'PLANNING' + 'Phase 1'"
|
|
236
|
+
else
|
|
237
|
+
fail_case "banner plan 1 foundation" "exit=$EXIT"
|
|
238
|
+
fi
|
|
239
|
+
|
|
240
|
+
# 13. banner with unknown action — falls back to uppercased action label
|
|
241
|
+
TMP=$(mktmp)
|
|
242
|
+
OUT=$(cd "$TMP" && HOME="$TMP" $NODE "$UI_JS" banner frobnicate 2>&1)
|
|
243
|
+
EXIT=$?
|
|
244
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
245
|
+
if [ "$EXIT" -eq 0 ] \
|
|
246
|
+
&& echo "$CLEAN" | grep -q "QUALIA" \
|
|
247
|
+
&& echo "$CLEAN" | grep -q "FROBNICATE"; then
|
|
248
|
+
pass "banner unknown action → uppercased fallback label"
|
|
249
|
+
else
|
|
250
|
+
fail_case "banner unknown action" "exit=$EXIT"
|
|
251
|
+
fi
|
|
252
|
+
|
|
253
|
+
# 14. context (no project) — exit 0, shows 'Project' and 'No project detected' hint
|
|
254
|
+
TMP=$(mktmp)
|
|
255
|
+
OUT=$(cd "$TMP" && HOME="$TMP" $NODE "$UI_JS" context 2>&1)
|
|
256
|
+
EXIT=$?
|
|
257
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
258
|
+
if [ "$EXIT" -eq 0 ] \
|
|
259
|
+
&& echo "$CLEAN" | grep -q "Project" \
|
|
260
|
+
&& echo "$CLEAN" | grep -q "No project detected"; then
|
|
261
|
+
pass "context without project → 'Project' + 'No project detected'"
|
|
262
|
+
else
|
|
263
|
+
fail_case "context without project" "exit=$EXIT"
|
|
264
|
+
fi
|
|
265
|
+
|
|
266
|
+
# 15. ok <message>
|
|
267
|
+
TMP=$(mktmp)
|
|
268
|
+
OUT=$(HOME="$TMP" $NODE "$UI_JS" ok "hello world" 2>&1)
|
|
269
|
+
EXIT=$?
|
|
270
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
271
|
+
if [ "$EXIT" -eq 0 ] \
|
|
272
|
+
&& echo "$CLEAN" | grep -q "hello world" \
|
|
273
|
+
&& echo "$OUT" | grep -q "✓"; then
|
|
274
|
+
pass "ok → '✓' + message"
|
|
275
|
+
else
|
|
276
|
+
fail_case "ok message" "exit=$EXIT"
|
|
277
|
+
fi
|
|
278
|
+
|
|
279
|
+
# 16. fail <message>
|
|
280
|
+
TMP=$(mktmp)
|
|
281
|
+
OUT=$(HOME="$TMP" $NODE "$UI_JS" fail "nope nope" 2>&1)
|
|
282
|
+
EXIT=$?
|
|
283
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
284
|
+
if [ "$EXIT" -eq 0 ] \
|
|
285
|
+
&& echo "$CLEAN" | grep -q "nope nope" \
|
|
286
|
+
&& echo "$OUT" | grep -q "✗"; then
|
|
287
|
+
pass "fail → '✗' + message"
|
|
288
|
+
else
|
|
289
|
+
fail_case "fail message" "exit=$EXIT"
|
|
290
|
+
fi
|
|
291
|
+
|
|
292
|
+
# 17. warn <message>
|
|
293
|
+
TMP=$(mktmp)
|
|
294
|
+
OUT=$(HOME="$TMP" $NODE "$UI_JS" warn "careful" 2>&1)
|
|
295
|
+
EXIT=$?
|
|
296
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
297
|
+
if [ "$EXIT" -eq 0 ] \
|
|
298
|
+
&& echo "$CLEAN" | grep -q "careful"; then
|
|
299
|
+
pass "warn → message rendered"
|
|
300
|
+
else
|
|
301
|
+
fail_case "warn message" "exit=$EXIT"
|
|
302
|
+
fi
|
|
303
|
+
|
|
304
|
+
# 18. info <message>
|
|
305
|
+
TMP=$(mktmp)
|
|
306
|
+
OUT=$(HOME="$TMP" $NODE "$UI_JS" info "just fyi" 2>&1)
|
|
307
|
+
EXIT=$?
|
|
308
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
309
|
+
if [ "$EXIT" -eq 0 ] \
|
|
310
|
+
&& echo "$CLEAN" | grep -q "just fyi"; then
|
|
311
|
+
pass "info → message rendered"
|
|
312
|
+
else
|
|
313
|
+
fail_case "info message" "exit=$EXIT"
|
|
314
|
+
fi
|
|
315
|
+
|
|
316
|
+
# 19. divider renders a horizontal rule with '━' character
|
|
317
|
+
TMP=$(mktmp)
|
|
318
|
+
OUT=$(HOME="$TMP" $NODE "$UI_JS" divider 2>&1)
|
|
319
|
+
EXIT=$?
|
|
320
|
+
if [ "$EXIT" -eq 0 ] \
|
|
321
|
+
&& echo "$OUT" | grep -q "━"; then
|
|
322
|
+
pass "divider → '━' rule"
|
|
323
|
+
else
|
|
324
|
+
fail_case "divider" "exit=$EXIT"
|
|
325
|
+
fi
|
|
326
|
+
|
|
327
|
+
# 20. spawn agent description
|
|
328
|
+
TMP=$(mktmp)
|
|
329
|
+
OUT=$(HOME="$TMP" $NODE "$UI_JS" spawn builder "task 3" 2>&1)
|
|
330
|
+
EXIT=$?
|
|
331
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
332
|
+
if [ "$EXIT" -eq 0 ] \
|
|
333
|
+
&& echo "$CLEAN" | grep -q "Spawning" \
|
|
334
|
+
&& echo "$CLEAN" | grep -q "builder" \
|
|
335
|
+
&& echo "$CLEAN" | grep -q "task 3"; then
|
|
336
|
+
pass "spawn builder → 'Spawning builder — task 3'"
|
|
337
|
+
else
|
|
338
|
+
fail_case "spawn" "exit=$EXIT"
|
|
339
|
+
fi
|
|
340
|
+
|
|
341
|
+
# 21. wave 1 3 5 — renders wave header with task count
|
|
342
|
+
TMP=$(mktmp)
|
|
343
|
+
OUT=$(HOME="$TMP" $NODE "$UI_JS" wave 1 3 5 2>&1)
|
|
344
|
+
EXIT=$?
|
|
345
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
346
|
+
if [ "$EXIT" -eq 0 ] \
|
|
347
|
+
&& echo "$CLEAN" | grep -q "Wave 1/3" \
|
|
348
|
+
&& echo "$CLEAN" | grep -q "5 tasks"; then
|
|
349
|
+
pass "wave 1 3 5 → 'Wave 1/3 (5 tasks)'"
|
|
350
|
+
else
|
|
351
|
+
fail_case "wave" "exit=$EXIT"
|
|
352
|
+
fi
|
|
353
|
+
|
|
354
|
+
# 22. task <N> <title>
|
|
355
|
+
TMP=$(mktmp)
|
|
356
|
+
OUT=$(HOME="$TMP" $NODE "$UI_JS" task 2 "Build login form" 2>&1)
|
|
357
|
+
EXIT=$?
|
|
358
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
359
|
+
if [ "$EXIT" -eq 0 ] \
|
|
360
|
+
&& echo "$CLEAN" | grep -q "Build login form" \
|
|
361
|
+
&& echo "$CLEAN" | grep -q "2\."; then
|
|
362
|
+
pass "task 2 title → '2. Build login form'"
|
|
363
|
+
else
|
|
364
|
+
fail_case "task" "exit=$EXIT"
|
|
365
|
+
fi
|
|
366
|
+
|
|
367
|
+
# 23. done <N> <title> <commit>
|
|
368
|
+
TMP=$(mktmp)
|
|
369
|
+
OUT=$(HOME="$TMP" $NODE "$UI_JS" done 3 "TaskDone" "abc1234" 2>&1)
|
|
370
|
+
EXIT=$?
|
|
371
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
372
|
+
if [ "$EXIT" -eq 0 ] \
|
|
373
|
+
&& echo "$CLEAN" | grep -q "TaskDone" \
|
|
374
|
+
&& echo "$CLEAN" | grep -q "abc1234" \
|
|
375
|
+
&& echo "$OUT" | grep -q "✓"; then
|
|
376
|
+
pass "done 3 TaskDone abc1234 → check + title + commit"
|
|
377
|
+
else
|
|
378
|
+
fail_case "done" "exit=$EXIT"
|
|
379
|
+
fi
|
|
380
|
+
|
|
381
|
+
# 24. next /qualia-build
|
|
382
|
+
TMP=$(mktmp)
|
|
383
|
+
OUT=$(HOME="$TMP" $NODE "$UI_JS" next /qualia-build 2>&1)
|
|
384
|
+
EXIT=$?
|
|
385
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
386
|
+
if [ "$EXIT" -eq 0 ] \
|
|
387
|
+
&& echo "$CLEAN" | grep -q "Next:" \
|
|
388
|
+
&& echo "$CLEAN" | grep -q "/qualia-build"; then
|
|
389
|
+
pass "next /qualia-build → 'Next: /qualia-build'"
|
|
390
|
+
else
|
|
391
|
+
fail_case "next" "exit=$EXIT"
|
|
392
|
+
fi
|
|
393
|
+
|
|
394
|
+
# 25. end DONE with next command
|
|
395
|
+
TMP=$(mktmp)
|
|
396
|
+
OUT=$(HOME="$TMP" $NODE "$UI_JS" end SHIPPED /qualia-handoff 2>&1)
|
|
397
|
+
EXIT=$?
|
|
398
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
399
|
+
if [ "$EXIT" -eq 0 ] \
|
|
400
|
+
&& echo "$CLEAN" | grep -q "SHIPPED" \
|
|
401
|
+
&& echo "$CLEAN" | grep -q "/qualia-handoff"; then
|
|
402
|
+
pass "end SHIPPED /qualia-handoff → closes with next"
|
|
403
|
+
else
|
|
404
|
+
fail_case "end" "exit=$EXIT"
|
|
405
|
+
fi
|
|
406
|
+
|
|
407
|
+
# 26. unknown command exits 1 with usage line on stderr
|
|
408
|
+
TMP=$(mktmp)
|
|
409
|
+
STDERR=$(HOME="$TMP" $NODE "$UI_JS" frobnicate 2>&1 >/dev/null)
|
|
410
|
+
EXIT=$?
|
|
411
|
+
if [ "$EXIT" -eq 1 ] \
|
|
412
|
+
&& echo "$STDERR" | grep -q "Usage:"; then
|
|
413
|
+
pass "unknown command → exit 1, 'Usage:' on stderr"
|
|
414
|
+
else
|
|
415
|
+
fail_case "unknown command" "exit=$EXIT"
|
|
416
|
+
fi
|
|
417
|
+
|
|
418
|
+
# 27. banner router respects config — shows OWNER + name when config present
|
|
419
|
+
TMP=$(mktmp)
|
|
420
|
+
mkdir -p "$TMP/.claude"
|
|
421
|
+
cat > "$TMP/.claude/.qualia-config.json" <<'EOF'
|
|
422
|
+
{
|
|
423
|
+
"code": "QS-FAWZI-01",
|
|
424
|
+
"installed_by": "Fawzi Goussous",
|
|
425
|
+
"role": "OWNER",
|
|
426
|
+
"version": "2.8.1",
|
|
427
|
+
"installed_at": "2026-04-10"
|
|
428
|
+
}
|
|
429
|
+
EOF
|
|
430
|
+
OUT=$(cd "$TMP" && HOME="$TMP" $NODE "$UI_JS" banner router 2>&1)
|
|
431
|
+
EXIT=$?
|
|
432
|
+
CLEAN=$(echo "$OUT" | strip_ansi)
|
|
433
|
+
if [ "$EXIT" -eq 0 ] \
|
|
434
|
+
&& echo "$CLEAN" | grep -q "OWNER" \
|
|
435
|
+
&& echo "$CLEAN" | grep -q "Fawzi Goussous"; then
|
|
436
|
+
pass "banner router with config → shows OWNER + 'Fawzi Goussous'"
|
|
437
|
+
else
|
|
438
|
+
fail_case "banner with config" "exit=$EXIT"
|
|
439
|
+
fi
|
|
440
|
+
|
|
441
|
+
echo ""
|
|
442
|
+
|
|
443
|
+
# ─── install.js ───────────────────────────────────────────
|
|
444
|
+
echo "install.js:"
|
|
445
|
+
|
|
446
|
+
# 28. Happy path: valid code installs everything
|
|
447
|
+
TMP=$(mktmp)
|
|
448
|
+
echo "QS-FAWZI-01" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
|
|
449
|
+
EXIT=$?
|
|
450
|
+
if [ "$EXIT" -eq 0 ] \
|
|
451
|
+
&& [ -f "$TMP/.claude/skills/qualia/SKILL.md" ] \
|
|
452
|
+
&& [ -f "$TMP/.claude/hooks/session-start.js" ] \
|
|
453
|
+
&& [ -f "$TMP/.claude/bin/state.js" ] \
|
|
454
|
+
&& [ -f "$TMP/.claude/bin/qualia-ui.js" ] \
|
|
455
|
+
&& [ -f "$TMP/.claude/bin/statusline.js" ] \
|
|
456
|
+
&& [ -f "$TMP/.claude/.qualia-config.json" ]; then
|
|
457
|
+
pass "QS-FAWZI-01 → installs skills, hooks, bin/, config"
|
|
458
|
+
else
|
|
459
|
+
fail_case "QS-FAWZI-01 happy path" "exit=$EXIT"
|
|
460
|
+
fi
|
|
461
|
+
|
|
462
|
+
# 29. Config JSON has correct fields after happy path
|
|
463
|
+
if grep -q '"code": "QS-FAWZI-01"' "$TMP/.claude/.qualia-config.json" \
|
|
464
|
+
&& grep -q '"installed_by": "Fawzi Goussous"' "$TMP/.claude/.qualia-config.json" \
|
|
465
|
+
&& grep -q '"role": "OWNER"' "$TMP/.claude/.qualia-config.json"; then
|
|
466
|
+
pass "config JSON has code, installed_by, role=OWNER"
|
|
467
|
+
else
|
|
468
|
+
fail_case "config JSON fields"
|
|
469
|
+
fi
|
|
470
|
+
|
|
471
|
+
# 30. CLAUDE.md role placeholder replaced
|
|
472
|
+
if grep -q "Role: OWNER" "$TMP/.claude/CLAUDE.md" \
|
|
473
|
+
&& ! grep -q "{{ROLE}}" "$TMP/.claude/CLAUDE.md"; then
|
|
474
|
+
pass "CLAUDE.md has Role: OWNER, no {{ROLE}} placeholder"
|
|
475
|
+
else
|
|
476
|
+
fail_case "CLAUDE.md role substitution"
|
|
477
|
+
fi
|
|
478
|
+
|
|
479
|
+
# 31. All 8 hooks installed
|
|
480
|
+
HOOK_COUNT=$(ls "$TMP/.claude/hooks/"*.js 2>/dev/null | wc -l)
|
|
481
|
+
if [ "$HOOK_COUNT" -eq 8 ]; then
|
|
482
|
+
pass "8 hooks installed in hooks/"
|
|
483
|
+
else
|
|
484
|
+
fail_case "hook count" "got $HOOK_COUNT"
|
|
485
|
+
fi
|
|
486
|
+
|
|
487
|
+
# 32. settings.json written with hooks + statusLine
|
|
488
|
+
if [ -f "$TMP/.claude/settings.json" ] \
|
|
489
|
+
&& grep -q '"SessionStart"' "$TMP/.claude/settings.json" \
|
|
490
|
+
&& grep -q '"PreToolUse"' "$TMP/.claude/settings.json" \
|
|
491
|
+
&& grep -q '"statusLine"' "$TMP/.claude/settings.json"; then
|
|
492
|
+
pass "settings.json has SessionStart, PreToolUse, statusLine"
|
|
493
|
+
else
|
|
494
|
+
fail_case "settings.json contents"
|
|
495
|
+
fi
|
|
496
|
+
|
|
497
|
+
# 33. settings.json contains all 8 hooks wired correctly
|
|
498
|
+
if grep -q 'block-env-edit.js' "$TMP/.claude/settings.json" \
|
|
499
|
+
&& grep -q 'branch-guard.js' "$TMP/.claude/settings.json" \
|
|
500
|
+
&& grep -q 'migration-guard.js' "$TMP/.claude/settings.json" \
|
|
501
|
+
&& grep -q 'pre-push.js' "$TMP/.claude/settings.json" \
|
|
502
|
+
&& grep -q 'pre-deploy-gate.js' "$TMP/.claude/settings.json" \
|
|
503
|
+
&& grep -q 'auto-update.js' "$TMP/.claude/settings.json" \
|
|
504
|
+
&& grep -q 'session-start.js' "$TMP/.claude/settings.json" \
|
|
505
|
+
&& grep -q 'pre-compact.js' "$TMP/.claude/settings.json"; then
|
|
506
|
+
pass "settings.json has all 8 hooks wired"
|
|
507
|
+
else
|
|
508
|
+
fail_case "settings.json missing hooks"
|
|
509
|
+
fi
|
|
510
|
+
|
|
511
|
+
# 34. Lowercase code works (resolveTeamCode normalizes)
|
|
512
|
+
TMP=$(mktmp)
|
|
513
|
+
echo "qs-fawzi-01" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
|
|
514
|
+
EXIT=$?
|
|
515
|
+
if [ "$EXIT" -eq 0 ] \
|
|
516
|
+
&& [ -f "$TMP/.claude/.qualia-config.json" ] \
|
|
517
|
+
&& grep -q '"code": "QS-FAWZI-01"' "$TMP/.claude/.qualia-config.json"; then
|
|
518
|
+
pass "lowercase 'qs-fawzi-01' → canonical 'QS-FAWZI-01'"
|
|
519
|
+
else
|
|
520
|
+
fail_case "lowercase normalization" "exit=$EXIT"
|
|
521
|
+
fi
|
|
522
|
+
|
|
523
|
+
# 34. O/0 typo tolerance — letter O in suffix normalized to digit 0
|
|
524
|
+
TMP=$(mktmp)
|
|
525
|
+
echo "QS-FAWZI-O1" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
|
|
526
|
+
EXIT=$?
|
|
527
|
+
if [ "$EXIT" -eq 0 ] \
|
|
528
|
+
&& [ -f "$TMP/.claude/.qualia-config.json" ] \
|
|
529
|
+
&& grep -q '"code": "QS-FAWZI-01"' "$TMP/.claude/.qualia-config.json"; then
|
|
530
|
+
pass "letter 'O' in suffix → normalized to digit '0'"
|
|
531
|
+
else
|
|
532
|
+
fail_case "O/0 fuzzy match" "exit=$EXIT"
|
|
533
|
+
fi
|
|
534
|
+
|
|
535
|
+
# 35. MOAYAD real O in name preserved (only suffix is normalized)
|
|
536
|
+
TMP=$(mktmp)
|
|
537
|
+
echo "QS-MOAYAD-03" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
|
|
538
|
+
EXIT=$?
|
|
539
|
+
if [ "$EXIT" -eq 0 ] \
|
|
540
|
+
&& [ -f "$TMP/.claude/.qualia-config.json" ] \
|
|
541
|
+
&& grep -q '"code": "QS-MOAYAD-03"' "$TMP/.claude/.qualia-config.json" \
|
|
542
|
+
&& grep -q '"installed_by": "Moayad"' "$TMP/.claude/.qualia-config.json"; then
|
|
543
|
+
pass "QS-MOAYAD-03 → 'O' in name preserved"
|
|
544
|
+
else
|
|
545
|
+
fail_case "Moayad real-O" "exit=$EXIT"
|
|
546
|
+
fi
|
|
547
|
+
|
|
548
|
+
# 36. EMPLOYEE role set correctly
|
|
549
|
+
if grep -q '"role": "EMPLOYEE"' "$TMP/.claude/.qualia-config.json" \
|
|
550
|
+
&& grep -q "Role: EMPLOYEE" "$TMP/.claude/CLAUDE.md"; then
|
|
551
|
+
pass "Moayad role → EMPLOYEE"
|
|
552
|
+
else
|
|
553
|
+
fail_case "Moayad EMPLOYEE role"
|
|
554
|
+
fi
|
|
555
|
+
|
|
556
|
+
# 37. Invalid code exits 1 with helpful message
|
|
557
|
+
TMP=$(mktmp)
|
|
558
|
+
echo "QS-BOGUS-99" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
|
|
559
|
+
EXIT=$?
|
|
560
|
+
CLEAN=$(strip_ansi < "$TMP/out.log")
|
|
561
|
+
if [ "$EXIT" -eq 1 ] \
|
|
562
|
+
&& echo "$CLEAN" | grep -q "Invalid code" \
|
|
563
|
+
&& [ ! -f "$TMP/.claude/.qualia-config.json" ]; then
|
|
564
|
+
pass "QS-BOGUS-99 → exit 1, 'Invalid code', no config written"
|
|
565
|
+
else
|
|
566
|
+
fail_case "invalid code" "exit=$EXIT"
|
|
567
|
+
fi
|
|
568
|
+
|
|
569
|
+
# 38. Empty code (newline only) → exit 1, invalid code message
|
|
570
|
+
TMP=$(mktmp)
|
|
571
|
+
printf '\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
|
|
572
|
+
EXIT=$?
|
|
573
|
+
CLEAN=$(strip_ansi < "$TMP/out.log")
|
|
574
|
+
if [ "$EXIT" -eq 1 ] \
|
|
575
|
+
&& echo "$CLEAN" | grep -q "Invalid code" \
|
|
576
|
+
&& [ ! -f "$TMP/.claude/.qualia-config.json" ]; then
|
|
577
|
+
pass "empty code → exit 1, 'Invalid code'"
|
|
578
|
+
else
|
|
579
|
+
fail_case "empty code" "exit=$EXIT"
|
|
580
|
+
fi
|
|
581
|
+
|
|
582
|
+
# 39. Code with surrounding whitespace is accepted
|
|
583
|
+
TMP=$(mktmp)
|
|
584
|
+
printf ' QS-FAWZI-01 \n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
|
|
585
|
+
EXIT=$?
|
|
586
|
+
if [ "$EXIT" -eq 0 ] \
|
|
587
|
+
&& grep -q '"code": "QS-FAWZI-01"' "$TMP/.claude/.qualia-config.json"; then
|
|
588
|
+
pass "whitespace-padded code → accepted and trimmed"
|
|
589
|
+
else
|
|
590
|
+
fail_case "whitespace trim" "exit=$EXIT"
|
|
591
|
+
fi
|
|
592
|
+
|
|
593
|
+
# 40. Settings.json merge preserves custom top-level keys
|
|
594
|
+
TMP=$(mktmp)
|
|
595
|
+
mkdir -p "$TMP/.claude"
|
|
596
|
+
cat > "$TMP/.claude/settings.json" <<'EOF'
|
|
597
|
+
{
|
|
598
|
+
"customKey": "preserved",
|
|
599
|
+
"env": {
|
|
600
|
+
"MY_CUSTOM_VAR": "hello"
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
EOF
|
|
604
|
+
echo "QS-FAWZI-01" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
|
|
605
|
+
EXIT=$?
|
|
606
|
+
MERGED=$($NODE -e 'const s=JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"));console.log([s.customKey,s.env&&s.env.MY_CUSTOM_VAR,s.env&&s.env.CLAUDE_CODE_NO_FLICKER,!!s.hooks,!!s.statusLine].join("|"))' "$TMP/.claude/settings.json" 2>/dev/null)
|
|
607
|
+
if [ "$EXIT" -eq 0 ] \
|
|
608
|
+
&& [ "$MERGED" = "preserved|hello|1|true|true" ]; then
|
|
609
|
+
pass "settings.json merge preserves custom keys + adds new hooks/env"
|
|
610
|
+
else
|
|
611
|
+
fail_case "settings.json merge" "got '$MERGED' exit=$EXIT"
|
|
612
|
+
fi
|
|
613
|
+
|
|
614
|
+
# 41. Knowledge files created on first install
|
|
615
|
+
TMP=$(mktmp)
|
|
616
|
+
echo "QS-FAWZI-01" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
|
|
617
|
+
EXIT=$?
|
|
618
|
+
if [ "$EXIT" -eq 0 ] \
|
|
619
|
+
&& [ -f "$TMP/.claude/knowledge/learned-patterns.md" ] \
|
|
620
|
+
&& [ -f "$TMP/.claude/knowledge/common-fixes.md" ] \
|
|
621
|
+
&& [ -f "$TMP/.claude/knowledge/client-prefs.md" ]; then
|
|
622
|
+
pass "knowledge/ files created on first install"
|
|
623
|
+
else
|
|
624
|
+
fail_case "knowledge files created" "exit=$EXIT"
|
|
625
|
+
fi
|
|
626
|
+
|
|
627
|
+
# 42. Idempotent re-install preserves user edits to knowledge files
|
|
628
|
+
printf '\n## CUSTOM LEARNING — DO NOT OVERWRITE\n' >> "$TMP/.claude/knowledge/learned-patterns.md"
|
|
629
|
+
echo "QS-FAWZI-01" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out2.log" 2>&1
|
|
630
|
+
EXIT=$?
|
|
631
|
+
if [ "$EXIT" -eq 0 ] \
|
|
632
|
+
&& grep -q "CUSTOM LEARNING" "$TMP/.claude/knowledge/learned-patterns.md"; then
|
|
633
|
+
pass "re-install preserves user edits in knowledge files"
|
|
634
|
+
else
|
|
635
|
+
fail_case "knowledge idempotency" "exit=$EXIT"
|
|
636
|
+
fi
|
|
637
|
+
|
|
638
|
+
# 43. ERP API key file created and not overwritten on re-install
|
|
639
|
+
if [ -f "$TMP/.claude/.erp-api-key" ]; then
|
|
640
|
+
echo "custom-erp-key" > "$TMP/.claude/.erp-api-key"
|
|
641
|
+
echo "QS-FAWZI-01" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out3.log" 2>&1
|
|
642
|
+
if grep -q "custom-erp-key" "$TMP/.claude/.erp-api-key"; then
|
|
643
|
+
pass ".erp-api-key preserved on re-install"
|
|
644
|
+
else
|
|
645
|
+
fail_case ".erp-api-key preservation"
|
|
646
|
+
fi
|
|
647
|
+
else
|
|
648
|
+
fail_case ".erp-api-key missing after install"
|
|
649
|
+
fi
|
|
650
|
+
|
|
651
|
+
# 44. Templates copied to qualia-templates/
|
|
652
|
+
TMP=$(mktmp)
|
|
653
|
+
echo "QS-FAWZI-01" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
|
|
654
|
+
EXIT=$?
|
|
655
|
+
TMPL_COUNT=$(ls "$TMP/.claude/qualia-templates/" 2>/dev/null | wc -l)
|
|
656
|
+
if [ "$EXIT" -eq 0 ] && [ "$TMPL_COUNT" -gt 0 ]; then
|
|
657
|
+
pass "templates copied to qualia-templates/ ($TMPL_COUNT files)"
|
|
658
|
+
else
|
|
659
|
+
fail_case "templates copied" "exit=$EXIT count=$TMPL_COUNT"
|
|
660
|
+
fi
|
|
661
|
+
|
|
662
|
+
# 45. All agents copied
|
|
663
|
+
AGENT_COUNT=$(ls "$TMP/.claude/agents/" 2>/dev/null | wc -l)
|
|
664
|
+
if [ "$AGENT_COUNT" -gt 0 ]; then
|
|
665
|
+
pass "agents copied ($AGENT_COUNT files)"
|
|
666
|
+
else
|
|
667
|
+
fail_case "agents copied" "count=$AGENT_COUNT"
|
|
668
|
+
fi
|
|
669
|
+
|
|
670
|
+
# 46. Rules copied
|
|
671
|
+
RULE_COUNT=$(ls "$TMP/.claude/rules/" 2>/dev/null | wc -l)
|
|
672
|
+
if [ "$RULE_COUNT" -gt 0 ]; then
|
|
673
|
+
pass "rules copied ($RULE_COUNT files)"
|
|
674
|
+
else
|
|
675
|
+
fail_case "rules copied" "count=$RULE_COUNT"
|
|
676
|
+
fi
|
|
677
|
+
|
|
678
|
+
# 47. Config version matches package.json version
|
|
679
|
+
if grep -q "\"version\": \"$PKG_VERSION\"" "$TMP/.claude/.qualia-config.json"; then
|
|
680
|
+
pass "config version matches package.json ($PKG_VERSION)"
|
|
681
|
+
else
|
|
682
|
+
fail_case "config version mismatch"
|
|
683
|
+
fi
|
|
684
|
+
|
|
685
|
+
echo ""
|
|
686
|
+
echo "=== Results: $PASS passed, $FAIL failed ==="
|
|
687
|
+
[ "$FAIL" -eq 0 ] && exit 0 || exit 1
|