bigpowers 2.73.8 → 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.
- package/.continue/rules/context7-mcp.md +0 -0
- package/.continue/rules/diagnose-stall.md +0 -0
- package/.kilocode/rules/context7-mcp.md +0 -0
- package/.kilocode/rules/diagnose-stall.md +0 -0
- package/.pi/package.json +2 -2
- package/.pi/prompts/audit-code.md +17 -13
- package/.pi/prompts/change-request.md +3 -1
- package/.pi/prompts/compose-workflow.md +15 -0
- package/.pi/prompts/context7-mcp.md +54 -0
- package/.pi/prompts/craft-skill.md +28 -0
- package/.pi/prompts/deepen-architecture.md +20 -0
- package/.pi/prompts/delegate-task.md +14 -0
- package/.pi/prompts/deploy.md +8 -0
- package/.pi/prompts/develop-tdd.md +15 -4
- package/.pi/prompts/diagnose-stall.md +53 -0
- package/.pi/prompts/dispatch-agents.md +49 -19
- package/.pi/prompts/gate-trace.md +9 -1
- package/.pi/prompts/guard-git.md +14 -0
- package/.pi/prompts/migrate-spec.md +12 -0
- package/.pi/prompts/plan-work.md +62 -2
- package/.pi/prompts/publish-package.md +11 -0
- package/.pi/prompts/release-branch.md +39 -43
- package/.pi/prompts/request-review.md +57 -17
- package/.pi/prompts/run-benchmark.md +3 -3
- package/.pi/prompts/run-evals.md +26 -6
- package/.pi/prompts/security-review.md +56 -8
- package/.pi/prompts/seed-conventions.md +61 -0
- package/.pi/prompts/session-state.md +5 -10
- package/.pi/prompts/slice-tasks.md +3 -0
- package/.pi/prompts/smoke-test.md +11 -0
- package/.pi/prompts/stocktake-skills.md +2 -1
- package/.pi/prompts/validate-contracts.md +12 -0
- package/.pi/prompts/validate-fix.md +2 -0
- package/.pi/prompts/verify-work.md +31 -20
- package/.pi/prompts/wire-ci.md +11 -0
- package/.pi/prompts/write-document.md +10 -0
- package/.pi/skills/audit-code/SKILL.md +17 -13
- package/.pi/skills/change-request/SKILL.md +3 -1
- package/.pi/skills/compose-workflow/SKILL.md +15 -0
- package/.pi/skills/context7-mcp/SKILL.md +56 -0
- package/.pi/skills/craft-skill/SKILL.md +28 -0
- package/.pi/skills/deepen-architecture/SKILL.md +20 -0
- package/.pi/skills/delegate-task/SKILL.md +14 -0
- package/.pi/skills/deploy/SKILL.md +8 -0
- package/.pi/skills/develop-tdd/SKILL.md +15 -4
- package/.pi/skills/diagnose-stall/SKILL.md +55 -0
- package/.pi/skills/dispatch-agents/SKILL.md +49 -19
- package/.pi/skills/gate-trace/SKILL.md +9 -1
- package/.pi/skills/guard-git/SKILL.md +14 -0
- package/.pi/skills/migrate-spec/SKILL.md +12 -0
- package/.pi/skills/plan-work/SKILL.md +62 -2
- package/.pi/skills/publish-package/SKILL.md +11 -0
- package/.pi/skills/release-branch/SKILL.md +39 -43
- package/.pi/skills/request-review/SKILL.md +57 -17
- package/.pi/skills/run-benchmark/SKILL.md +3 -3
- package/.pi/skills/run-evals/SKILL.md +26 -6
- package/.pi/skills/security-review/SKILL.md +56 -8
- package/.pi/skills/seed-conventions/SKILL.md +61 -0
- package/.pi/skills/session-state/SKILL.md +5 -10
- package/.pi/skills/slice-tasks/SKILL.md +3 -0
- package/.pi/skills/smoke-test/SKILL.md +11 -0
- package/.pi/skills/stocktake-skills/SKILL.md +2 -1
- package/.pi/skills/validate-contracts/SKILL.md +12 -0
- package/.pi/skills/validate-fix/SKILL.md +2 -0
- package/.pi/skills/verify-work/SKILL.md +31 -20
- package/.pi/skills/wire-ci/SKILL.md +11 -0
- package/.pi/skills/write-document/SKILL.md +10 -0
- package/CHANGELOG.md +14 -0
- package/CLAUDE.md +59 -1
- package/CONVENTIONS.md +80 -5
- package/README.md +1 -1
- package/SKILL-INDEX.md +1 -1
- package/package.json +1 -1
- package/scripts/bp-churn-rank.sh +49 -0
- package/scripts/check-import-boundaries.sh +64 -0
- package/scripts/compile-rule-matrix.sh +114 -0
- package/scripts/hooks/rtk-rewrite.sh +11 -0
- package/scripts/hooks/token-mgmt-pre-tool-use.sh +53 -0
- package/scripts/install.sh +6 -0
- package/scripts/lib/completeness-critic.sh +62 -0
- package/scripts/lib/doc-fetch-cache.sh +71 -0
- package/scripts/lib/golden-suite-gates.sh +3 -1
- package/scripts/lib/parallel-review-worktrees.sh +34 -0
- package/scripts/lib/plan-consistency-check.sh +88 -0
- package/scripts/lib/run-benchmark.py +210 -0
- package/scripts/lib/simple_yaml.py +130 -0
- package/scripts/lib/sync-context-engineering-ref.sh +19 -0
- package/scripts/lib/trace-matrix.py +10 -281
- package/scripts/lib/trace_renderer.py +147 -0
- package/scripts/references-manifest.yaml +19 -0
- package/scripts/run-benchmark.sh +6 -0
- package/scripts/sync-references.sh +25 -0
- package/scripts/test-trace-matrix-size.sh +46 -0
- package/scripts/validate-skill-catalog.sh +147 -0
- package/scripts/validate-skill-description.sh +70 -0
- package/skills/audit-code/SKILL.md +19 -13
- package/skills/change-request/SKILL.md +3 -1
- package/skills/compose-workflow/SKILL.md +15 -0
- package/skills/context7-mcp/SKILL.md +57 -0
- package/skills/craft-skill/SKILL.md +29 -0
- package/skills/deepen-architecture/SKILL.md +22 -0
- package/skills/delegate-task/SKILL.md +14 -0
- package/skills/deploy/SKILL.md +9 -0
- package/skills/develop-tdd/SKILL.md +18 -4
- package/skills/diagnose-stall/SKILL.md +56 -0
- package/skills/dispatch-agents/SKILL.md +51 -19
- package/skills/gate-trace/SKILL.md +11 -1
- package/skills/guard-git/REFERENCE.md +14 -0
- package/skills/migrate-spec/REFERENCE.md +12 -0
- package/skills/plan-work/REFERENCE.md +29 -2
- package/skills/plan-work/SKILL.md +38 -0
- package/skills/publish-package/REFERENCE.md +11 -0
- package/skills/release-branch/REFERENCE.md +14 -0
- package/skills/release-branch/SKILL.md +28 -43
- package/skills/request-review/SKILL.md +59 -17
- package/skills/run-benchmark/SKILL.md +4 -4
- package/skills/run-evals/REFERENCE.md +14 -4
- package/skills/run-evals/SKILL.md +13 -2
- package/skills/security-review/REFERENCE-false-positives.md +9 -8
- package/skills/security-review/REFERENCE-vuln-categories.md +4 -0
- package/skills/security-review/SKILL.md +45 -0
- package/skills/security-review/fixtures/CWE-79-xss-negative.js +6 -0
- package/skills/security-review/fixtures/CWE-79-xss-positive.js +6 -0
- package/skills/security-review/fixtures/CWE-89-sqli-negative.py +8 -0
- package/skills/security-review/fixtures/CWE-89-sqli-positive.py +9 -0
- package/skills/seed-conventions/REFERENCE.md +40 -0
- package/skills/seed-conventions/SKILL.md +22 -0
- package/skills/session-state/SKILL.md +5 -10
- package/skills/slice-tasks/SKILL.md +3 -0
- package/skills/smoke-test/REFERENCE.md +11 -0
- package/skills/stocktake-skills/SKILL.md +3 -1
- package/skills/validate-contracts/REFERENCE.md +12 -0
- package/skills/validate-fix/SKILL.md +3 -0
- package/skills/verify-work/REFERENCE.md +17 -0
- package/skills/verify-work/SKILL.md +18 -20
- package/skills/wire-ci/REFERENCE.md +11 -0
- package/skills/write-document/REFERENCE.md +10 -0
- package/skills-lock.json +32 -22
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|

|
|
5
|
-

|
|
6
6
|
|
|
7
7
|
**Agent skills synthesizing 17 years of software engineering discipline — from Clean Code to AI-native architecture — into a single, prescriptive methodology for solo developers.**
|
|
8
8
|
|
package/SKILL-INDEX.md
CHANGED
package/package.json
CHANGED
|
@@ -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
|
package/scripts/install.sh
CHANGED
|
@@ -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
|