qualia-framework 6.1.0 → 6.2.9
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 +39 -26
- package/agents/roadmapper.md +1 -1
- package/bin/cli.js +339 -200
- package/bin/codex-goal.js +92 -0
- package/bin/erp-retry.js +11 -3
- package/bin/install.js +483 -55
- package/bin/knowledge-flush.js +25 -13
- package/bin/knowledge.js +11 -1
- package/bin/project-snapshot.js +293 -0
- package/bin/qualia-ui.js +13 -2
- package/bin/report-payload.js +137 -0
- package/bin/state.js +8 -1
- package/bin/statusline.js +14 -2
- package/docs/changelog-v6.html +864 -0
- package/docs/ecosystem-operating-model.md +121 -0
- package/docs/erp-contract.md +74 -21
- package/docs/onboarding.html +1 -1
- package/docs/release.md +44 -0
- package/docs/reviews/v6.2.1-revival-audit.md +53 -0
- package/docs/reviews/v6.2.2-memory-erp-audit.md +41 -0
- package/docs/reviews/v6.2.3-erp-id-guard.md +15 -0
- package/guide.md +16 -4
- package/hooks/auto-update.js +14 -7
- package/hooks/branch-guard.js +10 -2
- package/hooks/env-empty-guard.js +10 -1
- package/hooks/git-guardrails.js +10 -1
- package/hooks/migration-guard.js +4 -1
- package/hooks/pre-deploy-gate.js +38 -1
- package/hooks/pre-push.js +56 -157
- package/hooks/session-start.js +22 -14
- package/hooks/stop-session-log.js +11 -3
- package/hooks/supabase-destructive-guard.js +11 -1
- package/hooks/vercel-account-guard.js +12 -3
- package/package.json +3 -2
- package/rules/codex-goal.md +46 -0
- package/skills/qualia-build/SKILL.md +4 -0
- package/skills/qualia-feature/SKILL.md +4 -0
- package/skills/qualia-map/SKILL.md +1 -1
- package/skills/qualia-milestone/SKILL.md +1 -1
- package/skills/qualia-optimize/SKILL.md +1 -1
- package/skills/qualia-plan/SKILL.md +4 -0
- package/skills/qualia-polish/SKILL.md +2 -2
- package/skills/qualia-report/SKILL.md +6 -43
- package/skills/qualia-road/SKILL.md +1 -1
- package/skills/qualia-verify/SKILL.md +1 -1
- package/templates/help.html +1 -1
- package/templates/knowledge/agents.md +3 -3
- package/templates/knowledge/index.md +1 -1
- package/templates/tracking.json +3 -0
- package/templates/work-packet.md +46 -0
- package/tests/bin.test.sh +411 -13
- package/tests/hooks.test.sh +1 -8
- package/tests/install-smoke.test.sh +137 -0
- package/tests/published-install-smoke.test.sh +126 -0
- package/tests/refs.test.sh +42 -0
- package/tests/run-all.sh +1 -0
- package/tests/runner.js +19 -33
- package/tests/state.test.sh +4 -1
- package/hooks/pre-compact.js +0 -127
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// codex-goal — suggest a Codex /goal objective + token budget from current
|
|
3
|
+
// .planning/STATE.md + ROADMAP.md state.
|
|
4
|
+
//
|
|
5
|
+
// Output is a single line meant to be pasted into a Codex session, or quoted
|
|
6
|
+
// in an agent prompt that will then issue update_goal itself. The framework
|
|
7
|
+
// does NOT write directly to ~/.codex/goals_1.sqlite — Codex owns the schema
|
|
8
|
+
// and the thread_id; the /goal slash command (and the update_goal tool the
|
|
9
|
+
// model can call) are the stable interfaces.
|
|
10
|
+
//
|
|
11
|
+
// Usage: node bin/codex-goal.js [phase|task|feature|quick]
|
|
12
|
+
// default scope = phase
|
|
13
|
+
|
|
14
|
+
const fs = require("fs");
|
|
15
|
+
const path = require("path");
|
|
16
|
+
|
|
17
|
+
const SCOPE = (process.argv[2] || "phase").toLowerCase();
|
|
18
|
+
|
|
19
|
+
// Token budgets are calibrated to Codex's per-thread context window and the
|
|
20
|
+
// typical Qualia work-unit size. Phase = full builder loop with verification.
|
|
21
|
+
// Task/feature = single fresh-context spawn. Quick = one-shot inline edit.
|
|
22
|
+
const TOKEN_BUDGETS = {
|
|
23
|
+
phase: 80000,
|
|
24
|
+
task: 30000,
|
|
25
|
+
feature: 30000,
|
|
26
|
+
quick: 10000,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const PLANNING = path.join(process.cwd(), ".planning");
|
|
30
|
+
const STATE_FILE = path.join(PLANNING, "STATE.md");
|
|
31
|
+
const ROADMAP_FILE = path.join(PLANNING, "ROADMAP.md");
|
|
32
|
+
|
|
33
|
+
function readSafe(p) {
|
|
34
|
+
try { return fs.readFileSync(p, "utf8"); } catch { return ""; }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function parseState(content) {
|
|
38
|
+
if (!content) return null;
|
|
39
|
+
const phaseMatch = content.match(/^Phase:\s*(\d+)\s+of\s+(\d+)\s*[—-]\s*(.+?)\r?$/m);
|
|
40
|
+
if (!phaseMatch) return null;
|
|
41
|
+
return {
|
|
42
|
+
phase: parseInt(phaseMatch[1], 10),
|
|
43
|
+
total: parseInt(phaseMatch[2], 10),
|
|
44
|
+
name: phaseMatch[3].trim(),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function readPhaseGoal(roadmap, phaseNum) {
|
|
49
|
+
if (!roadmap) return "";
|
|
50
|
+
// Match a heading like "## Phase 2 — Name" or "## Phase 2: Name", then
|
|
51
|
+
// grab the "Goal:" line that follows.
|
|
52
|
+
const heading = new RegExp(`##\\s*Phase\\s*${phaseNum}\\s*[—:\\-]\\s*[^\\n]+`, "i");
|
|
53
|
+
const idx = roadmap.search(heading);
|
|
54
|
+
if (idx === -1) return "";
|
|
55
|
+
const body = roadmap.slice(idx, idx + 2000);
|
|
56
|
+
const goalMatch = body.match(/^\s*\*?\*?Goal:?\*?\*?\s*(.+?)$/im);
|
|
57
|
+
return goalMatch ? goalMatch[1].trim() : "";
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function clip(s, max) {
|
|
61
|
+
return s.length <= max ? s : s.slice(0, max - 1).trimEnd() + "…";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function main() {
|
|
65
|
+
const budget = TOKEN_BUDGETS[SCOPE];
|
|
66
|
+
if (budget == null) {
|
|
67
|
+
process.stderr.write(`unknown scope: ${SCOPE} (use phase|task|feature|quick)\n`);
|
|
68
|
+
process.exit(2);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const state = parseState(readSafe(STATE_FILE));
|
|
72
|
+
if (!state) {
|
|
73
|
+
// No .planning/STATE.md — fall back to a generic shape so the helper
|
|
74
|
+
// still emits something useful for ad-hoc invocations.
|
|
75
|
+
const objective = `${SCOPE[0].toUpperCase() + SCOPE.slice(1)} in ${path.basename(process.cwd())}`;
|
|
76
|
+
process.stdout.write(`/goal ${objective}\n`);
|
|
77
|
+
process.stdout.write(`# token_budget suggestion: ${budget}\n`);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const phaseGoal = readPhaseGoal(readSafe(ROADMAP_FILE), state.phase);
|
|
82
|
+
const objectivePrefix = `Phase ${state.phase}/${state.total} — ${state.name}`;
|
|
83
|
+
const objective = clip(
|
|
84
|
+
phaseGoal ? `${objectivePrefix}: ${phaseGoal}` : objectivePrefix,
|
|
85
|
+
280
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
process.stdout.write(`/goal ${objective}\n`);
|
|
89
|
+
process.stdout.write(`# token_budget suggestion: ${budget}\n`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
main();
|
package/bin/erp-retry.js
CHANGED
|
@@ -40,9 +40,17 @@ const http = require("http");
|
|
|
40
40
|
const urlLib = require("url");
|
|
41
41
|
|
|
42
42
|
const HOME = os.homedir();
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
43
|
+
function qualiaHome() {
|
|
44
|
+
if (process.env.QUALIA_HOME) return process.env.QUALIA_HOME;
|
|
45
|
+
const parent = path.basename(path.dirname(__dirname));
|
|
46
|
+
if (parent === ".codex" || parent === ".claude") return path.dirname(__dirname);
|
|
47
|
+
return path.join(HOME, ".claude");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const QUALIA_HOME = qualiaHome();
|
|
51
|
+
const QUEUE_FILE = path.join(QUALIA_HOME, ".erp-retry-queue.json");
|
|
52
|
+
const API_KEY_FILE = path.join(QUALIA_HOME, ".erp-api-key");
|
|
53
|
+
const CONFIG_FILE = path.join(QUALIA_HOME, ".qualia-config.json");
|
|
46
54
|
|
|
47
55
|
const MAX_GIVE_UP_ATTEMPTS = 10;
|
|
48
56
|
const DEFAULT_TIMEOUT_MS = 5000;
|