viepilot 3.11.0 → 3.12.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/CHANGELOG.md +14 -0
- package/bin/vp-tools.cjs +79 -0
- package/docs/skills-reference.md +36 -0
- package/lib/tracker-compact.cjs +124 -0
- package/package.json +1 -1
- package/workflows/autonomous.md +9 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
+
## [3.12.0] - 2026-05-25
|
|
13
|
+
### Changed
|
|
14
|
+
- `workflows/autonomous.md`: tracker-agent now rewrites Current State block (find-and-replace)
|
|
15
|
+
instead of appending — TRACKER.md stays ≤ 20 lines regardless of phase count (DEBT-002)
|
|
16
|
+
- `workflows/autonomous.md`: auto-compact size guard — if TRACKER.md > 400 lines, runs
|
|
17
|
+
`vp-tools tracker compact` before reading (DEBT-002)
|
|
18
|
+
- `workflows/autonomous.md`: Decision Log capped at 20 rows; older rows archived to TRACKER-HISTORY.md
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- `lib/tracker-compact.cjs`: compact() + rewriteCurrentState() — rescue tool for bloated TRACKER.md files
|
|
22
|
+
- `bin/vp-tools.cjs`: `tracker compact [--keep N]` subcommand — compact bloated TRACKER.md, archive history to TRACKER-HISTORY.md
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
12
26
|
## [3.11.0] - 2026-05-25
|
|
13
27
|
|
|
14
28
|
### Added
|
package/bin/vp-tools.cjs
CHANGED
|
@@ -1389,6 +1389,70 @@ ${colors.cyan}Examples:${colors.reset}
|
|
|
1389
1389
|
console.log();
|
|
1390
1390
|
},
|
|
1391
1391
|
|
|
1392
|
+
/**
|
|
1393
|
+
* Compact bloated TRACKER.md and archive history (DEBT-002)
|
|
1394
|
+
* Usage: vp-tools tracker compact [--keep N] [--dry-run] [--path <file>]
|
|
1395
|
+
*/
|
|
1396
|
+
tracker: (args) => {
|
|
1397
|
+
const sub = args[0];
|
|
1398
|
+
|
|
1399
|
+
if (!sub || sub === 'help') {
|
|
1400
|
+
console.log(`${colors.cyan}Usage:${colors.reset}
|
|
1401
|
+
vp-tools tracker compact [--keep N] [--dry-run] [--path <file>]
|
|
1402
|
+
|
|
1403
|
+
${colors.cyan}Subcommands:${colors.reset}
|
|
1404
|
+
compact Compact bloated TRACKER.md, archive history
|
|
1405
|
+
|
|
1406
|
+
${colors.cyan}Options:${colors.reset}
|
|
1407
|
+
--keep N Number of rows to keep (default: 5)
|
|
1408
|
+
--dry-run Preview changes without writing
|
|
1409
|
+
--path <file> Path to TRACKER.md (default: .viepilot/TRACKER.md)
|
|
1410
|
+
|
|
1411
|
+
${colors.cyan}Examples:${colors.reset}
|
|
1412
|
+
${colors.gray}$${colors.reset} vp-tools tracker compact
|
|
1413
|
+
${colors.gray}$${colors.reset} vp-tools tracker compact --keep 10 --dry-run
|
|
1414
|
+
${colors.gray}$${colors.reset} vp-tools tracker compact --path /path/to/TRACKER.md`);
|
|
1415
|
+
return;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
if (sub === 'compact') {
|
|
1419
|
+
// Parse options
|
|
1420
|
+
const keepIdx = args.indexOf('--keep');
|
|
1421
|
+
const keepN = keepIdx !== -1 ? parseInt(args[keepIdx + 1], 10) : 5;
|
|
1422
|
+
const isDryRun = args.includes('--dry-run');
|
|
1423
|
+
|
|
1424
|
+
const pathIdx = args.indexOf('--path');
|
|
1425
|
+
const argPath = pathIdx !== -1 ? args[pathIdx + 1] : null;
|
|
1426
|
+
|
|
1427
|
+
const trackerPath = argPath || path.join(process.cwd(), '.viepilot', 'TRACKER.md');
|
|
1428
|
+
|
|
1429
|
+
try {
|
|
1430
|
+
const { compact } = require(path.join(__dirname, '../lib/tracker-compact.cjs'));
|
|
1431
|
+
const result = compact(trackerPath, { keep: keepN, dryRun: isDryRun });
|
|
1432
|
+
|
|
1433
|
+
if (isDryRun) {
|
|
1434
|
+
console.log(`[dry-run] Would compact ${trackerPath}`);
|
|
1435
|
+
console.log(` Lines to remove: ${result.linesRemoved}`);
|
|
1436
|
+
console.log(` Rows to archive: ${result.rowsArchived}`);
|
|
1437
|
+
console.log(' No files written.');
|
|
1438
|
+
} else {
|
|
1439
|
+
console.log(formatSuccess(`Compacted ${trackerPath}`));
|
|
1440
|
+
console.log(` Lines removed: ${result.linesRemoved}`);
|
|
1441
|
+
console.log(` Rows archived: ${result.rowsArchived}`);
|
|
1442
|
+
console.log(` History file: ${result.historyFile}`);
|
|
1443
|
+
console.log(` Result: ${result.trackerLines} lines remaining`);
|
|
1444
|
+
}
|
|
1445
|
+
process.exit(0);
|
|
1446
|
+
} catch (err) {
|
|
1447
|
+
console.error(formatError('tracker compact error:', err.message));
|
|
1448
|
+
process.exit(1);
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
console.error(formatError(`Unknown tracker subcommand: ${sub}`, 'Use: compact'));
|
|
1453
|
+
process.exit(1);
|
|
1454
|
+
},
|
|
1455
|
+
|
|
1392
1456
|
/**
|
|
1393
1457
|
* Validate adapter capability requirements (FEAT-021 Phase 127)
|
|
1394
1458
|
* Usage: vp-tools validate --adapter <id>
|
|
@@ -1618,6 +1682,20 @@ ${colors.cyan}Examples:${colors.reset}
|
|
|
1618
1682
|
'vp-tools update --global --dry-run',
|
|
1619
1683
|
],
|
|
1620
1684
|
},
|
|
1685
|
+
'tracker': {
|
|
1686
|
+
usage: 'vp-tools tracker compact [--keep N] [--dry-run] [--path <file>]',
|
|
1687
|
+
description: 'Compact bloated TRACKER.md and archive history',
|
|
1688
|
+
options: [
|
|
1689
|
+
'--keep N: Number of rows to keep (default: 5)',
|
|
1690
|
+
'--dry-run: Preview changes without writing',
|
|
1691
|
+
'--path <file>: Path to TRACKER.md (default: .viepilot/TRACKER.md)',
|
|
1692
|
+
],
|
|
1693
|
+
examples: [
|
|
1694
|
+
'vp-tools tracker compact',
|
|
1695
|
+
'vp-tools tracker compact --keep 10 --dry-run',
|
|
1696
|
+
'vp-tools tracker compact --path /path/to/TRACKER.md',
|
|
1697
|
+
],
|
|
1698
|
+
},
|
|
1621
1699
|
};
|
|
1622
1700
|
|
|
1623
1701
|
if (command && commandHelp[command]) {
|
|
@@ -1669,6 +1747,7 @@ ${colors.cyan}Commands:${colors.reset}
|
|
|
1669
1747
|
${colors.bold}persona${colors.reset} <op> Manage user personas (get|infer|list|set|auto-switch|context)
|
|
1670
1748
|
${colors.bold}detect-adapter${colors.reset} [--json] Detect active adapter (claude-code/cursor/antigravity/codex/copilot)
|
|
1671
1749
|
${colors.bold}validate${colors.reset} --adapter <id> Validate adapter capability requirements; exits 1 on critical gaps
|
|
1750
|
+
${colors.bold}tracker${colors.reset} compact [--keep N] Compact bloated TRACKER.md, archive history
|
|
1672
1751
|
${colors.bold}help${colors.reset} [command] Show help (optionally for specific command)
|
|
1673
1752
|
|
|
1674
1753
|
${colors.cyan}Examples:${colors.reset}
|
package/docs/skills-reference.md
CHANGED
|
@@ -643,3 +643,39 @@ controls output style, stack preferences, and team-size assumptions injected int
|
|
|
643
643
|
### Output
|
|
644
644
|
- `~/.viepilot/config.json` updated
|
|
645
645
|
- `## User Persona` injected into each skill session
|
|
646
|
+
|
|
647
|
+
---
|
|
648
|
+
|
|
649
|
+
## /vp-qa
|
|
650
|
+
|
|
651
|
+
**Version**: v1.0.0 (fw 2.19.0)
|
|
652
|
+
**Phase**: 148 (ENH-100)
|
|
653
|
+
|
|
654
|
+
Scan-first QA agent team generator. Researches the codebase first (stack detection, file sampling,
|
|
655
|
+
domain mapping), then generates a context-tailored QA agent team using the Write tool directly — no
|
|
656
|
+
templates. Number of agents and their domains are determined by research output.
|
|
657
|
+
|
|
658
|
+
### Triggers
|
|
659
|
+
`vp-qa`, `/vp-qa`, "qa agents", "generate qa team", "quality assurance agents"
|
|
660
|
+
|
|
661
|
+
### Flags
|
|
662
|
+
- `/vp-qa` — auto-detect adapter + stack, generate QA team
|
|
663
|
+
- `/vp-qa --run` — generate + immediately invoke qa-orchestrator
|
|
664
|
+
- `/vp-qa --focus sec` — bias research toward security domains
|
|
665
|
+
- `/vp-qa --focus perf` — bias research toward performance domains
|
|
666
|
+
- `/vp-qa --target <id>` — override adapter detection (claude-code / cursor-agent / antigravity / codex / copilot)
|
|
667
|
+
|
|
668
|
+
### Output by Adapter
|
|
669
|
+
| Adapter | Output Location | Format |
|
|
670
|
+
|---------|----------------|--------|
|
|
671
|
+
| claude-code | `.claude/agents/qa-orchestrator.md` + `*-scanner.md` | Multi-file, parallel fan-out |
|
|
672
|
+
| cursor-agent | `.cursor/rules/qa-checklist.mdc` | Single MDC rule file |
|
|
673
|
+
| codex | `AGENTS.md` (appended) | `## QA Agent Instructions` section |
|
|
674
|
+
| antigravity | `.agents/skills/qa-orchestrator/SKILL.md` | Multi-file skill |
|
|
675
|
+
| copilot | `.github/agents/qa-orchestrator.agent.md` | Single agent file |
|
|
676
|
+
|
|
677
|
+
### Flow
|
|
678
|
+
1. **Research phase**: reads codebase, detects stack, samples files, reads `agents/qa-templates/rules/{stack}.md`
|
|
679
|
+
2. **Adapter routing**: `lib/qa-router.cjs` determines output spec
|
|
680
|
+
3. **LLM generates**: Write tool creates agent files directly from research output
|
|
681
|
+
4. **Post-scan**: generated `qa-orchestrator` creates `.viepilot/requests/BUG-{N}.md` entries; `AskUserQuestion` for accept/decline
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
function rewriteCurrentState(content, newBlock) {
|
|
5
|
+
const match = content.match(/^## Current State\n/m);
|
|
6
|
+
if (!match) return content;
|
|
7
|
+
const start = match.index + match[0].length;
|
|
8
|
+
const after = content.slice(start).search(/^## /m);
|
|
9
|
+
const before = content.slice(0, match.index);
|
|
10
|
+
const nextSection = after === -1 ? '' : content.slice(start + after);
|
|
11
|
+
return before + '## Current State\n' + newBlock + nextSection;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function parseStanzas(lines) {
|
|
15
|
+
const stanzas = [];
|
|
16
|
+
let current = [];
|
|
17
|
+
for (const line of lines) {
|
|
18
|
+
if (line.match(/\*\*Current Phase\*\*/)) {
|
|
19
|
+
if (current.length > 0) stanzas.push(current);
|
|
20
|
+
current = [line];
|
|
21
|
+
} else if (current.length > 0) {
|
|
22
|
+
current.push(line);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (current.length > 0) stanzas.push(current);
|
|
26
|
+
return stanzas;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function compact(trackerPath, options = {}) {
|
|
30
|
+
if (!fs.existsSync(trackerPath)) {
|
|
31
|
+
throw new Error('TRACKER.md not found: ' + trackerPath);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const { keep = 5, dryRun = false } = options;
|
|
35
|
+
const maxRows = Math.max(keep * 4, 20);
|
|
36
|
+
const content = fs.readFileSync(trackerPath, 'utf8');
|
|
37
|
+
const lines = content.split('\n');
|
|
38
|
+
|
|
39
|
+
let linesRemoved = 0;
|
|
40
|
+
let rowsArchived = 0;
|
|
41
|
+
let archiveBlock = '';
|
|
42
|
+
|
|
43
|
+
// Process Current State
|
|
44
|
+
const csIdx = lines.findIndex(l => l === '## Current State');
|
|
45
|
+
const nextIdx = lines.findIndex((l, i) => i > csIdx && l.match(/^## /));
|
|
46
|
+
|
|
47
|
+
if (csIdx !== -1 && nextIdx !== -1) {
|
|
48
|
+
const csLines = lines.slice(csIdx + 1, nextIdx);
|
|
49
|
+
const stanzas = parseStanzas(csLines);
|
|
50
|
+
if (stanzas.length > 1) {
|
|
51
|
+
const archived = stanzas.slice(0, -1).map(s => s.join('\n')).join('\n');
|
|
52
|
+
linesRemoved = archived.split('\n').length;
|
|
53
|
+
archiveBlock += '## Archived Current State\n' + archived + '\n\n';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Process Decision Log
|
|
58
|
+
const dlIdx = lines.findIndex(l => l === '## Decision Log');
|
|
59
|
+
const dlEnd = nextIdx > dlIdx ? nextIdx : lines.length;
|
|
60
|
+
|
|
61
|
+
if (dlIdx !== -1) {
|
|
62
|
+
const tlines = lines.slice(dlIdx + 1, dlEnd);
|
|
63
|
+
let hIdx = -1, sIdx = -1;
|
|
64
|
+
for (let i = 0; i < tlines.length; i++) {
|
|
65
|
+
if (tlines[i].match(/\|\s*Date\s*\|/)) hIdx = i;
|
|
66
|
+
if (hIdx !== -1 && tlines[i].match(/^\|\s*[-:]+/)) {
|
|
67
|
+
sIdx = i;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (hIdx !== -1 && sIdx !== -1) {
|
|
72
|
+
const rows = tlines.slice(sIdx + 1).filter(l => l.trim().match(/^\|/));
|
|
73
|
+
if (rows.length > maxRows) {
|
|
74
|
+
rowsArchived = rows.length - maxRows;
|
|
75
|
+
archiveBlock += '## Archived Decision Log Rows\n' + rows.slice(0, -maxRows).join('\n') + '\n';
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!dryRun && archiveBlock) {
|
|
81
|
+
const histPath = path.join(path.dirname(trackerPath), 'TRACKER-HISTORY.md');
|
|
82
|
+
fs.appendFileSync(histPath, '\n---\n# TRACKER Archive — ' + new Date().toISOString().split('T')[0] + '\n\n' + archiveBlock);
|
|
83
|
+
|
|
84
|
+
// Rewrite TRACKER.md
|
|
85
|
+
let newContent = content;
|
|
86
|
+
if (csIdx !== -1 && nextIdx !== -1) {
|
|
87
|
+
const stanzas = parseStanzas(lines.slice(csIdx + 1, nextIdx));
|
|
88
|
+
if (stanzas.length > 0) {
|
|
89
|
+
newContent = rewriteCurrentState(newContent, stanzas[stanzas.length - 1].join('\n') + '\n');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (dlIdx !== -1) {
|
|
94
|
+
const tlines = lines.slice(dlIdx + 1, dlEnd);
|
|
95
|
+
let hIdx = -1, sIdx = -1;
|
|
96
|
+
for (let i = 0; i < tlines.length; i++) {
|
|
97
|
+
if (tlines[i].match(/\|\s*Date\s*\|/)) hIdx = i;
|
|
98
|
+
if (hIdx !== -1 && tlines[i].match(/^\|\s*[-:]+/)) {
|
|
99
|
+
sIdx = i;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (hIdx !== -1 && sIdx !== -1) {
|
|
104
|
+
const rows = tlines.slice(sIdx + 1).filter(l => l.trim().match(/^\|/));
|
|
105
|
+
const kept = rows.slice(-maxRows);
|
|
106
|
+
const newTable = [tlines[hIdx], tlines[sIdx], ...kept].join('\n');
|
|
107
|
+
const before = lines.slice(0, dlIdx + 1).join('\n');
|
|
108
|
+
const after = lines.slice(dlEnd).join('\n');
|
|
109
|
+
newContent = before + '\n' + newTable + '\n' + after;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
fs.writeFileSync(trackerPath, newContent, 'utf8');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
linesRemoved,
|
|
118
|
+
rowsArchived,
|
|
119
|
+
historyFile: path.join(path.dirname(trackerPath), 'TRACKER-HISTORY.md'),
|
|
120
|
+
trackerLines: lines.length - linesRemoved
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
module.exports = { compact, rewriteCurrentState };
|
package/package.json
CHANGED
package/workflows/autonomous.md
CHANGED
|
@@ -74,6 +74,13 @@ Parse `{{VP_ARGS}}` for flags:
|
|
|
74
74
|
Load context:
|
|
75
75
|
```bash
|
|
76
76
|
cat .viepilot/AI-GUIDE.md
|
|
77
|
+
|
|
78
|
+
# Size guard — auto-compact if TRACKER.md is bloated (> 400 lines)
|
|
79
|
+
if [ -f ".viepilot/TRACKER.md" ] && [ "$(wc -l < .viepilot/TRACKER.md)" -gt 400 ]; then
|
|
80
|
+
echo "⚠️ TRACKER.md is large ($(wc -l < .viepilot/TRACKER.md) lines) — auto-compacting..."
|
|
81
|
+
node bin/vp-tools.cjs tracker compact --keep 5
|
|
82
|
+
fi
|
|
83
|
+
|
|
77
84
|
cat .viepilot/TRACKER.md
|
|
78
85
|
cat .viepilot/ROADMAP.md
|
|
79
86
|
```
|
|
@@ -907,9 +914,10 @@ After phase quality gate passes, send a desktop + phone alert:
|
|
|
907
914
|
```
|
|
908
915
|
Agent({ subagent_type: "tracker-agent",
|
|
909
916
|
description: "Update TRACKER.md — phase {N} complete",
|
|
910
|
-
prompt: "operation:
|
|
917
|
+
prompt: "operation: rewrite-current-state. data: Last completed phase {N} — {phase_name}. version: {version}. IMPORTANT: REPLACE the entire '## Current State' section (find the section, overwrite it) — do NOT append new lines. The section must stay ≤ 20 lines total. Also cap '## Decision Log' table at 20 rows — if > 20 rows exist, archive older rows to .viepilot/TRACKER-HISTORY.md."
|
|
911
918
|
})
|
|
912
919
|
```
|
|
920
|
+
> Rescue bloated TRACKER.md: `node bin/vp-tools.cjs tracker compact [--keep N]` (DEBT-002)
|
|
913
921
|
7. Push branch + tags — spawn vp-git-agent:
|
|
914
922
|
```
|
|
915
923
|
Agent({ subagent_type: "vp-git-agent",
|