vbounce-engine 2.5.1 → 2.5.3
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 +5 -5
- package/VBOUNCE_MANIFEST.md +23 -8
- package/brains/CLAUDE.md +6 -6
- package/package.json +1 -1
- package/scripts/close_sprint.mjs +9 -2
- package/scripts/complete_story.mjs +7 -1
- package/scripts/constants.mjs +16 -0
- package/scripts/doctor.mjs +1 -0
- package/scripts/pre_gate_common.sh +47 -0
- package/scripts/run_script.sh +195 -0
- package/scripts/update_state.mjs +1 -5
- package/scripts/validate_state.mjs +1 -5
- package/skills/agent-team/SKILL.md +65 -8
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
<p>
|
|
7
7
|
<a href="https://github.com/sandrinio/v-bounce-engine/blob/main/LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-yellow.svg"></a>
|
|
8
|
-
<a href="https://www.npmjs.com/package/vbounce"><img alt="NPM Version" src="https://img.shields.io/npm/v/vbounce"></a>
|
|
8
|
+
<a href="https://www.npmjs.com/package/vbounce-engine"><img alt="NPM Version" src="https://img.shields.io/npm/v/vbounce-engine"></a>
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p>
|
|
@@ -21,14 +21,14 @@ Get your new AI team up and running in seconds. No complex setup, no vector data
|
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
23
|
# 1. Install the framework for your platform of choice
|
|
24
|
-
npx vbounce install claude # Claude Code (Full Orchestration)
|
|
25
|
-
# Or: npx vbounce install cursor|gemini|codex|vscode
|
|
24
|
+
npx vbounce-engine install claude # Claude Code (Full Orchestration)
|
|
25
|
+
# Or: npx vbounce-engine install cursor|gemini|codex|vscode
|
|
26
26
|
|
|
27
27
|
# 2. Verify your installation
|
|
28
|
-
npx vbounce doctor
|
|
28
|
+
npx vbounce-engine doctor
|
|
29
29
|
|
|
30
30
|
# 3. Initialize your first sprint!
|
|
31
|
-
npx vbounce sprint init S-01 D-01
|
|
31
|
+
npx vbounce-engine sprint init S-01 D-01
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
> **Requirements**: Node.js and a project directory. That's it. One person to set the vision, the AI handles the execution.
|
package/VBOUNCE_MANIFEST.md
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
> Any modification to `.claude/agents/`, `.vbounce/skills/`, `.vbounce/templates/`, or `.vbounce/scripts/` MUST also update this file.
|
|
5
5
|
> Run `vbounce doctor` to validate file existence against this manifest.
|
|
6
6
|
|
|
7
|
-
**Version:** 2.5.
|
|
8
|
-
**Last updated:** 2026-03-
|
|
7
|
+
**Version:** 2.5.3
|
|
8
|
+
**Last updated:** 2026-03-26
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -185,6 +185,16 @@ Skills are modular instructions loaded by agents. Located in `.vbounce/skills/`.
|
|
|
185
185
|
|
|
186
186
|
Scripts automate framework operations. Located in `.vbounce/scripts/`.
|
|
187
187
|
|
|
188
|
+
### Script Execution Wrapper
|
|
189
|
+
| Script | When | Input | Output |
|
|
190
|
+
|--------|------|-------|--------|
|
|
191
|
+
| `.vbounce/scripts/run_script.sh` | **Every script invocation** | Script name + args | Passthrough stdout/stderr, pre-flight checks, structured diagnostics on failure |
|
|
192
|
+
|
|
193
|
+
### Shared Constants
|
|
194
|
+
| Script | When | Input | Output |
|
|
195
|
+
|--------|------|-------|--------|
|
|
196
|
+
| `.vbounce/scripts/constants.mjs` | Imported by lifecycle scripts | — | `VALID_STATES`, `TERMINAL_STATES` (single source of truth) |
|
|
197
|
+
|
|
188
198
|
### Sprint Lifecycle
|
|
189
199
|
| Script | When | Input | Output |
|
|
190
200
|
|--------|------|-------|--------|
|
|
@@ -364,16 +374,21 @@ Regression suite for validating the engine after any path, script, or template c
|
|
|
364
374
|
|
|
365
375
|
| File | Suite | What it checks |
|
|
366
376
|
|------|-------|----------------|
|
|
367
|
-
| `tests/harness.mjs` | — | Test primitives: `suite()`, `record()`, `assertFileExists()`, `assertNoMatch()`, `assertScriptRuns()`, `generateReport()` |
|
|
368
|
-
| `tests/
|
|
377
|
+
| `tests/harness.mjs` | — | Test primitives: `suite()`, `record()`, `assertFileExists()`, `assertNoMatch()`, `assertScriptRuns()`, `assertBashRuns()`, `generateReport()` |
|
|
378
|
+
| `tests/fixtures.mjs` | — | Shared fixture generator: `createSprintFixtures()`, `createSyntheticReport()`, `removeSprintFixtures()` |
|
|
379
|
+
| `tests/run.mjs` | — | Main runner: installs to temp dir, runs all 12 suites, generates JSON + Markdown reports |
|
|
369
380
|
| `tests/suites/install.mjs` | Install Integrity | 76+ file existence checks across all installed components |
|
|
370
381
|
| `tests/suites/paths.mjs` | Path Integrity | 500+ stale path pattern scans across all shipped `.md`/`.mjs` files |
|
|
371
382
|
| `tests/suites/doctor.mjs` | Doctor Accuracy | False positive and false negative detection |
|
|
372
|
-
| `tests/suites/scripts.mjs` | Script Validation | Import checks, functional tests, ROOT resolution for all
|
|
383
|
+
| `tests/suites/scripts.mjs` | Script Validation | Import checks, functional tests, ROOT resolution for all `.mjs` scripts |
|
|
373
384
|
| `tests/suites/brains.mjs` | Agent Contracts | Frontmatter, report YAML signatures, CLAUDE.md ↔ agents consistency |
|
|
374
385
|
| `tests/suites/manifest.mjs` | Manifest Completeness | All backtick paths resolve, orphan file detection |
|
|
375
386
|
| `tests/suites/templates.mjs` | Template/Skill Integrity | Structure validation, stale paths, CLAUDE.md ↔ skills cross-reference |
|
|
376
387
|
| `tests/suites/lifecycle.mjs` | Full Lifecycle | 41-test simulation: fixtures → init → transitions → context prep → complete → close → analytics → edge cases |
|
|
388
|
+
| `tests/suites/agent-errors.mjs` | Agent Error Paths | Scripts called in wrong order, wrong state, wrong/missing args — verifies actionable errors, not raw crashes |
|
|
389
|
+
| `tests/suites/run-script-wrapper.mjs` | Script Wrapper | `run_script.sh` pre-flight checks, diagnostic block output, success/failure passthrough, bash script support |
|
|
390
|
+
| `tests/suites/parallel-stories.mjs` | Parallel Stories | Concurrent state management: 3 stories transition independently, bounce counts isolated, re-init behavior |
|
|
391
|
+
| `tests/suites/report-parsing.mjs` | Report Parsing | Malformed agent reports (no frontmatter, empty, truncated YAML, missing fields) handled gracefully |
|
|
377
392
|
|
|
378
393
|
Reports output to `tests/reports/report-{timestamp}.{json,md}`.
|
|
379
394
|
|
|
@@ -396,9 +411,9 @@ Reports output to `tests/reports/report-{timestamp}.{json,md}`.
|
|
|
396
411
|
| Templates | 13 |
|
|
397
412
|
| Skills (SKILL.md + references) | 26 |
|
|
398
413
|
| React rules | 57 |
|
|
399
|
-
| Scripts |
|
|
400
|
-
| Test suite |
|
|
414
|
+
| Scripts | 29 |
|
|
415
|
+
| Test suite | 16 |
|
|
401
416
|
| Diagrams | 6 |
|
|
402
417
|
| Docs + Visual Assets | 6 + ~15 icons/images |
|
|
403
418
|
| CLI | 1 |
|
|
404
|
-
| **Total** | **~
|
|
419
|
+
| **Total** | **~193** |
|
package/brains/CLAUDE.md
CHANGED
|
@@ -58,12 +58,12 @@ Determine which phase you're in from what the human is asking, then load the rig
|
|
|
58
58
|
> - **Planning (Phase 1 & 2):** Load `@.vbounce/skills/doc-manager/SKILL.md` + `@.vbounce/skills/product-graph/SKILL.md`
|
|
59
59
|
> - **Execution (Phase 3):** Load `@.vbounce/skills/agent-team/SKILL.md`
|
|
60
60
|
|
|
61
|
-
> **On-demand skills
|
|
62
|
-
> -
|
|
63
|
-
> -
|
|
64
|
-
> -
|
|
65
|
-
> -
|
|
66
|
-
> -
|
|
61
|
+
> **On-demand skills** (read the file directly when the user asks — these are NOT slash commands):
|
|
62
|
+
> - "doc" → read `@.vbounce/skills/doc-manager/SKILL.md`
|
|
63
|
+
> - "review" → read `@.vbounce/skills/vibe-code-review/SKILL.md` — code review
|
|
64
|
+
> - "write-skill" → read `@.vbounce/skills/write-skill/SKILL.md` — skill authoring
|
|
65
|
+
> - "improve" → read `@.vbounce/skills/improve/SKILL.md` — framework improvement
|
|
66
|
+
> - "react" → read `@.vbounce/skills/react-best-practices/SKILL.md` — frontend patterns
|
|
67
67
|
|
|
68
68
|
## Subagents
|
|
69
69
|
|
package/package.json
CHANGED
package/scripts/close_sprint.mjs
CHANGED
|
@@ -12,6 +12,7 @@ import fs from 'fs';
|
|
|
12
12
|
import path from 'path';
|
|
13
13
|
import { fileURLToPath } from 'url';
|
|
14
14
|
import { spawnSync } from 'child_process';
|
|
15
|
+
import { TERMINAL_STATES } from './constants.mjs';
|
|
15
16
|
|
|
16
17
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
17
18
|
const ROOT = path.resolve(__dirname, '../..');
|
|
@@ -37,7 +38,13 @@ if (!fs.existsSync(stateFile)) {
|
|
|
37
38
|
process.exit(1);
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
let state;
|
|
42
|
+
try {
|
|
43
|
+
state = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
|
|
44
|
+
} catch (e) {
|
|
45
|
+
console.error(`ERROR: state.json is not valid JSON — ${e.message}`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
41
48
|
|
|
42
49
|
if (state.sprint_id !== sprintId) {
|
|
43
50
|
console.error(`ERROR: state.json is for sprint ${state.sprint_id}, not ${sprintId}`);
|
|
@@ -46,7 +53,7 @@ if (state.sprint_id !== sprintId) {
|
|
|
46
53
|
|
|
47
54
|
// 2. Check all stories are terminal
|
|
48
55
|
const activeStories = Object.entries(state.stories || {}).filter(
|
|
49
|
-
([, s]) => !
|
|
56
|
+
([, s]) => !TERMINAL_STATES.includes(s.state)
|
|
50
57
|
);
|
|
51
58
|
|
|
52
59
|
if (activeStories.length > 0) {
|
|
@@ -42,7 +42,13 @@ if (!fs.existsSync(stateFile)) {
|
|
|
42
42
|
console.error('ERROR: .vbounce/state.json not found');
|
|
43
43
|
process.exit(1);
|
|
44
44
|
}
|
|
45
|
-
|
|
45
|
+
let state;
|
|
46
|
+
try {
|
|
47
|
+
state = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
|
|
48
|
+
} catch (e) {
|
|
49
|
+
console.error(`ERROR: state.json is not valid JSON — ${e.message}`);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
46
52
|
if (!state.stories[storyId]) {
|
|
47
53
|
console.error(`ERROR: Story "${storyId}" not found in state.json`);
|
|
48
54
|
process.exit(1);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* constants.mjs
|
|
5
|
+
* Shared constants for V-Bounce Engine scripts.
|
|
6
|
+
* Single source of truth for story states and terminal states.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** All valid story states in lifecycle order. */
|
|
10
|
+
export const VALID_STATES = [
|
|
11
|
+
'Draft', 'Refinement', 'Ready to Bounce', 'Bouncing',
|
|
12
|
+
'QA Passed', 'Architect Passed', 'Done', 'Escalated', 'Parking Lot'
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
/** Terminal states — stories that are no longer active. */
|
|
16
|
+
export const TERMINAL_STATES = ['Done', 'Escalated', 'Parking Lot'];
|
package/scripts/doctor.mjs
CHANGED
|
@@ -100,6 +100,7 @@ if (skillCount === requiredSkills.length) pass(`Skills: ${skillCount}/${required
|
|
|
100
100
|
|
|
101
101
|
// Check scripts
|
|
102
102
|
const requiredScripts = [
|
|
103
|
+
'run_script.sh',
|
|
103
104
|
'validate_report.mjs', 'update_state.mjs', 'validate_state.mjs',
|
|
104
105
|
'validate_sprint_plan.mjs', 'validate_bounce_readiness.mjs',
|
|
105
106
|
'init_sprint.mjs', 'close_sprint.mjs', 'complete_story.mjs',
|
|
@@ -536,6 +536,53 @@ check_file_size_limit() {
|
|
|
536
536
|
fi
|
|
537
537
|
}
|
|
538
538
|
|
|
539
|
+
# ── Pre-merge report verification ────────────────────────────────────
|
|
540
|
+
|
|
541
|
+
check_gate_reports_exist() {
|
|
542
|
+
local dir="$1" story_id="$2"
|
|
543
|
+
local reports_dir="${dir}/.vbounce/reports"
|
|
544
|
+
local missing=0
|
|
545
|
+
local details=""
|
|
546
|
+
|
|
547
|
+
if [[ ! -d "$reports_dir" ]]; then
|
|
548
|
+
record_result "gate_reports" "FAIL" ".vbounce/reports/ directory not found in worktree"
|
|
549
|
+
record_result_plain "gate_reports" "FAIL" ".vbounce/reports/ directory not found in worktree"
|
|
550
|
+
return
|
|
551
|
+
fi
|
|
552
|
+
|
|
553
|
+
# Check for QA report (any bounce)
|
|
554
|
+
local qa_report
|
|
555
|
+
qa_report=$(find "$reports_dir" -name "${story_id}-qa*" -o -name "${story_id}*-qa*" 2>/dev/null | head -1)
|
|
556
|
+
if [[ -z "$qa_report" ]]; then
|
|
557
|
+
missing=$((missing + 1))
|
|
558
|
+
details="${details}QA report missing. "
|
|
559
|
+
fi
|
|
560
|
+
|
|
561
|
+
# Check for Architect report (any bounce)
|
|
562
|
+
local arch_report
|
|
563
|
+
arch_report=$(find "$reports_dir" -name "${story_id}-arch*" -o -name "${story_id}*-arch*" 2>/dev/null | head -1)
|
|
564
|
+
if [[ -z "$arch_report" ]]; then
|
|
565
|
+
missing=$((missing + 1))
|
|
566
|
+
details="${details}Architect report missing. "
|
|
567
|
+
fi
|
|
568
|
+
|
|
569
|
+
# Check for Dev report
|
|
570
|
+
local dev_report
|
|
571
|
+
dev_report=$(find "$reports_dir" -name "${story_id}-dev*" -o -name "${story_id}*-dev*" 2>/dev/null | head -1)
|
|
572
|
+
if [[ -z "$dev_report" ]]; then
|
|
573
|
+
missing=$((missing + 1))
|
|
574
|
+
details="${details}Dev report missing. "
|
|
575
|
+
fi
|
|
576
|
+
|
|
577
|
+
if [[ $missing -eq 0 ]]; then
|
|
578
|
+
record_result "gate_reports" "PASS" "Dev, QA, and Architect reports present"
|
|
579
|
+
record_result_plain "gate_reports" "PASS" "Dev, QA, and Architect reports present"
|
|
580
|
+
else
|
|
581
|
+
record_result "gate_reports" "FAIL" "${details}"
|
|
582
|
+
record_result_plain "gate_reports" "FAIL" "${details}"
|
|
583
|
+
fi
|
|
584
|
+
}
|
|
585
|
+
|
|
539
586
|
# ── Custom check runner ──────────────────────────────────────────────
|
|
540
587
|
|
|
541
588
|
run_custom_check() {
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# run_script.sh — Safe wrapper for V-Bounce script execution
|
|
3
|
+
# Usage: ./.vbounce/scripts/run_script.sh <script> [args...]
|
|
4
|
+
#
|
|
5
|
+
# All agents MUST invoke .vbounce scripts through this wrapper.
|
|
6
|
+
# Captures exit code, stdout, stderr. On failure, prints a structured
|
|
7
|
+
# diagnostic block that agents can parse and act on.
|
|
8
|
+
|
|
9
|
+
set -uo pipefail
|
|
10
|
+
|
|
11
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
12
|
+
ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
|
13
|
+
|
|
14
|
+
RED='\033[0;31m'
|
|
15
|
+
GREEN='\033[0;32m'
|
|
16
|
+
YELLOW='\033[1;33m'
|
|
17
|
+
CYAN='\033[0;36m'
|
|
18
|
+
NC='\033[0m'
|
|
19
|
+
|
|
20
|
+
# ── Arguments ────────────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
SCRIPT_NAME="${1:-}"
|
|
23
|
+
|
|
24
|
+
if [[ -z "$SCRIPT_NAME" ]]; then
|
|
25
|
+
echo "Usage: ./.vbounce/scripts/run_script.sh <script> [args...]"
|
|
26
|
+
echo ""
|
|
27
|
+
echo "Examples:"
|
|
28
|
+
echo " ./.vbounce/scripts/run_script.sh validate_state.mjs"
|
|
29
|
+
echo " ./.vbounce/scripts/run_script.sh pre_gate_runner.sh qa .worktrees/STORY-001-01/"
|
|
30
|
+
echo " ./.vbounce/scripts/run_script.sh complete_story.mjs STORY-001-01"
|
|
31
|
+
exit 1
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
shift
|
|
35
|
+
SCRIPT_ARGS=("$@")
|
|
36
|
+
|
|
37
|
+
# ── Resolve script path ─────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
SCRIPT_PATH="${SCRIPT_DIR}/${SCRIPT_NAME}"
|
|
40
|
+
|
|
41
|
+
if [[ ! -f "$SCRIPT_PATH" ]]; then
|
|
42
|
+
echo ""
|
|
43
|
+
echo -e "${RED}┌─ SCRIPT FAILURE ─────────────────────────────────────────┐${NC}"
|
|
44
|
+
echo -e "${RED}│ Script: ${SCRIPT_NAME}${NC}"
|
|
45
|
+
echo -e "${RED}│ Exit Code: 127 (not found)${NC}"
|
|
46
|
+
echo -e "${RED}│ Error: ${SCRIPT_PATH} does not exist${NC}"
|
|
47
|
+
echo -e "${RED}│${NC}"
|
|
48
|
+
echo -e "${RED}│ Available scripts:${NC}"
|
|
49
|
+
for f in "${SCRIPT_DIR}"/*.{mjs,sh}; do
|
|
50
|
+
[[ -f "$f" ]] && [[ "$(basename "$f")" != "run_script.sh" ]] && echo -e "${RED}│ $(basename "$f")${NC}"
|
|
51
|
+
done
|
|
52
|
+
echo -e "${RED}│${NC}"
|
|
53
|
+
echo -e "${RED}│ Action: Check script name for typos${NC}"
|
|
54
|
+
echo -e "${RED}└──────────────────────────────────────────────────────────┘${NC}"
|
|
55
|
+
exit 127
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
# ── Pre-flight checks ───────────────────────────────────────────────
|
|
59
|
+
|
|
60
|
+
PREFLIGHT_WARNINGS=""
|
|
61
|
+
|
|
62
|
+
# Check state.json for scripts that need it
|
|
63
|
+
NEEDS_STATE=(
|
|
64
|
+
"update_state.mjs" "validate_state.mjs" "complete_story.mjs"
|
|
65
|
+
"close_sprint.mjs" "prep_sprint_context.mjs" "validate_bounce_readiness.mjs"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
for s in "${NEEDS_STATE[@]}"; do
|
|
69
|
+
if [[ "$SCRIPT_NAME" == "$s" ]]; then
|
|
70
|
+
if [[ ! -f "${ROOT}/.vbounce/state.json" ]]; then
|
|
71
|
+
PREFLIGHT_WARNINGS="${PREFLIGHT_WARNINGS}\n ⚠ state.json missing — ${SCRIPT_NAME} will fail"
|
|
72
|
+
elif ! node -e "JSON.parse(require('fs').readFileSync('${ROOT}/.vbounce/state.json','utf8'))" 2>/dev/null; then
|
|
73
|
+
PREFLIGHT_WARNINGS="${PREFLIGHT_WARNINGS}\n ⚠ state.json is invalid JSON — ${SCRIPT_NAME} will fail"
|
|
74
|
+
fi
|
|
75
|
+
break
|
|
76
|
+
fi
|
|
77
|
+
done
|
|
78
|
+
|
|
79
|
+
# Check .vbounce directory exists
|
|
80
|
+
if [[ ! -d "${ROOT}/.vbounce" ]]; then
|
|
81
|
+
PREFLIGHT_WARNINGS="${PREFLIGHT_WARNINGS}\n ⚠ .vbounce/ directory missing"
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
if [[ -n "$PREFLIGHT_WARNINGS" ]]; then
|
|
85
|
+
echo -e "${YELLOW}Pre-flight warnings:${PREFLIGHT_WARNINGS}${NC}"
|
|
86
|
+
echo ""
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# ── Execute ──────────────────────────────────────────────────────────
|
|
90
|
+
|
|
91
|
+
STDOUT_FILE=$(mktemp)
|
|
92
|
+
STDERR_FILE=$(mktemp)
|
|
93
|
+
trap 'rm -f "$STDOUT_FILE" "$STDERR_FILE"' EXIT
|
|
94
|
+
|
|
95
|
+
# Determine runner
|
|
96
|
+
RUNNER=""
|
|
97
|
+
case "$SCRIPT_NAME" in
|
|
98
|
+
*.mjs) RUNNER="node" ;;
|
|
99
|
+
*.sh) RUNNER="bash" ;;
|
|
100
|
+
*) RUNNER="" ;;
|
|
101
|
+
esac
|
|
102
|
+
|
|
103
|
+
if [[ -n "$RUNNER" ]]; then
|
|
104
|
+
$RUNNER "$SCRIPT_PATH" ${SCRIPT_ARGS[@]+"${SCRIPT_ARGS[@]}"} > "$STDOUT_FILE" 2> "$STDERR_FILE"
|
|
105
|
+
else
|
|
106
|
+
"$SCRIPT_PATH" ${SCRIPT_ARGS[@]+"${SCRIPT_ARGS[@]}"} > "$STDOUT_FILE" 2> "$STDERR_FILE"
|
|
107
|
+
fi
|
|
108
|
+
EXIT_CODE=$?
|
|
109
|
+
|
|
110
|
+
# ── Output ───────────────────────────────────────────────────────────
|
|
111
|
+
|
|
112
|
+
# Always show stdout
|
|
113
|
+
cat "$STDOUT_FILE"
|
|
114
|
+
|
|
115
|
+
if [[ $EXIT_CODE -eq 0 ]]; then
|
|
116
|
+
# Success — show stderr as warnings if any
|
|
117
|
+
if [[ -s "$STDERR_FILE" ]]; then
|
|
118
|
+
echo ""
|
|
119
|
+
echo -e "${YELLOW}Warnings (stderr):${NC}"
|
|
120
|
+
cat "$STDERR_FILE"
|
|
121
|
+
fi
|
|
122
|
+
exit 0
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
# ── Failure diagnostic ───────────────────────────────────────────────
|
|
126
|
+
|
|
127
|
+
STDERR_CONTENT=$(cat "$STDERR_FILE")
|
|
128
|
+
|
|
129
|
+
echo ""
|
|
130
|
+
echo -e "${RED}┌─ SCRIPT FAILURE ─────────────────────────────────────────┐${NC}"
|
|
131
|
+
echo -e "${RED}│ Script: ${SCRIPT_NAME} ${SCRIPT_ARGS[*]+"${SCRIPT_ARGS[*]}"}${NC}"
|
|
132
|
+
echo -e "${RED}│ Exit Code: ${EXIT_CODE}${NC}"
|
|
133
|
+
echo -e "${RED}│${NC}"
|
|
134
|
+
|
|
135
|
+
# Show stderr (truncated to 20 lines)
|
|
136
|
+
if [[ -n "$STDERR_CONTENT" ]]; then
|
|
137
|
+
echo -e "${RED}│ Stderr:${NC}"
|
|
138
|
+
echo "$STDERR_CONTENT" | head -20 | while IFS= read -r line; do
|
|
139
|
+
echo -e "${RED}│ ${line}${NC}"
|
|
140
|
+
done
|
|
141
|
+
STDERR_LINES=$(echo "$STDERR_CONTENT" | wc -l | tr -d ' ')
|
|
142
|
+
if [[ "$STDERR_LINES" -gt 20 ]]; then
|
|
143
|
+
echo -e "${RED}│ ... (${STDERR_LINES} total lines, truncated)${NC}"
|
|
144
|
+
fi
|
|
145
|
+
else
|
|
146
|
+
echo -e "${RED}│ Stderr: (empty)${NC}"
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
echo -e "${RED}│${NC}"
|
|
150
|
+
|
|
151
|
+
# ── Diagnosis ────────────────────────────────────────────────────────
|
|
152
|
+
|
|
153
|
+
echo -e "${RED}│ Diagnosis:${NC}"
|
|
154
|
+
|
|
155
|
+
# Check common root causes
|
|
156
|
+
if echo "$STDERR_CONTENT" | grep -qi "state.json not found\|state.json missing"; then
|
|
157
|
+
echo -e "${RED}│ Missing state.json — sprint was never initialized${NC}"
|
|
158
|
+
echo -e "${RED}│${NC}"
|
|
159
|
+
echo -e "${RED}│ Fix: Run ./.vbounce/scripts/init_sprint.mjs S-XX D-XX --stories STORY-IDS${NC}"
|
|
160
|
+
|
|
161
|
+
elif echo "$STDERR_CONTENT" | grep -qi "not valid JSON\|Unexpected token\|SyntaxError"; then
|
|
162
|
+
echo -e "${RED}│ state.json is corrupted (invalid JSON)${NC}"
|
|
163
|
+
echo -e "${RED}│${NC}"
|
|
164
|
+
echo -e "${RED}│ Fix: Run ./.vbounce/scripts/validate_state.mjs to see errors,${NC}"
|
|
165
|
+
echo -e "${RED}│ then repair or regenerate with init_sprint.mjs${NC}"
|
|
166
|
+
|
|
167
|
+
elif echo "$STDERR_CONTENT" | grep -qi "not found in state.json\|not found in stories"; then
|
|
168
|
+
echo -e "${RED}│ Story ID not registered in state.json${NC}"
|
|
169
|
+
echo -e "${RED}│${NC}"
|
|
170
|
+
echo -e "${RED}│ Fix: Verify the story ID, or add it via update_state.mjs${NC}"
|
|
171
|
+
|
|
172
|
+
elif echo "$STDERR_CONTENT" | grep -qi "ENOENT\|no such file"; then
|
|
173
|
+
echo -e "${RED}│ A required file or directory is missing${NC}"
|
|
174
|
+
echo -e "${RED}│${NC}"
|
|
175
|
+
echo -e "${RED}│ Fix: Run ./.vbounce/scripts/doctor.mjs to identify missing files${NC}"
|
|
176
|
+
|
|
177
|
+
elif echo "$STDERR_CONTENT" | grep -qi "permission denied\|EACCES"; then
|
|
178
|
+
echo -e "${RED}│ Permission denied on a file or directory${NC}"
|
|
179
|
+
echo -e "${RED}│${NC}"
|
|
180
|
+
echo -e "${RED}│ Fix: Check file permissions — shell scripts may need chmod +x${NC}"
|
|
181
|
+
|
|
182
|
+
elif [[ $EXIT_CODE -eq 1 ]]; then
|
|
183
|
+
echo -e "${RED}│ Script reported failure (exit 1) — check stderr above${NC}"
|
|
184
|
+
echo -e "${RED}│${NC}"
|
|
185
|
+
echo -e "${RED}│ Fix: Run ./.vbounce/scripts/doctor.mjs for a full health check${NC}"
|
|
186
|
+
|
|
187
|
+
else
|
|
188
|
+
echo -e "${RED}│ Unexpected exit code ${EXIT_CODE}${NC}"
|
|
189
|
+
echo -e "${RED}│${NC}"
|
|
190
|
+
echo -e "${RED}│ Fix: Run ./.vbounce/scripts/doctor.mjs for a full health check${NC}"
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
echo -e "${RED}└──────────────────────────────────────────────────────────┘${NC}"
|
|
194
|
+
|
|
195
|
+
exit $EXIT_CODE
|
package/scripts/update_state.mjs
CHANGED
|
@@ -16,16 +16,12 @@ import fs from 'fs';
|
|
|
16
16
|
import path from 'path';
|
|
17
17
|
import { fileURLToPath } from 'url';
|
|
18
18
|
import { validateState } from './validate_state.mjs';
|
|
19
|
+
import { VALID_STATES } from './constants.mjs';
|
|
19
20
|
|
|
20
21
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
21
22
|
const ROOT = path.resolve(__dirname, '../..');
|
|
22
23
|
const STATE_FILE = path.join(ROOT, '.vbounce', 'state.json');
|
|
23
24
|
|
|
24
|
-
const VALID_STATES = [
|
|
25
|
-
'Draft', 'Refinement', 'Ready to Bounce', 'Bouncing',
|
|
26
|
-
'QA Passed', 'Architect Passed', 'Done', 'Escalated', 'Parking Lot'
|
|
27
|
-
];
|
|
28
|
-
|
|
29
25
|
function readState() {
|
|
30
26
|
if (!fs.existsSync(STATE_FILE)) {
|
|
31
27
|
console.error(`ERROR: ${STATE_FILE} not found. Run: vbounce sprint init S-XX D-XX`);
|
|
@@ -10,16 +10,12 @@
|
|
|
10
10
|
import fs from 'fs';
|
|
11
11
|
import path from 'path';
|
|
12
12
|
import { fileURLToPath } from 'url';
|
|
13
|
+
import { VALID_STATES } from './constants.mjs';
|
|
13
14
|
|
|
14
15
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
15
16
|
const ROOT = path.resolve(__dirname, '../..');
|
|
16
17
|
const STATE_FILE = path.join(ROOT, '.vbounce', 'state.json');
|
|
17
18
|
|
|
18
|
-
const VALID_STATES = [
|
|
19
|
-
'Draft', 'Refinement', 'Ready to Bounce', 'Bouncing',
|
|
20
|
-
'QA Passed', 'Architect Passed', 'Done', 'Escalated', 'Parking Lot'
|
|
21
|
-
];
|
|
22
|
-
|
|
23
19
|
/**
|
|
24
20
|
* Validates a state object. Returns { valid, errors }.
|
|
25
21
|
* @param {object} state
|
|
@@ -184,6 +184,14 @@ Examples:
|
|
|
184
184
|
git checkout -b sprint/S-01 main
|
|
185
185
|
mkdir -p .vbounce/archive
|
|
186
186
|
|
|
187
|
+
1b. Initialize sprint state (MANDATORY):
|
|
188
|
+
./.vbounce/scripts/run_script.sh init_sprint.mjs S-{XX} D-{NN} --stories STORY-ID1,STORY-ID2,...
|
|
189
|
+
- Extract story IDs and delivery ID from the confirmed Sprint Plan §1 table
|
|
190
|
+
- This creates .vbounce/state.json — required by all downstream scripts
|
|
191
|
+
- If state.json already exists for this sprint, the script will warn and overwrite
|
|
192
|
+
- Verify success: run_script.sh validate_state.mjs
|
|
193
|
+
- If this step fails, DO NOT proceed — no scripts will work without state.json
|
|
194
|
+
|
|
187
195
|
2. Verify Sprint Plan:
|
|
188
196
|
- Sprint Plan status must be "Confirmed" (human-approved in Phase 2)
|
|
189
197
|
- §0 Sprint Readiness Gate must be fully checked
|
|
@@ -197,13 +205,13 @@ Examples:
|
|
|
197
205
|
4. **Hotfix Path** (L1 Trivial tasks only — triaged during Phase 1):
|
|
198
206
|
a. Create `HOTFIX-{Date}-{Name}.md` using the template.
|
|
199
207
|
b. Delegate to Developer (no worktree needed if acting on active branch).
|
|
200
|
-
c. Developer runs `hotfix_manager.sh ledger "{Title}" "{Description}"` after implementation.
|
|
208
|
+
c. Developer runs `run_script.sh hotfix_manager.sh ledger "{Title}" "{Description}"` after implementation.
|
|
201
209
|
d. Human/Lead verifies manually.
|
|
202
|
-
e. DevOps runs `hotfix_manager.sh sync` to update any active story worktrees.
|
|
210
|
+
e. DevOps runs `run_script.sh hotfix_manager.sh sync` to update any active story worktrees.
|
|
203
211
|
f. Update Delivery Plan Status to "Done".
|
|
204
212
|
|
|
205
213
|
5. **Gate Config Check**:
|
|
206
|
-
- If `.vbounce/gate-checks.json` does not exist, run `./.vbounce/scripts/init_gate_config.sh` to auto-detect the project stack and generate default gate checks.
|
|
214
|
+
- If `.vbounce/gate-checks.json` does not exist, run `./.vbounce/scripts/run_script.sh init_gate_config.sh` to auto-detect the project stack and generate default gate checks.
|
|
207
215
|
- If it exists, verify it's current (stack detection may have changed).
|
|
208
216
|
|
|
209
217
|
6. **Parallel Readiness Check** (before bouncing multiple stories simultaneously):
|
|
@@ -267,7 +275,7 @@ mkdir -p .worktrees/STORY-{ID}-{StoryName}/.vbounce/{tasks,reports}
|
|
|
267
275
|
### Step 3: QA Pass
|
|
268
276
|
```
|
|
269
277
|
0. Run pre-QA gate scan:
|
|
270
|
-
./.vbounce/scripts/pre_gate_runner.sh qa .worktrees/STORY-{ID}-{StoryName}/ sprint/S-{XX}
|
|
278
|
+
./.vbounce/scripts/run_script.sh pre_gate_runner.sh qa .worktrees/STORY-{ID}-{StoryName}/ sprint/S-{XX}
|
|
271
279
|
- If scan FAILS on trivial issues (debug statements, missing JSDoc, TODOs):
|
|
272
280
|
Return to Developer for quick fix. Do NOT spawn QA for mechanical failures.
|
|
273
281
|
If pre-gate scan fails 3+ times → Escalate: present failures to human with options:
|
|
@@ -293,7 +301,7 @@ mkdir -p .worktrees/STORY-{ID}-{StoryName}/.vbounce/{tasks,reports}
|
|
|
293
301
|
### Step 4: Architect Pass
|
|
294
302
|
```
|
|
295
303
|
0. Run pre-Architect gate scan:
|
|
296
|
-
./.vbounce/scripts/pre_gate_runner.sh arch .worktrees/STORY-{ID}-{StoryName}/ sprint/S-{XX}
|
|
304
|
+
./.vbounce/scripts/run_script.sh pre_gate_runner.sh arch .worktrees/STORY-{ID}-{StoryName}/ sprint/S-{XX}
|
|
297
305
|
- If scan reveals new dependencies or structural violations:
|
|
298
306
|
Return to Developer for resolution. Do NOT spawn Architect for mechanical failures.
|
|
299
307
|
If pre-gate scan fails 3+ times → Escalate to human (same options as pre-QA escalation).
|
|
@@ -315,6 +323,13 @@ mkdir -p .worktrees/STORY-{ID}-{StoryName}/.vbounce/{tasks,reports}
|
|
|
315
323
|
|
|
316
324
|
### Step 5: Story Merge (DevOps)
|
|
317
325
|
```
|
|
326
|
+
0. Verify gate reports exist (MANDATORY before merge):
|
|
327
|
+
- Dev report: .worktrees/STORY-{ID}-{StoryName}/.vbounce/reports/STORY-{ID}-{StoryName}-dev*.md
|
|
328
|
+
- QA report: .worktrees/STORY-{ID}-{StoryName}/.vbounce/reports/STORY-{ID}-{StoryName}-qa*.md
|
|
329
|
+
- Arch report: .worktrees/STORY-{ID}-{StoryName}/.vbounce/reports/STORY-{ID}-{StoryName}-arch*.md
|
|
330
|
+
If ANY report is missing, DO NOT proceed with merge.
|
|
331
|
+
Return to Lead with: which reports are missing and which agents need to re-run.
|
|
332
|
+
(Fast Track stories skip QA/Arch — only Dev report required.)
|
|
318
333
|
1. Spawn devops subagent with:
|
|
319
334
|
- Story ID and sprint branch name
|
|
320
335
|
- All gate reports (QA PASS + Architect PASS)
|
|
@@ -375,7 +390,7 @@ This phase gives ad-hoc post-delivery feedback a proper home. Without it, users
|
|
|
375
390
|
After ALL stories are merged into `sprint/S-01`:
|
|
376
391
|
```
|
|
377
392
|
1. Spawn architect subagent on sprint/S-01 branch
|
|
378
|
-
2. First, Architect runs `./.vbounce/scripts/hotfix_manager.sh audit` to check for hotfix drift. If it fails, perform deep audit on flagged files.
|
|
393
|
+
2. First, Architect runs `./.vbounce/scripts/run_script.sh hotfix_manager.sh audit` to check for hotfix drift. If it fails, perform deep audit on flagged files.
|
|
379
394
|
3. Run Sprint Integration Audit — Deep Audit on combined changes
|
|
380
395
|
4. Check for: duplicate routes, competing state, overlapping migrations
|
|
381
396
|
5. If issues found:
|
|
@@ -423,14 +438,14 @@ After ALL stories are merged into `sprint/S-01`:
|
|
|
423
438
|
7. **Framework Self-Assessment** (aggregated from agent reports):
|
|
424
439
|
- Collect all `## Process Feedback` sections from agent reports in `.vbounce/archive/S-{XX}/`
|
|
425
440
|
- Populate §5 Framework Self-Assessment tables in the Sprint Report by category
|
|
426
|
-
- **Always run** `suggest_improvements.mjs` — every sprint, unconditionally. First sprints generate the most friction.
|
|
441
|
+
- **Always run** `run_script.sh suggest_improvements.mjs` — every sprint, unconditionally. First sprints generate the most friction.
|
|
427
442
|
- **Verbally present** the top improvement suggestions to the user. Do NOT just embed them in the report — tell the user directly:
|
|
428
443
|
- Summarize each P0/P1 suggestion in plain language (what's broken, why it matters, what to change)
|
|
429
444
|
- For P2/P3 suggestions, give a brief list and note they're in `.vbounce/improvement-suggestions.md`
|
|
430
445
|
- Ask the user: *"Want me to run `/improve` to apply any of these?"*
|
|
431
446
|
- If user approves → read `.vbounce/skills/improve/SKILL.md` and execute the improvement process
|
|
432
447
|
8. Product Documentation check (runs on `main` after sprint merge):
|
|
433
|
-
a. **Staleness Detection** — run `./.vbounce/scripts/vdoc_staleness.mjs S-{XX}`
|
|
448
|
+
a. **Staleness Detection** — run `./.vbounce/scripts/run_script.sh vdoc_staleness.mjs S-{XX}`
|
|
434
449
|
- Cross-references all Dev Reports' `files_modified` against manifest key files
|
|
435
450
|
- Generates `.vbounce/scribe-task-S-{XX}.md` with targeted list of stale docs
|
|
436
451
|
- Populates Sprint Report §1 "Product Docs Affected" table
|
|
@@ -558,8 +573,50 @@ If merging story branch into sprint branch creates conflicts:
|
|
|
558
573
|
|
|
559
574
|
---
|
|
560
575
|
|
|
576
|
+
## Script Execution Protocol
|
|
577
|
+
|
|
578
|
+
**All `.vbounce/scripts/*` invocations MUST go through the wrapper:**
|
|
579
|
+
|
|
580
|
+
```bash
|
|
581
|
+
./.vbounce/scripts/run_script.sh <script-name> [args...]
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
**Never call scripts directly.** The wrapper captures exit codes, stdout, and stderr separately, runs pre-flight checks (e.g. state.json existence), and on failure prints a structured diagnostic block with root cause and suggested fix.
|
|
585
|
+
|
|
586
|
+
### When a Script Fails
|
|
587
|
+
|
|
588
|
+
1. **Stop the current step.** Do not retry blindly or continue as if the script succeeded.
|
|
589
|
+
2. **Read the diagnostic block.** The wrapper prints the exit code, stderr, root cause, and a suggested fix.
|
|
590
|
+
3. **Attempt self-repair (once).** If the fix is within the agent's capability:
|
|
591
|
+
- Missing `state.json` → run `run_script.sh init_sprint.mjs S-{XX} D-{XX} --stories {IDS}`
|
|
592
|
+
- Invalid JSON → run `run_script.sh validate_state.mjs`, repair, retry
|
|
593
|
+
- Missing file/directory → run `run_script.sh doctor.mjs`, fix what's reported, retry
|
|
594
|
+
- Permission denied → `chmod +x` the script, retry
|
|
595
|
+
4. **Re-run through the wrapper.** If the retry succeeds, continue the step. Log the failure and fix in the agent report under `## Script Incidents`.
|
|
596
|
+
5. **Escalate if retry fails.** Write a **Script Failure Report** in the agent report and return it to the Lead:
|
|
597
|
+
|
|
598
|
+
```markdown
|
|
599
|
+
## Script Incidents
|
|
600
|
+
|
|
601
|
+
### [FAIL] {script_name} {args}
|
|
602
|
+
- **Exit code:** {N}
|
|
603
|
+
- **Stderr:** {first 10 lines}
|
|
604
|
+
- **Root cause:** {from diagnostic block or agent analysis}
|
|
605
|
+
- **Self-repair attempted:** {what was tried}
|
|
606
|
+
- **Status:** Resolved / Escalated
|
|
607
|
+
- **Suggested fix:** {if escalated — what the Lead or human should do}
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
6. **Lead routes escalated failures:**
|
|
611
|
+
- Infrastructure issue (missing state, corrupt config) → Lead fixes and re-delegates
|
|
612
|
+
- Script bug → Lead presents to human with the Script Failure Report and the diagnostic output
|
|
613
|
+
- Repeated failure (same script fails 3+ times across stories) → Flag in Sprint Report §5 Framework Self-Assessment as a **Blocker**
|
|
614
|
+
|
|
615
|
+
---
|
|
616
|
+
|
|
561
617
|
## Critical Rules
|
|
562
618
|
|
|
619
|
+
- **All scripts go through run_script.sh.** Never invoke `.vbounce/scripts/*.mjs` or `*.sh` directly. The wrapper provides error capture, pre-flight validation, and structured diagnostics that agents depend on for self-repair.
|
|
563
620
|
- **The Lead never writes code.** It plans, delegates, monitors, and consolidates.
|
|
564
621
|
- **Enforce Sequential Dependencies.** Never parallelize stories where one depends on the other. Wait for merge.
|
|
565
622
|
- **One story = one worktree.** Never mix stories in a single worktree.
|