@esoteric-logic/praxis-harness 2.11.0 → 2.13.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/base/CLAUDE.md +37 -3
- package/base/agents/evaluator.md +44 -0
- package/base/agents/planner.md +48 -0
- package/base/hooks/auto-format.sh +1 -1
- package/base/hooks/dep-audit.sh +1 -1
- package/base/hooks/file-guard.sh +3 -3
- package/base/hooks/recursion-guard.sh +7 -1
- package/base/hooks/session-data-collect.sh +1 -1
- package/base/hooks/vault-checkpoint.sh +5 -5
- package/base/rules/code-excellence.md +22 -0
- package/base/rules/coding.md +16 -0
- package/base/rules/context-budget.md +66 -0
- package/base/rules/context-management.md +4 -0
- package/base/rules/hooks-policy.md +53 -0
- package/base/rules/multi-agent-orchestration.md +99 -0
- package/base/rules/observable-code.md +87 -0
- package/base/rules/phase-detection.md +52 -0
- package/base/rules/refactor-triggers.md +59 -0
- package/base/rules/self-repair.md +53 -0
- package/base/rules/session-bridge.md +39 -0
- package/base/rules/session-metrics.md +61 -0
- package/base/rules/skill-authoring.md +85 -0
- package/base/rules/writing-quality.md +122 -0
- package/base/skills/px-compact/SKILL.md +100 -0
- package/base/skills/px-complexity-audit/SKILL.md +118 -0
- package/base/skills/px-context-probe/SKILL.md +1 -1
- package/base/skills/px-context-triage/SKILL.md +76 -0
- package/base/skills/px-discover/SKILL.md +4 -1
- package/base/skills/px-discuss/SKILL.md +4 -1
- package/base/skills/px-doc-lint/SKILL.md +107 -0
- package/base/skills/px-prose-review/SKILL.md +96 -0
- package/base/skills/px-quality-gate/SKILL.md +182 -0
- package/base/skills/px-risk/SKILL.md +4 -1
- package/base/skills/px-scaffold-new/SKILL.md +16 -14
- package/base/skills/px-session-retro/SKILL.md +1 -1
- package/base/skills/px-spec/SKILL.md +6 -2
- package/base/skills/px-verify/SKILL.md +2 -1
- package/bin/praxis.js +27 -6
- package/kits/api/KIT.md +2 -0
- package/kits/api/install.sh +1 -1
- package/kits/api/teardown.sh +1 -1
- package/kits/code-quality/KIT.md +2 -0
- package/kits/code-quality/hooks/generate-baseline.sh +1 -1
- package/kits/code-quality/hooks/post-commit.sh +3 -2
- package/kits/code-quality/hooks/pre-push.sh +15 -15
- package/kits/code-quality/install.sh +1 -1
- package/kits/code-quality/teardown.sh +3 -3
- package/kits/data/KIT.md +2 -0
- package/kits/data/install.sh +1 -1
- package/kits/data/teardown.sh +1 -1
- package/kits/infrastructure/KIT.md +2 -0
- package/kits/infrastructure/install.sh +1 -1
- package/kits/infrastructure/teardown.sh +1 -1
- package/kits/security/KIT.md +2 -0
- package/kits/security/install.sh +1 -1
- package/kits/security/teardown.sh +1 -1
- package/kits/web-designer/KIT.md +2 -0
- package/kits/web-designer/install.sh +1 -1
- package/kits/web-designer/teardown.sh +1 -1
- package/package.json +1 -1
- package/scripts/health-check.sh +21 -15
- package/scripts/install-tools.sh +5 -5
- package/scripts/lint-harness.sh +1 -1
- package/scripts/onboard-mcp.sh +1 -1
- package/scripts/test-harness.sh +1 -1
- package/scripts/update.sh +1 -1
|
@@ -46,10 +46,10 @@ Read identity table from `~/.claude/rules/git-workflow.md`.
|
|
|
46
46
|
|
|
47
47
|
## Phase 1 — Gather Info
|
|
48
48
|
|
|
49
|
-
Before asking, run vault duplicate check:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
Before asking, run vault duplicate check using configured backend:
|
|
50
|
+
- If `obsidian`: `obsidian search query="{slug}" path="01_Projects" limit=3`
|
|
51
|
+
- If `ripgrep`: `rg --files-with-matches "{slug}" {vault_path}/`
|
|
52
|
+
- If vault search fails: warn and proceed without blocking.
|
|
53
53
|
|
|
54
54
|
Ask in one message:
|
|
55
55
|
- **Project name** — display name
|
|
@@ -71,7 +71,7 @@ today_date = current date YYYY-MM-DD
|
|
|
71
71
|
|
|
72
72
|
## Phase 2 — Scaffold repo CLAUDE.md
|
|
73
73
|
|
|
74
|
-
1. Read `
|
|
74
|
+
1. Read `templates/project-index.md` (the repo CLAUDE.md template)
|
|
75
75
|
2. Apply full substitution map. All placeholders must resolve.
|
|
76
76
|
3. Scan output for remaining `{placeholder}` patterns. Resolve before writing.
|
|
77
77
|
4. Write to `{repo_root}/CLAUDE.md`
|
|
@@ -85,19 +85,19 @@ Create directories:
|
|
|
85
85
|
mkdir -p {vault_path}/plans {vault_path}/notes {vault_path}/specs {vault_path}/research
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
Create files from templates in `
|
|
89
|
-
- `_index.md` from `
|
|
90
|
-
- `status.md` from `
|
|
91
|
-
- `tasks.md` from `
|
|
92
|
-
- `notes/learnings.md`
|
|
93
|
-
- `notes/decision-log.md` from `decision-log`
|
|
94
|
-
- `.gitignore`
|
|
88
|
+
Create files from templates in `templates/`:
|
|
89
|
+
- `_index.md` from `templates/_index.md`
|
|
90
|
+
- `status.md` from `templates/status.md` (`current_plan:` empty)
|
|
91
|
+
- `tasks.md` from `templates/tasks.md`
|
|
92
|
+
- `notes/learnings.md` — scaffold minimal learnings file (no template exists; create with YAML frontmatter + empty `## Learnings` section)
|
|
93
|
+
- `notes/decision-log.md` from `templates/decision-log.md` (append-only decision log)
|
|
94
|
+
- `.gitignore` — scaffold standard gitignore for detected stack (new repos only)
|
|
95
95
|
|
|
96
96
|
---
|
|
97
97
|
|
|
98
98
|
## Phase 3.5 — Scaffold claude-progress.json
|
|
99
99
|
|
|
100
|
-
From `
|
|
100
|
+
From `templates/claude-progress.json`. Apply substitution map.
|
|
101
101
|
Write to `{vault_path}/claude-progress.json`.
|
|
102
102
|
|
|
103
103
|
---
|
|
@@ -105,7 +105,9 @@ Write to `{vault_path}/claude-progress.json`.
|
|
|
105
105
|
## Phase 4 — Vault Search Check
|
|
106
106
|
|
|
107
107
|
Vault indexing is automatic for `obsidian` backend. No manual re-index needed.
|
|
108
|
-
Verify the new project is searchable
|
|
108
|
+
Verify the new project is searchable using configured backend:
|
|
109
|
+
- If `obsidian`: `obsidian search query="{slug}" limit=1`
|
|
110
|
+
- If `ripgrep`: `rg --files-with-matches "{slug}" {vault_path}/`
|
|
109
111
|
On failure: warn, do not block.
|
|
110
112
|
|
|
111
113
|
---
|
|
@@ -48,7 +48,7 @@ Classify each: type, tag (`bugfix|convention|perf|security|tooling|arch|process`
|
|
|
48
48
|
For each finding with clear root cause:
|
|
49
49
|
- Project-specific → `{vault_path}/notes/learnings.md`
|
|
50
50
|
- Global/harness pattern → harness project learnings.md
|
|
51
|
-
- Check for duplicates via
|
|
51
|
+
- Check for duplicates via vault search (using configured backend) before writing. If vault search unavailable: skip duplicate check and proceed.
|
|
52
52
|
|
|
53
53
|
Format:
|
|
54
54
|
```markdown
|
|
@@ -21,11 +21,15 @@ You are creating a spec for the current project.
|
|
|
21
21
|
Ask the following in a single message:
|
|
22
22
|
- What is this spec for? (one sentence)
|
|
23
23
|
- Type: ADR (architecture decision) / RISK (risk register entry) / SPEC (technical spec)
|
|
24
|
-
- Is there an existing related spec in `specs/`?
|
|
24
|
+
- Is there an existing related spec in `specs/`?
|
|
25
|
+
- Read `vault_backend` from `~/.claude/praxis.config.json`
|
|
26
|
+
- If `obsidian`: run `obsidian search query="{topic}" limit=3`
|
|
27
|
+
- If `ripgrep`: run `rg --files-with-matches "{topic}" {vault_path}/specs/`
|
|
28
|
+
- If vault search fails (e.g., Obsidian not running): warn "Vault search unavailable — skipping conflict check" and proceed without blocking
|
|
25
29
|
|
|
26
30
|
**Step 2b — Cross-spec conflict check**
|
|
27
31
|
After the vault search from Step 2, check for conflicts with accepted ADRs:
|
|
28
|
-
- Run
|
|
32
|
+
- Run vault search for topic (using backend detected above) with limit=10
|
|
29
33
|
- For each result with `status: accepted` or `status: proposed`:
|
|
30
34
|
- Compare the decision direction. Does the new spec contradict an accepted decision?
|
|
31
35
|
- If conflict detected, present:
|
|
@@ -17,7 +17,8 @@ Execute in order, showing actual output (never assertions):
|
|
|
17
17
|
- **DeepSource**: `deepsource issues list <file>` for files in diff (if deepsource CLI available)
|
|
18
18
|
- If either tool finds HIGH/CRITICAL: treat as blocking — must fix before proceeding.
|
|
19
19
|
- If tools not installed: skip with advisory note, do not block. DeepSource cloud validates on push.
|
|
20
|
-
6. **
|
|
20
|
+
6. **Quality gate** → run `/px-quality-gate` on changed files → BLOCK on naming/prose/structure violations. See `px-quality-gate` skill for full check list.
|
|
21
|
+
7. **Functional check** — ask: "Is there a smoke test, `terraform plan` output, or browser check needed for this milestone?" If yes: block until user confirms it passed. If no: proceed.
|
|
21
22
|
|
|
22
23
|
Read test/lint/build commands from the project CLAUDE.md `## Commands` section.
|
|
23
24
|
If no commands are defined: warn and ask user for the correct commands.
|
package/bin/praxis.js
CHANGED
|
@@ -19,7 +19,7 @@ function fail(msg) { console.error(' \x1b[31m\u2717\x1b[0m ' + msg); }
|
|
|
19
19
|
function dim(msg) { console.log(' \x1b[2m' + msg + '\x1b[0m'); }
|
|
20
20
|
|
|
21
21
|
function toolExists(name) {
|
|
22
|
-
const r = spawnSync('
|
|
22
|
+
const r = spawnSync('command', ['-v', name], { stdio: 'pipe', shell: true });
|
|
23
23
|
return r.status === 0;
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -94,12 +94,33 @@ async function install() {
|
|
|
94
94
|
const hooksConfig = path.join(hooksDir, 'settings-hooks.json');
|
|
95
95
|
const settingsFile = path.join(CLAUDE_DIR, 'settings.json');
|
|
96
96
|
if (fs.existsSync(hooksConfig)) {
|
|
97
|
-
|
|
97
|
+
let hooksCfg;
|
|
98
|
+
try {
|
|
99
|
+
hooksCfg = JSON.parse(fs.readFileSync(hooksConfig, 'utf8'));
|
|
100
|
+
} catch (hookParseErr) {
|
|
101
|
+
fail('settings-hooks.json has invalid JSON: ' + hookParseErr.message);
|
|
102
|
+
hooksCfg = {};
|
|
103
|
+
}
|
|
98
104
|
let settings = {};
|
|
99
105
|
if (fs.existsSync(settingsFile)) {
|
|
100
|
-
|
|
106
|
+
const raw = fs.readFileSync(settingsFile, 'utf8');
|
|
107
|
+
try {
|
|
108
|
+
settings = JSON.parse(raw);
|
|
109
|
+
} catch (parseErr) {
|
|
110
|
+
// Preserve corrupt file as backup before overwriting
|
|
111
|
+
const backupPath = settingsFile + '.backup';
|
|
112
|
+
fs.writeFileSync(backupPath, raw);
|
|
113
|
+
fail('settings.json has invalid JSON — backed up to ' + backupPath);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Deep merge: preserve existing keys, overlay hooks
|
|
117
|
+
for (const [key, value] of Object.entries(hooksCfg)) {
|
|
118
|
+
if (typeof value === 'object' && !Array.isArray(value) && settings[key] && typeof settings[key] === 'object') {
|
|
119
|
+
settings[key] = { ...settings[key], ...value };
|
|
120
|
+
} else {
|
|
121
|
+
settings[key] = value;
|
|
122
|
+
}
|
|
101
123
|
}
|
|
102
|
-
Object.assign(settings, hooksCfg);
|
|
103
124
|
fs.writeFileSync(settingsFile, JSON.stringify(settings, null, 2) + '\n');
|
|
104
125
|
ok('hooks configuration merged into settings.json');
|
|
105
126
|
}
|
|
@@ -261,7 +282,7 @@ function health() {
|
|
|
261
282
|
} else {
|
|
262
283
|
total++; fail('vault_path not set in config');
|
|
263
284
|
}
|
|
264
|
-
} catch { total++; fail('praxis.config.json is invalid JSON'); }
|
|
285
|
+
} catch (configErr) { total++; fail('praxis.config.json is invalid JSON: ' + configErr.message); }
|
|
265
286
|
}
|
|
266
287
|
|
|
267
288
|
// Tools
|
|
@@ -386,7 +407,7 @@ else if (arg === '--version' || arg === '-v') { console.log(VERSION); }
|
|
|
386
407
|
else if (commands[arg]) {
|
|
387
408
|
const result = commands[arg]();
|
|
388
409
|
if (result && typeof result.catch === 'function') {
|
|
389
|
-
result.catch(err => { fail(err
|
|
410
|
+
result.catch(err => { fail(err?.message || String(err)); process.exit(1); });
|
|
390
411
|
}
|
|
391
412
|
}
|
|
392
413
|
else { fail('Unknown command: ' + arg); printHelp(); process.exit(1); }
|
package/kits/api/KIT.md
CHANGED
package/kits/api/install.sh
CHANGED
package/kits/api/teardown.sh
CHANGED
package/kits/code-quality/KIT.md
CHANGED
|
@@ -4,6 +4,8 @@ version: 1.0.0
|
|
|
4
4
|
description: "Code quality enforcement — parallel deterministic gate (SAST, secrets, SCA, IaC) + AI review layer (over-engineering, smells, structure, performance)"
|
|
5
5
|
activation: /kit:code-quality
|
|
6
6
|
deactivation: /kit:off
|
|
7
|
+
context_cost: high
|
|
8
|
+
depends_on: []
|
|
7
9
|
skills_chain:
|
|
8
10
|
- phase: gate
|
|
9
11
|
skills: [sast-scan, secrets-scan, sca-scan, iac-scan]
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
#!/bin/bash
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
2
3
|
# Triggers Claude AI self-review after commit
|
|
3
4
|
# This is advisory — does not block, surfaces findings for next commit
|
|
4
5
|
|
|
@@ -11,7 +12,7 @@ if ! command -v claude &>/dev/null; then
|
|
|
11
12
|
fi
|
|
12
13
|
|
|
13
14
|
CHANGED=$(git diff --name-only HEAD~1...HEAD 2>/dev/null | head -20)
|
|
14
|
-
if [ -z "$CHANGED" ]; then
|
|
15
|
+
if [[ -z "$CHANGED" ]]; then
|
|
15
16
|
exit 0
|
|
16
17
|
fi
|
|
17
18
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
set -
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
3
|
|
|
4
4
|
REPO_ROOT=$(git rev-parse --show-toplevel)
|
|
5
5
|
KIT_DIR="$REPO_ROOT/.claude/kits/code-quality"
|
|
@@ -33,7 +33,7 @@ echo "------------------------"
|
|
|
33
33
|
|
|
34
34
|
# Get changed files only (diff-scoped scanning)
|
|
35
35
|
CHANGED=$(git diff --name-only origin/HEAD...HEAD 2>/dev/null || git diff --name-only HEAD~1...HEAD 2>/dev/null || echo "")
|
|
36
|
-
if [ -z "$CHANGED" ]; then
|
|
36
|
+
if [[ -z "$CHANGED" ]]; then
|
|
37
37
|
echo " No changed files detected — skipping gate"
|
|
38
38
|
exit 0
|
|
39
39
|
fi
|
|
@@ -46,7 +46,7 @@ GATE_FAILURES=()
|
|
|
46
46
|
GATE_WARNINGS=()
|
|
47
47
|
|
|
48
48
|
# -- SAST (OpenGrep) --
|
|
49
|
-
if [ -s "$TMP/code-files.txt" ]; then
|
|
49
|
+
if [[ -s "$TMP/code-files.txt" ]]; then
|
|
50
50
|
echo " SAST scan (OpenGrep)..."
|
|
51
51
|
FILES=$(cat "$TMP/code-files.txt" | tr '\n' ' ')
|
|
52
52
|
opengrep scan --config auto --json $FILES > "$TMP/sast.json" 2>/dev/null || true
|
|
@@ -54,8 +54,8 @@ if [ -s "$TMP/code-files.txt" ]; then
|
|
|
54
54
|
CRITICAL=$(safe_jq '[.results[] | select(.extra.severity == "ERROR")] | length' "$TMP/sast.json")
|
|
55
55
|
HIGH=$(safe_jq '[.results[] | select(.extra.severity == "WARNING")] | length' "$TMP/sast.json")
|
|
56
56
|
|
|
57
|
-
[ "$CRITICAL" -gt 0 ] && GATE_FAILURES+=("SAST: $CRITICAL critical findings")
|
|
58
|
-
[ "$HIGH" -gt 0 ] && GATE_WARNINGS+=("SAST: $HIGH high findings")
|
|
57
|
+
[[ "$CRITICAL" -gt 0 ]] && GATE_FAILURES+=("SAST: $CRITICAL critical findings")
|
|
58
|
+
[[ "$HIGH" -gt 0 ]] && GATE_WARNINGS+=("SAST: $HIGH high findings")
|
|
59
59
|
echo " Critical: $CRITICAL High: $HIGH"
|
|
60
60
|
fi &
|
|
61
61
|
SAST_PID=$!
|
|
@@ -68,7 +68,7 @@ if [[ -s "$TMP/secrets.json" ]]; then
|
|
|
68
68
|
else
|
|
69
69
|
SECRETS=0
|
|
70
70
|
fi
|
|
71
|
-
[ "$SECRETS" -gt 0 ] && GATE_FAILURES+=("SECRETS: $SECRETS verified secrets found")
|
|
71
|
+
[[ "$SECRETS" -gt 0 ]] && GATE_FAILURES+=("SECRETS: $SECRETS verified secrets found")
|
|
72
72
|
echo " Verified secrets: $SECRETS" &
|
|
73
73
|
SECRETS_PID=$!
|
|
74
74
|
|
|
@@ -77,17 +77,17 @@ echo " Dependency scan (OSV-Scanner)..."
|
|
|
77
77
|
osv-scanner scan --format json "$REPO_ROOT" > "$TMP/sca.json" 2>/dev/null || true
|
|
78
78
|
SCA_CRITICAL=$(safe_jq '[.vulns[]? | select(.database_specific.severity? == "CRITICAL")] | length' "$TMP/sca.json")
|
|
79
79
|
SCA_HIGH=$(safe_jq '[.vulns[]? | select(.database_specific.severity? == "HIGH")] | length' "$TMP/sca.json")
|
|
80
|
-
[ "$SCA_CRITICAL" -gt 0 ] && GATE_FAILURES+=("SCA: $SCA_CRITICAL critical CVEs in dependencies")
|
|
81
|
-
[ "$SCA_HIGH" -gt 0 ] && GATE_WARNINGS+=("SCA: $SCA_HIGH high CVEs in dependencies")
|
|
80
|
+
[[ "$SCA_CRITICAL" -gt 0 ]] && GATE_FAILURES+=("SCA: $SCA_CRITICAL critical CVEs in dependencies")
|
|
81
|
+
[[ "$SCA_HIGH" -gt 0 ]] && GATE_WARNINGS+=("SCA: $SCA_HIGH high CVEs in dependencies")
|
|
82
82
|
echo " Critical CVEs: $SCA_CRITICAL High CVEs: $SCA_HIGH" &
|
|
83
83
|
SCA_PID=$!
|
|
84
84
|
|
|
85
85
|
# -- IaC (Checkov) --
|
|
86
|
-
if [ -s "$TMP/iac-files.txt" ]; then
|
|
86
|
+
if [[ -s "$TMP/iac-files.txt" ]]; then
|
|
87
87
|
echo " IaC scan (Checkov)..."
|
|
88
88
|
checkov -d "$REPO_ROOT" --output json --quiet --compact 2>/dev/null > "$TMP/iac.json" || true
|
|
89
89
|
IaC_FAIL=$(safe_jq '.results.failed_checks | length' "$TMP/iac.json")
|
|
90
|
-
[ "$IaC_FAIL" -gt 0 ] && GATE_WARNINGS+=("IaC: $IaC_FAIL policy violations")
|
|
90
|
+
[[ "$IaC_FAIL" -gt 0 ]] && GATE_WARNINGS+=("IaC: $IaC_FAIL policy violations")
|
|
91
91
|
echo " Policy violations: $IaC_FAIL"
|
|
92
92
|
fi &
|
|
93
93
|
IaC_PID=$!
|
|
@@ -97,10 +97,10 @@ wait $SAST_PID $SECRETS_PID $SCA_PID $IaC_PID 2>/dev/null || true
|
|
|
97
97
|
|
|
98
98
|
# -- COVERAGE --
|
|
99
99
|
COVERAGE_THRESHOLD=$(safe_jq '.coverage.line_min' "$CONFIG" 80)
|
|
100
|
-
if [ -f "$REPO_ROOT/coverage/coverage-summary.json" ]; then
|
|
100
|
+
if [[ -f "$REPO_ROOT/coverage/coverage-summary.json" ]]; then
|
|
101
101
|
COVERAGE=$(safe_jq '.total.lines.pct' "$REPO_ROOT/coverage/coverage-summary.json" 100)
|
|
102
102
|
BELOW=$(echo "$COVERAGE < $COVERAGE_THRESHOLD" | bc -l 2>/dev/null || echo 0)
|
|
103
|
-
[ "$BELOW"
|
|
103
|
+
[[ "$BELOW" == "1" ]] && GATE_WARNINGS+=("COVERAGE: ${COVERAGE}% below threshold ${COVERAGE_THRESHOLD}%")
|
|
104
104
|
echo " Coverage: ${COVERAGE}% (threshold: ${COVERAGE_THRESHOLD}%)"
|
|
105
105
|
fi
|
|
106
106
|
|
|
@@ -108,12 +108,12 @@ fi
|
|
|
108
108
|
echo ""
|
|
109
109
|
echo "------------------------"
|
|
110
110
|
|
|
111
|
-
if [ ${#GATE_WARNINGS[@]} -gt 0 ]; then
|
|
111
|
+
if [[ ${#GATE_WARNINGS[@]} -gt 0 ]]; then
|
|
112
112
|
echo "Warnings:"
|
|
113
113
|
for w in "${GATE_WARNINGS[@]}"; do echo " $w"; done
|
|
114
114
|
fi
|
|
115
115
|
|
|
116
|
-
if [ ${#GATE_FAILURES[@]} -gt 0 ]; then
|
|
116
|
+
if [[ ${#GATE_FAILURES[@]} -gt 0 ]]; then
|
|
117
117
|
echo "Gate BLOCKED:"
|
|
118
118
|
for f in "${GATE_FAILURES[@]}"; do echo " $f"; done
|
|
119
119
|
echo ""
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/bin/bash
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
|
|
4
4
|
echo "Removing code-quality kit hooks..."
|
|
@@ -6,8 +6,8 @@ echo "Removing code-quality kit hooks..."
|
|
|
6
6
|
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo ".")
|
|
7
7
|
HOOKS_DIR="$REPO_ROOT/.git/hooks"
|
|
8
8
|
|
|
9
|
-
[ -f "$HOOKS_DIR/pre-push" ] && rm "$HOOKS_DIR/pre-push" && echo " pre-push hook removed"
|
|
10
|
-
[ -f "$HOOKS_DIR/post-commit" ] && rm "$HOOKS_DIR/post-commit" && echo " post-commit hook removed"
|
|
9
|
+
[[ -f "$HOOKS_DIR/pre-push" ]] && rm "$HOOKS_DIR/pre-push" && echo " pre-push hook removed"
|
|
10
|
+
[[ -f "$HOOKS_DIR/post-commit" ]] && rm "$HOOKS_DIR/post-commit" && echo " post-commit hook removed"
|
|
11
11
|
|
|
12
12
|
echo ""
|
|
13
13
|
echo "Note: CLI tools (opengrep, trufflehog, osv-scanner, checkov) are system-level"
|
package/kits/data/KIT.md
CHANGED
package/kits/data/install.sh
CHANGED
package/kits/data/teardown.sh
CHANGED
package/kits/security/KIT.md
CHANGED
package/kits/security/install.sh
CHANGED
package/kits/web-designer/KIT.md
CHANGED
|
@@ -13,6 +13,8 @@ skills_chain:
|
|
|
13
13
|
skills: [web-accessibility, ui-skills-baseline, ui-skills-motion]
|
|
14
14
|
- phase: final-lint
|
|
15
15
|
skills: [web-design-guidelines]
|
|
16
|
+
context_cost: medium
|
|
17
|
+
depends_on: []
|
|
16
18
|
mcp_servers:
|
|
17
19
|
- name: 21st-magic
|
|
18
20
|
command: npx -y @21st-dev/magic@latest
|
package/package.json
CHANGED
package/scripts/health-check.sh
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/bin/bash
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
|
|
4
4
|
# ════════════════════════════════════════════════════════════════
|
|
@@ -16,23 +16,29 @@ FAIL=0
|
|
|
16
16
|
TOTAL=0
|
|
17
17
|
|
|
18
18
|
check() {
|
|
19
|
+
local label="$2"
|
|
19
20
|
TOTAL=$((TOTAL + 1))
|
|
20
|
-
if
|
|
21
|
-
echo " ✓ $
|
|
21
|
+
if "$@" 2>/dev/null; then
|
|
22
|
+
echo " ✓ $label"
|
|
22
23
|
PASS=$((PASS + 1))
|
|
23
24
|
else
|
|
24
|
-
echo " ✗ $
|
|
25
|
+
echo " ✗ $label"
|
|
25
26
|
FAIL=$((FAIL + 1))
|
|
26
27
|
fi
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
check_exists() { [[ -e "$1" ]]; }
|
|
31
|
+
check_file() { [[ -f "$1" ]]; }
|
|
32
|
+
check_dir() { [[ -d "$1" ]]; }
|
|
33
|
+
check_cmd() { command -v "$1" &>/dev/null; }
|
|
34
|
+
|
|
29
35
|
echo "Praxis Health Check"
|
|
30
36
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
31
37
|
|
|
32
38
|
# ─── CLAUDE.md symlink ───
|
|
33
39
|
echo ""
|
|
34
40
|
echo "Core:"
|
|
35
|
-
check "
|
|
41
|
+
check check_exists "$CLAUDE_DIR/CLAUDE.md" "CLAUDE.md installed"
|
|
36
42
|
|
|
37
43
|
# ─── Rules symlinks ───
|
|
38
44
|
echo ""
|
|
@@ -41,7 +47,7 @@ if [[ -d "$PRAXIS_DIR/base/rules" ]]; then
|
|
|
41
47
|
for rule in "$PRAXIS_DIR"/base/rules/*.md; do
|
|
42
48
|
[[ -f "$rule" ]] || continue
|
|
43
49
|
fname=$(basename "$rule")
|
|
44
|
-
check "
|
|
50
|
+
check check_exists "$CLAUDE_DIR/rules/$fname" "rules/$fname installed"
|
|
45
51
|
done
|
|
46
52
|
fi
|
|
47
53
|
|
|
@@ -52,7 +58,7 @@ if [[ -d "$PRAXIS_DIR/base/commands" ]]; then
|
|
|
52
58
|
for cmd in "$PRAXIS_DIR"/base/commands/*.md; do
|
|
53
59
|
[[ -f "$cmd" ]] || continue
|
|
54
60
|
fname=$(basename "$cmd")
|
|
55
|
-
check "
|
|
61
|
+
check check_exists "$CLAUDE_DIR/commands/$fname" "commands/$fname installed"
|
|
56
62
|
done
|
|
57
63
|
fi
|
|
58
64
|
|
|
@@ -63,24 +69,24 @@ if [[ -d "$PRAXIS_DIR/base/skills" ]]; then
|
|
|
63
69
|
for skill_dir in "$PRAXIS_DIR"/base/skills/*/; do
|
|
64
70
|
[[ -d "$skill_dir" ]] || continue
|
|
65
71
|
skill_name=$(basename "$skill_dir")
|
|
66
|
-
check "
|
|
72
|
+
check check_exists "$CLAUDE_DIR/skills/$skill_name" "skills/$skill_name installed"
|
|
67
73
|
done
|
|
68
74
|
fi
|
|
69
75
|
|
|
70
76
|
# ─── Kits symlink ───
|
|
71
77
|
echo ""
|
|
72
78
|
echo "Kits:"
|
|
73
|
-
check "
|
|
79
|
+
check check_exists "$CLAUDE_DIR/kits" "kits directory installed"
|
|
74
80
|
|
|
75
81
|
# ─── Config ───
|
|
76
82
|
echo ""
|
|
77
83
|
echo "Config:"
|
|
78
|
-
check "
|
|
84
|
+
check check_file "$CONFIG_FILE" "praxis.config.json exists"
|
|
79
85
|
|
|
80
86
|
if [[ -f "$CONFIG_FILE" ]]; then
|
|
81
87
|
VAULT_PATH=$(jq -r '.vault_path // empty' "$CONFIG_FILE" 2>/dev/null)
|
|
82
88
|
if [[ -n "$VAULT_PATH" ]]; then
|
|
83
|
-
check "
|
|
89
|
+
check check_dir "$VAULT_PATH" "vault_path ($VAULT_PATH) is a real directory"
|
|
84
90
|
else
|
|
85
91
|
TOTAL=$((TOTAL + 1))
|
|
86
92
|
echo " ✗ vault_path not set in config"
|
|
@@ -91,10 +97,10 @@ fi
|
|
|
91
97
|
# ─── Required tools ───
|
|
92
98
|
echo ""
|
|
93
99
|
echo "Tools:"
|
|
94
|
-
check
|
|
95
|
-
check
|
|
96
|
-
check
|
|
97
|
-
check
|
|
100
|
+
check check_cmd obsidian "Obsidian CLI available"
|
|
101
|
+
check check_cmd node "node available"
|
|
102
|
+
check check_cmd claude "claude available"
|
|
103
|
+
check check_cmd jq "jq available"
|
|
98
104
|
|
|
99
105
|
# ─── MCP Servers (warn only) ───
|
|
100
106
|
echo ""
|
package/scripts/install-tools.sh
CHANGED
|
@@ -17,7 +17,7 @@ for arg in "$@"; do
|
|
|
17
17
|
done
|
|
18
18
|
|
|
19
19
|
# Auto-detect if no flags
|
|
20
|
-
if [ $# -eq 0 ]; then
|
|
20
|
+
if [[ $# -eq 0 ]]; then
|
|
21
21
|
command -v go &>/dev/null && INSTALL_GO=true
|
|
22
22
|
command -v terraform &>/dev/null && INSTALL_TF=true
|
|
23
23
|
fi
|
|
@@ -43,7 +43,7 @@ install_go() { go install "$@" 2>/dev/null || true; }
|
|
|
43
43
|
|
|
44
44
|
# ── Core (always) ──
|
|
45
45
|
echo "── Installing core tools ──"
|
|
46
|
-
if [ "$PKG"
|
|
46
|
+
if [[ "$PKG" == "brew" ]]; then
|
|
47
47
|
install_brew shellcheck shfmt jq gitleaks
|
|
48
48
|
else
|
|
49
49
|
sudo apt-get update -qq
|
|
@@ -60,7 +60,7 @@ if $INSTALL_GO; then
|
|
|
60
60
|
echo "── Installing Go quality tools ──"
|
|
61
61
|
install_go golang.org/x/tools/cmd/goimports@latest
|
|
62
62
|
install_go golang.org/x/vuln/cmd/govulncheck@latest
|
|
63
|
-
if [ "$PKG"
|
|
63
|
+
if [[ "$PKG" == "brew" ]]; then
|
|
64
64
|
install_brew golangci-lint
|
|
65
65
|
else
|
|
66
66
|
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "$(go env GOPATH)/bin" 2>/dev/null || true
|
|
@@ -71,7 +71,7 @@ fi
|
|
|
71
71
|
if $INSTALL_TF; then
|
|
72
72
|
echo ""
|
|
73
73
|
echo "── Installing Terraform quality tools ──"
|
|
74
|
-
if [ "$PKG"
|
|
74
|
+
if [[ "$PKG" == "brew" ]]; then
|
|
75
75
|
install_brew tflint trivy infracost
|
|
76
76
|
else
|
|
77
77
|
echo "NOTE: Install tflint, trivy, infracost manually for Linux"
|
|
@@ -82,7 +82,7 @@ fi
|
|
|
82
82
|
if command -v docker &>/dev/null; then
|
|
83
83
|
echo ""
|
|
84
84
|
echo "── Installing container tools ──"
|
|
85
|
-
if [ "$PKG"
|
|
85
|
+
if [[ "$PKG" == "brew" ]]; then
|
|
86
86
|
install_brew hadolint
|
|
87
87
|
fi
|
|
88
88
|
fi
|
package/scripts/lint-harness.sh
CHANGED
package/scripts/onboard-mcp.sh
CHANGED
package/scripts/test-harness.sh
CHANGED
package/scripts/update.sh
CHANGED