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.
Files changed (232) hide show
  1. package/.claude-plugin/marketplace.json +24 -0
  2. package/.claude-plugin/plugin.json +43 -0
  3. package/CHANGELOG.md +391 -0
  4. package/LICENSE +56 -0
  5. package/NOTICE.md +18 -0
  6. package/README.md +582 -0
  7. package/SECURITY.md +193 -0
  8. package/bin/devrites.mjs +100 -0
  9. package/docs/architecture.md +272 -0
  10. package/docs/cli-mcp.md +57 -0
  11. package/docs/command-map.md +143 -0
  12. package/docs/flow.md +360 -0
  13. package/docs/release.md +29 -0
  14. package/docs/skills.md +214 -0
  15. package/docs/usage.md +325 -0
  16. package/install.sh +359 -0
  17. package/mcp/devrites-mcp.mjs +103 -0
  18. package/pack/.claude/agents/devrites-code-reviewer.md +50 -0
  19. package/pack/.claude/agents/devrites-doubt-reviewer.md +55 -0
  20. package/pack/.claude/agents/devrites-frontend-reviewer.md +52 -0
  21. package/pack/.claude/agents/devrites-performance-reviewer.md +47 -0
  22. package/pack/.claude/agents/devrites-plan-reviewer.md +79 -0
  23. package/pack/.claude/agents/devrites-security-auditor.md +53 -0
  24. package/pack/.claude/agents/devrites-simplifier-reviewer.md +75 -0
  25. package/pack/.claude/agents/devrites-slice-wright.md +181 -0
  26. package/pack/.claude/agents/devrites-spec-reviewer.md +72 -0
  27. package/pack/.claude/agents/devrites-strategy-reviewer.md +62 -0
  28. package/pack/.claude/agents/devrites-test-analyst.md +47 -0
  29. package/pack/.claude/hooks/devrites-a1-guard.sh +81 -0
  30. package/pack/.claude/hooks/devrites-allow.sh +44 -0
  31. package/pack/.claude/hooks/devrites-cursor.sh +28 -0
  32. package/pack/.claude/hooks/devrites-orient.sh +53 -0
  33. package/pack/.claude/hooks/devrites-redwatch.sh +39 -0
  34. package/pack/.claude/hooks/devrites-refresh-indexes.sh +127 -0
  35. package/pack/.claude/hooks/devrites-reviewer-readonly.sh +28 -0
  36. package/pack/.claude/hooks/devrites-statusline.sh +18 -0
  37. package/pack/.claude/hooks/devrites-stop-gate.sh +45 -0
  38. package/pack/.claude/hooks/devrites-wright-scope.sh +35 -0
  39. package/pack/.claude/hooks/hooks.json +52 -0
  40. package/pack/.claude/rules/README.md +48 -0
  41. package/pack/.claude/rules/afk-hitl.md +245 -0
  42. package/pack/.claude/rules/agents.md +98 -0
  43. package/pack/.claude/rules/anti-patterns.md +48 -0
  44. package/pack/.claude/rules/code-review.md +38 -0
  45. package/pack/.claude/rules/coding-style.md +55 -0
  46. package/pack/.claude/rules/context-hygiene.md +97 -0
  47. package/pack/.claude/rules/core.md +119 -0
  48. package/pack/.claude/rules/development-workflow.md +40 -0
  49. package/pack/.claude/rules/documentation.md +27 -0
  50. package/pack/.claude/rules/error-handling.md +33 -0
  51. package/pack/.claude/rules/git-workflow.md +35 -0
  52. package/pack/.claude/rules/hooks.md +38 -0
  53. package/pack/.claude/rules/patterns.md +45 -0
  54. package/pack/.claude/rules/performance.md +27 -0
  55. package/pack/.claude/rules/prose-style.md +101 -0
  56. package/pack/.claude/rules/security.md +63 -0
  57. package/pack/.claude/rules/testing.md +88 -0
  58. package/pack/.claude/rules/tooling.md +72 -0
  59. package/pack/.claude/settings.json +53 -0
  60. package/pack/.claude/skills/devrites-api-interface/SKILL.md +45 -0
  61. package/pack/.claude/skills/devrites-audit/SKILL.md +73 -0
  62. package/pack/.claude/skills/devrites-browser-proof/SKILL.md +38 -0
  63. package/pack/.claude/skills/devrites-debug-recovery/SKILL.md +50 -0
  64. package/pack/.claude/skills/devrites-debug-recovery/reference/build-the-loop.md +47 -0
  65. package/pack/.claude/skills/devrites-debug-recovery/reference/cleanup-and-classify.md +17 -0
  66. package/pack/.claude/skills/devrites-debug-recovery/reference/hypotheses.md +17 -0
  67. package/pack/.claude/skills/devrites-debug-recovery/reference/instrumentation.md +21 -0
  68. package/pack/.claude/skills/devrites-debug-recovery/reference/regression-test.md +31 -0
  69. package/pack/.claude/skills/devrites-doubt/SKILL.md +75 -0
  70. package/pack/.claude/skills/devrites-frontend-craft/SKILL.md +96 -0
  71. package/pack/.claude/skills/devrites-frontend-craft/reference/craft.md +59 -0
  72. package/pack/.claude/skills/devrites-frontend-craft/reference/design-references.md +116 -0
  73. package/pack/.claude/skills/devrites-frontend-craft/reference/fullstack.md +45 -0
  74. package/pack/.claude/skills/devrites-frontend-craft/reference/quality-standards.md +215 -0
  75. package/pack/.claude/skills/devrites-frontend-craft/reference/reuse-first.md +59 -0
  76. package/pack/.claude/skills/devrites-frontend-craft/reference/shape.md +60 -0
  77. package/pack/.claude/skills/devrites-interview/SKILL.md +81 -0
  78. package/pack/.claude/skills/devrites-lib/SKILL.md +76 -0
  79. package/pack/.claude/skills/devrites-lib/scripts/analyze.sh +78 -0
  80. package/pack/.claude/skills/devrites-lib/scripts/check-acceptance.sh +75 -0
  81. package/pack/.claude/skills/devrites-lib/scripts/close-out.sh +47 -0
  82. package/pack/.claude/skills/devrites-lib/scripts/conventions.py +273 -0
  83. package/pack/.claude/skills/devrites-lib/scripts/coverage.sh +51 -0
  84. package/pack/.claude/skills/devrites-lib/scripts/devrites.sh +69 -0
  85. package/pack/.claude/skills/devrites-lib/scripts/doctor.sh +92 -0
  86. package/pack/.claude/skills/devrites-lib/scripts/evidence-fresh.sh +63 -0
  87. package/pack/.claude/skills/devrites-lib/scripts/footprint.sh +45 -0
  88. package/pack/.claude/skills/devrites-lib/scripts/learnings.sh +74 -0
  89. package/pack/.claude/skills/devrites-lib/scripts/mutation-gate.sh +52 -0
  90. package/pack/.claude/skills/devrites-lib/scripts/package-existence.sh +68 -0
  91. package/pack/.claude/skills/devrites-lib/scripts/preamble.sh +76 -0
  92. package/pack/.claude/skills/devrites-lib/scripts/progress.sh +103 -0
  93. package/pack/.claude/skills/devrites-lib/scripts/readiness.sh +62 -0
  94. package/pack/.claude/skills/devrites-lib/scripts/reconcile.sh +123 -0
  95. package/pack/.claude/skills/devrites-lib/scripts/resolve.sh +279 -0
  96. package/pack/.claude/skills/devrites-lib/scripts/stuck.sh +67 -0
  97. package/pack/.claude/skills/devrites-lib/scripts/test-integrity.sh +87 -0
  98. package/pack/.claude/skills/devrites-lib/scripts/tick-afk.sh +52 -0
  99. package/pack/.claude/skills/devrites-prose-craft/SKILL.md +105 -0
  100. package/pack/.claude/skills/devrites-prose-craft/reference/banned-phrases.md +95 -0
  101. package/pack/.claude/skills/devrites-prose-craft/reference/examples.md +88 -0
  102. package/pack/.claude/skills/devrites-prose-craft/reference/structures.md +134 -0
  103. package/pack/.claude/skills/devrites-refresh-indexes/SKILL.md +54 -0
  104. package/pack/.claude/skills/devrites-source-driven/SKILL.md +36 -0
  105. package/pack/.claude/skills/devrites-ux-shape/SKILL.md +121 -0
  106. package/pack/.claude/skills/devrites-ux-shape/reference/brief-template.md +93 -0
  107. package/pack/.claude/skills/devrites-ux-shape/reference/visual-direction-probe.md +48 -0
  108. package/pack/.claude/skills/rite/SKILL.md +135 -0
  109. package/pack/.claude/skills/rite/reference/menu.md +32 -0
  110. package/pack/.claude/skills/rite-adopt/SKILL.md +83 -0
  111. package/pack/.claude/skills/rite-adopt/reference/adoption.md +58 -0
  112. package/pack/.claude/skills/rite-adopt/reference/anti-patterns.md +19 -0
  113. package/pack/.claude/skills/rite-autocomplete/SKILL.md +96 -0
  114. package/pack/.claude/skills/rite-autocomplete/reference/decision-policy.md +35 -0
  115. package/pack/.claude/skills/rite-autocomplete/reference/loop.md +54 -0
  116. package/pack/.claude/skills/rite-autocomplete/reference/stop-conditions.md +59 -0
  117. package/pack/.claude/skills/rite-build/SKILL.md +261 -0
  118. package/pack/.claude/skills/rite-build/reference/afk-discipline.md +145 -0
  119. package/pack/.claude/skills/rite-build/reference/anti-patterns.md +25 -0
  120. package/pack/.claude/skills/rite-build/reference/checkpoint-protocol.md +149 -0
  121. package/pack/.claude/skills/rite-build/reference/evidence-standard.md +32 -0
  122. package/pack/.claude/skills/rite-build/reference/frontend-trigger.md +39 -0
  123. package/pack/.claude/skills/rite-build/reference/one-slice-cycle.md +38 -0
  124. package/pack/.claude/skills/rite-build/reference/spec-drift-guard.md +43 -0
  125. package/pack/.claude/skills/rite-build/reference/tdd.md +26 -0
  126. package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +115 -0
  127. package/pack/.claude/skills/rite-define/SKILL.md +157 -0
  128. package/pack/.claude/skills/rite-define/reference/anti-patterns.md +25 -0
  129. package/pack/.claude/skills/rite-define/reference/gates.md +152 -0
  130. package/pack/.claude/skills/rite-define/reference/plan-template.md +65 -0
  131. package/pack/.claude/skills/rite-doctor/SKILL.md +50 -0
  132. package/pack/.claude/skills/rite-frame/SKILL.md +116 -0
  133. package/pack/.claude/skills/rite-frame/reference/failure-modes.md +68 -0
  134. package/pack/.claude/skills/rite-handoff/SKILL.md +95 -0
  135. package/pack/.claude/skills/rite-handoff/reference/handoff-template.md +34 -0
  136. package/pack/.claude/skills/rite-learn/SKILL.md +82 -0
  137. package/pack/.claude/skills/rite-plan/SKILL.md +82 -0
  138. package/pack/.claude/skills/rite-plan/reference/anti-patterns.md +24 -0
  139. package/pack/.claude/skills/rite-plan/reference/dependency-graph.md +33 -0
  140. package/pack/.claude/skills/rite-plan/reference/replan-and-repair.md +42 -0
  141. package/pack/.claude/skills/rite-plan/reference/slicing.md +52 -0
  142. package/pack/.claude/skills/rite-plan/reference/task-breakdown.md +34 -0
  143. package/pack/.claude/skills/rite-polish/SKILL.md +90 -0
  144. package/pack/.claude/skills/rite-polish/reference/anti-ai-slop.md +177 -0
  145. package/pack/.claude/skills/rite-polish/reference/anti-patterns.md +27 -0
  146. package/pack/.claude/skills/rite-polish/reference/backend-polish.md +80 -0
  147. package/pack/.claude/skills/rite-polish/reference/browser-polish-evidence.md +31 -0
  148. package/pack/.claude/skills/rite-polish/reference/code.md +85 -0
  149. package/pack/.claude/skills/rite-polish/reference/design-system-discovery.md +35 -0
  150. package/pack/.claude/skills/rite-polish/reference/harden-checklist.md +109 -0
  151. package/pack/.claude/skills/rite-polish/reference/ui.md +136 -0
  152. package/pack/.claude/skills/rite-pressure-test/SKILL.md +43 -0
  153. package/pack/.claude/skills/rite-prototype/SKILL.md +87 -0
  154. package/pack/.claude/skills/rite-prove/SKILL.md +120 -0
  155. package/pack/.claude/skills/rite-prove/reference/anti-patterns.md +25 -0
  156. package/pack/.claude/skills/rite-prove/reference/browser-proof.md +26 -0
  157. package/pack/.claude/skills/rite-prove/reference/failure-triage.md +25 -0
  158. package/pack/.claude/skills/rite-prove/reference/proof-ladder.md +26 -0
  159. package/pack/.claude/skills/rite-prove/reference/test-command-discovery.md +30 -0
  160. package/pack/.claude/skills/rite-quick/SKILL.md +81 -0
  161. package/pack/.claude/skills/rite-resolve/SKILL.md +113 -0
  162. package/pack/.claude/skills/rite-resolve/reference/answer-protocol.md +114 -0
  163. package/pack/.claude/skills/rite-review/SKILL.md +170 -0
  164. package/pack/.claude/skills/rite-review/reference/anti-patterns.md +32 -0
  165. package/pack/.claude/skills/rite-review/reference/cognitive-load.md +90 -0
  166. package/pack/.claude/skills/rite-review/reference/feature-scoped-review.md +26 -0
  167. package/pack/.claude/skills/rite-review/reference/five-axis-review.md +46 -0
  168. package/pack/.claude/skills/rite-review/reference/nielsen-heuristics.md +130 -0
  169. package/pack/.claude/skills/rite-review/reference/parallel-dispatch.md +62 -0
  170. package/pack/.claude/skills/rite-review/reference/performance-review.md +28 -0
  171. package/pack/.claude/skills/rite-review/reference/security-review.md +32 -0
  172. package/pack/.claude/skills/rite-seal/SKILL.md +183 -0
  173. package/pack/.claude/skills/rite-seal/reference/anti-patterns.md +27 -0
  174. package/pack/.claude/skills/rite-seal/reference/conventions-ledger.md +63 -0
  175. package/pack/.claude/skills/rite-seal/reference/final-evidence.md +72 -0
  176. package/pack/.claude/skills/rite-seal/reference/go-no-go.md +37 -0
  177. package/pack/.claude/skills/rite-seal/reference/parallel-dispatch.md +69 -0
  178. package/pack/.claude/skills/rite-seal/reference/risk-and-rollback.md +30 -0
  179. package/pack/.claude/skills/rite-seal/reference/seal-template.md +36 -0
  180. package/pack/.claude/skills/rite-ship/SKILL.md +120 -0
  181. package/pack/.claude/skills/rite-ship/reference/anti-patterns.md +25 -0
  182. package/pack/.claude/skills/rite-ship/reference/close-out.md +31 -0
  183. package/pack/.claude/skills/rite-ship/reference/design-memory.md +120 -0
  184. package/pack/.claude/skills/rite-ship/reference/git-ship.md +42 -0
  185. package/pack/.claude/skills/rite-ship/reference/ship-template.md +33 -0
  186. package/pack/.claude/skills/rite-spec/SKILL.md +126 -0
  187. package/pack/.claude/skills/rite-spec/reference/acceptance-criteria.md +31 -0
  188. package/pack/.claude/skills/rite-spec/reference/anti-patterns.md +25 -0
  189. package/pack/.claude/skills/rite-spec/reference/interview-patterns.md +56 -0
  190. package/pack/.claude/skills/rite-spec/reference/investigation.md +64 -0
  191. package/pack/.claude/skills/rite-spec/reference/question-protocol.md +61 -0
  192. package/pack/.claude/skills/rite-spec/reference/references-intake.md +57 -0
  193. package/pack/.claude/skills/rite-spec/reference/spec-checklists.md +73 -0
  194. package/pack/.claude/skills/rite-spec/reference/spec-template.md +124 -0
  195. package/pack/.claude/skills/rite-spec/reference/state-workspace.md +159 -0
  196. package/pack/.claude/skills/rite-status/SKILL.md +101 -0
  197. package/pack/.claude/skills/rite-temper/SKILL.md +119 -0
  198. package/pack/.claude/skills/rite-temper/reference/anti-patterns.md +29 -0
  199. package/pack/.claude/skills/rite-temper/reference/review-dimensions.md +65 -0
  200. package/pack/.claude/skills/rite-temper/reference/scope-modes.md +53 -0
  201. package/pack/.claude/skills/rite-temper/reference/significance.md +46 -0
  202. package/pack/.claude/skills/rite-temper/reference/strategy-template.md +90 -0
  203. package/pack/.claude/skills/rite-vet/SKILL.md +155 -0
  204. package/pack/.claude/skills/rite-vet/reference/anti-patterns.md +29 -0
  205. package/pack/.claude/skills/rite-vet/reference/artifacts.md +135 -0
  206. package/pack/.claude/skills/rite-vet/reference/cross-model.md +41 -0
  207. package/pack/.claude/skills/rite-vet/reference/depth.md +53 -0
  208. package/pack/.claude/skills/rite-vet/reference/eng-lenses.md +48 -0
  209. package/pack/.claude/skills/rite-vet/reference/review-axes.md +167 -0
  210. package/pack/.claude/skills/rite-zoom-out/SKILL.md +75 -0
  211. package/package.json +68 -0
  212. package/scripts/build-release-tarball.sh +74 -0
  213. package/scripts/check-cross-refs.py +121 -0
  214. package/scripts/check-no-global-writes.sh +44 -0
  215. package/scripts/check-rule-uniqueness.sh +73 -0
  216. package/scripts/devrites-detect.sh +175 -0
  217. package/scripts/eval-runner.py +273 -0
  218. package/scripts/grade-feature.sh +104 -0
  219. package/scripts/install-lib.sh +83 -0
  220. package/scripts/pin.sh +166 -0
  221. package/scripts/render-eval-summary.py +48 -0
  222. package/scripts/run-evals.sh +149 -0
  223. package/scripts/run-outcome-evals.sh +49 -0
  224. package/scripts/scan-pack-security.py +209 -0
  225. package/scripts/scan-supply-chain-iocs.py +127 -0
  226. package/scripts/supply-chain-iocs.json +11 -0
  227. package/scripts/sync-version.sh +56 -0
  228. package/scripts/validate-frontmatter.py +149 -0
  229. package/scripts/validate-workflow-security.py +86 -0
  230. package/scripts/validate.sh +234 -0
  231. package/uninstall.sh +137 -0
  232. 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