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
@@ -126,7 +126,7 @@ fi
126
126
  ### Step 6 — Upload to ERP
127
127
 
128
128
  The full payload-builder + 3-attempt-retry logic lives unchanged from v4 — see the **ERP Upload** section below for the canonical implementation. Behavior summary:
129
- - ERP disabled in config → skip silently, note local commit
129
+ - ERP disabled in config → skip upload with an info line, note local commit
130
130
  - API key missing → warn with self-service fix instructions, skip upload
131
131
  - 401/422 → permanent failure, no retry, tell employee to ask Fawzi
132
132
  - Transient (timeout/5xx) → 3 attempts with 1s/3s/9s backoff
@@ -149,7 +149,7 @@ node ~/.claude/bin/qualia-ui.js info "Shift report submitted. You can clock out
149
149
  | Symptom | Likely cause | Self-service fix |
150
150
  |---|---|---|
151
151
  | "Could not allocate report ID" | tracking.json missing/corrupt | `cat .planning/tracking.json` to inspect, or restore from `git checkout HEAD -- .planning/tracking.json` |
152
- | "ERP API key missing" | `~/.claude/.erp-api-key` empty | `qualia-framework set-erp-key <key>` (ask Fawzi for the key) |
152
+ | "ERP API key missing" | `~/.claude/.erp-api-key` empty | `printf '%s' "$QUALIA_ERP_KEY" \| qualia-framework set-erp-key` (ask Fawzi for the key) |
153
153
  | "ERP auth failed (401)" | Key revoked or wrong | Ask Fawzi for a fresh key |
154
154
  | "ERP upload failed after 3 attempts" | ERP down or network issue | Local commit is safe. Re-run `/qualia-report` later. |
155
155
  | "git push failed" | Auth or network or upstream issue | `git push` manually, see the error, fix, re-run |
@@ -181,53 +181,16 @@ IDEMPOTENCY_KEY=$(node -e "
181
181
 
182
182
  # Guard: API key required for upload (otherwise curl posts an empty bearer)
183
183
  if [ "$ERP_ENABLED" = "true" ] && [ -z "$API_KEY" ] && [ "$DRY_RUN" != "true" ]; then
184
- node ~/.claude/bin/qualia-ui.js warn "ERP API key missing (~/.claude/.erp-api-key). Run: qualia-framework set-erp-key <key>"
184
+ node ~/.claude/bin/qualia-ui.js warn "ERP API key missing (~/.claude/.erp-api-key). Run: printf '%s' \"\$QUALIA_ERP_KEY\" | qualia-framework set-erp-key"
185
185
  ERP_ENABLED="false"
186
186
  fi
187
187
 
188
- # Build payload (env-var-passed user values to dodge shell escaping)
188
+ # Build payload (env-var-passed user values to dodge shell escaping).
189
+ # `report-payload.js` is the canonical, tested Framework -> ERP payload builder.
189
190
  PAYLOAD=$(
190
191
  SUBMITTED_BY="$SUBMITTED_BY" SUBMITTED_AT="$SUBMITTED_AT" \
191
192
  CLIENT_REPORT_ID="$CLIENT_REPORT_ID" REPORT_FILE="$REPORT_FILE" \
192
- node -e "
193
- const fs=require('fs'),path=require('path'),os=require('os');
194
- const {spawnSync}=require('child_process');
195
- const git=(a)=>{const r=spawnSync('git',a,{encoding:'utf8',timeout:3000});return r.status===0?r.stdout.trim():'';};
196
- const repoSlug=(r)=>(r||'').replace(/^git@github\\.com:/,'github.com/').replace(/^https?:\\/\\//,'').replace(/\\.git$/,'').split('/').filter(Boolean).pop();
197
- let config={};try{config=JSON.parse(fs.readFileSync(path.join(os.homedir(),'.claude/.qualia-config.json'),'utf8'));}catch{}
198
- const t=JSON.parse(fs.readFileSync('.planning/tracking.json','utf8'));
199
- const notes=fs.readFileSync(process.env.REPORT_FILE,'utf8').substring(0,60000);
200
- const commits=[];try{const r=spawnSync('git',['log','--oneline','--since=8 hours ago','--format=%h'],{encoding:'utf8',timeout:3000});if(r.stdout)commits.push(...r.stdout.trim().split('\n').filter(Boolean));}catch{}
201
- const gitRemote=t.git_remote||git(['config','--get','remote.origin.url']);
202
- const projectKey=t.project_id||repoSlug(gitRemote)||require('path').basename(process.cwd());
203
- // Session duration: minutes from session_started_at to submitted_at. The ERP's
204
- // example payload (docs/erp-contract.md:93) includes this; without it the ERP
205
- // can't compute shift-length analytics without parsing notes.
206
- let sessionDurationMinutes=0;
207
- if(t.session_started_at){
208
- const startMs=Date.parse(t.session_started_at);
209
- const endMs=Date.parse(process.env.SUBMITTED_AT)||Date.now();
210
- if(!Number.isNaN(startMs)&&endMs>startMs){
211
- sessionDurationMinutes=Math.round((endMs-startMs)/60000);
212
- }
213
- }
214
- console.log(JSON.stringify({
215
- project:t.project||require('path').basename(process.cwd()),
216
- project_id:projectKey,team_id:t.team_id||'qualia-solutions',git_remote:gitRemote,
217
- client:t.client||'',client_report_id:process.env.CLIENT_REPORT_ID,
218
- framework_version:config.version||'',milestone:t.milestone||1,
219
- milestone_name:t.milestone_name||'',milestones:Array.isArray(t.milestones)?t.milestones:[],
220
- phase:t.phase,phase_name:t.phase_name,total_phases:t.total_phases,status:t.status,
221
- tasks_done:t.tasks_done||0,tasks_total:t.tasks_total||0,verification:t.verification||'pending',
222
- gap_cycles:(t.gap_cycles||{})[String(t.phase)]||0,build_count:t.build_count||0,
223
- deploy_count:t.deploy_count||0,deployed_url:t.deployed_url||'',
224
- ...(t.session_started_at?{session_started_at:t.session_started_at}:{}),
225
- ...(t.last_pushed_at?{last_pushed_at:t.last_pushed_at}:{}),
226
- session_duration_minutes:sessionDurationMinutes,
227
- lifetime:t.lifetime||{},commits:commits,notes:notes,
228
- submitted_by:process.env.SUBMITTED_BY||'unknown',submitted_at:process.env.SUBMITTED_AT
229
- }));
230
- "
193
+ node ~/.claude/bin/report-payload.js
231
194
  )
232
195
 
233
196
  # --dry-run: print and stop
@@ -117,7 +117,7 @@ No accumulated garbage. No context rot.
117
117
  - **Intent verification** — Confirm before modifying 3+ files (OWNER role: just do it)
118
118
 
119
119
  ## Tracking
120
- `.planning/tracking.json` is updated on every push. The ERP reads it via git.
120
+ `.planning/tracking.json` is updated locally on every push. It feeds statusline, stop-session-log, and `/qualia-report`; the ERP receives explicit report uploads and does not read this file from git.
121
121
  Never edit tracking.json manually — hooks update it from STATE.md.
122
122
 
123
123
  ## Compaction — ALWAYS preserve
@@ -106,7 +106,7 @@ Findings merge into main report. Union PASS/FAIL: either pass found CRITICAL/HIG
106
106
 
107
107
  ### 2d. INSUFFICIENT EVIDENCE downgrade (mandatory)
108
108
 
109
- The verifier marks criteria it could not check (budget exhaustion, missing context) as `INSUFFICIENT EVIDENCE`. The orchestrator treats those as silent PASS unless explicitly downgraded — that's the #1 false-pass vector. Grep the verification file before declaring PASS:
109
+ The verifier marks criteria it could not check (budget exhaustion, missing context) as `INSUFFICIENT EVIDENCE`. The orchestrator must treat those as FAIL before declaring PASS. Grep the verification file and downgrade immediately:
110
110
 
111
111
  ```bash
112
112
  IE_COUNT=$(grep -c "INSUFFICIENT EVIDENCE" .planning/phase-{N}-verification.md 2>/dev/null || echo 0)
@@ -437,7 +437,7 @@
437
437
  <div class="cmd"><span class="cmd-name">qualia-framework install</span><span class="cmd-desc">Install or reinstall the framework.</span></div>
438
438
  <div class="cmd"><span class="cmd-name">qualia-framework update</span><span class="cmd-desc">Update to the latest version.</span></div>
439
439
  <div class="cmd"><span class="cmd-name">qualia-framework version</span><span class="cmd-desc">Show installed version + check for updates.</span></div>
440
- <div class="cmd"><span class="cmd-name">qualia-framework uninstall</span><span class="cmd-desc">Clean removal from ~/.claude/ while preserving user-owned settings.</span></div>
440
+ <div class="cmd"><span class="cmd-name">qualia-framework uninstall</span><span class="cmd-desc">Clean removal from installed Claude/Codex homes while preserving user-owned settings.</span></div>
441
441
  <div class="cmd"><span class="cmd-name">qualia-framework migrate</span><span class="cmd-desc">Upgrade legacy settings.json to the current hook layout.</span></div>
442
442
  <div class="cmd"><span class="cmd-name">qualia-framework analytics</span><span class="cmd-desc">Hook telemetry, verification pass rates, gap cycles.</span></div>
443
443
  <div class="cmd"><span class="cmd-name">qualia-framework set-erp-key</span><span class="cmd-desc">Save and enable the ERP API key.</span></div>
@@ -6,11 +6,11 @@ once at session start.
6
6
 
7
7
  ## What's here
8
8
 
9
- `~/.claude/knowledge/` is the project-spanning memory tier. It holds three
9
+ The installed `knowledge/` directory is the project-spanning memory tier. It holds three
10
10
  kinds of files, each with a clear purpose. Treat the structure as a contract.
11
11
 
12
12
  ```
13
- ~/.claude/knowledge/
13
+ knowledge/
14
14
  ├── agents.md ← this file (system overview)
15
15
  ├── index.md ← entry point — start here when answering questions
16
16
  ├── daily-log/
@@ -43,7 +43,7 @@ kinds of files, each with a clear purpose. Treat the structure as a contract.
43
43
  **Do not pretend something is in memory if it is not.** Better to say
44
44
  "INSUFFICIENT EVIDENCE: searched index.md and learned-patterns.md, no entry
45
45
  matches" than to hallucinate a recalled pattern. The grounding protocol
46
- (`~/.claude/rules/grounding.md`) applies here too.
46
+ (`rules/grounding.md`) applies here too.
47
47
 
48
48
  ## Tiers
49
49
 
@@ -1,6 +1,6 @@
1
1
  # Knowledge Index
2
2
 
3
- Entry point for `~/.claude/knowledge/`. When answering a question, **read this
3
+ Entry point for the installed `knowledge/` directory. When answering a question, **read this
4
4
  file first**, then jump to the specific file(s) that match.
5
5
 
6
6
  > Auto-maintained by `/qualia-learn`. Do not hand-edit unless the file is out
@@ -5,6 +5,9 @@
5
5
  "assigned_to": "",
6
6
  "team_id": "",
7
7
  "project_id": "",
8
+ "erp_project_id": "",
9
+ "client_id": "",
10
+ "workspace_id": "",
8
11
  "git_remote": "",
9
12
  "milestone": 1,
10
13
  "milestone_name": "",
@@ -0,0 +1,46 @@
1
+ # Work Packet — {{PROJECT_NAME}}
2
+
3
+ Purpose: ERP-approved context for the next Framework session. This is the handoff from operations/control into Claude Code or Codex execution.
4
+
5
+ ## Source
6
+
7
+ - ERP project:
8
+ - ERP project ID (UUID):
9
+ - Client:
10
+ - Client ID (UUID):
11
+ - Workspace ID (UUID):
12
+ - Git remote:
13
+ - Assigned to:
14
+ - Prepared by:
15
+ - Prepared at:
16
+
17
+ ## Current Truth
18
+
19
+ - Current milestone:
20
+ - Current phase:
21
+ - Open blocker:
22
+ - Latest report:
23
+ - Deadline:
24
+ - Client-visible status:
25
+
26
+ ## Approved Work
27
+
28
+ 1.
29
+ 2.
30
+ 3.
31
+
32
+ ## Guardrails
33
+
34
+ - Do not change deadlines, project status, or client-visible updates without approval.
35
+ - Do not treat chat transcripts as final truth unless the ERP record confirms them.
36
+ - Use Framework `.planning/` for execution state; use ERP as the operational source of truth.
37
+
38
+ ## Memory Context
39
+
40
+ - Relevant client preferences:
41
+ - Reusable lessons:
42
+ - Known mistakes to avoid:
43
+
44
+ ## Next Framework Command
45
+
46
+ `/qualia`