qualia-framework-v2 2.9.0 → 2.10.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/bin/cli.js +2 -2
- package/bin/install.js +18 -18
- package/bin/qualia-ui.js +26 -26
- package/bin/statusline.js +53 -3
- package/hooks/migration-guard.js +1 -1
- package/hooks/pre-deploy-gate.js +2 -2
- package/package.json +1 -1
- package/skills/qualia-design/SKILL.md +1 -1
- package/skills/qualia-learn/SKILL.md +1 -1
- package/skills/qualia-new/SKILL.md +2 -2
- package/skills/qualia-review/SKILL.md +1 -1
package/bin/cli.js
CHANGED
|
@@ -34,7 +34,7 @@ function writeConfig(cfg) {
|
|
|
34
34
|
|
|
35
35
|
function banner() {
|
|
36
36
|
console.log("");
|
|
37
|
-
console.log(` ${TEAL}${BOLD}
|
|
37
|
+
console.log(` ${TEAL}${BOLD}⬢${RESET} ${WHITE}${BOLD}Qualia Framework${RESET} ${DIM}v${PKG.version}${RESET}`);
|
|
38
38
|
console.log(` ${DIM}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -339,7 +339,7 @@ async function cmdUninstall() {
|
|
|
339
339
|
|
|
340
340
|
// Summary.
|
|
341
341
|
console.log("");
|
|
342
|
-
console.log(`${TEAL}
|
|
342
|
+
console.log(`${TEAL} ⬢ Uninstall complete${RESET}`);
|
|
343
343
|
console.log(`${DIM} ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);
|
|
344
344
|
console.log(` ${DIM}Files removed:${RESET} ${WHITE}${counters.filesRemoved}${RESET}`);
|
|
345
345
|
console.log(` ${DIM}Directories removed:${RESET} ${WHITE}${counters.dirsRemoved}${RESET}`);
|
package/bin/install.js
CHANGED
|
@@ -70,7 +70,7 @@ function askCode() {
|
|
|
70
70
|
return new Promise((resolve) => {
|
|
71
71
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
72
72
|
console.log("");
|
|
73
|
-
console.log(`${TEAL}
|
|
73
|
+
console.log(`${TEAL} ⬢ Qualia Framework v2${RESET}`);
|
|
74
74
|
console.log(`${DIM} ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);
|
|
75
75
|
console.log("");
|
|
76
76
|
rl.question(` ${WHITE}Enter install code:${RESET} `, (answer) => {
|
|
@@ -425,16 +425,16 @@ Client-specific preferences, design choices, and requirements. Loaded by \`/qual
|
|
|
425
425
|
settings.spinnerTipsOverride = {
|
|
426
426
|
excludeDefault: true,
|
|
427
427
|
tips: [
|
|
428
|
-
"
|
|
429
|
-
"
|
|
430
|
-
"
|
|
431
|
-
"
|
|
432
|
-
"
|
|
433
|
-
"
|
|
434
|
-
"
|
|
435
|
-
"
|
|
436
|
-
"
|
|
437
|
-
"
|
|
428
|
+
"⬢ Lost? Type /qualia for the next step",
|
|
429
|
+
"⬢ Small fix? Use /qualia-quick to skip planning",
|
|
430
|
+
"⬢ End of day? /qualia-report before you clock out",
|
|
431
|
+
"⬢ Context isolation: every task gets a fresh AI brain",
|
|
432
|
+
"⬢ The verifier doesn't trust claims — it greps the code",
|
|
433
|
+
"⬢ Plans are prompts — the plan IS what the builder reads",
|
|
434
|
+
"⬢ Feature branches only — never push to main",
|
|
435
|
+
"⬢ Read before write — no exceptions",
|
|
436
|
+
"⬢ MVP first — build what's asked, nothing extra",
|
|
437
|
+
"⬢ tracking.json syncs to ERP on every push",
|
|
438
438
|
],
|
|
439
439
|
};
|
|
440
440
|
|
|
@@ -470,21 +470,21 @@ Client-specific preferences, design choices, and requirements. Loaded by \`/qual
|
|
|
470
470
|
if: "Bash(git push*)",
|
|
471
471
|
command: nodeCmd("branch-guard.js"),
|
|
472
472
|
timeout: 10,
|
|
473
|
-
statusMessage: "
|
|
473
|
+
statusMessage: "⬢ Checking branch permissions...",
|
|
474
474
|
},
|
|
475
475
|
{
|
|
476
476
|
type: "command",
|
|
477
477
|
if: "Bash(git push*)",
|
|
478
478
|
command: nodeCmd("pre-push.js"),
|
|
479
479
|
timeout: 15,
|
|
480
|
-
statusMessage: "
|
|
480
|
+
statusMessage: "⬢ Syncing tracking...",
|
|
481
481
|
},
|
|
482
482
|
{
|
|
483
483
|
type: "command",
|
|
484
484
|
if: "Bash(vercel --prod*)",
|
|
485
485
|
command: nodeCmd("pre-deploy-gate.js"),
|
|
486
486
|
timeout: 180,
|
|
487
|
-
statusMessage: "
|
|
487
|
+
statusMessage: "⬢ Running quality gates...",
|
|
488
488
|
},
|
|
489
489
|
],
|
|
490
490
|
},
|
|
@@ -496,14 +496,14 @@ Client-specific preferences, design choices, and requirements. Loaded by \`/qual
|
|
|
496
496
|
if: "Edit(*.env*)|Write(*.env*)",
|
|
497
497
|
command: nodeCmd("block-env-edit.js"),
|
|
498
498
|
timeout: 5,
|
|
499
|
-
statusMessage: "
|
|
499
|
+
statusMessage: "⬢ Checking file permissions...",
|
|
500
500
|
},
|
|
501
501
|
{
|
|
502
502
|
type: "command",
|
|
503
503
|
if: "Edit(*migration*)|Write(*migration*)|Edit(*.sql)|Write(*.sql)",
|
|
504
504
|
command: nodeCmd("migration-guard.js"),
|
|
505
505
|
timeout: 10,
|
|
506
|
-
statusMessage: "
|
|
506
|
+
statusMessage: "⬢ Checking migration safety...",
|
|
507
507
|
},
|
|
508
508
|
],
|
|
509
509
|
},
|
|
@@ -516,7 +516,7 @@ Client-specific preferences, design choices, and requirements. Loaded by \`/qual
|
|
|
516
516
|
type: "command",
|
|
517
517
|
command: nodeCmd("pre-compact.js"),
|
|
518
518
|
timeout: 15,
|
|
519
|
-
statusMessage: "
|
|
519
|
+
statusMessage: "⬢ Saving state...",
|
|
520
520
|
},
|
|
521
521
|
],
|
|
522
522
|
},
|
|
@@ -542,7 +542,7 @@ Client-specific preferences, design choices, and requirements. Loaded by \`/qual
|
|
|
542
542
|
|
|
543
543
|
// ─── Summary ───────────────────────────────────────────
|
|
544
544
|
console.log("");
|
|
545
|
-
console.log(`${TEAL}
|
|
545
|
+
console.log(`${TEAL} ⬢ Installed ✓${RESET}`);
|
|
546
546
|
console.log(`${DIM} ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);
|
|
547
547
|
console.log(` ${WHITE}${member.name}${RESET} ${DIM}(${member.role})${RESET}`);
|
|
548
548
|
console.log(` Skills: ${WHITE}${skills.length}${RESET}`);
|
package/bin/qualia-ui.js
CHANGED
|
@@ -40,25 +40,25 @@ const RULE_DIM = `${DIM2}${RULE}${RESET}`;
|
|
|
40
40
|
|
|
41
41
|
// ─── Action Labels ───────────────────────────────────────
|
|
42
42
|
const ACTIONS = {
|
|
43
|
-
router: { label: "SMART ROUTER", glyph: "
|
|
44
|
-
new: { label: "NEW PROJECT", glyph: "
|
|
45
|
-
plan: { label: "PLANNING", glyph: "
|
|
46
|
-
build: { label: "BUILDING", glyph: "
|
|
47
|
-
verify: { label: "VERIFYING", glyph: "
|
|
48
|
-
polish: { label: "POLISHING", glyph: "
|
|
49
|
-
ship: { label: "SHIPPING", glyph: "
|
|
50
|
-
handoff: { label: "HANDING OFF", glyph: "
|
|
51
|
-
report: { label: "SESSION REPORT", glyph: "
|
|
52
|
-
debug: { label: "DEBUGGING", glyph: "
|
|
53
|
-
learn: { label: "LEARNING", glyph: "
|
|
54
|
-
pause: { label: "PAUSING", glyph: "
|
|
55
|
-
resume: { label: "RESUMING", glyph: "
|
|
56
|
-
review: { label: "REVIEW", glyph: "
|
|
57
|
-
design: { label: "DESIGN PASS", glyph: "
|
|
58
|
-
quick: { label: "QUICK FIX", glyph: "
|
|
59
|
-
task: { label: "TASK", glyph: "
|
|
60
|
-
"skill-new": { label: "NEW SKILL", glyph: "
|
|
61
|
-
gaps: { label: "GAP CLOSURE", glyph: "
|
|
43
|
+
router: { label: "SMART ROUTER", glyph: "⬢" },
|
|
44
|
+
new: { label: "NEW PROJECT", glyph: "✦" },
|
|
45
|
+
plan: { label: "PLANNING", glyph: "▣" },
|
|
46
|
+
build: { label: "BUILDING", glyph: "⚙" },
|
|
47
|
+
verify: { label: "VERIFYING", glyph: "◎" },
|
|
48
|
+
polish: { label: "POLISHING", glyph: "✧" },
|
|
49
|
+
ship: { label: "SHIPPING", glyph: "△" },
|
|
50
|
+
handoff: { label: "HANDING OFF", glyph: "⇢" },
|
|
51
|
+
report: { label: "SESSION REPORT", glyph: "▤" },
|
|
52
|
+
debug: { label: "DEBUGGING", glyph: "⊘" },
|
|
53
|
+
learn: { label: "LEARNING", glyph: "⊙" },
|
|
54
|
+
pause: { label: "PAUSING", glyph: "⏸" },
|
|
55
|
+
resume: { label: "RESUMING", glyph: "▶" },
|
|
56
|
+
review: { label: "REVIEW", glyph: "⊛" },
|
|
57
|
+
design: { label: "DESIGN PASS", glyph: "◈" },
|
|
58
|
+
quick: { label: "QUICK FIX", glyph: "⚡" },
|
|
59
|
+
task: { label: "TASK", glyph: "▪" },
|
|
60
|
+
"skill-new": { label: "NEW SKILL", glyph: "✦" },
|
|
61
|
+
gaps: { label: "GAP CLOSURE", glyph: "⟐" },
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
// ─── State Reading ───────────────────────────────────────
|
|
@@ -126,7 +126,7 @@ function pad(str, width) {
|
|
|
126
126
|
|
|
127
127
|
// ─── Commands ────────────────────────────────────────────
|
|
128
128
|
function cmdBanner(action, phase, subtitle) {
|
|
129
|
-
const spec = ACTIONS[action] || { label: (action || "qualia").toUpperCase(), glyph: "
|
|
129
|
+
const spec = ACTIONS[action] || { label: (action || "qualia").toUpperCase(), glyph: "⬢" };
|
|
130
130
|
const state = readState();
|
|
131
131
|
const config = readConfig();
|
|
132
132
|
const project = projectName();
|
|
@@ -136,7 +136,7 @@ function cmdBanner(action, phase, subtitle) {
|
|
|
136
136
|
: spec.label;
|
|
137
137
|
|
|
138
138
|
console.log("");
|
|
139
|
-
console.log(` ${TEAL}${BOLD}${spec.glyph}${RESET} ${WHITE}${BOLD}QUALIA${RESET} ${DIM}
|
|
139
|
+
console.log(` ${TEAL}${BOLD}${spec.glyph}${RESET} ${WHITE}${BOLD}QUALIA${RESET} ${DIM}▸${RESET} ${WHITE}${title}${RESET}`);
|
|
140
140
|
console.log(` ${RULE_DIM}`);
|
|
141
141
|
|
|
142
142
|
// Context panel
|
|
@@ -218,7 +218,7 @@ function cmdInfo(msg) {
|
|
|
218
218
|
function cmdSpawn(agent, desc) {
|
|
219
219
|
const name = agent || "agent";
|
|
220
220
|
const d = desc ? ` ${DIM}— ${desc}${RESET}` : "";
|
|
221
|
-
console.log(` ${TEAL}
|
|
221
|
+
console.log(` ${TEAL}⬡${RESET} ${WHITE}Spawning${RESET} ${TEAL}${name}${RESET}${d}`);
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
function cmdWave(num, total, taskCount) {
|
|
@@ -226,7 +226,7 @@ function cmdWave(num, total, taskCount) {
|
|
|
226
226
|
const n = parseInt(num) || 0;
|
|
227
227
|
const t = parseInt(total) || 0;
|
|
228
228
|
const c = parseInt(taskCount) || 0;
|
|
229
|
-
console.log(` ${TEAL}
|
|
229
|
+
console.log(` ${TEAL}»${RESET} ${WHITE}${BOLD}Wave ${n}/${t}${RESET} ${DIM}(${c} ${c === 1 ? "task" : "tasks"}, parallel)${RESET}`);
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
function cmdTask(num, title) {
|
|
@@ -241,16 +241,16 @@ function cmdDone(num, title, commit) {
|
|
|
241
241
|
function cmdNext(cmd) {
|
|
242
242
|
if (!cmd) return;
|
|
243
243
|
console.log("");
|
|
244
|
-
console.log(` ${TEAL}
|
|
244
|
+
console.log(` ${TEAL}⟶${RESET} ${WHITE}Next:${RESET} ${TEAL}${BOLD}${cmd}${RESET}`);
|
|
245
245
|
console.log("");
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
function cmdEnd(status, nextCmd) {
|
|
249
249
|
console.log("");
|
|
250
|
-
console.log(` ${TEAL}${BOLD}
|
|
250
|
+
console.log(` ${TEAL}${BOLD}⬢${RESET} ${WHITE}${BOLD}${status || "DONE"}${RESET}`);
|
|
251
251
|
console.log(` ${RULE_DIM}`);
|
|
252
252
|
if (nextCmd) {
|
|
253
|
-
console.log(` ${TEAL}
|
|
253
|
+
console.log(` ${TEAL}⟶${RESET} ${WHITE}Next:${RESET} ${TEAL}${BOLD}${nextCmd}${RESET}`);
|
|
254
254
|
}
|
|
255
255
|
console.log("");
|
|
256
256
|
}
|
package/bin/statusline.js
CHANGED
|
@@ -11,6 +11,7 @@ const fs = require("fs");
|
|
|
11
11
|
const os = require("os");
|
|
12
12
|
const path = require("path");
|
|
13
13
|
const { spawnSync } = require("child_process");
|
|
14
|
+
const HOME = os.homedir();
|
|
14
15
|
|
|
15
16
|
// ─── Colors (matches bin/qualia-ui.js palette) ───────────
|
|
16
17
|
const TEAL = "\x1b[38;2;0;206;209m";
|
|
@@ -151,6 +152,47 @@ try {
|
|
|
151
152
|
}
|
|
152
153
|
} catch {}
|
|
153
154
|
|
|
155
|
+
// ─── Memory count ────────────────────────────────────────
|
|
156
|
+
let MEMORY_COUNT = 0;
|
|
157
|
+
try {
|
|
158
|
+
const dirKey = DIR.replace(/\//g, "-");
|
|
159
|
+
const memDir = path.join(HOME, ".claude", "projects", dirKey, "memory");
|
|
160
|
+
if (fs.existsSync(memDir)) {
|
|
161
|
+
const files = fs.readdirSync(memDir).filter(f => f.endsWith(".md") && f !== "MEMORY.md");
|
|
162
|
+
MEMORY_COUNT = files.length;
|
|
163
|
+
}
|
|
164
|
+
} catch {}
|
|
165
|
+
|
|
166
|
+
// ─── Hooks count ─────────────────────────────────────────
|
|
167
|
+
let HOOKS_COUNT = 0;
|
|
168
|
+
try {
|
|
169
|
+
const settingsPath = path.join(HOME, ".claude", "settings.json");
|
|
170
|
+
if (fs.existsSync(settingsPath)) {
|
|
171
|
+
const settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
|
|
172
|
+
if (settings.hooks) {
|
|
173
|
+
for (const event of Object.values(settings.hooks)) {
|
|
174
|
+
if (Array.isArray(event)) {
|
|
175
|
+
for (const matcher of event) {
|
|
176
|
+
if (matcher.hooks && Array.isArray(matcher.hooks)) {
|
|
177
|
+
HOOKS_COUNT += matcher.hooks.length;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
} catch {}
|
|
185
|
+
|
|
186
|
+
// ─── Skills count ────────────────────────────────────────
|
|
187
|
+
let SKILLS_COUNT = 0;
|
|
188
|
+
try {
|
|
189
|
+
const skillsDir = path.join(HOME, ".claude", "skills");
|
|
190
|
+
if (fs.existsSync(skillsDir)) {
|
|
191
|
+
const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
|
|
192
|
+
SKILLS_COUNT = entries.filter(e => e.isDirectory() || e.name.endsWith(".md")).length;
|
|
193
|
+
}
|
|
194
|
+
} catch {}
|
|
195
|
+
|
|
154
196
|
// ─── Duration ────────────────────────────────────────────
|
|
155
197
|
let DUR = "0s";
|
|
156
198
|
try {
|
|
@@ -167,11 +209,11 @@ try {
|
|
|
167
209
|
COST_FMT = `$${COST.toFixed(2)}`;
|
|
168
210
|
} catch {}
|
|
169
211
|
|
|
170
|
-
// ─── Line 1: Project + Git + Agent + Worktree + Phase
|
|
212
|
+
// ─── Line 1: Project + Git + Agent + Worktree + Phase + Memory + Hooks ──
|
|
171
213
|
let LINE1 = "";
|
|
172
214
|
try {
|
|
173
215
|
const dirBase = path.basename(DIR) || DIR;
|
|
174
|
-
LINE1 = `${TEAL}
|
|
216
|
+
LINE1 = `${TEAL}⬢${RESET} ${WHITE}${dirBase}${RESET}`;
|
|
175
217
|
if (BRANCH) {
|
|
176
218
|
if (CHANGES > 0) {
|
|
177
219
|
LINE1 += ` ${DIM}on${RESET} ${TEAL_GLOW}${BRANCH}${RESET} ${YELLOW}~${CHANGES}${RESET}`;
|
|
@@ -182,8 +224,16 @@ try {
|
|
|
182
224
|
if (AGENT) LINE1 += ` ${DIM}│${RESET} ${TEAL}⚡${AGENT}${RESET}`;
|
|
183
225
|
if (WORKTREE) LINE1 += ` ${DIM}│${RESET} ${TEAL_DIM}⎇ ${WORKTREE}${RESET}`;
|
|
184
226
|
if (PHASE_INFO) LINE1 += ` ${DIM}│${RESET} ${PHASE_INFO}`;
|
|
227
|
+
// Memory, hooks, skills — context indicators
|
|
228
|
+
const contextParts = [];
|
|
229
|
+
if (MEMORY_COUNT > 0) contextParts.push(`${TEAL}⊙${RESET}${DIM}${MEMORY_COUNT}${RESET}`);
|
|
230
|
+
if (HOOKS_COUNT > 0) contextParts.push(`${TEAL_GLOW}⚙${RESET}${DIM}${HOOKS_COUNT}${RESET}`);
|
|
231
|
+
if (SKILLS_COUNT > 0) contextParts.push(`${TEAL_DIM}✦${RESET}${DIM}${SKILLS_COUNT}${RESET}`);
|
|
232
|
+
if (contextParts.length > 0) {
|
|
233
|
+
LINE1 += ` ${DIM}│${RESET} ${contextParts.join(` ${DIM}·${RESET} `)}`;
|
|
234
|
+
}
|
|
185
235
|
} catch {
|
|
186
|
-
LINE1 = `${TEAL}
|
|
236
|
+
LINE1 = `${TEAL}⬢${RESET} ${WHITE}qualia${RESET}`;
|
|
187
237
|
}
|
|
188
238
|
|
|
189
239
|
// ─── Line 2: Context bar + Cost + Duration + Model ───────
|
package/hooks/migration-guard.js
CHANGED
|
@@ -48,7 +48,7 @@ if (/CREATE\s+TABLE/i.test(content) && !/ENABLE\s+ROW\s+LEVEL\s+SECURITY/i.test(
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
if (errors.length > 0) {
|
|
51
|
-
console.log("
|
|
51
|
+
console.log("⬢ Migration guard — dangerous patterns found:");
|
|
52
52
|
for (const e of errors) {
|
|
53
53
|
console.log(` ✗ ${e}`);
|
|
54
54
|
}
|
package/hooks/pre-deploy-gate.js
CHANGED
|
@@ -73,7 +73,7 @@ function scanServiceRoleLeaks() {
|
|
|
73
73
|
return leaks;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
console.log("
|
|
76
|
+
console.log("⬢ Pre-deploy gate...");
|
|
77
77
|
|
|
78
78
|
// TypeScript
|
|
79
79
|
if (fs.existsSync("tsconfig.json")) {
|
|
@@ -105,6 +105,6 @@ if (leaks.length > 0) {
|
|
|
105
105
|
process.exit(1);
|
|
106
106
|
}
|
|
107
107
|
console.log(" ✓ Security");
|
|
108
|
-
console.log("
|
|
108
|
+
console.log("⬢ All gates passed.");
|
|
109
109
|
|
|
110
110
|
process.exit(0);
|
package/package.json
CHANGED
|
@@ -100,7 +100,7 @@ options:
|
|
|
100
100
|
description: "Gradients, rounded shapes, vibrant palette"
|
|
101
101
|
preview: |
|
|
102
102
|
┌──────────────────────────────┐
|
|
103
|
-
│
|
|
103
|
+
│ ⬢ ● ▲ ■ COLORFUL │
|
|
104
104
|
│ │
|
|
105
105
|
│ ╭──────╮ ╭──────╮ │
|
|
106
106
|
│ │ Card │ │ Card │ │
|
|
@@ -173,7 +173,7 @@ If there's an entry for this client, show it to the user: *"I have notes on {cli
|
|
|
173
173
|
Present a summary:
|
|
174
174
|
|
|
175
175
|
```
|
|
176
|
-
|
|
176
|
+
⬢ QUALIA ▸ PROJECT SUMMARY
|
|
177
177
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
178
178
|
|
|
179
179
|
Project {name}
|