qualia-framework 2.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/README.md +50 -0
- package/bin/cli.js +519 -0
- package/framework/agents/architecture-strategist.md +53 -0
- package/framework/agents/backend-agent.md +150 -0
- package/framework/agents/code-simplicity-reviewer.md +86 -0
- package/framework/agents/frontend-agent.md +111 -0
- package/framework/agents/kieran-typescript-reviewer.md +96 -0
- package/framework/agents/performance-oracle.md +111 -0
- package/framework/agents/qualia-codebase-mapper.md +760 -0
- package/framework/agents/qualia-debugger.md +1203 -0
- package/framework/agents/qualia-executor.md +881 -0
- package/framework/agents/qualia-integration-checker.md +423 -0
- package/framework/agents/qualia-phase-researcher.md +453 -0
- package/framework/agents/qualia-plan-checker.md +699 -0
- package/framework/agents/qualia-planner.md +1241 -0
- package/framework/agents/qualia-project-researcher.md +602 -0
- package/framework/agents/qualia-research-synthesizer.md +236 -0
- package/framework/agents/qualia-roadmapper.md +605 -0
- package/framework/agents/qualia-verifier.md +685 -0
- package/framework/agents/team-orchestrator.md +228 -0
- package/framework/agents/teams/full-stack-team.md +48 -0
- package/framework/agents/teams/optimize-team.md +53 -0
- package/framework/agents/teams/review-team.md +62 -0
- package/framework/agents/teams/ship-team.md +86 -0
- package/framework/agents/test-agent.md +182 -0
- package/framework/askpass.sh +2 -0
- package/framework/commands/design.md +53 -0
- package/framework/commands/quick-db.md +22 -0
- package/framework/config/retention.json +35 -0
- package/framework/core/PRINCIPLES.md +77 -0
- package/framework/hooks/auto-format.sh +45 -0
- package/framework/hooks/block-env-edit.sh +42 -0
- package/framework/hooks/branch-guard.sh +46 -0
- package/framework/hooks/confirm-delete.sh +56 -0
- package/framework/hooks/migration-validate.sh +68 -0
- package/framework/hooks/notification-speak.sh +15 -0
- package/framework/hooks/pre-commit.sh +80 -0
- package/framework/hooks/pre-compact.sh +55 -0
- package/framework/hooks/pre-deploy-gate.sh +151 -0
- package/framework/hooks/qualia-colors.sh +32 -0
- package/framework/hooks/retention-cleanup.sh +43 -0
- package/framework/hooks/save-session-state.sh +153 -0
- package/framework/hooks/session-context-loader.sh +28 -0
- package/framework/hooks/session-learn.sh +30 -0
- package/framework/knowledge/claudecode-bible.md +1384 -0
- package/framework/knowledge/client-prefs.md +22 -0
- package/framework/knowledge/common-fixes.md +25 -0
- package/framework/knowledge/deployment-map.md +35 -0
- package/framework/knowledge/email-signature.html +1 -0
- package/framework/knowledge/employees.md +8 -0
- package/framework/knowledge/learned-patterns.md +51 -0
- package/framework/knowledge/optimization-research-2026.md +137 -0
- package/framework/knowledge/qualia-context.md +67 -0
- package/framework/knowledge/supabase-patterns.md +50 -0
- package/framework/knowledge/voice-agent-patterns.md +46 -0
- package/framework/qualia-engine/VERSION +1 -0
- package/framework/qualia-engine/bin/qualia-tools.js +2160 -0
- package/framework/qualia-engine/bin/qualia-tools.test.js +1054 -0
- package/framework/qualia-engine/references/checkpoints.md +775 -0
- package/framework/qualia-engine/references/continuation-format.md +249 -0
- package/framework/qualia-engine/references/decimal-phase-calculation.md +65 -0
- package/framework/qualia-engine/references/design-quality.md +56 -0
- package/framework/qualia-engine/references/git-integration.md +254 -0
- package/framework/qualia-engine/references/git-planning-commit.md +50 -0
- package/framework/qualia-engine/references/model-profile-resolution.md +32 -0
- package/framework/qualia-engine/references/model-profiles.md +73 -0
- package/framework/qualia-engine/references/phase-argument-parsing.md +61 -0
- package/framework/qualia-engine/references/planning-config.md +195 -0
- package/framework/qualia-engine/references/questioning.md +141 -0
- package/framework/qualia-engine/references/tdd.md +263 -0
- package/framework/qualia-engine/references/ui-brand.md +160 -0
- package/framework/qualia-engine/references/verification-patterns.md +612 -0
- package/framework/qualia-engine/templates/DEBUG.md +159 -0
- package/framework/qualia-engine/templates/DESIGN.md +81 -0
- package/framework/qualia-engine/templates/UAT.md +247 -0
- package/framework/qualia-engine/templates/codebase/architecture.md +255 -0
- package/framework/qualia-engine/templates/codebase/concerns.md +310 -0
- package/framework/qualia-engine/templates/codebase/conventions.md +307 -0
- package/framework/qualia-engine/templates/codebase/integrations.md +280 -0
- package/framework/qualia-engine/templates/codebase/stack.md +186 -0
- package/framework/qualia-engine/templates/codebase/structure.md +285 -0
- package/framework/qualia-engine/templates/codebase/testing.md +480 -0
- package/framework/qualia-engine/templates/config.json +35 -0
- package/framework/qualia-engine/templates/context.md +283 -0
- package/framework/qualia-engine/templates/continue-here.md +78 -0
- package/framework/qualia-engine/templates/debug-subagent-prompt.md +91 -0
- package/framework/qualia-engine/templates/discovery.md +146 -0
- package/framework/qualia-engine/templates/milestone-archive.md +123 -0
- package/framework/qualia-engine/templates/milestone.md +115 -0
- package/framework/qualia-engine/templates/phase-prompt.md +567 -0
- package/framework/qualia-engine/templates/planner-subagent-prompt.md +117 -0
- package/framework/qualia-engine/templates/project.md +184 -0
- package/framework/qualia-engine/templates/projects/ai-agent.md +156 -0
- package/framework/qualia-engine/templates/projects/mobile-app.md +181 -0
- package/framework/qualia-engine/templates/projects/voice-agent.md +134 -0
- package/framework/qualia-engine/templates/projects/website.md +137 -0
- package/framework/qualia-engine/templates/requirements.md +231 -0
- package/framework/qualia-engine/templates/research-project/ARCHITECTURE.md +204 -0
- package/framework/qualia-engine/templates/research-project/FEATURES.md +147 -0
- package/framework/qualia-engine/templates/research-project/PITFALLS.md +200 -0
- package/framework/qualia-engine/templates/research-project/STACK.md +120 -0
- package/framework/qualia-engine/templates/research-project/SUMMARY.md +170 -0
- package/framework/qualia-engine/templates/research.md +552 -0
- package/framework/qualia-engine/templates/roadmap.md +202 -0
- package/framework/qualia-engine/templates/state.md +176 -0
- package/framework/qualia-engine/templates/summary-complex.md +59 -0
- package/framework/qualia-engine/templates/summary-minimal.md +41 -0
- package/framework/qualia-engine/templates/summary-standard.md +48 -0
- package/framework/qualia-engine/templates/summary.md +246 -0
- package/framework/qualia-engine/templates/user-setup.md +311 -0
- package/framework/qualia-engine/templates/verification-report.md +322 -0
- package/framework/qualia-engine/workflows/add-phase.md +179 -0
- package/framework/qualia-engine/workflows/add-todo.md +157 -0
- package/framework/qualia-engine/workflows/audit-milestone.md +241 -0
- package/framework/qualia-engine/workflows/check-todos.md +176 -0
- package/framework/qualia-engine/workflows/complete-milestone.md +858 -0
- package/framework/qualia-engine/workflows/diagnose-issues.md +219 -0
- package/framework/qualia-engine/workflows/discovery-phase.md +289 -0
- package/framework/qualia-engine/workflows/discuss-phase.md +534 -0
- package/framework/qualia-engine/workflows/execute-phase.md +559 -0
- package/framework/qualia-engine/workflows/execute-plan.md +438 -0
- package/framework/qualia-engine/workflows/help.md +470 -0
- package/framework/qualia-engine/workflows/insert-phase.md +220 -0
- package/framework/qualia-engine/workflows/list-phase-assumptions.md +178 -0
- package/framework/qualia-engine/workflows/map-codebase.md +327 -0
- package/framework/qualia-engine/workflows/new-milestone.md +363 -0
- package/framework/qualia-engine/workflows/new-project.md +1037 -0
- package/framework/qualia-engine/workflows/pause-work.md +122 -0
- package/framework/qualia-engine/workflows/plan-milestone-gaps.md +256 -0
- package/framework/qualia-engine/workflows/plan-phase.md +422 -0
- package/framework/qualia-engine/workflows/progress.md +354 -0
- package/framework/qualia-engine/workflows/quick.md +252 -0
- package/framework/qualia-engine/workflows/remove-phase.md +326 -0
- package/framework/qualia-engine/workflows/research-phase.md +74 -0
- package/framework/qualia-engine/workflows/resume-project.md +306 -0
- package/framework/qualia-engine/workflows/set-profile.md +80 -0
- package/framework/qualia-engine/workflows/settings.md +145 -0
- package/framework/qualia-engine/workflows/transition.md +556 -0
- package/framework/qualia-engine/workflows/update.md +197 -0
- package/framework/qualia-engine/workflows/verify-phase.md +195 -0
- package/framework/qualia-engine/workflows/verify-work.md +625 -0
- package/framework/rules/context7.md +11 -0
- package/framework/rules/deployment.md +29 -0
- package/framework/rules/frontend.md +33 -0
- package/framework/rules/security.md +12 -0
- package/framework/rules/speed.md +20 -0
- package/framework/scripts/__pycache__/say.cpython-314.pyc +0 -0
- package/framework/scripts/apply-retention.sh +120 -0
- package/framework/scripts/bootstrap-pop-os.sh +354 -0
- package/framework/scripts/claude-voice +13 -0
- package/framework/scripts/cleanup.sh +131 -0
- package/framework/scripts/cowork-mode.sh +141 -0
- package/framework/scripts/generate-project-claude-md.sh +153 -0
- package/framework/scripts/load-test-webhook.js +172 -0
- package/framework/scripts/say.py +236 -0
- package/framework/scripts/showcase-video-recorder/ffmpeg-builder.js +167 -0
- package/framework/scripts/showcase-video-recorder/playwright-helpers.js +216 -0
- package/framework/scripts/speak.py +55 -0
- package/framework/scripts/speak.sh +18 -0
- package/framework/scripts/status.sh +138 -0
- package/framework/scripts/sync-to-framework.sh +65 -0
- package/framework/scripts/voice-hotkey.py +227 -0
- package/framework/scripts/voice-input.sh +51 -0
- package/framework/skills/animate/SKILL.md +202 -0
- package/framework/skills/bolder/SKILL.md +144 -0
- package/framework/skills/browser-qa/SKILL.md +536 -0
- package/framework/skills/clarify/SKILL.md +179 -0
- package/framework/skills/colorize/SKILL.md +170 -0
- package/framework/skills/critique/SKILL.md +126 -0
- package/framework/skills/deep-research/SKILL.md +271 -0
- package/framework/skills/delight/SKILL.md +329 -0
- package/framework/skills/deploy/SKILL.md +261 -0
- package/framework/skills/deploy-verify/SKILL.md +377 -0
- package/framework/skills/deploy-verify/scripts/canary-check.sh +206 -0
- package/framework/skills/deploy-verify/scripts/check-console-errors.js +147 -0
- package/framework/skills/deploy-verify/scripts/check-cwv.js +139 -0
- package/framework/skills/deploy-verify/scripts/project-detect.sh +84 -0
- package/framework/skills/deploy-verify/scripts/verify.sh +548 -0
- package/framework/skills/design-quieter/SKILL.md +130 -0
- package/framework/skills/distill/SKILL.md +149 -0
- package/framework/skills/docs-lookup/SKILL.md +78 -0
- package/framework/skills/fcm-notifications/SKILL.md +125 -0
- package/framework/skills/financial-ledger/SKILL.md +1039 -0
- package/framework/skills/frontend-master/NOTICE.md +4 -0
- package/framework/skills/frontend-master/SKILL.md +127 -0
- package/framework/skills/frontend-master/reference/color-and-contrast.md +132 -0
- package/framework/skills/frontend-master/reference/interaction-design.md +123 -0
- package/framework/skills/frontend-master/reference/motion-design.md +99 -0
- package/framework/skills/frontend-master/reference/responsive-design.md +114 -0
- package/framework/skills/frontend-master/reference/spatial-design.md +100 -0
- package/framework/skills/frontend-master/reference/typography.md +131 -0
- package/framework/skills/frontend-master/reference/ux-writing.md +107 -0
- package/framework/skills/harden/SKILL.md +357 -0
- package/framework/skills/i18n-rtl/SKILL.md +752 -0
- package/framework/skills/learn/SKILL.md +71 -0
- package/framework/skills/memory/SKILL.md +50 -0
- package/framework/skills/mobile-expo/SKILL.md +864 -0
- package/framework/skills/mobile-expo/references/store-checklist.md +550 -0
- package/framework/skills/nestjs-backend/README.md +73 -0
- package/framework/skills/nestjs-backend/SKILL.md +446 -0
- package/framework/skills/nestjs-backend/references/templates.md +1173 -0
- package/framework/skills/normalize/SKILL.md +79 -0
- package/framework/skills/onboard/SKILL.md +242 -0
- package/framework/skills/polish/SKILL.md +209 -0
- package/framework/skills/pr/SKILL.md +66 -0
- package/framework/skills/qualia/SKILL.md +153 -0
- package/framework/skills/qualia-add-todo/SKILL.md +68 -0
- package/framework/skills/qualia-audit-milestone/SKILL.md +92 -0
- package/framework/skills/qualia-check-todos/SKILL.md +55 -0
- package/framework/skills/qualia-complete-milestone/SKILL.md +108 -0
- package/framework/skills/qualia-debug/SKILL.md +149 -0
- package/framework/skills/qualia-design/SKILL.md +203 -0
- package/framework/skills/qualia-discuss-phase/SKILL.md +72 -0
- package/framework/skills/qualia-execute-phase/SKILL.md +86 -0
- package/framework/skills/qualia-help/SKILL.md +67 -0
- package/framework/skills/qualia-idk/SKILL.md +352 -0
- package/framework/skills/qualia-list-phase-assumptions/SKILL.md +67 -0
- package/framework/skills/qualia-new-milestone/SKILL.md +72 -0
- package/framework/skills/qualia-new-project/SKILL.md +92 -0
- package/framework/skills/qualia-optimize/SKILL.md +417 -0
- package/framework/skills/qualia-pause-work/SKILL.md +96 -0
- package/framework/skills/qualia-plan-milestone-gaps/SKILL.md +57 -0
- package/framework/skills/qualia-plan-phase/SKILL.md +101 -0
- package/framework/skills/qualia-progress/SKILL.md +53 -0
- package/framework/skills/qualia-quick/SKILL.md +89 -0
- package/framework/skills/qualia-research-phase/SKILL.md +88 -0
- package/framework/skills/qualia-resume-work/SKILL.md +62 -0
- package/framework/skills/qualia-review/SKILL.md +263 -0
- package/framework/skills/qualia-start/SKILL.md +182 -0
- package/framework/skills/qualia-verify-work/SKILL.md +105 -0
- package/framework/skills/qualia-workflow/SKILL.md +130 -0
- package/framework/skills/rag/SKILL.md +750 -0
- package/framework/skills/responsive/SKILL.md +231 -0
- package/framework/skills/retro/SKILL.md +284 -0
- package/framework/skills/sakani-conventions/SKILL.md +136 -0
- package/framework/skills/sakani-conventions/evals/evals.json +23 -0
- package/framework/skills/sakani-conventions/references/entities.md +365 -0
- package/framework/skills/sakani-conventions/references/error-codes.md +95 -0
- package/framework/skills/seo-master/SKILL.md +490 -0
- package/framework/skills/seo-master/references/checklist.md +199 -0
- package/framework/skills/seo-master/references/structured-data.md +609 -0
- package/framework/skills/ship/SKILL.md +202 -0
- package/framework/skills/stack-researcher/SKILL.md +215 -0
- package/framework/skills/status/SKILL.md +154 -0
- package/framework/skills/status/scripts/health-check.sh +562 -0
- package/framework/skills/subscription-payments/SKILL.md +250 -0
- package/framework/skills/supabase/SKILL.md +973 -0
- package/framework/skills/supabase/references/templates.md +159 -0
- package/framework/skills/team/SKILL.md +67 -0
- package/framework/skills/test-runner/SKILL.md +202 -0
- package/framework/skills/voice-agent/SKILL.md +407 -0
- package/framework/skills/zoho-workflow/SKILL.md +51 -0
- package/framework/statusline-command.sh +117 -0
- package/package.json +24 -0
- package/profiles/fawzi.json +16 -0
- package/profiles/hasan.json +16 -0
- package/profiles/moayad.json +16 -0
- package/templates/CLAUDE-owner.md +52 -0
- package/templates/CLAUDE.md.hbs +58 -0
- package/templates/env.claude.template +12 -0
- package/templates/settings.json +141 -0
package/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Qualia Framework
|
|
2
|
+
|
|
3
|
+
Claude Code framework installer for Qualia Solutions team members.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx github:Qualiasolutions/qualia-framework
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Enter your employee code when prompted. Contact Fawzi for your code.
|
|
12
|
+
|
|
13
|
+
## Update
|
|
14
|
+
|
|
15
|
+
Pull latest framework changes (skills, hooks, agents) without touching your config:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx github:Qualiasolutions/qualia-framework update
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Verify
|
|
22
|
+
|
|
23
|
+
Check your installation is healthy:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx github:Qualiasolutions/qualia-framework verify
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## What Gets Installed
|
|
30
|
+
|
|
31
|
+
- `~/.claude/skills/` — 63 Claude Code skills
|
|
32
|
+
- `~/.claude/hooks/` — 13 hook scripts (pre-commit, deploy gate, etc.)
|
|
33
|
+
- `~/.claude/agents/` — 19 agent definitions
|
|
34
|
+
- `~/.claude/rules/` — Security, frontend, deployment, speed rules
|
|
35
|
+
- `~/.claude/qualia-engine/` — Workflow engine
|
|
36
|
+
- `~/.claude/knowledge/` — Shared knowledge base
|
|
37
|
+
- `~/.claude/CLAUDE.md` — Personalized to your role
|
|
38
|
+
- `~/.claude/settings.json` — Merged with your existing config
|
|
39
|
+
|
|
40
|
+
## Employee Codes
|
|
41
|
+
|
|
42
|
+
| Code | Person |
|
|
43
|
+
|------|--------|
|
|
44
|
+
| `QS-HASAN-2026` | Hasan |
|
|
45
|
+
| `QS-MOAYAD-2025` | Moayad |
|
|
46
|
+
|
|
47
|
+
## After Install
|
|
48
|
+
|
|
49
|
+
1. Fill in your API keys in `~/.claude/.env.claude`
|
|
50
|
+
2. Run `/qualia-start` in Claude Code to activate the framework
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const readline = require('readline');
|
|
6
|
+
const { execSync } = require('child_process');
|
|
7
|
+
|
|
8
|
+
const CLAUDE_DIR = path.join(require('os').homedir(), '.claude');
|
|
9
|
+
const PKG_ROOT = path.resolve(__dirname, '..');
|
|
10
|
+
const FRAMEWORK_DIR = path.join(PKG_ROOT, 'framework');
|
|
11
|
+
const PROFILES_DIR = path.join(PKG_ROOT, 'profiles');
|
|
12
|
+
const TEMPLATES_DIR = path.join(PKG_ROOT, 'templates');
|
|
13
|
+
|
|
14
|
+
// ── Colors ──
|
|
15
|
+
const c = {
|
|
16
|
+
reset: '\x1b[0m',
|
|
17
|
+
bold: '\x1b[1m',
|
|
18
|
+
dim: '\x1b[2m',
|
|
19
|
+
green: '\x1b[32m',
|
|
20
|
+
yellow: '\x1b[33m',
|
|
21
|
+
red: '\x1b[31m',
|
|
22
|
+
cyan: '\x1b[36m',
|
|
23
|
+
magenta: '\x1b[35m',
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function log(msg) { console.log(msg); }
|
|
27
|
+
function ok(msg) { log(` ${c.green}\u2713${c.reset} ${msg}`); }
|
|
28
|
+
function warn(msg) { log(` ${c.yellow}\u26A0${c.reset} ${msg}`); }
|
|
29
|
+
function fail(msg) { log(` ${c.red}\u2717${c.reset} ${msg}`); }
|
|
30
|
+
function step(n, total, msg) { log(`\n${c.cyan}[${n}/${total}]${c.reset} ${msg}`); }
|
|
31
|
+
|
|
32
|
+
// ── Helpers ──
|
|
33
|
+
function copyDirSync(src, dest) {
|
|
34
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
35
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
36
|
+
const srcPath = path.join(src, entry.name);
|
|
37
|
+
const destPath = path.join(dest, entry.name);
|
|
38
|
+
if (entry.isDirectory()) {
|
|
39
|
+
copyDirSync(srcPath, destPath);
|
|
40
|
+
} else {
|
|
41
|
+
fs.copyFileSync(srcPath, destPath);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function countDir(dir, type) {
|
|
47
|
+
if (!fs.existsSync(dir)) return 0;
|
|
48
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
49
|
+
if (type === 'dirs') return entries.filter(e => e.isDirectory()).length;
|
|
50
|
+
return entries.filter(e => e.isFile()).length;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function deepMerge(target, source) {
|
|
54
|
+
const result = { ...target };
|
|
55
|
+
for (const key of Object.keys(source)) {
|
|
56
|
+
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])
|
|
57
|
+
&& target[key] && typeof target[key] === 'object' && !Array.isArray(target[key])) {
|
|
58
|
+
result[key] = deepMerge(target[key], source[key]);
|
|
59
|
+
} else if (result[key] === undefined || result[key] === null || result[key] === '') {
|
|
60
|
+
result[key] = source[key];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function loadProfiles() {
|
|
67
|
+
const profiles = {};
|
|
68
|
+
for (const file of fs.readdirSync(PROFILES_DIR)) {
|
|
69
|
+
if (!file.endsWith('.json')) continue;
|
|
70
|
+
const profile = JSON.parse(fs.readFileSync(path.join(PROFILES_DIR, file), 'utf8'));
|
|
71
|
+
profiles[profile.code.toUpperCase()] = profile;
|
|
72
|
+
}
|
|
73
|
+
return profiles;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function renderCLAUDEmd(profile) {
|
|
77
|
+
let template = fs.readFileSync(path.join(TEMPLATES_DIR, 'CLAUDE.md.hbs'), 'utf8');
|
|
78
|
+
|
|
79
|
+
const isOwner = profile.role === 'OWNER';
|
|
80
|
+
const isDeveloper = profile.role === 'DEVELOPER';
|
|
81
|
+
const isArabic = profile.language && profile.language.includes('ar');
|
|
82
|
+
|
|
83
|
+
const roleTitle = isOwner ? 'Founder' : (profile.type === 'full-time' ? 'Full-time Developer' : 'Developer');
|
|
84
|
+
|
|
85
|
+
const replacements = {
|
|
86
|
+
'{{fullName}}': profile.fullName || profile.name,
|
|
87
|
+
'{{name}}': profile.name,
|
|
88
|
+
'{{role}}': profile.role,
|
|
89
|
+
'{{roleTitle}}': roleTitle,
|
|
90
|
+
'{{location}}': profile.location || '',
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
for (const [key, val] of Object.entries(replacements)) {
|
|
94
|
+
template = template.replace(new RegExp(escapeRegex(key), 'g'), val);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Handle conditionals — inner first, then outer
|
|
98
|
+
template = processConditional(template, 'canDeploy', profile.permissions?.canDeploy);
|
|
99
|
+
template = processConditional(template, 'canAccessAllProjects', profile.permissions?.canAccessAllProjects);
|
|
100
|
+
template = processConditional(template, 'isOwner', isOwner);
|
|
101
|
+
template = processConditional(template, 'isDeveloper', isDeveloper);
|
|
102
|
+
template = processConditional(template, 'isArabic', isArabic);
|
|
103
|
+
|
|
104
|
+
// Clean up empty lines
|
|
105
|
+
template = template.replace(/\n{3,}/g, '\n\n');
|
|
106
|
+
|
|
107
|
+
return template;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function escapeRegex(str) {
|
|
111
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function processConditional(text, name, value) {
|
|
115
|
+
const ifRegex = new RegExp(`\\{\\{#if ${name}\\}\\}([\\s\\S]*?)(?:\\{\\{else\\}\\}([\\s\\S]*?))?\\{\\{/if\\}\\}`, 'g');
|
|
116
|
+
return text.replace(ifRegex, (_, ifBlock, elseBlock) => {
|
|
117
|
+
return value ? ifBlock : (elseBlock || '');
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function mergeSettings(existingPath, templatePath) {
|
|
122
|
+
const template = JSON.parse(fs.readFileSync(templatePath, 'utf8'));
|
|
123
|
+
|
|
124
|
+
if (!fs.existsSync(existingPath)) return template;
|
|
125
|
+
|
|
126
|
+
const existing = JSON.parse(fs.readFileSync(existingPath, 'utf8'));
|
|
127
|
+
|
|
128
|
+
// Preserve existing env values (API keys), merge in new ones
|
|
129
|
+
const merged = { ...template };
|
|
130
|
+
if (existing.env) {
|
|
131
|
+
merged.env = { ...template.env };
|
|
132
|
+
for (const [key, val] of Object.entries(existing.env)) {
|
|
133
|
+
if (val && val !== '' && !val.startsWith('$')) {
|
|
134
|
+
merged.env[key] = val;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Overwrite hooks, permissions, statusLine from template (framework-managed)
|
|
140
|
+
merged.hooks = template.hooks;
|
|
141
|
+
merged.permissions = template.permissions;
|
|
142
|
+
merged.statusLine = template.statusLine;
|
|
143
|
+
|
|
144
|
+
// Preserve user's existing plugins and MCP servers
|
|
145
|
+
if (existing.enabledPlugins) {
|
|
146
|
+
merged.enabledPlugins = existing.enabledPlugins;
|
|
147
|
+
}
|
|
148
|
+
if (existing.mcpServers) {
|
|
149
|
+
merged.mcpServers = existing.mcpServers;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return merged;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function prompt(question) {
|
|
156
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
157
|
+
return new Promise(resolve => {
|
|
158
|
+
rl.question(question, answer => {
|
|
159
|
+
rl.close();
|
|
160
|
+
resolve(answer.trim());
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// ── Main ──
|
|
166
|
+
async function main() {
|
|
167
|
+
const command = process.argv[2];
|
|
168
|
+
|
|
169
|
+
if (command === 'update') {
|
|
170
|
+
await runUpdate();
|
|
171
|
+
} else if (command === 'verify') {
|
|
172
|
+
runVerify();
|
|
173
|
+
} else {
|
|
174
|
+
await runInstall();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function runInstall() {
|
|
179
|
+
log('');
|
|
180
|
+
log(`${c.cyan}\u2554${'═'.repeat(54)}\u2557${c.reset}`);
|
|
181
|
+
log(`${c.cyan}\u2551${c.reset}${c.bold} QUALIA FRAMEWORK \u2014 INSTALLER ${c.reset}${c.cyan}\u2551${c.reset}`);
|
|
182
|
+
log(`${c.cyan}\u255A${'═'.repeat(54)}\u255D${c.reset}`);
|
|
183
|
+
log('');
|
|
184
|
+
|
|
185
|
+
const profiles = loadProfiles();
|
|
186
|
+
const code = await prompt(` Enter your employee code: `);
|
|
187
|
+
const profile = profiles[code.toUpperCase()];
|
|
188
|
+
|
|
189
|
+
if (!profile) {
|
|
190
|
+
log('');
|
|
191
|
+
fail(`Unknown code "${code}". Contact Fawzi for your employee code.`);
|
|
192
|
+
log(`${c.dim} Available format: QS-NAME-YEAR${c.reset}`);
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
log('');
|
|
197
|
+
log(` ${c.green}\u2192${c.reset} Welcome, ${c.bold}${profile.name}${c.reset}! Setting up your Qualia environment...`);
|
|
198
|
+
|
|
199
|
+
const TOTAL = 6;
|
|
200
|
+
|
|
201
|
+
// Step 1: Backup existing
|
|
202
|
+
step(1, TOTAL, 'Checking existing ~/.claude/ ...');
|
|
203
|
+
if (fs.existsSync(CLAUDE_DIR)) {
|
|
204
|
+
const date = new Date().toISOString().split('T')[0];
|
|
205
|
+
const backupDir = `${CLAUDE_DIR}.backup-${date}`;
|
|
206
|
+
if (!fs.existsSync(backupDir)) {
|
|
207
|
+
// Don't backup the whole thing — just the config files we'll overwrite
|
|
208
|
+
fs.mkdirSync(backupDir, { recursive: true });
|
|
209
|
+
for (const f of ['CLAUDE.md', 'settings.json', '.env.claude']) {
|
|
210
|
+
const src = path.join(CLAUDE_DIR, f);
|
|
211
|
+
if (fs.existsSync(src)) {
|
|
212
|
+
fs.copyFileSync(src, path.join(backupDir, f));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
ok(`Config backed up to ${c.dim}~/.claude.backup-${date}/${c.reset}`);
|
|
216
|
+
} else {
|
|
217
|
+
ok('Backup already exists for today');
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
fs.mkdirSync(CLAUDE_DIR, { recursive: true });
|
|
221
|
+
ok('Created ~/.claude/');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Step 2: Copy framework files
|
|
225
|
+
step(2, TOTAL, 'Installing framework files ...');
|
|
226
|
+
|
|
227
|
+
const dirs = ['skills', 'hooks', 'agents', 'rules', 'qualia-engine', 'scripts', 'knowledge'];
|
|
228
|
+
for (const dir of dirs) {
|
|
229
|
+
const src = path.join(FRAMEWORK_DIR, dir);
|
|
230
|
+
const dest = path.join(CLAUDE_DIR, dir);
|
|
231
|
+
if (fs.existsSync(src)) {
|
|
232
|
+
copyDirSync(src, dest);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Copy standalone files
|
|
237
|
+
for (const f of ['statusline-command.sh', 'askpass.sh']) {
|
|
238
|
+
const src = path.join(FRAMEWORK_DIR, f);
|
|
239
|
+
if (fs.existsSync(src)) {
|
|
240
|
+
fs.copyFileSync(src, path.join(CLAUDE_DIR, f));
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Make hooks executable
|
|
245
|
+
const hooksDir = path.join(CLAUDE_DIR, 'hooks');
|
|
246
|
+
if (fs.existsSync(hooksDir)) {
|
|
247
|
+
for (const f of fs.readdirSync(hooksDir)) {
|
|
248
|
+
if (f.endsWith('.sh')) {
|
|
249
|
+
fs.chmodSync(path.join(hooksDir, f), 0o755);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
// Make standalone scripts executable
|
|
254
|
+
for (const f of ['statusline-command.sh', 'askpass.sh']) {
|
|
255
|
+
const p = path.join(CLAUDE_DIR, f);
|
|
256
|
+
if (fs.existsSync(p)) fs.chmodSync(p, 0o755);
|
|
257
|
+
}
|
|
258
|
+
// Make qualia-engine bin executable
|
|
259
|
+
const engineBin = path.join(CLAUDE_DIR, 'qualia-engine', 'bin');
|
|
260
|
+
if (fs.existsSync(engineBin)) {
|
|
261
|
+
for (const f of fs.readdirSync(engineBin)) {
|
|
262
|
+
const p = path.join(engineBin, f);
|
|
263
|
+
try { fs.chmodSync(p, 0o755); } catch {}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
ok(`${countDir(path.join(CLAUDE_DIR, 'skills'), 'dirs')} skills`);
|
|
268
|
+
ok(`${countDir(hooksDir, 'files')} hooks (chmod +x)`);
|
|
269
|
+
ok(`${countDir(path.join(CLAUDE_DIR, 'agents'), 'files')} agents`);
|
|
270
|
+
ok(`${countDir(path.join(CLAUDE_DIR, 'rules'), 'files')} rule files`);
|
|
271
|
+
ok('qualia-engine');
|
|
272
|
+
ok('knowledge base');
|
|
273
|
+
|
|
274
|
+
// Step 3: Generate CLAUDE.md
|
|
275
|
+
step(3, TOTAL, 'Generating your CLAUDE.md ...');
|
|
276
|
+
const claudeMd = renderCLAUDEmd(profile);
|
|
277
|
+
fs.writeFileSync(path.join(CLAUDE_DIR, 'CLAUDE.md'), claudeMd);
|
|
278
|
+
|
|
279
|
+
const roleDesc = profile.role === 'OWNER' ? 'Full authority' :
|
|
280
|
+
`Feature branches${profile.permissions?.canDeploy ? ', can deploy' : ', no prod deploy'}`;
|
|
281
|
+
ok(`Identity: ${profile.name} \u2014 ${profile.role === 'OWNER' ? 'Founder' : 'Developer'} at Qualia Solutions`);
|
|
282
|
+
ok(`Role: ${profile.role} (${roleDesc})`);
|
|
283
|
+
|
|
284
|
+
// Step 4: Configure settings.json
|
|
285
|
+
step(4, TOTAL, 'Configuring settings.json ...');
|
|
286
|
+
const settingsPath = path.join(CLAUDE_DIR, 'settings.json');
|
|
287
|
+
const templateSettingsPath = path.join(TEMPLATES_DIR, 'settings.json');
|
|
288
|
+
const mergedSettings = mergeSettings(settingsPath, templateSettingsPath);
|
|
289
|
+
|
|
290
|
+
// Fix SUDO_ASKPASS to absolute path
|
|
291
|
+
mergedSettings.env.SUDO_ASKPASS = path.join(CLAUDE_DIR, 'askpass.sh');
|
|
292
|
+
mergedSettings.env.CLAUDE_ENV_FILE = path.join(CLAUDE_DIR, '.env.claude');
|
|
293
|
+
|
|
294
|
+
fs.writeFileSync(settingsPath, JSON.stringify(mergedSettings, null, 2) + '\n');
|
|
295
|
+
ok('Hooks wired');
|
|
296
|
+
ok('Preserved your existing API keys');
|
|
297
|
+
ok('Settings configured');
|
|
298
|
+
|
|
299
|
+
// Step 5: Environment
|
|
300
|
+
step(5, TOTAL, 'Setting up environment ...');
|
|
301
|
+
const envPath = path.join(CLAUDE_DIR, '.env.claude');
|
|
302
|
+
if (fs.existsSync(envPath)) {
|
|
303
|
+
ok('.env.claude already exists (preserved)');
|
|
304
|
+
} else {
|
|
305
|
+
fs.copyFileSync(path.join(TEMPLATES_DIR, 'env.claude.template'), envPath);
|
|
306
|
+
fs.chmodSync(envPath, 0o600);
|
|
307
|
+
warn(`Fill in your API keys: ${c.dim}~/.claude/.env.claude${c.reset}`);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Create required directories
|
|
311
|
+
for (const d of ['projects', 'session-env', 'backups']) {
|
|
312
|
+
fs.mkdirSync(path.join(CLAUDE_DIR, d), { recursive: true });
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Step 6: Verify
|
|
316
|
+
step(6, TOTAL, 'Verifying installation ...');
|
|
317
|
+
|
|
318
|
+
let hooksOk = 0;
|
|
319
|
+
const hooksTotal = fs.readdirSync(hooksDir).filter(f => f.endsWith('.sh')).length;
|
|
320
|
+
for (const f of fs.readdirSync(hooksDir)) {
|
|
321
|
+
if (!f.endsWith('.sh')) continue;
|
|
322
|
+
try {
|
|
323
|
+
const stat = fs.statSync(path.join(hooksDir, f));
|
|
324
|
+
if (stat.mode & 0o111) hooksOk++;
|
|
325
|
+
} catch {}
|
|
326
|
+
}
|
|
327
|
+
if (hooksOk === hooksTotal) {
|
|
328
|
+
ok(`${hooksOk}/${hooksTotal} hooks executable`);
|
|
329
|
+
} else {
|
|
330
|
+
warn(`${hooksOk}/${hooksTotal} hooks executable`);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
try {
|
|
334
|
+
JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
335
|
+
ok('settings.json valid JSON');
|
|
336
|
+
} catch {
|
|
337
|
+
fail('settings.json invalid JSON!');
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (fs.existsSync(path.join(CLAUDE_DIR, 'CLAUDE.md'))) {
|
|
341
|
+
ok('CLAUDE.md generated');
|
|
342
|
+
} else {
|
|
343
|
+
fail('CLAUDE.md missing!');
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Done
|
|
347
|
+
log('');
|
|
348
|
+
log(`${c.green}\u2554${'═'.repeat(54)}\u2557${c.reset}`);
|
|
349
|
+
log(`${c.green}\u2551${c.reset}${c.bold} \u2713 INSTALLED \u2014 Run /qualia-start in Claude Code ${c.reset}${c.green}\u2551${c.reset}`);
|
|
350
|
+
log(`${c.green}\u255A${'═'.repeat(54)}\u255D${c.reset}`);
|
|
351
|
+
log('');
|
|
352
|
+
log(` ${c.dim}Update later: npx github:Qualiasolutions/qualia-framework update${c.reset}`);
|
|
353
|
+
log('');
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
async function runUpdate() {
|
|
357
|
+
log('');
|
|
358
|
+
log(`${c.cyan}\u25C6 Qualia Framework \u2014 Update${c.reset}`);
|
|
359
|
+
log('');
|
|
360
|
+
|
|
361
|
+
if (!fs.existsSync(CLAUDE_DIR)) {
|
|
362
|
+
fail('No ~/.claude/ found. Run the installer first (without "update").');
|
|
363
|
+
process.exit(1);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Authenticate — always require code on update
|
|
367
|
+
const profiles = loadProfiles();
|
|
368
|
+
const code = await prompt(` Enter your employee code: `);
|
|
369
|
+
const profile = profiles[code.toUpperCase()];
|
|
370
|
+
|
|
371
|
+
if (!profile) {
|
|
372
|
+
log('');
|
|
373
|
+
fail(`Unknown code "${code}". Contact Fawzi for your employee code.`);
|
|
374
|
+
process.exit(1);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
log(` ${c.green}\u2192${c.reset} Updating for ${c.bold}${profile.name}${c.reset} (${profile.role})`);
|
|
378
|
+
log('');
|
|
379
|
+
|
|
380
|
+
// Count what's changing
|
|
381
|
+
const frameworkDirs = ['skills', 'hooks', 'agents', 'rules', 'qualia-engine', 'scripts', 'knowledge'];
|
|
382
|
+
const counts = {};
|
|
383
|
+
let totalFiles = 0;
|
|
384
|
+
|
|
385
|
+
for (const dir of frameworkDirs) {
|
|
386
|
+
const src = path.join(FRAMEWORK_DIR, dir);
|
|
387
|
+
if (fs.existsSync(src)) {
|
|
388
|
+
const count = countFilesRecursive(src);
|
|
389
|
+
counts[dir] = count;
|
|
390
|
+
totalFiles += count;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Show what will be updated
|
|
395
|
+
log(` ${c.bold}Components to update:${c.reset}`);
|
|
396
|
+
for (const [dir, count] of Object.entries(counts)) {
|
|
397
|
+
log(` ${c.dim}\u2022${c.reset} ${dir} (${count} files)`);
|
|
398
|
+
}
|
|
399
|
+
log(` ${c.bold}Total: ${totalFiles} files${c.reset}`);
|
|
400
|
+
log('');
|
|
401
|
+
|
|
402
|
+
// Update framework files
|
|
403
|
+
let updated = 0;
|
|
404
|
+
for (const dir of frameworkDirs) {
|
|
405
|
+
const src = path.join(FRAMEWORK_DIR, dir);
|
|
406
|
+
const dest = path.join(CLAUDE_DIR, dir);
|
|
407
|
+
if (fs.existsSync(src)) {
|
|
408
|
+
copyDirSync(src, dest);
|
|
409
|
+
updated++;
|
|
410
|
+
ok(`${dir} (${counts[dir]} files)`);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Copy standalone files
|
|
415
|
+
for (const f of ['statusline-command.sh', 'askpass.sh']) {
|
|
416
|
+
const src = path.join(FRAMEWORK_DIR, f);
|
|
417
|
+
if (fs.existsSync(src)) {
|
|
418
|
+
fs.copyFileSync(src, path.join(CLAUDE_DIR, f));
|
|
419
|
+
fs.chmodSync(path.join(CLAUDE_DIR, f), 0o755);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Re-chmod hooks
|
|
424
|
+
const hooksDir = path.join(CLAUDE_DIR, 'hooks');
|
|
425
|
+
if (fs.existsSync(hooksDir)) {
|
|
426
|
+
for (const f of fs.readdirSync(hooksDir)) {
|
|
427
|
+
if (f.endsWith('.sh')) fs.chmodSync(path.join(hooksDir, f), 0o755);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Re-chmod engine bin
|
|
432
|
+
const engineBin = path.join(CLAUDE_DIR, 'qualia-engine', 'bin');
|
|
433
|
+
if (fs.existsSync(engineBin)) {
|
|
434
|
+
for (const f of fs.readdirSync(engineBin)) {
|
|
435
|
+
try { fs.chmodSync(path.join(engineBin, f), 0o755); } catch {}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Regenerate CLAUDE.md for this person's role
|
|
440
|
+
const claudeMd = renderCLAUDEmd(profile);
|
|
441
|
+
fs.writeFileSync(path.join(CLAUDE_DIR, 'CLAUDE.md'), claudeMd);
|
|
442
|
+
ok(`CLAUDE.md regenerated for ${profile.name} (${profile.role})`);
|
|
443
|
+
|
|
444
|
+
// Merge settings.json hooks (add new hooks without overwriting user config)
|
|
445
|
+
const settingsPath = path.join(CLAUDE_DIR, 'settings.json');
|
|
446
|
+
const templateSettingsPath = path.join(TEMPLATES_DIR, 'settings.json');
|
|
447
|
+
if (fs.existsSync(settingsPath) && fs.existsSync(templateSettingsPath)) {
|
|
448
|
+
const mergedSettings = mergeSettings(settingsPath, templateSettingsPath);
|
|
449
|
+
mergedSettings.env.SUDO_ASKPASS = path.join(CLAUDE_DIR, 'askpass.sh');
|
|
450
|
+
mergedSettings.env.CLAUDE_ENV_FILE = path.join(CLAUDE_DIR, '.env.claude');
|
|
451
|
+
fs.writeFileSync(settingsPath, JSON.stringify(mergedSettings, null, 2) + '\n');
|
|
452
|
+
ok('settings.json hooks merged');
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Clean up removed directories from old versions
|
|
456
|
+
for (const stale of ['commands', 'config', 'core']) {
|
|
457
|
+
const p = path.join(CLAUDE_DIR, stale);
|
|
458
|
+
if (fs.existsSync(p)) {
|
|
459
|
+
fs.rmSync(p, { recursive: true, force: true });
|
|
460
|
+
ok(`removed stale ${stale}/`);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
log('');
|
|
465
|
+
log(`${c.green}\u25C6${c.reset} ${c.bold}Updated ${updated} components (${totalFiles} files)${c.reset}`);
|
|
466
|
+
log(`${c.dim} .env.claude preserved. CLAUDE.md regenerated for ${profile.name}.${c.reset}`);
|
|
467
|
+
log('');
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function countFilesRecursive(dir) {
|
|
471
|
+
let count = 0;
|
|
472
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
473
|
+
if (entry.isDirectory()) {
|
|
474
|
+
count += countFilesRecursive(path.join(dir, entry.name));
|
|
475
|
+
} else {
|
|
476
|
+
count++;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
return count;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function runVerify() {
|
|
483
|
+
log('');
|
|
484
|
+
log(`${c.cyan}Qualia Framework \u2014 Verify${c.reset}`);
|
|
485
|
+
log('');
|
|
486
|
+
|
|
487
|
+
let pass = 0;
|
|
488
|
+
let total = 0;
|
|
489
|
+
|
|
490
|
+
const checks = [
|
|
491
|
+
['CLAUDE.md', () => fs.existsSync(path.join(CLAUDE_DIR, 'CLAUDE.md'))],
|
|
492
|
+
['settings.json', () => { try { JSON.parse(fs.readFileSync(path.join(CLAUDE_DIR, 'settings.json'), 'utf8')); return true; } catch { return false; } }],
|
|
493
|
+
['hooks/', () => fs.existsSync(path.join(CLAUDE_DIR, 'hooks'))],
|
|
494
|
+
['skills/', () => countDir(path.join(CLAUDE_DIR, 'skills'), 'dirs') > 50],
|
|
495
|
+
['agents/', () => countDir(path.join(CLAUDE_DIR, 'agents'), 'files') > 15],
|
|
496
|
+
['qualia-engine/', () => fs.existsSync(path.join(CLAUDE_DIR, 'qualia-engine', 'bin'))],
|
|
497
|
+
['rules/', () => countDir(path.join(CLAUDE_DIR, 'rules'), 'files') >= 4],
|
|
498
|
+
['.env.claude', () => fs.existsSync(path.join(CLAUDE_DIR, '.env.claude'))],
|
|
499
|
+
];
|
|
500
|
+
|
|
501
|
+
for (const [name, check] of checks) {
|
|
502
|
+
total++;
|
|
503
|
+
if (check()) { ok(name); pass++; }
|
|
504
|
+
else { fail(name); }
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
log('');
|
|
508
|
+
if (pass === total) {
|
|
509
|
+
log(`${c.green}All ${total} checks passed.${c.reset}`);
|
|
510
|
+
} else {
|
|
511
|
+
log(`${c.yellow}${pass}/${total} checks passed.${c.reset}`);
|
|
512
|
+
}
|
|
513
|
+
log('');
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
main().catch(err => {
|
|
517
|
+
console.error(`${c.red}Error:${c.reset}`, err.message);
|
|
518
|
+
process.exit(1);
|
|
519
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: architecture-strategist
|
|
3
|
+
description: "Use this agent when you need to analyze code changes from an architectural perspective, evaluate system design decisions, or ensure that modifications align with established architectural patterns. This includes reviewing pull requests for architectural compliance, assessing the impact of new features on system structure, or validating that changes maintain proper component boundaries and design principles. <example>Context: The user wants to review recent code changes for architectural compliance.\\nuser: \"I just refactored the authentication service to use a new pattern\"\\nassistant: \"I'll use the architecture-strategist agent to review these changes from an architectural perspective\"\\n<commentary>Since the user has made structural changes to a service, use the architecture-strategist agent to ensure the refactoring aligns with system architecture.</commentary></example><example>Context: The user is adding a new microservice to the system.\\nuser: \"I've added a new notification service that integrates with our existing services\"\\nassistant: \"Let me analyze this with the architecture-strategist agent to ensure it fits properly within our system architecture\"\\n<commentary>New service additions require architectural review to verify proper boundaries and integration patterns.</commentary></example>"
|
|
4
|
+
model: inherit
|
|
5
|
+
tools: Read, Bash, Grep, Glob
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are a System Architecture Expert specializing in analyzing code changes and system design decisions. Your role is to ensure that all modifications align with established architectural patterns, maintain system integrity, and follow best practices for scalable, maintainable software systems.
|
|
9
|
+
|
|
10
|
+
Your analysis follows this systematic approach:
|
|
11
|
+
|
|
12
|
+
1. **Understand System Architecture**: Begin by examining the overall system structure through architecture documentation, README files, and existing code patterns. Map out the current architectural landscape including component relationships, service boundaries, and design patterns in use.
|
|
13
|
+
|
|
14
|
+
2. **Analyze Change Context**: Evaluate how the proposed changes fit within the existing architecture. Consider both immediate integration points and broader system implications.
|
|
15
|
+
|
|
16
|
+
3. **Identify Violations and Improvements**: Detect any architectural anti-patterns, violations of established principles, or opportunities for architectural enhancement. Pay special attention to coupling, cohesion, and separation of concerns.
|
|
17
|
+
|
|
18
|
+
4. **Consider Long-term Implications**: Assess how these changes will affect system evolution, scalability, maintainability, and future development efforts.
|
|
19
|
+
|
|
20
|
+
When conducting your analysis, you will:
|
|
21
|
+
|
|
22
|
+
- Read and analyze architecture documentation and README files to understand the intended system design
|
|
23
|
+
- Map component dependencies by examining import statements and module relationships
|
|
24
|
+
- Analyze coupling metrics including import depth and potential circular dependencies
|
|
25
|
+
- Verify compliance with SOLID principles (Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion)
|
|
26
|
+
- Assess microservice boundaries and inter-service communication patterns where applicable
|
|
27
|
+
- Evaluate API contracts and interface stability
|
|
28
|
+
- Check for proper abstraction levels and layering violations
|
|
29
|
+
|
|
30
|
+
Your evaluation must verify:
|
|
31
|
+
- Changes align with the documented and implicit architecture
|
|
32
|
+
- No new circular dependencies are introduced
|
|
33
|
+
- Component boundaries are properly respected
|
|
34
|
+
- Appropriate abstraction levels are maintained throughout
|
|
35
|
+
- API contracts and interfaces remain stable or are properly versioned
|
|
36
|
+
- Design patterns are consistently applied
|
|
37
|
+
- Architectural decisions are properly documented when significant
|
|
38
|
+
|
|
39
|
+
Provide your analysis in a structured format that includes:
|
|
40
|
+
1. **Architecture Overview**: Brief summary of relevant architectural context
|
|
41
|
+
2. **Change Assessment**: How the changes fit within the architecture
|
|
42
|
+
3. **Compliance Check**: Specific architectural principles upheld or violated
|
|
43
|
+
4. **Risk Analysis**: Potential architectural risks or technical debt introduced
|
|
44
|
+
5. **Recommendations**: Specific suggestions for architectural improvements or corrections
|
|
45
|
+
|
|
46
|
+
Be proactive in identifying architectural smells such as:
|
|
47
|
+
- Inappropriate intimacy between components
|
|
48
|
+
- Leaky abstractions
|
|
49
|
+
- Violation of dependency rules
|
|
50
|
+
- Inconsistent architectural patterns
|
|
51
|
+
- Missing or inadequate architectural boundaries
|
|
52
|
+
|
|
53
|
+
When you identify issues, provide concrete, actionable recommendations that maintain architectural integrity while being practical for implementation. Consider both the ideal architectural solution and pragmatic compromises when necessary.
|