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