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.
Files changed (59) hide show
  1. package/README.md +39 -26
  2. package/agents/roadmapper.md +1 -1
  3. package/bin/cli.js +339 -200
  4. package/bin/codex-goal.js +92 -0
  5. package/bin/erp-retry.js +11 -3
  6. package/bin/install.js +483 -55
  7. package/bin/knowledge-flush.js +25 -13
  8. package/bin/knowledge.js +11 -1
  9. package/bin/project-snapshot.js +293 -0
  10. package/bin/qualia-ui.js +13 -2
  11. package/bin/report-payload.js +137 -0
  12. package/bin/state.js +8 -1
  13. package/bin/statusline.js +14 -2
  14. package/docs/changelog-v6.html +864 -0
  15. package/docs/ecosystem-operating-model.md +121 -0
  16. package/docs/erp-contract.md +74 -21
  17. package/docs/onboarding.html +1 -1
  18. package/docs/release.md +44 -0
  19. package/docs/reviews/v6.2.1-revival-audit.md +53 -0
  20. package/docs/reviews/v6.2.2-memory-erp-audit.md +41 -0
  21. package/docs/reviews/v6.2.3-erp-id-guard.md +15 -0
  22. package/guide.md +16 -4
  23. package/hooks/auto-update.js +14 -7
  24. package/hooks/branch-guard.js +10 -2
  25. package/hooks/env-empty-guard.js +10 -1
  26. package/hooks/git-guardrails.js +10 -1
  27. package/hooks/migration-guard.js +4 -1
  28. package/hooks/pre-deploy-gate.js +38 -1
  29. package/hooks/pre-push.js +56 -157
  30. package/hooks/session-start.js +22 -14
  31. package/hooks/stop-session-log.js +11 -3
  32. package/hooks/supabase-destructive-guard.js +11 -1
  33. package/hooks/vercel-account-guard.js +12 -3
  34. package/package.json +3 -2
  35. package/rules/codex-goal.md +46 -0
  36. package/skills/qualia-build/SKILL.md +4 -0
  37. package/skills/qualia-feature/SKILL.md +4 -0
  38. package/skills/qualia-map/SKILL.md +1 -1
  39. package/skills/qualia-milestone/SKILL.md +1 -1
  40. package/skills/qualia-optimize/SKILL.md +1 -1
  41. package/skills/qualia-plan/SKILL.md +4 -0
  42. package/skills/qualia-polish/SKILL.md +2 -2
  43. package/skills/qualia-report/SKILL.md +6 -43
  44. package/skills/qualia-road/SKILL.md +1 -1
  45. package/skills/qualia-verify/SKILL.md +1 -1
  46. package/templates/help.html +1 -1
  47. package/templates/knowledge/agents.md +3 -3
  48. package/templates/knowledge/index.md +1 -1
  49. package/templates/tracking.json +3 -0
  50. package/templates/work-packet.md +46 -0
  51. package/tests/bin.test.sh +411 -13
  52. package/tests/hooks.test.sh +1 -8
  53. package/tests/install-smoke.test.sh +137 -0
  54. package/tests/published-install-smoke.test.sh +126 -0
  55. package/tests/refs.test.sh +42 -0
  56. package/tests/run-all.sh +1 -0
  57. package/tests/runner.js +19 -33
  58. package/tests/state.test.sh +4 -1
  59. 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
- const QUEUE_FILE = path.join(HOME, ".claude", ".erp-retry-queue.json");
44
- const API_KEY_FILE = path.join(HOME, ".claude", ".erp-api-key");
45
- const CONFIG_FILE = path.join(HOME, ".claude", ".qualia-config.json");
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;