qualia-framework 2.6.0 → 3.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/CLAUDE.md +64 -0
- package/README.md +103 -30
- package/agents/builder.md +110 -0
- package/agents/planner.md +134 -0
- package/agents/qa-browser.md +186 -0
- package/agents/verifier.md +221 -0
- package/bin/cli.js +336 -531
- package/bin/install.js +570 -0
- package/bin/qualia-ui.js +299 -0
- package/bin/state.js +630 -0
- package/bin/statusline.js +252 -0
- package/guide.md +63 -0
- package/hooks/auto-update.js +139 -0
- package/hooks/branch-guard.js +47 -0
- package/hooks/migration-guard.js +60 -0
- package/hooks/pre-compact.js +32 -0
- package/hooks/pre-deploy-gate.js +110 -0
- package/hooks/pre-push.js +33 -0
- package/hooks/session-start.js +170 -0
- package/package.json +29 -20
- package/rules/design-reference.md +179 -0
- package/rules/frontend.md +126 -0
- package/skills/qualia/SKILL.md +87 -0
- package/skills/qualia-build/SKILL.md +97 -0
- package/skills/qualia-debug/SKILL.md +87 -0
- package/skills/qualia-design/SKILL.md +93 -0
- package/skills/qualia-handoff/SKILL.md +66 -0
- package/skills/qualia-idk/SKILL.md +8 -0
- package/skills/qualia-learn/SKILL.md +88 -0
- package/skills/qualia-new/SKILL.md +323 -0
- package/{framework/skills → skills}/qualia-optimize/SKILL.md +1 -1
- package/skills/qualia-pause/SKILL.md +63 -0
- package/skills/qualia-plan/SKILL.md +101 -0
- package/skills/qualia-polish/SKILL.md +157 -0
- package/skills/qualia-quick/SKILL.md +37 -0
- package/skills/qualia-report/SKILL.md +105 -0
- package/skills/qualia-resume/SKILL.md +49 -0
- package/skills/qualia-review/SKILL.md +76 -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-verify/SKILL.md +113 -0
- package/templates/DESIGN.md +137 -0
- package/templates/plan.md +28 -0
- package/templates/project.md +22 -0
- package/templates/state.md +27 -0
- package/templates/tracking.json +20 -0
- package/tests/bin.test.sh +673 -0
- package/tests/hooks.test.sh +315 -0
- package/tests/state.test.sh +535 -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-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
package/bin/install.js
ADDED
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { createInterface } = require("readline");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
|
|
7
|
+
// ─── Colors ──────────────────────────────────────────────
|
|
8
|
+
const TEAL = "\x1b[38;2;0;206;209m";
|
|
9
|
+
const DIM = "\x1b[38;2;80;90;100m";
|
|
10
|
+
const GREEN = "\x1b[38;2;52;211;153m";
|
|
11
|
+
const WHITE = "\x1b[38;2;220;225;230m";
|
|
12
|
+
const YELLOW = "\x1b[38;2;234;179;8m";
|
|
13
|
+
const RED = "\x1b[38;2;239;68;68m";
|
|
14
|
+
const RESET = "\x1b[0m";
|
|
15
|
+
|
|
16
|
+
// ─── Team codes ──────────────────────────────────────────
|
|
17
|
+
const TEAM = {
|
|
18
|
+
"QS-FAWZI-01": {
|
|
19
|
+
name: "Fawzi Goussous",
|
|
20
|
+
role: "OWNER",
|
|
21
|
+
description: "Company owner. Full access. Can push to main, approve deploys, edit secrets.",
|
|
22
|
+
},
|
|
23
|
+
"QS-HASAN-02": {
|
|
24
|
+
name: "Hasan",
|
|
25
|
+
role: "EMPLOYEE",
|
|
26
|
+
description: "Developer. Feature branches only. Cannot push to main or edit .env files.",
|
|
27
|
+
},
|
|
28
|
+
"QS-MOAYAD-03": {
|
|
29
|
+
name: "Moayad",
|
|
30
|
+
role: "EMPLOYEE",
|
|
31
|
+
description: "Developer. Feature branches only. Cannot push to main or edit .env files.",
|
|
32
|
+
},
|
|
33
|
+
"QS-RAMA-04": {
|
|
34
|
+
name: "Rama",
|
|
35
|
+
role: "EMPLOYEE",
|
|
36
|
+
description: "Developer. Feature branches only. Cannot push to main or edit .env files.",
|
|
37
|
+
},
|
|
38
|
+
"QS-SALLY-05": {
|
|
39
|
+
name: "Sally",
|
|
40
|
+
role: "EMPLOYEE",
|
|
41
|
+
description: "Developer. Feature branches only. Cannot push to main or edit .env files.",
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const CLAUDE_DIR = path.join(require("os").homedir(), ".claude");
|
|
46
|
+
const FRAMEWORK_DIR = path.resolve(__dirname, "..");
|
|
47
|
+
|
|
48
|
+
let installed = 0;
|
|
49
|
+
let errors = 0;
|
|
50
|
+
|
|
51
|
+
function log(msg) {
|
|
52
|
+
console.log(` ${msg}`);
|
|
53
|
+
}
|
|
54
|
+
function ok(label) {
|
|
55
|
+
installed++;
|
|
56
|
+
log(`${GREEN}✓${RESET} ${label}`);
|
|
57
|
+
}
|
|
58
|
+
function warn(label) {
|
|
59
|
+
errors++;
|
|
60
|
+
log(`${YELLOW}✗${RESET} ${label}`);
|
|
61
|
+
}
|
|
62
|
+
function copy(src, dest) {
|
|
63
|
+
const destDir = path.dirname(dest);
|
|
64
|
+
if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
|
|
65
|
+
fs.copyFileSync(src, dest);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ─── Prompt for code ─────────────────────────────────────
|
|
69
|
+
function askCode() {
|
|
70
|
+
return new Promise((resolve) => {
|
|
71
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
72
|
+
console.log("");
|
|
73
|
+
console.log(`${TEAL} ⬢ Qualia Framework v2${RESET}`);
|
|
74
|
+
console.log(`${DIM} ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);
|
|
75
|
+
console.log("");
|
|
76
|
+
rl.question(` ${WHITE}Enter install code:${RESET} `, (answer) => {
|
|
77
|
+
rl.close();
|
|
78
|
+
resolve(answer.trim());
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ─── Resolve team code (tolerates case + O/0 typo in suffix) ─
|
|
84
|
+
// Accepts "qs-fawzi-01", "QS-FAWZI-01", "QS-FAWZI-O1" (letter O in the
|
|
85
|
+
// numeric suffix), and returns the canonical key if found, else null.
|
|
86
|
+
// Only normalizes O→0 in the segment AFTER the last dash — "QS-MOAYAD-03"
|
|
87
|
+
// contains a real "O" in the name and must not be mangled.
|
|
88
|
+
function resolveTeamCode(input) {
|
|
89
|
+
const normalized = String(input || "").trim().toUpperCase();
|
|
90
|
+
if (TEAM[normalized]) return normalized;
|
|
91
|
+
const fuzzy = normalized.replace(
|
|
92
|
+
/-([^-]*)$/,
|
|
93
|
+
(_, suffix) => `-${suffix.replace(/O/g, "0")}`
|
|
94
|
+
);
|
|
95
|
+
if (TEAM[fuzzy]) return fuzzy;
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ─── Main ────────────────────────────────────────────────
|
|
100
|
+
async function main() {
|
|
101
|
+
const rawCode = await askCode();
|
|
102
|
+
const code = resolveTeamCode(rawCode);
|
|
103
|
+
const member = code ? TEAM[code] : null;
|
|
104
|
+
|
|
105
|
+
if (!member) {
|
|
106
|
+
console.log("");
|
|
107
|
+
log(`${RED}✗${RESET} Invalid code: "${rawCode}". Get your install code from Fawzi.`);
|
|
108
|
+
log(`${DIM} Tip: codes use digit zero, not letter O. Format: QS-NAME-01${RESET}`);
|
|
109
|
+
console.log("");
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
console.log("");
|
|
114
|
+
log(`${GREEN}✓${RESET} ${WHITE}${member.name}${RESET} ${DIM}(${member.role})${RESET}`);
|
|
115
|
+
console.log("");
|
|
116
|
+
log(`Installing to ${WHITE}${CLAUDE_DIR}${RESET}`);
|
|
117
|
+
console.log("");
|
|
118
|
+
|
|
119
|
+
// ─── Skills ──────────────────────────────────────────
|
|
120
|
+
const skillsDir = path.join(FRAMEWORK_DIR, "skills");
|
|
121
|
+
const skills = fs
|
|
122
|
+
.readdirSync(skillsDir)
|
|
123
|
+
.filter((d) => fs.statSync(path.join(skillsDir, d)).isDirectory());
|
|
124
|
+
|
|
125
|
+
log(`${WHITE}Skills${RESET}`);
|
|
126
|
+
for (const skill of skills) {
|
|
127
|
+
try {
|
|
128
|
+
copy(
|
|
129
|
+
path.join(skillsDir, skill, "SKILL.md"),
|
|
130
|
+
path.join(CLAUDE_DIR, "skills", skill, "SKILL.md")
|
|
131
|
+
);
|
|
132
|
+
ok(skill);
|
|
133
|
+
} catch (e) {
|
|
134
|
+
warn(`${skill} — ${e.message}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ─── Agents ────────────────────────────────────────────
|
|
139
|
+
log(`${WHITE}Agents${RESET}`);
|
|
140
|
+
const agentsDir = path.join(FRAMEWORK_DIR, "agents");
|
|
141
|
+
for (const file of fs.readdirSync(agentsDir)) {
|
|
142
|
+
try {
|
|
143
|
+
copy(path.join(agentsDir, file), path.join(CLAUDE_DIR, "agents", file));
|
|
144
|
+
ok(file);
|
|
145
|
+
} catch (e) {
|
|
146
|
+
warn(`${file} — ${e.message}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ─── Rules ─────────────────────────────────────────────
|
|
151
|
+
log(`${WHITE}Rules${RESET}`);
|
|
152
|
+
const rulesDir = path.join(FRAMEWORK_DIR, "rules");
|
|
153
|
+
for (const file of fs.readdirSync(rulesDir)) {
|
|
154
|
+
try {
|
|
155
|
+
copy(path.join(rulesDir, file), path.join(CLAUDE_DIR, "rules", file));
|
|
156
|
+
ok(file);
|
|
157
|
+
} catch (e) {
|
|
158
|
+
warn(`${file} — ${e.message}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ─── Hooks ─────────────────────────────────────────────
|
|
163
|
+
log(`${WHITE}Hooks${RESET}`);
|
|
164
|
+
const hooksSource = path.join(FRAMEWORK_DIR, "hooks");
|
|
165
|
+
const hooksDest = path.join(CLAUDE_DIR, "hooks");
|
|
166
|
+
if (!fs.existsSync(hooksDest)) fs.mkdirSync(hooksDest, { recursive: true });
|
|
167
|
+
// Clean up legacy .sh hooks from previous installs so no orphans
|
|
168
|
+
// remain on disk after upgrading to the pure-Node hooks.
|
|
169
|
+
// Also purge explicitly-deprecated hooks by name (these are no longer
|
|
170
|
+
// shipped in framework/hooks/ but may linger on existing installs).
|
|
171
|
+
const DEPRECATED_HOOKS = [
|
|
172
|
+
"block-env-edit.js", // v3.2.0: team decision to unblock .env read/write
|
|
173
|
+
];
|
|
174
|
+
try {
|
|
175
|
+
for (const f of fs.readdirSync(hooksDest)) {
|
|
176
|
+
if (f.endsWith(".sh") || DEPRECATED_HOOKS.includes(f)) {
|
|
177
|
+
try { fs.unlinkSync(path.join(hooksDest, f)); } catch {}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
} catch {}
|
|
181
|
+
for (const file of fs.readdirSync(hooksSource)) {
|
|
182
|
+
try {
|
|
183
|
+
const dest = path.join(hooksDest, file);
|
|
184
|
+
copy(path.join(hooksSource, file), dest);
|
|
185
|
+
// chmod is a no-op on Windows but harmless
|
|
186
|
+
fs.chmodSync(dest, 0o755);
|
|
187
|
+
ok(file);
|
|
188
|
+
} catch (e) {
|
|
189
|
+
warn(`${file} — ${e.message}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ─── Status line ───────────────────────────────────────
|
|
194
|
+
log(`${WHITE}Status line${RESET}`);
|
|
195
|
+
try {
|
|
196
|
+
const slDest = path.join(CLAUDE_DIR, "bin", "statusline.js");
|
|
197
|
+
copy(path.join(FRAMEWORK_DIR, "bin", "statusline.js"), slDest);
|
|
198
|
+
ok("statusline.js");
|
|
199
|
+
} catch (e) {
|
|
200
|
+
warn(`statusline.js — ${e.message}`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ─── Templates ─────────────────────────────────────────
|
|
204
|
+
log(`${WHITE}Templates${RESET}`);
|
|
205
|
+
const tmplDir = path.join(FRAMEWORK_DIR, "templates");
|
|
206
|
+
const tmplDest = path.join(CLAUDE_DIR, "qualia-templates");
|
|
207
|
+
if (!fs.existsSync(tmplDest)) fs.mkdirSync(tmplDest, { recursive: true });
|
|
208
|
+
for (const file of fs.readdirSync(tmplDir)) {
|
|
209
|
+
try {
|
|
210
|
+
copy(path.join(tmplDir, file), path.join(tmplDest, file));
|
|
211
|
+
ok(file);
|
|
212
|
+
} catch (e) {
|
|
213
|
+
warn(`${file} — ${e.message}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// ─── CLAUDE.md with role ───────────────────────────────
|
|
218
|
+
log(`${WHITE}CLAUDE.md${RESET}`);
|
|
219
|
+
try {
|
|
220
|
+
let claudeMd = fs.readFileSync(
|
|
221
|
+
path.join(FRAMEWORK_DIR, "CLAUDE.md"),
|
|
222
|
+
"utf8"
|
|
223
|
+
);
|
|
224
|
+
claudeMd = claudeMd.replace("{{ROLE}}", member.role);
|
|
225
|
+
claudeMd = claudeMd.replace("{{ROLE_DESCRIPTION}}", member.description);
|
|
226
|
+
const claudeDest = path.join(CLAUDE_DIR, "CLAUDE.md");
|
|
227
|
+
fs.writeFileSync(claudeDest, claudeMd, "utf8");
|
|
228
|
+
ok(`Configured as ${member.role}`);
|
|
229
|
+
} catch (e) {
|
|
230
|
+
warn(`CLAUDE.md — ${e.message}`);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// ─── Scripts ─────────────────────────────────────────────
|
|
234
|
+
log(`${WHITE}Scripts${RESET}`);
|
|
235
|
+
try {
|
|
236
|
+
const binDest = path.join(CLAUDE_DIR, "bin");
|
|
237
|
+
if (!fs.existsSync(binDest)) fs.mkdirSync(binDest, { recursive: true });
|
|
238
|
+
copy(
|
|
239
|
+
path.join(FRAMEWORK_DIR, "bin", "state.js"),
|
|
240
|
+
path.join(binDest, "state.js")
|
|
241
|
+
);
|
|
242
|
+
ok("state.js (state machine)");
|
|
243
|
+
copy(
|
|
244
|
+
path.join(FRAMEWORK_DIR, "bin", "qualia-ui.js"),
|
|
245
|
+
path.join(binDest, "qualia-ui.js")
|
|
246
|
+
);
|
|
247
|
+
fs.chmodSync(path.join(binDest, "qualia-ui.js"), 0o755);
|
|
248
|
+
ok("qualia-ui.js (cosmetics library)");
|
|
249
|
+
copy(
|
|
250
|
+
path.join(FRAMEWORK_DIR, "bin", "statusline.js"),
|
|
251
|
+
path.join(binDest, "statusline.js")
|
|
252
|
+
);
|
|
253
|
+
ok("statusline.js (status bar renderer)");
|
|
254
|
+
} catch (e) {
|
|
255
|
+
warn(`scripts — ${e.message}`);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// ─── Guide ─────────────────────────────────────────────
|
|
259
|
+
try {
|
|
260
|
+
copy(
|
|
261
|
+
path.join(FRAMEWORK_DIR, "guide.md"),
|
|
262
|
+
path.join(CLAUDE_DIR, "qualia-guide.md")
|
|
263
|
+
);
|
|
264
|
+
ok("guide.md");
|
|
265
|
+
} catch (e) {
|
|
266
|
+
warn(`guide.md — ${e.message}`);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ─── Knowledge directory ─────────────────────────────────
|
|
270
|
+
log(`${WHITE}Knowledge${RESET}`);
|
|
271
|
+
const knowledgeDir = path.join(CLAUDE_DIR, "knowledge");
|
|
272
|
+
if (!fs.existsSync(knowledgeDir)) fs.mkdirSync(knowledgeDir, { recursive: true });
|
|
273
|
+
const knowledgeFiles = {
|
|
274
|
+
"learned-patterns.md": `# Learned Patterns
|
|
275
|
+
|
|
276
|
+
Patterns discovered across projects. Updated by \`/qualia-learn\` and manual notes.
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## Cross-platform Node: always spawnSync with argv, never execSync with shell strings
|
|
281
|
+
**Why:** \`execSync(\\\`node \${path}/state.js check 2>/dev/null\\\`)\` breaks on Windows when the path contains spaces (common: \`C:\\\\Users\\\\John Doe\`) and the \`2>/dev/null\` redirect is bash-only. Windows cmd.exe tries to create \`\\\\dev\\\\null\` at drive root.
|
|
282
|
+
**How:** Use \`spawnSync(process.execPath, [path, "check"], { stdio: ["ignore","pipe","ignore"] })\`. Argv array is immune to path splitting; \`stdio: "ignore"\` silences stderr without shell redirection.
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Cross-platform stdin piping: spawnSync with input:, not bash <<< here-strings
|
|
287
|
+
**Why:** The \`<<<\` bash here-string works on bash + zsh but fails silently on Windows cmd.exe AND on Debian/Ubuntu where \`/bin/sh\` is dash (no \`<<<\` support).
|
|
288
|
+
**How:** \`spawnSync("npx", ["cmd"], { input: "data\\\\n", stdio: ["pipe","inherit","inherit"], shell: process.platform === "win32" })\`. The \`input:\` option pipes stdin directly. \`shell: process.platform === "win32"\` is required because npm/npx are \`.cmd\` shims on Windows that only resolve through a shell.
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## Fresh-context isolation beats shared-context compression
|
|
293
|
+
**Why:** Claude's output quality degrades as context fills. A single massive context doing plan + build + verify hits the degradation curve on the later tasks.
|
|
294
|
+
**How:** Spawn separate subagents for planner / builder (per task) / verifier. Each gets fresh context. Task 50 gets the same quality as task 1. Cost: PROJECT.md + STATE.md get re-loaded into each subagent context, but the quality win dominates.
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Goal-backward verification beats task-completion tracking
|
|
299
|
+
**Why:** A task "create chat component" can be marked complete with a placeholder file. The task ran; the goal didn't.
|
|
300
|
+
**How:** For each phase success criterion, do a 3-level check: (1) what must be TRUE, (2) what files/functions must EXIST and be substantive (not stubs), (3) what must be CONNECTED (imported and called). Grep the codebase. Never trust summaries.
|
|
301
|
+
`,
|
|
302
|
+
"common-fixes.md": `# Common Fixes
|
|
303
|
+
|
|
304
|
+
Recurring issues and their solutions.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## Install code "Invalid" — user typed letter O instead of digit 0
|
|
309
|
+
**Symptom:** \`npx qualia-framework install\` rejects \`QS-NAME-O1\` (letter O in suffix).
|
|
310
|
+
**Cause:** Team codes use digit zero (\`-01\`, \`-02\`, etc.), not letter O.
|
|
311
|
+
**Fix:** Since v2.8.1, install.js auto-normalizes: \`QS-FAWZI-O1\` → \`QS-FAWZI-01\`. The normalization only touches the segment after the last dash, so \`QS-MOAYAD-03\` (real O in name) is preserved.
|
|
312
|
+
**Framework version:** Fixed in v2.8.1.
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## Windows banner shows "No project detected" inside a real project
|
|
317
|
+
**Symptom:** The session-start banner from qualia-ui.js displays the router panel but without phase/status, even in a project with \`.planning/\`.
|
|
318
|
+
**Cause:** Before v2.8.0, \`qualia-ui.js\` called state.js via \`execSync(\\\`node \${path} check 2>/dev/null\\\`)\`. Windows cmd.exe couldn't parse the \`2>/dev/null\` redirect and/or split the path on spaces in the username.
|
|
319
|
+
**Fix:** v2.8.0 switched to \`spawnSync(process.execPath, [statePath, "check"], { stdio: ["ignore","pipe","ignore"] })\`. Argv array + silent stdio = cross-platform safe.
|
|
320
|
+
**Framework version:** Fixed in v2.8.0.
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## \`npx qualia-framework update\` fails on Windows or Ubuntu
|
|
325
|
+
**Symptom:** Manual update command fails silently or with a shell parse error on Windows and Debian/Ubuntu.
|
|
326
|
+
**Cause:** Before v2.8.0, cli.js cmdUpdate used \`execSync(\\\`npx ... install <<< "\${code}"\\\`, { shell: true })\`. The \`<<<\` here-string is bash-only; cmd.exe doesn't understand it, and \`/bin/sh\` on Debian/Ubuntu is \`dash\` which also lacks it.
|
|
327
|
+
**Fix:** v2.8.0 replaced with \`spawnSync("npx", [...], { input: code + "\\\\n", shell: process.platform === "win32" })\`. Uses stdin pipe instead of here-string.
|
|
328
|
+
**Framework version:** Fixed in v2.8.0.
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Pre-deploy gate false-positive on Next.js Server Components using service_role
|
|
333
|
+
**Symptom:** \`/qualia-ship\` is blocked with "service_role found in client code" for a file that's actually a Server Component (runs server-side only).
|
|
334
|
+
**Cause:** pre-deploy-gate.js skips files matching \`.server.\` filename pattern OR \`server/\` directory path. If the Server Component is at \`app/admin/page.tsx\` (no .server. marker, not in a server/ dir), the scan flags it.
|
|
335
|
+
**Workaround:** Rename to \`.server.tsx\` OR move to a \`server/\` subdirectory OR extract the service_role usage into a helper in \`lib/server/\`.
|
|
336
|
+
**Framework version:** Known issue; better heuristic planned for a future release.
|
|
337
|
+
`,
|
|
338
|
+
"client-prefs.md": `# Client Preferences
|
|
339
|
+
|
|
340
|
+
Client-specific preferences, design choices, and requirements. Loaded by \`/qualia-new\` when starting a project for a known client.
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## Example Client (template)
|
|
345
|
+
**Industry:** {e.g., fintech, healthcare, SaaS}
|
|
346
|
+
**Contact:** {email}
|
|
347
|
+
**Design:** {dark-bold | clean-minimal | colorful-playful | corporate-professional}
|
|
348
|
+
**Stack preferences:** {anything non-default}
|
|
349
|
+
**Hard constraints:** {things they've explicitly said no to}
|
|
350
|
+
**Source of notes:** {date or conversation reference}
|
|
351
|
+
`,
|
|
352
|
+
};
|
|
353
|
+
for (const [name, defaultContent] of Object.entries(knowledgeFiles)) {
|
|
354
|
+
const dest = path.join(knowledgeDir, name);
|
|
355
|
+
if (!fs.existsSync(dest)) {
|
|
356
|
+
fs.writeFileSync(dest, defaultContent);
|
|
357
|
+
ok(`${name} (created)`);
|
|
358
|
+
} else {
|
|
359
|
+
ok(`${name} (exists)`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// ─── Save config (for update command) ──────────────────
|
|
364
|
+
const configFile = path.join(CLAUDE_DIR, ".qualia-config.json");
|
|
365
|
+
const config = {
|
|
366
|
+
code,
|
|
367
|
+
installed_by: member.name,
|
|
368
|
+
role: member.role,
|
|
369
|
+
version: require("../package.json").version,
|
|
370
|
+
installed_at: new Date().toISOString().split("T")[0],
|
|
371
|
+
};
|
|
372
|
+
fs.writeFileSync(configFile, JSON.stringify(config, null, 2) + "\n");
|
|
373
|
+
|
|
374
|
+
// ─── ERP API key (for report uploads) ──────────────────
|
|
375
|
+
log(`${WHITE}ERP integration${RESET}`);
|
|
376
|
+
const erpKeyFile = path.join(CLAUDE_DIR, ".erp-api-key");
|
|
377
|
+
if (!fs.existsSync(erpKeyFile)) {
|
|
378
|
+
fs.writeFileSync(erpKeyFile, "qualia-claude-2026", { mode: 0o600 });
|
|
379
|
+
ok(".erp-api-key (created)");
|
|
380
|
+
} else {
|
|
381
|
+
ok(".erp-api-key (exists)");
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// ─── Configure settings.json ───────────────────────────
|
|
385
|
+
console.log("");
|
|
386
|
+
log(`${WHITE}Configuring settings.json...${RESET}`);
|
|
387
|
+
|
|
388
|
+
const settingsPath = path.join(CLAUDE_DIR, "settings.json");
|
|
389
|
+
let settings = {};
|
|
390
|
+
if (fs.existsSync(settingsPath)) {
|
|
391
|
+
try {
|
|
392
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
|
|
393
|
+
} catch {}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Env
|
|
397
|
+
if (!settings.env) settings.env = {};
|
|
398
|
+
Object.assign(settings.env, {
|
|
399
|
+
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1",
|
|
400
|
+
CLAUDE_CODE_DISABLE_AUTO_MEMORY: "0",
|
|
401
|
+
MAX_MCP_OUTPUT_TOKENS: "25000",
|
|
402
|
+
CLAUDE_CODE_NO_FLICKER: "1",
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
// Status line
|
|
406
|
+
settings.statusLine = {
|
|
407
|
+
type: "command",
|
|
408
|
+
command: `node "${path.join(CLAUDE_DIR, "bin", "statusline.js")}"`,
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
// Spinner
|
|
412
|
+
settings.spinnerVerbs = {
|
|
413
|
+
mode: "replace",
|
|
414
|
+
verbs: [
|
|
415
|
+
"Qualia-fying",
|
|
416
|
+
"Solution-ing",
|
|
417
|
+
"Teal-crafting",
|
|
418
|
+
"Vibe-forging",
|
|
419
|
+
"Shipping",
|
|
420
|
+
"Wiring",
|
|
421
|
+
"Polishing",
|
|
422
|
+
"Verifying",
|
|
423
|
+
"Orchestrating",
|
|
424
|
+
"Architecting",
|
|
425
|
+
"Deploying",
|
|
426
|
+
"Hardening",
|
|
427
|
+
],
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
settings.spinnerTipsOverride = {
|
|
431
|
+
excludeDefault: true,
|
|
432
|
+
tips: [
|
|
433
|
+
"⬢ Lost? Type /qualia for the next step",
|
|
434
|
+
"⬢ Small fix? Use /qualia-quick to skip planning",
|
|
435
|
+
"⬢ End of day? /qualia-report before you clock out",
|
|
436
|
+
"⬢ Context isolation: every task gets a fresh AI brain",
|
|
437
|
+
"⬢ The verifier doesn't trust claims — it greps the code",
|
|
438
|
+
"⬢ Plans are prompts — the plan IS what the builder reads",
|
|
439
|
+
"⬢ Feature branches only — never push to main",
|
|
440
|
+
"⬢ Read before write — no exceptions",
|
|
441
|
+
"⬢ MVP first — build what's asked, nothing extra",
|
|
442
|
+
"⬢ tracking.json syncs to ERP on every push",
|
|
443
|
+
],
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
// Hooks — pure Node.js, cross-platform (Windows/macOS/Linux).
|
|
447
|
+
// Every hook command is `node <absolute-path-to-hook.js>` which avoids the
|
|
448
|
+
// bash/Git Bash requirement on Windows.
|
|
449
|
+
const hd = path.join(CLAUDE_DIR, "hooks");
|
|
450
|
+
const nodeCmd = (hookFile) => `node "${path.join(hd, hookFile)}"`;
|
|
451
|
+
settings.hooks = {
|
|
452
|
+
SessionStart: [
|
|
453
|
+
{
|
|
454
|
+
matcher: ".*",
|
|
455
|
+
hooks: [
|
|
456
|
+
{
|
|
457
|
+
type: "command",
|
|
458
|
+
command: nodeCmd("session-start.js"),
|
|
459
|
+
timeout: 5,
|
|
460
|
+
},
|
|
461
|
+
],
|
|
462
|
+
},
|
|
463
|
+
],
|
|
464
|
+
PreToolUse: [
|
|
465
|
+
{
|
|
466
|
+
matcher: "Bash",
|
|
467
|
+
hooks: [
|
|
468
|
+
{
|
|
469
|
+
type: "command",
|
|
470
|
+
command: nodeCmd("auto-update.js"),
|
|
471
|
+
timeout: 5,
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
type: "command",
|
|
475
|
+
if: "Bash(git push*)",
|
|
476
|
+
command: nodeCmd("branch-guard.js"),
|
|
477
|
+
timeout: 10,
|
|
478
|
+
statusMessage: "⬢ Checking branch permissions...",
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
type: "command",
|
|
482
|
+
if: "Bash(git push*)",
|
|
483
|
+
command: nodeCmd("pre-push.js"),
|
|
484
|
+
timeout: 15,
|
|
485
|
+
statusMessage: "⬢ Syncing tracking...",
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
type: "command",
|
|
489
|
+
if: "Bash(vercel --prod*)",
|
|
490
|
+
command: nodeCmd("pre-deploy-gate.js"),
|
|
491
|
+
timeout: 180,
|
|
492
|
+
statusMessage: "⬢ Running quality gates...",
|
|
493
|
+
},
|
|
494
|
+
],
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
matcher: "Edit|Write",
|
|
498
|
+
hooks: [
|
|
499
|
+
{
|
|
500
|
+
type: "command",
|
|
501
|
+
if: "Edit(*migration*)|Write(*migration*)|Edit(*.sql)|Write(*.sql)",
|
|
502
|
+
command: nodeCmd("migration-guard.js"),
|
|
503
|
+
timeout: 10,
|
|
504
|
+
statusMessage: "⬢ Checking migration safety...",
|
|
505
|
+
},
|
|
506
|
+
],
|
|
507
|
+
},
|
|
508
|
+
],
|
|
509
|
+
PreCompact: [
|
|
510
|
+
{
|
|
511
|
+
matcher: "compact",
|
|
512
|
+
hooks: [
|
|
513
|
+
{
|
|
514
|
+
type: "command",
|
|
515
|
+
command: nodeCmd("pre-compact.js"),
|
|
516
|
+
timeout: 15,
|
|
517
|
+
statusMessage: "⬢ Saving state...",
|
|
518
|
+
},
|
|
519
|
+
],
|
|
520
|
+
},
|
|
521
|
+
],
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
// Permissions
|
|
525
|
+
if (!settings.permissions) settings.permissions = {};
|
|
526
|
+
if (!settings.permissions.allow) settings.permissions.allow = [];
|
|
527
|
+
if (!settings.permissions.deny) {
|
|
528
|
+
settings.permissions.deny = [
|
|
529
|
+
"Read(./.env)",
|
|
530
|
+
"Read(./.env.*)",
|
|
531
|
+
"Read(./secrets/**)",
|
|
532
|
+
];
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
536
|
+
|
|
537
|
+
ok("Hooks: session-start, auto-update, branch-guard, pre-push, env-block, migration-guard, deploy-gate, pre-compact");
|
|
538
|
+
ok("Status line + spinner configured");
|
|
539
|
+
ok("Environment variables + permissions");
|
|
540
|
+
|
|
541
|
+
// ─── Summary ───────────────────────────────────────────
|
|
542
|
+
console.log("");
|
|
543
|
+
console.log(`${TEAL} ⬢ Installed ✓${RESET}`);
|
|
544
|
+
console.log(`${DIM} ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);
|
|
545
|
+
console.log(` ${WHITE}${member.name}${RESET} ${DIM}(${member.role})${RESET}`);
|
|
546
|
+
console.log(` Skills: ${WHITE}${skills.length}${RESET}`);
|
|
547
|
+
const agentCount = fs.readdirSync(agentsDir).filter(f => f.endsWith('.md')).length;
|
|
548
|
+
console.log(` Agents: ${WHITE}${agentCount}${RESET} ${DIM}(planner, builder, verifier, qa-browser)${RESET}`);
|
|
549
|
+
console.log(` Hooks: ${WHITE}8${RESET} ${DIM}(session-start, auto-update, branch-guard, pre-push, env-block, migration-guard, deploy-gate, pre-compact)${RESET}`);
|
|
550
|
+
console.log(` Rules: ${WHITE}${fs.readdirSync(rulesDir).length}${RESET} ${DIM}(security, frontend, design-reference, deployment)${RESET}`);
|
|
551
|
+
console.log(` Scripts: ${WHITE}3${RESET} ${DIM}(state.js, qualia-ui.js, statusline.js)${RESET}`);
|
|
552
|
+
console.log(` Knowledge: ${WHITE}3${RESET} ${DIM}(patterns, fixes, client prefs)${RESET}`);
|
|
553
|
+
console.log(` Templates: ${WHITE}${fs.readdirSync(tmplDir).length}${RESET}`);
|
|
554
|
+
console.log(` Status line: ${GREEN}✓${RESET}`);
|
|
555
|
+
console.log(` CLAUDE.md: ${GREEN}✓${RESET} ${DIM}(${member.role})${RESET}`);
|
|
556
|
+
|
|
557
|
+
if (errors > 0) {
|
|
558
|
+
console.log("");
|
|
559
|
+
console.log(` ${YELLOW}${errors} warning(s)${RESET} — check output above`);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
console.log("");
|
|
563
|
+
console.log(` Restart Claude Code, then type ${TEAL}/qualia${RESET} in any project.`);
|
|
564
|
+
console.log("");
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
main().catch((e) => {
|
|
568
|
+
console.error(`${RED} ✗ Installation failed: ${e.message}${RESET}`);
|
|
569
|
+
process.exit(1);
|
|
570
|
+
});
|