@sandrinio/vbounce 1.2.0 → 1.3.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 +3 -1
- package/bin/vbounce.mjs +42 -7
- package/brains/AGENTS.md +5 -2
- package/brains/CHANGELOG.md +7 -0
- package/brains/CLAUDE.md +5 -2
- package/brains/GEMINI.md +5 -2
- package/brains/SETUP.md +12 -0
- package/brains/claude-agents/architect.md +16 -2
- package/brains/claude-agents/developer.md +13 -3
- package/brains/claude-agents/devops.md +14 -1
- package/brains/claude-agents/qa.md +19 -2
- package/package.json +10 -3
- package/scripts/pre_bounce_sync.sh +37 -0
- package/scripts/validate_report.mjs +122 -0
- package/scripts/vbounce_ask.mjs +98 -0
- package/scripts/vbounce_index.mjs +184 -0
- package/scripts/verify_framework.mjs +105 -0
- package/scripts/verify_framework.sh +13 -0
- package/templates/hotfix.md +1 -0
- package/templates/story.md +1 -0
package/README.md
CHANGED
|
@@ -48,7 +48,9 @@ npx @sandrinio/vbounce install codex
|
|
|
48
48
|
### What gets installed?
|
|
49
49
|
- **Agent Instructions:** The "Brain" file (e.g., `CLAUDE.md`, `.cursor/rules/`) that teaches your AI how to follow the V-Bounce process.
|
|
50
50
|
- **Templates:** Markdown templates for your Charter, Roadmap, Epics, and Stories.
|
|
51
|
-
- **
|
|
51
|
+
- **Bundled Scripts:** Our validation pipeline (`validate_report.mjs`) and RAG synchronization engine (`pre_bounce_sync.sh`).
|
|
52
|
+
- **Autonomous RAG Setup:** The installer automatically runs `npm install` for required libraries and initializes your local LanceDB knowledge base (`.bounce/.lancedb/`).
|
|
53
|
+
- **vdoc Integration:** Fully compatible with [`@sandrinio/vdoc`](https://github.com/sandrinio/vdoc) to automatically construct semantic product documentation.
|
|
52
54
|
|
|
53
55
|
### 🧰 The Bundled Skills
|
|
54
56
|
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:
|
package/bin/vbounce.mjs
CHANGED
|
@@ -5,6 +5,8 @@ import path from 'path';
|
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
import readline from 'readline';
|
|
7
7
|
|
|
8
|
+
import { execSync } from 'child_process';
|
|
9
|
+
|
|
8
10
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
11
|
const __dirname = path.dirname(__filename);
|
|
10
12
|
const pkgRoot = path.join(__dirname, '..');
|
|
@@ -61,33 +63,39 @@ const platformMappings = {
|
|
|
61
63
|
{ src: 'brains/CLAUDE.md', dest: 'CLAUDE.md' },
|
|
62
64
|
{ src: 'brains/claude-agents', dest: '.claude/agents' },
|
|
63
65
|
{ src: 'templates', dest: 'templates' },
|
|
64
|
-
{ src: 'skills', dest: 'skills' }
|
|
66
|
+
{ src: 'skills', dest: 'skills' },
|
|
67
|
+
{ src: 'scripts', dest: 'scripts' }
|
|
65
68
|
],
|
|
66
69
|
cursor: [
|
|
67
70
|
{ src: 'brains/cursor-rules', dest: '.cursor/rules' },
|
|
68
71
|
{ src: 'templates', dest: 'templates' },
|
|
69
|
-
{ src: 'skills', dest: 'skills' }
|
|
72
|
+
{ src: 'skills', dest: 'skills' },
|
|
73
|
+
{ src: 'scripts', dest: 'scripts' }
|
|
70
74
|
],
|
|
71
75
|
gemini: [
|
|
72
76
|
{ src: 'brains/GEMINI.md', dest: 'GEMINI.md' },
|
|
73
77
|
{ src: 'templates', dest: 'templates' },
|
|
74
78
|
{ src: 'skills', dest: 'skills' },
|
|
75
|
-
{ src: 'skills', dest: '.agents/skills' }
|
|
79
|
+
{ src: 'skills', dest: '.agents/skills' },
|
|
80
|
+
{ src: 'scripts', dest: 'scripts' }
|
|
76
81
|
],
|
|
77
82
|
codex: [
|
|
78
83
|
{ src: 'brains/AGENTS.md', dest: 'AGENTS.md' },
|
|
79
84
|
{ src: 'templates', dest: 'templates' },
|
|
80
|
-
{ src: 'skills', dest: 'skills' }
|
|
85
|
+
{ src: 'skills', dest: 'skills' },
|
|
86
|
+
{ src: 'scripts', dest: 'scripts' }
|
|
81
87
|
],
|
|
82
88
|
vscode: [
|
|
83
89
|
{ src: 'brains/CLAUDE.md', dest: '.github/copilot-instructions.md' },
|
|
84
90
|
{ src: 'templates', dest: 'templates' },
|
|
85
|
-
{ src: 'skills', dest: 'skills' }
|
|
91
|
+
{ src: 'skills', dest: 'skills' },
|
|
92
|
+
{ src: 'scripts', dest: 'scripts' }
|
|
86
93
|
],
|
|
87
94
|
copilot: [
|
|
88
95
|
{ src: 'brains/CLAUDE.md', dest: '.github/copilot-instructions.md' },
|
|
89
96
|
{ src: 'templates', dest: 'templates' },
|
|
90
|
-
{ src: 'skills', dest: 'skills' }
|
|
97
|
+
{ src: 'skills', dest: 'skills' },
|
|
98
|
+
{ src: 'scripts', dest: 'scripts' }
|
|
91
99
|
]
|
|
92
100
|
};
|
|
93
101
|
|
|
@@ -130,7 +138,7 @@ if (toOverwrite.length > 0) {
|
|
|
130
138
|
|
|
131
139
|
console.log('');
|
|
132
140
|
|
|
133
|
-
askQuestion('Proceed with installation? [y/N] ').then(answer => {
|
|
141
|
+
askQuestion('Proceed with installation? [y/N] ').then(async answer => {
|
|
134
142
|
rl.close();
|
|
135
143
|
const confirmation = answer.trim().toLowerCase();
|
|
136
144
|
|
|
@@ -161,5 +169,32 @@ askQuestion('Proceed with installation? [y/N] ').then(answer => {
|
|
|
161
169
|
console.log(` \x1b[32m✓\x1b[0m ${rule.dest}`);
|
|
162
170
|
});
|
|
163
171
|
|
|
172
|
+
console.log('\n⚙️ Installing RAG dependencies...');
|
|
173
|
+
try {
|
|
174
|
+
const deps = [
|
|
175
|
+
'@lancedb/lancedb',
|
|
176
|
+
'@xenova/transformers',
|
|
177
|
+
'js-yaml',
|
|
178
|
+
'marked',
|
|
179
|
+
'commander'
|
|
180
|
+
];
|
|
181
|
+
console.log(` Running: npm install ${deps.join(' ')}`);
|
|
182
|
+
execSync(`npm install ${deps.join(' ')}`, { stdio: 'inherit', cwd: CWD });
|
|
183
|
+
console.log(' \x1b[32m✓\x1b[0m Dependencies installed.');
|
|
184
|
+
} catch (err) {
|
|
185
|
+
console.error(' \x1b[31m✖\x1b[0m Failed to install dependencies. You may need to run it manually.');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
console.log('\n🧠 Initializing RAG Knowledge Base...');
|
|
189
|
+
try {
|
|
190
|
+
const syncScript = path.join(CWD, 'scripts', 'pre_bounce_sync.sh');
|
|
191
|
+
if (fs.existsSync(syncScript)) {
|
|
192
|
+
execSync(`chmod +x "${syncScript}" && "${syncScript}"`, { stdio: 'inherit', cwd: CWD });
|
|
193
|
+
console.log(' \x1b[32m✓\x1b[0m Knowledge base initialized.');
|
|
194
|
+
}
|
|
195
|
+
} catch (err) {
|
|
196
|
+
console.error(' \x1b[31m✖\x1b[0m Failed to initialize knowledge base. Run ./scripts/pre_bounce_sync.sh manually.');
|
|
197
|
+
}
|
|
198
|
+
|
|
164
199
|
console.log('\n✅ V-Bounce OS successfully installed! Welcome to the team.\n');
|
|
165
200
|
});
|
package/brains/AGENTS.md
CHANGED
|
@@ -38,9 +38,10 @@ Before starting any sprint, the Team Lead MUST:
|
|
|
38
38
|
|
|
39
39
|
### Phase 2: The Bounce (Implementation)
|
|
40
40
|
**Standard Path (L2-L4 Stories):**
|
|
41
|
+
0. Team Lead runs `./scripts/pre_bounce_sync.sh` to ensure LanceDB RAG context is fresh.
|
|
41
42
|
1. Team Lead sends Story context pack to Developer.
|
|
42
|
-
2. Developer
|
|
43
|
-
3. QA runs Quick Scan + PR Review, validates against Story §2 The Truth. If fail → Bug Report to Dev.
|
|
43
|
+
2. Developer queries LanceDB, implements code, writes Implementation Report. CLI Orchestrator must run `./scripts/validate_report.mjs` on the report to enforce YAML strictness.
|
|
44
|
+
3. QA runs Quick Scan + PR Review, validates against Story §2 The Truth. If fail → Bug Report to Dev. CLI Orchestrator must run `./scripts/validate_report.mjs` on the QA report before passing to Architect/Dev.
|
|
44
45
|
4. Dev fixes and resubmits. 3+ failures → Escalated.
|
|
45
46
|
5. Architect runs Deep Audit + Trend Check, validates Safe Zone compliance and ADR adherence.
|
|
46
47
|
6. DevOps merges story branch into sprint branch, validates post-merge, handles release tagging.
|
|
@@ -92,6 +93,8 @@ Bouncing → Escalated (3+ failures)
|
|
|
92
93
|
9. Reports are the only handoff. No direct agent-to-agent communication.
|
|
93
94
|
10. One source of truth. Reference upstream documents, don't duplicate.
|
|
94
95
|
11. Change Logs are mandatory on every document modification.
|
|
96
|
+
12. Agent Reports MUST use YAML Frontmatter. Every `.bounce/report/` generated must start with a strict `---` YAML block containing the core status and metrics before the Markdown body.
|
|
97
|
+
13. Framework Integrity. Any modification to a `brains/` or `skills/` file MUST be recorded in `brains/CHANGELOG.md` and trigger `./scripts/pre_bounce_sync.sh`.
|
|
95
98
|
|
|
96
99
|
## Framework Structure
|
|
97
100
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# V-Bounce OS Brains & Skills Changelog
|
|
2
|
+
|
|
3
|
+
This log tracks modifications to the core agentic framework (e.g., `brains/`, `skills/`).
|
|
4
|
+
Per **Rule 13: Framework Integrity**, anytime an entry is made here, the orchestrator MUST trigger `./scripts/pre_bounce_sync.sh` to update the RAG embeddings globally.
|
|
5
|
+
|
|
6
|
+
## [2026-03-02]
|
|
7
|
+
- **Initialized**: Created strict Framework Integrity tracking, YAML context handoffs, and RAG validation pipeline.
|
package/brains/CLAUDE.md
CHANGED
|
@@ -50,9 +50,10 @@ Before starting any sprint, the Team Lead MUST:
|
|
|
50
50
|
|
|
51
51
|
### Phase 2: The Bounce (Implementation)
|
|
52
52
|
**Standard Path (L2-L4 Stories):**
|
|
53
|
+
0. Team Lead runs `./scripts/pre_bounce_sync.sh` to ensure LanceDB RAG context is fresh.
|
|
53
54
|
1. Team Lead sends Story context pack to Developer.
|
|
54
|
-
2. Developer
|
|
55
|
-
3. QA runs Quick Scan + PR Review, validates against Story §2 The Truth. If fail → Bug Report to Dev.
|
|
55
|
+
2. Developer queries LanceDB, implements code, writes Implementation Report. CLI Orchestrator must run `./scripts/validate_report.mjs` on the report to enforce YAML strictness.
|
|
56
|
+
3. QA runs Quick Scan + PR Review, validates against Story §2 The Truth. If fail → Bug Report to Dev. CLI Orchestrator must run `./scripts/validate_report.mjs` on the QA report before passing to Architect/Dev.
|
|
56
57
|
4. Dev fixes and resubmits. 3+ failures → Escalated.
|
|
57
58
|
5. Architect runs Deep Audit + Trend Check, validates Safe Zone compliance and ADR adherence.
|
|
58
59
|
6. DevOps merges story branch into sprint branch, validates post-merge, handles release tagging.
|
|
@@ -106,6 +107,8 @@ Draft → Refinement → Ready to Bounce → Bouncing → QA Passed → Architec
|
|
|
106
107
|
9. **Reports are the only handoff**. No direct agent-to-agent communication.
|
|
107
108
|
10. **One source of truth**. Reference upstream documents, don't duplicate.
|
|
108
109
|
11. **Change Logs are mandatory** on every document modification.
|
|
110
|
+
12. **Agent Reports MUST use YAML Frontmatter**. Every `.bounce/report/` generated must start with a strict `---` YAML block containing the core status and metrics before the Markdown body.
|
|
111
|
+
13. **Framework Integrity**. Any modification to a `brains/` or `skills/` file MUST be recorded in `brains/CHANGELOG.md` and trigger `./scripts/pre_bounce_sync.sh`.
|
|
109
112
|
|
|
110
113
|
## Framework Structure
|
|
111
114
|
|
package/brains/GEMINI.md
CHANGED
|
@@ -41,9 +41,10 @@ Before starting any sprint, the Team Lead MUST:
|
|
|
41
41
|
|
|
42
42
|
### Phase 2: The Bounce (Implementation)
|
|
43
43
|
**Standard Path (L2-L4 Stories):**
|
|
44
|
+
0. Team Lead runs `./scripts/pre_bounce_sync.sh` to ensure LanceDB RAG context is fresh.
|
|
44
45
|
1. Team Lead sends Story context pack to Developer.
|
|
45
|
-
2. Developer
|
|
46
|
-
3. QA runs Quick Scan + PR Review, validates against Story §2 The Truth. If fail → Bug Report to Dev.
|
|
46
|
+
2. Developer queries LanceDB, implements code, writes Implementation Report. CLI Orchestrator must run `./scripts/validate_report.mjs` on the report to enforce YAML strictness.
|
|
47
|
+
3. QA runs Quick Scan + PR Review, validates against Story §2 The Truth. If fail → Bug Report to Dev. CLI Orchestrator must run `./scripts/validate_report.mjs` on the QA report before passing to Architect/Dev.
|
|
47
48
|
4. Dev fixes and resubmits. 3+ failures → Escalated.
|
|
48
49
|
5. Architect runs Deep Audit + Trend Check, validates Safe Zone compliance and ADR adherence.
|
|
49
50
|
6. DevOps merges story branch into sprint branch, validates post-merge, handles release tagging.
|
|
@@ -97,6 +98,8 @@ Draft → Refinement → Ready to Bounce → Bouncing → QA Passed → Architec
|
|
|
97
98
|
9. **Reports are the only handoff**. No direct agent-to-agent communication.
|
|
98
99
|
10. **One source of truth**. Reference upstream documents, don't duplicate.
|
|
99
100
|
11. **Change Logs are mandatory** on every document modification.
|
|
101
|
+
12. **Agent Reports MUST use YAML Frontmatter**. Every `.bounce/report/` generated must start with a strict `---` YAML block containing the core status and metrics before the Markdown body.
|
|
102
|
+
13. **Framework Integrity**. Any modification to a `brains/` or `skills/` file MUST be recorded in `brains/CHANGELOG.md` and trigger `./scripts/pre_bounce_sync.sh`.
|
|
100
103
|
|
|
101
104
|
## Framework Structure
|
|
102
105
|
|
package/brains/SETUP.md
CHANGED
|
@@ -5,6 +5,7 @@ Step-by-step guide to set up V-Bounce OS in an existing or new project.
|
|
|
5
5
|
## Prerequisites
|
|
6
6
|
|
|
7
7
|
- A git repository (V-Bounce OS uses branches and worktrees)
|
|
8
|
+
- Node.js installed (for validation and semantic search scripts)
|
|
8
9
|
- At least one supported AI coding tool installed
|
|
9
10
|
- The V-Bounce OS folder (this repo)
|
|
10
11
|
|
|
@@ -116,6 +117,17 @@ The agent will:
|
|
|
116
117
|
4. Merge completed stories
|
|
117
118
|
5. Generate a Sprint Report for your review
|
|
118
119
|
|
|
120
|
+
## Step 7: Automated RAG Initialization
|
|
121
|
+
|
|
122
|
+
V-Bounce OS uses LanceDB to provide agents with targeted context. While the `npx @sandrinio/vbounce install` command handles this automatically, you can manually re-trigger a sync if you add new architectural rules or change your brains:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Re-build your local knowledge base
|
|
126
|
+
./scripts/pre_bounce_sync.sh
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
This updates your local embeddings in `.bounce/.lancedb/`. Agents use `./scripts/vbounce_ask.mjs` to fetch rules on demand, ensuring they are always aligned with your latest Roadmap and Lessons.
|
|
130
|
+
|
|
119
131
|
## Folder Structure After Setup
|
|
120
132
|
|
|
121
133
|
```
|
|
@@ -14,7 +14,7 @@ Audit the codebase for structural integrity, standards compliance, and long-term
|
|
|
14
14
|
|
|
15
15
|
## Before Auditing
|
|
16
16
|
|
|
17
|
-
1. **
|
|
17
|
+
1. **Query Project Lessons**: Run `./scripts/vbounce_ask.mjs "architectural constraints and historical mistakes for <story summary>"` to retrieve relevant context from `LESSONS.md` and past reports.
|
|
18
18
|
2. **Read all reports** for this story (`.bounce/reports/STORY-{ID}-*.md`) — Dev Report, QA Report.
|
|
19
19
|
3. **Read the full Story spec** — especially §3 Implementation Guide and §3.1 ADR References.
|
|
20
20
|
4. **Read Roadmap §3 ADRs** — every architecture decision the implementation must comply with.
|
|
@@ -65,10 +65,18 @@ Check that the changes don't break existing functionality:
|
|
|
65
65
|
|
|
66
66
|
## Your Output
|
|
67
67
|
|
|
68
|
-
Write an **Architectural Audit Report** to `.bounce/reports/STORY-{ID}-arch.md
|
|
68
|
+
Write an **Architectural Audit Report** to `.bounce/reports/STORY-{ID}-arch.md`.
|
|
69
|
+
You MUST include the YAML frontmatter block exactly as shown below:
|
|
69
70
|
|
|
70
71
|
### If Audit PASSES:
|
|
71
72
|
```markdown
|
|
73
|
+
---
|
|
74
|
+
status: "PASS"
|
|
75
|
+
safe_zone_score: {SCORE}
|
|
76
|
+
ai_isms_detected: {count}
|
|
77
|
+
regression_risk: "{Low/Medium/High}"
|
|
78
|
+
---
|
|
79
|
+
|
|
72
80
|
# Architectural Audit Report: STORY-{ID} — PASS
|
|
73
81
|
|
|
74
82
|
## Safe Zone Compliance: {SCORE}/10
|
|
@@ -108,6 +116,12 @@ PASS — Ready for Sprint Review.
|
|
|
108
116
|
|
|
109
117
|
### If Audit FAILS:
|
|
110
118
|
```markdown
|
|
119
|
+
---
|
|
120
|
+
status: "FAIL"
|
|
121
|
+
bounce_count: {N}
|
|
122
|
+
critical_failures: {count}
|
|
123
|
+
---
|
|
124
|
+
|
|
111
125
|
# Architectural Audit Report: STORY-{ID} — FAIL
|
|
112
126
|
|
|
113
127
|
## Critical Failures
|
|
@@ -12,8 +12,9 @@ Implement features and fix bugs as specified in Story documents. You write code
|
|
|
12
12
|
|
|
13
13
|
## Before Writing ANY Code
|
|
14
14
|
|
|
15
|
-
1. **
|
|
16
|
-
2. **
|
|
15
|
+
1. **Query Project Lessons**: Run `./scripts/vbounce_ask.mjs "<summarize your specific coding task here>"` to retrieve relevant constraints and gotchas from `LESSONS.md` and historical reports. Treat these as hard constraints. No exceptions.
|
|
16
|
+
2. **Query Architectural Decisions**: If your task involves core systems (auth, db, state), run `./scripts/vbounce_ask.mjs "<system> decisions"` to get relevant ADRs from the Roadmap.
|
|
17
|
+
3. **Read the Story spec** — §1 The Spec for requirements, §3 Implementation Guide for technical approach.
|
|
17
18
|
3. **Check ADR references** in §3.1 — comply with all architecture decisions from the Roadmap.
|
|
18
19
|
4. **Read relevant react-best-practices rules** — consult `skills/react-best-practices/` for patterns matching your task.
|
|
19
20
|
5. **Check product documentation** — if the task file references product docs from `product_documentation/`, read them. Understand how the existing feature works before changing adjacent code. If your implementation changes behavior described in a product doc, flag it in your report.
|
|
@@ -33,9 +34,18 @@ Do NOT proceed with a broken spec. Instead:
|
|
|
33
34
|
|
|
34
35
|
## Your Output
|
|
35
36
|
|
|
36
|
-
Write a **Developer Implementation Report** to `.bounce/reports/STORY-{ID}-dev.md
|
|
37
|
+
Write a **Developer Implementation Report** to `.bounce/reports/STORY-{ID}-dev.md`.
|
|
38
|
+
You MUST include the YAML frontmatter block exactly as shown below:
|
|
37
39
|
|
|
38
40
|
```markdown
|
|
41
|
+
---
|
|
42
|
+
status: "implemented"
|
|
43
|
+
correction_tax: {X}
|
|
44
|
+
files_modified:
|
|
45
|
+
- "path/to/file.ts"
|
|
46
|
+
lessons_flagged: {number of lessons}
|
|
47
|
+
---
|
|
48
|
+
|
|
39
49
|
# Developer Implementation Report: STORY-{ID}
|
|
40
50
|
|
|
41
51
|
## Files Modified
|
|
@@ -146,10 +146,17 @@ Before approving a deployment:
|
|
|
146
146
|
|
|
147
147
|
## Your Output
|
|
148
148
|
|
|
149
|
-
Write a **DevOps Report** to `.bounce/reports/STORY-{ID}-devops.md` (for story merges) or `.bounce/reports/sprint-S-{XX}-devops.md` (for sprint releases)
|
|
149
|
+
Write a **DevOps Report** to `.bounce/reports/STORY-{ID}-devops.md` (for story merges) or `.bounce/reports/sprint-S-{XX}-devops.md` (for sprint releases).
|
|
150
|
+
You MUST include the YAML frontmatter block exactly as shown below:
|
|
150
151
|
|
|
151
152
|
### Story Merge Report
|
|
152
153
|
```markdown
|
|
154
|
+
---
|
|
155
|
+
type: "story-merge"
|
|
156
|
+
status: "{Clean / Conflicts Resolved / Failed}"
|
|
157
|
+
conflicts_detected: {true/false}
|
|
158
|
+
---
|
|
159
|
+
|
|
153
160
|
# DevOps Report: STORY-{ID} Merge
|
|
154
161
|
|
|
155
162
|
## Pre-Merge Checks
|
|
@@ -178,6 +185,12 @@ Write a **DevOps Report** to `.bounce/reports/STORY-{ID}-devops.md` (for story m
|
|
|
178
185
|
|
|
179
186
|
### Sprint Release Report
|
|
180
187
|
```markdown
|
|
188
|
+
---
|
|
189
|
+
type: "sprint-release"
|
|
190
|
+
status: "{Deployed / Pending / Manual}"
|
|
191
|
+
version: "{VERSION}"
|
|
192
|
+
---
|
|
193
|
+
|
|
181
194
|
# DevOps Report: Sprint S-{XX} Release
|
|
182
195
|
|
|
183
196
|
## Pre-Release Checks
|
|
@@ -12,7 +12,7 @@ Validate that the Developer's implementation meets the Story's acceptance criter
|
|
|
12
12
|
|
|
13
13
|
## Before Testing
|
|
14
14
|
|
|
15
|
-
1. **
|
|
15
|
+
1. **Query Project Lessons**: Run `./scripts/vbounce_ask.mjs "<summarize the story spec here>"` to retrieve known failure patterns relevant to this story from `LESSONS.md` and past reports.
|
|
16
16
|
2. **Read the Developer Implementation Report** (`.bounce/reports/STORY-{ID}-dev.md`) to understand what was built.
|
|
17
17
|
3. **Read Story §2 The Truth** — these are your pass/fail criteria. If the Gherkin scenarios don't pass, the bounce failed.
|
|
18
18
|
|
|
@@ -58,10 +58,18 @@ Check for unnecessary complexity the Developer added beyond the Story spec:
|
|
|
58
58
|
|
|
59
59
|
## Your Output
|
|
60
60
|
|
|
61
|
-
Write a **QA Validation Report** to `.bounce/reports/STORY-{ID}-qa.md
|
|
61
|
+
Write a **QA Validation Report** to `.bounce/reports/STORY-{ID}-qa.md`.
|
|
62
|
+
You MUST include the YAML frontmatter block exactly as shown below:
|
|
62
63
|
|
|
63
64
|
### If Tests PASS:
|
|
64
65
|
```markdown
|
|
66
|
+
---
|
|
67
|
+
status: "PASS"
|
|
68
|
+
bounce_count: {N}
|
|
69
|
+
bugs_found: 0
|
|
70
|
+
gold_plating_detected: false
|
|
71
|
+
---
|
|
72
|
+
|
|
65
73
|
# QA Validation Report: STORY-{ID} — PASS
|
|
66
74
|
|
|
67
75
|
## Quick Scan Results
|
|
@@ -98,6 +106,15 @@ PASS — Ready for Architect review.
|
|
|
98
106
|
|
|
99
107
|
### If Tests FAIL:
|
|
100
108
|
```markdown
|
|
109
|
+
---
|
|
110
|
+
status: "FAIL"
|
|
111
|
+
bounce_count: {N}
|
|
112
|
+
bugs_found: {number of bugs}
|
|
113
|
+
gold_plating_detected: {true/false}
|
|
114
|
+
failed_scenarios:
|
|
115
|
+
- "{scenario name}"
|
|
116
|
+
---
|
|
117
|
+
|
|
101
118
|
# QA Validation Report: STORY-{ID} — FAIL (Bounce {N})
|
|
102
119
|
|
|
103
120
|
## Failures
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sandrinio/vbounce",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "V-Bounce OS: Turn your AI coding assistant into a full engineering team through structured SDLC skills.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -38,5 +38,12 @@
|
|
|
38
38
|
"skills",
|
|
39
39
|
"scripts",
|
|
40
40
|
"docs"
|
|
41
|
-
]
|
|
42
|
-
|
|
41
|
+
],
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@lancedb/lancedb": "^0.26.2",
|
|
44
|
+
"@xenova/transformers": "^2.17.2",
|
|
45
|
+
"commander": "^14.0.3",
|
|
46
|
+
"js-yaml": "^4.1.1",
|
|
47
|
+
"marked": "^17.0.3"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# pre_bounce_sync.sh
|
|
4
|
+
#
|
|
5
|
+
# Run this before kicking off the Implementation Loop (Bounce).
|
|
6
|
+
# This prevents the "Stale Context" edge case by forcing the LanceDB
|
|
7
|
+
# index to refresh with the latest rules from LESSONS.md and ROADMAP.md.
|
|
8
|
+
|
|
9
|
+
echo "==========================================="
|
|
10
|
+
echo " V-Bounce OS: Pre-Bounce Sync Started"
|
|
11
|
+
echo "==========================================="
|
|
12
|
+
|
|
13
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd)"
|
|
14
|
+
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
15
|
+
|
|
16
|
+
cd "$ROOT_DIR" || exit 1
|
|
17
|
+
|
|
18
|
+
# 1. Check for Node Modules
|
|
19
|
+
if [ ! -d "node_modules" ]; then
|
|
20
|
+
echo "Error: node_modules not found. Run 'npm install'."
|
|
21
|
+
exit 1
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
# 2. Rebuild the semantic search index
|
|
25
|
+
echo "Syncing V-Bounce Knowledge Base (LanceDB)..."
|
|
26
|
+
node ./scripts/vbounce_index.mjs --all
|
|
27
|
+
|
|
28
|
+
if [ $? -ne 0 ]; then
|
|
29
|
+
echo "Error: LanceDB index sync failed."
|
|
30
|
+
exit 1
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
echo "==========================================="
|
|
34
|
+
echo " Pre-Bounce Sync Complete. RAG is fresh."
|
|
35
|
+
echo " Ready for Team Lead delegation."
|
|
36
|
+
echo "==========================================="
|
|
37
|
+
exit 0
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* validate_report.mjs
|
|
5
|
+
*
|
|
6
|
+
* Strict YAML Frontmatter validation for V-Bounce OS Agent Reports.
|
|
7
|
+
* Fails loudly if an agent hallucinates formatting or omits required fields,
|
|
8
|
+
* so the orchestrator can bounce the prompt back.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import fs from 'fs';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import yaml from 'js-yaml';
|
|
14
|
+
|
|
15
|
+
// Defined schemas for each report type
|
|
16
|
+
const SCHEMAS = {
|
|
17
|
+
dev: ['status', 'correction_tax', 'files_modified', 'lessons_flagged'],
|
|
18
|
+
qa: {
|
|
19
|
+
base: ['status', 'bounce_count', 'bugs_found', 'gold_plating_detected'],
|
|
20
|
+
conditional: { 'FAIL': ['failed_scenarios'] }
|
|
21
|
+
},
|
|
22
|
+
arch: {
|
|
23
|
+
base: ['status'],
|
|
24
|
+
conditional: { 'PASS': ['safe_zone_score', 'ai_isms_detected', 'regression_risk'], 'FAIL': ['bounce_count', 'critical_failures'] }
|
|
25
|
+
},
|
|
26
|
+
devops: {
|
|
27
|
+
base: ['type', 'status'],
|
|
28
|
+
conditional: { 'story-merge': ['conflicts_detected'], 'sprint-release': ['version'] }
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function extractFrontmatter(content) {
|
|
33
|
+
// Matches "---" at the start of the file or after whitespace
|
|
34
|
+
const match = content.match(/^---\s*[\r\n]+([\s\S]*?)[\r\n]+---\s*/);
|
|
35
|
+
if (!match) {
|
|
36
|
+
throw new Error('NO_FRONTMATTER: Report missing strict YAML --- delimiters at the top of the file.');
|
|
37
|
+
}
|
|
38
|
+
return match[1];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function validateDev(data) {
|
|
42
|
+
const missing = SCHEMAS.dev.filter(k => !(k in data));
|
|
43
|
+
if (missing.length > 0) throw new Error(`DEV_SCHEMA_ERROR: Missing required keys: ${missing.join(', ')}`);
|
|
44
|
+
if (!Array.isArray(data.files_modified)) throw new Error(`DEV_SCHEMA_ERROR: 'files_modified' must be an array.`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function validateQA(data) {
|
|
48
|
+
const missing = SCHEMAS.qa.base.filter(k => !(k in data));
|
|
49
|
+
if (missing.length > 0) throw new Error(`QA_SCHEMA_ERROR: Missing required keys: ${missing.join(', ')}`);
|
|
50
|
+
|
|
51
|
+
if (data.status === 'FAIL') {
|
|
52
|
+
const conditionalMissing = SCHEMAS.qa.conditional.FAIL.filter(k => !(k in data));
|
|
53
|
+
if (conditionalMissing.length > 0) throw new Error(`QA_SCHEMA_ERROR: 'FAIL' status requires keys: ${conditionalMissing.join(', ')}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function validateArch(data) {
|
|
58
|
+
const missing = SCHEMAS.arch.base.filter(k => !(k in data));
|
|
59
|
+
if (missing.length > 0) throw new Error(`ARCH_SCHEMA_ERROR: Missing required keys: ${missing.join(', ')}`);
|
|
60
|
+
|
|
61
|
+
const s = data.status === 'PASS' ? 'PASS' : 'FAIL';
|
|
62
|
+
const conditionalMissing = SCHEMAS.arch.conditional[s].filter(k => !(k in data));
|
|
63
|
+
if (conditionalMissing.length > 0) throw new Error(`ARCH_SCHEMA_ERROR: '${s}' status requires keys: ${conditionalMissing.join(', ')}`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function validateDevops(data) {
|
|
67
|
+
const missing = SCHEMAS.devops.base.filter(k => !(k in data));
|
|
68
|
+
if (missing.length > 0) throw new Error(`DEVOPS_SCHEMA_ERROR: Missing required keys: ${missing.join(', ')}`);
|
|
69
|
+
|
|
70
|
+
const typeStr = String(data.type);
|
|
71
|
+
if (SCHEMAS.devops.conditional[typeStr]) {
|
|
72
|
+
const conditionalMissing = SCHEMAS.devops.conditional[typeStr].filter(k => !(k in data));
|
|
73
|
+
if (conditionalMissing.length > 0) throw new Error(`DEVOPS_SCHEMA_ERROR: '${typeStr}' type requires keys: ${conditionalMissing.join(', ')}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function main() {
|
|
78
|
+
const filePath = process.argv[2];
|
|
79
|
+
if (!filePath) {
|
|
80
|
+
console.error("Usage: validate_report.mjs <path-to-markdown-file>");
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const filename = path.basename(filePath);
|
|
85
|
+
|
|
86
|
+
// Infer agent type from filename convention
|
|
87
|
+
let agentType = 'unknown';
|
|
88
|
+
if (filename.endsWith('-dev.md')) agentType = 'dev';
|
|
89
|
+
else if (filename.endsWith('-qa.md')) agentType = 'qa';
|
|
90
|
+
else if (filename.endsWith('-arch.md')) agentType = 'arch';
|
|
91
|
+
else if (filename.endsWith('-devops.md')) agentType = 'devops';
|
|
92
|
+
|
|
93
|
+
if (agentType === 'unknown') {
|
|
94
|
+
console.error(`WARNING: Unrecognized report type for ${filename}. Ensure filename ends in -dev.md, -qa.md, -arch.md, or -devops.md.`);
|
|
95
|
+
process.exit(0); // Soft pass, not an agent workflow report
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const rawContent = fs.readFileSync(filePath, 'utf8');
|
|
100
|
+
const yamlString = extractFrontmatter(rawContent);
|
|
101
|
+
const data = yaml.load(yamlString);
|
|
102
|
+
|
|
103
|
+
if (!data || typeof data !== 'object') {
|
|
104
|
+
throw new Error("YAML_PARSE_ERROR: Frontmatter parsed to an empty or invalid object.");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (agentType === 'dev') validateDev(data);
|
|
108
|
+
if (agentType === 'qa') validateQA(data);
|
|
109
|
+
if (agentType === 'arch') validateArch(data);
|
|
110
|
+
if (agentType === 'devops') validateDevops(data);
|
|
111
|
+
|
|
112
|
+
console.log(`VALID: ${filename} matches the ${agentType.toUpperCase()} schema.`);
|
|
113
|
+
process.exit(0);
|
|
114
|
+
|
|
115
|
+
} catch (error) {
|
|
116
|
+
// We print specifically to stdout so automation scripts can capture the payload and bounce it back to the AI
|
|
117
|
+
console.log(`VALIDATION_FAILED\n${error.message}`);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
main();
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { connect } from '@lancedb/lancedb';
|
|
6
|
+
import { pipeline } from '@xenova/transformers';
|
|
7
|
+
import { program } from 'commander';
|
|
8
|
+
|
|
9
|
+
const LANCE_DIR = path.join(process.cwd(), '.bounce', '.lancedb');
|
|
10
|
+
|
|
11
|
+
program
|
|
12
|
+
.name('vbounce_ask')
|
|
13
|
+
.description('Query V-Bounce OS LanceDB for relevant context')
|
|
14
|
+
.argument('<query>', 'The semantic query to search for')
|
|
15
|
+
.option('-f, --filter <field=value>', 'Filter by metadata (e.g., type=lesson)')
|
|
16
|
+
.option('-l, --limit <number>', 'Number of results to return', 3)
|
|
17
|
+
.parse(process.argv);
|
|
18
|
+
|
|
19
|
+
const options = program.opts();
|
|
20
|
+
const query = program.args[0];
|
|
21
|
+
|
|
22
|
+
class LocalEmbeddingFunction {
|
|
23
|
+
constructor() {
|
|
24
|
+
this.modelName = 'Xenova/all-MiniLM-L6-v2';
|
|
25
|
+
this.extractor = null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async init() {
|
|
29
|
+
if (!this.extractor) {
|
|
30
|
+
this.extractor = await pipeline('feature-extraction', this.modelName, {
|
|
31
|
+
quantized: true,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async embedQuery(text) {
|
|
37
|
+
await this.init();
|
|
38
|
+
const output = await this.extractor(text, { pooling: 'mean', normalize: true });
|
|
39
|
+
return Array.from(output.data);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function main() {
|
|
44
|
+
if (!query) {
|
|
45
|
+
console.error("Error: Must provide a semantic query string.");
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!fs.existsSync(LANCE_DIR)) {
|
|
50
|
+
console.error(`Error: LanceDB not found at ${LANCE_DIR}. Have you run vbounce_index yet?`);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const db = await connect(LANCE_DIR);
|
|
55
|
+
let table;
|
|
56
|
+
try {
|
|
57
|
+
table = await db.openTable('vbounce_context');
|
|
58
|
+
} catch (e) {
|
|
59
|
+
console.error("Error: Table 'vbounce_context' not found. Please index documents first.");
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const embedder = new LocalEmbeddingFunction();
|
|
64
|
+
const queryVector = await embedder.embedQuery(query);
|
|
65
|
+
|
|
66
|
+
let search = table.vectorSearch(queryVector).limit(parseInt(options.limit));
|
|
67
|
+
|
|
68
|
+
if (options.filter) {
|
|
69
|
+
const [field, value] = options.filter.split('=');
|
|
70
|
+
// LanceDB JS uses SQL-like string criteria for filtering
|
|
71
|
+
if (field === "type") {
|
|
72
|
+
search = search.where(`\`type\` = '${value}'`);
|
|
73
|
+
} else if (field === "section") {
|
|
74
|
+
search = search.where(`\`section\` = '${value}'`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const results = await search.toArray();
|
|
79
|
+
|
|
80
|
+
if (results.length === 0) {
|
|
81
|
+
console.log("No relevant context found.");
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
console.log(`\n--- V-Bounce Semantic Retrieval ---`);
|
|
86
|
+
console.log(`Query: "${query}"`);
|
|
87
|
+
console.log(`Found ${results.length} relevant chunks.\n`);
|
|
88
|
+
|
|
89
|
+
results.forEach((r, idx) => {
|
|
90
|
+
console.log(`[Result ${idx + 1}] Source: ${r.file} (${r.type || 'unknown'} > ${r.section || 'General'})`);
|
|
91
|
+
console.log(`Distance: ${r._distance ? r._distance.toFixed(4) : 'N/A'}`);
|
|
92
|
+
console.log('-'.repeat(40));
|
|
93
|
+
console.log(r.text.trim());
|
|
94
|
+
console.log('\n');
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { connect } from '@lancedb/lancedb';
|
|
6
|
+
import { pipeline } from '@xenova/transformers';
|
|
7
|
+
import { marked } from 'marked';
|
|
8
|
+
import { program } from 'commander';
|
|
9
|
+
|
|
10
|
+
const LANCE_DIR = path.join(process.cwd(), '.bounce', '.lancedb');
|
|
11
|
+
|
|
12
|
+
program
|
|
13
|
+
.name('vbounce_index')
|
|
14
|
+
.description('Index V-Bounce OS documents into local LanceDB')
|
|
15
|
+
.argument('[path]', 'File or directory path to index (or use --all)')
|
|
16
|
+
.option('--all', 'Index all standard V-Bounce directories')
|
|
17
|
+
.parse(process.argv);
|
|
18
|
+
|
|
19
|
+
const options = program.opts();
|
|
20
|
+
const targetPath = program.args[0];
|
|
21
|
+
|
|
22
|
+
// Initialize local embedding model wrapper
|
|
23
|
+
class LocalEmbeddingFunction {
|
|
24
|
+
constructor() {
|
|
25
|
+
this.modelName = 'Xenova/all-MiniLM-L6-v2';
|
|
26
|
+
this.extractor = null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async init() {
|
|
30
|
+
if (!this.extractor) {
|
|
31
|
+
console.log(`Loading embedding model (${this.modelName})...`);
|
|
32
|
+
this.extractor = await pipeline('feature-extraction', this.modelName, {
|
|
33
|
+
quantized: true,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async computeSourceEmbeddings(texts) {
|
|
39
|
+
await this.init();
|
|
40
|
+
const embeddings = [];
|
|
41
|
+
for (const text of texts) {
|
|
42
|
+
const output = await this.extractor(text, { pooling: 'mean', normalize: true });
|
|
43
|
+
embeddings.push(Array.from(output.data));
|
|
44
|
+
}
|
|
45
|
+
return embeddings;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Function to chunk Markdown files semantically (simplified for MVP)
|
|
50
|
+
function chunkMarkdown(content, metadata) {
|
|
51
|
+
const tokens = marked.lexer(content);
|
|
52
|
+
const chunks = [];
|
|
53
|
+
let currentHeader = 'General';
|
|
54
|
+
let buffer = '';
|
|
55
|
+
|
|
56
|
+
for (const token of tokens) {
|
|
57
|
+
if (token.type === 'heading') {
|
|
58
|
+
if (buffer.trim()) {
|
|
59
|
+
chunks.push({ text: buffer.trim(), section: currentHeader, ...metadata });
|
|
60
|
+
}
|
|
61
|
+
currentHeader = token.text;
|
|
62
|
+
buffer = `${token.raw}\n`;
|
|
63
|
+
} else {
|
|
64
|
+
buffer += `${token.raw}\n`;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (buffer.trim()) {
|
|
69
|
+
chunks.push({ text: buffer.trim(), section: currentHeader, ...metadata });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return chunks;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function indexFile(filePath, embedder) {
|
|
76
|
+
console.log(`Processing file: ${filePath}`);
|
|
77
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
78
|
+
const basename = path.basename(filePath);
|
|
79
|
+
|
|
80
|
+
let type = 'unknown';
|
|
81
|
+
if (filePath.includes('LESSONS.md')) type = 'lesson';
|
|
82
|
+
else if (filePath.includes('ROADMAP.md')) type = 'adr';
|
|
83
|
+
else if (filePath.includes('.bounce/reports')) type = 'report';
|
|
84
|
+
else if (filePath.includes('product_plans')) type = 'plan';
|
|
85
|
+
else if (filePath.includes('product_documentation')) type = 'documentation';
|
|
86
|
+
|
|
87
|
+
const metadata = { file: basename, type };
|
|
88
|
+
const chunks = chunkMarkdown(content, metadata);
|
|
89
|
+
|
|
90
|
+
if (chunks.length === 0) return [];
|
|
91
|
+
|
|
92
|
+
console.log(` Extracted ${chunks.length} chunks. Generating embeddings...`);
|
|
93
|
+
|
|
94
|
+
const textsToEmbed = chunks.map(c => `[${c.type} - ${c.file} - ${c.section}]\n${c.text}`);
|
|
95
|
+
const vectors = await embedder.computeSourceEmbeddings(textsToEmbed);
|
|
96
|
+
|
|
97
|
+
return chunks.map((chunk, i) => ({
|
|
98
|
+
id: `${chunk.file}-${i}`,
|
|
99
|
+
file: chunk.file,
|
|
100
|
+
type: chunk.type,
|
|
101
|
+
section: chunk.section,
|
|
102
|
+
text: chunk.text,
|
|
103
|
+
vector: vectors[i]
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function main() {
|
|
108
|
+
if (!targetPath && !options.all) {
|
|
109
|
+
console.error("Error: Must specify a path or use --all");
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const embedder = new LocalEmbeddingFunction();
|
|
114
|
+
|
|
115
|
+
// Ensure table exists
|
|
116
|
+
if (!fs.existsSync(LANCE_DIR)) {
|
|
117
|
+
fs.mkdirSync(LANCE_DIR, { recursive: true });
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const db = await connect(LANCE_DIR);
|
|
121
|
+
let table;
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
table = await db.openTable('vbounce_context');
|
|
125
|
+
} catch (e) {
|
|
126
|
+
// Table doesn't exist, will create dynamically on first insert
|
|
127
|
+
console.log("Creating new vbounce_context table...");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const filesToIndex = [];
|
|
131
|
+
|
|
132
|
+
function walkDir(dir) {
|
|
133
|
+
if (!fs.existsSync(dir)) return;
|
|
134
|
+
const files = fs.readdirSync(dir);
|
|
135
|
+
for (const file of files) {
|
|
136
|
+
const fullPath = path.join(dir, file);
|
|
137
|
+
const stat = fs.statSync(fullPath);
|
|
138
|
+
if (stat.isDirectory()) {
|
|
139
|
+
walkDir(fullPath);
|
|
140
|
+
} else if (fullPath.endsWith('.md')) {
|
|
141
|
+
filesToIndex.push(fullPath);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (options.all) {
|
|
147
|
+
if (fs.existsSync('LESSONS.md')) filesToIndex.push('LESSONS.md');
|
|
148
|
+
if (fs.existsSync('ROADMAP.md')) filesToIndex.push('ROADMAP.md');
|
|
149
|
+
walkDir('product_plans');
|
|
150
|
+
walkDir('product_documentation');
|
|
151
|
+
walkDir('.bounce/reports');
|
|
152
|
+
} else if (targetPath) {
|
|
153
|
+
const stat = fs.statSync(targetPath);
|
|
154
|
+
if (stat.isFile()) {
|
|
155
|
+
filesToIndex.push(targetPath);
|
|
156
|
+
} else if (stat.isDirectory()) {
|
|
157
|
+
walkDir(targetPath);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (filesToIndex.length === 0) {
|
|
162
|
+
console.log("No files found to index.");
|
|
163
|
+
process.exit(0);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
let allRecords = [];
|
|
167
|
+
for (const file of filesToIndex) {
|
|
168
|
+
const records = await indexFile(file, embedder);
|
|
169
|
+
allRecords = allRecords.concat(records);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (allRecords.length > 0) {
|
|
173
|
+
if (table) {
|
|
174
|
+
console.log(`Adding ${allRecords.length} records to existing table...`);
|
|
175
|
+
await table.add(allRecords);
|
|
176
|
+
} else {
|
|
177
|
+
console.log(`Creating table with ${allRecords.length} records...`);
|
|
178
|
+
table = await db.createTable('vbounce_context', allRecords);
|
|
179
|
+
}
|
|
180
|
+
console.log(`Successfully indexed into LanceDB.`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* verify_framework.mjs
|
|
5
|
+
*
|
|
6
|
+
* Tests the backward-compatibility of the AI agent prompts against
|
|
7
|
+
* the strict YAML parsing schemas in validate_report.mjs.
|
|
8
|
+
*
|
|
9
|
+
* Triggered manually by humans or automatically by CI when updating brains/.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import fs from 'fs';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
|
|
15
|
+
const AGENTS_DIR = path.join(process.cwd(), 'brains', 'claude-agents');
|
|
16
|
+
|
|
17
|
+
// The exact substring signatures that MUST exist in the agent instructions
|
|
18
|
+
// to ensure the LLM knows to output the correct YAML schema.
|
|
19
|
+
const EXPECTED_PROMPT_SIGNATURES = {
|
|
20
|
+
'developer.md': [
|
|
21
|
+
'status:',
|
|
22
|
+
'correction_tax:',
|
|
23
|
+
'files_modified:',
|
|
24
|
+
'lessons_flagged:'
|
|
25
|
+
],
|
|
26
|
+
'qa.md': [
|
|
27
|
+
'status: "PASS"',
|
|
28
|
+
'bugs_found: 0',
|
|
29
|
+
'status: "FAIL"',
|
|
30
|
+
'failed_scenarios:'
|
|
31
|
+
],
|
|
32
|
+
'architect.md': [
|
|
33
|
+
'status: "PASS"',
|
|
34
|
+
'safe_zone_score:',
|
|
35
|
+
'regression_risk:',
|
|
36
|
+
'status: "FAIL"',
|
|
37
|
+
'critical_failures:'
|
|
38
|
+
],
|
|
39
|
+
'devops.md': [
|
|
40
|
+
'type: "story-merge"',
|
|
41
|
+
'conflicts_detected:',
|
|
42
|
+
'type: "sprint-release"',
|
|
43
|
+
'version:'
|
|
44
|
+
]
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
function main() {
|
|
48
|
+
console.log("===========================================");
|
|
49
|
+
console.log(" V-Bounce OS: Framework Integrity Check");
|
|
50
|
+
console.log("===========================================\n");
|
|
51
|
+
|
|
52
|
+
let hasErrors = false;
|
|
53
|
+
|
|
54
|
+
if (!fs.existsSync(AGENTS_DIR)) {
|
|
55
|
+
console.error(`ERROR: ${AGENTS_DIR} not found.`);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const files = fs.readdirSync(AGENTS_DIR).filter(f => f.endsWith('.md'));
|
|
60
|
+
|
|
61
|
+
for (const file of files) {
|
|
62
|
+
const filePath = path.join(AGENTS_DIR, file);
|
|
63
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
64
|
+
|
|
65
|
+
const requiredSignatures = EXPECTED_PROMPT_SIGNATURES[file];
|
|
66
|
+
if (!requiredSignatures) {
|
|
67
|
+
console.log(`[PASS] ${file} (No strict YAML signatures required)`);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let filePassed = true;
|
|
72
|
+
for (const sig of requiredSignatures) {
|
|
73
|
+
if (!content.includes(sig)) {
|
|
74
|
+
console.error(`[FAIL] ${file} is missing required YAML instruction key: '${sig}'`);
|
|
75
|
+
filePassed = false;
|
|
76
|
+
hasErrors = true;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Check for general Rule 12 presence
|
|
81
|
+
if (!content.includes('YAML frontmatter') && !content.includes('YAML Frontmatter')) {
|
|
82
|
+
console.error(`[FAIL] ${file} appears to be missing the Rule 12 YAML Frontmatter instruction.`);
|
|
83
|
+
filePassed = false;
|
|
84
|
+
hasErrors = true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (filePassed) {
|
|
88
|
+
console.log(`[PASS] ${file} contains all required YAML extraction signatures.`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
console.log("\n-------------------------------------------");
|
|
93
|
+
if (hasErrors) {
|
|
94
|
+
console.error("❌ INTEGRITY CHECK FAILED.");
|
|
95
|
+
console.error("Agent prompts have drifted from the validate_report.mjs schema.");
|
|
96
|
+
console.error("Please fix the agent templates in brains/claude-agents/ to restore pipeline integrity.");
|
|
97
|
+
process.exit(1);
|
|
98
|
+
} else {
|
|
99
|
+
console.log("✅ INTEGRITY CHECK PASSED.");
|
|
100
|
+
console.log("All agent prompts strictly map to the required pipeline metadata schemas.");
|
|
101
|
+
process.exit(0);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
main();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# verify_framework.sh
|
|
4
|
+
#
|
|
5
|
+
# Wrapper script to execute the Framework Integrity Check.
|
|
6
|
+
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd)"
|
|
8
|
+
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
9
|
+
|
|
10
|
+
cd "$ROOT_DIR" || exit 1
|
|
11
|
+
|
|
12
|
+
node ./scripts/verify_framework.mjs
|
|
13
|
+
exit $?
|
package/templates/hotfix.md
CHANGED
|
@@ -56,4 +56,5 @@ Do NOT output these instructions.
|
|
|
56
56
|
|
|
57
57
|
- [ ] {Simple step, e.g., "Open the settings modal and verify the button is aligned."}
|
|
58
58
|
- [ ] Automated tests still pass (`npm test`).
|
|
59
|
+
- [ ] **Framework Integrity**: If `brains/` or `skills/` were modified, log to `brains/CHANGELOG.md` and run `./scripts/pre_bounce_sync.sh`.
|
|
59
60
|
- [ ] **Post-Fix Action**: Run `./scripts/hotfix_manager.sh ledger "HOTFIX: {Name}" "{Brief Fix Description}"`
|
package/templates/story.md
CHANGED
|
@@ -148,3 +148,4 @@ POST /api/resource
|
|
|
148
148
|
- [ ] LESSONS.md consulted before implementation.
|
|
149
149
|
- [ ] No violations of Roadmap ADRs.
|
|
150
150
|
- [ ] Documentation (API/Tech Stack) updated.
|
|
151
|
+
- [ ] **Framework Integrity**: If `brains/` or `skills/` were modified, log to `brains/CHANGELOG.md` and run `./scripts/pre_bounce_sync.sh`.
|