bigpowers 2.73.9 → 2.74.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 (134) hide show
  1. package/.continue/rules/context7-mcp.md +0 -0
  2. package/.continue/rules/diagnose-stall.md +0 -0
  3. package/.kilocode/rules/context7-mcp.md +0 -0
  4. package/.kilocode/rules/diagnose-stall.md +0 -0
  5. package/.pi/package.json +2 -2
  6. package/.pi/prompts/audit-code.md +17 -13
  7. package/.pi/prompts/change-request.md +3 -1
  8. package/.pi/prompts/compose-workflow.md +15 -0
  9. package/.pi/prompts/context7-mcp.md +54 -0
  10. package/.pi/prompts/craft-skill.md +28 -0
  11. package/.pi/prompts/deepen-architecture.md +20 -0
  12. package/.pi/prompts/delegate-task.md +14 -0
  13. package/.pi/prompts/deploy.md +8 -0
  14. package/.pi/prompts/develop-tdd.md +15 -4
  15. package/.pi/prompts/diagnose-stall.md +53 -0
  16. package/.pi/prompts/dispatch-agents.md +49 -19
  17. package/.pi/prompts/gate-trace.md +9 -1
  18. package/.pi/prompts/guard-git.md +14 -0
  19. package/.pi/prompts/migrate-spec.md +12 -0
  20. package/.pi/prompts/plan-work.md +62 -2
  21. package/.pi/prompts/publish-package.md +11 -0
  22. package/.pi/prompts/release-branch.md +39 -43
  23. package/.pi/prompts/request-review.md +57 -17
  24. package/.pi/prompts/run-benchmark.md +3 -3
  25. package/.pi/prompts/run-evals.md +26 -6
  26. package/.pi/prompts/security-review.md +56 -8
  27. package/.pi/prompts/seed-conventions.md +61 -0
  28. package/.pi/prompts/session-state.md +5 -10
  29. package/.pi/prompts/slice-tasks.md +3 -0
  30. package/.pi/prompts/smoke-test.md +11 -0
  31. package/.pi/prompts/stocktake-skills.md +2 -1
  32. package/.pi/prompts/validate-contracts.md +12 -0
  33. package/.pi/prompts/validate-fix.md +2 -0
  34. package/.pi/prompts/verify-work.md +31 -20
  35. package/.pi/prompts/wire-ci.md +11 -0
  36. package/.pi/prompts/write-document.md +10 -0
  37. package/.pi/skills/audit-code/SKILL.md +17 -13
  38. package/.pi/skills/change-request/SKILL.md +3 -1
  39. package/.pi/skills/compose-workflow/SKILL.md +15 -0
  40. package/.pi/skills/context7-mcp/SKILL.md +56 -0
  41. package/.pi/skills/craft-skill/SKILL.md +28 -0
  42. package/.pi/skills/deepen-architecture/SKILL.md +20 -0
  43. package/.pi/skills/delegate-task/SKILL.md +14 -0
  44. package/.pi/skills/deploy/SKILL.md +8 -0
  45. package/.pi/skills/develop-tdd/SKILL.md +15 -4
  46. package/.pi/skills/diagnose-stall/SKILL.md +55 -0
  47. package/.pi/skills/dispatch-agents/SKILL.md +49 -19
  48. package/.pi/skills/gate-trace/SKILL.md +9 -1
  49. package/.pi/skills/guard-git/SKILL.md +14 -0
  50. package/.pi/skills/migrate-spec/SKILL.md +12 -0
  51. package/.pi/skills/plan-work/SKILL.md +62 -2
  52. package/.pi/skills/publish-package/SKILL.md +11 -0
  53. package/.pi/skills/release-branch/SKILL.md +39 -43
  54. package/.pi/skills/request-review/SKILL.md +57 -17
  55. package/.pi/skills/run-benchmark/SKILL.md +3 -3
  56. package/.pi/skills/run-evals/SKILL.md +26 -6
  57. package/.pi/skills/security-review/SKILL.md +56 -8
  58. package/.pi/skills/seed-conventions/SKILL.md +61 -0
  59. package/.pi/skills/session-state/SKILL.md +5 -10
  60. package/.pi/skills/slice-tasks/SKILL.md +3 -0
  61. package/.pi/skills/smoke-test/SKILL.md +11 -0
  62. package/.pi/skills/stocktake-skills/SKILL.md +2 -1
  63. package/.pi/skills/validate-contracts/SKILL.md +12 -0
  64. package/.pi/skills/validate-fix/SKILL.md +2 -0
  65. package/.pi/skills/verify-work/SKILL.md +31 -20
  66. package/.pi/skills/wire-ci/SKILL.md +11 -0
  67. package/.pi/skills/write-document/SKILL.md +10 -0
  68. package/CHANGELOG.md +7 -0
  69. package/CLAUDE.md +59 -1
  70. package/CONVENTIONS.md +76 -0
  71. package/README.md +1 -1
  72. package/SKILL-INDEX.md +1 -1
  73. package/package.json +1 -1
  74. package/scripts/bp-churn-rank.sh +49 -0
  75. package/scripts/check-import-boundaries.sh +64 -0
  76. package/scripts/compile-rule-matrix.sh +114 -0
  77. package/scripts/hooks/rtk-rewrite.sh +11 -0
  78. package/scripts/hooks/token-mgmt-pre-tool-use.sh +53 -0
  79. package/scripts/install.sh +6 -0
  80. package/scripts/lib/completeness-critic.sh +62 -0
  81. package/scripts/lib/doc-fetch-cache.sh +71 -0
  82. package/scripts/lib/golden-suite-gates.sh +3 -1
  83. package/scripts/lib/parallel-review-worktrees.sh +34 -0
  84. package/scripts/lib/plan-consistency-check.sh +88 -0
  85. package/scripts/lib/run-benchmark.py +210 -0
  86. package/scripts/lib/sync-context-engineering-ref.sh +19 -0
  87. package/scripts/references-manifest.yaml +19 -0
  88. package/scripts/run-benchmark.sh +6 -0
  89. package/scripts/sync-references.sh +25 -0
  90. package/scripts/validate-skill-catalog.sh +147 -0
  91. package/scripts/validate-skill-description.sh +70 -0
  92. package/skills/audit-code/SKILL.md +19 -13
  93. package/skills/change-request/SKILL.md +3 -1
  94. package/skills/compose-workflow/SKILL.md +15 -0
  95. package/skills/context7-mcp/SKILL.md +57 -0
  96. package/skills/craft-skill/SKILL.md +29 -0
  97. package/skills/deepen-architecture/SKILL.md +22 -0
  98. package/skills/delegate-task/SKILL.md +14 -0
  99. package/skills/deploy/SKILL.md +9 -0
  100. package/skills/develop-tdd/SKILL.md +18 -4
  101. package/skills/diagnose-stall/SKILL.md +56 -0
  102. package/skills/dispatch-agents/SKILL.md +51 -19
  103. package/skills/gate-trace/SKILL.md +11 -1
  104. package/skills/guard-git/REFERENCE.md +14 -0
  105. package/skills/migrate-spec/REFERENCE.md +12 -0
  106. package/skills/plan-work/REFERENCE.md +29 -2
  107. package/skills/plan-work/SKILL.md +38 -0
  108. package/skills/publish-package/REFERENCE.md +11 -0
  109. package/skills/release-branch/REFERENCE.md +14 -0
  110. package/skills/release-branch/SKILL.md +28 -43
  111. package/skills/request-review/SKILL.md +59 -17
  112. package/skills/run-benchmark/SKILL.md +4 -4
  113. package/skills/run-evals/REFERENCE.md +14 -4
  114. package/skills/run-evals/SKILL.md +13 -2
  115. package/skills/security-review/REFERENCE-false-positives.md +9 -8
  116. package/skills/security-review/REFERENCE-vuln-categories.md +4 -0
  117. package/skills/security-review/SKILL.md +45 -0
  118. package/skills/security-review/fixtures/CWE-79-xss-negative.js +6 -0
  119. package/skills/security-review/fixtures/CWE-79-xss-positive.js +6 -0
  120. package/skills/security-review/fixtures/CWE-89-sqli-negative.py +8 -0
  121. package/skills/security-review/fixtures/CWE-89-sqli-positive.py +9 -0
  122. package/skills/seed-conventions/REFERENCE.md +40 -0
  123. package/skills/seed-conventions/SKILL.md +22 -0
  124. package/skills/session-state/SKILL.md +5 -10
  125. package/skills/slice-tasks/SKILL.md +3 -0
  126. package/skills/smoke-test/REFERENCE.md +11 -0
  127. package/skills/stocktake-skills/SKILL.md +3 -1
  128. package/skills/validate-contracts/REFERENCE.md +12 -0
  129. package/skills/validate-fix/SKILL.md +3 -0
  130. package/skills/verify-work/REFERENCE.md +17 -0
  131. package/skills/verify-work/SKILL.md +18 -20
  132. package/skills/wire-ci/REFERENCE.md +11 -0
  133. package/skills/write-document/REFERENCE.md +10 -0
  134. package/skills-lock.json +32 -22
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bigpowers",
3
- "version": "2.73.9",
3
+ "version": "2.74.0",
4
4
  "description": "73 agent skills synthesizing 17 years of software engineering discipline into a prescriptive methodology for solo developers",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env bash
2
+ # story: e45s31
3
+ # Rank files by git churn for review prioritization (aidd-churn pattern).
4
+ # Usage: bash scripts/bp-churn-rank.sh [--since 90.days] [--limit N] [path...]
5
+ set -euo pipefail
6
+
7
+ SINCE="90.days"
8
+ LIMIT=20
9
+ PATHS=()
10
+
11
+ while [[ $# -gt 0 ]]; do
12
+ case "$1" in
13
+ --since)
14
+ SINCE="${2:?--since requires a value}"
15
+ shift 2
16
+ ;;
17
+ --limit)
18
+ LIMIT="${2:?--limit requires a number}"
19
+ shift 2
20
+ ;;
21
+ -h|--help)
22
+ echo "Usage: bash scripts/bp-churn-rank.sh [--since 90.days] [--limit 20] [path...]"
23
+ exit 0
24
+ ;;
25
+ *)
26
+ PATHS+=("$1")
27
+ shift
28
+ ;;
29
+ esac
30
+ done
31
+
32
+ if ! git rev-parse --git-dir >/dev/null 2>&1; then
33
+ echo "FAIL: not a git repository" >&2
34
+ exit 1
35
+ fi
36
+
37
+ PATHSPEC=""
38
+ if [[ ${#PATHS[@]} -gt 0 ]]; then
39
+ PATHSPEC="-- ${PATHS[*]}"
40
+ fi
41
+
42
+ # shellcheck disable=SC2086
43
+ git log --since="$SINCE" --name-only --pretty=format: $PATHSPEC \
44
+ | grep -v '^$' \
45
+ | sort \
46
+ | uniq -c \
47
+ | sort -rn \
48
+ | head -n "$LIMIT" \
49
+ | awk '{printf "%4d %s\n", $1, $2}'
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env bash
2
+ # story: e45s14
3
+ # check-import-boundaries.sh — enforce specs/import-boundaries.json in CI
4
+ set -euo pipefail
5
+
6
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
+ REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
8
+ BOUNDARIES="$REPO_ROOT/specs/import-boundaries.json"
9
+
10
+ if [[ ! -f "$BOUNDARIES" ]]; then
11
+ echo "FAIL: missing $BOUNDARIES"
12
+ exit 1
13
+ fi
14
+
15
+ python3 - "$REPO_ROOT" "$BOUNDARIES" <<'PY'
16
+ import json, re, sys
17
+ from pathlib import Path
18
+
19
+ root = Path(sys.argv[1])
20
+ rules_path = Path(sys.argv[2])
21
+ rules = json.loads(rules_path.read_text(encoding="utf-8"))
22
+
23
+ def glob_match(pattern: str, path: str) -> bool:
24
+ import fnmatch
25
+ return fnmatch.fnmatch(path, pattern)
26
+
27
+ violations = []
28
+
29
+ for boundary in rules.get("boundaries", []):
30
+ from_pat = boundary["from"]
31
+ allow = boundary.get("allow", [])
32
+ deny = boundary.get("deny", [])
33
+
34
+ for sh in root.glob("scripts/**/*.sh"):
35
+ rel = sh.relative_to(root).as_posix()
36
+ if not glob_match(from_pat, rel):
37
+ continue
38
+ text = sh.read_text(encoding="utf-8", errors="replace")
39
+ for line in text.splitlines():
40
+ m = re.match(r'^\s*(?:source|\.)\s+["\']?([^"\']+)["\']?', line)
41
+ if not m:
42
+ continue
43
+ target = m.group(1)
44
+ if target.startswith("$"):
45
+ continue
46
+ if not target.startswith("scripts/") and not target.startswith("guard-git/"):
47
+ if any(glob_match(d, target) for d in deny):
48
+ violations.append(f"{rel}: forbidden source {target}")
49
+ continue
50
+ rel_target = target
51
+ if not (Path(root / rel_target).exists() or glob_match(rel_target, rel_target)):
52
+ pass
53
+ allowed = any(glob_match(a, rel_target) for a in allow)
54
+ if not allowed:
55
+ violations.append(f"{rel}: source {rel_target} not in allowlist for {from_pat}")
56
+
57
+ if violations:
58
+ print("IMPORT BOUNDARY FAIL:")
59
+ for v in violations:
60
+ print(f" {v}")
61
+ sys.exit(1)
62
+
63
+ print(f"IMPORT BOUNDARIES OK ({len(rules.get('boundaries', []))} rules)")
64
+ PY
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env bash
2
+ # story: e45s25
3
+ # Compile CONVENTIONS.md risk tiers → versioned specs/rule-matrix.json
4
+ set -euo pipefail
5
+ source "$(dirname "${BASH_SOURCE[0]}")/lib/python-env.sh"
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+ REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
9
+ CONVENTIONS="$REPO_ROOT/CONVENTIONS.md"
10
+ OUTPUT="$REPO_ROOT/specs/rule-matrix.json"
11
+ MATRIX_VERSION="1.0.0"
12
+
13
+ show_help() {
14
+ cat <<EOF
15
+ Usage: $(basename "$0") [OPTION]
16
+
17
+ Compile CONVENTIONS.md § Risk Tiers into specs/rule-matrix.json.
18
+ P0/P1/P2/P3 entries are diffable across git tags.
19
+
20
+ Options:
21
+ --stdout Print JSON to stdout instead of writing file
22
+ --help Show this help and exit
23
+ EOF
24
+ }
25
+
26
+ STDOUT_ONLY=0
27
+ if [ "$#" -eq 1 ]; then
28
+ case "$1" in
29
+ --help) show_help; exit 0 ;;
30
+ --stdout) STDOUT_ONLY=1 ;;
31
+ *) echo "[ERROR] Unknown option: $1" >&2; exit 1 ;;
32
+ esac
33
+ fi
34
+
35
+ if [ ! -f "$CONVENTIONS" ]; then
36
+ echo "[ERROR] CONVENTIONS.md not found at $CONVENTIONS" >&2
37
+ exit 1
38
+ fi
39
+
40
+ $PYTHON - "$CONVENTIONS" "$OUTPUT" "$MATRIX_VERSION" "$STDOUT_ONLY" <<'PY'
41
+ import hashlib
42
+ import json
43
+ import re
44
+ import sys
45
+ from datetime import datetime, timezone
46
+
47
+ conventions_path, output_path, matrix_version, stdout_only = sys.argv[1:5]
48
+ stdout_only = stdout_only == "1"
49
+
50
+ with open(conventions_path, encoding="utf-8") as f:
51
+ content = f.read()
52
+
53
+ source_hash = hashlib.sha256(content.encode("utf-8")).hexdigest()[:16]
54
+
55
+ # Extract Risk Tiers section
56
+ m = re.search(
57
+ r"^## Risk Tiers \(Effective Rule Matrix\)\s*\n(.*?)(?=^## |\Z)",
58
+ content,
59
+ re.MULTILINE | re.DOTALL,
60
+ )
61
+ if not m:
62
+ print("[ERROR] CONVENTIONS.md missing '## Risk Tiers (Effective Rule Matrix)'", file=sys.stderr)
63
+ sys.exit(1)
64
+
65
+ section = m.group(1)
66
+ tier_re = re.compile(r"^### (P[0-3]) —[^\n]*\n(.*?)(?=^### |\Z)", re.MULTILINE | re.DOTALL)
67
+ rule_re = re.compile(
68
+ r"^- \*\*\[([^\]]+)\]\*\*:\s*(.+?)\.\s*\(([^)]+)\)\s*$",
69
+ re.MULTILINE,
70
+ )
71
+
72
+ tiers: dict[str, list[dict]] = {"P0": [], "P1": [], "P2": [], "P3": []}
73
+
74
+ for tier_match in tier_re.finditer(section):
75
+ tier = tier_match.group(1)
76
+ body = tier_match.group(2)
77
+ for rule_match in rule_re.finditer(body):
78
+ rule_id, text, enforce_raw = rule_match.groups()
79
+ enforce = [s.strip().strip("`") for s in enforce_raw.split(",")]
80
+ tiers[tier].append(
81
+ {
82
+ "id": rule_id,
83
+ "text": text.strip(),
84
+ "enforce": enforce,
85
+ }
86
+ )
87
+
88
+ for tier in tiers:
89
+ if not tiers[tier]:
90
+ print(f"[ERROR] No rules parsed for tier {tier}", file=sys.stderr)
91
+ sys.exit(1)
92
+
93
+ doc = {
94
+ "matrix_version": matrix_version,
95
+ "generated_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
96
+ "source": "CONVENTIONS.md",
97
+ "source_section": "Risk Tiers (Effective Rule Matrix)",
98
+ "source_hash": source_hash,
99
+ "tiers": tiers,
100
+ }
101
+
102
+ payload = json.dumps(doc, indent=2, sort_keys=True) + "\n"
103
+
104
+ if stdout_only:
105
+ print(payload, end="")
106
+ else:
107
+ import os
108
+
109
+ os.makedirs(os.path.dirname(output_path), exist_ok=True)
110
+ with open(output_path, "w", encoding="utf-8") as out:
111
+ out.write(payload)
112
+ total = sum(len(v) for v in tiers.values())
113
+ print(f"OK: wrote {output_path} ({total} rules, matrix_version={matrix_version})")
114
+ PY
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env bash
2
+ # story: e45s16
3
+ # rtk-rewrite.sh — PreToolUse hook delegating to rtk's native Bash rewriter.
4
+ set -euo pipefail
5
+
6
+ if command -v rtk >/dev/null 2>&1; then
7
+ exec rtk hook claude
8
+ fi
9
+
10
+ # rtk missing — pass through unchanged (agent should run `bts doctor` / install rtk)
11
+ exit 0
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env bash
2
+ # story: e45s03
3
+ # Mechanical PreToolUse backstop — block oversized Read/Grep/Bash before context bloat.
4
+ set -euo pipefail
5
+
6
+ READ_MAX_BYTES=102400 # 100KB
7
+ GREP_MAX_MATCHES=200
8
+ BASH_WARN_PATTERNS='^(npm test|pnpm test|yarn test|cargo test|go test|jest|vitest|pytest|rake test|rspec|git log|git diff|docker logs|kubectl logs|find |rg |grep )'
9
+
10
+ deny() {
11
+ echo "TOKEN-MGMT BLOCK: $1" >&2
12
+ echo "Use sqz_read_file / sqz_grep / rtk / bts compress per CLAUDE.md § Token Management." >&2
13
+ exit 2
14
+ }
15
+
16
+ INPUT="$(cat)"
17
+ TOOL="$(echo "$INPUT" | jq -r '.tool_name // .tool // empty')"
18
+ TOOL_INPUT="$(echo "$INPUT" | jq -c '.tool_input // .input // {}')"
19
+
20
+ case "$TOOL" in
21
+ Read|read)
22
+ PATH_ARG="$(echo "$TOOL_INPUT" | jq -r '.path // .file_path // .file // empty')"
23
+ [[ -n "$PATH_ARG" && -f "$PATH_ARG" ]] || exit 0
24
+ SIZE="$(wc -c < "$PATH_ARG" | tr -d ' ')"
25
+ if (( SIZE > READ_MAX_BYTES )); then
26
+ deny "Read $PATH_ARG is ${SIZE} bytes (max ${READ_MAX_BYTES}). Use sqz_read_file or bts compress."
27
+ fi
28
+ ;;
29
+ Grep|grep)
30
+ LIMIT="$(echo "$TOOL_INPUT" | jq -r '.head_limit // .max_matches // empty')"
31
+ if [[ -z "$LIMIT" || "$LIMIT" == "null" ]]; then
32
+ deny "Grep without head_limit (max ${GREP_MAX_MATCHES}). Set head_limit<=${GREP_MAX_MATCHES} or use sqz_grep."
33
+ fi
34
+ if [[ "$LIMIT" =~ ^[0-9]+$ ]] && (( LIMIT > GREP_MAX_MATCHES )); then
35
+ deny "Grep head_limit=${LIMIT} exceeds ${GREP_MAX_MATCHES}. Lower limit or use sqz_grep."
36
+ fi
37
+ ;;
38
+ Bash|bash|Shell|shell)
39
+ CMD="$(echo "$TOOL_INPUT" | jq -r '.command // empty')"
40
+ [[ -n "$CMD" ]] || exit 0
41
+ if echo "$CMD" | grep -qE 'sqz compress|bts compress|rtk |SQZ_NO_DEDUP'; then
42
+ exit 0
43
+ fi
44
+ if echo "$CMD" | grep -qE "$BASH_WARN_PATTERNS"; then
45
+ deny "Bash may exceed 500 lines of output. Prefix with rtk or pipe through sqz compress."
46
+ fi
47
+ ;;
48
+ *)
49
+ exit 0
50
+ ;;
51
+ esac
52
+
53
+ exit 0
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env bash
2
+ # story: e45s16
2
3
  # install.sh — global symlink install for bigpowers skills
3
4
  #
4
5
  # Supported tools:
@@ -83,6 +84,9 @@ install_claude() {
83
84
  link "$REPO_ROOT/.gemini/extensions/bigpowers/hooks/run-hook.cmd" "$CLAUDE_HOOKS_DIR/run-hook.cmd"
84
85
  link "$REPO_ROOT/guard-git/scripts/block-dangerous-git.sh" "$CLAUDE_HOOKS_DIR/block-dangerous-git.sh"
85
86
  link "$REPO_ROOT/guard-git/scripts/lib" "$CLAUDE_HOOKS_DIR/lib"
87
+ link "$REPO_ROOT/scripts/hooks/rtk-rewrite.sh" "$CLAUDE_HOOKS_DIR/rtk-rewrite.sh"
88
+ # story: e45s16
89
+ chmod +x "$REPO_ROOT/scripts/hooks/rtk-rewrite.sh" 2>/dev/null || true
86
90
 
87
91
  if [[ -f "$CLAUDE_SETTINGS" ]]; then
88
92
  echo " Configuring global hooks in $CLAUDE_SETTINGS..."
@@ -92,6 +96,7 @@ install_claude() {
92
96
  cat "$CLAUDE_SETTINGS" | jq '
93
97
  .hooks.SessionStart += [{"matcher":"startup|clear|compact","hooks":[{"type":"command","command":"\"'"$CLAUDE_HOOKS_DIR/run-hook.cmd"'\" session-start","async":false}]}] |
94
98
  .hooks.PreToolUse += [{"matcher":"Bash","hooks":[{"type":"command","command":"\"'"$CLAUDE_HOOKS_DIR/block-dangerous-git.sh"'\""}]}] |
99
+ .hooks.PreToolUse += [{"matcher":"Bash","hooks":[{"type":"command","command":"\"'"$CLAUDE_HOOKS_DIR/rtk-rewrite.sh"'\""}]}] |
95
100
  # deduplicate
96
101
  .hooks.SessionStart |= unique |
97
102
  .hooks.PreToolUse |= unique
@@ -115,6 +120,7 @@ uninstall_claude() {
115
120
  unlink_if_managed "$CLAUDE_HOOKS_DIR/session-start" "$REPO_ROOT/"
116
121
  unlink_if_managed "$CLAUDE_HOOKS_DIR/run-hook.cmd" "$REPO_ROOT/"
117
122
  unlink_if_managed "$CLAUDE_HOOKS_DIR/block-dangerous-git.sh" "$REPO_ROOT/"
123
+ unlink_if_managed "$CLAUDE_HOOKS_DIR/rtk-rewrite.sh" "$REPO_ROOT/"
118
124
  unlink_if_managed "$CLAUDE_HOOKS_DIR/lib" "$REPO_ROOT/"
119
125
  fi
120
126
  }
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env bash
2
+ # story: e45s05
3
+ # Adversarial gap-finding completeness critic — post gate-trace.
4
+ # Classifications: BLOCKER | WARNING | FILLED
5
+ set -euo pipefail
6
+
7
+ REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
8
+ cd "$REPO_ROOT"
9
+
10
+ BLOCKERS=0
11
+ WARNINGS=0
12
+ FILLED=0
13
+
14
+ classify() {
15
+ local kind="$1" msg="$2"
16
+ echo "[$kind] $msg"
17
+ case "$kind" in
18
+ BLOCKER) BLOCKERS=$((BLOCKERS + 1)) ;;
19
+ WARNING) WARNINGS=$((WARNINGS + 1)) ;;
20
+ FILLED) FILLED=$((FILLED + 1)) ;;
21
+ esac
22
+ }
23
+
24
+ # Ensure upstream artifacts exist
25
+ [[ -f specs/traceability-matrix.json ]] \
26
+ || classify BLOCKER "Missing specs/traceability-matrix.json — run trace-stories.sh --json"
27
+ [[ -f specs/blind-spots.json ]] \
28
+ || classify BLOCKER "Missing specs/blind-spots.json — run check-blind-spots.sh"
29
+
30
+ if [[ -f specs/traceability-matrix.json ]]; then
31
+ UNDONE="$(jq '[.stories[]? | select(.status != "done" and (.code_tags // 0) == 0)] | length' specs/traceability-matrix.json 2>/dev/null || echo 0)"
32
+ (( UNDONE > 0 )) && classify BLOCKER "$UNDONE active story(ies) with zero code tags"
33
+ COVERAGE="$(jq -r '.summary.coverage_percent // .coverage_percent // empty' specs/traceability-matrix.json 2>/dev/null)"
34
+ if [[ -n "$COVERAGE" && "$COVERAGE" != "null" ]]; then
35
+ awk -v c="$COVERAGE" 'BEGIN{if(c+0 < 60) exit 1}' || classify WARNING "Trace coverage ${COVERAGE}% below 60% target"
36
+ awk -v c="$COVERAGE" 'BEGIN{if(c+0 >= 80) exit 0; exit 1}' && classify FILLED "Trace coverage ${COVERAGE}% meets 80% PASS bar"
37
+ fi
38
+ fi
39
+
40
+ if [[ -f specs/blind-spots.json ]]; then
41
+ HIGH="$(jq '[.findings[]? | select(.severity == "HIGH")] | length' specs/blind-spots.json 2>/dev/null || echo 0)"
42
+ (( HIGH > 0 )) && classify BLOCKER "$HIGH HIGH-severity blind-spot finding(s) remain open"
43
+ fi
44
+
45
+ # Verify evidence for done stories
46
+ if [[ -d specs/verifications ]]; then
47
+ VC="$(find specs/verifications -maxdepth 1 -name '*-verify.yaml' 2>/dev/null | wc -l | tr -d ' ')"
48
+ (( VC == 0 )) && classify WARNING "No specs/verifications/*-verify.yaml evidence bundles"
49
+ (( VC > 0 )) && classify FILLED "$VC verification evidence bundle(s) on disk"
50
+ else
51
+ classify WARNING "specs/verifications/ directory missing"
52
+ fi
53
+
54
+ echo "---"
55
+ echo "completeness-critic: BLOCKER=$BLOCKERS WARNING=$WARNINGS FILLED=$FILLED"
56
+
57
+ if (( BLOCKERS > 0 )); then
58
+ echo "MERGE GATE ABORT: BLOCKER findings must be resolved" >&2
59
+ exit 1
60
+ fi
61
+
62
+ exit 0
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env bash
2
+ # story: e45s20
3
+ # doc-fetch-cache.sh — ETag-revalidated fetch cache for Context7 / bts docs queries.
4
+ # Usage:
5
+ # bash scripts/lib/doc-fetch-cache.sh get <cache-key> # print cached body or empty
6
+ # bash scripts/lib/doc-fetch-cache.sh put <key> <etag> <body-file>
7
+ # bash scripts/lib/doc-fetch-cache.sh stale <cache-key> # exit 0 if TTL expired
8
+ set -euo pipefail
9
+
10
+ CACHE_DIR="${DOC_CACHE_DIR:-.bigpowers/cache/docs}"
11
+ TTL_SEC="${DOC_CACHE_TTL:-300}"
12
+
13
+ mkdir -p "$CACHE_DIR"
14
+
15
+ _key_path() {
16
+ local key="$1"
17
+ local hash
18
+ hash=$(printf '%s' "$key" | shasum -a 256 | awk '{print $1}')
19
+ echo "$CACHE_DIR/${hash}"
20
+ }
21
+
22
+ cmd_get() {
23
+ local key="$1" base etag_file body_file meta_file
24
+ base="$(_key_path "$key")"
25
+ body_file="${base}.body"
26
+ etag_file="${base}.etag"
27
+ meta_file="${base}.meta"
28
+
29
+ [[ -f "$body_file" && -f "$meta_file" ]] || exit 1
30
+
31
+ local cached_at now
32
+ cached_at=$(grep '^cached_at=' "$meta_file" | cut -d= -f2)
33
+ now=$(date +%s)
34
+ if [[ -n "$cached_at" && $((now - cached_at)) -gt "$TTL_SEC" ]]; then
35
+ exit 1
36
+ fi
37
+
38
+ cat "$body_file"
39
+ [[ -f "$etag_file" ]] && printf 'ETAG:%s\n' "$(cat "$etag_file")" >&2
40
+ exit 0
41
+ }
42
+
43
+ cmd_put() {
44
+ local key="$1" etag="$2" body_file="$3" base
45
+ base="$(_key_path "$key")"
46
+ cp "$body_file" "${base}.body"
47
+ printf '%s' "$etag" > "${base}.etag"
48
+ printf 'cached_at=%s\nkey=%s\n' "$(date +%s)" "$key" > "${base}.meta"
49
+ }
50
+
51
+ cmd_stale() {
52
+ local key="$1" base meta_file
53
+ base="$(_key_path "$key")"
54
+ meta_file="${base}.meta"
55
+ [[ -f "$meta_file" ]] || exit 0
56
+ local cached_at now
57
+ cached_at=$(grep '^cached_at=' "$meta_file" | cut -d= -f2)
58
+ now=$(date +%s)
59
+ [[ $((now - cached_at)) -gt "$TTL_SEC" ]] && exit 0
60
+ exit 1
61
+ }
62
+
63
+ case "${1:-}" in
64
+ get) cmd_get "${2:?key}" ;;
65
+ put) cmd_put "${2:?key}" "${3:?etag}" "${4:?body}" ;;
66
+ stale) cmd_stale "${2:?key}" ;;
67
+ *)
68
+ echo "Usage: doc-fetch-cache.sh get|put|stale <key> [etag] [body-file]" >&2
69
+ exit 2
70
+ ;;
71
+ esac
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bash
2
- # story: e42s04 e45s02
2
+ # story: e42s04 e45s02 e45s14
3
3
  # Deterministic gate runner for golden suite — sourced by golden-suite-run.sh
4
4
 
5
5
  if [ -n "${GOLDEN_GATES_LOADED:-}" ]; then return 0; fi
@@ -14,6 +14,8 @@ GOLDEN_GATES=(
14
14
  "g09-yaml-roundtrip:bash scripts/golden-g09-yaml-roundtrip.sh:false"
15
15
  "g10-trace-anti-vacuity:bash scripts/golden-g10-trace-anti-vacuity.sh:false"
16
16
  "g11-gitignore-venv:bash scripts/golden-g11-gitignore-venv.sh:false"
17
+ "import-boundaries:bash scripts/check-import-boundaries.sh:false"
18
+ "skill-catalog:bash scripts/validate-skill-catalog.sh:false"
17
19
  "specs-parse:bash scripts/validate-specs-yaml.sh:false"
18
20
  )
19
21
 
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env bash
2
+ # story: e45s18
3
+ # parallel-review-worktrees.sh — isolated git worktrees for parallel audit-code / security-review
4
+ # Usage: bash scripts/lib/parallel-review-worktrees.sh <audit-code|security-review>
5
+ set -euo pipefail
6
+
7
+ CHECK="${1:?usage: parallel-review-worktrees.sh <audit-code|security-review>}"
8
+ REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
9
+ cd "$REPO_ROOT"
10
+
11
+ BASE=".bigpowers/worktrees/review-${CHECK}"
12
+ mkdir -p "$(dirname "$BASE")"
13
+
14
+ if git worktree list | grep -q "$BASE"; then
15
+ git worktree remove --force "$BASE" 2>/dev/null || true
16
+ fi
17
+
18
+ git worktree add --detach "$BASE" HEAD >/dev/null
19
+ echo "WORKTREE: $BASE (detached @ $(git -C "$BASE" rev-parse --short HEAD))"
20
+
21
+ case "$CHECK" in
22
+ audit-code)
23
+ echo "Run audit-code checklist inside worktree; reports → specs/verifications/"
24
+ ;;
25
+ security-review)
26
+ echo "Run security-review 5-phase scan inside worktree; reports → specs/security/"
27
+ ;;
28
+ *)
29
+ echo "Unknown check: $CHECK" >&2
30
+ exit 2
31
+ ;;
32
+ esac
33
+
34
+ echo "OK: isolated worktree ready — parallel checks cannot corrupt parent working tree"
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env bash
2
+ # story: e45s04
3
+ # Pre-build cross-artifact consistency — slice-tasks output vs epic capsule.
4
+ # Severity: CRITICAL | HIGH | MED | LOW (LOW is informational only).
5
+ set -euo pipefail
6
+
7
+ CAPSULE="${1:-}"
8
+ if [[ -z "$CAPSULE" || ! -d "$CAPSULE" ]]; then
9
+ echo "Usage: bash scripts/lib/plan-consistency-check.sh specs/epics/eNN-slug" >&2
10
+ exit 2
11
+ fi
12
+
13
+ EPIC_YAML="$CAPSULE/epic.yaml"
14
+ CRITICAL=0
15
+ HIGH=0
16
+ MED=0
17
+
18
+ report() {
19
+ local sev="$1" msg="$2"
20
+ echo "[$sev] $msg"
21
+ case "$sev" in
22
+ CRITICAL) CRITICAL=$((CRITICAL + 1)) ;;
23
+ HIGH) HIGH=$((HIGH + 1)) ;;
24
+ MED) MED=$((MED + 1)) ;;
25
+ esac
26
+ }
27
+
28
+ [[ -f "$EPIC_YAML" ]] || report CRITICAL "Missing epic.yaml in $CAPSULE"
29
+
30
+ # Story IDs declared in epic.yaml
31
+ declare -A EPIC_STORIES=()
32
+ if [[ -f "$EPIC_YAML" ]]; then
33
+ while IFS= read -r sid; do
34
+ [[ -n "$sid" ]] && EPIC_STORIES["$sid"]=1
35
+ done < <(grep -E '^[[:space:]]*- id: e[0-9]+s[0-9]+' "$EPIC_YAML" | awk '{print $3}')
36
+ fi
37
+
38
+ shopt -s nullglob
39
+ SPECS=("$CAPSULE"/e*s*.md)
40
+ TASKS=("$CAPSULE"/e*s*-tasks.yaml)
41
+ shopt -u nullglob
42
+
43
+ (( ${#SPECS[@]} > 0 )) || report CRITICAL "No story spec .md files in capsule (run slice-tasks first)"
44
+ (( ${#TASKS[@]} > 0 )) || report CRITICAL "No *-tasks.yaml files in capsule (run plan-work first)"
45
+
46
+ declare -A SPEC_IDS=()
47
+ for spec in "${SPECS[@]}"; do
48
+ base="$(basename "$spec" .md)"
49
+ sid="$(echo "$base" | grep -oE 'e[0-9]+s[0-9]+' | head -1)"
50
+ [[ -n "$sid" ]] || continue
51
+ SPEC_IDS["$sid"]=1
52
+ [[ -n "${EPIC_STORIES[$sid]+x}" ]] || report HIGH "Story $sid in spec file but missing from epic.yaml manifest"
53
+ grep -qE '^## (17\.|Acceptance|Verification Script)' "$spec" \
54
+ || report HIGH "Story $sid spec missing §17 acceptance criteria or Verification Script"
55
+ grep -qiE 'ambiguous|TBD|TODO|FIXME' "$spec" \
56
+ && report MED "Story $sid spec contains ambiguous/TBD markers"
57
+ done
58
+
59
+ for tasks in "${TASKS[@]}"; do
60
+ base="$(basename "$tasks" -tasks.yaml)"
61
+ sid="$(echo "$base" | grep -oE 'e[0-9]+s[0-9]+' | head -1)"
62
+ [[ -n "$sid" ]] || continue
63
+ [[ -n "${SPEC_IDS[$sid]+x}" ]] || report CRITICAL "tasks.yaml for $sid without matching story spec .md"
64
+ grep -qE '^[[:space:]]*verify:' "$tasks" \
65
+ || report CRITICAL "Story $sid tasks.yaml missing runnable verify: commands"
66
+ grep -qE '^status:[[:space:]]*(failing|todo|passing)' "$tasks" \
67
+ || report MED "Story $sid tasks.yaml should use status: failing|passing ledger (e45s06)"
68
+ done
69
+
70
+ for sid in "${!EPIC_STORIES[@]}"; do
71
+ [[ -n "${SPEC_IDS[$sid]+x}" ]] || report HIGH "epic.yaml lists $sid but no story spec .md exists"
72
+ done
73
+
74
+ echo "---"
75
+ echo "plan-consistency-check: CRITICAL=$CRITICAL HIGH=$HIGH MED=$MED"
76
+
77
+ if (( CRITICAL > 0 || HIGH > 0 )); then
78
+ echo "BLOCKED: resolve CRITICAL/HIGH before code generation" >&2
79
+ exit 1
80
+ fi
81
+
82
+ if (( MED > 0 )); then
83
+ echo "WARN: MED findings present — confirm with user before build"
84
+ exit 0
85
+ fi
86
+
87
+ echo "PASS: capsule artifacts consistent"
88
+ exit 0