devrites 1.19.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/.claude-plugin/marketplace.json +24 -0
- package/.claude-plugin/plugin.json +43 -0
- package/CHANGELOG.md +391 -0
- package/LICENSE +56 -0
- package/NOTICE.md +18 -0
- package/README.md +582 -0
- package/SECURITY.md +193 -0
- package/bin/devrites.mjs +100 -0
- package/docs/architecture.md +272 -0
- package/docs/cli-mcp.md +57 -0
- package/docs/command-map.md +143 -0
- package/docs/flow.md +360 -0
- package/docs/release.md +29 -0
- package/docs/skills.md +214 -0
- package/docs/usage.md +325 -0
- package/install.sh +359 -0
- package/mcp/devrites-mcp.mjs +103 -0
- package/pack/.claude/agents/devrites-code-reviewer.md +50 -0
- package/pack/.claude/agents/devrites-doubt-reviewer.md +55 -0
- package/pack/.claude/agents/devrites-frontend-reviewer.md +52 -0
- package/pack/.claude/agents/devrites-performance-reviewer.md +47 -0
- package/pack/.claude/agents/devrites-plan-reviewer.md +79 -0
- package/pack/.claude/agents/devrites-security-auditor.md +53 -0
- package/pack/.claude/agents/devrites-simplifier-reviewer.md +75 -0
- package/pack/.claude/agents/devrites-slice-wright.md +181 -0
- package/pack/.claude/agents/devrites-spec-reviewer.md +72 -0
- package/pack/.claude/agents/devrites-strategy-reviewer.md +62 -0
- package/pack/.claude/agents/devrites-test-analyst.md +47 -0
- package/pack/.claude/hooks/devrites-a1-guard.sh +81 -0
- package/pack/.claude/hooks/devrites-allow.sh +44 -0
- package/pack/.claude/hooks/devrites-cursor.sh +28 -0
- package/pack/.claude/hooks/devrites-orient.sh +53 -0
- package/pack/.claude/hooks/devrites-redwatch.sh +39 -0
- package/pack/.claude/hooks/devrites-refresh-indexes.sh +127 -0
- package/pack/.claude/hooks/devrites-reviewer-readonly.sh +28 -0
- package/pack/.claude/hooks/devrites-statusline.sh +18 -0
- package/pack/.claude/hooks/devrites-stop-gate.sh +45 -0
- package/pack/.claude/hooks/devrites-wright-scope.sh +35 -0
- package/pack/.claude/hooks/hooks.json +52 -0
- package/pack/.claude/rules/README.md +48 -0
- package/pack/.claude/rules/afk-hitl.md +245 -0
- package/pack/.claude/rules/agents.md +98 -0
- package/pack/.claude/rules/anti-patterns.md +48 -0
- package/pack/.claude/rules/code-review.md +38 -0
- package/pack/.claude/rules/coding-style.md +55 -0
- package/pack/.claude/rules/context-hygiene.md +97 -0
- package/pack/.claude/rules/core.md +119 -0
- package/pack/.claude/rules/development-workflow.md +40 -0
- package/pack/.claude/rules/documentation.md +27 -0
- package/pack/.claude/rules/error-handling.md +33 -0
- package/pack/.claude/rules/git-workflow.md +35 -0
- package/pack/.claude/rules/hooks.md +38 -0
- package/pack/.claude/rules/patterns.md +45 -0
- package/pack/.claude/rules/performance.md +27 -0
- package/pack/.claude/rules/prose-style.md +101 -0
- package/pack/.claude/rules/security.md +63 -0
- package/pack/.claude/rules/testing.md +88 -0
- package/pack/.claude/rules/tooling.md +72 -0
- package/pack/.claude/settings.json +53 -0
- package/pack/.claude/skills/devrites-api-interface/SKILL.md +45 -0
- package/pack/.claude/skills/devrites-audit/SKILL.md +73 -0
- package/pack/.claude/skills/devrites-browser-proof/SKILL.md +38 -0
- package/pack/.claude/skills/devrites-debug-recovery/SKILL.md +50 -0
- package/pack/.claude/skills/devrites-debug-recovery/reference/build-the-loop.md +47 -0
- package/pack/.claude/skills/devrites-debug-recovery/reference/cleanup-and-classify.md +17 -0
- package/pack/.claude/skills/devrites-debug-recovery/reference/hypotheses.md +17 -0
- package/pack/.claude/skills/devrites-debug-recovery/reference/instrumentation.md +21 -0
- package/pack/.claude/skills/devrites-debug-recovery/reference/regression-test.md +31 -0
- package/pack/.claude/skills/devrites-doubt/SKILL.md +75 -0
- package/pack/.claude/skills/devrites-frontend-craft/SKILL.md +96 -0
- package/pack/.claude/skills/devrites-frontend-craft/reference/craft.md +59 -0
- package/pack/.claude/skills/devrites-frontend-craft/reference/design-references.md +116 -0
- package/pack/.claude/skills/devrites-frontend-craft/reference/fullstack.md +45 -0
- package/pack/.claude/skills/devrites-frontend-craft/reference/quality-standards.md +215 -0
- package/pack/.claude/skills/devrites-frontend-craft/reference/reuse-first.md +59 -0
- package/pack/.claude/skills/devrites-frontend-craft/reference/shape.md +60 -0
- package/pack/.claude/skills/devrites-interview/SKILL.md +81 -0
- package/pack/.claude/skills/devrites-lib/SKILL.md +76 -0
- package/pack/.claude/skills/devrites-lib/scripts/analyze.sh +78 -0
- package/pack/.claude/skills/devrites-lib/scripts/check-acceptance.sh +75 -0
- package/pack/.claude/skills/devrites-lib/scripts/close-out.sh +47 -0
- package/pack/.claude/skills/devrites-lib/scripts/conventions.py +273 -0
- package/pack/.claude/skills/devrites-lib/scripts/coverage.sh +51 -0
- package/pack/.claude/skills/devrites-lib/scripts/devrites.sh +69 -0
- package/pack/.claude/skills/devrites-lib/scripts/doctor.sh +92 -0
- package/pack/.claude/skills/devrites-lib/scripts/evidence-fresh.sh +63 -0
- package/pack/.claude/skills/devrites-lib/scripts/footprint.sh +45 -0
- package/pack/.claude/skills/devrites-lib/scripts/learnings.sh +74 -0
- package/pack/.claude/skills/devrites-lib/scripts/mutation-gate.sh +52 -0
- package/pack/.claude/skills/devrites-lib/scripts/package-existence.sh +68 -0
- package/pack/.claude/skills/devrites-lib/scripts/preamble.sh +76 -0
- package/pack/.claude/skills/devrites-lib/scripts/progress.sh +103 -0
- package/pack/.claude/skills/devrites-lib/scripts/readiness.sh +62 -0
- package/pack/.claude/skills/devrites-lib/scripts/reconcile.sh +123 -0
- package/pack/.claude/skills/devrites-lib/scripts/resolve.sh +279 -0
- package/pack/.claude/skills/devrites-lib/scripts/stuck.sh +67 -0
- package/pack/.claude/skills/devrites-lib/scripts/test-integrity.sh +87 -0
- package/pack/.claude/skills/devrites-lib/scripts/tick-afk.sh +52 -0
- package/pack/.claude/skills/devrites-prose-craft/SKILL.md +105 -0
- package/pack/.claude/skills/devrites-prose-craft/reference/banned-phrases.md +95 -0
- package/pack/.claude/skills/devrites-prose-craft/reference/examples.md +88 -0
- package/pack/.claude/skills/devrites-prose-craft/reference/structures.md +134 -0
- package/pack/.claude/skills/devrites-refresh-indexes/SKILL.md +54 -0
- package/pack/.claude/skills/devrites-source-driven/SKILL.md +36 -0
- package/pack/.claude/skills/devrites-ux-shape/SKILL.md +121 -0
- package/pack/.claude/skills/devrites-ux-shape/reference/brief-template.md +93 -0
- package/pack/.claude/skills/devrites-ux-shape/reference/visual-direction-probe.md +48 -0
- package/pack/.claude/skills/rite/SKILL.md +135 -0
- package/pack/.claude/skills/rite/reference/menu.md +32 -0
- package/pack/.claude/skills/rite-adopt/SKILL.md +83 -0
- package/pack/.claude/skills/rite-adopt/reference/adoption.md +58 -0
- package/pack/.claude/skills/rite-adopt/reference/anti-patterns.md +19 -0
- package/pack/.claude/skills/rite-autocomplete/SKILL.md +96 -0
- package/pack/.claude/skills/rite-autocomplete/reference/decision-policy.md +35 -0
- package/pack/.claude/skills/rite-autocomplete/reference/loop.md +54 -0
- package/pack/.claude/skills/rite-autocomplete/reference/stop-conditions.md +59 -0
- package/pack/.claude/skills/rite-build/SKILL.md +261 -0
- package/pack/.claude/skills/rite-build/reference/afk-discipline.md +145 -0
- package/pack/.claude/skills/rite-build/reference/anti-patterns.md +25 -0
- package/pack/.claude/skills/rite-build/reference/checkpoint-protocol.md +149 -0
- package/pack/.claude/skills/rite-build/reference/evidence-standard.md +32 -0
- package/pack/.claude/skills/rite-build/reference/frontend-trigger.md +39 -0
- package/pack/.claude/skills/rite-build/reference/one-slice-cycle.md +38 -0
- package/pack/.claude/skills/rite-build/reference/spec-drift-guard.md +43 -0
- package/pack/.claude/skills/rite-build/reference/tdd.md +26 -0
- package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +115 -0
- package/pack/.claude/skills/rite-define/SKILL.md +157 -0
- package/pack/.claude/skills/rite-define/reference/anti-patterns.md +25 -0
- package/pack/.claude/skills/rite-define/reference/gates.md +152 -0
- package/pack/.claude/skills/rite-define/reference/plan-template.md +65 -0
- package/pack/.claude/skills/rite-doctor/SKILL.md +50 -0
- package/pack/.claude/skills/rite-frame/SKILL.md +116 -0
- package/pack/.claude/skills/rite-frame/reference/failure-modes.md +68 -0
- package/pack/.claude/skills/rite-handoff/SKILL.md +95 -0
- package/pack/.claude/skills/rite-handoff/reference/handoff-template.md +34 -0
- package/pack/.claude/skills/rite-learn/SKILL.md +82 -0
- package/pack/.claude/skills/rite-plan/SKILL.md +82 -0
- package/pack/.claude/skills/rite-plan/reference/anti-patterns.md +24 -0
- package/pack/.claude/skills/rite-plan/reference/dependency-graph.md +33 -0
- package/pack/.claude/skills/rite-plan/reference/replan-and-repair.md +42 -0
- package/pack/.claude/skills/rite-plan/reference/slicing.md +52 -0
- package/pack/.claude/skills/rite-plan/reference/task-breakdown.md +34 -0
- package/pack/.claude/skills/rite-polish/SKILL.md +90 -0
- package/pack/.claude/skills/rite-polish/reference/anti-ai-slop.md +177 -0
- package/pack/.claude/skills/rite-polish/reference/anti-patterns.md +27 -0
- package/pack/.claude/skills/rite-polish/reference/backend-polish.md +80 -0
- package/pack/.claude/skills/rite-polish/reference/browser-polish-evidence.md +31 -0
- package/pack/.claude/skills/rite-polish/reference/code.md +85 -0
- package/pack/.claude/skills/rite-polish/reference/design-system-discovery.md +35 -0
- package/pack/.claude/skills/rite-polish/reference/harden-checklist.md +109 -0
- package/pack/.claude/skills/rite-polish/reference/ui.md +136 -0
- package/pack/.claude/skills/rite-pressure-test/SKILL.md +43 -0
- package/pack/.claude/skills/rite-prototype/SKILL.md +87 -0
- package/pack/.claude/skills/rite-prove/SKILL.md +120 -0
- package/pack/.claude/skills/rite-prove/reference/anti-patterns.md +25 -0
- package/pack/.claude/skills/rite-prove/reference/browser-proof.md +26 -0
- package/pack/.claude/skills/rite-prove/reference/failure-triage.md +25 -0
- package/pack/.claude/skills/rite-prove/reference/proof-ladder.md +26 -0
- package/pack/.claude/skills/rite-prove/reference/test-command-discovery.md +30 -0
- package/pack/.claude/skills/rite-quick/SKILL.md +81 -0
- package/pack/.claude/skills/rite-resolve/SKILL.md +113 -0
- package/pack/.claude/skills/rite-resolve/reference/answer-protocol.md +114 -0
- package/pack/.claude/skills/rite-review/SKILL.md +170 -0
- package/pack/.claude/skills/rite-review/reference/anti-patterns.md +32 -0
- package/pack/.claude/skills/rite-review/reference/cognitive-load.md +90 -0
- package/pack/.claude/skills/rite-review/reference/feature-scoped-review.md +26 -0
- package/pack/.claude/skills/rite-review/reference/five-axis-review.md +46 -0
- package/pack/.claude/skills/rite-review/reference/nielsen-heuristics.md +130 -0
- package/pack/.claude/skills/rite-review/reference/parallel-dispatch.md +62 -0
- package/pack/.claude/skills/rite-review/reference/performance-review.md +28 -0
- package/pack/.claude/skills/rite-review/reference/security-review.md +32 -0
- package/pack/.claude/skills/rite-seal/SKILL.md +183 -0
- package/pack/.claude/skills/rite-seal/reference/anti-patterns.md +27 -0
- package/pack/.claude/skills/rite-seal/reference/conventions-ledger.md +63 -0
- package/pack/.claude/skills/rite-seal/reference/final-evidence.md +72 -0
- package/pack/.claude/skills/rite-seal/reference/go-no-go.md +37 -0
- package/pack/.claude/skills/rite-seal/reference/parallel-dispatch.md +69 -0
- package/pack/.claude/skills/rite-seal/reference/risk-and-rollback.md +30 -0
- package/pack/.claude/skills/rite-seal/reference/seal-template.md +36 -0
- package/pack/.claude/skills/rite-ship/SKILL.md +120 -0
- package/pack/.claude/skills/rite-ship/reference/anti-patterns.md +25 -0
- package/pack/.claude/skills/rite-ship/reference/close-out.md +31 -0
- package/pack/.claude/skills/rite-ship/reference/design-memory.md +120 -0
- package/pack/.claude/skills/rite-ship/reference/git-ship.md +42 -0
- package/pack/.claude/skills/rite-ship/reference/ship-template.md +33 -0
- package/pack/.claude/skills/rite-spec/SKILL.md +126 -0
- package/pack/.claude/skills/rite-spec/reference/acceptance-criteria.md +31 -0
- package/pack/.claude/skills/rite-spec/reference/anti-patterns.md +25 -0
- package/pack/.claude/skills/rite-spec/reference/interview-patterns.md +56 -0
- package/pack/.claude/skills/rite-spec/reference/investigation.md +64 -0
- package/pack/.claude/skills/rite-spec/reference/question-protocol.md +61 -0
- package/pack/.claude/skills/rite-spec/reference/references-intake.md +57 -0
- package/pack/.claude/skills/rite-spec/reference/spec-checklists.md +73 -0
- package/pack/.claude/skills/rite-spec/reference/spec-template.md +124 -0
- package/pack/.claude/skills/rite-spec/reference/state-workspace.md +159 -0
- package/pack/.claude/skills/rite-status/SKILL.md +101 -0
- package/pack/.claude/skills/rite-temper/SKILL.md +119 -0
- package/pack/.claude/skills/rite-temper/reference/anti-patterns.md +29 -0
- package/pack/.claude/skills/rite-temper/reference/review-dimensions.md +65 -0
- package/pack/.claude/skills/rite-temper/reference/scope-modes.md +53 -0
- package/pack/.claude/skills/rite-temper/reference/significance.md +46 -0
- package/pack/.claude/skills/rite-temper/reference/strategy-template.md +90 -0
- package/pack/.claude/skills/rite-vet/SKILL.md +155 -0
- package/pack/.claude/skills/rite-vet/reference/anti-patterns.md +29 -0
- package/pack/.claude/skills/rite-vet/reference/artifacts.md +135 -0
- package/pack/.claude/skills/rite-vet/reference/cross-model.md +41 -0
- package/pack/.claude/skills/rite-vet/reference/depth.md +53 -0
- package/pack/.claude/skills/rite-vet/reference/eng-lenses.md +48 -0
- package/pack/.claude/skills/rite-vet/reference/review-axes.md +167 -0
- package/pack/.claude/skills/rite-zoom-out/SKILL.md +75 -0
- package/package.json +68 -0
- package/scripts/build-release-tarball.sh +74 -0
- package/scripts/check-cross-refs.py +121 -0
- package/scripts/check-no-global-writes.sh +44 -0
- package/scripts/check-rule-uniqueness.sh +73 -0
- package/scripts/devrites-detect.sh +175 -0
- package/scripts/eval-runner.py +273 -0
- package/scripts/grade-feature.sh +104 -0
- package/scripts/install-lib.sh +83 -0
- package/scripts/pin.sh +166 -0
- package/scripts/render-eval-summary.py +48 -0
- package/scripts/run-evals.sh +149 -0
- package/scripts/run-outcome-evals.sh +49 -0
- package/scripts/scan-pack-security.py +209 -0
- package/scripts/scan-supply-chain-iocs.py +127 -0
- package/scripts/supply-chain-iocs.json +11 -0
- package/scripts/sync-version.sh +56 -0
- package/scripts/validate-frontmatter.py +149 -0
- package/scripts/validate-workflow-security.py +86 -0
- package/scripts/validate.sh +234 -0
- package/uninstall.sh +137 -0
- package/update.sh +196 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# coverage.sh — render the AC -> slice(s) -> test -> evidence-status traceability matrix
|
|
3
|
+
# for a feature, from the workspace artifacts. The living map /rite-prove and /rite-seal
|
|
4
|
+
# walk to prove every acceptance criterion is covered and proven. Read-only; deterministic.
|
|
5
|
+
#
|
|
6
|
+
# Convention (pairs with check-acceptance.sh): acceptance criteria carry a stable id —
|
|
7
|
+
# spec.md "## Acceptance criteria" -> - [ ] [AC1] <criterion>
|
|
8
|
+
# tasks.md slice -> Satisfies: AC1, AC2
|
|
9
|
+
# seal.md "## Acceptance Criteria" -> - [x] [AC1] <criterion> — evidence: <...>
|
|
10
|
+
# A criterion is proven iff its [ACn] id is checked ([x]) in seal.md.
|
|
11
|
+
#
|
|
12
|
+
# Usage: coverage.sh [slug] (slug defaults to .devrites/ACTIVE)
|
|
13
|
+
# Exit: 0 rendered · 2 no workspace
|
|
14
|
+
set -u
|
|
15
|
+
|
|
16
|
+
slug="${1:-}"
|
|
17
|
+
[ -n "$slug" ] || slug="$(cat .devrites/ACTIVE 2>/dev/null || true)"
|
|
18
|
+
[ -n "$slug" ] || { echo "coverage: no active workspace." >&2; exit 2; }
|
|
19
|
+
d=".devrites/work/$slug"
|
|
20
|
+
[ -d "$d" ] || { echo "coverage: no workspace at $d." >&2; exit 2; }
|
|
21
|
+
|
|
22
|
+
spec="$d/spec.md"; tasks="$d/tasks.md"; seal="$d/seal.md"
|
|
23
|
+
|
|
24
|
+
[ -f "$spec" ] || { echo "coverage: no spec.md — nothing to map." >&2; exit 2; }
|
|
25
|
+
|
|
26
|
+
echo "# Coverage matrix: $slug"
|
|
27
|
+
echo
|
|
28
|
+
echo "| AC | Slice(s) | Proven in seal? |"
|
|
29
|
+
echo "|----|----------|-----------------|"
|
|
30
|
+
|
|
31
|
+
# Each [ACn] id mentioned in spec.md.
|
|
32
|
+
grep -oE '\[AC[0-9]+\]' "$spec" 2>/dev/null | tr -d '[]' | sort -u | while IFS= read -r ac; do
|
|
33
|
+
[ -n "$ac" ] || continue
|
|
34
|
+
# Slices whose "Satisfies:" line names this AC.
|
|
35
|
+
slices=""
|
|
36
|
+
if [ -f "$tasks" ]; then
|
|
37
|
+
slices="$(awk -v ac="$ac" '
|
|
38
|
+
/^##[[:space:]]*Slice/ { s=$0; sub(/^##[[:space:]]*/,"",s) }
|
|
39
|
+
/^[[:space:]]*Satisfies:/ { if (index($0, ac)) { gsub(/^##[[:space:]]*/,"",s); print s } }
|
|
40
|
+
' "$tasks" | paste -sd ';' - 2>/dev/null)"
|
|
41
|
+
fi
|
|
42
|
+
[ -n "$slices" ] || slices="— (UNCOVERED)"
|
|
43
|
+
proven="pending"
|
|
44
|
+
if [ -f "$seal" ] && grep -qE "^[[:space:]]*-[[:space:]]*\[x\][[:space:]]*\[$ac\]" "$seal" 2>/dev/null; then
|
|
45
|
+
proven="yes"
|
|
46
|
+
fi
|
|
47
|
+
printf '| %s | %s | %s |\n' "$ac" "$slices" "$proven"
|
|
48
|
+
done
|
|
49
|
+
|
|
50
|
+
echo
|
|
51
|
+
echo "_Generated by coverage.sh from spec.md / tasks.md / seal.md. UNCOVERED rows block /rite-vet's analyze gate._"
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# devrites — tool-agnostic CLI over the .devrites/ workflow state.
|
|
3
|
+
#
|
|
4
|
+
# The DevRites discipline lives in the .devrites/ Markdown files + these state
|
|
5
|
+
# scripts, NOT in the Claude Code harness. This CLI is the portable surface over
|
|
6
|
+
# them: any agent (Cursor, Codex, Gemini CLI, CI) or a human can orient, gate,
|
|
7
|
+
# and advance a DevRites workflow by calling `devrites <command>` — no skill
|
|
8
|
+
# prose required. (The MCP wrapper in mcp/devrites-mcp.mjs exposes the same ops
|
|
9
|
+
# as MCP tools.)
|
|
10
|
+
#
|
|
11
|
+
# Run from the project root. Sibling scripts resolve by this file's location;
|
|
12
|
+
# the .devrites/ workspace resolves relative to CWD, like the rest of the pack.
|
|
13
|
+
#
|
|
14
|
+
# Commands & exit codes are listed by `devrites help`.
|
|
15
|
+
|
|
16
|
+
set -euo pipefail
|
|
17
|
+
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
18
|
+
|
|
19
|
+
usage() {
|
|
20
|
+
cat <<'EOF'
|
|
21
|
+
devrites — drive the .devrites/ workflow from any tool (run at the project root)
|
|
22
|
+
|
|
23
|
+
orient [slug] orientation digest for the active feature (read-only)
|
|
24
|
+
status [slug] alias for orient
|
|
25
|
+
progress [slug] progress footer — slice meter + flow ribbon (read-only)
|
|
26
|
+
ready [slug] build-readiness gate (0 ready · 2 no-plan · 3 awaiting · 4 blocked · 5 none)
|
|
27
|
+
evidence-fresh [slug] evidence-freshness gate (0 fresh · 3 stale)
|
|
28
|
+
acceptance [slug|dir] acceptance-criteria gate (0 all proven · 1 gap)
|
|
29
|
+
tick-afk [slug] decrement the AFK slice budget (3 = exhausted)
|
|
30
|
+
resolve <args...> answer / --drop / --batch a questions.md entry
|
|
31
|
+
close [slug] archive the workspace + clear ACTIVE
|
|
32
|
+
active print the active slug
|
|
33
|
+
list list workspace slugs under .devrites/work/
|
|
34
|
+
use <slug> re-point .devrites/ACTIVE to <slug>
|
|
35
|
+
help this text
|
|
36
|
+
EOF
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
active_slug() { { cat .devrites/ACTIVE 2>/dev/null || true; } | tr -d '[:space:]'; }
|
|
40
|
+
resolve_slug() { local s="${1:-}"; [ -n "$s" ] || s="$(active_slug)"; printf '%s' "$s"; }
|
|
41
|
+
|
|
42
|
+
cmd="${1:-help}"; [ $# -gt 0 ] && shift || true
|
|
43
|
+
|
|
44
|
+
case "$cmd" in
|
|
45
|
+
orient|status) exec bash "$HERE/preamble.sh" "$@" ;;
|
|
46
|
+
progress) exec bash "$HERE/progress.sh" "$@" ;;
|
|
47
|
+
ready) exec bash "$HERE/readiness.sh" "$@" ;;
|
|
48
|
+
evidence-fresh) exec bash "$HERE/evidence-fresh.sh" "$@" ;;
|
|
49
|
+
acceptance)
|
|
50
|
+
a="${1:-}"
|
|
51
|
+
if [ -n "$a" ] && [ -d "$a" ]; then d="$a"
|
|
52
|
+
else s="$(resolve_slug "${a:-}")"; [ -n "$s" ] || { echo "devrites: no active feature" >&2; exit 5; }; d=".devrites/work/$s"; fi
|
|
53
|
+
exec bash "$HERE/check-acceptance.sh" "$d" ;;
|
|
54
|
+
tick-afk)
|
|
55
|
+
s="$(resolve_slug "${1:-}")"; [ -n "$s" ] || { echo "devrites: no active feature" >&2; exit 5; }
|
|
56
|
+
exec bash "$HERE/tick-afk.sh" ".devrites/work/$s/state.md" ;;
|
|
57
|
+
resolve) exec bash "$HERE/resolve.sh" "$@" ;;
|
|
58
|
+
close)
|
|
59
|
+
s="$(resolve_slug "${1:-}")"; [ -n "$s" ] || { echo "devrites: no slug and no ACTIVE" >&2; exit 4; }
|
|
60
|
+
exec bash "$HERE/close-out.sh" "$s" ;;
|
|
61
|
+
active) a="$(active_slug)"; [ -n "$a" ] && printf '%s\n' "$a" || echo "(none)" ;;
|
|
62
|
+
list) if [ -d .devrites/work ]; then ls -1 .devrites/work; else echo "(no .devrites/work)"; fi ;;
|
|
63
|
+
use)
|
|
64
|
+
s="${1:-}"; [ -n "$s" ] || { echo "usage: devrites use <slug>" >&2; exit 2; }
|
|
65
|
+
[ -d ".devrites/work/$s" ] || { echo "devrites: no workspace .devrites/work/$s" >&2; exit 5; }
|
|
66
|
+
printf '%s\n' "$s" > .devrites/ACTIVE; echo "active: $s" ;;
|
|
67
|
+
help|-h|--help) usage ;;
|
|
68
|
+
*) echo "devrites: unknown command '$cmd' (try: devrites help)" >&2; usage >&2; exit 2 ;;
|
|
69
|
+
esac
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# doctor.sh — DevRites health diagnose. READ-ONLY. Never writes, never blocks.
|
|
3
|
+
#
|
|
4
|
+
# Checks install integrity + the active .devrites/ workspace for the inconsistencies that
|
|
5
|
+
# silently waste a session: a stale ACTIVE pointer, a corrupt workspace, an orphaned gate,
|
|
6
|
+
# or broken hook wiring. Two surfaces wrap this one core:
|
|
7
|
+
# - the SessionStart orient hook calls it and surfaces issues only when there are any
|
|
8
|
+
# (silent-when-healthy);
|
|
9
|
+
# - the /rite-doctor skill calls it with --verbose for a full report on demand.
|
|
10
|
+
#
|
|
11
|
+
# Usage: doctor.sh [--root DIR] [--verbose]
|
|
12
|
+
# Output: one "issue: <what> — <fix>" line per problem (always); with --verbose, also a
|
|
13
|
+
# "ok: <check>" line per passing check.
|
|
14
|
+
# Exit: 0 = healthy (no issues); 1 = one or more issues found.
|
|
15
|
+
set -u
|
|
16
|
+
|
|
17
|
+
ROOT="."
|
|
18
|
+
VERBOSE=0
|
|
19
|
+
while [ $# -gt 0 ]; do
|
|
20
|
+
case "$1" in
|
|
21
|
+
--root) ROOT="$2"; shift 2 ;;
|
|
22
|
+
--root=*) ROOT="${1#--root=}"; shift ;;
|
|
23
|
+
--verbose|-v) VERBOSE=1; shift ;;
|
|
24
|
+
*) shift ;;
|
|
25
|
+
esac
|
|
26
|
+
done
|
|
27
|
+
|
|
28
|
+
issues=0
|
|
29
|
+
issue() { printf 'issue: %s\n' "$1"; issues=$((issues + 1)); }
|
|
30
|
+
ok() { [ "$VERBOSE" -eq 1 ] && printf 'ok: %s\n' "$1"; return 0; }
|
|
31
|
+
|
|
32
|
+
DR="$ROOT/.devrites"
|
|
33
|
+
|
|
34
|
+
# Not a DevRites project at all → nothing to diagnose (stay silent, healthy).
|
|
35
|
+
if [ ! -d "$DR" ]; then
|
|
36
|
+
ok "no .devrites/ — not a DevRites project"
|
|
37
|
+
exit 0
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Resolve the installed pack base (user project = .claude/; dev repo = pack/.claude/).
|
|
41
|
+
BASE="$ROOT/.claude"
|
|
42
|
+
[ -d "$BASE/skills/devrites-lib" ] || BASE="$ROOT/pack/.claude"
|
|
43
|
+
|
|
44
|
+
# 1. Install integrity — the core shared scripts must be present.
|
|
45
|
+
missing=""
|
|
46
|
+
for s in preamble.sh progress.sh readiness.sh conventions.py; do
|
|
47
|
+
[ -f "$BASE/skills/devrites-lib/scripts/$s" ] || missing="$missing $s"
|
|
48
|
+
done
|
|
49
|
+
if [ -n "$missing" ]; then
|
|
50
|
+
issue "install incomplete — missing devrites-lib script(s):$missing — reinstall DevRites"
|
|
51
|
+
else
|
|
52
|
+
ok "devrites-lib core scripts present"
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# 2. Broken hook wiring — every devrites hook referenced in settings.json must exist on disk.
|
|
56
|
+
SET="$ROOT/.claude/settings.json"
|
|
57
|
+
if [ -f "$SET" ]; then
|
|
58
|
+
for h in $(grep -oE 'devrites-[a-z-]+\.sh' "$SET" 2>/dev/null | sort -u); do
|
|
59
|
+
[ -f "$ROOT/.claude/hooks/$h" ] || issue "settings.json wires missing hook: .claude/hooks/$h — reinstall or remove the hook entry"
|
|
60
|
+
done
|
|
61
|
+
ok "hook wiring checked"
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# 3. ACTIVE pointer — if set, it must name a real workspace.
|
|
65
|
+
slug="$(cat "$DR/ACTIVE" 2>/dev/null | tr -d '[:space:]')"
|
|
66
|
+
if [ -z "$slug" ]; then
|
|
67
|
+
ok "no active feature (ACTIVE empty)"
|
|
68
|
+
else
|
|
69
|
+
WS="$DR/work/$slug"
|
|
70
|
+
if [ ! -d "$WS" ]; then
|
|
71
|
+
issue "stale ACTIVE — points at '$slug' but .devrites/work/$slug/ is gone — run /rite-status or 'rite use <slug>'"
|
|
72
|
+
else
|
|
73
|
+
ok "active feature '$slug' workspace present"
|
|
74
|
+
# 4. Corrupt workspace — an active workspace must have state.md.
|
|
75
|
+
if [ ! -f "$WS/state.md" ]; then
|
|
76
|
+
issue "corrupt workspace '$slug' — state.md missing — the phase cursor is lost"
|
|
77
|
+
else
|
|
78
|
+
ok "workspace '$slug' has state.md"
|
|
79
|
+
# 5. Orphaned gate — an open validating/blocking question while the feature reads done/shipped.
|
|
80
|
+
if [ -f "$WS/questions.md" ] && grep -qiE '^status:[[:space:]]*open' "$WS/questions.md" 2>/dev/null \
|
|
81
|
+
&& grep -qiE '^gate:[[:space:]]*(validating|blocking)' "$WS/questions.md" 2>/dev/null \
|
|
82
|
+
&& grep -qiE '(phase|status):[[:space:]]*(done|shipped)' "$WS/state.md" 2>/dev/null; then
|
|
83
|
+
issue "orphaned gate in '$slug' — an open validating/blocking question remains while state reads done/shipped — resolve it via /rite-resolve"
|
|
84
|
+
else
|
|
85
|
+
ok "no orphaned gates in '$slug'"
|
|
86
|
+
fi
|
|
87
|
+
fi
|
|
88
|
+
fi
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
[ "$issues" -gt 0 ] && exit 1
|
|
92
|
+
exit 0
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Evidence-freshness gate for DevRites — enforces the rule in
|
|
3
|
+
# rite-seal/reference/final-evidence.md ("evidence must post-date the code it
|
|
4
|
+
# proves; if any touched file is newer than the proof it is a NO-GO until
|
|
5
|
+
# re-proven") as a deterministic exit code, instead of a prose mtime comparison
|
|
6
|
+
# the model must remember to perform. Used by /rite-seal; usable by /rite-prove.
|
|
7
|
+
# Read-only.
|
|
8
|
+
#
|
|
9
|
+
# Usage: evidence-fresh.sh [slug]
|
|
10
|
+
# slug — optional; defaults to .devrites/ACTIVE
|
|
11
|
+
#
|
|
12
|
+
# Compares the newest mtime among files referenced in touched-files.md
|
|
13
|
+
# (backtick-quoted paths that still exist) against evidence.md /
|
|
14
|
+
# browser-evidence.md. If any touched file is newer, the proof is stale.
|
|
15
|
+
#
|
|
16
|
+
# Exit codes:
|
|
17
|
+
# 0 fresh (evidence post-dates every touched file) — or nothing to compare
|
|
18
|
+
# 3 STALE — a touched file is newer than the proof → re-run /rite-prove
|
|
19
|
+
# 5 no workspace / no evidence to check
|
|
20
|
+
|
|
21
|
+
set -euo pipefail
|
|
22
|
+
|
|
23
|
+
slug="${1:-$(cat .devrites/ACTIVE 2>/dev/null || true)}"
|
|
24
|
+
d=".devrites/work/$slug"
|
|
25
|
+
if [ -z "$slug" ] || [ ! -d "$d" ]; then
|
|
26
|
+
printf 'evidence-fresh: no active workspace (slug=%s)\n' "${slug:-<unset>}" >&2
|
|
27
|
+
exit 5
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
ev="$d/evidence.md"; bev="$d/browser-evidence.md"; tf="$d/touched-files.md"
|
|
31
|
+
if [ ! -f "$ev" ] && [ ! -f "$bev" ]; then
|
|
32
|
+
printf 'evidence-fresh: no evidence.md / browser-evidence.md in %s — run /rite-prove\n' "$d" >&2
|
|
33
|
+
exit 5
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Portable mtime in epoch seconds: GNU coreutils `stat -c`, BSD/macOS `stat -f`.
|
|
37
|
+
mtime() { stat -c %Y "$1" 2>/dev/null || stat -f %m "$1" 2>/dev/null || echo 0; }
|
|
38
|
+
|
|
39
|
+
newest_ev=0
|
|
40
|
+
for f in "$ev" "$bev"; do
|
|
41
|
+
[ -f "$f" ] || continue
|
|
42
|
+
m=$(mtime "$f"); [ "$m" -gt "$newest_ev" ] && newest_ev=$m
|
|
43
|
+
done
|
|
44
|
+
|
|
45
|
+
if [ ! -f "$tf" ]; then
|
|
46
|
+
printf 'evidence-fresh: no touched-files.md — nothing to compare (treating as fresh).\n'
|
|
47
|
+
exit 0
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
newest_code=0; newest_path=""
|
|
51
|
+
while IFS= read -r p; do
|
|
52
|
+
[ -n "$p" ] && [ -f "$p" ] || continue
|
|
53
|
+
m=$(mtime "$p")
|
|
54
|
+
if [ "$m" -gt "$newest_code" ]; then newest_code=$m; newest_path="$p"; fi
|
|
55
|
+
done < <(grep -oE '`[^`]+`' "$tf" 2>/dev/null | tr -d '`')
|
|
56
|
+
|
|
57
|
+
if [ "$newest_code" -gt "$newest_ev" ]; then
|
|
58
|
+
printf 'evidence-fresh: STALE — %s is newer than the proof. Re-run /rite-prove before GO.\n' "$newest_path" >&2
|
|
59
|
+
exit 3
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
printf 'evidence-fresh: OK — evidence post-dates every touched file.\n'
|
|
63
|
+
exit 0
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# footprint.sh — the fan-out footprint for a feature: how heavy the run was, in numbers
|
|
3
|
+
# DevRites can actually count. NO token or dollar figure is ever produced (DevRites can't
|
|
4
|
+
# truthfully source one — inventing it would violate the proof thesis). Deterministic:
|
|
5
|
+
# every number comes from the append-only dispatch log the orchestrator writes.
|
|
6
|
+
#
|
|
7
|
+
# footprint.sh log <slug> <kind> [label] # append one dispatch record (orchestrator)
|
|
8
|
+
# footprint.sh render <slug> # print the one-line footprint (read-only)
|
|
9
|
+
#
|
|
10
|
+
# kind ∈ wright | reviewer | audit | doubt. The log lives at
|
|
11
|
+
# .devrites/work/<slug>/footprint.log as "<epoch> <kind> <label>" lines.
|
|
12
|
+
set -u
|
|
13
|
+
|
|
14
|
+
cmd="${1:-}"; slug="${2:-}"
|
|
15
|
+
[ -n "$cmd" ] && [ -n "$slug" ] || { echo "usage: footprint.sh log|render <slug> [...]" >&2; exit 2; }
|
|
16
|
+
|
|
17
|
+
dir=".devrites/work/$slug"
|
|
18
|
+
log="$dir/footprint.log"
|
|
19
|
+
|
|
20
|
+
case "$cmd" in
|
|
21
|
+
log)
|
|
22
|
+
kind="${3:-}"; label="${4:-}"
|
|
23
|
+
[ -n "$kind" ] || { echo "usage: footprint.sh log <slug> <kind> [label]" >&2; exit 2; }
|
|
24
|
+
[ -d "$dir" ] || exit 0 # no workspace → nothing to record (never fail the caller)
|
|
25
|
+
printf '%s %s %s\n' "$(date +%s)" "$kind" "$label" >> "$log"
|
|
26
|
+
;;
|
|
27
|
+
render)
|
|
28
|
+
[ -f "$log" ] || { echo "Footprint: n/a (no dispatch records)"; exit 0; }
|
|
29
|
+
awk '
|
|
30
|
+
{ n++; c[$2]++; e=$1; if (min=="" || e<min) min=e; if (e>max) max=e }
|
|
31
|
+
END {
|
|
32
|
+
mins = (max>min) ? int((max-min)/60) : 0
|
|
33
|
+
w=c["wright"]+0; r=c["reviewer"]+0; a=c["audit"]+0; d=c["doubt"]+0
|
|
34
|
+
parts=""
|
|
35
|
+
if (w) parts = parts sep w " wright"; sep=" · "
|
|
36
|
+
if (r) { parts = parts sep r " reviewer" (r==1?"":"s"); sep=" · " }
|
|
37
|
+
if (a) { parts = parts sep a " audit" (a==1?"":"s"); sep=" · " }
|
|
38
|
+
if (d) { parts = parts sep d " doubt"; sep=" · " }
|
|
39
|
+
printf "Footprint: %d subagent%s (%s) · %d slice%s · ~%dm active\n", \
|
|
40
|
+
n, (n==1?"":"s"), parts, w, (w==1?"":"s"), mins
|
|
41
|
+
}' "$log"
|
|
42
|
+
;;
|
|
43
|
+
*)
|
|
44
|
+
echo "usage: footprint.sh log|render <slug> [...]" >&2; exit 2 ;;
|
|
45
|
+
esac
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# learnings.sh — the cross-feature learning ledger for /rite-learn. Recurring corrections,
|
|
3
|
+
# dismissed review findings, and dead-ends are durable signal that today dies with each
|
|
4
|
+
# archived feature; this captures them in .devrites/learnings.md (loaded by the review
|
|
5
|
+
# skills before a fan-out) and mines archived features for repeated patterns worth
|
|
6
|
+
# promoting to a project rule. `add`/`mine` only; the promotion decision stays human.
|
|
7
|
+
#
|
|
8
|
+
# learnings.sh add <slug> "<text>" [tag] # append a dated entry to the ledger
|
|
9
|
+
# learnings.sh list # print the ledger
|
|
10
|
+
# learnings.sh mine [archive-dir] # cluster repeated finding phrases from archived features
|
|
11
|
+
# learnings.sh nudge [archive-dir] # silent unless a class recurs >=3x AND new signal since last review
|
|
12
|
+
#
|
|
13
|
+
# Ledger: .devrites/learnings.md (created on first add). `list`/`mine`/`nudge` are read-only.
|
|
14
|
+
# `nudge` snoozes on .devrites/.learnings-reviewed (touched by /rite-learn) so it never nags.
|
|
15
|
+
#
|
|
16
|
+
# Exit codes: 0 ok · 2 bad args
|
|
17
|
+
set -u
|
|
18
|
+
|
|
19
|
+
ledger=".devrites/learnings.md"
|
|
20
|
+
cmd="${1:-}"
|
|
21
|
+
|
|
22
|
+
case "$cmd" in
|
|
23
|
+
add)
|
|
24
|
+
slug="${2:-}"; text="${3:-}"; tag="${4:-note}"
|
|
25
|
+
[ -n "$text" ] || { echo "usage: learnings.sh add <slug> \"<text>\" [tag]" >&2; exit 2; }
|
|
26
|
+
if [ ! -f "$ledger" ]; then
|
|
27
|
+
mkdir -p "$(dirname "$ledger")"
|
|
28
|
+
printf '# DevRites learnings ledger\n\nProject-local lessons mined from shipped features — recurring corrections,\ndismissed-finding classes, and dead-ends. Loaded by the review skills before a fan-out so\nthe same false positive or the same mistake does not recur. Untrusted prior: live code\nalways overrides a ledger entry (see rules/security.md).\n\n' > "$ledger"
|
|
29
|
+
fi
|
|
30
|
+
printf -- '- [%s] (%s · %s) %s\n' "$(date +%Y-%m-%d)" "$tag" "${slug:-?}" "$text" >> "$ledger"
|
|
31
|
+
echo "learnings: recorded."
|
|
32
|
+
;;
|
|
33
|
+
list)
|
|
34
|
+
[ -f "$ledger" ] && cat "$ledger" || echo "learnings: ledger empty ($ledger not present)."
|
|
35
|
+
;;
|
|
36
|
+
mine)
|
|
37
|
+
arch="${2:-.devrites/archive}"
|
|
38
|
+
[ -d "$arch" ] || { echo "learnings: no archive at $arch — nothing to mine."; exit 0; }
|
|
39
|
+
echo "learnings: repeated finding/decision phrases across archived features (count >= 2):"
|
|
40
|
+
# Pull short finding/dead-end lines, normalize (lowercase, strip ids/paths/numbers), cluster.
|
|
41
|
+
grep -rhiE '^[-*] |finding|dead end|drift|dismiss' \
|
|
42
|
+
"$arch"/*/decisions.md "$arch"/*/drift.md "$arch"/*/review.md 2>/dev/null \
|
|
43
|
+
| sed -E 's/^[-*[:space:]]+//; s/`[^`]*`//g; s/[0-9]+//g; s/[[:space:]]+/ /g' \
|
|
44
|
+
| tr '[:upper:]' '[:lower:]' \
|
|
45
|
+
| awk '{ $1=$1; if (length($0) > 12) print substr($0,1,80) }' \
|
|
46
|
+
| sort | uniq -c | sort -rn \
|
|
47
|
+
| awk '$1 >= 2 { printf " %2d× %s\n", $1, substr($0, index($0,$2)) }' \
|
|
48
|
+
| head -25
|
|
49
|
+
echo "(review these — a stable recurring class is a candidate for a project rule or a ledger entry.)"
|
|
50
|
+
;;
|
|
51
|
+
nudge)
|
|
52
|
+
arch="${2:-.devrites/archive}"
|
|
53
|
+
[ -d "$arch" ] || exit 0
|
|
54
|
+
# Cross-feature only: need >=2 shipped features before a "recurring across features" nudge.
|
|
55
|
+
[ "$(ls -d "$arch"/*/ 2>/dev/null | wc -l | tr -d ' ')" -ge 2 ] || exit 0
|
|
56
|
+
# Snooze: stay silent if reviewed since the newest archived file changed.
|
|
57
|
+
marker=".devrites/.learnings-reviewed"
|
|
58
|
+
if [ -f "$marker" ] && [ -z "$(find "$arch" -type f -newer "$marker" 2>/dev/null | head -1)" ]; then
|
|
59
|
+
exit 0
|
|
60
|
+
fi
|
|
61
|
+
top="$(grep -rhiE '^[-*] |finding|dead end|drift|dismiss' \
|
|
62
|
+
"$arch"/*/decisions.md "$arch"/*/drift.md "$arch"/*/review.md 2>/dev/null \
|
|
63
|
+
| sed -E 's/^[-*[:space:]]+//; s/`[^`]*`//g; s/[0-9]+//g; s/[[:space:]]+/ /g' \
|
|
64
|
+
| tr '[:upper:]' '[:lower:]' \
|
|
65
|
+
| awk '{ if (length($0) > 12) print substr($0,1,60) }' \
|
|
66
|
+
| sort | uniq -c | sort -rn | awk '$1 >= 3 { print; exit }')"
|
|
67
|
+
[ -z "$top" ] && exit 0
|
|
68
|
+
n="$(printf '%s' "$top" | awk '{print $1}')"
|
|
69
|
+
phrase="$(printf '%s' "$top" | sed -E 's/^[[:space:]]*[0-9]+[[:space:]]+//' | cut -c1-48)"
|
|
70
|
+
printf 'learnings: a pattern recurs %sx across shipped features ("%s…") — review + maybe promote it to a rule with /rite-learn.\n' "$n" "$phrase"
|
|
71
|
+
;;
|
|
72
|
+
*)
|
|
73
|
+
echo "usage: learnings.sh add|list|mine|nudge [...]" >&2; exit 2 ;;
|
|
74
|
+
esac
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# mutation-gate.sh — certify the tests are strong enough to back "done": run the project's
|
|
3
|
+
# mutation runner scoped to the changed files and surface survived mutants (a behaviour no
|
|
4
|
+
# test actually checks). Coverage says a line RAN; mutation says it is CHECKED. Advisory by
|
|
5
|
+
# default (a survivor is a finding for the test reviewer, not an auto-fail) — set
|
|
6
|
+
# DEVRITES_MUTATION=enforce to make a sub-threshold score a hard NO-GO. No runner installed
|
|
7
|
+
# -> exit 0 with a note (never block a project that has no mutation tooling). Best-effort:
|
|
8
|
+
# wraps the runner, does not reimplement it.
|
|
9
|
+
#
|
|
10
|
+
# Usage: mutation-gate.sh [slug] (slug defaults to .devrites/ACTIVE)
|
|
11
|
+
# Env: DEVRITES_MUTATION=enforce DEVRITES_MUTATION_MIN=<percent, default 60>
|
|
12
|
+
# Exit: 0 advisory/clean/no-tool · 2 no workspace · 3 enforce + below threshold
|
|
13
|
+
set -u
|
|
14
|
+
|
|
15
|
+
slug="${1:-}"
|
|
16
|
+
[ -n "$slug" ] || slug="$(cat .devrites/ACTIVE 2>/dev/null || true)"
|
|
17
|
+
[ -n "$slug" ] || { echo "mutation-gate: no active workspace." >&2; exit 2; }
|
|
18
|
+
d=".devrites/work/$slug"
|
|
19
|
+
[ -d "$d" ] || { echo "mutation-gate: no workspace at $d." >&2; exit 2; }
|
|
20
|
+
|
|
21
|
+
root="$(git rev-parse --show-toplevel 2>/dev/null || true)"
|
|
22
|
+
enforce="${DEVRITES_MUTATION:-advisory}"
|
|
23
|
+
min="${DEVRITES_MUTATION_MIN:-60}"
|
|
24
|
+
|
|
25
|
+
tool=""
|
|
26
|
+
if [ -f "${root:-.}/stryker.conf.json" ] || [ -f "${root:-.}/stryker.config.js" ] || [ -f "${root:-.}/stryker.config.mjs" ]; then
|
|
27
|
+
command -v npx >/dev/null 2>&1 && tool="stryker"
|
|
28
|
+
elif command -v mutmut >/dev/null 2>&1; then tool="mutmut"
|
|
29
|
+
elif command -v cosmic-ray >/dev/null 2>&1; then tool="cosmic-ray"
|
|
30
|
+
elif command -v pitest >/dev/null 2>&1 || [ -f "${root:-.}/pom.xml" ]; then tool="pitest"
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
if [ -z "$tool" ]; then
|
|
34
|
+
echo "mutation-gate: no mutation runner detected (stryker / mutmut / cosmic-ray / pitest) — advisory skipped."
|
|
35
|
+
echo " Strengthen the criticals by hand-mutating (flip a comparison, drop a guard) and confirming a test goes red (rules/testing.md)."
|
|
36
|
+
exit 0
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
echo "mutation-gate: detected '$tool'. Run it scoped to the slice's changed files and read the mutation score:"
|
|
40
|
+
case "$tool" in
|
|
41
|
+
stryker) echo " npx stryker run --mutate \"\$(git diff --name-only HEAD | paste -sd, -)\"" ;;
|
|
42
|
+
mutmut) echo " mutmut run --paths-to-mutate \"\$(git diff --name-only HEAD | tr '\\n' ' ')\" && mutmut results" ;;
|
|
43
|
+
cosmic-ray) echo " (configure session over the changed files, then: cosmic-ray exec ... && cr-report ...)" ;;
|
|
44
|
+
pitest) echo " mvn org.pitest:pitest-maven:mutationCoverage -DtargetClasses=<changed>" ;;
|
|
45
|
+
esac
|
|
46
|
+
echo " Record the score + any survived mutants in evidence.md; a survivor is a behaviour no test checks (a finding for the test reviewer)."
|
|
47
|
+
echo " Mode: ${enforce} (DEVRITES_MUTATION=enforce makes a score < ${min}% a NO-GO)."
|
|
48
|
+
|
|
49
|
+
# This wrapper does not execute the (potentially very slow) runner itself — the score is
|
|
50
|
+
# read by the caller and banded into the seal verdict. Enforce only short-circuits the
|
|
51
|
+
# advisory text; the deterministic NO-GO is applied by /rite-seal against the recorded score.
|
|
52
|
+
exit 0
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# package-existence.sh — slopsquatting / hallucinated-dependency gate. Before a slice's
|
|
3
|
+
# new third-party imports are trusted, assert each one is actually DECLARED in the project
|
|
4
|
+
# manifest (not just imported) — the entry point for AI-hallucinated package names that
|
|
5
|
+
# don't exist or typo-squat a real one. Distinct from a known-bad-version (IOC) scanner:
|
|
6
|
+
# this catches the fabricated/undeclared dep. Manifest check is deterministic + offline;
|
|
7
|
+
# a registry-existence probe is best-effort and skipped without network.
|
|
8
|
+
#
|
|
9
|
+
# Usage: package-existence.sh [slug] (slug defaults to .devrites/ACTIVE)
|
|
10
|
+
# Exit: 0 clean / nothing to check · 2 no workspace · 3 undeclared import found
|
|
11
|
+
set -u
|
|
12
|
+
|
|
13
|
+
slug="${1:-}"
|
|
14
|
+
[ -n "$slug" ] || slug="$(cat .devrites/ACTIVE 2>/dev/null || true)"
|
|
15
|
+
[ -n "$slug" ] || { echo "package-existence: no active workspace." >&2; exit 2; }
|
|
16
|
+
d=".devrites/work/$slug"
|
|
17
|
+
[ -d "$d" ] || { echo "package-existence: no workspace at $d." >&2; exit 2; }
|
|
18
|
+
|
|
19
|
+
root="$(git rev-parse --show-toplevel 2>/dev/null || true)"
|
|
20
|
+
[ -n "$root" ] || { echo "package-existence: not a git repo — skipped." >&2; exit 0; }
|
|
21
|
+
base_tree="$(cat "$d/.reconcile-base" 2>/dev/null || true)"
|
|
22
|
+
ref="${base_tree:-HEAD}"
|
|
23
|
+
|
|
24
|
+
# Manifest text to grep declared deps against (JS/TS, Python, Go, Rust).
|
|
25
|
+
manifests=""
|
|
26
|
+
for m in package.json requirements.txt pyproject.toml Pipfile go.mod Cargo.toml; do
|
|
27
|
+
[ -f "$root/$m" ] && manifests="$manifests $root/$m"
|
|
28
|
+
done
|
|
29
|
+
[ -n "$manifests" ] || { echo "package-existence: no recognized manifest — skipped." >&2; exit 0; }
|
|
30
|
+
|
|
31
|
+
declared() { grep -qiE "(^|[^[:alnum:]_-])$(printf '%s' "$1" | sed 's/[.[\*^$()+?{|]/\\&/g')([^[:alnum:]_-]|\$)" $manifests 2>/dev/null; }
|
|
32
|
+
|
|
33
|
+
# Newly-added import lines in the diff (lines starting with '+', not the +++ header).
|
|
34
|
+
added="$(git -C "$root" diff "$ref" 2>/dev/null | grep -E '^\+' | grep -vE '^\+\+\+')"
|
|
35
|
+
|
|
36
|
+
# Extract bare top-level package names from common import forms.
|
|
37
|
+
pkgs="$(printf '%s\n' "$added" | grep -oE \
|
|
38
|
+
"from +['\"][^'\".]+|require\(['\"][^'\".]+|import +[A-Za-z0-9_]+|^\+[[:space:]]*import +[a-zA-Z0-9_]+" \
|
|
39
|
+
2>/dev/null \
|
|
40
|
+
| sed -E "s/.*['\"]//; s/^\+?[[:space:]]*(from|import|require\()?[[:space:]]*//" \
|
|
41
|
+
| grep -oE '^[@A-Za-z0-9_][A-Za-z0-9_./-]*' \
|
|
42
|
+
| sed -E 's#^(@[^/]+/[^/]+).*#\1#; s#^([^@][^/]+)/.*#\1#' \
|
|
43
|
+
| grep -vE '^(\.|/|[A-Z]:)' \
|
|
44
|
+
| sort -u)"
|
|
45
|
+
|
|
46
|
+
# Standard-library / local prefixes that never need a manifest entry.
|
|
47
|
+
STD='^(os|sys|re|json|math|time|datetime|typing|collections|itertools|functools|pathlib|subprocess|logging|fmt|errors|context|strings|strconv|net|http|io|bufio|std|core|alloc|crate|self|super|react|node:|fs|path|util|crypto|events|stream|child_process)$'
|
|
48
|
+
|
|
49
|
+
bad=0; report=""
|
|
50
|
+
while IFS= read -r p; do
|
|
51
|
+
[ -n "$p" ] || continue
|
|
52
|
+
printf '%s' "$p" | grep -qE "$STD" && continue
|
|
53
|
+
if ! declared "$p"; then
|
|
54
|
+
bad=$((bad+1)); report="${report} - ${p}: imported but not declared in any manifest
|
|
55
|
+
"
|
|
56
|
+
fi
|
|
57
|
+
done <<EOF
|
|
58
|
+
$pkgs
|
|
59
|
+
EOF
|
|
60
|
+
|
|
61
|
+
if [ "$bad" -gt 0 ]; then
|
|
62
|
+
echo "package-existence: $bad imported package(s) are NOT declared in a manifest — verify each exists and add it via the package manager:" >&2
|
|
63
|
+
printf '%s' "$report" >&2
|
|
64
|
+
echo "An undeclared import is how hallucinated/typo-squatted packages slip in. Confirm the name on the registry before trusting it." >&2
|
|
65
|
+
exit 3
|
|
66
|
+
fi
|
|
67
|
+
echo "package-existence: OK — every new third-party import is declared in a manifest."
|
|
68
|
+
exit 0
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# DevRites orientation preamble — print the active feature's workspace state.
|
|
3
|
+
# Run first (step 0) by every workspace-operating rite-* skill via the standard
|
|
4
|
+
# resolution snippet. Read-only; never mutates workspace files.
|
|
5
|
+
# Portable across harnesses (no Claude-Code-specific `!`-prefix syntax in SKILL.md).
|
|
6
|
+
#
|
|
7
|
+
# Usage: preamble.sh [slug]
|
|
8
|
+
# slug — optional override; defaults to .devrites/ACTIVE
|
|
9
|
+
#
|
|
10
|
+
# Paths resolve relative to CWD (the project root), matching the rest of the
|
|
11
|
+
# pack; do not anchor to the git root here — callers/tests run it with CWD set
|
|
12
|
+
# to the workspace root, which is not always a git repo.
|
|
13
|
+
#
|
|
14
|
+
# Output: structured plain text the SKILL.md asks the model to orient from.
|
|
15
|
+
|
|
16
|
+
set -u
|
|
17
|
+
slug="${1:-$(cat .devrites/ACTIVE 2>/dev/null)}"
|
|
18
|
+
d=".devrites/work/$slug"
|
|
19
|
+
|
|
20
|
+
if [ -z "$slug" ] || [ ! -d "$d" ]; then
|
|
21
|
+
echo "No active workspace. Run /rite-spec <feature> to start."
|
|
22
|
+
exit 0
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
echo "## $slug"
|
|
26
|
+
if [ -f "$d/state.md" ]; then
|
|
27
|
+
echo "### state.md"
|
|
28
|
+
cat "$d/state.md"
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
echo
|
|
32
|
+
echo "### artifacts present"
|
|
33
|
+
for f in brief spec references strategy plan tasks eng-review test-plan questions decisions assumptions drift touched-files evidence browser-evidence design-brief polish-report review seal ship handoff; do
|
|
34
|
+
if [ -f "$d/$f.md" ]; then
|
|
35
|
+
echo " ✓ $f.md"
|
|
36
|
+
fi
|
|
37
|
+
done
|
|
38
|
+
|
|
39
|
+
echo
|
|
40
|
+
echo "### run mode"
|
|
41
|
+
if [ -f ".devrites/AFK" ]; then
|
|
42
|
+
echo " AFK (sentinel present)"
|
|
43
|
+
# surface optional config without parsing yaml — print non-comment lines verbatim
|
|
44
|
+
grep -vE '^\s*(#|$)' .devrites/AFK 2>/dev/null | sed 's/^/ /'
|
|
45
|
+
else
|
|
46
|
+
echo " HITL (no sentinel)"
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
echo
|
|
50
|
+
echo "### questions"
|
|
51
|
+
q="$d/questions.md"
|
|
52
|
+
if [ -f "$q" ]; then
|
|
53
|
+
# Tally by gate using "status:" + "gate:" lines that follow each "## q-" header.
|
|
54
|
+
awk '
|
|
55
|
+
# Finalize the previous block BEFORE resetting — adjacent "## q-" headers
|
|
56
|
+
# would otherwise drop every open question except the last.
|
|
57
|
+
/^## q-/ {
|
|
58
|
+
if (in_q && status == "open") counts[gate]++
|
|
59
|
+
in_q=1; status=""; gate=""; next
|
|
60
|
+
}
|
|
61
|
+
in_q && /^status:/ { sub(/^status:[[:space:]]*/, "", $0); status=$0 }
|
|
62
|
+
in_q && /^gate:/ { sub(/^gate:[[:space:]]*/, "", $0); gate=$0 }
|
|
63
|
+
in_q && /^##[[:space:]]/ {
|
|
64
|
+
# a non-question header ends the block — finalize; only counts "open"
|
|
65
|
+
if (status == "open") counts[gate]++
|
|
66
|
+
in_q=0
|
|
67
|
+
}
|
|
68
|
+
END {
|
|
69
|
+
if (in_q && status == "open") counts[gate]++
|
|
70
|
+
printf " open: %d blocking, %d validating, %d advisory, %d escalating\n", \
|
|
71
|
+
counts["blocking"]+0, counts["validating"]+0, counts["advisory"]+0, counts["escalating"]+0
|
|
72
|
+
}
|
|
73
|
+
' "$q"
|
|
74
|
+
else
|
|
75
|
+
echo " (no questions.md yet)"
|
|
76
|
+
fi
|