@sandrinio/vbounce 1.5.0 → 1.7.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 +108 -18
- package/bin/vbounce.mjs +291 -146
- package/brains/AGENTS.md +12 -10
- package/brains/CHANGELOG.md +99 -1
- package/brains/CLAUDE.md +29 -22
- package/brains/GEMINI.md +47 -9
- package/brains/SETUP.md +11 -5
- package/brains/claude-agents/architect.md +22 -6
- package/brains/claude-agents/developer.md +2 -2
- package/brains/claude-agents/devops.md +3 -0
- package/brains/claude-agents/qa.md +25 -9
- package/brains/copilot/copilot-instructions.md +49 -0
- package/brains/cursor-rules/vbounce-process.mdc +9 -7
- package/brains/windsurf/.windsurfrules +30 -0
- package/package.json +2 -4
- package/scripts/close_sprint.mjs +94 -0
- package/scripts/complete_story.mjs +113 -0
- package/scripts/doctor.mjs +144 -0
- package/scripts/init_gate_config.sh +151 -0
- package/scripts/init_sprint.mjs +121 -0
- package/scripts/pre_gate_common.sh +576 -0
- package/scripts/pre_gate_runner.sh +176 -0
- package/scripts/prep_arch_context.mjs +178 -0
- package/scripts/prep_qa_context.mjs +134 -0
- package/scripts/prep_sprint_context.mjs +118 -0
- package/scripts/prep_sprint_summary.mjs +154 -0
- package/scripts/sprint_trends.mjs +160 -0
- package/scripts/suggest_improvements.mjs +200 -0
- package/scripts/update_state.mjs +132 -0
- package/scripts/validate_bounce_readiness.mjs +125 -0
- package/scripts/validate_report.mjs +39 -2
- package/scripts/validate_sprint_plan.mjs +117 -0
- package/scripts/validate_state.mjs +99 -0
- package/skills/agent-team/SKILL.md +56 -21
- package/skills/agent-team/references/cleanup.md +42 -0
- package/skills/agent-team/references/delivery-sync.md +43 -0
- package/skills/agent-team/references/git-strategy.md +52 -0
- package/skills/agent-team/references/mid-sprint-triage.md +71 -0
- package/skills/agent-team/references/report-naming.md +34 -0
- package/skills/doc-manager/SKILL.md +5 -4
- package/skills/improve/SKILL.md +27 -1
- package/skills/lesson/SKILL.md +23 -0
- package/templates/delivery_plan.md +1 -1
- package/templates/hotfix.md +1 -1
- package/templates/sprint.md +65 -13
- package/templates/sprint_report.md +8 -1
- package/templates/story.md +1 -1
- package/scripts/pre_bounce_sync.sh +0 -37
- package/scripts/vbounce_ask.mjs +0 -98
- package/scripts/vbounce_index.mjs +0 -184
package/README.md
CHANGED
|
@@ -38,22 +38,12 @@ V-Bounce OS organizes planning documents (`product_plans/`) through a strict sta
|
|
|
38
38
|
|
|
39
39
|
## 🛠️ The Tech Stack
|
|
40
40
|
|
|
41
|
-
V-Bounce OS is built to be **local-first, privacy-conscious, and
|
|
41
|
+
V-Bounce OS is built to be **local-first, privacy-conscious, and dependency-light**.
|
|
42
42
|
|
|
43
|
-
- **
|
|
44
|
-
- **
|
|
45
|
-
- **
|
|
46
|
-
- **
|
|
47
|
-
|
|
48
|
-
---
|
|
49
|
-
|
|
50
|
-
## 🧠 Semantic Context (Local RAG)
|
|
51
|
-
|
|
52
|
-
V-Bounce OS doesn't just dump your entire codebase into a prompt. It uses **Retrieval-Augmented Generation (RAG)** to find only the rules that matter right now.
|
|
53
|
-
|
|
54
|
-
1. **Indexing**: The `pre_bounce_sync.sh` script crawls your `product_plans/`, `LESSONS.md`, and `Roadmap ADRs`, converting them into searchable vectors.
|
|
55
|
-
2. **Querying**: Agents use the built-in `./scripts/vbounce_ask.mjs` tool to ask questions like *"What are the architectural constraints for auth?"* or *"What mistakes did we make with the last React component?"*.
|
|
56
|
-
3. **Targeted Context**: The agent receives only the most relevant 3-5 snippets of project history, preventing context-window bloat and improving instruction following.
|
|
43
|
+
- **Runtime**: Node.js — Powering the validation pipeline, context preparation, and CLI.
|
|
44
|
+
- **Data Contract**: YAML Frontmatter + Markdown — Human-readable agent handoffs that are also strictly machine-parsable.
|
|
45
|
+
- **State Management**: `.bounce/state.json` — Machine-readable sprint state for instant crash recovery without re-reading documents.
|
|
46
|
+
- **Context Budget**: On-demand prep scripts (`vbounce prep sprint/qa/arch`) generate capped context packs — no embedding or vector DB required.
|
|
57
47
|
|
|
58
48
|
---
|
|
59
49
|
|
|
@@ -80,11 +70,111 @@ npx @sandrinio/vbounce install codex
|
|
|
80
70
|
|
|
81
71
|
### What gets installed?
|
|
82
72
|
- **Agent Instructions:** The "Brain" file (e.g., `CLAUDE.md`, `.cursor/rules/`) that teaches your AI how to follow the V-Bounce process.
|
|
83
|
-
- **Templates:** Markdown templates for your Charter, Roadmap, Epics, and
|
|
84
|
-
- **Bundled Scripts:**
|
|
85
|
-
- **
|
|
73
|
+
- **Templates:** Markdown templates for your Charter, Roadmap, Epics, Stories, Sprint Plans, and Delivery Plans.
|
|
74
|
+
- **Bundled Scripts:** 16+ automation scripts — validation pipeline, context preparation, state management, sprint lifecycle, and the self-improvement loop.
|
|
75
|
+
- **Lightweight Dependencies:** The installer runs `npm install` for `js-yaml`, `marked`, and `commander` — nothing else. No vector DBs, no embedding models.
|
|
86
76
|
- **vdoc Integration:** The installer offers to install [`@sandrinio/vdoc`](https://github.com/sandrinio/vdoc) for your platform — enabling automatic semantic product documentation generation via the Scribe agent.
|
|
87
77
|
|
|
78
|
+
After installing, run `vbounce doctor` to verify your setup is complete.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 🛠️ The `vbounce` CLI
|
|
83
|
+
|
|
84
|
+
All V-Bounce OS operations route through a unified CLI. Every command is designed to be run by the Team Lead agent — not just humans.
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Sprint lifecycle
|
|
88
|
+
vbounce sprint init S-01 D-01 # Initialize sprint state.json + plan dir
|
|
89
|
+
vbounce sprint close S-01 # Validate terminal states, archive, close
|
|
90
|
+
|
|
91
|
+
# Story lifecycle
|
|
92
|
+
vbounce story complete STORY-001-01-login # Update state.json + sprint plan §4
|
|
93
|
+
|
|
94
|
+
# State management (crash recovery)
|
|
95
|
+
vbounce state show # Print current state.json
|
|
96
|
+
vbounce state update STORY-001-01-login "QA Passed" # Update story state
|
|
97
|
+
vbounce state update STORY-001-01-login "Bouncing" --qa-bounce # Increment QA bounce
|
|
98
|
+
|
|
99
|
+
# Context preparation (context budget management)
|
|
100
|
+
vbounce prep sprint S-01 # Generate sprint-context-S-01.md (≤200 lines)
|
|
101
|
+
vbounce prep qa STORY-001-01-login # Generate qa-context-STORY-ID.md (≤300 lines)
|
|
102
|
+
vbounce prep arch STORY-001-01-login # Generate arch-context with truncated diff
|
|
103
|
+
|
|
104
|
+
# Validation gates
|
|
105
|
+
vbounce validate report .bounce/reports/STORY-001-01-login-qa.md
|
|
106
|
+
vbounce validate state # Validate state.json schema
|
|
107
|
+
vbounce validate sprint S-01 # Validate sprint plan structure + cross-refs
|
|
108
|
+
vbounce validate ready STORY-001-01-login # Pre-bounce readiness gate
|
|
109
|
+
|
|
110
|
+
# Self-improvement loop
|
|
111
|
+
vbounce trends # Compute sprint metrics → .bounce/trends.md
|
|
112
|
+
vbounce suggest S-01 # Generate improvement suggestions
|
|
113
|
+
|
|
114
|
+
# Framework health
|
|
115
|
+
vbounce doctor # Check all required files, scripts, templates
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## 🔄 State Management & Crash Recovery
|
|
121
|
+
|
|
122
|
+
V-Bounce OS tracks sprint state in `.bounce/state.json` — a machine-readable snapshot that survives context resets and session interruptions.
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"sprint_id": "S-01",
|
|
127
|
+
"delivery_id": "D-01",
|
|
128
|
+
"current_phase": "bouncing",
|
|
129
|
+
"last_action": "QA failed STORY-001-01-login — bounce 1",
|
|
130
|
+
"stories": {
|
|
131
|
+
"STORY-001-01-login": {
|
|
132
|
+
"state": "Bouncing",
|
|
133
|
+
"qa_bounces": 1,
|
|
134
|
+
"arch_bounces": 0,
|
|
135
|
+
"worktree": ".worktrees/STORY-001-01-login",
|
|
136
|
+
"updated_at": "2026-03-12T10:00:00Z"
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
When a new session starts, the Team Lead reads `state.json` in under 5 seconds to know exactly where the sprint left off — no re-reading 10 markdown files.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## 📊 Self-Improvement Loop
|
|
147
|
+
|
|
148
|
+
V-Bounce OS tracks its own performance and suggests improvements automatically.
|
|
149
|
+
|
|
150
|
+
1. **Root Cause Tagging**: Every QA and Architect FAIL report includes a `root_cause:` field (e.g., `missing_tests`, `adr_violation`, `spec_ambiguity`) that feeds into trend analysis.
|
|
151
|
+
2. **Sprint Trends**: `vbounce trends` scans all archived reports to compute first-pass rate, average bounce count, correction tax, and root cause breakdown per sprint.
|
|
152
|
+
3. **Improvement Suggestions**: `vbounce suggest S-{XX}` reads trends, LESSONS.md, and the improvement log to flag stale lessons, recurring failure patterns, and graduation candidates.
|
|
153
|
+
4. **Improvement Log**: `.bounce/improvement-log.md` tracks every suggestion with Applied/Rejected/Deferred status — so nothing falls through the cracks.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 🔧 Tool Tier Model
|
|
158
|
+
|
|
159
|
+
V-Bounce OS supports four tiers of AI tools with dedicated brain files for each.
|
|
160
|
+
|
|
161
|
+
| Tier | Tools | Brain File | Capabilities |
|
|
162
|
+
|------|-------|------------|--------------|
|
|
163
|
+
| **Tier 1** | Claude Code | `brains/CLAUDE.md` | Full orchestration — spawns subagents, manages state, runs all CLI commands |
|
|
164
|
+
| **Tier 2** | Gemini CLI, OpenAI Codex | `brains/GEMINI.md`, `brains/codex/` | Single-agent — follows bounce loop, reads state.json, all CLI commands |
|
|
165
|
+
| **Tier 3** | Cursor | `brains/cursor-rules/` | Role-specific context injection via `.cursor/rules/` MDC files |
|
|
166
|
+
| **Tier 4** | GitHub Copilot, Windsurf | `brains/copilot/`, `brains/windsurf/` | Awareness mode — checklist-driven, reads state.json, CLI commands for safe operations |
|
|
167
|
+
|
|
168
|
+
Install the appropriate brain for your tool:
|
|
169
|
+
```bash
|
|
170
|
+
npx @sandrinio/vbounce install claude # Tier 1
|
|
171
|
+
npx @sandrinio/vbounce install gemini # Tier 2
|
|
172
|
+
npx @sandrinio/vbounce install cursor # Tier 3
|
|
173
|
+
npx @sandrinio/vbounce install vscode # Tier 4
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
88
178
|
### 🧰 The Bundled Skills
|
|
89
179
|
V-Bounce OS installs a powerful suite of specialized markdown `skills/` directly into your workspace. These act as modular capabilities you can invoke dynamically or that the Team Lead agent will invoke automatically during the SDLC process:
|
|
90
180
|
|
package/bin/vbounce.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import path from 'path';
|
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
import readline from 'readline';
|
|
7
7
|
|
|
8
|
-
import { execSync } from 'child_process';
|
|
8
|
+
import { execSync, spawnSync } from 'child_process';
|
|
9
9
|
|
|
10
10
|
const __filename = fileURLToPath(import.meta.url);
|
|
11
11
|
const __dirname = path.dirname(__filename);
|
|
@@ -13,7 +13,7 @@ const pkgRoot = path.join(__dirname, '..');
|
|
|
13
13
|
|
|
14
14
|
const args = process.argv.slice(2);
|
|
15
15
|
const command = args[0];
|
|
16
|
-
const
|
|
16
|
+
const sub = args[1];
|
|
17
17
|
|
|
18
18
|
if (command === '-v' || command === '--version') {
|
|
19
19
|
const pkgPath = path.join(pkgRoot, 'package.json');
|
|
@@ -26,7 +26,32 @@ if (command === '-v' || command === '--version') {
|
|
|
26
26
|
process.exit(0);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
//
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Script runner helper
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Run a Node.js script from the scripts/ directory with forwarded args.
|
|
35
|
+
* @param {string} scriptName - filename inside scripts/ (e.g. 'doctor.mjs')
|
|
36
|
+
* @param {string[]} scriptArgs - additional CLI arguments
|
|
37
|
+
*/
|
|
38
|
+
function runScript(scriptName, scriptArgs = []) {
|
|
39
|
+
const scriptPath = path.join(pkgRoot, 'scripts', scriptName);
|
|
40
|
+
if (!fs.existsSync(scriptPath)) {
|
|
41
|
+
console.error(`Error: Script not found: scripts/${scriptName}`);
|
|
42
|
+
console.error('Run `vbounce doctor` to check which scripts are missing.');
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
const result = spawnSync(process.execPath, [scriptPath, ...scriptArgs], {
|
|
46
|
+
stdio: 'inherit',
|
|
47
|
+
cwd: process.cwd()
|
|
48
|
+
});
|
|
49
|
+
process.exit(result.status ?? 0);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Utility for interactive prompt (used by install)
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
30
55
|
const rl = readline.createInterface({
|
|
31
56
|
input: process.stdin,
|
|
32
57
|
output: process.stdout
|
|
@@ -34,14 +59,33 @@ const rl = readline.createInterface({
|
|
|
34
59
|
|
|
35
60
|
const askQuestion = (query) => new Promise(resolve => rl.question(query, resolve));
|
|
36
61
|
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
// Help text
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
|
|
37
66
|
function displayHelp() {
|
|
38
67
|
console.log(`
|
|
39
|
-
|
|
68
|
+
V-Bounce OS CLI
|
|
40
69
|
|
|
41
70
|
Usage:
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
71
|
+
vbounce install <platform> Install V-Bounce OS into a project
|
|
72
|
+
vbounce state show Show current sprint state
|
|
73
|
+
vbounce state update <storyId> <state|--qa-bounce>
|
|
74
|
+
vbounce sprint init <sprintId> <deliveryId> [--stories STORY-001,...]
|
|
75
|
+
vbounce sprint close <sprintId>
|
|
76
|
+
vbounce story complete <storyId> [options]
|
|
77
|
+
vbounce validate report <file> Validate agent report YAML
|
|
78
|
+
vbounce validate state Validate state.json
|
|
79
|
+
vbounce validate sprint [file] Validate Sprint Plan
|
|
80
|
+
vbounce validate ready <storyId> Pre-bounce gate check
|
|
81
|
+
vbounce prep qa <storyId> Generate QA context pack
|
|
82
|
+
vbounce prep arch <storyId> Generate Architect context pack
|
|
83
|
+
vbounce prep sprint <sprintId> Generate Sprint context pack
|
|
84
|
+
vbounce trends Cross-sprint trend analysis
|
|
85
|
+
vbounce suggest <sprintId> Generate improvement suggestions
|
|
86
|
+
vbounce doctor Validate all configs and state files
|
|
87
|
+
|
|
88
|
+
Install Platforms:
|
|
45
89
|
claude : Installs CLAUDE.md and Claude Code subagents
|
|
46
90
|
cursor : Installs modular .cursor/rules/
|
|
47
91
|
gemini : Installs GEMINI.md and Antigravity skills
|
|
@@ -52,179 +96,280 @@ Supported Platforms:
|
|
|
52
96
|
process.exit(0);
|
|
53
97
|
}
|
|
54
98
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
// Route commands
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
58
102
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
// Map vbounce platform names to vdoc platform names
|
|
62
|
-
const vdocPlatformMap = {
|
|
63
|
-
claude: 'claude',
|
|
64
|
-
cursor: 'cursor',
|
|
65
|
-
gemini: 'gemini',
|
|
66
|
-
codex: 'agents',
|
|
67
|
-
vscode: 'vscode',
|
|
68
|
-
copilot: 'vscode'
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const platformMappings = {
|
|
72
|
-
claude: [
|
|
73
|
-
{ src: 'brains/CLAUDE.md', dest: 'CLAUDE.md' },
|
|
74
|
-
{ src: 'brains/claude-agents', dest: '.claude/agents' },
|
|
75
|
-
{ src: 'templates', dest: 'templates' },
|
|
76
|
-
{ src: 'skills', dest: 'skills' },
|
|
77
|
-
{ src: 'scripts', dest: 'scripts' }
|
|
78
|
-
],
|
|
79
|
-
cursor: [
|
|
80
|
-
{ src: 'brains/cursor-rules', dest: '.cursor/rules' },
|
|
81
|
-
{ src: 'templates', dest: 'templates' },
|
|
82
|
-
{ src: 'skills', dest: 'skills' },
|
|
83
|
-
{ src: 'scripts', dest: 'scripts' }
|
|
84
|
-
],
|
|
85
|
-
gemini: [
|
|
86
|
-
{ src: 'brains/GEMINI.md', dest: 'GEMINI.md' },
|
|
87
|
-
{ src: 'templates', dest: 'templates' },
|
|
88
|
-
{ src: 'skills', dest: 'skills' },
|
|
89
|
-
{ src: 'skills', dest: '.agents/skills' },
|
|
90
|
-
{ src: 'scripts', dest: 'scripts' }
|
|
91
|
-
],
|
|
92
|
-
codex: [
|
|
93
|
-
{ src: 'brains/AGENTS.md', dest: 'AGENTS.md' },
|
|
94
|
-
{ src: 'templates', dest: 'templates' },
|
|
95
|
-
{ src: 'skills', dest: 'skills' },
|
|
96
|
-
{ src: 'scripts', dest: 'scripts' }
|
|
97
|
-
],
|
|
98
|
-
vscode: [
|
|
99
|
-
{ src: 'brains/CLAUDE.md', dest: '.github/copilot-instructions.md' },
|
|
100
|
-
{ src: 'templates', dest: 'templates' },
|
|
101
|
-
{ src: 'skills', dest: 'skills' },
|
|
102
|
-
{ src: 'scripts', dest: 'scripts' }
|
|
103
|
-
],
|
|
104
|
-
copilot: [
|
|
105
|
-
{ src: 'brains/CLAUDE.md', dest: '.github/copilot-instructions.md' },
|
|
106
|
-
{ src: 'templates', dest: 'templates' },
|
|
107
|
-
{ src: 'skills', dest: 'skills' },
|
|
108
|
-
{ src: 'scripts', dest: 'scripts' }
|
|
109
|
-
]
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
const mapping = platformMappings[targetPlatform];
|
|
113
|
-
|
|
114
|
-
if (!mapping) {
|
|
115
|
-
console.error(`Error: Unsupported platform '${targetPlatform}'.\n`);
|
|
103
|
+
if (!command || command === 'help' || command === '--help' || command === '-h') {
|
|
104
|
+
rl.close();
|
|
116
105
|
displayHelp();
|
|
117
106
|
}
|
|
118
107
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
108
|
+
// -- state --
|
|
109
|
+
if (command === 'state') {
|
|
110
|
+
rl.close();
|
|
111
|
+
if (sub === 'show') {
|
|
112
|
+
runScript('update_state.mjs', ['--show']);
|
|
113
|
+
} else if (sub === 'update') {
|
|
114
|
+
// vbounce state update <storyId> <newState|--qa-bounce>
|
|
115
|
+
runScript('update_state.mjs', args.slice(2));
|
|
116
|
+
} else {
|
|
117
|
+
console.error(`Unknown state subcommand: ${sub}`);
|
|
118
|
+
console.error('Usage: vbounce state show | vbounce state update <storyId> <state|--qa-bounce>');
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
123
122
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
123
|
+
// -- sprint --
|
|
124
|
+
if (command === 'sprint') {
|
|
125
|
+
rl.close();
|
|
126
|
+
if (sub === 'init') {
|
|
127
|
+
runScript('init_sprint.mjs', args.slice(2));
|
|
128
|
+
} else if (sub === 'close') {
|
|
129
|
+
runScript('close_sprint.mjs', args.slice(2));
|
|
130
|
+
} else {
|
|
131
|
+
console.error(`Unknown sprint subcommand: ${sub}`);
|
|
132
|
+
console.error('Usage: vbounce sprint init <sprintId> <deliveryId> | vbounce sprint close <sprintId>');
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
127
136
|
|
|
128
|
-
|
|
129
|
-
|
|
137
|
+
// -- story --
|
|
138
|
+
if (command === 'story') {
|
|
139
|
+
rl.close();
|
|
140
|
+
if (sub === 'complete') {
|
|
141
|
+
runScript('complete_story.mjs', args.slice(2));
|
|
142
|
+
} else {
|
|
143
|
+
console.error(`Unknown story subcommand: ${sub}`);
|
|
144
|
+
console.error('Usage: vbounce story complete <storyId> [options]');
|
|
145
|
+
process.exit(1);
|
|
130
146
|
}
|
|
147
|
+
}
|
|
131
148
|
|
|
132
|
-
|
|
133
|
-
|
|
149
|
+
// -- validate --
|
|
150
|
+
if (command === 'validate') {
|
|
151
|
+
rl.close();
|
|
152
|
+
if (sub === 'report') {
|
|
153
|
+
runScript('validate_report.mjs', args.slice(2));
|
|
154
|
+
} else if (sub === 'state') {
|
|
155
|
+
runScript('validate_state.mjs', args.slice(2));
|
|
156
|
+
} else if (sub === 'sprint') {
|
|
157
|
+
runScript('validate_sprint_plan.mjs', args.slice(2));
|
|
158
|
+
} else if (sub === 'ready') {
|
|
159
|
+
runScript('validate_bounce_readiness.mjs', args.slice(2));
|
|
134
160
|
} else {
|
|
135
|
-
|
|
161
|
+
console.error(`Unknown validate subcommand: ${sub}`);
|
|
162
|
+
console.error('Usage: vbounce validate report <file> | state | sprint [file] | ready <storyId>');
|
|
163
|
+
process.exit(1);
|
|
136
164
|
}
|
|
137
|
-
}
|
|
165
|
+
}
|
|
138
166
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
167
|
+
// -- prep --
|
|
168
|
+
if (command === 'prep') {
|
|
169
|
+
rl.close();
|
|
170
|
+
if (sub === 'qa') {
|
|
171
|
+
runScript('prep_qa_context.mjs', args.slice(2));
|
|
172
|
+
} else if (sub === 'arch') {
|
|
173
|
+
runScript('prep_arch_context.mjs', args.slice(2));
|
|
174
|
+
} else if (sub === 'sprint') {
|
|
175
|
+
runScript('prep_sprint_context.mjs', args.slice(2));
|
|
176
|
+
} else {
|
|
177
|
+
console.error(`Unknown prep subcommand: ${sub}`);
|
|
178
|
+
console.error('Usage: vbounce prep qa <storyId> | arch <storyId> | sprint <sprintId>');
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
142
181
|
}
|
|
143
182
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
183
|
+
// -- trends --
|
|
184
|
+
if (command === 'trends') {
|
|
185
|
+
rl.close();
|
|
186
|
+
runScript('sprint_trends.mjs', args.slice(1));
|
|
147
187
|
}
|
|
148
188
|
|
|
149
|
-
|
|
189
|
+
// -- suggest --
|
|
190
|
+
if (command === 'suggest') {
|
|
191
|
+
rl.close();
|
|
192
|
+
runScript('suggest_improvements.mjs', args.slice(1));
|
|
193
|
+
}
|
|
150
194
|
|
|
151
|
-
|
|
195
|
+
// -- doctor --
|
|
196
|
+
if (command === 'doctor') {
|
|
152
197
|
rl.close();
|
|
153
|
-
|
|
198
|
+
runScript('doctor.mjs', args.slice(1));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
// install command (original functionality)
|
|
203
|
+
// ---------------------------------------------------------------------------
|
|
204
|
+
|
|
205
|
+
if (command === 'install') {
|
|
206
|
+
const targetPlatform = sub?.toLowerCase();
|
|
154
207
|
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
|
|
208
|
+
if (!targetPlatform) {
|
|
209
|
+
rl.close();
|
|
210
|
+
displayHelp();
|
|
158
211
|
}
|
|
159
212
|
|
|
160
|
-
|
|
213
|
+
const CWD = process.cwd();
|
|
214
|
+
|
|
215
|
+
// Map vbounce platform names to vdoc platform names
|
|
216
|
+
const vdocPlatformMap = {
|
|
217
|
+
claude: 'claude',
|
|
218
|
+
cursor: 'cursor',
|
|
219
|
+
gemini: 'gemini',
|
|
220
|
+
codex: 'agents',
|
|
221
|
+
vscode: 'vscode',
|
|
222
|
+
copilot: 'vscode'
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const platformMappings = {
|
|
226
|
+
claude: [
|
|
227
|
+
{ src: 'brains/CLAUDE.md', dest: 'CLAUDE.md' },
|
|
228
|
+
{ src: 'brains/claude-agents', dest: '.claude/agents' },
|
|
229
|
+
{ src: 'templates', dest: 'templates' },
|
|
230
|
+
{ src: 'skills', dest: 'skills' },
|
|
231
|
+
{ src: 'scripts', dest: 'scripts' }
|
|
232
|
+
],
|
|
233
|
+
cursor: [
|
|
234
|
+
{ src: 'brains/cursor-rules', dest: '.cursor/rules' },
|
|
235
|
+
{ src: 'templates', dest: 'templates' },
|
|
236
|
+
{ src: 'skills', dest: 'skills' },
|
|
237
|
+
{ src: 'scripts', dest: 'scripts' }
|
|
238
|
+
],
|
|
239
|
+
gemini: [
|
|
240
|
+
{ src: 'brains/GEMINI.md', dest: 'GEMINI.md' },
|
|
241
|
+
{ src: 'templates', dest: 'templates' },
|
|
242
|
+
{ src: 'skills', dest: 'skills' },
|
|
243
|
+
{ src: 'skills', dest: '.agents/skills' },
|
|
244
|
+
{ src: 'scripts', dest: 'scripts' }
|
|
245
|
+
],
|
|
246
|
+
codex: [
|
|
247
|
+
{ src: 'brains/AGENTS.md', dest: 'AGENTS.md' },
|
|
248
|
+
{ src: 'templates', dest: 'templates' },
|
|
249
|
+
{ src: 'skills', dest: 'skills' },
|
|
250
|
+
{ src: 'scripts', dest: 'scripts' }
|
|
251
|
+
],
|
|
252
|
+
vscode: [
|
|
253
|
+
{ src: 'brains/CLAUDE.md', dest: '.github/copilot-instructions.md' },
|
|
254
|
+
{ src: 'templates', dest: 'templates' },
|
|
255
|
+
{ src: 'skills', dest: 'skills' },
|
|
256
|
+
{ src: 'scripts', dest: 'scripts' }
|
|
257
|
+
],
|
|
258
|
+
copilot: [
|
|
259
|
+
{ src: 'brains/CLAUDE.md', dest: '.github/copilot-instructions.md' },
|
|
260
|
+
{ src: 'templates', dest: 'templates' },
|
|
261
|
+
{ src: 'skills', dest: 'skills' },
|
|
262
|
+
{ src: 'scripts', dest: 'scripts' }
|
|
263
|
+
]
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
const mapping = platformMappings[targetPlatform];
|
|
267
|
+
|
|
268
|
+
if (!mapping) {
|
|
269
|
+
rl.close();
|
|
270
|
+
console.error(`Error: Unsupported platform '${targetPlatform}'.\n`);
|
|
271
|
+
displayHelp();
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
console.log(`\n🚀 Preparing to install V-Bounce OS for \x1b[36m${targetPlatform}\x1b[0m...\n`);
|
|
275
|
+
|
|
276
|
+
const toCopy = [];
|
|
277
|
+
const toOverwrite = [];
|
|
161
278
|
|
|
162
279
|
mapping.forEach(rule => {
|
|
163
280
|
const sourcePath = path.join(pkgRoot, rule.src);
|
|
164
281
|
const destPath = path.join(CWD, rule.dest);
|
|
165
282
|
|
|
166
|
-
if (!fs.existsSync(sourcePath))
|
|
283
|
+
if (!fs.existsSync(sourcePath)) {
|
|
284
|
+
return; // Source does not exist internally, skip
|
|
285
|
+
}
|
|
167
286
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
fs.mkdirSync(destPath, { recursive: true });
|
|
171
|
-
fs.cpSync(sourcePath, destPath, { recursive: true, force: true });
|
|
287
|
+
if (fs.existsSync(destPath)) {
|
|
288
|
+
toOverwrite.push(rule.dest);
|
|
172
289
|
} else {
|
|
173
|
-
|
|
174
|
-
if (!fs.existsSync(destDir)) {
|
|
175
|
-
fs.mkdirSync(destDir, { recursive: true });
|
|
176
|
-
}
|
|
177
|
-
fs.copyFileSync(sourcePath, destPath);
|
|
290
|
+
toCopy.push(rule.dest);
|
|
178
291
|
}
|
|
179
|
-
console.log(` \x1b[32m✓\x1b[0m ${rule.dest}`);
|
|
180
292
|
});
|
|
181
293
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
'@lancedb/lancedb',
|
|
186
|
-
'@xenova/transformers',
|
|
187
|
-
'js-yaml',
|
|
188
|
-
'marked',
|
|
189
|
-
'commander'
|
|
190
|
-
];
|
|
191
|
-
console.log(` Running: npm install ${deps.join(' ')}`);
|
|
192
|
-
execSync(`npm install ${deps.join(' ')}`, { stdio: 'inherit', cwd: CWD });
|
|
193
|
-
console.log(' \x1b[32m✓\x1b[0m Dependencies installed.');
|
|
194
|
-
} catch (err) {
|
|
195
|
-
console.error(' \x1b[31m✖\x1b[0m Failed to install dependencies. You may need to run it manually.');
|
|
294
|
+
if (toCopy.length > 0) {
|
|
295
|
+
console.log('The following will be \x1b[32mCREATED\x1b[0m:');
|
|
296
|
+
toCopy.forEach(f => console.log(` + ${f}`));
|
|
196
297
|
}
|
|
197
298
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
if (fs.existsSync(syncScript)) {
|
|
202
|
-
execSync(`chmod +x "${syncScript}" && "${syncScript}"`, { stdio: 'inherit', cwd: CWD });
|
|
203
|
-
console.log(' \x1b[32m✓\x1b[0m Knowledge base initialized.');
|
|
204
|
-
}
|
|
205
|
-
} catch (err) {
|
|
206
|
-
console.error(' \x1b[31m✖\x1b[0m Failed to initialize knowledge base. Run ./scripts/pre_bounce_sync.sh manually.');
|
|
299
|
+
if (toOverwrite.length > 0) {
|
|
300
|
+
console.log('\nThe following will be \x1b[33mOVERWRITTEN\x1b[0m:');
|
|
301
|
+
toOverwrite.forEach(f => console.log(` ! ${f}`));
|
|
207
302
|
}
|
|
208
303
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
304
|
+
console.log('');
|
|
305
|
+
|
|
306
|
+
askQuestion('Proceed with installation? [y/N] ').then(async answer => {
|
|
307
|
+
rl.close();
|
|
308
|
+
const confirmation = answer.trim().toLowerCase();
|
|
309
|
+
|
|
310
|
+
if (confirmation !== 'y' && confirmation !== 'yes') {
|
|
311
|
+
console.log('\n❌ Installation cancelled.\n');
|
|
312
|
+
process.exit(0);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
console.log('\n📦 Installing files...');
|
|
316
|
+
|
|
317
|
+
mapping.forEach(rule => {
|
|
318
|
+
const sourcePath = path.join(pkgRoot, rule.src);
|
|
319
|
+
const destPath = path.join(CWD, rule.dest);
|
|
320
|
+
|
|
321
|
+
if (!fs.existsSync(sourcePath)) return;
|
|
322
|
+
|
|
323
|
+
const stats = fs.statSync(sourcePath);
|
|
324
|
+
if (stats.isDirectory()) {
|
|
325
|
+
fs.mkdirSync(destPath, { recursive: true });
|
|
326
|
+
fs.cpSync(sourcePath, destPath, { recursive: true, force: true });
|
|
327
|
+
} else {
|
|
328
|
+
const destDir = path.dirname(destPath);
|
|
329
|
+
if (!fs.existsSync(destDir)) {
|
|
330
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
331
|
+
}
|
|
332
|
+
fs.copyFileSync(sourcePath, destPath);
|
|
223
333
|
}
|
|
224
|
-
|
|
225
|
-
|
|
334
|
+
console.log(` \x1b[32m✓\x1b[0m ${rule.dest}`);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
console.log('\n⚙️ Installing dependencies...');
|
|
338
|
+
try {
|
|
339
|
+
const deps = ['js-yaml', 'marked', 'commander'];
|
|
340
|
+
console.log(` Running: npm install ${deps.join(' ')}`);
|
|
341
|
+
execSync(`npm install ${deps.join(' ')}`, { stdio: 'inherit', cwd: CWD });
|
|
342
|
+
console.log(' \x1b[32m✓\x1b[0m Dependencies installed.');
|
|
343
|
+
} catch (err) {
|
|
344
|
+
console.error(' \x1b[31m✖\x1b[0m Failed to install dependencies. You may need to run it manually.');
|
|
226
345
|
}
|
|
227
|
-
}
|
|
228
346
|
|
|
229
|
-
|
|
230
|
-
|
|
347
|
+
// vdoc integration
|
|
348
|
+
const vdocPlatform = vdocPlatformMap[targetPlatform];
|
|
349
|
+
if (vdocPlatform) {
|
|
350
|
+
const rl2 = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
351
|
+
const vdocAnswer = await new Promise(resolve => rl2.question('\n📝 Install vdoc (AI-powered documentation generator)? [y/N] ', resolve));
|
|
352
|
+
rl2.close();
|
|
353
|
+
|
|
354
|
+
if (vdocAnswer.trim().toLowerCase() === 'y' || vdocAnswer.trim().toLowerCase() === 'yes') {
|
|
355
|
+
console.log(`\n📝 Installing vdoc for ${vdocPlatform}...`);
|
|
356
|
+
try {
|
|
357
|
+
execSync(`npx @sandrinio/vdoc install ${vdocPlatform}`, { stdio: 'inherit', cwd: CWD });
|
|
358
|
+
console.log(' \x1b[32m✓\x1b[0m vdoc installed.');
|
|
359
|
+
} catch (err) {
|
|
360
|
+
console.error(` \x1b[31m✖\x1b[0m Failed to install vdoc. Run manually: npx @sandrinio/vdoc install ${vdocPlatform}`);
|
|
361
|
+
}
|
|
362
|
+
} else {
|
|
363
|
+
console.log(`\n Skipped. You can install later: npx @sandrinio/vdoc install ${vdocPlatform}`);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
console.log('\n✅ V-Bounce OS successfully installed! Welcome to the team.\n');
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
} else {
|
|
371
|
+
// Unknown command fallthrough
|
|
372
|
+
rl.close();
|
|
373
|
+
console.error(`Unknown command: ${command}`);
|
|
374
|
+
displayHelp();
|
|
375
|
+
}
|