@sandrinio/vbounce 1.4.0 → 1.6.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/README.md +28 -2
- package/bin/vbounce.mjs +30 -0
- package/brains/AGENTS.md +26 -18
- package/brains/CHANGELOG.md +35 -0
- package/brains/CLAUDE.md +29 -19
- package/brains/GEMINI.md +28 -18
- package/brains/SETUP.md +7 -10
- package/brains/claude-agents/architect.md +37 -6
- package/brains/claude-agents/developer.md +20 -7
- package/brains/claude-agents/devops.md +31 -12
- package/brains/claude-agents/qa.md +31 -8
- package/brains/claude-agents/scribe.md +16 -7
- package/brains/cursor-rules/vbounce-docs.mdc +12 -8
- package/brains/cursor-rules/vbounce-process.mdc +11 -8
- package/brains/cursor-rules/vbounce-rules.mdc +9 -6
- package/package.json +1 -1
- package/scripts/init_gate_config.sh +151 -0
- package/scripts/pre_gate_common.sh +576 -0
- package/scripts/pre_gate_runner.sh +176 -0
- package/scripts/validate_report.mjs +5 -5
- package/scripts/vbounce_index.mjs +2 -2
- package/scripts/verify_framework.mjs +11 -0
- package/skills/agent-team/SKILL.md +112 -68
- package/skills/doc-manager/SKILL.md +58 -44
- package/skills/improve/SKILL.md +205 -0
- package/templates/charter.md +1 -1
- package/templates/delivery_plan.md +28 -181
- package/templates/epic.md +6 -4
- package/templates/risk_registry.md +2 -2
- package/templates/roadmap.md +1 -1
- package/templates/sprint.md +48 -0
- package/templates/sprint_report.md +57 -18
- package/templates/story.md +6 -3
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# pre_gate_runner.sh — Runs pre-gate checks before QA or Architect agents
|
|
3
|
+
# Usage: ./scripts/pre_gate_runner.sh <qa|arch> [worktree-path] [base-branch]
|
|
4
|
+
#
|
|
5
|
+
# Reads .bounce/gate-checks.json for check configuration.
|
|
6
|
+
# If no config exists, runs universal defaults with auto-detected stack.
|
|
7
|
+
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
|
+
source "${SCRIPT_DIR}/pre_gate_common.sh"
|
|
12
|
+
|
|
13
|
+
# ── Arguments ────────────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
GATE_TYPE="${1:-}"
|
|
16
|
+
WORKTREE_PATH="${2:-.}"
|
|
17
|
+
BASE_BRANCH="${3:-}"
|
|
18
|
+
PLAIN_RESULTS=""
|
|
19
|
+
|
|
20
|
+
if [[ -z "$GATE_TYPE" ]] || [[ "$GATE_TYPE" != "qa" && "$GATE_TYPE" != "arch" ]]; then
|
|
21
|
+
echo "Usage: ./scripts/pre_gate_runner.sh <qa|arch> [worktree-path] [base-branch]"
|
|
22
|
+
echo ""
|
|
23
|
+
echo " qa — Run QA pre-gate checks (before QA agent)"
|
|
24
|
+
echo " arch — Run Architect pre-gate checks (before Architect agent)"
|
|
25
|
+
echo ""
|
|
26
|
+
echo " worktree-path — Path to story worktree (default: current dir)"
|
|
27
|
+
echo " base-branch — Branch to diff against (default: auto-detect)"
|
|
28
|
+
exit 1
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# Resolve to absolute path
|
|
32
|
+
WORKTREE_PATH="$(cd "$WORKTREE_PATH" && pwd)"
|
|
33
|
+
|
|
34
|
+
echo -e "${CYAN}V-Bounce OS Pre-Gate Scanner${NC}"
|
|
35
|
+
echo -e "Gate: ${YELLOW}${GATE_TYPE}${NC}"
|
|
36
|
+
echo -e "Target: ${WORKTREE_PATH}"
|
|
37
|
+
echo ""
|
|
38
|
+
|
|
39
|
+
# ── Auto-detect base branch if not provided ──────────────────────────
|
|
40
|
+
|
|
41
|
+
if [[ -z "$BASE_BRANCH" ]]; then
|
|
42
|
+
cd "$WORKTREE_PATH"
|
|
43
|
+
# Try to find the sprint branch this story branched from
|
|
44
|
+
BASE_BRANCH=$(git log --oneline --merges -1 --format=%H 2>/dev/null || echo "")
|
|
45
|
+
if [[ -z "$BASE_BRANCH" ]]; then
|
|
46
|
+
# Fall back to parent branch detection
|
|
47
|
+
BASE_BRANCH=$(git rev-parse --abbrev-ref HEAD@{upstream} 2>/dev/null || echo "")
|
|
48
|
+
fi
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# ── Load config or use defaults ──────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
CONFIG_PATH="${WORKTREE_PATH}/.bounce/gate-checks.json"
|
|
54
|
+
HAS_CONFIG=false
|
|
55
|
+
|
|
56
|
+
if [[ -f "$CONFIG_PATH" ]]; then
|
|
57
|
+
HAS_CONFIG=true
|
|
58
|
+
echo -e "Config: ${GREEN}${CONFIG_PATH}${NC}"
|
|
59
|
+
else
|
|
60
|
+
# Check parent repo too (worktree might not have it)
|
|
61
|
+
REPO_ROOT=$(cd "$WORKTREE_PATH" && git rev-parse --show-toplevel 2>/dev/null || echo "$WORKTREE_PATH")
|
|
62
|
+
CONFIG_PATH="${REPO_ROOT}/.bounce/gate-checks.json"
|
|
63
|
+
if [[ -f "$CONFIG_PATH" ]]; then
|
|
64
|
+
HAS_CONFIG=true
|
|
65
|
+
echo -e "Config: ${GREEN}${CONFIG_PATH}${NC}"
|
|
66
|
+
else
|
|
67
|
+
echo -e "Config: ${YELLOW}None found — using universal defaults${NC}"
|
|
68
|
+
fi
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
echo ""
|
|
72
|
+
|
|
73
|
+
# ── Get modified files ───────────────────────────────────────────────
|
|
74
|
+
|
|
75
|
+
MODIFIED_FILES=$(get_modified_files "$WORKTREE_PATH" "$BASE_BRANCH")
|
|
76
|
+
|
|
77
|
+
# ── Run checks ───────────────────────────────────────────────────────
|
|
78
|
+
|
|
79
|
+
run_checks_from_config() {
|
|
80
|
+
local gate="$1"
|
|
81
|
+
local checks_key="${gate}_checks"
|
|
82
|
+
|
|
83
|
+
# Parse config with node (available since V-Bounce requires it)
|
|
84
|
+
local check_ids
|
|
85
|
+
check_ids=$(node -e "
|
|
86
|
+
const fs = require('fs');
|
|
87
|
+
const cfg = JSON.parse(fs.readFileSync('${CONFIG_PATH}', 'utf8'));
|
|
88
|
+
const checks = cfg['${checks_key}'] || [];
|
|
89
|
+
checks.filter(c => c.enabled !== false).forEach(c => {
|
|
90
|
+
console.log(JSON.stringify(c));
|
|
91
|
+
});
|
|
92
|
+
" 2>/dev/null)
|
|
93
|
+
|
|
94
|
+
while IFS= read -r check_json; do
|
|
95
|
+
[[ -z "$check_json" ]] && continue
|
|
96
|
+
|
|
97
|
+
local id cmd pattern glob should_find max_lines description
|
|
98
|
+
id=$(echo "$check_json" | node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));console.log(d.id||'')" 2>/dev/null)
|
|
99
|
+
cmd=$(echo "$check_json" | node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));console.log(d.cmd||'')" 2>/dev/null)
|
|
100
|
+
pattern=$(echo "$check_json" | node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));console.log(d.pattern||'')" 2>/dev/null)
|
|
101
|
+
glob=$(echo "$check_json" | node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));console.log(d.glob||'')" 2>/dev/null)
|
|
102
|
+
should_find=$(echo "$check_json" | node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));console.log(d.should_find||'false')" 2>/dev/null)
|
|
103
|
+
max_lines=$(echo "$check_json" | node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));console.log(d.max_lines||'500')" 2>/dev/null)
|
|
104
|
+
description=$(echo "$check_json" | node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));console.log(d.description||d.id||'')" 2>/dev/null)
|
|
105
|
+
|
|
106
|
+
case "$id" in
|
|
107
|
+
tests_exist) check_tests_exist "$WORKTREE_PATH" "$MODIFIED_FILES" ;;
|
|
108
|
+
tests_pass) check_tests_pass "$WORKTREE_PATH" ;;
|
|
109
|
+
build) check_build "$WORKTREE_PATH" ;;
|
|
110
|
+
lint) check_lint "$WORKTREE_PATH" ;;
|
|
111
|
+
no_debug_output) check_no_debug_output "$WORKTREE_PATH" "$MODIFIED_FILES" ;;
|
|
112
|
+
no_todo_fixme) check_no_todo_fixme "$WORKTREE_PATH" "$MODIFIED_FILES" ;;
|
|
113
|
+
exports_have_docs) check_exports_have_docs "$WORKTREE_PATH" "$MODIFIED_FILES" ;;
|
|
114
|
+
no_new_deps) check_no_new_dependencies "$WORKTREE_PATH" "$BASE_BRANCH" ;;
|
|
115
|
+
file_size) check_file_size_limit "$WORKTREE_PATH" "$MODIFIED_FILES" "$max_lines" ;;
|
|
116
|
+
custom_cmd) run_custom_check "$WORKTREE_PATH" "$description" "$cmd" "$description" ;;
|
|
117
|
+
custom_grep) run_custom_grep_check "$WORKTREE_PATH" "$description" "$pattern" "$glob" "$should_find" ;;
|
|
118
|
+
*)
|
|
119
|
+
# Unknown built-in — try as custom command if cmd is provided
|
|
120
|
+
if [[ -n "$cmd" ]]; then
|
|
121
|
+
run_custom_check "$WORKTREE_PATH" "$id" "$cmd" "$description"
|
|
122
|
+
else
|
|
123
|
+
record_result "$id" "SKIP" "Unknown check type"
|
|
124
|
+
record_result_plain "$id" "SKIP" "Unknown check type"
|
|
125
|
+
fi
|
|
126
|
+
;;
|
|
127
|
+
esac
|
|
128
|
+
done <<< "$check_ids"
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
run_universal_defaults() {
|
|
132
|
+
local gate="$1"
|
|
133
|
+
|
|
134
|
+
# QA-level checks (always run)
|
|
135
|
+
check_tests_exist "$WORKTREE_PATH" "$MODIFIED_FILES"
|
|
136
|
+
check_tests_pass "$WORKTREE_PATH"
|
|
137
|
+
check_build "$WORKTREE_PATH"
|
|
138
|
+
check_lint "$WORKTREE_PATH"
|
|
139
|
+
check_no_debug_output "$WORKTREE_PATH" "$MODIFIED_FILES"
|
|
140
|
+
check_no_todo_fixme "$WORKTREE_PATH" "$MODIFIED_FILES"
|
|
141
|
+
check_exports_have_docs "$WORKTREE_PATH" "$MODIFIED_FILES"
|
|
142
|
+
|
|
143
|
+
# Architect-level checks (only for arch gate)
|
|
144
|
+
if [[ "$gate" == "arch" ]]; then
|
|
145
|
+
check_no_new_dependencies "$WORKTREE_PATH" "$BASE_BRANCH"
|
|
146
|
+
check_file_size_limit "$WORKTREE_PATH" "$MODIFIED_FILES" 500
|
|
147
|
+
fi
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
# ── Execute ──────────────────────────────────────────────────────────
|
|
151
|
+
|
|
152
|
+
if [[ "$HAS_CONFIG" == "true" ]]; then
|
|
153
|
+
run_checks_from_config "$GATE_TYPE"
|
|
154
|
+
else
|
|
155
|
+
run_universal_defaults "$GATE_TYPE"
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
# ── Output ───────────────────────────────────────────────────────────
|
|
159
|
+
|
|
160
|
+
print_summary
|
|
161
|
+
|
|
162
|
+
# Write report
|
|
163
|
+
REPORT_DIR="${WORKTREE_PATH}/.bounce/reports"
|
|
164
|
+
REPORT_FILE="${REPORT_DIR}/pre-${GATE_TYPE}-scan.txt"
|
|
165
|
+
write_report "$REPORT_FILE"
|
|
166
|
+
echo ""
|
|
167
|
+
echo -e "Report: ${CYAN}${REPORT_FILE}${NC}"
|
|
168
|
+
|
|
169
|
+
# Exit code
|
|
170
|
+
if [[ $FAIL_COUNT -gt 0 ]]; then
|
|
171
|
+
echo -e "\n${RED}Gate check failed with ${FAIL_COUNT} failure(s).${NC}"
|
|
172
|
+
exit 1
|
|
173
|
+
else
|
|
174
|
+
echo -e "\n${GREEN}All checks passed.${NC}"
|
|
175
|
+
exit 0
|
|
176
|
+
fi
|
|
@@ -14,20 +14,20 @@ import yaml from 'js-yaml';
|
|
|
14
14
|
|
|
15
15
|
// Defined schemas for each report type
|
|
16
16
|
const SCHEMAS = {
|
|
17
|
-
dev: ['status', 'correction_tax', 'tests_written', 'files_modified', 'lessons_flagged'],
|
|
17
|
+
dev: ['status', 'correction_tax', 'tokens_used', 'tests_written', 'files_modified', 'lessons_flagged'],
|
|
18
18
|
qa: {
|
|
19
|
-
base: ['status', 'bounce_count', 'bugs_found', 'gold_plating_detected'],
|
|
19
|
+
base: ['status', 'bounce_count', 'tokens_used', 'bugs_found', 'gold_plating_detected'],
|
|
20
20
|
conditional: { 'FAIL': ['failed_scenarios'] }
|
|
21
21
|
},
|
|
22
22
|
arch: {
|
|
23
|
-
base: ['status'],
|
|
23
|
+
base: ['status', 'tokens_used'],
|
|
24
24
|
conditional: { 'PASS': ['safe_zone_score', 'ai_isms_detected', 'regression_risk'], 'FAIL': ['bounce_count', 'critical_failures'] }
|
|
25
25
|
},
|
|
26
26
|
devops: {
|
|
27
|
-
base: ['type', 'status'],
|
|
27
|
+
base: ['type', 'status', 'tokens_used'],
|
|
28
28
|
conditional: { 'story-merge': ['conflicts_detected'], 'sprint-release': ['version'] }
|
|
29
29
|
},
|
|
30
|
-
scribe: ['mode', 'docs_created', 'docs_updated', 'docs_removed']
|
|
30
|
+
scribe: ['mode', 'tokens_used', 'docs_created', 'docs_updated', 'docs_removed']
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
function extractFrontmatter(content) {
|
|
@@ -82,7 +82,7 @@ async function indexFile(filePath, embedder) {
|
|
|
82
82
|
else if (filePath.includes('ROADMAP.md')) type = 'adr';
|
|
83
83
|
else if (filePath.includes('.bounce/reports')) type = 'report';
|
|
84
84
|
else if (filePath.includes('product_plans')) type = 'plan';
|
|
85
|
-
else if (filePath.includes('
|
|
85
|
+
else if (filePath.includes('vdocs')) type = 'documentation';
|
|
86
86
|
|
|
87
87
|
const metadata = { file: basename, type };
|
|
88
88
|
const chunks = chunkMarkdown(content, metadata);
|
|
@@ -147,7 +147,7 @@ async function main() {
|
|
|
147
147
|
if (fs.existsSync('LESSONS.md')) filesToIndex.push('LESSONS.md');
|
|
148
148
|
if (fs.existsSync('ROADMAP.md')) filesToIndex.push('ROADMAP.md');
|
|
149
149
|
walkDir('product_plans');
|
|
150
|
-
walkDir('
|
|
150
|
+
walkDir('vdocs');
|
|
151
151
|
walkDir('.bounce/reports');
|
|
152
152
|
} else if (targetPath) {
|
|
153
153
|
const stat = fs.statSync(targetPath);
|
|
@@ -20,30 +20,41 @@ const EXPECTED_PROMPT_SIGNATURES = {
|
|
|
20
20
|
'developer.md': [
|
|
21
21
|
'status:',
|
|
22
22
|
'correction_tax:',
|
|
23
|
+
'tokens_used:',
|
|
24
|
+
'tests_written:',
|
|
23
25
|
'files_modified:',
|
|
24
26
|
'lessons_flagged:'
|
|
25
27
|
],
|
|
26
28
|
'qa.md': [
|
|
27
29
|
'status: "PASS"',
|
|
30
|
+
'bounce_count:',
|
|
28
31
|
'bugs_found: 0',
|
|
32
|
+
'gold_plating_detected:',
|
|
29
33
|
'status: "FAIL"',
|
|
34
|
+
'tokens_used:',
|
|
30
35
|
'failed_scenarios:'
|
|
31
36
|
],
|
|
32
37
|
'architect.md': [
|
|
33
38
|
'status: "PASS"',
|
|
34
39
|
'safe_zone_score:',
|
|
40
|
+
'ai_isms_detected:',
|
|
35
41
|
'regression_risk:',
|
|
36
42
|
'status: "FAIL"',
|
|
43
|
+
'bounce_count:',
|
|
44
|
+
'tokens_used:',
|
|
37
45
|
'critical_failures:'
|
|
38
46
|
],
|
|
39
47
|
'devops.md': [
|
|
40
48
|
'type: "story-merge"',
|
|
49
|
+
'status:',
|
|
41
50
|
'conflicts_detected:',
|
|
42
51
|
'type: "sprint-release"',
|
|
52
|
+
'tokens_used:',
|
|
43
53
|
'version:'
|
|
44
54
|
],
|
|
45
55
|
'scribe.md': [
|
|
46
56
|
'mode:',
|
|
57
|
+
'tokens_used:',
|
|
47
58
|
'docs_created:',
|
|
48
59
|
'docs_updated:',
|
|
49
60
|
'docs_removed:'
|