@sandrinio/vbounce 1.7.0 → 1.9.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 +168 -160
- package/bin/vbounce.mjs +250 -25
- package/brains/AGENTS.md +4 -4
- package/brains/CHANGELOG.md +2 -2
- package/brains/CLAUDE.md +4 -4
- package/brains/GEMINI.md +5 -5
- package/brains/SETUP.md +15 -15
- package/brains/claude-agents/architect.md +1 -1
- package/brains/claude-agents/developer.md +1 -1
- package/brains/claude-agents/devops.md +1 -1
- package/brains/claude-agents/qa.md +2 -1
- package/brains/claude-agents/scribe.md +1 -1
- package/brains/copilot/copilot-instructions.md +3 -3
- package/brains/cursor-rules/vbounce-docs.mdc +2 -2
- package/brains/cursor-rules/vbounce-process.mdc +3 -3
- package/brains/cursor-rules/vbounce-rules.mdc +2 -2
- package/brains/windsurf/.windsurfrules +2 -2
- package/docs/HOTFIX_EDGE_CASES.md +1 -1
- package/package.json +5 -5
- package/scripts/doctor.mjs +3 -3
- package/scripts/hotfix_manager.sh +2 -2
- package/scripts/init_gate_config.sh +1 -1
- package/scripts/pre_gate_common.sh +1 -1
- package/scripts/pre_gate_runner.sh +1 -1
- package/scripts/prep_qa_context.mjs +19 -1
- package/scripts/prep_sprint_context.mjs +24 -1
- package/scripts/suggest_improvements.mjs +1 -1
- package/scripts/validate_bounce_readiness.mjs +27 -0
- package/scripts/validate_report.mjs +1 -1
- package/scripts/vdoc_match.mjs +269 -0
- package/scripts/vdoc_staleness.mjs +199 -0
- package/scripts/verify_framework.mjs +1 -1
- package/skills/agent-team/SKILL.md +18 -11
- package/skills/doc-manager/SKILL.md +5 -5
- package/skills/improve/SKILL.md +2 -2
- package/templates/sprint_report.md +6 -2
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* vdoc_staleness.mjs
|
|
5
|
+
* Cross-references Dev Reports' files_modified against vdoc manifest key files.
|
|
6
|
+
* Generates a targeted Scribe task file listing stale docs.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* ./scripts/vdoc_staleness.mjs S-05
|
|
10
|
+
*
|
|
11
|
+
* Output: .bounce/scribe-task-S-05.md
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import fs from 'fs';
|
|
15
|
+
import path from 'path';
|
|
16
|
+
import { fileURLToPath } from 'url';
|
|
17
|
+
import yaml from 'js-yaml';
|
|
18
|
+
|
|
19
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
21
|
+
|
|
22
|
+
const sprintId = process.argv[2];
|
|
23
|
+
if (!sprintId) {
|
|
24
|
+
console.error('Usage: vdoc_staleness.mjs S-XX');
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const VDOCS_DIR = path.join(ROOT, 'vdocs');
|
|
29
|
+
const MANIFEST_PATH = path.join(VDOCS_DIR, '_manifest.json');
|
|
30
|
+
|
|
31
|
+
// ── Check manifest ────────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
if (!fs.existsSync(MANIFEST_PATH)) {
|
|
34
|
+
console.log('No vdocs/_manifest.json found — skipping staleness check');
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const manifest = JSON.parse(fs.readFileSync(MANIFEST_PATH, 'utf8'));
|
|
39
|
+
const docs = manifest.documentation || [];
|
|
40
|
+
|
|
41
|
+
// ── Collect all files_modified from Dev Reports ───────────────────
|
|
42
|
+
|
|
43
|
+
const allModifiedFiles = new Set();
|
|
44
|
+
const storyModifications = {}; // storyId -> files
|
|
45
|
+
|
|
46
|
+
function findDevReports(dir) {
|
|
47
|
+
if (!fs.existsSync(dir)) return [];
|
|
48
|
+
const results = [];
|
|
49
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
50
|
+
for (const e of entries) {
|
|
51
|
+
const full = path.join(dir, e.name);
|
|
52
|
+
if (e.isDirectory()) results.push(...findDevReports(full));
|
|
53
|
+
else if (e.name.endsWith('-dev.md')) results.push(full);
|
|
54
|
+
}
|
|
55
|
+
return results;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const reportDirs = [
|
|
59
|
+
path.join(ROOT, '.bounce', 'reports'),
|
|
60
|
+
path.join(ROOT, '.bounce', 'archive', sprintId),
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
for (const dir of reportDirs) {
|
|
64
|
+
const reports = findDevReports(dir);
|
|
65
|
+
for (const report of reports) {
|
|
66
|
+
try {
|
|
67
|
+
const content = fs.readFileSync(report, 'utf8');
|
|
68
|
+
const fmMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
69
|
+
if (!fmMatch) continue;
|
|
70
|
+
const fm = yaml.load(fmMatch[1]) || {};
|
|
71
|
+
const files = fm.files_modified || [];
|
|
72
|
+
const storyMatch = path.basename(report).match(/STORY-[\w-]+/);
|
|
73
|
+
const storyId = storyMatch ? storyMatch[0] : 'unknown';
|
|
74
|
+
storyModifications[storyId] = files;
|
|
75
|
+
files.forEach(f => allModifiedFiles.add(f));
|
|
76
|
+
} catch { /* skip malformed reports */ }
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (allModifiedFiles.size === 0) {
|
|
81
|
+
console.log('No files_modified found in Dev Reports — nothing to check');
|
|
82
|
+
process.exit(0);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ── Cross-reference against manifest key files ────────────────────
|
|
86
|
+
|
|
87
|
+
const staleDocs = [];
|
|
88
|
+
|
|
89
|
+
for (const doc of docs) {
|
|
90
|
+
// Get key files from doc frontmatter or Key Files section
|
|
91
|
+
const docKeyFiles = [];
|
|
92
|
+
|
|
93
|
+
// From manifest entry
|
|
94
|
+
if (doc.keyFiles) docKeyFiles.push(...doc.keyFiles);
|
|
95
|
+
|
|
96
|
+
// From the doc file itself
|
|
97
|
+
const docPath = path.join(VDOCS_DIR, doc.filepath);
|
|
98
|
+
if (fs.existsSync(docPath)) {
|
|
99
|
+
const content = fs.readFileSync(docPath, 'utf8');
|
|
100
|
+
|
|
101
|
+
// Parse frontmatter keyFiles
|
|
102
|
+
const fmMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
103
|
+
if (fmMatch) {
|
|
104
|
+
try {
|
|
105
|
+
const fm = yaml.load(fmMatch[1]) || {};
|
|
106
|
+
if (fm.keyFiles) docKeyFiles.push(...fm.keyFiles);
|
|
107
|
+
} catch { /* ignore */ }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Parse Key Files table
|
|
111
|
+
const tableMatch = content.match(/## Key Files[\s\S]*?\|[^|]+\|[^|]+\|[^|]+\|([\s\S]*?)(?=\n---|\n##)/);
|
|
112
|
+
if (tableMatch) {
|
|
113
|
+
const rows = tableMatch[1].split('\n').filter(r => r.includes('|'));
|
|
114
|
+
for (const row of rows) {
|
|
115
|
+
const cells = row.split('|').map(c => c.trim());
|
|
116
|
+
const filePath = cells[1]?.replace(/`/g, '');
|
|
117
|
+
if (filePath && filePath.includes('/')) docKeyFiles.push(filePath);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Check for overlap
|
|
123
|
+
const uniqueKeyFiles = [...new Set(docKeyFiles)];
|
|
124
|
+
const overlapping = uniqueKeyFiles.filter(kf =>
|
|
125
|
+
[...allModifiedFiles].some(mf => mf.includes(kf) || kf.includes(mf))
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
if (overlapping.length > 0) {
|
|
129
|
+
// Find which stories touched these files
|
|
130
|
+
const touchedBy = [];
|
|
131
|
+
for (const [sid, files] of Object.entries(storyModifications)) {
|
|
132
|
+
if (files.some(f => overlapping.some(o => f.includes(o) || o.includes(f)))) {
|
|
133
|
+
touchedBy.push(sid);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
staleDocs.push({
|
|
138
|
+
filepath: doc.filepath,
|
|
139
|
+
title: doc.title,
|
|
140
|
+
overlappingFiles: overlapping,
|
|
141
|
+
touchedBy,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (staleDocs.length === 0) {
|
|
147
|
+
console.log('✓ No stale vdocs detected — all docs are current');
|
|
148
|
+
process.exit(0);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ── Generate Scribe task file ─────────────────────────────────────
|
|
152
|
+
|
|
153
|
+
const taskLines = [
|
|
154
|
+
`---`,
|
|
155
|
+
`sprint_id: "${sprintId}"`,
|
|
156
|
+
`mode: "audit"`,
|
|
157
|
+
`stale_docs: ${staleDocs.length}`,
|
|
158
|
+
`generated: "${new Date().toISOString().split('T')[0]}"`,
|
|
159
|
+
`---`,
|
|
160
|
+
``,
|
|
161
|
+
`# Scribe Task: ${sprintId} — Targeted Doc Update`,
|
|
162
|
+
``,
|
|
163
|
+
`> Auto-generated by staleness detection. ${staleDocs.length} doc(s) need updating.`,
|
|
164
|
+
``,
|
|
165
|
+
`## Stale Documents`,
|
|
166
|
+
``,
|
|
167
|
+
`| Doc | Title | Files Modified | Touched By |`,
|
|
168
|
+
`|-----|-------|---------------|------------|`,
|
|
169
|
+
...staleDocs.map(d =>
|
|
170
|
+
`| ${d.filepath} | ${d.title} | ${d.overlappingFiles.slice(0, 3).join(', ')}${d.overlappingFiles.length > 3 ? ` (+${d.overlappingFiles.length - 3})` : ''} | ${d.touchedBy.join(', ')} |`
|
|
171
|
+
),
|
|
172
|
+
``,
|
|
173
|
+
`## Instructions`,
|
|
174
|
+
``,
|
|
175
|
+
`For each stale doc:`,
|
|
176
|
+
`1. Read the current doc and the Dev Reports from the stories listed above`,
|
|
177
|
+
`2. Re-read the modified source files to understand what changed`,
|
|
178
|
+
`3. Update only the affected sections — do not rewrite the entire doc`,
|
|
179
|
+
`4. Bump frontmatter \`version\` (increment by 1) and set \`lastUpdated\` to today`,
|
|
180
|
+
`5. Update the manifest entry if tags or description need adjustment`,
|
|
181
|
+
`6. Regenerate the context slice in \`vdocs/_slices/\``,
|
|
182
|
+
``,
|
|
183
|
+
`## Priority`,
|
|
184
|
+
``,
|
|
185
|
+
...staleDocs.map(d => {
|
|
186
|
+
const fileCount = d.overlappingFiles.length;
|
|
187
|
+
const priority = fileCount >= 3 ? 'HIGH' : fileCount >= 2 ? 'MEDIUM' : 'LOW';
|
|
188
|
+
return `- **${d.filepath}**: ${priority} (${fileCount} key file(s) modified)`;
|
|
189
|
+
}),
|
|
190
|
+
];
|
|
191
|
+
|
|
192
|
+
const taskFile = path.join(ROOT, '.bounce', `scribe-task-${sprintId}.md`);
|
|
193
|
+
fs.writeFileSync(taskFile, taskLines.join('\n'));
|
|
194
|
+
|
|
195
|
+
console.log(`✓ Scribe task written to .bounce/scribe-task-${sprintId}.md`);
|
|
196
|
+
console.log(` ${staleDocs.length} stale doc(s) detected:`);
|
|
197
|
+
for (const d of staleDocs) {
|
|
198
|
+
console.log(` - ${d.filepath} (${d.overlappingFiles.length} key files modified by ${d.touchedBy.join(', ')})`);
|
|
199
|
+
}
|
|
@@ -63,7 +63,7 @@ const EXPECTED_PROMPT_SIGNATURES = {
|
|
|
63
63
|
|
|
64
64
|
function main() {
|
|
65
65
|
console.log("===========================================");
|
|
66
|
-
console.log(" V-Bounce
|
|
66
|
+
console.log(" V-Bounce Engine: Framework Integrity Check");
|
|
67
67
|
console.log("===========================================\n");
|
|
68
68
|
|
|
69
69
|
let hasErrors = false;
|
|
@@ -359,17 +359,24 @@ After ALL stories are merged into `sprint/S-01`:
|
|
|
359
359
|
- Offer to run the `improve` skill to propose framework changes
|
|
360
360
|
- If user approves → read `skills/improve/SKILL.md` and execute the improvement process
|
|
361
361
|
8. Product Documentation check (runs on `main` after sprint merge):
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
362
|
+
a. **Staleness Detection** — run `./scripts/vdoc_staleness.mjs S-{XX}`
|
|
363
|
+
- Cross-references all Dev Reports' `files_modified` against manifest key files
|
|
364
|
+
- Generates `.bounce/scribe-task-S-{XX}.md` with targeted list of stale docs
|
|
365
|
+
- Populates Sprint Report §1 "Product Docs Affected" table
|
|
366
|
+
- If no `vdocs/_manifest.json` exists → skip silently (graceful no-op)
|
|
367
|
+
b. **Scribe Task Decision:**
|
|
368
|
+
- If staleness detection found stale docs → offer targeted Scribe task
|
|
369
|
+
- If sprint delivered 3+ features and no vdocs exist → offer vdoc init
|
|
370
|
+
- If any Developer report flagged stale product docs → offer Scribe update
|
|
371
|
+
c. If user approves → spawn scribe subagent on `main` branch with:
|
|
372
|
+
- `.bounce/scribe-task-S-{XX}.md` (targeted task — when available)
|
|
373
|
+
- Sprint Report (what was built)
|
|
374
|
+
- Dev reports that flagged affected product docs
|
|
375
|
+
- Current _manifest.json (if exists)
|
|
376
|
+
- Mode: "audit" (if docs exist) or "init" (if first time)
|
|
377
|
+
d. Scribe generates/updates docs and writes Scribe Report
|
|
378
|
+
- Documentation is post-implementation — it reflects what was built
|
|
379
|
+
- Scribe commits documentation as a follow-up commit on `main`
|
|
373
380
|
```
|
|
374
381
|
|
|
375
382
|
---
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: doc-manager
|
|
3
|
-
description: "Use when creating, modifying, or navigating V-Bounce
|
|
3
|
+
description: "Use when creating, modifying, or navigating V-Bounce Engine planning documents. Trigger on any request to create a charter, roadmap, epic, story, delivery plan, or risk registry — or when the user asks to update, refine, decompose, or transition documents between phases. Also trigger when an agent needs to know which template to use, where a document fits in the hierarchy, or what upstream/downstream documents to read before writing. This skill manages the full document lifecycle from Charter through Sprint execution."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Document Hierarchy Manager
|
|
7
7
|
|
|
8
8
|
## Purpose
|
|
9
9
|
|
|
10
|
-
This skill is the navigation system for V-Bounce
|
|
10
|
+
This skill is the navigation system for V-Bounce Engine planning documents. It knows the full document hierarchy, what each template contains, where to find templates, and the rules for creating, modifying, and transitioning documents between phases.
|
|
11
11
|
|
|
12
12
|
**Core principle:** No document exists in isolation. Every document inherits context from upstream and feeds downstream consumers. YOU MUST read upstream documents before creating any new document.
|
|
13
13
|
|
|
@@ -120,10 +120,10 @@ product_plans/
|
|
|
120
120
|
- `sprints/` contains active 1-week execution boundaries. A Story file physically moves here when a sprint begins.
|
|
121
121
|
- `archive/` is where finished Sprints and finished Epics are moved for permanent record keeping.
|
|
122
122
|
|
|
123
|
-
### V-Bounce
|
|
123
|
+
### V-Bounce Engine Framework Structure
|
|
124
124
|
|
|
125
125
|
```
|
|
126
|
-
V-Bounce
|
|
126
|
+
V-Bounce Engine/
|
|
127
127
|
├── brains/ — Agent brain files for each AI coding tool
|
|
128
128
|
│ ├── CLAUDE.md — Claude Code brain
|
|
129
129
|
│ ├── AGENTS.md — Codex CLI brain
|
|
@@ -148,7 +148,7 @@ When initializing a new project, deploy the correct brain file for the AI coding
|
|
|
148
148
|
| Gemini CLI | `brains/GEMINI.md` | Project root as `GEMINI.md` |
|
|
149
149
|
| Antigravity | `brains/GEMINI.md` | Project root + copy `skills/` to `.agents/skills/` |
|
|
150
150
|
|
|
151
|
-
Brain files contain the V-Bounce process, critical rules, and skill references. Each tool's brain file is self-contained and authoritative. When updating V-Bounce
|
|
151
|
+
Brain files contain the V-Bounce process, critical rules, and skill references. Each tool's brain file is self-contained and authoritative. When updating V-Bounce Engine rules, update each brain file directly and keep them in sync.
|
|
152
152
|
|
|
153
153
|
## Document Operations
|
|
154
154
|
|
package/skills/improve/SKILL.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: improve
|
|
3
|
-
description: "Use when the V-Bounce
|
|
3
|
+
description: "Use when the V-Bounce Engine framework needs to evolve based on accumulated agent feedback. Activates after sprint retros, when recurring friction patterns emerge, or when the user explicitly asks to improve the framework. Reads Process Feedback from sprint reports, identifies patterns, proposes specific changes to templates, skills, brain files, scripts, and agent configs, and applies approved changes. This is the system's self-improvement loop."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Framework Self-Improvement
|
|
7
7
|
|
|
8
8
|
## Purpose
|
|
9
9
|
|
|
10
|
-
V-Bounce
|
|
10
|
+
V-Bounce Engine is not static. Every sprint generates friction signals from agents who work within the framework daily. This skill closes the feedback loop: it reads what agents struggled with, identifies patterns, and proposes targeted improvements to the framework itself.
|
|
11
11
|
|
|
12
12
|
**Core principle:** No framework change happens without human approval. The system suggests — the human decides.
|
|
13
13
|
|
|
@@ -54,9 +54,13 @@ delivery_plan_ref: "product_plans/{delivery}/DELIVERY_PLAN.md"
|
|
|
54
54
|
- {e.g., "STORY-001-03-email_notifications — Escalated (template integration failed 3x)"}
|
|
55
55
|
|
|
56
56
|
### Product Docs Affected
|
|
57
|
-
>
|
|
57
|
+
> Auto-populated from staleness detection (`vbounce docs check S-{XX}`). Shows which vdocs were impacted by this sprint's code changes. Scribe agent receives a targeted task from `.bounce/scribe-task-S-{XX}.md`.
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
| Doc | Stale Key Files | Touched By | Priority | Scribe Action |
|
|
60
|
+
|-----|----------------|------------|----------|---------------|
|
|
61
|
+
| {e.g., `AUTHENTICATION_DOC.md`} | {e.g., `src/auth/index.ts`} | {e.g., `STORY-001-02`} | {HIGH/MEDIUM/LOW} | {Update / Quality Fix / New} |
|
|
62
|
+
|
|
63
|
+
> If no `vdocs/_manifest.json` exists, write "N/A — vdoc not installed".
|
|
60
64
|
|
|
61
65
|
---
|
|
62
66
|
|